Commit dcbb816a authored by Sean Christopherson's avatar Sean Christopherson Committed by Paolo Bonzini

KVM: x86/pmu: Clear "reprogram" bit if counter is disabled or disallowed

When reprogramming a counter, clear the counter's "reprogram pending" bit
if the counter is disabled (by the guest) or is disallowed (by the
userspace filter).  In both cases, there's no need to re-attempt
programming on the next coincident KVM_REQ_PMU as enabling the counter by
either method will trigger reprogramming.
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Message-Id: <20220923001355.3741194-3-seanjc@google.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent f1c5651f
...@@ -150,9 +150,9 @@ static void kvm_perf_overflow(struct perf_event *perf_event, ...@@ -150,9 +150,9 @@ static void kvm_perf_overflow(struct perf_event *perf_event,
__kvm_perf_overflow(pmc, true); __kvm_perf_overflow(pmc, true);
} }
static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config,
u64 config, bool exclude_user, bool exclude_user, bool exclude_kernel,
bool exclude_kernel, bool intr) bool intr)
{ {
struct kvm_pmu *pmu = pmc_to_pmu(pmc); struct kvm_pmu *pmu = pmc_to_pmu(pmc);
struct perf_event *event; struct perf_event *event;
...@@ -204,14 +204,14 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, ...@@ -204,14 +204,14 @@ static void pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type,
if (IS_ERR(event)) { if (IS_ERR(event)) {
pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n", pr_debug_ratelimited("kvm_pmu: event creation failed %ld for pmc->idx = %d\n",
PTR_ERR(event), pmc->idx); PTR_ERR(event), pmc->idx);
return; return PTR_ERR(event);
} }
pmc->perf_event = event; pmc->perf_event = event;
pmc_to_pmu(pmc)->event_count++; pmc_to_pmu(pmc)->event_count++;
clear_bit(pmc->idx, pmc_to_pmu(pmc)->reprogram_pmi);
pmc->is_paused = false; pmc->is_paused = false;
pmc->intr = intr || pebs; pmc->intr = intr || pebs;
return 0;
} }
static void pmc_pause_counter(struct kvm_pmc *pmc) static void pmc_pause_counter(struct kvm_pmc *pmc)
...@@ -245,7 +245,6 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc) ...@@ -245,7 +245,6 @@ static bool pmc_resume_counter(struct kvm_pmc *pmc)
perf_event_enable(pmc->perf_event); perf_event_enable(pmc->perf_event);
pmc->is_paused = false; pmc->is_paused = false;
clear_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->reprogram_pmi);
return true; return true;
} }
...@@ -303,10 +302,10 @@ void reprogram_counter(struct kvm_pmc *pmc) ...@@ -303,10 +302,10 @@ void reprogram_counter(struct kvm_pmc *pmc)
pmc_pause_counter(pmc); pmc_pause_counter(pmc);
if (!pmc_speculative_in_use(pmc) || !pmc_is_enabled(pmc)) if (!pmc_speculative_in_use(pmc) || !pmc_is_enabled(pmc))
return; goto reprogram_complete;
if (!check_pmu_event_filter(pmc)) if (!check_pmu_event_filter(pmc))
return; goto reprogram_complete;
if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL) if (eventsel & ARCH_PERFMON_EVENTSEL_PIN_CONTROL)
printk_once("kvm pmu: pin control bit is ignored\n"); printk_once("kvm pmu: pin control bit is ignored\n");
...@@ -324,16 +323,27 @@ void reprogram_counter(struct kvm_pmc *pmc) ...@@ -324,16 +323,27 @@ void reprogram_counter(struct kvm_pmc *pmc)
} }
if (pmc->current_config == new_config && pmc_resume_counter(pmc)) if (pmc->current_config == new_config && pmc_resume_counter(pmc))
return; goto reprogram_complete;
pmc_release_perf_event(pmc); pmc_release_perf_event(pmc);
pmc->current_config = new_config; pmc->current_config = new_config;
pmc_reprogram_counter(pmc, PERF_TYPE_RAW,
(eventsel & pmu->raw_event_mask), /*
!(eventsel & ARCH_PERFMON_EVENTSEL_USR), * If reprogramming fails, e.g. due to contention, leave the counter's
!(eventsel & ARCH_PERFMON_EVENTSEL_OS), * regprogram bit set, i.e. opportunistically try again on the next PMU
eventsel & ARCH_PERFMON_EVENTSEL_INT); * refresh. Don't make a new request as doing so can stall the guest
* if reprogramming repeatedly fails.
*/
if (pmc_reprogram_counter(pmc, PERF_TYPE_RAW,
(eventsel & pmu->raw_event_mask),
!(eventsel & ARCH_PERFMON_EVENTSEL_USR),
!(eventsel & ARCH_PERFMON_EVENTSEL_OS),
eventsel & ARCH_PERFMON_EVENTSEL_INT))
return;
reprogram_complete:
clear_bit(pmc->idx, (unsigned long *)&pmc_to_pmu(pmc)->reprogram_pmi);
} }
EXPORT_SYMBOL_GPL(reprogram_counter); EXPORT_SYMBOL_GPL(reprogram_counter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment