aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-07-31 16:07:09 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-08-01 07:02:37 -0400
commitbb68cfe2f5a7f43058aed299fdbb73eb281734ed (patch)
tree04ad72d536b8ea36b546524952a41111ef0d0a6b
parent16f73eb02d7e1765ccab3d2018e0bd98eb93d973 (diff)
x86/hpet: Cure interface abuse in the resume path
The HPET resume path abuses irq_domain_[de]activate_irq() to restore the MSI message in the HPET chip for the boot CPU on resume and it relies on an implementation detail of the interrupt core code, which magically makes the HPET unmask call invoked via a irq_disable/enable pair. This worked as long as the irq code did unconditionally invoke the unmask() callback. With the recent changes which keep track of the masked state to avoid expensive hardware access, this does not longer work. As a consequence the HPET timer interrupts are not unmasked which breaks resume as the boot CPU waits forever that a timer interrupt arrives. Make the restore of the MSI message explicit and invoke the unmask() function directly. While at it get rid of the pointless affinity setting as nothing can change the affinity of the interrupt and the vector across suspend/resume. The restore of the MSI message reestablishes the previous affinity setting which is the correct one. Fixes: bf22ff45bed6 ("genirq: Avoid unnecessary low level irq function calls") Reported-and-tested-by: Tomi Sarvela <tomi.p.sarvela@intel.com> Reported-by: Martin Peres <martin.peres@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com> Cc: jeffy.chen@rock-chips.com Cc: Peter Zijlstra <peterz@infradead.org> Cc: Marc Zyngier <marc.zyngier@arm.com> Link: http://lkml.kernel.org/r/alpine.DEB.2.20.1707312158590.2287@nanos
-rw-r--r--arch/x86/kernel/hpet.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 16f82a3aaec7..8ce4212e2b8d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -345,21 +345,10 @@ static int hpet_shutdown(struct clock_event_device *evt, int timer)
345 return 0; 345 return 0;
346} 346}
347 347
348static int hpet_resume(struct clock_event_device *evt, int timer) 348static int hpet_resume(struct clock_event_device *evt)
349{ 349{
350 if (!timer) { 350 hpet_enable_legacy_int();
351 hpet_enable_legacy_int();
352 } else {
353 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
354
355 irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
356 irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
357 disable_hardirq(hdev->irq);
358 irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
359 enable_irq(hdev->irq);
360 }
361 hpet_print_config(); 351 hpet_print_config();
362
363 return 0; 352 return 0;
364} 353}
365 354
@@ -417,7 +406,7 @@ static int hpet_legacy_set_periodic(struct clock_event_device *evt)
417 406
418static int hpet_legacy_resume(struct clock_event_device *evt) 407static int hpet_legacy_resume(struct clock_event_device *evt)
419{ 408{
420 return hpet_resume(evt, 0); 409 return hpet_resume(evt);
421} 410}
422 411
423static int hpet_legacy_next_event(unsigned long delta, 412static int hpet_legacy_next_event(unsigned long delta,
@@ -510,8 +499,14 @@ static int hpet_msi_set_periodic(struct clock_event_device *evt)
510static int hpet_msi_resume(struct clock_event_device *evt) 499static int hpet_msi_resume(struct clock_event_device *evt)
511{ 500{
512 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt); 501 struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
502 struct irq_data *data = irq_get_irq_data(hdev->irq);
503 struct msi_msg msg;
513 504
514 return hpet_resume(evt, hdev->num); 505 /* Restore the MSI msg and unmask the interrupt */
506 irq_chip_compose_msi_msg(data, &msg);
507 hpet_msi_write(hdev, &msg);
508 hpet_msi_unmask(data);
509 return 0;
515} 510}
516 511
517static int hpet_msi_next_event(unsigned long delta, 512static int hpet_msi_next_event(unsigned long delta,