irqchip: armada-370-xp: Add suspend/resume support
This commit adds suspend/resume support to the irqchip driver used on Armada XP platforms (amongst others). It does so by adding a set of suspend/resume syscore_ops, that will respectively save and restore the necessary registers to ensure interrupts continue to work after resume. It is worth mentioning that the affinity is lost during a suspend/resume cycle, because when a secondary CPU is brought off-line, all interrupts that are assigned to this CPU in terms of affinity gets re-assigned to a still running CPU. Therefore, right before entering suspend, all interrupts are assigned to the boot CPU. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jason Cooper <jason@lakedaemon.net> Cc: linux-kernel@vger.kernel.org Link: https://lkml.kernel.org/r/1416585613-2113-4-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
This commit is contained in:
parent
e92293a2a7
commit
0f077eb5cf
|
@ -26,6 +26,7 @@
|
||||||
#include <linux/of_pci.h>
|
#include <linux/of_pci.h>
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/syscore_ops.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
#include <asm/exception.h>
|
#include <asm/exception.h>
|
||||||
|
@ -66,6 +67,7 @@
|
||||||
static void __iomem *per_cpu_int_base;
|
static void __iomem *per_cpu_int_base;
|
||||||
static void __iomem *main_int_base;
|
static void __iomem *main_int_base;
|
||||||
static struct irq_domain *armada_370_xp_mpic_domain;
|
static struct irq_domain *armada_370_xp_mpic_domain;
|
||||||
|
static u32 doorbell_mask_reg;
|
||||||
#ifdef CONFIG_PCI_MSI
|
#ifdef CONFIG_PCI_MSI
|
||||||
static struct irq_domain *armada_370_xp_msi_domain;
|
static struct irq_domain *armada_370_xp_msi_domain;
|
||||||
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
|
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
|
||||||
|
@ -474,6 +476,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int armada_370_xp_mpic_suspend(void)
|
||||||
|
{
|
||||||
|
doorbell_mask_reg = readl(per_cpu_int_base +
|
||||||
|
ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void armada_370_xp_mpic_resume(void)
|
||||||
|
{
|
||||||
|
int nirqs;
|
||||||
|
irq_hw_number_t irq;
|
||||||
|
|
||||||
|
/* Re-enable interrupts */
|
||||||
|
nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
|
||||||
|
for (irq = 0; irq < nirqs; irq++) {
|
||||||
|
struct irq_data *data;
|
||||||
|
int virq;
|
||||||
|
|
||||||
|
virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
|
||||||
|
if (virq == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
|
||||||
|
writel(irq, per_cpu_int_base +
|
||||||
|
ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
||||||
|
else
|
||||||
|
writel(irq, main_int_base +
|
||||||
|
ARMADA_370_XP_INT_SET_ENABLE_OFFS);
|
||||||
|
|
||||||
|
data = irq_get_irq_data(virq);
|
||||||
|
if (!irqd_irq_disabled(data))
|
||||||
|
armada_370_xp_irq_unmask(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reconfigure doorbells for IPIs and MSIs */
|
||||||
|
writel(doorbell_mask_reg,
|
||||||
|
per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
|
||||||
|
if (doorbell_mask_reg & IPI_DOORBELL_MASK)
|
||||||
|
writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
||||||
|
if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
|
||||||
|
writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct syscore_ops armada_370_xp_mpic_syscore_ops = {
|
||||||
|
.suspend = armada_370_xp_mpic_suspend,
|
||||||
|
.resume = armada_370_xp_mpic_resume,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init armada_370_xp_mpic_of_init(struct device_node *node,
|
static int __init armada_370_xp_mpic_of_init(struct device_node *node,
|
||||||
struct device_node *parent)
|
struct device_node *parent)
|
||||||
{
|
{
|
||||||
|
@ -530,6 +580,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
|
||||||
armada_370_xp_mpic_handle_cascade_irq);
|
armada_370_xp_mpic_handle_cascade_irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue