mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-27 08:50:17 +00:00
hv_exc: Make IPI/IRQ/timer/PMC emulation storage per-CPU
Signed-off-by: Hector Martin <marcan@marcan.st>
This commit is contained in:
parent
290e851d98
commit
184a516367
1 changed files with 23 additions and 18 deletions
41
src/hv_exc.c
41
src/hv_exc.c
|
@ -17,10 +17,14 @@ extern spinlock_t bhl;
|
||||||
((op2) << ESR_ISS_MSR_OP2_SHIFT))
|
((op2) << ESR_ISS_MSR_OP2_SHIFT))
|
||||||
#define SYSREG_ISS(...) _SYSREG_ISS(__VA_ARGS__)
|
#define SYSREG_ISS(...) _SYSREG_ISS(__VA_ARGS__)
|
||||||
|
|
||||||
bool ipi_pending = false;
|
#define D_PERCPU(t, x) t x[MAX_CPUS]
|
||||||
bool pmc_pending = false;
|
#define PERCPU(x) x[mrs(TPIDR_EL2)]
|
||||||
u64 pmc_irq_mode = 0;
|
|
||||||
static u64 exc_entry_pmcr0_cnt;
|
D_PERCPU(static bool, ipi_pending);
|
||||||
|
D_PERCPU(static bool, pmc_pending);
|
||||||
|
D_PERCPU(static u64, pmc_irq_mode);
|
||||||
|
|
||||||
|
D_PERCPU(static u64, exc_entry_pmcr0_cnt);
|
||||||
|
|
||||||
void hv_exit_guest(void) __attribute__((noreturn));
|
void hv_exit_guest(void) __attribute__((noreturn));
|
||||||
|
|
||||||
|
@ -97,7 +101,7 @@ static void hv_update_fiq(void)
|
||||||
reg_set(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENA_ENA_V);
|
reg_set(SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2, VM_TMR_FIQ_ENA_ENA_V);
|
||||||
}
|
}
|
||||||
|
|
||||||
fiq_pending |= ipi_pending || pmc_pending;
|
fiq_pending |= PERCPU(ipi_pending) || PERCPU(pmc_pending);
|
||||||
|
|
||||||
sysop("isb");
|
sysop("isb");
|
||||||
|
|
||||||
|
@ -166,20 +170,21 @@ static bool hv_handle_msr(u64 *regs, u64 iss)
|
||||||
SYSREG_PASS(SYS_IMP_APL_IPI_CR_EL1)
|
SYSREG_PASS(SYS_IMP_APL_IPI_CR_EL1)
|
||||||
case SYSREG_ISS(SYS_IMP_APL_IPI_SR_EL1):
|
case SYSREG_ISS(SYS_IMP_APL_IPI_SR_EL1):
|
||||||
if (is_read)
|
if (is_read)
|
||||||
regs[rt] = ipi_pending ? IPI_SR_PENDING : 0;
|
regs[rt] = PERCPU(ipi_pending) ? IPI_SR_PENDING : 0;
|
||||||
else if (regs[rt] & IPI_SR_PENDING)
|
else if (regs[rt] & IPI_SR_PENDING)
|
||||||
ipi_pending = false;
|
PERCPU(ipi_pending) = false;
|
||||||
return true;
|
return true;
|
||||||
/* shadow the interrupt mode and state flag */
|
/* shadow the interrupt mode and state flag */
|
||||||
case SYSREG_ISS(SYS_IMP_APL_PMCR0):
|
case SYSREG_ISS(SYS_IMP_APL_PMCR0):
|
||||||
if (is_read) {
|
if (is_read) {
|
||||||
u64 val = (mrs(SYS_IMP_APL_PMCR0) & ~PMCR0_IMODE_MASK) | pmc_irq_mode;
|
u64 val = (mrs(SYS_IMP_APL_PMCR0) & ~PMCR0_IMODE_MASK) | PERCPU(pmc_irq_mode);
|
||||||
regs[rt] = val | (pmc_pending ? PMCR0_IACT : 0) | exc_entry_pmcr0_cnt;
|
regs[rt] =
|
||||||
|
val | (PERCPU(pmc_pending) ? PMCR0_IACT : 0) | PERCPU(exc_entry_pmcr0_cnt);
|
||||||
} else {
|
} else {
|
||||||
pmc_pending = !!(regs[rt] & PMCR0_IACT);
|
PERCPU(pmc_pending) = !!(regs[rt] & PMCR0_IACT);
|
||||||
pmc_irq_mode = regs[rt] & PMCR0_IMODE_MASK;
|
PERCPU(pmc_irq_mode) = regs[rt] & PMCR0_IMODE_MASK;
|
||||||
exc_entry_pmcr0_cnt = regs[rt] & PMCR0_CNT_MASK;
|
PERCPU(exc_entry_pmcr0_cnt) = regs[rt] & PMCR0_CNT_MASK;
|
||||||
msr(SYS_IMP_APL_PMCR0, regs[rt] & ~exc_entry_pmcr0_cnt);
|
msr(SYS_IMP_APL_PMCR0, regs[rt] & ~PERCPU(exc_entry_pmcr0_cnt));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
#ifdef DEBUG_PMU_IRQ
|
#ifdef DEBUG_PMU_IRQ
|
||||||
|
@ -211,7 +216,7 @@ static void hv_exc_entry(u64 *regs)
|
||||||
exc_entry_time = mrs(CNTPCT_EL0);
|
exc_entry_time = mrs(CNTPCT_EL0);
|
||||||
/* disable PMU counters in the hypervisor */
|
/* disable PMU counters in the hypervisor */
|
||||||
u64 pmcr0 = mrs(SYS_IMP_APL_PMCR0);
|
u64 pmcr0 = mrs(SYS_IMP_APL_PMCR0);
|
||||||
exc_entry_pmcr0_cnt = pmcr0 & PMCR0_CNT_MASK;
|
PERCPU(exc_entry_pmcr0_cnt) = pmcr0 & PMCR0_CNT_MASK;
|
||||||
msr(SYS_IMP_APL_PMCR0, pmcr0 & ~PMCR0_CNT_MASK);
|
msr(SYS_IMP_APL_PMCR0, pmcr0 & ~PMCR0_CNT_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +225,8 @@ static void hv_exc_exit(u64 *regs)
|
||||||
UNUSED(regs);
|
UNUSED(regs);
|
||||||
hv_wdt_breadcrumb('x');
|
hv_wdt_breadcrumb('x');
|
||||||
hv_update_fiq();
|
hv_update_fiq();
|
||||||
/* reenabale PMU counters */
|
/* reenable PMU counters */
|
||||||
reg_set(SYS_IMP_APL_PMCR0, exc_entry_pmcr0_cnt);
|
reg_set(SYS_IMP_APL_PMCR0, PERCPU(exc_entry_pmcr0_cnt));
|
||||||
u64 lost = mrs(CNTPCT_EL0) - exc_entry_time;
|
u64 lost = mrs(CNTPCT_EL0) - exc_entry_time;
|
||||||
if (lost > 8)
|
if (lost > 8)
|
||||||
stolen_time += lost - 8;
|
stolen_time += lost - 8;
|
||||||
|
@ -298,7 +303,7 @@ void hv_exc_fiq(u64 *regs)
|
||||||
printf("[FIQ] PMC IRQ, masking and delivering to the guest\n");
|
printf("[FIQ] PMC IRQ, masking and delivering to the guest\n");
|
||||||
#endif
|
#endif
|
||||||
reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK);
|
reg_clr(SYS_IMP_APL_PMCR0, PMCR0_IACT | PMCR0_IMODE_MASK);
|
||||||
pmc_pending = true;
|
PERCPU(pmc_pending) = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
reg = mrs(SYS_IMP_APL_UPMCR0);
|
reg = mrs(SYS_IMP_APL_UPMCR0);
|
||||||
|
@ -309,7 +314,7 @@ void hv_exc_fiq(u64 *regs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) {
|
if (mrs(SYS_IMP_APL_IPI_SR_EL1) & IPI_SR_PENDING) {
|
||||||
ipi_pending = true;
|
PERCPU(ipi_pending) = true;
|
||||||
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
msr(SYS_IMP_APL_IPI_SR_EL1, IPI_SR_PENDING);
|
||||||
sysop("isb");
|
sysop("isb");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue