static int
arm64_start_pmc(int cpu, int ri)
{
	struct pmc_hw *phw;
	uint32_t config;
	struct pmc *pm;

	phw    = &arm64_pcpu[cpu]->pc_arm64pmcs[ri];
	pm     = phw->phw_pmc;
	config = pm->pm_md.pm_arm64.pm_arm64_evsel;

	/*
	 * Configure the event selection.
	 */
	WRITE_SPECIALREG(PMSELR_EL0, ri);
	WRITE_SPECIALREG(PMXEVTYPER_EL0, config);

	isb();

	/*
	 * Enable the PMC.
	 */
	arm64_interrupt_enable(ri);
	arm64_counter_enable(ri);

	return 0;
}
Beispiel #2
0
int
cpu_set_user_tls(struct thread *td, void *tls_base)
{
	struct pcb *pcb;

	if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS)
		return (EINVAL);

	pcb = td->td_pcb;
	if (td->td_frame->tf_spsr & PSR_M_32) {
		/* 32bits arm stores the user TLS into tpidrro */
		pcb->pcb_tpidrro_el0 = (register_t)tls_base;
		pcb->pcb_tpidr_el0 = (register_t)tls_base;
		if (td == curthread) {
			WRITE_SPECIALREG(tpidrro_el0, tls_base);
			WRITE_SPECIALREG(tpidr_el0, tls_base);
		}
	} else {
		pcb->pcb_tpidr_el0 = (register_t)tls_base;
		if (td == curthread)
			WRITE_SPECIALREG(tpidr_el0, tls_base);
	}

	return (0);
}
static void
arm64_pmcn_write(unsigned int pmc, uint32_t reg)
{

	KASSERT(pmc < arm64_npmcs, ("%s: illegal PMC number %d", __func__, pmc));

	WRITE_SPECIALREG(PMSELR_EL0, pmc);
	WRITE_SPECIALREG(PMXEVCNTR_EL0, reg);

	isb();
}
static void
arm64_pmcr_write(uint32_t reg)
{

	WRITE_SPECIALREG(PMCR_EL0, reg);

	isb();
}
/*
 * Counter Set Enable Register
 */
static __inline void
arm64_counter_enable(unsigned int pmc)
{
	uint32_t reg;

	reg = (1 << pmc);
	WRITE_SPECIALREG(PMCNTENSET_EL0, reg);

	isb();
}
/*
 * Interrupt Clear Set Register
 */
static __inline void
arm64_interrupt_disable(uint32_t pmc)
{
	uint32_t reg;

	reg = (1 << pmc);
	WRITE_SPECIALREG(PMINTENCLR_EL1, reg);

	isb();
}
/*
 * Performance Count Register N
 */
static uint32_t
arm64_pmcn_read(unsigned int pmc)
{

	KASSERT(pmc < arm64_npmcs, ("%s: illegal PMC number %d", __func__, pmc));

	WRITE_SPECIALREG(PMSELR_EL0, pmc);

	isb();

	return (READ_SPECIALREG(PMXEVCNTR_EL0));
}
Beispiel #8
0
int
cpu_set_user_tls(struct thread *td, void *tls_base)
{
	struct pcb *pcb;

	if ((uintptr_t)tls_base >= VM_MAXUSER_ADDRESS)
		return (EINVAL);

	pcb = td->td_pcb;
	pcb->pcb_tpidr_el0 = (register_t)tls_base;
	if (td == curthread)
		WRITE_SPECIALREG(tpidr_el0, tls_base);

	return (0);
}
static int
arm64_intr(struct trapframe *tf)
{
	struct arm64_cpu *pc;
	int retval, ri;
	struct pmc *pm;
	int error;
	int reg, cpu;

	cpu = curcpu;
	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
	    ("[arm64,%d] CPU %d out of range", __LINE__, cpu));

	retval = 0;
	pc = arm64_pcpu[cpu];

	for (ri = 0; ri < arm64_npmcs; ri++) {
		pm = arm64_pcpu[cpu]->pc_arm64pmcs[ri].phw_pmc;
		if (pm == NULL)
			continue;
		if (!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
			continue;

		/* Check if counter is overflowed */
		reg = (1 << ri);
		if ((READ_SPECIALREG(PMOVSCLR_EL0) & reg) == 0)
			continue;
		/* Clear Overflow Flag */
		WRITE_SPECIALREG(PMOVSCLR_EL0, reg);

		isb();

		retval = 1; /* Found an interrupting PMC. */
		if (pm->pm_state != PMC_STATE_RUNNING)
			continue;

		error = pmc_process_interrupt(PMC_HR, pm, tf);
		if (error)
			arm64_stop_pmc(cpu, ri);

		/* Reload sampling count */
		arm64_write_pmc(cpu, ri, pm->pm_sc.pm_reloadcount);
	}

	return (retval);
}