Beispiel #1
0
uint32_t
cpu_get_mid(u_int cpu_impl)
{

	switch (cpu_impl) {
	case CPU_IMPL_SPARC64:
	case CPU_IMPL_SPARC64V:
	case CPU_IMPL_ULTRASPARCI:
	case CPU_IMPL_ULTRASPARCII:
	case CPU_IMPL_ULTRASPARCIIi:
	case CPU_IMPL_ULTRASPARCIIe:
		return (UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG)));
	case CPU_IMPL_ULTRASPARCIII:
	case CPU_IMPL_ULTRASPARCIIIp:
		return (FIREPLANE_CR_GET_AID(ldxa(AA_FIREPLANE_CONFIG,
		    ASI_FIREPLANE_CONFIG_REG)));
	case CPU_IMPL_ULTRASPARCIIIi:
	case CPU_IMPL_ULTRASPARCIIIip:
		return (JBUS_CR_GET_JID(ldxa(0, ASI_JBUS_CONFIG_REG)));
	case CPU_IMPL_ULTRASPARCIV:
	case CPU_IMPL_ULTRASPARCIVp:
		return (INTR_ID_GET_ID(ldxa(AA_INTR_ID, ASI_INTR_ID)));
	default:
		return (0);
	}
}
Beispiel #2
0
/*
 * Send an interprocessor interrupt - sun4u.
 */
void
sparc64_send_ipi_sun4u(int upaid, ipifunc_t func, uint64_t arg1, uint64_t arg2)
{
	int i, ik, shift = 0;
	uint64_t intr_func;

	KASSERT(upaid != curcpu()->ci_cpuid);

	/*
	 * UltraSPARC-IIIi CPUs select the BUSY/NACK pair based on the
	 * lower two bits of the ITID.
	 */
	if (CPU_IS_USIIIi())
		shift = (upaid & 0x3) * 2;

	if (ldxa(0, ASI_IDSR) & (IDSR_BUSY << shift))
		panic("recursive IPI?");

	intr_func = (uint64_t)(u_long)func;

	/* Schedule an interrupt. */
	for (i = 0; i < 10000; i++) {
		int s = intr_disable();

		stxa(IDDR_0H, ASI_INTERRUPT_DISPATCH, intr_func);
		stxa(IDDR_1H, ASI_INTERRUPT_DISPATCH, arg1);
		stxa(IDDR_2H, ASI_INTERRUPT_DISPATCH, arg2);
		stxa(IDCR(upaid), ASI_INTERRUPT_DISPATCH, 0);
		membar_Sync();
		/* Workaround for SpitFire erratum #54, from FreeBSD */
		if (CPU_IS_SPITFIRE()) {
			(void)ldxa(P_DCR_0, ASI_INTERRUPT_RECEIVE_DATA);
			membar_Sync();
		}

		for (ik = 0; ik < 1000000; ik++) {
			if (ldxa(0, ASI_IDSR) & (IDSR_BUSY << shift))
				continue;
			else
				break;
		}
		intr_restore(s);

		if (ik == 1000000)
			break;

		if ((ldxa(0, ASI_IDSR) & (IDSR_NACK << shift)) == 0)
			return;
		/*
		 * Wait for a while with enabling interrupts to avoid
		 * deadlocks.  XXX - random value is better.
		 */
		DELAY(1);
	}

	if (panicstr == NULL)
		panic("cpu%d: ipi_send: couldn't send ipi to UPAID %u"
			" (tried %d times)", cpu_number(), upaid, i);
}
Beispiel #3
0
/*
 * Flush all user mappings from the TLBs.
 */
