Loading drivers/irqchip/irq-gic.c +148 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> #include <linux/msm_rtb.h> #ifdef CONFIG_PM #include <linux/syscore_ops.h> #endif #include <asm/cputype.h> #include <asm/irq.h> Loading Loading @@ -90,6 +93,11 @@ struct gic_chip_data { #ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *); #endif #ifdef CONFIG_PM unsigned int irq_offset; unsigned int wakeup_irqs[32]; unsigned int enabled_irqs[32]; #endif }; #ifdef CONFIG_BL_SWITCHER Loading Loading @@ -228,6 +236,116 @@ static void gic_unmask_irq(struct irq_data *d) gic_poke_irq(d, GIC_DIST_ENABLE_SET); } #ifdef CONFIG_PM static DEFINE_RAW_SPINLOCK(irq_controller_lock); #ifndef MAX_GIC_NR #define MAX_GIC_NR 1 #endif static int gic_suspend_one(struct gic_chip_data *gic) { unsigned int i; void __iomem *base = gic_data_dist_base(gic); for (i = 0; i * 32 < gic->gic_irqs; i++) { gic->enabled_irqs[i] = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4); /* disable all of them */ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4); /* enable the wakeup set */ writel_relaxed(gic->wakeup_irqs[i], base + GIC_DIST_ENABLE_SET + i * 4); } /* make sure all gic setting finished */ mb(); return 0; } static int gic_suspend(void) { int i; for (i = 0; i < MAX_GIC_NR; i++) gic_suspend_one(&gic_data[i]); return 0; } static void gic_show_resume_irq(struct gic_chip_data *gic) { unsigned int i; u32 enabled; u32 pending[32]; void __iomem *base = gic_data_dist_base(gic); raw_spin_lock(&irq_controller_lock); for (i = 0; i * 32 < gic->gic_irqs; i++) { enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4); pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4); pending[i] &= enabled; } raw_spin_unlock(&irq_controller_lock); for (i = find_first_bit((unsigned long *)pending, gic->gic_irqs); i < gic->gic_irqs; i = find_next_bit((unsigned long *)pending, gic->gic_irqs, i+1)) { unsigned int irq = irq_find_mapping(gic->domain, i + gic->irq_offset); struct irq_desc *desc = irq_to_desc(irq); const char *name = "null"; if (desc == NULL) name = "stray irq"; else if (desc->action && desc->action->name) name = desc->action->name; pr_warn("%s: %d triggered %s\n", __func__, i + gic->irq_offset, name); } } static void gic_resume_one(struct gic_chip_data *gic) { unsigned int i; void __iomem *base = gic_data_dist_base(gic); gic_show_resume_irq(gic); for (i = 0; i * 32 < gic->gic_irqs; i++) { /* disable all of them */ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4); /* enable the enabled set */ writel_relaxed(gic->enabled_irqs[i], base + GIC_DIST_ENABLE_SET + i * 4); } /* make sure all gic setting finished */ mb(); } static void gic_resume(void) { int i; for (i = 0; i < MAX_GIC_NR; i++) gic_resume_one(&gic_data[i]); } static struct syscore_ops gic_syscore_ops = { .suspend = gic_suspend, .resume = gic_resume, }; static int __init gic_init_sys(void) { register_syscore_ops(&gic_syscore_ops); return 0; } arch_initcall(gic_init_sys); #endif static void gic_eoi_irq(struct irq_data *d) { writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); Loading Loading @@ -351,6 +469,30 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, } #endif #ifdef CONFIG_PM static int gic_set_wake(struct irq_data *d, unsigned int on) { int ret = 0; unsigned int reg_offset, bit_offset; unsigned int gicirq = gic_irq(d); struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); /* per-cpu interrupts cannot be wakeup interrupts */ WARN_ON(gicirq < 32); reg_offset = gicirq / 32; bit_offset = gicirq % 32; if (on) gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset; else gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset); return ret; } #endif static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqstat, irqnr; Loading Loading @@ -425,9 +567,15 @@ static const struct irq_chip gic_chip = { .irq_set_type = gic_set_type, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, #ifdef CONFIG_PM .irq_set_wake = gic_set_wake, .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND, #else .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, #endif }; void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) Loading Loading
drivers/irqchip/irq-gic.c +148 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ #include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> #include <linux/msm_rtb.h> #ifdef CONFIG_PM #include <linux/syscore_ops.h> #endif #include <asm/cputype.h> #include <asm/irq.h> Loading Loading @@ -90,6 +93,11 @@ struct gic_chip_data { #ifdef CONFIG_GIC_NON_BANKED void __iomem *(*get_base)(union gic_base *); #endif #ifdef CONFIG_PM unsigned int irq_offset; unsigned int wakeup_irqs[32]; unsigned int enabled_irqs[32]; #endif }; #ifdef CONFIG_BL_SWITCHER Loading Loading @@ -228,6 +236,116 @@ static void gic_unmask_irq(struct irq_data *d) gic_poke_irq(d, GIC_DIST_ENABLE_SET); } #ifdef CONFIG_PM static DEFINE_RAW_SPINLOCK(irq_controller_lock); #ifndef MAX_GIC_NR #define MAX_GIC_NR 1 #endif static int gic_suspend_one(struct gic_chip_data *gic) { unsigned int i; void __iomem *base = gic_data_dist_base(gic); for (i = 0; i * 32 < gic->gic_irqs; i++) { gic->enabled_irqs[i] = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4); /* disable all of them */ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4); /* enable the wakeup set */ writel_relaxed(gic->wakeup_irqs[i], base + GIC_DIST_ENABLE_SET + i * 4); } /* make sure all gic setting finished */ mb(); return 0; } static int gic_suspend(void) { int i; for (i = 0; i < MAX_GIC_NR; i++) gic_suspend_one(&gic_data[i]); return 0; } static void gic_show_resume_irq(struct gic_chip_data *gic) { unsigned int i; u32 enabled; u32 pending[32]; void __iomem *base = gic_data_dist_base(gic); raw_spin_lock(&irq_controller_lock); for (i = 0; i * 32 < gic->gic_irqs; i++) { enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4); pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4); pending[i] &= enabled; } raw_spin_unlock(&irq_controller_lock); for (i = find_first_bit((unsigned long *)pending, gic->gic_irqs); i < gic->gic_irqs; i = find_next_bit((unsigned long *)pending, gic->gic_irqs, i+1)) { unsigned int irq = irq_find_mapping(gic->domain, i + gic->irq_offset); struct irq_desc *desc = irq_to_desc(irq); const char *name = "null"; if (desc == NULL) name = "stray irq"; else if (desc->action && desc->action->name) name = desc->action->name; pr_warn("%s: %d triggered %s\n", __func__, i + gic->irq_offset, name); } } static void gic_resume_one(struct gic_chip_data *gic) { unsigned int i; void __iomem *base = gic_data_dist_base(gic); gic_show_resume_irq(gic); for (i = 0; i * 32 < gic->gic_irqs; i++) { /* disable all of them */ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4); /* enable the enabled set */ writel_relaxed(gic->enabled_irqs[i], base + GIC_DIST_ENABLE_SET + i * 4); } /* make sure all gic setting finished */ mb(); } static void gic_resume(void) { int i; for (i = 0; i < MAX_GIC_NR; i++) gic_resume_one(&gic_data[i]); } static struct syscore_ops gic_syscore_ops = { .suspend = gic_suspend, .resume = gic_resume, }; static int __init gic_init_sys(void) { register_syscore_ops(&gic_syscore_ops); return 0; } arch_initcall(gic_init_sys); #endif static void gic_eoi_irq(struct irq_data *d) { writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); Loading Loading @@ -351,6 +469,30 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, } #endif #ifdef CONFIG_PM static int gic_set_wake(struct irq_data *d, unsigned int on) { int ret = 0; unsigned int reg_offset, bit_offset; unsigned int gicirq = gic_irq(d); struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d); /* per-cpu interrupts cannot be wakeup interrupts */ WARN_ON(gicirq < 32); reg_offset = gicirq / 32; bit_offset = gicirq % 32; if (on) gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset; else gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset); return ret; } #endif static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) { u32 irqstat, irqnr; Loading Loading @@ -425,9 +567,15 @@ static const struct irq_chip gic_chip = { .irq_set_type = gic_set_type, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, #ifdef CONFIG_PM .irq_set_wake = gic_set_wake, .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_MASK_ON_SUSPEND, #else .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, #endif }; void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) Loading