aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/ps3/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/ps3/interrupt.c')
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c442
1 files changed, 245 insertions, 197 deletions
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 6f5de438b980..bb17283275aa 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -24,7 +24,6 @@
24 24
25#include <asm/machdep.h> 25#include <asm/machdep.h>
26#include <asm/udbg.h> 26#include <asm/udbg.h>
27#include <asm/ps3.h>
28#include <asm/lv1call.h> 27#include <asm/lv1call.h>
29 28
30#include "platform.h" 29#include "platform.h"
@@ -36,15 +35,148 @@
36#endif 35#endif
37 36
38/** 37/**
38 * struct ps3_bmp - a per cpu irq status and mask bitmap structure
39 * @status: 256 bit status bitmap indexed by plug
40 * @unused_1:
41 * @mask: 256 bit mask bitmap indexed by plug
42 * @unused_2:
43 * @lock:
44 * @ipi_debug_brk_mask:
45 *
46 * The HV mantains per SMT thread mappings of HV outlet to HV plug on
47 * behalf of the guest. These mappings are implemented as 256 bit guest
48 * supplied bitmaps indexed by plug number. The addresses of the bitmaps
49 * are registered with the HV through lv1_configure_irq_state_bitmap().
50 * The HV requires that the 512 bits of status + mask not cross a page
51 * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte
52 * alignment.
53 *
54 * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
55 * of 512 plugs supported on a processor. To simplify the logic this
56 * implementation equates HV plug value to Linux virq value, constrains each
57 * interrupt to have a system wide unique plug number, and limits the range
58 * of the plug values to map into the first dword of the bitmaps. This
59 * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
60 * that there is no constraint on how many in this set an individual thread
61 * can acquire.
62 */
63
64#define PS3_BMP_MINALIGN 64
65
66struct ps3_bmp {
67 struct {
68 u64 status;
69 u64 unused_1[3];
70 u64 mask;
71 u64 unused_2[3];
72 };
73 u64 ipi_debug_brk_mask;
74 spinlock_t lock;
75};
76
77/**
78 * struct ps3_private - a per cpu data structure
79 * @bmp: ps3_bmp structure
80 * @node: HV logical_ppe_id
81 * @cpu: HV thread_id
82 */
83
84struct ps3_private {
85 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
86 u64 node;
87 unsigned int cpu;
88};
89
90static DEFINE_PER_CPU(struct ps3_private, ps3_private);
91
92int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
93 unsigned int *virq)
94{
95 int result;
96 struct ps3_private *pd;
97
98 /* This defines the default interrupt distribution policy. */
99
100 if (cpu == PS3_BINDING_CPU_ANY)
101 cpu = 0;
102
103 pd = &per_cpu(ps3_private, cpu);
104
105 *virq = irq_create_mapping(NULL, outlet);
106
107 if (*virq == NO_IRQ) {
108 pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
109 __func__, __LINE__, outlet);
110 result = -ENOMEM;
111 goto fail_create;
112 }
113
114 /* Binds outlet to cpu + virq. */
115
116 result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
117
118 if (result) {
119 pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
120 __func__, __LINE__, ps3_result(result));
121 result = -EPERM;
122 goto fail_connect;
123 }
124
125 pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
126 outlet, cpu, *virq);
127
128 result = set_irq_chip_data(*virq, pd);
129
130 if (result) {
131 pr_debug("%s:%d: set_irq_chip_data failed\n",
132 __func__, __LINE__);
133 goto fail_set;
134 }
135
136 return result;
137
138fail_set:
139 lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
140fail_connect:
141 irq_dispose_mapping(*virq);
142fail_create:
143 return result;
144}
145EXPORT_SYMBOL_GPL(ps3_alloc_irq);
146
147int ps3_free_irq(unsigned int virq)
148{
149 int result;
150 const struct ps3_private *pd = get_irq_chip_data(virq);
151
152 pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
153 pd->node, pd->cpu, virq);
154
155 result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
156
157 if (result)
158 pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
159 __func__, __LINE__, ps3_result(result));
160
161 set_irq_chip_data(virq, NULL);
162 irq_dispose_mapping(virq);
163 return result;
164}
165EXPORT_SYMBOL_GPL(ps3_free_irq);
166
167/**
39 * ps3_alloc_io_irq - Assign a virq to a system bus device. 168 * ps3_alloc_io_irq - Assign a virq to a system bus device.
40 * interrupt_id: The device interrupt id read from the system repository. 169 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
170 * serviced on.
171 * @interrupt_id: The device interrupt id read from the system repository.
41 * @virq: The assigned Linux virq. 172 * @virq: The assigned Linux virq.
42 * 173 *
43 * An io irq represents a non-virtualized device interrupt. interrupt_id 174 * An io irq represents a non-virtualized device interrupt. interrupt_id
44 * coresponds to the interrupt number of the interrupt controller. 175 * coresponds to the interrupt number of the interrupt controller.
45 */ 176 */
46 177
47int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) 178int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
179 unsigned int *virq)
48{ 180{
49 int result; 181 int result;
50 unsigned long outlet; 182 unsigned long outlet;
@@ -57,12 +189,10 @@ int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq)
57 return result; 189 return result;
58 } 190 }
59 191
60 *virq = irq_create_mapping(NULL, outlet); 192 result = ps3_alloc_irq(cpu, outlet, virq);
61 193 BUG_ON(result);
62 pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n",
63 __func__, __LINE__, interrupt_id, outlet, *virq);
64 194
65 return 0; 195 return result;
66} 196}
67 197
68int ps3_free_io_irq(unsigned int virq) 198int ps3_free_io_irq(unsigned int virq)
@@ -75,13 +205,15 @@ int ps3_free_io_irq(unsigned int virq)
75 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", 205 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
76 __func__, __LINE__, ps3_result(result)); 206 __func__, __LINE__, ps3_result(result));
77 207
78 irq_dispose_mapping(virq); 208 ps3_free_irq(virq);
79 209
80 return result; 210 return result;
81} 211}
82 212
83/** 213/**
84 * ps3_alloc_event_irq - Allocate a virq for use with a system event. 214 * ps3_alloc_event_irq - Allocate a virq for use with a system event.
215 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
216 * serviced on.
85 * @virq: The assigned Linux virq. 217 * @virq: The assigned Linux virq.
86 * 218 *
87 * The virq can be used with lv1_connect_interrupt_event_receive_port() to 219 * The virq can be used with lv1_connect_interrupt_event_receive_port() to
@@ -89,7 +221,7 @@ int ps3_free_io_irq(unsigned int virq)
89 * events. 221 * events.
90 */ 222 */
91 223
92int ps3_alloc_event_irq(unsigned int *virq) 224int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
93{ 225{
94 int result; 226 int result;
95 unsigned long outlet; 227 unsigned long outlet;
@@ -103,12 +235,10 @@ int ps3_alloc_event_irq(unsigned int *virq)
103 return result; 235 return result;
104 } 236 }
105 237
106 *virq = irq_create_mapping(NULL, outlet); 238 result = ps3_alloc_irq(cpu, outlet, virq);
107 239 BUG_ON(result);
108 pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet,
109 *virq);
110 240
111 return 0; 241 return result;
112} 242}
113 243
114int ps3_free_event_irq(unsigned int virq) 244int ps3_free_event_irq(unsigned int virq)
@@ -123,7 +253,7 @@ int ps3_free_event_irq(unsigned int virq)
123 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", 253 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
124 __func__, __LINE__, ps3_result(result)); 254 __func__, __LINE__, ps3_result(result));
125 255
126 irq_dispose_mapping(virq); 256 ps3_free_irq(virq);
127 257
128 pr_debug(" <- %s:%d\n", __func__, __LINE__); 258 pr_debug(" <- %s:%d\n", __func__, __LINE__);
129 return result; 259 return result;
@@ -136,6 +266,8 @@ int ps3_send_event_locally(unsigned int virq)
136 266
137/** 267/**
138 * ps3_connect_event_irq - Assign a virq to a system bus device. 268 * ps3_connect_event_irq - Assign a virq to a system bus device.
269 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
270 * serviced on.
139 * @did: The HV device identifier read from the system repository. 271 * @did: The HV device identifier read from the system repository.
140 * @interrupt_id: The device interrupt id read from the system repository. 272 * @interrupt_id: The device interrupt id read from the system repository.
141 * @virq: The assigned Linux virq. 273 * @virq: The assigned Linux virq.
@@ -144,12 +276,13 @@ int ps3_send_event_locally(unsigned int virq)
144 * coresponds to the software interrupt number. 276 * coresponds to the software interrupt number.
145 */ 277 */
146 278
147int ps3_connect_event_irq(const struct ps3_device_id *did, 279int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
148 unsigned int interrupt_id, unsigned int *virq) 280 const struct ps3_device_id *did, unsigned int interrupt_id,
281 unsigned int *virq)
149{ 282{
150 int result; 283 int result;
151 284
152 result = ps3_alloc_event_irq(virq); 285 result = ps3_alloc_event_irq(cpu, virq);
153 286
154 if (result) 287 if (result)
155 return result; 288 return result;
@@ -196,6 +329,8 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
196 329
197/** 330/**
198 * ps3_alloc_vuart_irq - Configure the system virtual uart virq. 331 * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
332 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
333 * serviced on.
199 * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. 334 * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
200 * @virq: The assigned Linux virq. 335 * @virq: The assigned Linux virq.
201 * 336 *
@@ -203,13 +338,14 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
203 * freeing the interrupt will return a wrong state error. 338 * freeing the interrupt will return a wrong state error.
204 */ 339 */
205 340
206int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) 341int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
342 unsigned int *virq)
207{ 343{
208 int result; 344 int result;
209 unsigned long outlet; 345 unsigned long outlet;
210 unsigned long lpar_addr; 346 u64 lpar_addr;
211 347
212 BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); 348 BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
213 349
214 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); 350 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
215 351
@@ -221,12 +357,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq)
221 return result; 357 return result;
222 } 358 }
223 359
224 *virq = irq_create_mapping(NULL, outlet); 360 result = ps3_alloc_irq(cpu, outlet, virq);
225 361 BUG_ON(result);
226 pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__,
227 outlet, *virq);
228 362
229 return 0; 363 return result;
230} 364}
231 365
232int ps3_free_vuart_irq(unsigned int virq) 366int ps3_free_vuart_irq(unsigned int virq)
@@ -241,21 +375,23 @@ int ps3_free_vuart_irq(unsigned int virq)
241 return result; 375 return result;
242 } 376 }
243 377
244 irq_dispose_mapping(virq); 378 ps3_free_irq(virq);
245 379
246 return result; 380 return result;
247} 381}
248 382
249/** 383/**
250 * ps3_alloc_spe_irq - Configure an spe virq. 384 * ps3_alloc_spe_irq - Configure an spe virq.
385 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
386 * serviced on.
251 * @spe_id: The spe_id returned from lv1_construct_logical_spe(). 387 * @spe_id: The spe_id returned from lv1_construct_logical_spe().
252 * @class: The spe interrupt class {0,1,2}. 388 * @class: The spe interrupt class {0,1,2}.
253 * @virq: The assigned Linux virq. 389 * @virq: The assigned Linux virq.
254 * 390 *
255 */ 391 */
256 392
257int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, 393int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
258 unsigned int *virq) 394 unsigned int class, unsigned int *virq)
259{ 395{
260 int result; 396 int result;
261 unsigned long outlet; 397 unsigned long outlet;
@@ -270,73 +406,24 @@ int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
270 return result; 406 return result;
271 } 407 }
272 408
273 *virq = irq_create_mapping(NULL, outlet); 409 result = ps3_alloc_irq(cpu, outlet, virq);
274 410 BUG_ON(result);
275 pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n",
276 __func__, __LINE__, spe_id, class, outlet, *virq);
277 411
278 return 0; 412 return result;
279} 413}
280 414
281int ps3_free_spe_irq(unsigned int virq) 415int ps3_free_spe_irq(unsigned int virq)
282{ 416{
283 irq_dispose_mapping(virq); 417 ps3_free_irq(virq);
284 return 0; 418 return 0;
285} 419}
286 420
421
287#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) 422#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
288#define PS3_PLUG_MAX 63 423#define PS3_PLUG_MAX 63
289 424
290/**
291 * struct bmp - a per cpu irq status and mask bitmap structure
292 * @status: 256 bit status bitmap indexed by plug
293 * @unused_1:
294 * @mask: 256 bit mask bitmap indexed by plug
295 * @unused_2:
296 * @lock:
297 * @ipi_debug_brk_mask:
298 *
299 * The HV mantains per SMT thread mappings of HV outlet to HV plug on
300 * behalf of the guest. These mappings are implemented as 256 bit guest
301 * supplied bitmaps indexed by plug number. The address of the bitmaps are
302 * registered with the HV through lv1_configure_irq_state_bitmap().
303 *
304 * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
305 * of 512 plugs supported on a processor. To simplify the logic this
306 * implementation equates HV plug value to linux virq value, constrains each
307 * interrupt to have a system wide unique plug number, and limits the range
308 * of the plug values to map into the first dword of the bitmaps. This
309 * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
310 * that there is no constraint on how many in this set an individual thread
311 * can aquire.
312 */
313
314struct bmp {
315 struct {
316 unsigned long status;
317 unsigned long unused_1[3];
318 unsigned long mask;
319 unsigned long unused_2[3];
320 } __attribute__ ((packed));
321 spinlock_t lock;
322 unsigned long ipi_debug_brk_mask;
323};
324
325/**
326 * struct private - a per cpu data structure
327 * @node: HV node id
328 * @cpu: HV thread id
329 * @bmp: an HV bmp structure
330 */
331
332struct private {
333 unsigned long node;
334 unsigned int cpu;
335 struct bmp bmp;
336};
337
338#if defined(DEBUG) 425#if defined(DEBUG)
339static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, 426static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
340 const char* func, int line) 427 const char* func, int line)
341{ 428{
342 pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", 429 pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
@@ -346,14 +433,14 @@ static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cp
346} 433}
347 434
348static void __attribute__ ((unused)) _dump_256_bmp(const char *header, 435static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
349 const unsigned long *p, unsigned cpu, const char* func, int line) 436 const u64 *p, unsigned cpu, const char* func, int line)
350{ 437{
351 pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", 438 pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
352 func, line, header, cpu, p[0], p[1], p[2], p[3]); 439 func, line, header, cpu, p[0], p[1], p[2], p[3]);
353} 440}
354 441
355#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) 442#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
356static void _dump_bmp(struct private* pd, const char* func, int line) 443static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
357{ 444{
358 unsigned long flags; 445 unsigned long flags;
359 446
@@ -364,7 +451,7 @@ static void _dump_bmp(struct private* pd, const char* func, int line)
364} 451}
365 452
366#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) 453#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
367static void __attribute__ ((unused)) _dump_mask(struct private* pd, 454static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
368 const char* func, int line) 455 const char* func, int line)
369{ 456{
370 unsigned long flags; 457 unsigned long flags;
@@ -374,109 +461,94 @@ static void __attribute__ ((unused)) _dump_mask(struct private* pd,
374 spin_unlock_irqrestore(&pd->bmp.lock, flags); 461 spin_unlock_irqrestore(&pd->bmp.lock, flags);
375} 462}
376#else 463#else
377static void dump_bmp(struct private* pd) {}; 464static void dump_bmp(struct ps3_private* pd) {};
378#endif /* defined(DEBUG) */ 465#endif /* defined(DEBUG) */
379 466
380static void chip_mask(unsigned int virq) 467static void ps3_chip_mask(unsigned int virq)
381{ 468{
469 struct ps3_private *pd = get_irq_chip_data(virq);
470 u64 bit = 0x8000000000000000UL >> virq;
471 u64 *p = &pd->bmp.mask;
472 u64 old;
382 unsigned long flags; 473 unsigned long flags;
383 struct private *pd = get_irq_chip_data(virq);
384 474
385 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 475 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
386 476
387 BUG_ON(virq < NUM_ISA_INTERRUPTS); 477 local_irq_save(flags);
388 BUG_ON(virq > PS3_PLUG_MAX); 478 asm volatile(
389 479 "1: ldarx %0,0,%3\n"
390 spin_lock_irqsave(&pd->bmp.lock, flags); 480 "andc %0,%0,%2\n"
391 pd->bmp.mask &= ~(0x8000000000000000UL >> virq); 481 "stdcx. %0,0,%3\n"
392 spin_unlock_irqrestore(&pd->bmp.lock, flags); 482 "bne- 1b"
483 : "=&r" (old), "+m" (*p)
484 : "r" (bit), "r" (p)
485 : "cc" );
393 486
394 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 487 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
488 local_irq_restore(flags);
395} 489}
396 490
397static void chip_unmask(unsigned int virq) 491static void ps3_chip_unmask(unsigned int virq)
398{ 492{
493 struct ps3_private *pd = get_irq_chip_data(virq);
494 u64 bit = 0x8000000000000000UL >> virq;
495 u64 *p = &pd->bmp.mask;
496 u64 old;
399 unsigned long flags; 497 unsigned long flags;
400 struct private *pd = get_irq_chip_data(virq);
401 498
402 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 499 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
403 500
404 BUG_ON(virq < NUM_ISA_INTERRUPTS); 501 local_irq_save(flags);
405 BUG_ON(virq > PS3_PLUG_MAX); 502 asm volatile(
406 503 "1: ldarx %0,0,%3\n"
407 spin_lock_irqsave(&pd->bmp.lock, flags); 504 "or %0,%0,%2\n"
408 pd->bmp.mask |= (0x8000000000000000UL >> virq); 505 "stdcx. %0,0,%3\n"
409 spin_unlock_irqrestore(&pd->bmp.lock, flags); 506 "bne- 1b"
507 : "=&r" (old), "+m" (*p)
508 : "r" (bit), "r" (p)
509 : "cc" );
410 510
411 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 511 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
512 local_irq_restore(flags);
412} 513}
413 514
414static void chip_eoi(unsigned int virq) 515static void ps3_chip_eoi(unsigned int virq)
415{ 516{
416 lv1_end_of_interrupt(virq); 517 const struct ps3_private *pd = get_irq_chip_data(virq);
518 lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
417} 519}
418 520
419static struct irq_chip irq_chip = { 521static struct irq_chip irq_chip = {
420 .typename = "ps3", 522 .typename = "ps3",
421 .mask = chip_mask, 523 .mask = ps3_chip_mask,
422 .unmask = chip_unmask, 524 .unmask = ps3_chip_unmask,
423 .eoi = chip_eoi, 525 .eoi = ps3_chip_eoi,
424}; 526};
425 527
426static void host_unmap(struct irq_host *h, unsigned int virq) 528static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
427{ 529{
428 int result; 530 set_irq_chip_data(virq, NULL);
429
430 pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq);
431
432 lv1_disconnect_irq_plug(virq);
433
434 result = set_irq_chip_data(virq, NULL);
435 BUG_ON(result);
436} 531}
437 532
438static DEFINE_PER_CPU(struct private, private); 533static int ps3_host_map(struct irq_host *h, unsigned int virq,
439
440static int host_map(struct irq_host *h, unsigned int virq,
441 irq_hw_number_t hwirq) 534 irq_hw_number_t hwirq)
442{ 535{
443 int result; 536 pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
444 unsigned int cpu;
445
446 pr_debug(" -> %s:%d\n", __func__, __LINE__);
447 pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq,
448 virq); 537 virq);
449 538
450 /* bind this virq to a cpu */
451
452 preempt_disable();
453 cpu = smp_processor_id();
454 result = lv1_connect_irq_plug(virq, hwirq);
455 preempt_enable();
456
457 if (result) {
458 pr_info("%s:%d: lv1_connect_irq_plug failed:"
459 " %s\n", __func__, __LINE__, ps3_result(result));
460 return -EPERM;
461 }
462
463 result = set_irq_chip_data(virq, &per_cpu(private, cpu));
464 BUG_ON(result);
465
466 set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); 539 set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
467 540
468 pr_debug(" <- %s:%d\n", __func__, __LINE__); 541 return 0;
469 return result;
470} 542}
471 543
472static struct irq_host_ops host_ops = { 544static struct irq_host_ops ps3_host_ops = {
473 .map = host_map, 545 .map = ps3_host_map,
474 .unmap = host_unmap, 546 .unmap = ps3_host_unmap,
475}; 547};
476 548
477void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) 549void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
478{ 550{
479 struct private *pd = &per_cpu(private, cpu); 551 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
480 552
481 pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; 553 pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
482 554
@@ -484,57 +556,32 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
484 cpu, virq, pd->bmp.ipi_debug_brk_mask); 556 cpu, virq, pd->bmp.ipi_debug_brk_mask);
485} 557}
486 558
487static int bmp_get_and_clear_status_bit(struct bmp *m) 559unsigned int ps3_get_irq(void)
488{ 560{
489 unsigned long flags; 561 struct ps3_private *pd = &__get_cpu_var(ps3_private);
490 unsigned int bit; 562 u64 x = (pd->bmp.status & pd->bmp.mask);
491 unsigned long x; 563 unsigned int plug;
492
493 spin_lock_irqsave(&m->lock, flags);
494 564
495 /* check for ipi break first to stop this cpu ASAP */ 565 /* check for ipi break first to stop this cpu ASAP */
496 566
497 if (m->status & m->ipi_debug_brk_mask) { 567 if (x & pd->bmp.ipi_debug_brk_mask)
498 m->status &= ~m->ipi_debug_brk_mask; 568 x &= pd->bmp.ipi_debug_brk_mask;
499 spin_unlock_irqrestore(&m->lock, flags);
500 return __ilog2(m->ipi_debug_brk_mask);
501 }
502
503 x = (m->status & m->mask);
504 569
505 for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1) 570 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
506 if (x & 0x8000000000000000UL) { 571 plug &= 0x3f;
507 m->status &= ~(0x8000000000000000UL >> bit);
508 spin_unlock_irqrestore(&m->lock, flags);
509 return bit;
510 }
511 572
512 spin_unlock_irqrestore(&m->lock, flags); 573 if (unlikely(plug) == NO_IRQ) {
513
514 pr_debug("%s:%d: not found\n", __func__, __LINE__);
515 return -1;
516}
517
518unsigned int ps3_get_irq(void)
519{
520 int plug;
521
522 struct private *pd = &__get_cpu_var(private);
523
524 plug = bmp_get_and_clear_status_bit(&pd->bmp);
525
526 if (plug < 1) {
527 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, 574 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
528 pd->cpu); 575 pd->cpu);
529 dump_bmp(&per_cpu(private, 0)); 576 dump_bmp(&per_cpu(ps3_private, 0));
530 dump_bmp(&per_cpu(private, 1)); 577 dump_bmp(&per_cpu(ps3_private, 1));
531 return NO_IRQ; 578 return NO_IRQ;
532 } 579 }
533 580
534#if defined(DEBUG) 581#if defined(DEBUG)
535 if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) { 582 if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
536 dump_bmp(&per_cpu(private, 0)); 583 dump_bmp(&per_cpu(ps3_private, 0));
537 dump_bmp(&per_cpu(private, 1)); 584 dump_bmp(&per_cpu(ps3_private, 1));
538 BUG(); 585 BUG();
539 } 586 }
540#endif 587#endif
@@ -544,26 +591,27 @@ unsigned int ps3_get_irq(void)
544void __init ps3_init_IRQ(void) 591void __init ps3_init_IRQ(void)
545{ 592{
546 int result; 593 int result;
547 unsigned long node;
548 unsigned cpu; 594 unsigned cpu;
549 struct irq_host *host; 595 struct irq_host *host;
550 596
551 lv1_get_logical_ppe_id(&node); 597 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
552
553 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops,
554 PS3_INVALID_OUTLET); 598 PS3_INVALID_OUTLET);
555 irq_set_default_host(host); 599 irq_set_default_host(host);
556 irq_set_virq_count(PS3_PLUG_MAX + 1); 600 irq_set_virq_count(PS3_PLUG_MAX + 1);
557 601
558 for_each_possible_cpu(cpu) { 602 for_each_possible_cpu(cpu) {
559 struct private *pd = &per_cpu(private, cpu); 603 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
560 604
561 pd->node = node; 605 lv1_get_logical_ppe_id(&pd->node);
562 pd->cpu = cpu; 606 pd->cpu = get_hard_smp_processor_id(cpu);
563 spin_lock_init(&pd->bmp.lock); 607 spin_lock_init(&pd->bmp.lock);
564 608
565 result = lv1_configure_irq_state_bitmap(node, cpu, 609 pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
566 ps3_mm_phys_to_lpar(__pa(&pd->bmp.status))); 610 __LINE__, pd->node, pd->cpu,
611 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
612
613 result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
614 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
567 615
568 if (result) 616 if (result)
569 pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" 617 pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"