void
zeus_tlb_flush_user(void)
{
	u_long data, tag;
	u_int i, slot;

	for (i = 0; i < ZEUS_FTLB_ENTRIES; i++) {
		slot = TLB_DAR_SLOT(TLB_DAR_FTLB, i);
		data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		tag = ldxa(slot, ASI_DTLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_DTLB_DATA_ACCESS_REG, 0);
		data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
		tag = ldxa(slot, ASI_ITLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_ITLB_DATA_ACCESS_REG, 0);
	}
	for (i = 0; i < ZEUS_STLB_ENTRIES; i++) {
		slot = TLB_DAR_SLOT(TLB_DAR_STLB, i);
		data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		tag = ldxa(slot, ASI_DTLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_DTLB_DATA_ACCESS_REG, 0);
		data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
		tag = ldxa(slot, ASI_ITLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_ITLB_DATA_ACCESS_REG, 0);
	}
}
Beispiel #4
0
vm_offset_t
watch_phys_get(int *bm)
{
	u_long pa;
	u_long lsucr;
	
	if (!watch_phys_active())
		return (0);

	pa = ldxa(AA_DMMU_PWPR, ASI_DMMU);
	lsucr = ldxa(0, ASI_LSU_CTL_REG);
	*bm = (lsucr & LSU_PM_MASK) >> LSU_PM_SHIFT;
	
	return ((vm_offset_t)pa);
}
Beispiel #5
0
vm_offset_t
watch_virt_get(int *bm)
{
	u_long va;
	u_long lsucr;
	
	if (!watch_virt_active())
		return (0);

	va = ldxa(AA_DMMU_VWPR, ASI_DMMU);
	lsucr = ldxa(0, ASI_LSU_CTL_REG);
	*bm = (lsucr & LSU_VM_MASK) >> LSU_VM_SHIFT;
	
	return ((vm_offset_t)va);
}
Beispiel #6
0
/*
 * CPU-specific initialization for Fujitsu Zeus CPUs
 */
void
zeus_init(u_int cpu_impl)
{
	u_long val;

	/* Ensure the TSB Extension Registers hold 0 as TSB_Base. */

	stxa(AA_DMMU_TSB_PEXT_REG, ASI_DMMU, 0);
	stxa(AA_IMMU_TSB_PEXT_REG, ASI_IMMU, 0);
	membar(Sync);

	stxa(AA_DMMU_TSB_SEXT_REG, ASI_DMMU, 0);
	/*
	 * NB: the secondary context was removed from the iMMU.
	 */
	membar(Sync);

	stxa(AA_DMMU_TSB_NEXT_REG, ASI_DMMU, 0);
	stxa(AA_IMMU_TSB_NEXT_REG, ASI_IMMU, 0);
	membar(Sync);

	val = ldxa(AA_MCNTL, ASI_MCNTL);
	/* Ensure MCNTL_JPS1_TSBP is 0. */
	val &= ~MCNTL_JPS1_TSBP;
	/*
	 * Ensure 4-Mbyte page entries are stored in the 1024-entry, 2-way set
	 * associative TLB.
	 */
	val = (val & ~MCNTL_RMD_MASK) | MCNTL_RMD_1024;
	stxa(AA_MCNTL, ASI_MCNTL, val);
}
Beispiel #7
0
/*
 * Flush all lines from the level 1 caches.
 */
void
cheetah_cache_flush(void)
{
	u_long addr, lsu;
	register_t s;

	s = intr_disable();
	for (addr = 0; addr < PCPU_GET(cache.dc_size);
	    addr += PCPU_GET(cache.dc_linesize))
		/*
		 * Note that US-IV+ additionally require a membar #Sync before
		 * a load or store to ASI_DCACHE_TAG.
		 */
		__asm __volatile(
		    "membar #Sync;"
		    "stxa %%g0, [%0] %1;"
		    "membar #Sync"
		    : : "r" (addr), "n" (ASI_DCACHE_TAG));

	/* The I$ must be disabled when flushing it so ensure it's off. */
	lsu = ldxa(0, ASI_LSU_CTL_REG);
	stxa(0, ASI_LSU_CTL_REG, lsu & ~(LSU_IC));
	flush(KERNBASE);
	for (addr = CHEETAH_ICACHE_TAG_LOWER;
	    addr < PCPU_GET(cache.ic_size) * 2;
	    addr += PCPU_GET(cache.ic_linesize) * 2)
		__asm __volatile(
		    "stxa %%g0, [%0] %1;"
		    "membar #Sync"
		    : : "r" (addr), "n" (ASI_ICACHE_TAG));
	stxa(0, ASI_LSU_CTL_REG, lsu);
	flush(KERNBASE);
	intr_restore(s);
}
Beispiel #8
0
/*
 * Enable level 1 caches.
 */
