diff mbox series

[SRU,jammy/linux-aws,kinetic/linux-aws,20/20] UBUNTU: SAUCE: xen: Restore xen-pirqs on resume from hibernation

Message ID 20220817085150.2078055-25-gerald.yang@canonical.com
State New
Headers show
Series UBUNTU: SAUCE: PM: Hibernate: Enable Hibernation for Xen Based Instance Types | expand

Commit Message

Gerald Yang Aug. 17, 2022, 8:51 a.m. UTC
From: Anchal Agarwal <anchalag@amazon.com>

BugLink: https://bugs.launchpad.net/bugs/1968062

shutdown_pirq is invoked during hibernation path and hence
PIRQs should be restarted during resume. [Commit: xen: Only
restore the ACPI SCI interrupt in xen_restore_pirqs] restores
only ACPI SCI interrupt however, that is not the right thing
to do as all pirqs should be enabled as a part of
resume_device_irqs during suspend/resume device interrupts.
Apparently, chip->irq_startup is called only if IRQD_IRQ_STARTED
is unset during irq_startup on resume. This flag gets cleared by
free_irq->irq_shutdown during suspend.

free_irq() never gets explicitly called for ioapic-edge and
ioapic-level interrupts as respective drivers do nothing during
suspend/resume. So we shut them down explicitly in the first place
in syscore_suspend path to clear IRQ<>event channel mapping.
shutdown_pirq being called explicitly during suspend does not
clear this flags, hence .irq_enable is called in irq_startup
during resume instead and pirq's never start up.

This commit exports irq_state_clr_started API to clear the flag
during shutdown_pirq. Also, following the order in which
ipis/virqs/pirqs are restored during xen resume, the same order
should be followed for hibernation path. As per the flow of
hibernation_platform_enter, we should not restore pirqs explicitly
in syscore_resume ops and it should be done in resume devices path.

Signed-off-by: Anchal Agarwal <anchalag@amazon.com>
(cherry picked from commit f6dd31829fa706ecbcd3ccaa4b5eaab25fe7bf6d amazon-5.15.y/mainline)
Signed-off-by: Gerald Yang <gerald.yang@canonical.com>
Signed-off-by: Matthew Ruffell <matthew.ruffell@canonical.com>
---
 arch/x86/xen/suspend.c           |  1 -
 drivers/xen/events/events_base.c | 42 +-------------------------------
 include/linux/irq.h              |  2 ++
 kernel/irq/chip.c                |  4 +--
 4 files changed, 5 insertions(+), 44 deletions(-)
diff mbox series

Patch

diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index 39644923b623..8be6ffa6bfbe 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -133,7 +133,6 @@  static void xen_syscore_resume(void)
 
 	gnttab_resume();
 
-	xen_restore_pirqs();
 }
 
 /*
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 775af2aa6dc8..7beb5c658ef2 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -2146,50 +2146,10 @@  void xen_shutdown_pirqs(void)
 			continue;
 
 		shutdown_pirq(irq_get_irq_data(info->irq));
+		irq_state_clr_started(irq_to_desc(info->irq));
 	}
 }
 
-/*
- * For now, only restore the ACPI SCI pirq.
- */
-void xen_restore_pirqs(void)
-{
-#ifdef CONFIG_ACPI
-	int pirq, rc, irq, gsi;
-	struct physdev_map_pirq map_irq;
-	struct irq_info *info;
-
-	list_for_each_entry(info, &xen_irq_list_head, list) {
-		if (info->type != IRQT_PIRQ)
-			continue;
-
-		pirq = info->u.pirq.pirq;
-		gsi = info->u.pirq.gsi;
-		irq = info->irq;
-
-		if (gsi != acpi_gbl_FADT.sci_interrupt)
-			continue;
-
-		map_irq.domid = DOMID_SELF;
-		map_irq.type = MAP_PIRQ_TYPE_GSI;
-		map_irq.index = gsi;
-		map_irq.pirq = pirq;
-
-		rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
-		if (rc) {
-			pr_warn("xen: ACPI SCI interrupt map failed, rc=%d\n",
-				rc);
-			xen_free_irq(irq);
-			continue;
-		}
-
-		printk(KERN_DEBUG "xen: restored ACPI SCI interrupt\n");
-
-		__startup_pirq(irq);
-	}
-#endif
-}
-
 static struct irq_chip xen_dynamic_chip __read_mostly = {
 	.name			= "xen-dyn",
 
diff --git a/include/linux/irq.h b/include/linux/irq.h
index c8293c817646..bb28da5d370c 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -811,6 +811,8 @@  extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset,
 				struct msi_desc *entry);
 extern struct irq_data *irq_get_irq_data(unsigned int irq);
 
+extern void irq_state_clr_started(struct irq_desc *desc);
+
 static inline struct irq_chip *irq_get_chip(unsigned int irq)
 {
 	struct irq_data *d = irq_get_irq_data(irq);
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index a98bcfc4be7b..1b1cd3ac5380 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -173,11 +173,11 @@  static void irq_state_clr_masked(struct irq_desc *desc)
 	irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED);
 }
 
-static void irq_state_clr_started(struct irq_desc *desc)
+void irq_state_clr_started(struct irq_desc *desc)
 {
 	irqd_clear(&desc->irq_data, IRQD_IRQ_STARTED);
 }
-
+EXPORT_SYMBOL_GPL(irq_state_clr_started);
 static void irq_state_set_started(struct irq_desc *desc)
 {
 	irqd_set(&desc->irq_data, IRQD_IRQ_STARTED);