aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/events/intel/core.c109
1 files changed, 60 insertions, 49 deletions
diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c
index 035c37481f57..9b320a51f82f 100644
--- a/arch/x86/events/intel/core.c
+++ b/arch/x86/events/intel/core.c
@@ -2200,59 +2200,15 @@ static void intel_pmu_reset(void)
2200 local_irq_restore(flags); 2200 local_irq_restore(flags);
2201} 2201}
2202 2202
2203/* 2203static int handle_pmi_common(struct pt_regs *regs, u64 status)
2204 * This handler is triggered by the local APIC, so the APIC IRQ handling
2205 * rules apply:
2206 */
2207static int intel_pmu_handle_irq(struct pt_regs *regs)
2208{ 2204{
2209 struct perf_sample_data data; 2205 struct perf_sample_data data;
2210 struct cpu_hw_events *cpuc; 2206 struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
2211 int bit, loops; 2207 int bit;
2212 u64 status; 2208 int handled = 0;
2213 int handled;
2214 int pmu_enabled;
2215
2216 cpuc = this_cpu_ptr(&cpu_hw_events);
2217
2218 /*
2219 * Save the PMU state.
2220 * It needs to be restored when leaving the handler.
2221 */
2222 pmu_enabled = cpuc->enabled;
2223 /*
2224 * No known reason to not always do late ACK,
2225 * but just in case do it opt-in.
2226 */
2227 if (!x86_pmu.late_ack)
2228 apic_write(APIC_LVTPC, APIC_DM_NMI);
2229 intel_bts_disable_local();
2230 cpuc->enabled = 0;
2231 __intel_pmu_disable_all();
2232 handled = intel_pmu_drain_bts_buffer();
2233 handled += intel_bts_interrupt();
2234 status = intel_pmu_get_status();
2235 if (!status)
2236 goto done;
2237
2238 loops = 0;
2239again:
2240 intel_pmu_lbr_read();
2241 intel_pmu_ack_status(status);
2242 if (++loops > 100) {
2243 static bool warned = false;
2244 if (!warned) {
2245 WARN(1, "perfevents: irq loop stuck!\n");
2246 perf_event_print_debug();
2247 warned = true;
2248 }
2249 intel_pmu_reset();
2250 goto done;
2251 }
2252 2209
2253 inc_irq_stat(apic_perf_irqs); 2210 inc_irq_stat(apic_perf_irqs);
2254 2211
2255
2256 /* 2212 /*
2257 * Ignore a range of extra bits in status that do not indicate 2213 * Ignore a range of extra bits in status that do not indicate
2258 * overflow by themselves. 2214 * overflow by themselves.
@@ -2261,7 +2217,7 @@ again:
2261 GLOBAL_STATUS_ASIF | 2217 GLOBAL_STATUS_ASIF |
2262 GLOBAL_STATUS_LBRS_FROZEN); 2218 GLOBAL_STATUS_LBRS_FROZEN);
2263 if (!status) 2219 if (!status)
2264 goto done; 2220 return 0;
2265 /* 2221 /*
2266 * In case multiple PEBS events are sampled at the same time, 2222 * In case multiple PEBS events are sampled at the same time,
2267 * it is possible to have GLOBAL_STATUS bit 62 set indicating 2223 * it is possible to have GLOBAL_STATUS bit 62 set indicating
@@ -2331,6 +2287,61 @@ again:
2331 x86_pmu_stop(event, 0); 2287 x86_pmu_stop(event, 0);
2332 } 2288 }
2333 2289
2290 return handled;
2291}
2292
2293/*
2294 * This handler is triggered by the local APIC, so the APIC IRQ handling
2295 * rules apply:
2296 */
2297static int intel_pmu_handle_irq(struct pt_regs *regs)
2298{
2299 struct cpu_hw_events *cpuc;
2300 int loops;
2301 u64 status;
2302 int handled;
2303 int pmu_enabled;
2304
2305 cpuc = this_cpu_ptr(&cpu_hw_events);
2306
2307 /*
2308 * Save the PMU state.
2309 * It needs to be restored when leaving the handler.
2310 */
2311 pmu_enabled = cpuc->enabled;
2312 /*
2313 * No known reason to not always do late ACK,
2314 * but just in case do it opt-in.
2315 */
2316 if (!x86_pmu.late_ack)
2317 apic_write(APIC_LVTPC, APIC_DM_NMI);
2318 intel_bts_disable_local();
2319 cpuc->enabled = 0;
2320 __intel_pmu_disable_all();
2321 handled = intel_pmu_drain_bts_buffer();
2322 handled += intel_bts_interrupt();
2323 status = intel_pmu_get_status();
2324 if (!status)
2325 goto done;
2326
2327 loops = 0;
2328again:
2329 intel_pmu_lbr_read();
2330 intel_pmu_ack_status(status);
2331 if (++loops > 100) {
2332 static bool warned;
2333
2334 if (!warned) {
2335 WARN(1, "perfevents: irq loop stuck!\n");
2336 perf_event_print_debug();
2337 warned = true;
2338 }
2339 intel_pmu_reset();
2340 goto done;
2341 }
2342
2343 handled += handle_pmi_common(regs, status);
2344
2334 /* 2345 /*
2335 * Repeat if there is more work to be done: 2346 * Repeat if there is more work to be done:
2336 */ 2347 */