void
zeus_cache_enable(u_int cpu_impl)
{
	u_long lsu;

	lsu = ldxa(0, ASI_LSU_CTL_REG);
	stxa(0, ASI_LSU_CTL_REG, lsu | LSU_IC | LSU_DC);
	flush(KERNBASE);
}
Beispiel #9
0
int
watch_phys_set_mask(vm_offset_t pa, u_long mask)
{
	u_long lsucr;

	stxa_sync(AA_DMMU_PWPR, ASI_DMMU, pa & (((2UL << 38) - 1) << 3));
	lsucr = ldxa(0, ASI_LSU_CTL_REG);
	lsucr = ((lsucr | LSU_PW) & ~LSU_PM_MASK) |
	    (mask << LSU_PM_SHIFT);
	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
	return (0);
}
Beispiel #10
0
int
watch_virt_set_mask(vm_offset_t va, u_long mask)
{
	u_long lsucr;

	stxa_sync(AA_DMMU_VWPR, ASI_DMMU, va & (((2UL << 41) - 1) << 3));
	lsucr = ldxa(0, ASI_LSU_CTL_REG);
	lsucr = ((lsucr | LSU_VW) & ~LSU_VM_MASK) |
	    (mask << LSU_VM_SHIFT);
	stxa_sync(0, ASI_LSU_CTL_REG, lsucr);
	return (0);
}
Beispiel #11
0
/*
 * Enable level 1 caches.
 */
void
cheetah_cache_enable(u_int cpu_impl)
{
	u_long lsu;

	lsu = ldxa(0, ASI_LSU_CTL_REG);
	if (cpu_impl == CPU_IMPL_ULTRASPARCIII) {
		/* Disable P$ due to US-III erratum #18. */
		lsu &= ~LSU_PE;
	}
	stxa(0, ASI_LSU_CTL_REG, lsu | LSU_IC | LSU_DC);
	flush(KERNBASE);
}
Beispiel #12
0
void
tlb_dump(void)
{
	u_long data;
	u_long tag;
	int slot;

	for (slot = 0; slot < tlb_dtlb_entries; slot++) {
		data = ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_DATA_ACCESS_REG);
		if ((data & TD_V) != 0) {
			tag = ldxa(TLB_DAR_SLOT(slot), ASI_DTLB_TAG_READ_REG);
			TR3("pmap_dump_tlb: dltb slot=%d data=%#lx tag=%#lx",
			    slot, data, tag);
		}
		data = ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_DATA_ACCESS_REG);
		if ((data & TD_V) != 0) {
			tag = ldxa(TLB_DAR_SLOT(slot), ASI_ITLB_TAG_READ_REG);
			TR3("pmap_dump_tlb: iltb slot=%d data=%#lx tag=%#lx",
			    slot, data, tag);
		}
	}
}
Beispiel #13
0
static void
tlb_init(void)
{
	phandle_t child;
	phandle_t root;
	char buf[128];
	u_int bootcpu;
	u_int cpu;

	bootcpu = UPA_CR_GET_MID(ldxa(0, ASI_UPA_CONFIG_REG));
	if ((root = OF_peer(0)) == -1)
		panic("main: OF_peer");
	for (child = OF_child(root); child != 0; child = OF_peer(child)) {
		if (child == -1)
			panic("main: OF_child");
		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("main: OF_getprop");
			if (cpu == bootcpu)
				break;
		}
	}
	if (cpu != bootcpu)
		panic("init_tlb: no node for bootcpu?!?!");
	if (OF_getprop(child, "#dtlb-entries", &dtlb_slot_max,
	    sizeof(dtlb_slot_max)) == -1 ||
	    OF_getprop(child, "#itlb-entries", &itlb_slot_max,
	    sizeof(itlb_slot_max)) == -1)
		panic("init_tlb: OF_getprop");
	dtlb_store = malloc(dtlb_slot_max * sizeof(*dtlb_store));
	itlb_store = malloc(itlb_slot_max * sizeof(*itlb_store));
	if (dtlb_store == NULL || itlb_store == NULL)
		panic("init_tlb: malloc");
}
Beispiel #14
0
int
watch_virt_active()
{

	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_VW);
}
Beispiel #15
0
void
watch_virt_clear()
{
	stxa_sync(0, ASI_LSU_CTL_REG,
	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_VW);
}
Beispiel #16
0
void
watch_phys_clear()
{
	stxa_sync(0, ASI_LSU_CTL_REG,
	    ldxa(0, ASI_LSU_CTL_REG) & ~LSU_PW);
}
Beispiel #17
0
/*
 * CPU-specific initialization - this is used for both the Sun Cheetah and
 * later as well as the Fujitsu Zeus and later CPUs.
 */
void
cheetah_init(u_int cpu_impl)
{
	u_long val;

	/* Ensure the TSB Extension Registers hold 0 as TSB_Base. */

	stxa(AA_DMMU_TSB_PEXT_REG, ASI_DMMU, 0);
	stxa(AA_IMMU_TSB_PEXT_REG, ASI_IMMU, 0);
	membar(Sync);

	stxa(AA_DMMU_TSB_SEXT_REG, ASI_DMMU, 0);
	/*
	 * NB: the secondary context was removed from the iMMU.
	 */
	membar(Sync);

	stxa(AA_DMMU_TSB_NEXT_REG, ASI_DMMU, 0);
	stxa(AA_IMMU_TSB_NEXT_REG, ASI_IMMU, 0);
	membar(Sync);

	if (cpu_impl == CPU_IMPL_SPARC64V) {
		/* Ensure MCNTL_JPS1_TSBP is 0. */
		val = ldxa(AA_MCNTL, ASI_MCNTL);
		val &= ~MCNTL_JPS1_TSBP;
		stxa(AA_MCNTL, ASI_MCNTL, val);
		return;
	}

	/*
	 * Configure the first large dTLB to hold 4MB pages (e.g. for direct
	 * mappings) for all three contexts and ensure the second one is set
	 * up to hold 8k pages for them.  Note that this is constraint by
	 * US-IV+, whose large dTLBs can only hold entries of certain page
	 * sizes each.
	 * For US-IV+, additionally ensure that the large iTLB is set up to
	 * hold 8k pages for nucleus and primary context (still no secondary
	 * iMMU context.
	 * NB: according to documentation, changing the page size of the same
	 * context requires a context demap before changing the corresponding
	 * page size, but we hardly can flush our locked pages here, so we use
	 * a demap all instead.
	 */
	stxa(TLB_DEMAP_ALL, ASI_DMMU_DEMAP, 0);
	membar(Sync);
	val = (TS_4M << TLB_PCXR_N_PGSZ0_SHIFT) |
	    (TS_8K << TLB_PCXR_N_PGSZ1_SHIFT) |
	    (TS_4M << TLB_PCXR_P_PGSZ0_SHIFT) |
	    (TS_8K << TLB_PCXR_P_PGSZ1_SHIFT);
	if (cpu_impl == CPU_IMPL_ULTRASPARCIVp)
		val |= (TS_8K << TLB_PCXR_N_PGSZ_I_SHIFT) |
		    (TS_8K << TLB_PCXR_P_PGSZ_I_SHIFT);
	stxa(AA_DMMU_PCXR, ASI_DMMU, val);
	val = (TS_4M << TLB_SCXR_S_PGSZ0_SHIFT) |
	    (TS_8K << TLB_SCXR_S_PGSZ1_SHIFT);
	stxa(AA_DMMU_SCXR, ASI_DMMU, val);
	flush(KERNBASE);

	/*
	 * Ensure DCR_IFPOE is disabled as long as we haven't implemented
	 * support for it (if ever) as most if not all firmware versions
	 * apparently turn it on.  Not making use of DCR_IFPOE should also
	 * avoid Cheetah erratum #109.
	 */
	val = rd(asr18) & ~DCR_IFPOE;
	if (cpu_impl == CPU_IMPL_ULTRASPARCIVp) {
		/*
		 * Ensure the branch prediction mode is set to PC indexing
		 * in order to work around US-IV+ erratum #2.
		 */
		val = (val & ~DCR_BPM_MASK) | DCR_BPM_PC;
		/*
		 * XXX disable dTLB parity error reporting as otherwise we
		 * get seemingly false positives when copying in the user
		 * window by simulating a fill trap on return to usermode in
		 * case single issue is disabled, which thus appears to be
		 * a CPU bug.
		 */
		val &= ~DCR_DTPE;
	}
	wr(asr18, val, 0);
}
Beispiel #18
0
int
watch_phys_active()
{

	return (ldxa(0, ASI_LSU_CTL_REG) & LSU_PW);
}
Beispiel #19
0
/*
 * Flush all user mappings from the TLBs.
 */
void
cheetah_tlb_flush_user(void)
{
	u_long data, tag;
	register_t s;
	u_int i, slot;

	/*
	 * We read ASI_{D,I}TLB_DATA_ACCESS_REG twice back-to-back in order
	 * to work around errata of USIII and beyond.
	 */
	for (i = 0; i < CHEETAH_T16_ENTRIES; i++) {
		slot = TLB_DAR_SLOT(TLB_DAR_T16, i);
		s = intr_disable();
		(void)ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		intr_restore(s);
		tag = ldxa(slot, ASI_DTLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_DTLB_DATA_ACCESS_REG, 0);
		s = intr_disable();
		(void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
		data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
		intr_restore(s);
		tag = ldxa(slot, ASI_ITLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && (data & TD_L) == 0 &&
		    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_ITLB_DATA_ACCESS_REG, 0);
	}
	for (i = 0; i < CHEETAH_DT512_ENTRIES; i++) {
		slot = TLB_DAR_SLOT(TLB_DAR_DT512_0, i);
		s = intr_disable();
		(void)ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		intr_restore(s);
		tag = ldxa(slot, ASI_DTLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_DTLB_DATA_ACCESS_REG, 0);
		slot = TLB_DAR_SLOT(TLB_DAR_DT512_1, i);
		s = intr_disable();
		(void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
		data = ldxa(slot, ASI_DTLB_DATA_ACCESS_REG);
		intr_restore(s);
		tag = ldxa(slot, ASI_DTLB_TAG_READ_REG);
		if ((data & TD_V) != 0 && TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
			stxa_sync(slot, ASI_DTLB_DATA_ACCESS_REG, 0);
	}
	if (PCPU_GET(impl) == CPU_IMPL_ULTRASPARCIVp) {
		for (i = 0; i < CHEETAH_IT512_ENTRIES; i++) {
			slot = TLB_DAR_SLOT(TLB_DAR_IT512, i);
			s = intr_disable();
			(void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
			data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
			intr_restore(s);
			tag = ldxa(slot, ASI_ITLB_TAG_READ_REG);
			if ((data & TD_V) != 0 &&
			    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
				stxa_sync(slot, ASI_ITLB_DATA_ACCESS_REG, 0);
		}
	} else {
		for (i = 0; i < CHEETAH_IT128_ENTRIES; i++) {
			slot = TLB_DAR_SLOT(TLB_DAR_IT128, i);
			s = intr_disable();
			(void)ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
			data = ldxa(slot, ASI_ITLB_DATA_ACCESS_REG);
			tag = ldxa(slot, ASI_ITLB_TAG_READ_REG);
			intr_restore(s);
			if ((data & TD_V) != 0 &&
			    TLB_TAR_CTX(tag) != TLB_CTX_KERNEL)
				stxa_sync(slot, ASI_ITLB_DATA_ACCESS_REG, 0);
		}
	}
}