blob: 097e8a2a3c5d7cbd2981baf3a6cad4d6eea80ce3 [file] [log] [blame]
David Gibson007e8f52005-10-28 15:35:50 +10001/*
2 * arch/powerpc/platforms/pseries/xics.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright 2000 IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +100011
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/types.h>
13#include <linux/threads.h>
14#include <linux/kernel.h>
15#include <linux/irq.h>
16#include <linux/smp.h>
17#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <linux/radix-tree.h>
20#include <linux/cpu.h>
Andre Detsch8435b022009-11-04 13:03:19 -020021#include <linux/msi.h>
Milton Miller188bddd2008-10-10 01:56:33 +000022#include <linux/of.h>
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +100023
Michael Ellerman57cfb812006-03-21 20:45:59 +110024#include <asm/firmware.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <asm/io.h>
26#include <asm/pgtable.h>
27#include <asm/smp.h>
28#include <asm/rtas.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <asm/hvcall.h>
30#include <asm/machdep.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
David Gibson007e8f52005-10-28 15:35:50 +100032#include "xics.h"
Anton Blanchardb9377ff2006-07-19 08:01:28 +100033#include "plpar_wrappers.h"
David Gibson007e8f52005-10-28 15:35:50 +100034
Milton Miller0641cc92008-10-10 01:56:30 +000035static struct irq_host *xics_host;
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define XICS_IPI 2
38#define XICS_IRQ_SPURIOUS 0
39
40/* Want a priority other than 0. Various HW issues require this. */
41#define DEFAULT_PRIORITY 5
42
David Gibson007e8f52005-10-28 15:35:50 +100043/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 * Mark IPIs as higher priority so we can take them inside interrupts that
Thomas Gleixner67144652006-07-01 19:29:22 -070045 * arent marked IRQF_DISABLED
Linus Torvalds1da177e2005-04-16 15:20:36 -070046 */
47#define IPI_PRIORITY 4
48
Milton Miller0641cc92008-10-10 01:56:30 +000049static unsigned int default_server = 0xFF;
50static unsigned int default_distrib_server = 0;
51static unsigned int interrupt_server_size = 8;
52
53/* RTAS service tokens */
54static int ibm_get_xive;
55static int ibm_set_xive;
56static int ibm_int_on;
57static int ibm_int_off;
58
59
60/* Direct hardware low level accessors */
61
62/* The part of the interrupt presentation layer that we care about */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063struct xics_ipl {
64 union {
65 u32 word;
66 u8 bytes[4];
67 } xirr_poll;
68 union {
69 u32 word;
70 u8 bytes[4];
71 } xirr;
72 u32 dummy;
73 union {
74 u32 word;
75 u8 bytes[4];
76 } qirr;
77};
78
79static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
80
Milton Millerd7cf0ed2007-12-14 15:52:09 +110081static inline unsigned int direct_xirr_info_get(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070082{
Milton Millerd7cf0ed2007-12-14 15:52:09 +110083 int cpu = smp_processor_id();
84
85 return in_be32(&xics_per_cpu[cpu]->xirr.word);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086}
87
Milton Miller9dc2d442008-10-10 01:56:32 +000088static inline void direct_xirr_info_set(unsigned int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Milton Millerd7cf0ed2007-12-14 15:52:09 +110090 int cpu = smp_processor_id();
91
92 out_be32(&xics_per_cpu[cpu]->xirr.word, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093}
94
Milton Millerd7cf0ed2007-12-14 15:52:09 +110095static inline void direct_cppr_info(u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
Milton Millerd7cf0ed2007-12-14 15:52:09 +110097 int cpu = smp_processor_id();
98
99 out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100}
101
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000102static inline void direct_qirr_info(int n_cpu, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103{
104 out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
105}
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000108/* LPAR low level accessors */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100110static inline unsigned int lpar_xirr_info_get(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111{
112 unsigned long lpar_rc;
David Gibson007e8f52005-10-28 15:35:50 +1000113 unsigned long return_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
115 lpar_rc = plpar_xirr(&return_value);
Segher Boessenkool706c8c92006-03-30 14:49:40 +0200116 if (lpar_rc != H_SUCCESS)
David Gibson007e8f52005-10-28 15:35:50 +1000117 panic(" bad return code xirr - rc = %lx \n", lpar_rc);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000118 return (unsigned int)return_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119}
120
Milton Miller9dc2d442008-10-10 01:56:32 +0000121static inline void lpar_xirr_info_set(unsigned int value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122{
123 unsigned long lpar_rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124
Milton Miller9dc2d442008-10-10 01:56:32 +0000125 lpar_rc = plpar_eoi(value);
Segher Boessenkool706c8c92006-03-30 14:49:40 +0200126 if (lpar_rc != H_SUCCESS)
Milton Miller9dc2d442008-10-10 01:56:32 +0000127 panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc,
128 value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129}
130
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100131static inline void lpar_cppr_info(u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
133 unsigned long lpar_rc;
134
135 lpar_rc = plpar_cppr(value);
Segher Boessenkool706c8c92006-03-30 14:49:40 +0200136 if (lpar_rc != H_SUCCESS)
David Gibson007e8f52005-10-28 15:35:50 +1000137 panic("bad return code cppr - rc = %lx\n", lpar_rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138}
139
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000140static inline void lpar_qirr_info(int n_cpu , u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141{
142 unsigned long lpar_rc;
143
144 lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value);
Segher Boessenkool706c8c92006-03-30 14:49:40 +0200145 if (lpar_rc != H_SUCCESS)
David Gibson007e8f52005-10-28 15:35:50 +1000146 panic("bad return code qirr - rc = %lx\n", lpar_rc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147}
148
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
Milton Miller0641cc92008-10-10 01:56:30 +0000150/* Interface to generic irq subsystem */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152#ifdef CONFIG_SMP
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000153static int get_irq_server(unsigned int virq, unsigned int strict_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000155 int server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 /* For the moment only implement delivery to all cpus or one cpu */
Mike Travise65e49d2009-01-12 15:27:13 -0800157 cpumask_t cpumask;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 cpumask_t tmp = CPU_MASK_NONE;
159
Michael Ellerman6cff46f2009-10-13 19:44:51 +0000160 cpumask_copy(&cpumask, irq_to_desc(virq)->affinity);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 if (!distribute_irqs)
162 return default_server;
163
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000164 if (!cpus_equal(cpumask, CPU_MASK_ALL)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 cpus_and(tmp, cpu_online_map, cpumask);
166
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000167 server = first_cpu(tmp);
168
169 if (server < NR_CPUS)
170 return get_hard_smp_processor_id(server);
171
172 if (strict_check)
173 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
175
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000176 if (cpus_equal(cpu_online_map, cpu_present_map))
177 return default_distrib_server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000179 return default_server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180}
181#else
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000182static int get_irq_server(unsigned int virq, unsigned int strict_check)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183{
184 return default_server;
185}
186#endif
187
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000188static void xics_unmask_irq(unsigned int virq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189{
190 unsigned int irq;
191 int call_status;
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000192 int server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
Michael Ellermanb69e9e92009-06-17 18:13:53 +0000194 pr_devel("xics: unmask virq %d\n", virq);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000195
196 irq = (unsigned int)irq_map[virq].hwirq;
Michael Ellermanb69e9e92009-06-17 18:13:53 +0000197 pr_devel(" -> map to hwirq 0x%x\n", irq);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000198 if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 return;
200
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000201 server = get_irq_server(virq, 0);
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000202
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
204 DEFAULT_PRIORITY);
205 if (call_status != 0) {
Milton Miller2172fe82008-10-10 01:56:39 +0000206 printk(KERN_ERR
207 "%s: ibm_set_xive irq %u server %x returned %d\n",
208 __func__, irq, server, call_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 return;
210 }
211
212 /* Now unmask the interrupt (often a no-op) */
213 call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
214 if (call_status != 0) {
Milton Miller2172fe82008-10-10 01:56:39 +0000215 printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
216 __func__, irq, call_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return;
218 }
219}
220
Milton Miller0641cc92008-10-10 01:56:30 +0000221static unsigned int xics_startup(unsigned int virq)
222{
Andre Detsch8435b022009-11-04 13:03:19 -0200223 /*
224 * The generic MSI code returns with the interrupt disabled on the
225 * card, using the MSI mask bits. Firmware doesn't appear to unmask
226 * at that level, so we do it here by hand.
227 */
228 if (irq_to_desc(virq)->msi_desc)
229 unmask_msi_irq(virq);
230
Milton Miller0641cc92008-10-10 01:56:30 +0000231 /* unmask it */
232 xics_unmask_irq(virq);
233 return 0;
234}
235
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000236static void xics_mask_real_irq(unsigned int irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 int call_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 if (irq == XICS_IPI)
241 return;
242
243 call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
244 if (call_status != 0) {
Milton Miller2172fe82008-10-10 01:56:39 +0000245 printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
246 __func__, irq, call_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 return;
248 }
249
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 /* Have to set XIVE to 0xff to be able to remove a slot */
Michal Ostrowski673aeb72006-12-20 07:29:40 -0600251 call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
252 default_server, 0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 if (call_status != 0) {
Milton Miller2172fe82008-10-10 01:56:39 +0000254 printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
255 __func__, irq, call_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 return;
257 }
258}
259
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000260static void xics_mask_irq(unsigned int virq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261{
262 unsigned int irq;
263
Michael Ellermanb69e9e92009-06-17 18:13:53 +0000264 pr_devel("xics: mask virq %d\n", virq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000266 irq = (unsigned int)irq_map[virq].hwirq;
267 if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
268 return;
269 xics_mask_real_irq(irq);
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000270}
271
Milton Miller0641cc92008-10-10 01:56:30 +0000272static void xics_mask_unknown_vec(unsigned int vec)
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000273{
Milton Miller0641cc92008-10-10 01:56:30 +0000274 printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
275 xics_mask_real_irq(vec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276}
277
Milton Miller8767e9b2008-10-10 01:56:23 +0000278static inline unsigned int xics_xirr_vector(unsigned int xirr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Milton Miller8767e9b2008-10-10 01:56:23 +0000280 /*
281 * The top byte is the old cppr, to be restored on EOI.
282 * The remaining 24 bits are the vector.
283 */
284 return xirr & 0x00ffffff;
285}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Olaf Hering35a84c22006-10-07 22:08:26 +1000287static unsigned int xics_get_irq_direct(void)
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000288{
Milton Miller8767e9b2008-10-10 01:56:23 +0000289 unsigned int xirr = direct_xirr_info_get();
290 unsigned int vec = xics_xirr_vector(xirr);
291 unsigned int irq;
292
293 if (vec == XICS_IRQ_SPURIOUS)
294 return NO_IRQ;
295
296 irq = irq_radix_revmap_lookup(xics_host, vec);
297 if (likely(irq != NO_IRQ))
298 return irq;
299
300 /* We don't have a linux mapping, so have rtas mask it. */
301 xics_mask_unknown_vec(vec);
302
303 /* We might learn about it later, so EOI it */
304 direct_xirr_info_set(xirr);
305 return NO_IRQ;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000306}
307
Olaf Hering35a84c22006-10-07 22:08:26 +1000308static unsigned int xics_get_irq_lpar(void)
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000309{
Milton Miller8767e9b2008-10-10 01:56:23 +0000310 unsigned int xirr = lpar_xirr_info_get();
311 unsigned int vec = xics_xirr_vector(xirr);
312 unsigned int irq;
313
314 if (vec == XICS_IRQ_SPURIOUS)
315 return NO_IRQ;
316
317 irq = irq_radix_revmap_lookup(xics_host, vec);
318 if (likely(irq != NO_IRQ))
319 return irq;
320
321 /* We don't have a linux mapping, so have RTAS mask it. */
322 xics_mask_unknown_vec(vec);
323
324 /* We might learn about it later, so EOI it */
325 lpar_xirr_info_set(xirr);
326 return NO_IRQ;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
Milton Miller0641cc92008-10-10 01:56:30 +0000329static void xics_eoi_direct(unsigned int virq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330{
Milton Miller0641cc92008-10-10 01:56:30 +0000331 unsigned int irq = (unsigned int)irq_map[virq].hwirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000333 iosync();
Milton Miller0641cc92008-10-10 01:56:30 +0000334 direct_xirr_info_set((0xff << 24) | irq);
335}
336
337static void xics_eoi_lpar(unsigned int virq)
338{
339 unsigned int irq = (unsigned int)irq_map[virq].hwirq;
340
341 iosync();
342 lpar_xirr_info_set((0xff << 24) | irq);
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000343}
344
Yinghai Lud5dedd42009-04-27 17:59:21 -0700345static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask)
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000346{
347 unsigned int irq;
348 int status;
349 int xics_status[2];
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000350 int irq_server;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000351
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000352 irq = (unsigned int)irq_map[virq].hwirq;
353 if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
Yinghai Lud5dedd42009-04-27 17:59:21 -0700354 return -1;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000355
356 status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
357
358 if (status) {
Milton Miller2172fe82008-10-10 01:56:39 +0000359 printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
360 __func__, irq, status);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700361 return -1;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000362 }
363
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000364 /*
365 * For the moment only implement delivery to all cpus or one cpu.
366 * Get current irq_server for the given irq
367 */
Anton Blancharde48395f2007-10-01 07:45:55 +1000368 irq_server = get_irq_server(virq, 1);
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000369 if (irq_server == -1) {
370 char cpulist[128];
371 cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
Milton Miller2172fe82008-10-10 01:56:39 +0000372 printk(KERN_WARNING
373 "%s: No online cpus in the mask %s for irq %d\n",
374 __func__, cpulist, virq);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700375 return -1;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000376 }
377
378 status = rtas_call(ibm_set_xive, 3, 1, NULL,
Mohan Kumar M7ccb4a62007-06-13 00:51:57 +1000379 irq, irq_server, xics_status[1]);
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000380
381 if (status) {
Milton Miller2172fe82008-10-10 01:56:39 +0000382 printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
383 __func__, irq, status);
Yinghai Lud5dedd42009-04-27 17:59:21 -0700384 return -1;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000385 }
Yinghai Lud5dedd42009-04-27 17:59:21 -0700386
387 return 0;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000388}
389
390static struct irq_chip xics_pic_direct = {
391 .typename = " XICS ",
392 .startup = xics_startup,
393 .mask = xics_mask_irq,
394 .unmask = xics_unmask_irq,
395 .eoi = xics_eoi_direct,
396 .set_affinity = xics_set_affinity
397};
398
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000399static struct irq_chip xics_pic_lpar = {
400 .typename = " XICS ",
401 .startup = xics_startup,
402 .mask = xics_mask_irq,
403 .unmask = xics_unmask_irq,
404 .eoi = xics_eoi_lpar,
405 .set_affinity = xics_set_affinity
406};
407
Milton Miller0641cc92008-10-10 01:56:30 +0000408
409/* Interface to arch irq controller subsystem layer */
410
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100411/* Points to the irq_chip we're actually using */
412static struct irq_chip *xics_irq_chip;
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000413
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000414static int xics_host_match(struct irq_host *h, struct device_node *node)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000416 /* IBM machines have interrupt parents of various funky types for things
417 * like vdevices, events, etc... The trick we use here is to match
418 * everything here except the legacy 8259 which is compatible "chrp,iic"
Paul Mackerras6c80a212005-05-06 16:28:56 +1000419 */
Stephen Rothwell55b61fe2007-05-03 17:26:52 +1000420 return !of_device_is_compatible(node, "chrp,iic");
Paul Mackerras6c80a212005-05-06 16:28:56 +1000421}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100423static int xics_host_map(struct irq_host *h, unsigned int virq,
424 irq_hw_number_t hw)
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000425{
Michael Ellermanb69e9e92009-06-17 18:13:53 +0000426 pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000427
Sebastien Dugue967e0122008-09-04 22:37:07 +1000428 /* Insert the interrupt mapping into the radix tree for fast lookup */
429 irq_radix_revmap_insert(xics_host, virq, hw);
430
Michael Ellerman6cff46f2009-10-13 19:44:51 +0000431 irq_to_desc(virq)->status |= IRQ_LEVEL;
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100432 set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000433 return 0;
434}
435
436static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
437 u32 *intspec, unsigned int intsize,
438 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
439
440{
441 /* Current xics implementation translates everything
442 * to level. It is not technically right for MSIs but this
443 * is irrelevant at this point. We might get smarter in the future
444 */
445 *out_hwirq = intspec[0];
446 *out_flags = IRQ_TYPE_LEVEL_LOW;
447
448 return 0;
449}
450
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100451static struct irq_host_ops xics_host_ops = {
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000452 .match = xics_host_match,
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100453 .map = xics_host_map,
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000454 .xlate = xics_host_xlate,
455};
456
457static void __init xics_init_host(void)
458{
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000459 if (firmware_has_feature(FW_FEATURE_LPAR))
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100460 xics_irq_chip = &xics_pic_lpar;
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000461 else
Michael Ellerman1af9fa82008-04-01 17:42:27 +1100462 xics_irq_chip = &xics_pic_direct;
463
464 xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops,
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000465 XICS_IRQ_SPURIOUS);
466 BUG_ON(xics_host == NULL);
467 irq_set_default_host(xics_host);
468}
469
Milton Miller0641cc92008-10-10 01:56:30 +0000470
471/* Inter-processor interrupt support */
472
473#ifdef CONFIG_SMP
474/*
475 * XICS only has a single IPI, so encode the messages per CPU
476 */
477struct xics_ipi_struct {
478 unsigned long value;
479 } ____cacheline_aligned;
480
481static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
482
483static inline void smp_xics_do_message(int cpu, int msg)
484{
485 set_bit(msg, &xics_ipi_message[cpu].value);
486 mb();
487 if (firmware_has_feature(FW_FEATURE_LPAR))
488 lpar_qirr_info(cpu, IPI_PRIORITY);
489 else
490 direct_qirr_info(cpu, IPI_PRIORITY);
491}
492
493void smp_xics_message_pass(int target, int msg)
494{
495 unsigned int i;
496
497 if (target < NR_CPUS) {
498 smp_xics_do_message(target, msg);
499 } else {
500 for_each_online_cpu(i) {
501 if (target == MSG_ALL_BUT_SELF
502 && i == smp_processor_id())
503 continue;
504 smp_xics_do_message(i, msg);
505 }
506 }
507}
508
509static irqreturn_t xics_ipi_dispatch(int cpu)
510{
511 WARN_ON(cpu_is_offline(cpu));
512
Milton Miller199f45c2008-10-10 01:56:44 +0000513 mb(); /* order mmio clearing qirr */
Milton Miller0641cc92008-10-10 01:56:30 +0000514 while (xics_ipi_message[cpu].value) {
515 if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
516 &xics_ipi_message[cpu].value)) {
Milton Miller0641cc92008-10-10 01:56:30 +0000517 smp_message_recv(PPC_MSG_CALL_FUNCTION);
518 }
519 if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
520 &xics_ipi_message[cpu].value)) {
Milton Miller0641cc92008-10-10 01:56:30 +0000521 smp_message_recv(PPC_MSG_RESCHEDULE);
522 }
523 if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
524 &xics_ipi_message[cpu].value)) {
Milton Miller0641cc92008-10-10 01:56:30 +0000525 smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
526 }
527#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
528 if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
529 &xics_ipi_message[cpu].value)) {
Milton Miller0641cc92008-10-10 01:56:30 +0000530 smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
531 }
532#endif
533 }
534 return IRQ_HANDLED;
535}
536
537static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
538{
539 int cpu = smp_processor_id();
540
541 direct_qirr_info(cpu, 0xff);
542
543 return xics_ipi_dispatch(cpu);
544}
545
546static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
547{
548 int cpu = smp_processor_id();
549
550 lpar_qirr_info(cpu, 0xff);
551
552 return xics_ipi_dispatch(cpu);
553}
554
555static void xics_request_ipi(void)
556{
557 unsigned int ipi;
558 int rc;
559
560 ipi = irq_create_mapping(xics_host, XICS_IPI);
561 BUG_ON(ipi == NO_IRQ);
562
563 /*
564 * IPIs are marked IRQF_DISABLED as they must run with irqs
565 * disabled
566 */
567 set_irq_handler(ipi, handle_percpu_irq);
568 if (firmware_has_feature(FW_FEATURE_LPAR))
Milton Millerd879f382008-10-10 01:56:39 +0000569 rc = request_irq(ipi, xics_ipi_action_lpar,
570 IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
Milton Miller0641cc92008-10-10 01:56:30 +0000571 else
Milton Millerd879f382008-10-10 01:56:39 +0000572 rc = request_irq(ipi, xics_ipi_action_direct,
573 IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
Milton Miller0641cc92008-10-10 01:56:30 +0000574 BUG_ON(rc);
575}
576
577int __init smp_xics_probe(void)
578{
579 xics_request_ipi();
580
581 return cpus_weight(cpu_possible_map);
582}
583
584#endif /* CONFIG_SMP */
585
586
587/* Initialization */
588
589static void xics_update_irq_servers(void)
590{
591 int i, j;
592 struct device_node *np;
593 u32 ilen;
Sebastien Dugue1ef80142008-10-22 04:36:32 +0000594 const u32 *ireg;
Milton Miller0641cc92008-10-10 01:56:30 +0000595 u32 hcpuid;
596
597 /* Find the server numbers for the boot cpu. */
598 np = of_get_cpu_node(boot_cpuid, NULL);
599 BUG_ON(!np);
600
601 ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
602 if (!ireg) {
603 of_node_put(np);
604 return;
605 }
606
607 i = ilen / sizeof(int);
608 hcpuid = get_hard_smp_processor_id(boot_cpuid);
609
610 /* Global interrupt distribution server is specified in the last
611 * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
612 * entry fom this property for current boot cpu id and use it as
613 * default distribution server
614 */
615 for (j = 0; j < i; j += 2) {
616 if (ireg[j] == hcpuid) {
617 default_server = hcpuid;
618 default_distrib_server = ireg[j+1];
Milton Miller0641cc92008-10-10 01:56:30 +0000619 }
620 }
621
622 of_node_put(np);
623}
624
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000625static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
626 unsigned long size)
627{
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000628 int i;
629
630 /* This may look gross but it's good enough for now, we don't quite
631 * have a hard -> linux processor id matching.
632 */
633 for_each_possible_cpu(i) {
634 if (!cpu_present(i))
635 continue;
636 if (hw_id == get_hard_smp_processor_id(i)) {
637 xics_per_cpu[i] = ioremap(addr, size);
638 return;
639 }
640 }
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000641}
642
643static void __init xics_init_one_node(struct device_node *np,
644 unsigned int *indx)
645{
646 unsigned int ilen;
Jeremy Kerr954a46e2006-07-12 15:39:43 +1000647 const u32 *ireg;
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000648
649 /* This code does the theorically broken assumption that the interrupt
650 * server numbers are the same as the hard CPU numbers.
651 * This happens to be the case so far but we are playing with fire...
652 * should be fixed one of these days. -BenH.
653 */
Stephen Rothwelle2eb6392007-04-03 22:26:41 +1000654 ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000655
656 /* Do that ever happen ? we'll know soon enough... but even good'old
657 * f80 does have that property ..
658 */
659 WARN_ON(ireg == NULL);
660 if (ireg) {
661 /*
662 * set node starting index for this node
663 */
664 *indx = *ireg;
665 }
Stephen Rothwelle2eb6392007-04-03 22:26:41 +1000666 ireg = of_get_property(np, "reg", &ilen);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000667 if (!ireg)
668 panic("xics_init_IRQ: can't find interrupt reg property");
669
670 while (ilen >= (4 * sizeof(u32))) {
671 unsigned long addr, size;
672
673 /* XXX Use proper OF parsing code here !!! */
674 addr = (unsigned long)*ireg++ << 32;
675 ilen -= sizeof(u32);
676 addr |= *ireg++;
677 ilen -= sizeof(u32);
678 size = (unsigned long)*ireg++ << 32;
679 ilen -= sizeof(u32);
680 size |= *ireg++;
681 ilen -= sizeof(u32);
682 xics_map_one_cpu(*indx, addr, size);
683 (*indx)++;
684 }
685}
686
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000687void __init xics_init_IRQ(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 struct device_node *np;
Nathan Fontenotde0723d2008-02-07 07:37:40 +1100690 u32 indx = 0;
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000691 int found = 0;
Sebastien Dugue1ef80142008-10-22 04:36:32 +0000692 const u32 *isize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
694 ppc64_boot_msg(0x20, "XICS Init");
695
696 ibm_get_xive = rtas_token("ibm,get-xive");
697 ibm_set_xive = rtas_token("ibm,set-xive");
698 ibm_int_on = rtas_token("ibm,int-on");
699 ibm_int_off = rtas_token("ibm,int-off");
700
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000701 for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") {
702 found = 1;
Milton Millera244a952008-10-10 01:56:33 +0000703 if (firmware_has_feature(FW_FEATURE_LPAR)) {
704 of_node_put(np);
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000705 break;
Milton Millera244a952008-10-10 01:56:33 +0000706 }
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000707 xics_init_one_node(np, &indx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000709 if (found == 0)
710 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711
Sebastien Dugue1ef80142008-10-22 04:36:32 +0000712 /* get the bit size of server numbers */
713 found = 0;
714
715 for_each_compatible_node(np, NULL, "ibm,ppc-xics") {
716 isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
717
718 if (!isize)
719 continue;
720
721 if (!found) {
722 interrupt_server_size = *isize;
723 found = 1;
724 } else if (*isize != interrupt_server_size) {
725 printk(KERN_WARNING "XICS: "
726 "mismatched ibm,interrupt-server#-size\n");
727 interrupt_server_size = max(*isize,
728 interrupt_server_size);
729 }
730 }
731
Nathan Fontenotde0723d2008-02-07 07:37:40 +1100732 xics_update_irq_servers();
Milton Miller302905a2008-10-10 01:56:28 +0000733 xics_init_host();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000735 if (firmware_has_feature(FW_FEATURE_LPAR))
736 ppc_md.get_irq = xics_get_irq_lpar;
737 else
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000738 ppc_md.get_irq = xics_get_irq_direct;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Paul Mackerras6c80a212005-05-06 16:28:56 +1000740 xics_setup_cpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741
742 ppc64_boot_msg(0x21, "XICS Done");
743}
744
Milton Miller0641cc92008-10-10 01:56:30 +0000745/* Cpu startup, shutdown, and hotplug */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746
Milton Miller0641cc92008-10-10 01:56:30 +0000747static void xics_set_cpu_priority(unsigned char cppr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
Milton Miller0641cc92008-10-10 01:56:30 +0000749 if (firmware_has_feature(FW_FEATURE_LPAR))
750 lpar_cppr_info(cppr);
751 else
752 direct_cppr_info(cppr);
753 iosync();
754}
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000755
Milton Millerb4963252008-10-10 01:56:34 +0000756/* Have the calling processor join or leave the specified global queue */
757static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
758{
Nathan Lynchedc72ac2008-12-11 09:14:25 +0000759 int index;
760 int status;
761
762 if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL))
763 return;
764
765 index = (1UL << interrupt_server_size) - 1 - gserver;
766
767 status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join);
768
769 WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n",
770 GLOBAL_INTERRUPT_QUEUE, index, join, status);
Milton Millerb4963252008-10-10 01:56:34 +0000771}
Milton Miller0641cc92008-10-10 01:56:30 +0000772
773void xics_setup_cpu(void)
774{
775 xics_set_cpu_priority(0xff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776
Milton Millerb4963252008-10-10 01:56:34 +0000777 xics_set_cpu_giq(default_distrib_server, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778}
Milton Millerd13f7202008-10-10 01:56:29 +0000779
Al Virof10095c2008-03-29 03:10:38 +0000780void xics_teardown_cpu(void)
R Sharadafce0d572005-06-25 14:58:10 -0700781{
782 int cpu = smp_processor_id();
R Sharadafce0d572005-06-25 14:58:10 -0700783
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100784 xics_set_cpu_priority(0);
Haren Myneni81bbbe92006-04-05 21:10:18 -0600785
Milton Millerb4963252008-10-10 01:56:34 +0000786 /* Clear any pending IPI request */
Benjamin Herrenschmidt6e99e452006-07-10 04:44:42 -0700787 if (firmware_has_feature(FW_FEATURE_LPAR))
788 lpar_qirr_info(cpu, 0xff);
789 else
790 direct_qirr_info(cpu, 0xff);
Nathan Fontenotc3e85062008-02-07 07:37:31 +1100791}
792
793void xics_kexec_teardown_cpu(int secondary)
794{
Nathan Fontenotc3e85062008-02-07 07:37:31 +1100795 xics_teardown_cpu();
Benjamin Herrenschmidt6e99e452006-07-10 04:44:42 -0700796
797 /*
Milton Miller1a57c922008-10-10 01:56:35 +0000798 * we take the ipi irq but and never return so we
799 * need to EOI the IPI, but want to leave our priority 0
Haren Myneni81bbbe92006-04-05 21:10:18 -0600800 *
Milton Miller1a57c922008-10-10 01:56:35 +0000801 * should we check all the other interrupts too?
Haren Myneni81bbbe92006-04-05 21:10:18 -0600802 * should we be flagging idle loop instead?
803 * or creating some task to be scheduled?
804 */
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000805
Milton Miller1a57c922008-10-10 01:56:35 +0000806 if (firmware_has_feature(FW_FEATURE_LPAR))
807 lpar_xirr_info_set((0x00 << 24) | XICS_IPI);
808 else
809 direct_xirr_info_set((0x00 << 24) | XICS_IPI);
Haren Myneni81bbbe92006-04-05 21:10:18 -0600810
R Sharadafce0d572005-06-25 14:58:10 -0700811 /*
Paul Mackerras6d22d852005-08-04 12:53:37 -0700812 * Some machines need to have at least one cpu in the GIQ,
813 * so leave the master cpu in the group.
R Sharadafce0d572005-06-25 14:58:10 -0700814 */
Haren Myneni81bbbe92006-04-05 21:10:18 -0600815 if (secondary)
Milton Millerb4963252008-10-10 01:56:34 +0000816 xics_set_cpu_giq(default_distrib_server, 0);
R Sharadafce0d572005-06-25 14:58:10 -0700817}
818
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819#ifdef CONFIG_HOTPLUG_CPU
820
821/* Interrupts are disabled. */
822void xics_migrate_irqs_away(void)
823{
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100824 int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
825 unsigned int irq, virq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Milton Miller302905a2008-10-10 01:56:28 +0000827 /* If we used to be the default server, move to the new "boot_cpuid" */
828 if (hw_cpu == default_server)
829 xics_update_irq_servers();
830
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 /* Reject any interrupt that was queued to us... */
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100832 xics_set_cpu_priority(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Milton Millerb4963252008-10-10 01:56:34 +0000834 /* Remove ourselves from the global interrupt queue */
835 xics_set_cpu_giq(default_distrib_server, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
837 /* Allow IPIs again... */
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100838 xics_set_cpu_priority(DEFAULT_PRIORITY);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 for_each_irq(virq) {
Benjamin Herrenschmidtb9e5b4e2006-07-03 19:32:51 +1000841 struct irq_desc *desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 int xics_status[2];
Milton Millerb4963252008-10-10 01:56:34 +0000843 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 unsigned long flags;
845
846 /* We cant set affinity on ISA interrupts */
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000847 if (virq < NUM_ISA_INTERRUPTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 continue;
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000849 if (irq_map[virq].host != xics_host)
850 continue;
851 irq = (unsigned int)irq_map[virq].hwirq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 /* We need to get IPIs still. */
Benjamin Herrenschmidt0ebfff12006-07-03 21:36:01 +1000853 if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 continue;
Michael Ellerman6cff46f2009-10-13 19:44:51 +0000855 desc = irq_to_desc(virq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856
857 /* We only need to migrate enabled IRQS */
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700858 if (desc == NULL || desc->chip == NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 || desc->action == NULL
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700860 || desc->chip->set_affinity == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 continue;
862
863 spin_lock_irqsave(&desc->lock, flags);
864
865 status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
866 if (status) {
Milton Miller2172fe82008-10-10 01:56:39 +0000867 printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
868 __func__, irq, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 goto unlock;
870 }
871
872 /*
873 * We only support delivery to all cpus or to one cpu.
874 * The irq has to be migrated only in the single cpu
875 * case.
876 */
Milton Millerd7cf0ed2007-12-14 15:52:09 +1100877 if (xics_status[0] != hw_cpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 goto unlock;
879
Anton Blanchard26370322005-09-12 13:12:11 +1000880 printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 virq, cpu);
882
883 /* Reset affinity to all cpus */
Michael Ellerman6cff46f2009-10-13 19:44:51 +0000884 cpumask_setall(irq_to_desc(virq)->affinity);
Rusty Russell0de26522008-12-13 21:20:26 +1030885 desc->chip->set_affinity(virq, cpu_all_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886unlock:
887 spin_unlock_irqrestore(&desc->lock, flags);
888 }
889}
890#endif