Blame view
drivers/irqchip/irq-armada-370-xp.c
15.8 KB
9ae6f740b arm: mach-mvebu: ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/* * Marvell Armada 370 and Armada XP SoC IRQ handling * * Copyright (C) 2012 Marvell * * Lior Amsalem <alior@marvell.com> * Gregory CLEMENT <gregory.clement@free-electrons.com> * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> * Ben Dooks <ben.dooks@codethink.co.uk> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> |
41a83e06e irqchip: Prepare ... |
21 |
#include <linux/irqchip.h> |
bc69b8adf irqchip: armada-3... |
22 |
#include <linux/irqchip/chained_irq.h> |
d7df84b3c irqchip: irq-arma... |
23 |
#include <linux/cpu.h> |
9ae6f740b arm: mach-mvebu: ... |
24 25 26 |
#include <linux/io.h> #include <linux/of_address.h> #include <linux/of_irq.h> |
31f614edb irqchip: armada-3... |
27 |
#include <linux/of_pci.h> |
9ae6f740b arm: mach-mvebu: ... |
28 |
#include <linux/irqdomain.h> |
31f614edb irqchip: armada-3... |
29 |
#include <linux/slab.h> |
0f077eb5c irqchip: armada-3... |
30 |
#include <linux/syscore_ops.h> |
31f614edb irqchip: armada-3... |
31 |
#include <linux/msi.h> |
9ae6f740b arm: mach-mvebu: ... |
32 33 |
#include <asm/mach/arch.h> #include <asm/exception.h> |
344e873e5 arm: mvebu: Add I... |
34 |
#include <asm/smp_plat.h> |
9339d432f irqchip: move IRQ... |
35 |
#include <asm/mach/irq.h> |
9ae6f740b arm: mach-mvebu: ... |
36 37 38 |
/* Interrupt Controller Registers Map */ #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) |
28da06dfd irqchip: armada-3... |
39 40 |
#define ARMADA_370_XP_INT_FABRIC_MASK_OFFS (0x54) #define ARMADA_370_XP_INT_CAUSE_PERF(cpu) (1 << cpu) |
9ae6f740b arm: mach-mvebu: ... |
41 |
|
f3e16ccd0 ARM: mvebu: MPIC:... |
42 |
#define ARMADA_370_XP_INT_CONTROL (0x00) |
9ae6f740b arm: mach-mvebu: ... |
43 44 |
#define ARMADA_370_XP_INT_SET_ENABLE_OFFS (0x30) #define ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS (0x34) |
3202bf015 arm: mvebu: Impro... |
45 |
#define ARMADA_370_XP_INT_SOURCE_CTL(irq) (0x100 + irq*4) |
8cc3cfc5c irqchip: armanda:... |
46 |
#define ARMADA_370_XP_INT_SOURCE_CPU_MASK 0xF |
758e83667 irqchip: armada-3... |
47 |
#define ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid) ((BIT(0) | BIT(8)) << cpuid) |
9ae6f740b arm: mach-mvebu: ... |
48 49 |
#define ARMADA_370_XP_CPU_INTACK_OFFS (0x44) |
bc69b8adf irqchip: armada-3... |
50 |
#define ARMADA_375_PPI_CAUSE (0x10) |
9ae6f740b arm: mach-mvebu: ... |
51 |
|
344e873e5 arm: mvebu: Add I... |
52 53 54 |
#define ARMADA_370_XP_SW_TRIG_INT_OFFS (0x4) #define ARMADA_370_XP_IN_DRBEL_MSK_OFFS (0xc) #define ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS (0x8) |
3202bf015 arm: mvebu: Impro... |
55 |
#define ARMADA_370_XP_MAX_PER_CPU_IRQS (28) |
5ec69017c irqchip: armada-3... |
56 57 58 |
#define IPI_DOORBELL_START (0) #define IPI_DOORBELL_END (8) #define IPI_DOORBELL_MASK 0xFF |
31f614edb irqchip: armada-3... |
59 60 61 62 |
#define PCI_MSI_DOORBELL_START (16) #define PCI_MSI_DOORBELL_NR (16) #define PCI_MSI_DOORBELL_END (32) #define PCI_MSI_DOORBELL_MASK 0xFFFF0000 |
344e873e5 arm: mvebu: Add I... |
63 |
|
9ae6f740b arm: mach-mvebu: ... |
64 65 66 |
static void __iomem *per_cpu_int_base; static void __iomem *main_int_base; static struct irq_domain *armada_370_xp_mpic_domain; |
0f077eb5c irqchip: armada-3... |
67 |
static u32 doorbell_mask_reg; |
5724be846 irqchip: armada-3... |
68 |
static int parent_irq; |
31f614edb irqchip: armada-3... |
69 70 |
#ifdef CONFIG_PCI_MSI static struct irq_domain *armada_370_xp_msi_domain; |
fcc392d50 irqchip/armada-37... |
71 |
static struct irq_domain *armada_370_xp_msi_inner_domain; |
31f614edb irqchip: armada-3... |
72 73 74 75 |
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR); static DEFINE_MUTEX(msi_used_lock); static phys_addr_t msi_doorbell_addr; #endif |
9ae6f740b arm: mach-mvebu: ... |
76 |
|
2c299de52 irqchip: armada-3... |
77 78 |
static inline bool is_percpu_irq(irq_hw_number_t irq) { |
080481f97 irqchip: armada-3... |
79 |
if (irq <= ARMADA_370_XP_MAX_PER_CPU_IRQS) |
2c299de52 irqchip: armada-3... |
80 |
return true; |
080481f97 irqchip: armada-3... |
81 82 |
return false; |
2c299de52 irqchip: armada-3... |
83 |
} |
3202bf015 arm: mvebu: Impro... |
84 85 86 |
/* * In SMP mode: * For shared global interrupts, mask/unmask global enable bit |
097ef18d5 arm: irq-armada-3... |
87 |
* For CPU interrupts, mask/unmask the calling CPU's bit |
3202bf015 arm: mvebu: Impro... |
88 |
*/ |
9ae6f740b arm: mach-mvebu: ... |
89 90 |
static void armada_370_xp_irq_mask(struct irq_data *d) { |
3202bf015 arm: mvebu: Impro... |
91 |
irq_hw_number_t hwirq = irqd_to_hwirq(d); |
2c299de52 irqchip: armada-3... |
92 |
if (!is_percpu_irq(hwirq)) |
3202bf015 arm: mvebu: Impro... |
93 94 95 96 97 |
writel(hwirq, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); else writel(hwirq, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); |
9ae6f740b arm: mach-mvebu: ... |
98 99 100 101 |
} static void armada_370_xp_irq_unmask(struct irq_data *d) { |
3202bf015 arm: mvebu: Impro... |
102 |
irq_hw_number_t hwirq = irqd_to_hwirq(d); |
2c299de52 irqchip: armada-3... |
103 |
if (!is_percpu_irq(hwirq)) |
3202bf015 arm: mvebu: Impro... |
104 105 106 107 108 |
writel(hwirq, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); else writel(hwirq, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); |
9ae6f740b arm: mach-mvebu: ... |
109 |
} |
31f614edb irqchip: armada-3... |
110 |
#ifdef CONFIG_PCI_MSI |
fcc392d50 irqchip/armada-37... |
111 |
static struct irq_chip armada_370_xp_msi_irq_chip = { |
f692a172d irqchip/armada-37... |
112 |
.name = "MPIC MSI", |
fcc392d50 irqchip/armada-37... |
113 114 115 |
.irq_mask = pci_msi_mask_irq, .irq_unmask = pci_msi_unmask_irq, }; |
31f614edb irqchip: armada-3... |
116 |
|
fcc392d50 irqchip/armada-37... |
117 |
static struct msi_domain_info armada_370_xp_msi_domain_info = { |
a71b9412c irqchip/armada-37... |
118 119 |
.flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | MSI_FLAG_MULTI_PCI_MSI), |
fcc392d50 irqchip/armada-37... |
120 121 |
.chip = &armada_370_xp_msi_irq_chip, }; |
31f614edb irqchip: armada-3... |
122 |
|
fcc392d50 irqchip/armada-37... |
123 |
static void armada_370_xp_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) |
31f614edb irqchip: armada-3... |
124 |
{ |
fcc392d50 irqchip/armada-37... |
125 126 127 |
msg->address_lo = lower_32_bits(msi_doorbell_addr); msg->address_hi = upper_32_bits(msi_doorbell_addr); msg->data = 0xf00 | (data->hwirq + PCI_MSI_DOORBELL_START); |
31f614edb irqchip: armada-3... |
128 |
} |
fcc392d50 irqchip/armada-37... |
129 130 |
static int armada_370_xp_msi_set_affinity(struct irq_data *irq_data, const struct cpumask *mask, bool force) |
31f614edb irqchip: armada-3... |
131 |
{ |
fcc392d50 irqchip/armada-37... |
132 133 |
return -EINVAL; } |
31f614edb irqchip: armada-3... |
134 |
|
fcc392d50 irqchip/armada-37... |
135 |
static struct irq_chip armada_370_xp_msi_bottom_irq_chip = { |
f692a172d irqchip/armada-37... |
136 |
.name = "MPIC MSI", |
fcc392d50 irqchip/armada-37... |
137 138 139 |
.irq_compose_msi_msg = armada_370_xp_compose_msi_msg, .irq_set_affinity = armada_370_xp_msi_set_affinity, }; |
3930115e0 irqchip: armada-3... |
140 |
|
fcc392d50 irqchip/armada-37... |
141 142 143 |
static int armada_370_xp_msi_alloc(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs, void *args) { |
a71b9412c irqchip/armada-37... |
144 |
int hwirq, i; |
31f614edb irqchip: armada-3... |
145 |
|
fcc392d50 irqchip/armada-37... |
146 |
mutex_lock(&msi_used_lock); |
a71b9412c irqchip/armada-37... |
147 148 149 |
hwirq = bitmap_find_next_zero_area(msi_used, PCI_MSI_DOORBELL_NR, 0, nr_irqs, 0); |
fcc392d50 irqchip/armada-37... |
150 151 152 |
if (hwirq >= PCI_MSI_DOORBELL_NR) { mutex_unlock(&msi_used_lock); return -ENOSPC; |
31f614edb irqchip: armada-3... |
153 |
} |
a71b9412c irqchip/armada-37... |
154 |
bitmap_set(msi_used, hwirq, nr_irqs); |
fcc392d50 irqchip/armada-37... |
155 |
mutex_unlock(&msi_used_lock); |
31f614edb irqchip: armada-3... |
156 |
|
a71b9412c irqchip/armada-37... |
157 158 159 160 161 162 |
for (i = 0; i < nr_irqs; i++) { irq_domain_set_info(domain, virq + i, hwirq + i, &armada_370_xp_msi_bottom_irq_chip, domain->host_data, handle_simple_irq, NULL, NULL); } |
31f614edb irqchip: armada-3... |
163 |
|
fcc392d50 irqchip/armada-37... |
164 |
return hwirq; |
31f614edb irqchip: armada-3... |
165 |
} |
fcc392d50 irqchip/armada-37... |
166 167 |
static void armada_370_xp_msi_free(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs) |
31f614edb irqchip: armada-3... |
168 |
{ |
fcc392d50 irqchip/armada-37... |
169 |
struct irq_data *d = irq_domain_get_irq_data(domain, virq); |
31f614edb irqchip: armada-3... |
170 |
|
fcc392d50 irqchip/armada-37... |
171 |
mutex_lock(&msi_used_lock); |
a71b9412c irqchip/armada-37... |
172 |
bitmap_clear(msi_used, d->hwirq, nr_irqs); |
fcc392d50 irqchip/armada-37... |
173 |
mutex_unlock(&msi_used_lock); |
31f614edb irqchip: armada-3... |
174 |
} |
fcc392d50 irqchip/armada-37... |
175 176 177 |
static const struct irq_domain_ops armada_370_xp_msi_domain_ops = { .alloc = armada_370_xp_msi_alloc, .free = armada_370_xp_msi_free, |
31f614edb irqchip: armada-3... |
178 179 180 181 182 |
}; static int armada_370_xp_msi_init(struct device_node *node, phys_addr_t main_int_phys_base) { |
31f614edb irqchip: armada-3... |
183 |
u32 reg; |
31f614edb irqchip: armada-3... |
184 185 186 |
msi_doorbell_addr = main_int_phys_base + ARMADA_370_XP_SW_TRIG_INT_OFFS; |
fcc392d50 irqchip/armada-37... |
187 188 189 190 |
armada_370_xp_msi_inner_domain = irq_domain_add_linear(NULL, PCI_MSI_DOORBELL_NR, &armada_370_xp_msi_domain_ops, NULL); if (!armada_370_xp_msi_inner_domain) |
31f614edb irqchip: armada-3... |
191 |
return -ENOMEM; |
31f614edb irqchip: armada-3... |
192 |
armada_370_xp_msi_domain = |
fcc392d50 irqchip/armada-37... |
193 194 195 |
pci_msi_create_irq_domain(of_node_to_fwnode(node), &armada_370_xp_msi_domain_info, armada_370_xp_msi_inner_domain); |
31f614edb irqchip: armada-3... |
196 |
if (!armada_370_xp_msi_domain) { |
fcc392d50 irqchip/armada-37... |
197 |
irq_domain_remove(armada_370_xp_msi_inner_domain); |
31f614edb irqchip: armada-3... |
198 199 |
return -ENOMEM; } |
31f614edb irqchip: armada-3... |
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
reg = readl(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS) | PCI_MSI_DOORBELL_MASK; writel(reg, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS); /* Unmask IPI interrupt */ writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); return 0; } #else static inline int armada_370_xp_msi_init(struct device_node *node, phys_addr_t main_int_phys_base) { return 0; } #endif |
344e873e5 arm: mvebu: Add I... |
218 |
#ifdef CONFIG_SMP |
19e61d414 ARM: mvebu: fix c... |
219 |
static DEFINE_RAW_SPINLOCK(irq_controller_lock); |
344e873e5 arm: mvebu: Add I... |
220 221 222 |
static int armada_xp_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) { |
3202bf015 arm: mvebu: Impro... |
223 |
irq_hw_number_t hwirq = irqd_to_hwirq(d); |
8cc3cfc5c irqchip: armanda:... |
224 |
unsigned long reg, mask; |
3202bf015 arm: mvebu: Impro... |
225 |
int cpu; |
8cc3cfc5c irqchip: armanda:... |
226 227 228 |
/* Select a single core from the affinity mask which is online */ cpu = cpumask_any_and(mask_val, cpu_online_mask); mask = 1UL << cpu_logical_map(cpu); |
3202bf015 arm: mvebu: Impro... |
229 230 |
raw_spin_lock(&irq_controller_lock); |
3202bf015 arm: mvebu: Impro... |
231 |
reg = readl(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); |
8cc3cfc5c irqchip: armanda:... |
232 |
reg = (reg & (~ARMADA_370_XP_INT_SOURCE_CPU_MASK)) | mask; |
3202bf015 arm: mvebu: Impro... |
233 |
writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq)); |
3202bf015 arm: mvebu: Impro... |
234 |
raw_spin_unlock(&irq_controller_lock); |
1dacf194b irqchip: irq-arma... |
235 |
return IRQ_SET_MASK_OK; |
344e873e5 arm: mvebu: Add I... |
236 237 |
} #endif |
9ae6f740b arm: mach-mvebu: ... |
238 |
static struct irq_chip armada_370_xp_irq_chip = { |
f692a172d irqchip/armada-37... |
239 |
.name = "MPIC", |
9ae6f740b arm: mach-mvebu: ... |
240 241 242 |
.irq_mask = armada_370_xp_irq_mask, .irq_mask_ack = armada_370_xp_irq_mask, .irq_unmask = armada_370_xp_irq_unmask, |
344e873e5 arm: mvebu: Add I... |
243 244 245 |
#ifdef CONFIG_SMP .irq_set_affinity = armada_xp_set_affinity, #endif |
0d8e1d80b irqchip: armada-3... |
246 |
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, |
9ae6f740b arm: mach-mvebu: ... |
247 248 249 250 251 252 |
}; static int armada_370_xp_mpic_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { armada_370_xp_irq_mask(irq_get_irq_data(virq)); |
2c299de52 irqchip: armada-3... |
253 |
if (!is_percpu_irq(hw)) |
600468d06 arm: mvebu: Fix t... |
254 255 256 257 |
writel(hw, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); else writel(hw, main_int_base + ARMADA_370_XP_INT_SET_ENABLE_OFFS); |
9ae6f740b arm: mach-mvebu: ... |
258 |
irq_set_status_flags(virq, IRQ_LEVEL); |
3a6f08a37 arm: mvebu: Add s... |
259 |
|
2c299de52 irqchip: armada-3... |
260 |
if (is_percpu_irq(hw)) { |
3a6f08a37 arm: mvebu: Add s... |
261 262 263 264 265 266 267 268 |
irq_set_percpu_devid(virq); irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, handle_percpu_devid_irq); } else { irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, handle_level_irq); } |
d17cab445 irqchip: Kill off... |
269 |
irq_set_probe(virq); |
353d6d6c8 irqchip/armada-37... |
270 |
irq_clear_status_flags(virq, IRQ_NOAUTOEN); |
9ae6f740b arm: mach-mvebu: ... |
271 272 273 |
return 0; } |
d7df84b3c irqchip: irq-arma... |
274 |
static void armada_xp_mpic_smp_cpu_init(void) |
344e873e5 arm: mvebu: Add I... |
275 |
{ |
b73842b75 irqchip: armada-3... |
276 277 278 279 280 281 282 283 |
u32 control; int nr_irqs, i; control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); nr_irqs = (control >> 2) & 0x3ff; for (i = 0; i < nr_irqs; i++) writel(i, per_cpu_int_base + ARMADA_370_XP_INT_SET_MASK_OFFS); |
344e873e5 arm: mvebu: Add I... |
284 285 286 287 |
/* Clear pending IPIs */ writel(0, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); /* Enable first 8 IPIs */ |
5ec69017c irqchip: armada-3... |
288 |
writel(IPI_DOORBELL_MASK, per_cpu_int_base + |
344e873e5 arm: mvebu: Add I... |
289 290 291 292 293 |
ARMADA_370_XP_IN_DRBEL_MSK_OFFS); /* Unmask IPI interrupt */ writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS); } |
d7df84b3c irqchip: irq-arma... |
294 |
|
28da06dfd irqchip: armada-3... |
295 296 297 298 299 300 301 302 |
static void armada_xp_mpic_perf_init(void) { unsigned long cpuid = cpu_logical_map(smp_processor_id()); /* Enable Performance Counter Overflow interrupts */ writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid), per_cpu_int_base + ARMADA_370_XP_INT_FABRIC_MASK_OFFS); } |
933a24b06 irqchip: armada-3... |
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
#ifdef CONFIG_SMP static void armada_mpic_send_doorbell(const struct cpumask *mask, unsigned int irq) { int cpu; unsigned long map = 0; /* Convert our logical CPU mask into a physical one. */ for_each_cpu(cpu, mask) map |= 1 << cpu_logical_map(cpu); /* * Ensure that stores to Normal memory are visible to the * other CPUs before issuing the IPI. */ dsb(); /* submit softirq */ writel((map << 8) | irq, main_int_base + ARMADA_370_XP_SW_TRIG_INT_OFFS); } |
cb5ff2d24 irqchip/armada-37... |
324 |
static int armada_xp_mpic_starting_cpu(unsigned int cpu) |
d7df84b3c irqchip: irq-arma... |
325 |
{ |
cb5ff2d24 irqchip/armada-37... |
326 327 328 |
armada_xp_mpic_perf_init(); armada_xp_mpic_smp_cpu_init(); return 0; |
d7df84b3c irqchip: irq-arma... |
329 |
} |
cb5ff2d24 irqchip/armada-37... |
330 |
static int mpic_cascaded_starting_cpu(unsigned int cpu) |
5724be846 irqchip: armada-3... |
331 |
{ |
cb5ff2d24 irqchip/armada-37... |
332 333 334 |
armada_xp_mpic_perf_init(); enable_percpu_irq(parent_irq, IRQ_TYPE_NONE); return 0; |
5724be846 irqchip: armada-3... |
335 |
} |
c76c15e6f irqchip/armada: A... |
336 |
#endif |
344e873e5 arm: mvebu: Add I... |
337 |
|
960097365 irqchip: Constify... |
338 |
static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = { |
9ae6f740b arm: mach-mvebu: ... |
339 340 341 |
.map = armada_370_xp_mpic_irq_map, .xlate = irq_domain_xlate_onecell, }; |
9b8cf779f irqchip: armada-3... |
342 |
#ifdef CONFIG_PCI_MSI |
bc69b8adf irqchip: armada-3... |
343 |
static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) |
9b8cf779f irqchip: armada-3... |
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
{ u32 msimask, msinr; msimask = readl_relaxed(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) & PCI_MSI_DOORBELL_MASK; writel(~msimask, per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); for (msinr = PCI_MSI_DOORBELL_START; msinr < PCI_MSI_DOORBELL_END; msinr++) { int irq; if (!(msimask & BIT(msinr))) continue; |
e89c6a06b irqchip: armada-3... |
360 |
if (is_chained) { |
fcc392d50 irqchip/armada-37... |
361 |
irq = irq_find_mapping(armada_370_xp_msi_inner_domain, |
0636bab67 irqchip/armada-37... |
362 |
msinr - PCI_MSI_DOORBELL_START); |
bc69b8adf irqchip: armada-3... |
363 |
generic_handle_irq(irq); |
e89c6a06b irqchip: armada-3... |
364 |
} else { |
0636bab67 irqchip/armada-37... |
365 |
irq = msinr - PCI_MSI_DOORBELL_START; |
fcc392d50 irqchip/armada-37... |
366 |
handle_domain_irq(armada_370_xp_msi_inner_domain, |
e89c6a06b irqchip: armada-3... |
367 368 |
irq, regs); } |
9b8cf779f irqchip: armada-3... |
369 370 371 |
} } #else |
bc69b8adf irqchip: armada-3... |
372 |
static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} |
9b8cf779f irqchip: armada-3... |
373 |
#endif |
bd0b9ac40 genirq: Remove ir... |
374 |
static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc) |
bc69b8adf irqchip: armada-3... |
375 |
{ |
5b29264c6 irqchip: Use irq_... |
376 |
struct irq_chip *chip = irq_desc_get_chip(desc); |
758e83667 irqchip: armada-3... |
377 |
unsigned long irqmap, irqn, irqsrc, cpuid; |
bc69b8adf irqchip: armada-3... |
378 379 380 381 382 |
unsigned int cascade_irq; chained_irq_enter(chip, desc); irqmap = readl_relaxed(per_cpu_int_base + ARMADA_375_PPI_CAUSE); |
758e83667 irqchip: armada-3... |
383 |
cpuid = cpu_logical_map(smp_processor_id()); |
bc69b8adf irqchip: armada-3... |
384 385 |
for_each_set_bit(irqn, &irqmap, BITS_PER_LONG) { |
758e83667 irqchip: armada-3... |
386 387 388 389 390 391 392 393 394 395 396 397 398 |
irqsrc = readl_relaxed(main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(irqn)); /* Check if the interrupt is not masked on current CPU. * Test IRQ (0-1) and FIQ (8-9) mask bits. */ if (!(irqsrc & ARMADA_370_XP_INT_IRQ_FIQ_MASK(cpuid))) continue; if (irqn == 1) { armada_370_xp_handle_msi_irq(NULL, true); continue; } |
bc69b8adf irqchip: armada-3... |
399 400 401 402 403 404 |
cascade_irq = irq_find_mapping(armada_370_xp_mpic_domain, irqn); generic_handle_irq(cascade_irq); } chained_irq_exit(chip, desc); } |
8783dd3a3 irqchip: Remove a... |
405 |
static void __exception_irq_entry |
9339d432f irqchip: move IRQ... |
406 |
armada_370_xp_handle_irq(struct pt_regs *regs) |
9ae6f740b arm: mach-mvebu: ... |
407 408 409 410 411 412 413 |
{ u32 irqstat, irqnr; do { irqstat = readl_relaxed(per_cpu_int_base + ARMADA_370_XP_CPU_INTACK_OFFS); irqnr = irqstat & 0x3FF; |
344e873e5 arm: mvebu: Add I... |
414 415 |
if (irqnr > 1022) break; |
31f614edb irqchip: armada-3... |
416 |
if (irqnr > 1) { |
e89c6a06b irqchip: armada-3... |
417 418 |
handle_domain_irq(armada_370_xp_mpic_domain, irqnr, regs); |
9ae6f740b arm: mach-mvebu: ... |
419 420 |
continue; } |
31f614edb irqchip: armada-3... |
421 |
|
31f614edb irqchip: armada-3... |
422 |
/* MSI handling */ |
9b8cf779f irqchip: armada-3... |
423 |
if (irqnr == 1) |
bc69b8adf irqchip: armada-3... |
424 |
armada_370_xp_handle_msi_irq(regs, false); |
31f614edb irqchip: armada-3... |
425 |
|
344e873e5 arm: mvebu: Add I... |
426 427 428 429 430 431 432 |
#ifdef CONFIG_SMP /* IPI Handling */ if (irqnr == 0) { u32 ipimask, ipinr; ipimask = readl_relaxed(per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS) |
5ec69017c irqchip: armada-3... |
433 |
& IPI_DOORBELL_MASK; |
344e873e5 arm: mvebu: Add I... |
434 |
|
a6f089e95 irqchip: armada-3... |
435 |
writel(~ipimask, per_cpu_int_base + |
344e873e5 arm: mvebu: Add I... |
436 437 438 |
ARMADA_370_XP_IN_DRBEL_CAUSE_OFFS); /* Handle all pending doorbells */ |
5ec69017c irqchip: armada-3... |
439 440 |
for (ipinr = IPI_DOORBELL_START; ipinr < IPI_DOORBELL_END; ipinr++) { |
344e873e5 arm: mvebu: Add I... |
441 442 443 444 445 446 |
if (ipimask & (0x1 << ipinr)) handle_IPI(ipinr, regs); } continue; } #endif |
9ae6f740b arm: mach-mvebu: ... |
447 |
|
9ae6f740b arm: mach-mvebu: ... |
448 449 |
} while (1); } |
0f077eb5c irqchip: armada-3... |
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
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; |
080481f97 irqchip: armada-3... |
471 |
if (!is_percpu_irq(irq)) |
0f077eb5c irqchip: armada-3... |
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 |
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); } |
6c8809024 irqchip/armada-37... |
491 |
static struct syscore_ops armada_370_xp_mpic_syscore_ops = { |
0f077eb5c irqchip: armada-3... |
492 493 494 |
.suspend = armada_370_xp_mpic_suspend, .resume = armada_370_xp_mpic_resume, }; |
b313ada8c irqchip: armada-3... |
495 496 |
static int __init armada_370_xp_mpic_of_init(struct device_node *node, struct device_node *parent) |
9ae6f740b arm: mach-mvebu: ... |
497 |
{ |
627dfcc24 irqchip: armada-3... |
498 |
struct resource main_int_res, per_cpu_int_res; |
5724be846 irqchip: armada-3... |
499 |
int nr_irqs, i; |
b313ada8c irqchip: armada-3... |
500 |
u32 control; |
627dfcc24 irqchip: armada-3... |
501 502 |
BUG_ON(of_address_to_resource(node, 0, &main_int_res)); BUG_ON(of_address_to_resource(node, 1, &per_cpu_int_res)); |
b313ada8c irqchip: armada-3... |
503 |
|
627dfcc24 irqchip: armada-3... |
504 505 506 507 508 509 510 511 512 |
BUG_ON(!request_mem_region(main_int_res.start, resource_size(&main_int_res), node->full_name)); BUG_ON(!request_mem_region(per_cpu_int_res.start, resource_size(&per_cpu_int_res), node->full_name)); main_int_base = ioremap(main_int_res.start, resource_size(&main_int_res)); |
b313ada8c irqchip: armada-3... |
513 |
BUG_ON(!main_int_base); |
627dfcc24 irqchip: armada-3... |
514 515 516 |
per_cpu_int_base = ioremap(per_cpu_int_res.start, resource_size(&per_cpu_int_res)); |
b313ada8c irqchip: armada-3... |
517 518 519 |
BUG_ON(!per_cpu_int_base); control = readl(main_int_base + ARMADA_370_XP_INT_CONTROL); |
b73842b75 irqchip: armada-3... |
520 521 522 523 |
nr_irqs = (control >> 2) & 0x3ff; for (i = 0; i < nr_irqs; i++) writel(i, main_int_base + ARMADA_370_XP_INT_CLEAR_ENABLE_OFFS); |
b313ada8c irqchip: armada-3... |
524 525 |
armada_370_xp_mpic_domain = |
b73842b75 irqchip: armada-3... |
526 |
irq_domain_add_linear(node, nr_irqs, |
b313ada8c irqchip: armada-3... |
527 |
&armada_370_xp_mpic_irq_ops, NULL); |
627dfcc24 irqchip: armada-3... |
528 |
BUG_ON(!armada_370_xp_mpic_domain); |
fcc392d50 irqchip/armada-37... |
529 |
armada_370_xp_mpic_domain->bus_token = DOMAIN_BUS_WIRED; |
b313ada8c irqchip: armada-3... |
530 |
|
933a24b06 irqchip: armada-3... |
531 |
/* Setup for the boot CPU */ |
28da06dfd irqchip: armada-3... |
532 |
armada_xp_mpic_perf_init(); |
b313ada8c irqchip: armada-3... |
533 |
armada_xp_mpic_smp_cpu_init(); |
b313ada8c irqchip: armada-3... |
534 |
|
31f614edb irqchip: armada-3... |
535 |
armada_370_xp_msi_init(node, main_int_res.start); |
bc69b8adf irqchip: armada-3... |
536 537 538 539 |
parent_irq = irq_of_parse_and_map(node, 0); if (parent_irq <= 0) { irq_set_default_host(armada_370_xp_mpic_domain); set_handle_irq(armada_370_xp_handle_irq); |
ef37d337e irqchip: irq-arma... |
540 541 |
#ifdef CONFIG_SMP set_smp_cross_call(armada_mpic_send_doorbell); |
cb5ff2d24 irqchip/armada-37... |
542 543 544 |
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING, "AP_IRQ_ARMADA_XP_STARTING", armada_xp_mpic_starting_cpu, NULL); |
ef37d337e irqchip: irq-arma... |
545 |
#endif |
bc69b8adf irqchip: armada-3... |
546 |
} else { |
5724be846 irqchip: armada-3... |
547 |
#ifdef CONFIG_SMP |
cb5ff2d24 irqchip/armada-37... |
548 549 550 |
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_CASC_STARTING, "AP_IRQ_ARMADA_CASC_STARTING", mpic_cascaded_starting_cpu, NULL); |
5724be846 irqchip: armada-3... |
551 |
#endif |
bc69b8adf irqchip: armada-3... |
552 553 554 |
irq_set_chained_handler(parent_irq, armada_370_xp_mpic_handle_cascade_irq); } |
b313ada8c irqchip: armada-3... |
555 |
|
0f077eb5c irqchip: armada-3... |
556 |
register_syscore_ops(&armada_370_xp_mpic_syscore_ops); |
b313ada8c irqchip: armada-3... |
557 |
return 0; |
9ae6f740b arm: mach-mvebu: ... |
558 |
} |
b313ada8c irqchip: armada-3... |
559 |
|
9339d432f irqchip: move IRQ... |
560 |
IRQCHIP_DECLARE(armada_370_xp_mpic, "marvell,mpic", armada_370_xp_mpic_of_init); |