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; }
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)); }
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); }