diff options
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 299 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 12 | ||||
-rw-r--r-- | drivers/ps3/vuart.c | 4 | ||||
-rw-r--r-- | include/asm-powerpc/ps3.h | 23 |
5 files changed, 200 insertions, 140 deletions
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index d3c97fbff7ef..27afd1f0358a 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -36,15 +36,140 @@ | |||
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * struct ps3_bmp - a per cpu irq status and mask bitmap structure | ||
40 | * @status: 256 bit status bitmap indexed by plug | ||
41 | * @unused_1: | ||
42 | * @mask: 256 bit mask bitmap indexed by plug | ||
43 | * @unused_2: | ||
44 | * @lock: | ||
45 | * @ipi_debug_brk_mask: | ||
46 | * | ||
47 | * The HV mantains per SMT thread mappings of HV outlet to HV plug on | ||
48 | * behalf of the guest. These mappings are implemented as 256 bit guest | ||
49 | * supplied bitmaps indexed by plug number. The addresses of the bitmaps | ||
50 | * are registered with the HV through lv1_configure_irq_state_bitmap(). | ||
51 | * | ||
52 | * The HV supports 256 plugs per thread, assigned as {0..255}, for a total | ||
53 | * of 512 plugs supported on a processor. To simplify the logic this | ||
54 | * implementation equates HV plug value to Linux virq value, constrains each | ||
55 | * interrupt to have a system wide unique plug number, and limits the range | ||
56 | * of the plug values to map into the first dword of the bitmaps. This | ||
57 | * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note | ||
58 | * that there is no constraint on how many in this set an individual thread | ||
59 | * can acquire. | ||
60 | */ | ||
61 | |||
62 | struct ps3_bmp { | ||
63 | struct { | ||
64 | u64 status; | ||
65 | u64 unused_1[3]; | ||
66 | u64 mask; | ||
67 | u64 unused_2[3]; | ||
68 | }; | ||
69 | u64 ipi_debug_brk_mask; | ||
70 | spinlock_t lock; | ||
71 | }; | ||
72 | |||
73 | /** | ||
74 | * struct ps3_private - a per cpu data structure | ||
75 | * @bmp: ps3_bmp structure | ||
76 | * @node: HV logical_ppe_id | ||
77 | * @cpu: HV thread_id | ||
78 | */ | ||
79 | |||
80 | struct ps3_private { | ||
81 | struct ps3_bmp bmp __attribute__ ((aligned (64))); | ||
82 | u64 node; | ||
83 | unsigned int cpu; | ||
84 | }; | ||
85 | |||
86 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | ||
87 | |||
88 | static int ps3_connect_irq(enum ps3_cpu_binding cpu, unsigned long outlet, | ||
89 | unsigned int *virq) | ||
90 | { | ||
91 | int result; | ||
92 | struct ps3_private *pd; | ||
93 | |||
94 | /* This defines the default interrupt distribution policy. */ | ||
95 | |||
96 | if (cpu == PS3_BINDING_CPU_ANY) | ||
97 | cpu = 0; | ||
98 | |||
99 | pd = &per_cpu(ps3_private, cpu); | ||
100 | |||
101 | *virq = irq_create_mapping(NULL, outlet); | ||
102 | |||
103 | if (*virq == NO_IRQ) { | ||
104 | pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", | ||
105 | __func__, __LINE__, outlet); | ||
106 | result = -ENOMEM; | ||
107 | goto fail_create; | ||
108 | } | ||
109 | |||
110 | /* Binds outlet to cpu + virq. */ | ||
111 | |||
112 | result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); | ||
113 | |||
114 | if (result) { | ||
115 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", | ||
116 | __func__, __LINE__, ps3_result(result)); | ||
117 | result = -EPERM; | ||
118 | goto fail_connect; | ||
119 | } | ||
120 | |||
121 | pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, | ||
122 | outlet, cpu, *virq); | ||
123 | |||
124 | result = set_irq_chip_data(*virq, pd); | ||
125 | |||
126 | if (result) { | ||
127 | pr_debug("%s:%d: set_irq_chip_data failed\n", | ||
128 | __func__, __LINE__); | ||
129 | goto fail_set; | ||
130 | } | ||
131 | |||
132 | return result; | ||
133 | |||
134 | fail_set: | ||
135 | lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); | ||
136 | fail_connect: | ||
137 | irq_dispose_mapping(*virq); | ||
138 | fail_create: | ||
139 | return result; | ||
140 | } | ||
141 | |||
142 | static void ps3_disconnect_irq(unsigned int virq) | ||
143 | { | ||
144 | int result; | ||
145 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
146 | |||
147 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | ||
148 | pd->node, pd->cpu, virq); | ||
149 | |||
150 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | ||
151 | |||
152 | if (result) | ||
153 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", | ||
154 | __func__, __LINE__, ps3_result(result)); | ||
155 | |||
156 | set_irq_chip_data(virq, NULL); | ||
157 | irq_dispose_mapping(virq); | ||
158 | } | ||
159 | |||
160 | /** | ||
39 | * ps3_alloc_io_irq - Assign a virq to a system bus device. | 161 | * ps3_alloc_io_irq - Assign a virq to a system bus device. |
40 | * interrupt_id: The device interrupt id read from the system repository. | 162 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
163 | * serviced on. | ||
164 | * @interrupt_id: The device interrupt id read from the system repository. | ||
41 | * @virq: The assigned Linux virq. | 165 | * @virq: The assigned Linux virq. |
42 | * | 166 | * |
43 | * An io irq represents a non-virtualized device interrupt. interrupt_id | 167 | * An io irq represents a non-virtualized device interrupt. interrupt_id |
44 | * coresponds to the interrupt number of the interrupt controller. | 168 | * coresponds to the interrupt number of the interrupt controller. |
45 | */ | 169 | */ |
46 | 170 | ||
47 | int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) | 171 | int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, |
172 | unsigned int *virq) | ||
48 | { | 173 | { |
49 | int result; | 174 | int result; |
50 | unsigned long outlet; | 175 | unsigned long outlet; |
@@ -57,12 +182,10 @@ int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) | |||
57 | return result; | 182 | return result; |
58 | } | 183 | } |
59 | 184 | ||
60 | *virq = irq_create_mapping(NULL, outlet); | 185 | result = ps3_connect_irq(cpu, outlet, virq); |
61 | 186 | BUG_ON(result); | |
62 | pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n", | ||
63 | __func__, __LINE__, interrupt_id, outlet, *virq); | ||
64 | 187 | ||
65 | return 0; | 188 | return result; |
66 | } | 189 | } |
67 | 190 | ||
68 | int ps3_free_io_irq(unsigned int virq) | 191 | int ps3_free_io_irq(unsigned int virq) |
@@ -75,13 +198,15 @@ int ps3_free_io_irq(unsigned int virq) | |||
75 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | 198 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", |
76 | __func__, __LINE__, ps3_result(result)); | 199 | __func__, __LINE__, ps3_result(result)); |
77 | 200 | ||
78 | irq_dispose_mapping(virq); | 201 | ps3_disconnect_irq(virq); |
79 | 202 | ||
80 | return result; | 203 | return result; |
81 | } | 204 | } |
82 | 205 | ||
83 | /** | 206 | /** |
84 | * ps3_alloc_event_irq - Allocate a virq for use with a system event. | 207 | * ps3_alloc_event_irq - Allocate a virq for use with a system event. |
208 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
209 | * serviced on. | ||
85 | * @virq: The assigned Linux virq. | 210 | * @virq: The assigned Linux virq. |
86 | * | 211 | * |
87 | * The virq can be used with lv1_connect_interrupt_event_receive_port() to | 212 | * The virq can be used with lv1_connect_interrupt_event_receive_port() to |
@@ -89,7 +214,7 @@ int ps3_free_io_irq(unsigned int virq) | |||
89 | * events. | 214 | * events. |
90 | */ | 215 | */ |
91 | 216 | ||
92 | int ps3_alloc_event_irq(unsigned int *virq) | 217 | int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq) |
93 | { | 218 | { |
94 | int result; | 219 | int result; |
95 | unsigned long outlet; | 220 | unsigned long outlet; |
@@ -103,12 +228,10 @@ int ps3_alloc_event_irq(unsigned int *virq) | |||
103 | return result; | 228 | return result; |
104 | } | 229 | } |
105 | 230 | ||
106 | *virq = irq_create_mapping(NULL, outlet); | 231 | result = ps3_connect_irq(cpu, outlet, virq); |
107 | 232 | BUG_ON(result); | |
108 | pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet, | ||
109 | *virq); | ||
110 | 233 | ||
111 | return 0; | 234 | return result; |
112 | } | 235 | } |
113 | 236 | ||
114 | int ps3_free_event_irq(unsigned int virq) | 237 | int ps3_free_event_irq(unsigned int virq) |
@@ -123,7 +246,7 @@ int ps3_free_event_irq(unsigned int virq) | |||
123 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", | 246 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", |
124 | __func__, __LINE__, ps3_result(result)); | 247 | __func__, __LINE__, ps3_result(result)); |
125 | 248 | ||
126 | irq_dispose_mapping(virq); | 249 | ps3_disconnect_irq(virq); |
127 | 250 | ||
128 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 251 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
129 | return result; | 252 | return result; |
@@ -136,6 +259,8 @@ int ps3_send_event_locally(unsigned int virq) | |||
136 | 259 | ||
137 | /** | 260 | /** |
138 | * ps3_connect_event_irq - Assign a virq to a system bus device. | 261 | * ps3_connect_event_irq - Assign a virq to a system bus device. |
262 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
263 | * serviced on. | ||
139 | * @did: The HV device identifier read from the system repository. | 264 | * @did: The HV device identifier read from the system repository. |
140 | * @interrupt_id: The device interrupt id read from the system repository. | 265 | * @interrupt_id: The device interrupt id read from the system repository. |
141 | * @virq: The assigned Linux virq. | 266 | * @virq: The assigned Linux virq. |
@@ -144,12 +269,13 @@ int ps3_send_event_locally(unsigned int virq) | |||
144 | * coresponds to the software interrupt number. | 269 | * coresponds to the software interrupt number. |
145 | */ | 270 | */ |
146 | 271 | ||
147 | int ps3_connect_event_irq(const struct ps3_device_id *did, | 272 | int ps3_connect_event_irq(enum ps3_cpu_binding cpu, |
148 | unsigned int interrupt_id, unsigned int *virq) | 273 | const struct ps3_device_id *did, unsigned int interrupt_id, |
274 | unsigned int *virq) | ||
149 | { | 275 | { |
150 | int result; | 276 | int result; |
151 | 277 | ||
152 | result = ps3_alloc_event_irq(virq); | 278 | result = ps3_alloc_event_irq(cpu, virq); |
153 | 279 | ||
154 | if (result) | 280 | if (result) |
155 | return result; | 281 | return result; |
@@ -196,6 +322,8 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, | |||
196 | 322 | ||
197 | /** | 323 | /** |
198 | * ps3_alloc_vuart_irq - Configure the system virtual uart virq. | 324 | * ps3_alloc_vuart_irq - Configure the system virtual uart virq. |
325 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
326 | * serviced on. | ||
199 | * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. | 327 | * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. |
200 | * @virq: The assigned Linux virq. | 328 | * @virq: The assigned Linux virq. |
201 | * | 329 | * |
@@ -203,13 +331,14 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, | |||
203 | * freeing the interrupt will return a wrong state error. | 331 | * freeing the interrupt will return a wrong state error. |
204 | */ | 332 | */ |
205 | 333 | ||
206 | int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) | 334 | int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, |
335 | unsigned int *virq) | ||
207 | { | 336 | { |
208 | int result; | 337 | int result; |
209 | unsigned long outlet; | 338 | unsigned long outlet; |
210 | unsigned long lpar_addr; | 339 | u64 lpar_addr; |
211 | 340 | ||
212 | BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); | 341 | BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); |
213 | 342 | ||
214 | lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); | 343 | lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); |
215 | 344 | ||
@@ -221,12 +350,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) | |||
221 | return result; | 350 | return result; |
222 | } | 351 | } |
223 | 352 | ||
224 | *virq = irq_create_mapping(NULL, outlet); | 353 | result = ps3_connect_irq(cpu, outlet, virq); |
225 | 354 | BUG_ON(result); | |
226 | pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, | ||
227 | outlet, *virq); | ||
228 | 355 | ||
229 | return 0; | 356 | return result; |
230 | } | 357 | } |
231 | 358 | ||
232 | int ps3_free_vuart_irq(unsigned int virq) | 359 | int ps3_free_vuart_irq(unsigned int virq) |
@@ -241,21 +368,23 @@ int ps3_free_vuart_irq(unsigned int virq) | |||
241 | return result; | 368 | return result; |
242 | } | 369 | } |
243 | 370 | ||
244 | irq_dispose_mapping(virq); | 371 | ps3_disconnect_irq(virq); |
245 | 372 | ||
246 | return result; | 373 | return result; |
247 | } | 374 | } |
248 | 375 | ||
249 | /** | 376 | /** |
250 | * ps3_alloc_spe_irq - Configure an spe virq. | 377 | * ps3_alloc_spe_irq - Configure an spe virq. |
378 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
379 | * serviced on. | ||
251 | * @spe_id: The spe_id returned from lv1_construct_logical_spe(). | 380 | * @spe_id: The spe_id returned from lv1_construct_logical_spe(). |
252 | * @class: The spe interrupt class {0,1,2}. | 381 | * @class: The spe interrupt class {0,1,2}. |
253 | * @virq: The assigned Linux virq. | 382 | * @virq: The assigned Linux virq. |
254 | * | 383 | * |
255 | */ | 384 | */ |
256 | 385 | ||
257 | int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | 386 | int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, |
258 | unsigned int *virq) | 387 | unsigned int class, unsigned int *virq) |
259 | { | 388 | { |
260 | int result; | 389 | int result; |
261 | unsigned long outlet; | 390 | unsigned long outlet; |
@@ -270,74 +399,23 @@ int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | |||
270 | return result; | 399 | return result; |
271 | } | 400 | } |
272 | 401 | ||
273 | *virq = irq_create_mapping(NULL, outlet); | 402 | result = ps3_connect_irq(cpu, outlet, virq); |
274 | 403 | 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 | 404 | ||
278 | return 0; | 405 | return result; |
279 | } | 406 | } |
280 | 407 | ||
281 | int ps3_free_spe_irq(unsigned int virq) | 408 | int ps3_free_spe_irq(unsigned int virq) |
282 | { | 409 | { |
283 | irq_dispose_mapping(virq); | 410 | ps3_disconnect_irq(virq); |
284 | return 0; | 411 | return 0; |
285 | } | 412 | } |
286 | 413 | ||
287 | #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) | 414 | #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) |
288 | #define PS3_PLUG_MAX 63 | 415 | #define PS3_PLUG_MAX 63 |
289 | 416 | ||
290 | /** | ||
291 | * struct ps3_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 | |||
314 | struct ps3_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__ ((aligned (64))); | ||
321 | |||
322 | spinlock_t lock; | ||
323 | unsigned long ipi_debug_brk_mask; | ||
324 | }; | ||
325 | |||
326 | /** | ||
327 | * struct ps3_private - a per cpu data structure | ||
328 | * @bmp: ps3_bmp structure | ||
329 | * @node: HV logical_ppe_id | ||
330 | * @cpu: HV thread_id | ||
331 | */ | ||
332 | |||
333 | struct ps3_private { | ||
334 | struct ps3_bmp bmp; | ||
335 | unsigned long node; | ||
336 | unsigned int cpu; | ||
337 | }; | ||
338 | |||
339 | #if defined(DEBUG) | 417 | #if defined(DEBUG) |
340 | static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, | 418 | static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, |
341 | const char* func, int line) | 419 | const char* func, int line) |
342 | { | 420 | { |
343 | pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", | 421 | pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", |
@@ -347,7 +425,7 @@ static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cp | |||
347 | } | 425 | } |
348 | 426 | ||
349 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, | 427 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, |
350 | const unsigned long *p, unsigned cpu, const char* func, int line) | 428 | const u64 *p, unsigned cpu, const char* func, int line) |
351 | { | 429 | { |
352 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", | 430 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", |
353 | func, line, header, cpu, p[0], p[1], p[2], p[3]); | 431 | func, line, header, cpu, p[0], p[1], p[2], p[3]); |
@@ -381,9 +459,9 @@ static void dump_bmp(struct ps3_private* pd) {}; | |||
381 | static void ps3_chip_mask(unsigned int virq) | 459 | static void ps3_chip_mask(unsigned int virq) |
382 | { | 460 | { |
383 | struct ps3_private *pd = get_irq_chip_data(virq); | 461 | struct ps3_private *pd = get_irq_chip_data(virq); |
384 | unsigned long bit = 0x8000000000000000UL >> virq; | 462 | u64 bit = 0x8000000000000000UL >> virq; |
385 | unsigned long *p = &pd->bmp.mask; | 463 | u64 *p = &pd->bmp.mask; |
386 | unsigned long old; | 464 | u64 old; |
387 | unsigned long flags; | 465 | unsigned long flags; |
388 | 466 | ||
389 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | 467 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); |
@@ -405,9 +483,9 @@ static void ps3_chip_mask(unsigned int virq) | |||
405 | static void ps3_chip_unmask(unsigned int virq) | 483 | static void ps3_chip_unmask(unsigned int virq) |
406 | { | 484 | { |
407 | struct ps3_private *pd = get_irq_chip_data(virq); | 485 | struct ps3_private *pd = get_irq_chip_data(virq); |
408 | unsigned long bit = 0x8000000000000000UL >> virq; | 486 | u64 bit = 0x8000000000000000UL >> virq; |
409 | unsigned long *p = &pd->bmp.mask; | 487 | u64 *p = &pd->bmp.mask; |
410 | unsigned long old; | 488 | u64 old; |
411 | unsigned long flags; | 489 | unsigned long flags; |
412 | 490 | ||
413 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | 491 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); |
@@ -441,45 +519,18 @@ static struct irq_chip irq_chip = { | |||
441 | 519 | ||
442 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) | 520 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) |
443 | { | 521 | { |
444 | int result; | 522 | set_irq_chip_data(virq, NULL); |
445 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
446 | |||
447 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | ||
448 | pd->node, pd->cpu, virq); | ||
449 | |||
450 | lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | ||
451 | |||
452 | result = set_irq_chip_data(virq, NULL); | ||
453 | BUG_ON(result); | ||
454 | } | 523 | } |
455 | 524 | ||
456 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | ||
457 | |||
458 | static int ps3_host_map(struct irq_host *h, unsigned int virq, | 525 | static int ps3_host_map(struct irq_host *h, unsigned int virq, |
459 | irq_hw_number_t hwirq) | 526 | irq_hw_number_t hwirq) |
460 | { | 527 | { |
461 | int result; | 528 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, |
462 | struct ps3_private *pd = &__get_cpu_var(ps3_private); | 529 | virq); |
463 | |||
464 | pr_debug("%s:%d: node %lu, cpu %d, hwirq %lu => virq %u\n", __func__, | ||
465 | __LINE__, pd->node, pd->cpu, hwirq, virq); | ||
466 | |||
467 | /* Binds this virq to pd->cpu (current cpu) */ | ||
468 | |||
469 | result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, virq, hwirq, 0); | ||
470 | |||
471 | if (result) { | ||
472 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed:" | ||
473 | " %s\n", __func__, __LINE__, ps3_result(result)); | ||
474 | return -EPERM; | ||
475 | } | ||
476 | |||
477 | result = set_irq_chip_data(virq, pd); | ||
478 | BUG_ON(result); | ||
479 | 530 | ||
480 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); | 531 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); |
481 | 532 | ||
482 | return result; | 533 | return 0; |
483 | } | 534 | } |
484 | 535 | ||
485 | static struct irq_host_ops ps3_host_ops = { | 536 | static struct irq_host_ops ps3_host_ops = { |
@@ -500,7 +551,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | |||
500 | unsigned int ps3_get_irq(void) | 551 | unsigned int ps3_get_irq(void) |
501 | { | 552 | { |
502 | struct ps3_private *pd = &__get_cpu_var(ps3_private); | 553 | struct ps3_private *pd = &__get_cpu_var(ps3_private); |
503 | unsigned long x = (pd->bmp.status & pd->bmp.mask); | 554 | u64 x = (pd->bmp.status & pd->bmp.mask); |
504 | unsigned int plug; | 555 | unsigned int plug; |
505 | 556 | ||
506 | /* check for ipi break first to stop this cpu ASAP */ | 557 | /* check for ipi break first to stop this cpu ASAP */ |
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 11d2080607ed..bde71b0572bd 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c | |||
@@ -111,7 +111,7 @@ static void __init ps3_smp_setup_cpu(int cpu) | |||
111 | BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); | 111 | BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); |
112 | 112 | ||
113 | for (i = 0; i < MSG_COUNT; i++) { | 113 | for (i = 0; i < MSG_COUNT; i++) { |
114 | result = ps3_alloc_event_irq(&virqs[i]); | 114 | result = ps3_alloc_event_irq(cpu, &virqs[i]); |
115 | 115 | ||
116 | if (result) | 116 | if (result) |
117 | continue; | 117 | continue; |
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index ed88dc6a7f2f..9f6edc58568d 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -267,20 +267,20 @@ static int __init setup_interrupts(struct spu *spu) | |||
267 | { | 267 | { |
268 | int result; | 268 | int result; |
269 | 269 | ||
270 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, | 270 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
271 | &spu->irqs[0]); | 271 | 0, &spu->irqs[0]); |
272 | 272 | ||
273 | if (result) | 273 | if (result) |
274 | goto fail_alloc_0; | 274 | goto fail_alloc_0; |
275 | 275 | ||
276 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, | 276 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
277 | &spu->irqs[1]); | 277 | 1, &spu->irqs[1]); |
278 | 278 | ||
279 | if (result) | 279 | if (result) |
280 | goto fail_alloc_1; | 280 | goto fail_alloc_1; |
281 | 281 | ||
282 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, | 282 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
283 | &spu->irqs[2]); | 283 | 2, &spu->irqs[2]); |
284 | 284 | ||
285 | if (result) | 285 | if (result) |
286 | goto fail_alloc_2; | 286 | goto fail_alloc_2; |
diff --git a/drivers/ps3/vuart.c b/drivers/ps3/vuart.c index 6974f65bcda5..a72da8f651f8 100644 --- a/drivers/ps3/vuart.c +++ b/drivers/ps3/vuart.c | |||
@@ -783,8 +783,8 @@ static int ps3_vuart_probe(struct device *_dev) | |||
783 | 783 | ||
784 | vuart_private.in_use++; | 784 | vuart_private.in_use++; |
785 | if (vuart_private.in_use == 1) { | 785 | if (vuart_private.in_use == 1) { |
786 | result = ps3_alloc_vuart_irq((void*)&vuart_private.bmp.status, | 786 | result = ps3_alloc_vuart_irq(PS3_BINDING_CPU_ANY, |
787 | &vuart_private.virq); | 787 | (void*)&vuart_private.bmp.status, &vuart_private.virq); |
788 | 788 | ||
789 | if (result) { | 789 | if (result) { |
790 | dev_dbg(&dev->core, | 790 | dev_dbg(&dev->core, |
diff --git a/include/asm-powerpc/ps3.h b/include/asm-powerpc/ps3.h index 8fed3a041dee..021f802161a6 100644 --- a/include/asm-powerpc/ps3.h +++ b/include/asm-powerpc/ps3.h | |||
@@ -140,19 +140,28 @@ unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr); | |||
140 | 140 | ||
141 | /* inrerrupt routines */ | 141 | /* inrerrupt routines */ |
142 | 142 | ||
143 | int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq); | 143 | enum ps3_cpu_binding { |
144 | PS3_BINDING_CPU_ANY = -1, | ||
145 | PS3_BINDING_CPU_0 = 0, | ||
146 | PS3_BINDING_CPU_1 = 1, | ||
147 | }; | ||
148 | |||
149 | int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, | ||
150 | unsigned int *virq); | ||
144 | int ps3_free_io_irq(unsigned int virq); | 151 | int ps3_free_io_irq(unsigned int virq); |
145 | int ps3_alloc_event_irq(unsigned int *virq); | 152 | int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq); |
146 | int ps3_free_event_irq(unsigned int virq); | 153 | int ps3_free_event_irq(unsigned int virq); |
147 | int ps3_send_event_locally(unsigned int virq); | 154 | int ps3_send_event_locally(unsigned int virq); |
148 | int ps3_connect_event_irq(const struct ps3_device_id *did, | 155 | int ps3_connect_event_irq(enum ps3_cpu_binding cpu, |
149 | unsigned int interrupt_id, unsigned int *virq); | 156 | const struct ps3_device_id *did, unsigned int interrupt_id, |
157 | unsigned int *virq); | ||
150 | int ps3_disconnect_event_irq(const struct ps3_device_id *did, | 158 | int ps3_disconnect_event_irq(const struct ps3_device_id *did, |
151 | unsigned int interrupt_id, unsigned int virq); | 159 | unsigned int interrupt_id, unsigned int virq); |
152 | int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq); | 160 | int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, |
153 | int ps3_free_vuart_irq(unsigned int virq); | ||
154 | int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | ||
155 | unsigned int *virq); | 161 | unsigned int *virq); |
162 | int ps3_free_vuart_irq(unsigned int virq); | ||
163 | int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, | ||
164 | unsigned int class, unsigned int *virq); | ||
156 | int ps3_free_spe_irq(unsigned int virq); | 165 | int ps3_free_spe_irq(unsigned int virq); |
157 | 166 | ||
158 | /* lv1 result codes */ | 167 | /* lv1 result codes */ |