blob: 4e43cb204b862479fac6af4d1a5020340bd7073b [file] [log] [blame]
Russell Kingf27ecac2005-08-18 21:31:00 +01001/*
2 * linux/arch/arm/common/gic.c
3 *
4 * Copyright (C) 2002 ARM Limited, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Interrupt architecture for the GIC:
11 *
12 * o There is one Interrupt Distributor, which receives interrupts
13 * from system devices and sends them to the Interrupt Controllers.
14 *
15 * o There is one CPU Interface per CPU, which sends interrupts sent
16 * by the Distributor, and interrupts generated locally, to the
Catalin Marinasb3a1bde2007-02-14 19:14:56 +010017 * associated CPU. The base address of the CPU interface is usually
18 * aliased so that the same address points to different chips depending
19 * on the CPU it is accessed from.
Russell Kingf27ecac2005-08-18 21:31:00 +010020 *
21 * Note that IRQs 0-31 are special - they are local to each CPU.
22 * As such, the enable set/clear, pending set/clear and active bit
23 * registers are banked per-cpu for these sources.
24 */
25#include <linux/init.h>
26#include <linux/kernel.h>
Rob Herring050113e2011-10-21 17:14:27 -050027#include <linux/err.h>
Arnd Bergmann4f874102011-11-01 00:28:37 +010028#include <linux/module.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010029#include <linux/list.h>
30#include <linux/smp.h>
Colin Cross692c3e252011-02-10 12:54:10 -080031#include <linux/cpu_pm.h>
Catalin Marinasdcb86e82005-08-31 21:45:14 +010032#include <linux/cpumask.h>
Russell Kingfced80c2008-09-06 12:10:45 +010033#include <linux/io.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034#include <linux/syscore_ops.h>
Rob Herring0fc0d942011-09-28 21:27:52 -050035#include <linux/of.h>
36#include <linux/of_address.h>
37#include <linux/of_irq.h>
Rob Herringc383e042011-09-28 21:25:31 -050038#include <linux/irqdomain.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010039#include <linux/interrupt.h>
40#include <linux/percpu.h>
41#include <linux/slab.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010042
43#include <asm/irq.h>
Marc Zyngier181621e2011-09-06 09:56:17 +010044#include <asm/exception.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010045#include <asm/mach/irq.h>
46#include <asm/hardware/gic.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#include <asm/system.h>
Trilok Sonieecb28c2011-07-20 16:24:14 +010048#include <asm/localtimer.h>
Russell Kingf27ecac2005-08-18 21:31:00 +010049
Marc Zyngier680392b2011-11-12 16:09:49 +000050union gic_base {
51 void __iomem *common_base;
52 void __percpu __iomem **percpu_base;
53};
54
55struct gic_chip_data {
56 unsigned int irq_offset;
57 union gic_base dist_base;
58 union gic_base cpu_base;
59 unsigned int max_irq;
60#ifdef CONFIG_PM
61 unsigned int wakeup_irqs[32];
62 unsigned int enabled_irqs[32];
63#endif
64#ifdef CONFIG_CPU_PM
65 u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
66 u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
67 u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
Rohit Vaswani26e44862012-01-05 20:26:40 -080068 u32 saved_dist_pri[DIV_ROUND_UP(1020, 4)];
Marc Zyngier680392b2011-11-12 16:09:49 +000069 u32 __percpu *saved_ppi_enable;
70 u32 __percpu *saved_ppi_conf;
71#endif
72#ifdef CONFIG_IRQ_DOMAIN
73 struct irq_domain domain;
74#endif
75 unsigned int gic_irqs;
76#ifdef CONFIG_GIC_NON_BANKED
77 void __iomem *(*get_base)(union gic_base *);
78#endif
79};
80
Thomas Gleixner450ea482009-07-03 08:44:46 -050081static DEFINE_RAW_SPINLOCK(irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +010082
Rohit Vaswani26e44862012-01-05 20:26:40 -080083#ifdef CONFIG_CPU_PM
84static unsigned int saved_dist_ctrl, saved_cpu_ctrl;
85#endif
86
Russell Kingff2e27a2010-12-04 16:13:29 +000087/* Address of GIC 0 CPU interface */
Russell Kingbef8f9e2010-12-04 16:50:58 +000088void __iomem *gic_cpu_base_addr __read_mostly;
Russell Kingff2e27a2010-12-04 16:13:29 +000089
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010090/*
91 * Supported arch specific GIC irq extension.
92 * Default make them NULL.
93 */
94struct irq_chip gic_arch_extn = {
Will Deacon1a017532011-02-09 12:01:12 +000095 .irq_eoi = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +010096 .irq_mask = NULL,
97 .irq_unmask = NULL,
98 .irq_retrigger = NULL,
99 .irq_set_type = NULL,
100 .irq_set_wake = NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700101 .irq_disable = NULL,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100102};
103
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100104#ifndef MAX_GIC_NR
105#define MAX_GIC_NR 1
106#endif
107
Russell Kingbef8f9e2010-12-04 16:50:58 +0000108static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100109
Marc Zyngier680392b2011-11-12 16:09:49 +0000110#ifdef CONFIG_GIC_NON_BANKED
111static void __iomem *gic_get_percpu_base(union gic_base *base)
112{
113 return *__this_cpu_ptr(base->percpu_base);
114}
115
116static void __iomem *gic_get_common_base(union gic_base *base)
117{
118 return base->common_base;
119}
120
121static inline void __iomem *gic_data_dist_base(struct gic_chip_data *data)
122{
123 return data->get_base(&data->dist_base);
124}
125
126static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
127{
128 return data->get_base(&data->cpu_base);
129}
130
131static inline void gic_set_base_accessor(struct gic_chip_data *data,
132 void __iomem *(*f)(union gic_base *))
133{
134 data->get_base = f;
135}
136#else
137#define gic_data_dist_base(d) ((d)->dist_base.common_base)
138#define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
139#define gic_set_base_accessor(d,f)
140#endif
141
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100142static inline void __iomem *gic_dist_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100143{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100144 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngier680392b2011-11-12 16:09:49 +0000145 return gic_data_dist_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100146}
147
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100148static inline void __iomem *gic_cpu_base(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100149{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100150 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
Marc Zyngier680392b2011-11-12 16:09:49 +0000151 return gic_data_cpu_base(gic_data);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100152}
153
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100154static inline unsigned int gic_irq(struct irq_data *d)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100155{
Rob Herringc383e042011-09-28 21:25:31 -0500156 return d->hwirq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100157}
158
Taniya Dasb241bd82012-03-19 17:58:06 +0530159#if defined(CONFIG_CPU_V7) && defined(CONFIG_GIC_SECURE)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800160static const inline bool is_cpu_secure(void)
161{
162 unsigned int dscr;
163
164 asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (dscr));
165
166 /* BIT(18) - NS bit; 1 = NS; 0 = S */
167 if (BIT(18) & dscr)
168 return false;
169 else
170 return true;
171}
172#else
173static const inline bool is_cpu_secure(void)
174{
175 return false;
176}
177#endif
178
Russell Kingf27ecac2005-08-18 21:31:00 +0100179/*
180 * Routines to acknowledge, disable and enable interrupts
Russell Kingf27ecac2005-08-18 21:31:00 +0100181 */
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100182static void gic_mask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100183{
Rob Herringc383e042011-09-28 21:25:31 -0500184 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100185
Thomas Gleixner450ea482009-07-03 08:44:46 -0500186 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530187 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100188 if (gic_arch_extn.irq_mask)
189 gic_arch_extn.irq_mask(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500190 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100191}
192
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100193static void gic_unmask_irq(struct irq_data *d)
Russell Kingf27ecac2005-08-18 21:31:00 +0100194{
Rob Herringc383e042011-09-28 21:25:31 -0500195 u32 mask = 1 << (gic_irq(d) % 32);
Thomas Gleixnerc4bfa282006-07-01 22:32:14 +0100196
Thomas Gleixner450ea482009-07-03 08:44:46 -0500197 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100198 if (gic_arch_extn.irq_unmask)
199 gic_arch_extn.irq_unmask(d);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530200 writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500201 raw_spin_unlock(&irq_controller_lock);
Russell Kingf27ecac2005-08-18 21:31:00 +0100202}
203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700204static void gic_disable_irq(struct irq_data *d)
205{
206 if (gic_arch_extn.irq_disable)
207 gic_arch_extn.irq_disable(d);
208}
209
210#ifdef CONFIG_PM
211static int gic_suspend_one(struct gic_chip_data *gic)
212{
213 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000214 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215
216 for (i = 0; i * 32 < gic->max_irq; i++) {
217 gic->enabled_irqs[i]
218 = readl_relaxed(base + GIC_DIST_ENABLE_SET + i * 4);
219 /* disable all of them */
220 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
221 /* enable the wakeup set */
222 writel_relaxed(gic->wakeup_irqs[i],
223 base + GIC_DIST_ENABLE_SET + i * 4);
224 }
225 mb();
226 return 0;
227}
228
229static int gic_suspend(void)
230{
231 int i;
232 for (i = 0; i < MAX_GIC_NR; i++)
233 gic_suspend_one(&gic_data[i]);
234 return 0;
235}
236
237extern int msm_show_resume_irq_mask;
238
239static void gic_show_resume_irq(struct gic_chip_data *gic)
240{
241 unsigned int i;
242 u32 enabled;
243 unsigned long pending[32];
Marc Zyngier680392b2011-11-12 16:09:49 +0000244 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245
246 if (!msm_show_resume_irq_mask)
247 return;
248
Thomas Gleixner450ea482009-07-03 08:44:46 -0500249 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 for (i = 0; i * 32 < gic->max_irq; i++) {
251 enabled = readl_relaxed(base + GIC_DIST_ENABLE_CLEAR + i * 4);
252 pending[i] = readl_relaxed(base + GIC_DIST_PENDING_SET + i * 4);
253 pending[i] &= enabled;
254 }
Thomas Gleixner450ea482009-07-03 08:44:46 -0500255 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256
257 for (i = find_first_bit(pending, gic->max_irq);
258 i < gic->max_irq;
259 i = find_next_bit(pending, gic->max_irq, i+1)) {
260 pr_warning("%s: %d triggered", __func__,
261 i + gic->irq_offset);
262 }
263}
264
265static void gic_resume_one(struct gic_chip_data *gic)
266{
267 unsigned int i;
Marc Zyngier680392b2011-11-12 16:09:49 +0000268 void __iomem *base = gic_data_dist_base(gic);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700269
270 gic_show_resume_irq(gic);
271 for (i = 0; i * 32 < gic->max_irq; i++) {
272 /* disable all of them */
273 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4);
274 /* enable the enabled set */
275 writel_relaxed(gic->enabled_irqs[i],
276 base + GIC_DIST_ENABLE_SET + i * 4);
277 }
278 mb();
279}
280
281static void gic_resume(void)
282{
283 int i;
284 for (i = 0; i < MAX_GIC_NR; i++)
285 gic_resume_one(&gic_data[i]);
286}
287
288static struct syscore_ops gic_syscore_ops = {
289 .suspend = gic_suspend,
290 .resume = gic_resume,
291};
292
293static int __init gic_init_sys(void)
294{
295 register_syscore_ops(&gic_syscore_ops);
296 return 0;
297}
298arch_initcall(gic_init_sys);
299
300#endif
301
Will Deacon1a017532011-02-09 12:01:12 +0000302static void gic_eoi_irq(struct irq_data *d)
303{
304 if (gic_arch_extn.irq_eoi) {
Thomas Gleixner450ea482009-07-03 08:44:46 -0500305 raw_spin_lock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000306 gic_arch_extn.irq_eoi(d);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500307 raw_spin_unlock(&irq_controller_lock);
Will Deacon1a017532011-02-09 12:01:12 +0000308 }
309
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530310 writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
Will Deacon1a017532011-02-09 12:01:12 +0000311}
312
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100313static int gic_set_type(struct irq_data *d, unsigned int type)
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100314{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100315 void __iomem *base = gic_dist_base(d);
316 unsigned int gicirq = gic_irq(d);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100317 u32 enablemask = 1 << (gicirq % 32);
318 u32 enableoff = (gicirq / 32) * 4;
319 u32 confmask = 0x2 << ((gicirq % 16) * 2);
320 u32 confoff = (gicirq / 16) * 4;
321 bool enabled = false;
322 u32 val;
323
324 /* Interrupt configuration for SGIs can't be changed */
325 if (gicirq < 16)
326 return -EINVAL;
327
328 if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
329 return -EINVAL;
330
Thomas Gleixner450ea482009-07-03 08:44:46 -0500331 raw_spin_lock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100332
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100333 if (gic_arch_extn.irq_set_type)
334 gic_arch_extn.irq_set_type(d, type);
335
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530336 val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100337 if (type == IRQ_TYPE_LEVEL_HIGH)
338 val &= ~confmask;
339 else if (type == IRQ_TYPE_EDGE_RISING)
340 val |= confmask;
341
342 /*
343 * As recommended by the spec, disable the interrupt before changing
344 * the configuration
345 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530346 if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
347 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100348 enabled = true;
349 }
350
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530351 writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100352
353 if (enabled)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530354 writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100355
Thomas Gleixner450ea482009-07-03 08:44:46 -0500356 raw_spin_unlock(&irq_controller_lock);
Rabin Vincent5c0c1f02010-05-28 04:37:38 +0100357
358 return 0;
359}
360
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100361static int gic_retrigger(struct irq_data *d)
362{
363 if (gic_arch_extn.irq_retrigger)
364 return gic_arch_extn.irq_retrigger(d);
365
Abhijeet Dharmapurikar9d44ea02011-10-30 16:47:19 -0700366 /* the retrigger expects 0 for failure */
367 return 0;
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100368}
369
Catalin Marinasa06f5462005-09-30 16:07:05 +0100370#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000371static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
372 bool force)
Russell Kingf27ecac2005-08-18 21:31:00 +0100373{
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100374 void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
Rob Herringc383e042011-09-28 21:25:31 -0500375 unsigned int shift = (gic_irq(d) % 4) * 8;
Russell Kingf3c52e22011-07-21 15:00:57 +0100376 unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
Russell Kingc1917892011-01-23 12:12:01 +0000377 u32 val, mask, bit;
378
Russell Kingf3c52e22011-07-21 15:00:57 +0100379 if (cpu >= 8 || cpu >= nr_cpu_ids)
Russell Kingc1917892011-01-23 12:12:01 +0000380 return -EINVAL;
381
382 mask = 0xff << shift;
Will Deacona803a8d2011-08-23 22:20:03 +0100383 bit = 1 << (cpu_logical_map(cpu) + shift);
Russell Kingf27ecac2005-08-18 21:31:00 +0100384
Thomas Gleixner450ea482009-07-03 08:44:46 -0500385 raw_spin_lock(&irq_controller_lock);
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530386 val = readl_relaxed(reg) & ~mask;
387 writel_relaxed(val | bit, reg);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500388 raw_spin_unlock(&irq_controller_lock);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700389
Russell Kingf3c52e22011-07-21 15:00:57 +0100390 return IRQ_SET_MASK_OK;
Russell Kingf27ecac2005-08-18 21:31:00 +0100391}
Catalin Marinasa06f5462005-09-30 16:07:05 +0100392#endif
Russell Kingf27ecac2005-08-18 21:31:00 +0100393
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100394#ifdef CONFIG_PM
395static int gic_set_wake(struct irq_data *d, unsigned int on)
396{
397 int ret = -ENXIO;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 unsigned int reg_offset, bit_offset;
399 unsigned int gicirq = gic_irq(d);
400 struct gic_chip_data *gic_data = irq_data_get_irq_chip_data(d);
401
402 /* per-cpu interrupts cannot be wakeup interrupts */
403 WARN_ON(gicirq < 32);
404
405 reg_offset = gicirq / 32;
406 bit_offset = gicirq % 32;
407
408 if (on)
409 gic_data->wakeup_irqs[reg_offset] |= 1 << bit_offset;
410 else
411 gic_data->wakeup_irqs[reg_offset] &= ~(1 << bit_offset);
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100412
413 if (gic_arch_extn.irq_set_wake)
414 ret = gic_arch_extn.irq_set_wake(d, on);
415
416 return ret;
417}
418
419#else
Rohit Vaswani550aa1a2011-10-06 21:15:37 -0700420static int gic_set_wake(struct irq_data *d, unsigned int on)
421{
422 return 0;
423}
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100424#endif
425
Marc Zyngier181621e2011-09-06 09:56:17 +0100426asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
427{
428 u32 irqstat, irqnr;
429 struct gic_chip_data *gic = &gic_data[0];
430 void __iomem *cpu_base = gic_data_cpu_base(gic);
431
432 do {
433 irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
434 irqnr = irqstat & ~0x1c00;
435
436 if (likely(irqnr > 15 && irqnr < 1021)) {
437 irqnr = irq_domain_to_irq(&gic->domain, irqnr);
438 handle_IRQ(irqnr, regs);
439 continue;
440 }
441 if (irqnr < 16) {
442 writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
443#ifdef CONFIG_SMP
444 handle_IPI(irqnr, regs);
445#endif
446 continue;
447 }
448 break;
449 } while (1);
450}
451
Russell King0f347bb2007-05-17 10:11:34 +0100452static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100453{
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100454 struct gic_chip_data *chip_data = irq_get_handler_data(irq);
455 struct irq_chip *chip = irq_get_chip(irq);
Russell King0f347bb2007-05-17 10:11:34 +0100456 unsigned int cascade_irq, gic_irq;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100457 unsigned long status;
458
Will Deacon1a017532011-02-09 12:01:12 +0000459 chained_irq_enter(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100460
Thomas Gleixner450ea482009-07-03 08:44:46 -0500461 raw_spin_lock(&irq_controller_lock);
Marc Zyngier680392b2011-11-12 16:09:49 +0000462 status = readl_relaxed(gic_data_cpu_base(chip_data) + GIC_CPU_INTACK);
Thomas Gleixner450ea482009-07-03 08:44:46 -0500463 raw_spin_unlock(&irq_controller_lock);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100464
Russell King0f347bb2007-05-17 10:11:34 +0100465 gic_irq = (status & 0x3ff);
466 if (gic_irq == 1023)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100467 goto out;
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100468
Rob Herringc383e042011-09-28 21:25:31 -0500469 cascade_irq = irq_domain_to_irq(&chip_data->domain, gic_irq);
Russell King0f347bb2007-05-17 10:11:34 +0100470 if (unlikely(gic_irq < 32 || gic_irq > 1020 || cascade_irq >= NR_IRQS))
471 do_bad_IRQ(cascade_irq, desc);
472 else
473 generic_handle_irq(cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100474
475 out:
Will Deacon1a017532011-02-09 12:01:12 +0000476 chained_irq_exit(chip, desc);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100477}
478
David Brownell38c677c2006-08-01 22:26:25 +0100479static struct irq_chip gic_chip = {
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100480 .name = "GIC",
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100481 .irq_mask = gic_mask_irq,
482 .irq_unmask = gic_unmask_irq,
Will Deacon1a017532011-02-09 12:01:12 +0000483 .irq_eoi = gic_eoi_irq,
Lennert Buytenhek7d1f4282010-11-29 10:18:20 +0100484 .irq_set_type = gic_set_type,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100485 .irq_retrigger = gic_retrigger,
Russell Kingf27ecac2005-08-18 21:31:00 +0100486#ifdef CONFIG_SMP
Russell Kingc1917892011-01-23 12:12:01 +0000487 .irq_set_affinity = gic_set_affinity,
Russell Kingf27ecac2005-08-18 21:31:00 +0100488#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700489 .irq_disable = gic_disable_irq,
Santosh Shilimkard7ed36a2011-03-02 08:03:22 +0100490 .irq_set_wake = gic_set_wake,
Russell Kingf27ecac2005-08-18 21:31:00 +0100491};
492
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100493void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
494{
495 if (gic_nr >= MAX_GIC_NR)
496 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100497 if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100498 BUG();
Thomas Gleixner6845664a2011-03-24 13:25:22 +0100499 irq_set_chained_handler(irq, gic_handle_cascade_irq);
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100500}
501
Rob Herringc383e042011-09-28 21:25:31 -0500502static void __init gic_dist_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100503{
Rob Herringc383e042011-09-28 21:25:31 -0500504 unsigned int i, irq;
Will Deacona803a8d2011-08-23 22:20:03 +0100505 u32 cpumask;
Rob Herringc383e042011-09-28 21:25:31 -0500506 unsigned int gic_irqs = gic->gic_irqs;
507 struct irq_domain *domain = &gic->domain;
Marc Zyngier680392b2011-11-12 16:09:49 +0000508 void __iomem *base = gic_data_dist_base(gic);
Will Deacona803a8d2011-08-23 22:20:03 +0100509 u32 cpu = 0;
Russell Kingf27ecac2005-08-18 21:31:00 +0100510
Will Deacona803a8d2011-08-23 22:20:03 +0100511#ifdef CONFIG_SMP
512 cpu = cpu_logical_map(smp_processor_id());
513#endif
514
515 cpumask = 1 << cpu;
Russell Kingf27ecac2005-08-18 21:31:00 +0100516 cpumask |= cpumask << 8;
517 cpumask |= cpumask << 16;
518
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530519 writel_relaxed(0, base + GIC_DIST_CTRL);
Russell Kingf27ecac2005-08-18 21:31:00 +0100520
521 /*
Russell Kingf27ecac2005-08-18 21:31:00 +0100522 * Set all global interrupts to be level triggered, active low.
523 */
Pawel Molle6afec92010-11-26 13:45:43 +0100524 for (i = 32; i < gic_irqs; i += 16)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530525 writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
Russell Kingf27ecac2005-08-18 21:31:00 +0100526
527 /*
528 * Set all global interrupts to this CPU only.
529 */
Pawel Molle6afec92010-11-26 13:45:43 +0100530 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530531 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100532
533 /*
Rohit Vaswani26e44862012-01-05 20:26:40 -0800534 * Set NS/S.
535 */
536 if (is_cpu_secure())
537 for (i = 32; i < gic_irqs; i += 32)
538 writel_relaxed(0xFFFFFFFF,
539 base + GIC_DIST_ISR + i * 4 / 32);
540
541 /*
Russell King9395f6e2010-11-11 23:10:30 +0000542 * Set priority on all global interrupts.
Russell Kingf27ecac2005-08-18 21:31:00 +0100543 */
Pawel Molle6afec92010-11-26 13:45:43 +0100544 for (i = 32; i < gic_irqs; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530545 writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
Russell Kingf27ecac2005-08-18 21:31:00 +0100546
547 /*
Russell King9395f6e2010-11-11 23:10:30 +0000548 * Disable all interrupts. Leave the PPI and SGIs alone
549 * as these enables are banked registers.
Russell Kingf27ecac2005-08-18 21:31:00 +0100550 */
Pawel Molle6afec92010-11-26 13:45:43 +0100551 for (i = 32; i < gic_irqs; i += 32)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530552 writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
Russell Kingf27ecac2005-08-18 21:31:00 +0100553
554 /*
555 * Setup the Linux IRQ subsystem.
556 */
Rob Herringc383e042011-09-28 21:25:31 -0500557 irq_domain_for_each_irq(domain, i, irq) {
558 if (i < 32) {
559 irq_set_percpu_devid(irq);
560 irq_set_chip_and_handler(irq, &gic_chip,
561 handle_percpu_devid_irq);
562 set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
563 } else {
564 irq_set_chip_and_handler(irq, &gic_chip,
565 handle_fasteoi_irq);
566 set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
567 }
568 irq_set_chip_data(irq, gic);
Russell Kingf27ecac2005-08-18 21:31:00 +0100569 }
570
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700571 gic->max_irq = gic_irqs;
572
Rohit Vaswani26e44862012-01-05 20:26:40 -0800573 if (is_cpu_secure())
574 writel_relaxed(3, base + GIC_DIST_CTRL);
575 else
576 writel_relaxed(1, base + GIC_DIST_CTRL);
577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100579}
580
Russell Kingbef8f9e2010-12-04 16:50:58 +0000581static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
Russell Kingf27ecac2005-08-18 21:31:00 +0100582{
Marc Zyngier680392b2011-11-12 16:09:49 +0000583 void __iomem *dist_base = gic_data_dist_base(gic);
584 void __iomem *base = gic_data_cpu_base(gic);
Russell King9395f6e2010-11-11 23:10:30 +0000585 int i;
586
Russell King9395f6e2010-11-11 23:10:30 +0000587 /*
588 * Deal with the banked PPI and SGI interrupts - disable all
589 * PPI interrupts, ensure all SGI interrupts are enabled.
590 */
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530591 writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
592 writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
Russell King9395f6e2010-11-11 23:10:30 +0000593
Rohit Vaswani26e44862012-01-05 20:26:40 -0800594 /* Set NS/S */
595 if (is_cpu_secure())
596 writel_relaxed(0xFFFFFFFF, dist_base + GIC_DIST_ISR);
597
Russell King9395f6e2010-11-11 23:10:30 +0000598 /*
599 * Set priority on PPI and SGI interrupts
600 */
601 for (i = 0; i < 32; i += 4)
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530602 writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
Russell King9395f6e2010-11-11 23:10:30 +0000603
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530604 writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800605
606 if (is_cpu_secure())
607 writel_relaxed(0xF, base + GIC_CPU_CTRL);
608 else
609 writel_relaxed(1, base + GIC_CPU_CTRL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100611}
612
Colin Cross692c3e252011-02-10 12:54:10 -0800613#ifdef CONFIG_CPU_PM
614/*
615 * Saves the GIC distributor registers during suspend or idle. Must be called
616 * with interrupts disabled but before powering down the GIC. After calling
617 * this function, no interrupts will be delivered by the GIC, and another
618 * platform-specific wakeup source must be enabled.
619 */
620static void gic_dist_save(unsigned int gic_nr)
621{
622 unsigned int gic_irqs;
623 void __iomem *dist_base;
624 int i;
625
626 if (gic_nr >= MAX_GIC_NR)
627 BUG();
628
629 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngier680392b2011-11-12 16:09:49 +0000630 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800631
632 if (!dist_base)
633 return;
634
Rohit Vaswani26e44862012-01-05 20:26:40 -0800635 saved_dist_ctrl = readl_relaxed(dist_base + GIC_DIST_CTRL);
636
Colin Cross692c3e252011-02-10 12:54:10 -0800637 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
638 gic_data[gic_nr].saved_spi_conf[i] =
639 readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
640
641 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
642 gic_data[gic_nr].saved_spi_target[i] =
643 readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
644
Rohit Vaswani26e44862012-01-05 20:26:40 -0800645 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
646 gic_data[gic_nr].saved_dist_pri[i] =
647 readl_relaxed(dist_base + GIC_DIST_PRI + i * 4);
648
Colin Cross692c3e252011-02-10 12:54:10 -0800649 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
650 gic_data[gic_nr].saved_spi_enable[i] =
651 readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
652}
653
654/*
655 * Restores the GIC distributor registers during resume or when coming out of
656 * idle. Must be called before enabling interrupts. If a level interrupt
657 * that occured while the GIC was suspended is still present, it will be
658 * handled normally, but any edge interrupts that occured will not be seen by
659 * the GIC and need to be handled by the platform-specific wakeup source.
660 */
661static void gic_dist_restore(unsigned int gic_nr)
662{
663 unsigned int gic_irqs;
664 unsigned int i;
665 void __iomem *dist_base;
666
667 if (gic_nr >= MAX_GIC_NR)
668 BUG();
669
670 gic_irqs = gic_data[gic_nr].gic_irqs;
Marc Zyngier680392b2011-11-12 16:09:49 +0000671 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800672
673 if (!dist_base)
674 return;
675
676 writel_relaxed(0, dist_base + GIC_DIST_CTRL);
677
678 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
679 writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
680 dist_base + GIC_DIST_CONFIG + i * 4);
681
682 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800683 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
Colin Cross692c3e252011-02-10 12:54:10 -0800684 dist_base + GIC_DIST_PRI + i * 4);
685
686 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
687 writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
688 dist_base + GIC_DIST_TARGET + i * 4);
689
690 for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
691 writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
692 dist_base + GIC_DIST_ENABLE_SET + i * 4);
693
Rohit Vaswani26e44862012-01-05 20:26:40 -0800694 writel_relaxed(saved_dist_ctrl, dist_base + GIC_DIST_CTRL);
Colin Cross692c3e252011-02-10 12:54:10 -0800695}
696
697static void gic_cpu_save(unsigned int gic_nr)
698{
699 int i;
700 u32 *ptr;
701 void __iomem *dist_base;
702 void __iomem *cpu_base;
703
704 if (gic_nr >= MAX_GIC_NR)
705 BUG();
706
Marc Zyngier680392b2011-11-12 16:09:49 +0000707 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
708 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800709
710 if (!dist_base || !cpu_base)
711 return;
712
Rohit Vaswani26e44862012-01-05 20:26:40 -0800713 saved_cpu_ctrl = readl_relaxed(cpu_base + GIC_CPU_CTRL);
714
715 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
716 gic_data[gic_nr].saved_dist_pri[i] = readl_relaxed(dist_base +
717 GIC_DIST_PRI + i * 4);
718
Colin Cross692c3e252011-02-10 12:54:10 -0800719 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
720 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
721 ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
722
723 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
724 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
725 ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
726
727}
728
729static void gic_cpu_restore(unsigned int gic_nr)
730{
731 int i;
732 u32 *ptr;
733 void __iomem *dist_base;
734 void __iomem *cpu_base;
735
736 if (gic_nr >= MAX_GIC_NR)
737 BUG();
738
Marc Zyngier680392b2011-11-12 16:09:49 +0000739 dist_base = gic_data_dist_base(&gic_data[gic_nr]);
740 cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
Colin Cross692c3e252011-02-10 12:54:10 -0800741
742 if (!dist_base || !cpu_base)
743 return;
744
745 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
746 for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
747 writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
748
749 ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
750 for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
751 writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
752
753 for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
Rohit Vaswani26e44862012-01-05 20:26:40 -0800754 writel_relaxed(gic_data[gic_nr].saved_dist_pri[i],
755 dist_base + GIC_DIST_PRI + i * 4);
Colin Cross692c3e252011-02-10 12:54:10 -0800756
757 writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
Rohit Vaswani26e44862012-01-05 20:26:40 -0800758 writel_relaxed(saved_cpu_ctrl, cpu_base + GIC_CPU_CTRL);
Colin Cross692c3e252011-02-10 12:54:10 -0800759}
760
761static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
762{
763 int i;
764
765 for (i = 0; i < MAX_GIC_NR; i++) {
Marc Zyngier680392b2011-11-12 16:09:49 +0000766#ifdef CONFIG_GIC_NON_BANKED
767 /* Skip over unused GICs */
768 if (!gic_data[i].get_base)
769 continue;
770#endif
Colin Cross692c3e252011-02-10 12:54:10 -0800771 switch (cmd) {
772 case CPU_PM_ENTER:
773 gic_cpu_save(i);
774 break;
775 case CPU_PM_ENTER_FAILED:
776 case CPU_PM_EXIT:
777 gic_cpu_restore(i);
778 break;
779 case CPU_CLUSTER_PM_ENTER:
780 gic_dist_save(i);
781 break;
782 case CPU_CLUSTER_PM_ENTER_FAILED:
783 case CPU_CLUSTER_PM_EXIT:
784 gic_dist_restore(i);
785 break;
786 }
787 }
788
789 return NOTIFY_OK;
790}
791
792static struct notifier_block gic_notifier_block = {
793 .notifier_call = gic_notifier,
794};
795
796static void __init gic_pm_init(struct gic_chip_data *gic)
797{
798 gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
799 sizeof(u32));
800 BUG_ON(!gic->saved_ppi_enable);
801
802 gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
803 sizeof(u32));
804 BUG_ON(!gic->saved_ppi_conf);
805
806 cpu_pm_register_notifier(&gic_notifier_block);
807}
808#else
809static void __init gic_pm_init(struct gic_chip_data *gic)
810{
811}
812#endif
813
Rob Herring0fc0d942011-09-28 21:27:52 -0500814#ifdef CONFIG_OF
815static int gic_irq_domain_dt_translate(struct irq_domain *d,
816 struct device_node *controller,
817 const u32 *intspec, unsigned int intsize,
818 unsigned long *out_hwirq, unsigned int *out_type)
819{
820 if (d->of_node != controller)
821 return -EINVAL;
822 if (intsize < 3)
823 return -EINVAL;
824
825 /* Get the interrupt number and add 16 to skip over SGIs */
826 *out_hwirq = intspec[1] + 16;
827
828 /* For SPIs, we need to add 16 more to get the GIC irq ID number */
829 if (!intspec[0])
830 *out_hwirq += 16;
831
832 *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
833 return 0;
834}
835#endif
836
Rob Herringc383e042011-09-28 21:25:31 -0500837const struct irq_domain_ops gic_irq_domain_ops = {
Rob Herring0fc0d942011-09-28 21:27:52 -0500838#ifdef CONFIG_OF
839 .dt_translate = gic_irq_domain_dt_translate,
840#endif
Rob Herringc383e042011-09-28 21:25:31 -0500841};
842
Marc Zyngier680392b2011-11-12 16:09:49 +0000843void __init gic_init_bases(unsigned int gic_nr, int irq_start,
844 void __iomem *dist_base, void __iomem *cpu_base,
845 u32 percpu_offset)
Russell Kingb580b892010-12-04 15:55:14 +0000846{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000847 struct gic_chip_data *gic;
Rob Herringc383e042011-09-28 21:25:31 -0500848 struct irq_domain *domain;
Michael Bohan33efecf2012-01-12 15:32:21 -0800849 int gic_irqs, rc;
Russell Kingbef8f9e2010-12-04 16:50:58 +0000850
851 BUG_ON(gic_nr >= MAX_GIC_NR);
852
853 gic = &gic_data[gic_nr];
Rob Herringc383e042011-09-28 21:25:31 -0500854 domain = &gic->domain;
Marc Zyngier680392b2011-11-12 16:09:49 +0000855#ifdef CONFIG_GIC_NON_BANKED
856 if (percpu_offset) { /* Frankein-GIC without banked registers... */
857 unsigned int cpu;
858
859 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
860 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
861 if (WARN_ON(!gic->dist_base.percpu_base ||
Michael Bohan33efecf2012-01-12 15:32:21 -0800862 !gic->cpu_base.percpu_base))
863 goto init_bases_err;
Marc Zyngier680392b2011-11-12 16:09:49 +0000864
865 for_each_possible_cpu(cpu) {
866 unsigned long offset = percpu_offset * cpu_logical_map(cpu);
867 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
868 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
869 }
870
871 gic_set_base_accessor(gic, gic_get_percpu_base);
872 } else
873#endif
874 { /* Normal, sane GIC... */
875 WARN(percpu_offset,
876 "GIC_NON_BANKED not enabled, ignoring %08x offset!",
877 percpu_offset);
878 gic->dist_base.common_base = dist_base;
879 gic->cpu_base.common_base = cpu_base;
880 gic_set_base_accessor(gic, gic_get_common_base);
881 }
Russell Kingbef8f9e2010-12-04 16:50:58 +0000882
Rob Herringc383e042011-09-28 21:25:31 -0500883 /*
884 * For primary GICs, skip over SGIs.
885 * For secondary GICs, skip over PPIs, too.
886 */
887 if (gic_nr == 0) {
Russell Kingff2e27a2010-12-04 16:13:29 +0000888 gic_cpu_base_addr = cpu_base;
Rob Herringc383e042011-09-28 21:25:31 -0500889 domain->hwirq_base = 16;
Rob Herring050113e2011-10-21 17:14:27 -0500890 if (irq_start > 0)
891 irq_start = (irq_start & ~31) + 16;
Rob Herringc383e042011-09-28 21:25:31 -0500892 } else
893 domain->hwirq_base = 32;
894
895 /*
896 * Find out how many interrupts are supported.
897 * The GIC only supports up to 1020 interrupt sources.
898 */
Marc Zyngier680392b2011-11-12 16:09:49 +0000899 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
Rob Herringc383e042011-09-28 21:25:31 -0500900 gic_irqs = (gic_irqs + 1) * 32;
901 if (gic_irqs > 1020)
902 gic_irqs = 1020;
903 gic->gic_irqs = gic_irqs;
904
905 domain->nr_irq = gic_irqs - domain->hwirq_base;
Rob Herring050113e2011-10-21 17:14:27 -0500906 domain->irq_base = irq_alloc_descs(irq_start, 16, domain->nr_irq,
Rob Herringc383e042011-09-28 21:25:31 -0500907 numa_node_id());
Rob Herring050113e2011-10-21 17:14:27 -0500908 if (IS_ERR_VALUE(domain->irq_base)) {
909 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
910 irq_start);
911 domain->irq_base = irq_start;
912 }
Rob Herringc383e042011-09-28 21:25:31 -0500913 domain->priv = gic;
914 domain->ops = &gic_irq_domain_ops;
Michael Bohan33efecf2012-01-12 15:32:21 -0800915 rc = irq_domain_add(domain);
916 if (rc) {
917 WARN(1, "Unable to create irq_domain\n");
918 goto init_bases_err;
919 }
Michael Bohanb8635c32012-01-05 18:32:10 -0800920 irq_domain_register(domain);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000921
Colin Cross692c3e252011-02-10 12:54:10 -0800922 gic_chip.flags |= gic_arch_extn.flags;
Rob Herringc383e042011-09-28 21:25:31 -0500923 gic_dist_init(gic);
Russell Kingbef8f9e2010-12-04 16:50:58 +0000924 gic_cpu_init(gic);
Colin Cross692c3e252011-02-10 12:54:10 -0800925 gic_pm_init(gic);
Michael Bohan33efecf2012-01-12 15:32:21 -0800926
927 return;
928
929init_bases_err:
930 free_percpu(gic->dist_base.percpu_base);
931 free_percpu(gic->cpu_base.percpu_base);
Russell Kingb580b892010-12-04 15:55:14 +0000932}
933
Russell King38489532010-12-04 16:01:03 +0000934void __cpuinit gic_secondary_init(unsigned int gic_nr)
935{
Russell Kingbef8f9e2010-12-04 16:50:58 +0000936 BUG_ON(gic_nr >= MAX_GIC_NR);
937
938 gic_cpu_init(&gic_data[gic_nr]);
Russell King38489532010-12-04 16:01:03 +0000939}
940
Russell Kingf27ecac2005-08-18 21:31:00 +0100941#ifdef CONFIG_SMP
Russell King82668102009-05-17 16:20:18 +0100942void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
Russell Kingf27ecac2005-08-18 21:31:00 +0100943{
Will Deacona803a8d2011-08-23 22:20:03 +0100944 int cpu;
Rohit Vaswani26e44862012-01-05 20:26:40 -0800945 unsigned long sgir;
Will Deacona803a8d2011-08-23 22:20:03 +0100946 unsigned long map = 0;
947
948 /* Convert our logical CPU mask into a physical one. */
949 for_each_cpu(cpu, mask)
950 map |= 1 << cpu_logical_map(cpu);
Russell Kingf27ecac2005-08-18 21:31:00 +0100951
Rohit Vaswani26e44862012-01-05 20:26:40 -0800952 sgir = (map << 16) | irq;
953 if (is_cpu_secure())
954 sgir |= (1 << 15);
955
Santosh Shilimkar6ac77e42011-03-28 19:27:46 +0530956 /*
957 * Ensure that stores to Normal memory are visible to the
958 * other CPUs before issuing the IPI.
959 */
960 dsb();
961
Catalin Marinasb3a1bde2007-02-14 19:14:56 +0100962 /* this always happens on GIC0 */
Rohit Vaswani26e44862012-01-05 20:26:40 -0800963 writel_relaxed(sgir,
964 gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965 mb();
Russell Kingf27ecac2005-08-18 21:31:00 +0100966}
967#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968
Rohit Vaswani26e44862012-01-05 20:26:40 -0800969void gic_set_irq_secure(unsigned int irq)
970{
971 unsigned int gicd_isr_reg, gicd_pri_reg;
972 unsigned int mask = 0xFFFFFF00;
973 struct gic_chip_data *gic_data = &gic_data[0];
974 struct irq_data *d = irq_get_irq_data(irq);
975
976 if (is_cpu_secure()) {
977 raw_spin_lock(&irq_controller_lock);
978 gicd_isr_reg = readl_relaxed(gic_dist_base(d) +
979 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
980 gicd_isr_reg &= ~BIT(gic_irq(d) % 32);
981 writel_relaxed(gicd_isr_reg, gic_dist_base(d) +
982 GIC_DIST_ISR + gic_irq(d) / 32 * 4);
983 /* Also increase the priority of that irq */
984 gicd_pri_reg = readl_relaxed(gic_dist_base(d) +
985 GIC_DIST_PRI + (gic_irq(d) * 4 / 4));
986 gicd_pri_reg &= mask;
987 gicd_pri_reg |= 0x80; /* Priority of 0x80 > 0xA0 */
988 writel_relaxed(gicd_pri_reg, gic_dist_base(d) + GIC_DIST_PRI +
989 gic_irq(d) * 4 / 4);
990 mb();
991 raw_spin_unlock(&irq_controller_lock);
992 } else {
993 WARN(1, "Trying to run secure operation from Non-secure mode");
994 }
995}
996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997/* before calling this function the interrupts should be disabled
998 * and the irq must be disabled at gic to avoid spurious interrupts */
999bool gic_is_spi_pending(unsigned int irq)
1000{
1001 struct irq_data *d = irq_get_irq_data(irq);
1002 struct gic_chip_data *gic_data = &gic_data[0];
1003 u32 mask, val;
1004
1005 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001006 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007 mask = 1 << (gic_irq(d) % 32);
1008 val = readl(gic_dist_base(d) +
1009 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1010 /* warn if the interrupt is enabled */
1011 WARN_ON(val & mask);
1012 val = readl(gic_dist_base(d) +
1013 GIC_DIST_PENDING_SET + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001014 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 return (bool) (val & mask);
1016}
1017
1018/* before calling this function the interrupts should be disabled
1019 * and the irq must be disabled at gic to avoid spurious interrupts */
1020void gic_clear_spi_pending(unsigned int irq)
1021{
1022 struct gic_chip_data *gic_data = &gic_data[0];
1023 struct irq_data *d = irq_get_irq_data(irq);
1024
1025 u32 mask, val;
1026 WARN_ON(!irqs_disabled());
Thomas Gleixner450ea482009-07-03 08:44:46 -05001027 raw_spin_lock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 mask = 1 << (gic_irq(d) % 32);
1029 val = readl(gic_dist_base(d) +
1030 GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
1031 /* warn if the interrupt is enabled */
1032 WARN_ON(val & mask);
1033 writel(mask, gic_dist_base(d) +
1034 GIC_DIST_PENDING_CLEAR + (gic_irq(d) / 32) * 4);
Thomas Gleixner450ea482009-07-03 08:44:46 -05001035 raw_spin_unlock(&irq_controller_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036}
Rob Herring0fc0d942011-09-28 21:27:52 -05001037#ifdef CONFIG_OF
1038static int gic_cnt __initdata = 0;
1039
1040int __init gic_of_init(struct device_node *node, struct device_node *parent)
1041{
1042 void __iomem *cpu_base;
1043 void __iomem *dist_base;
Marc Zyngier680392b2011-11-12 16:09:49 +00001044 u32 percpu_offset;
Rob Herring0fc0d942011-09-28 21:27:52 -05001045 int irq;
1046 struct irq_domain *domain = &gic_data[gic_cnt].domain;
1047
1048 if (WARN_ON(!node))
1049 return -ENODEV;
1050
1051 dist_base = of_iomap(node, 0);
1052 WARN(!dist_base, "unable to map gic dist registers\n");
1053
1054 cpu_base = of_iomap(node, 1);
1055 WARN(!cpu_base, "unable to map gic cpu registers\n");
1056
Marc Zyngier680392b2011-11-12 16:09:49 +00001057 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
1058 percpu_offset = 0;
1059
Rob Herring0fc0d942011-09-28 21:27:52 -05001060 domain->of_node = of_node_get(node);
1061
Marc Zyngier680392b2011-11-12 16:09:49 +00001062 gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset);
Rob Herring0fc0d942011-09-28 21:27:52 -05001063
1064 if (parent) {
1065 irq = irq_of_parse_and_map(node, 0);
1066 gic_cascade_irq(gic_cnt, irq);
1067 }
1068 gic_cnt++;
1069 return 0;
1070}
1071#endif