aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/ps3
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-08 13:04:20 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-08 13:04:20 -0500
commit21eb4fa1700112d1420d72e1de708af671a251c8 (patch)
tree3afd9f526da50108c27e05ac69826be5e7c2ad6e /arch/powerpc/platforms/ps3
parent0c0e8caf9fd6c9a49fb9fbdba14a8b7b4239adde (diff)
parentd003e7a1a569501cbe9a5ca14748177498c4893a (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc
* master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc: (116 commits) [POWERPC] Add export of vgacon_remap_base [POWERPC] Remove bogus comment about page_is_ram [POWERPC] windfarm: don't die on suspend thread signal [POWERPC] Fix comment in kernel/irq.c [POWERPC] ppc: Fix booke watchdog initialization [POWERPC] PPC: Use ARRAY_SIZE macro when appropriate [POWERPC] Use ARRAY_SIZE macro when appropriate [POWERPC] Fix ppc64's writing to struct file_operations [POWERPC] ppc: use syslog macro for the printk log level [POWERPC] ppc: cs4218_tdm remove extra brace [POWERPC] Add mpc52xx/lite5200 PCI support [POWERPC] Only use H_BULK_REMOVE if the firmware supports it [POWERPC] Fixup error handling when emulating a floating point instruction [POWERPC] Enable interrupts if we are doing fp math emulation [POWERPC] Added kprobes support to ppc32 [POWERPC] Make pSeries use the H_BULK_REMOVE hypervisor call [POWERPC] Clear RI bit in MSR before restoring r13 when returning to userspace [POWERPC] Fix performance monitor exception [POWERPC] Compile fixes for arch/powerpc dcr code [POWERPC] Maple: use mmio nvram ...
Diffstat (limited to 'arch/powerpc/platforms/ps3')
-rw-r--r--arch/powerpc/platforms/ps3/Makefile1
-rw-r--r--arch/powerpc/platforms/ps3/htab.c1
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c442
-rw-r--r--arch/powerpc/platforms/ps3/mm.c1
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c22
-rw-r--r--arch/powerpc/platforms/ps3/platform.h151
-rw-r--r--arch/powerpc/platforms/ps3/repository.c220
-rw-r--r--arch/powerpc/platforms/ps3/setup.c19
-rw-r--r--arch/powerpc/platforms/ps3/smp.c3
-rw-r--r--arch/powerpc/platforms/ps3/spu.c20
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c382
11 files changed, 1022 insertions, 240 deletions
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index 1994904f580..a0048fcf086 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -1,5 +1,6 @@
1obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o 1obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o
2obj-y += interrupt.o exports.o os-area.o 2obj-y += interrupt.o exports.o os-area.o
3obj-y += system-bus.o
3 4
4obj-$(CONFIG_SMP) += smp.o 5obj-$(CONFIG_SMP) += smp.o
5obj-$(CONFIG_SPU_BASE) += spu.o 6obj-$(CONFIG_SPU_BASE) += spu.o
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 8fe1769655a..a4b5a1bc60f 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -23,7 +23,6 @@
23#include <asm/machdep.h> 23#include <asm/machdep.h>
24#include <asm/lmb.h> 24#include <asm/lmb.h>
25#include <asm/udbg.h> 25#include <asm/udbg.h>
26#include <asm/ps3.h>
27#include <asm/lv1call.h> 26#include <asm/lv1call.h>
28 27
29#include "platform.h" 28#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 6f5de438b98..bb17283275a 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:"
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 49c0d010d49..42354de3f55 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -25,7 +25,6 @@
25#include <asm/firmware.h> 25#include <asm/firmware.h>
26#include <asm/lmb.h> 26#include <asm/lmb.h>
27#include <asm/udbg.h> 27#include <asm/udbg.h>
28#include <asm/ps3.h>
29#include <asm/lv1call.h> 28#include <asm/lv1call.h>
30 29
31#include "platform.h" 30#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 58358305dc1..5c3da08bc0c 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -22,7 +22,6 @@
22#include <linux/io.h> 22#include <linux/io.h>
23 23
24#include <asm/lmb.h> 24#include <asm/lmb.h>
25#include <asm/ps3.h>
26 25
27#include "platform.h" 26#include "platform.h"
28 27
@@ -59,7 +58,7 @@ struct os_area_header {
59 u32 ldr_format; 58 u32 ldr_format;
60 u32 ldr_size; 59 u32 ldr_size;
61 u32 _reserved_2[6]; 60 u32 _reserved_2[6];
62} __attribute__ ((packed)); 61};
63 62
64enum { 63enum {
65 PARAM_BOOT_FLAG_GAME_OS = 0, 64 PARAM_BOOT_FLAG_GAME_OS = 0,
@@ -67,13 +66,6 @@ enum {
67}; 66};
68 67
69enum { 68enum {
70 PARAM_AV_MULTI_OUT_NTSC = 0,
71 PARAM_AV_MULTI_OUT_PAL_RGB = 1,
72 PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
73 PARAM_AV_MULTI_OUT_SECAM = 3,
74};
75
76enum {
77 PARAM_CTRL_BUTTON_O_IS_YES = 0, 69 PARAM_CTRL_BUTTON_O_IS_YES = 0,
78 PARAM_CTRL_BUTTON_X_IS_YES = 1, 70 PARAM_CTRL_BUTTON_X_IS_YES = 1,
79}; 71};
@@ -114,7 +106,7 @@ struct os_area_params {
114 u8 dns_primary[4]; 106 u8 dns_primary[4];
115 u8 dns_secondary[4]; 107 u8 dns_secondary[4];
116 u8 _reserved_5[8]; 108 u8 _reserved_5[8];
117} __attribute__ ((packed)); 109};
118 110
119/** 111/**
120 * struct saved_params - Static working copies of data from the 'Other OS' area. 112 * struct saved_params - Static working copies of data from the 'Other OS' area.
@@ -257,3 +249,13 @@ u64 ps3_os_area_rtc_diff(void)
257{ 249{
258 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; 250 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
259} 251}
252
253/**
254 * ps3_os_area_get_av_multi_out - Returns the default video mode.
255 */
256
257enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void)
258{
259 return saved_params.av_multi_out;
260}
261EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out);
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 23b111bea9d..ca04f03305c 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -22,6 +22,9 @@
22#define _PS3_PLATFORM_H 22#define _PS3_PLATFORM_H
23 23
24#include <linux/rtc.h> 24#include <linux/rtc.h>
25#include <scsi/scsi.h>
26
27#include <asm/ps3.h>
25 28
26/* htab */ 29/* htab */
27 30
@@ -65,4 +68,152 @@ void ps3_spu_set_platform (void);
65static inline void ps3_spu_set_platform (void) {} 68static inline void ps3_spu_set_platform (void) {}
66#endif 69#endif
67 70
71/* repository bus info */
72
73enum ps3_bus_type {
74 PS3_BUS_TYPE_SB = 4,
75 PS3_BUS_TYPE_STORAGE = 5,
76};
77
78enum ps3_dev_type {
79 PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */
80 PS3_DEV_TYPE_SB_GELIC = 3,
81 PS3_DEV_TYPE_SB_USB = 4,
82 PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */
83 PS3_DEV_TYPE_SB_GPIO = 6,
84 PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
85};
86
87int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
88 u64 *value);
89int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
90int ps3_repository_read_bus_type(unsigned int bus_index,
91 enum ps3_bus_type *bus_type);
92int ps3_repository_read_bus_num_dev(unsigned int bus_index,
93 unsigned int *num_dev);
94
95/* repository bus device info */
96
97enum ps3_interrupt_type {
98 PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
99 PS3_INTERRUPT_TYPE_SB_OHCI = 3,
100 PS3_INTERRUPT_TYPE_SB_EHCI = 4,
101 PS3_INTERRUPT_TYPE_OTHER = 5,
102};
103
104enum ps3_reg_type {
105 PS3_REG_TYPE_SB_OHCI = 3,
106 PS3_REG_TYPE_SB_EHCI = 4,
107 PS3_REG_TYPE_SB_GPIO = 5,
108};
109
110int ps3_repository_read_dev_str(unsigned int bus_index,
111 unsigned int dev_index, const char *dev_str, u64 *value);
112int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
113 unsigned int *dev_id);
114int ps3_repository_read_dev_type(unsigned int bus_index,
115 unsigned int dev_index, enum ps3_dev_type *dev_type);
116int ps3_repository_read_dev_intr(unsigned int bus_index,
117 unsigned int dev_index, unsigned int intr_index,
118 enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
119int ps3_repository_read_dev_reg_type(unsigned int bus_index,
120 unsigned int dev_index, unsigned int reg_index,
121 enum ps3_reg_type *reg_type);
122int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
123 unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
124 u64 *len);
125int ps3_repository_read_dev_reg(unsigned int bus_index,
126 unsigned int dev_index, unsigned int reg_index,
127 enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len);
128
129/* repository bus enumerators */
130
131struct ps3_repository_device {
132 unsigned int bus_index;
133 unsigned int dev_index;
134 struct ps3_device_id did;
135};
136
137int ps3_repository_find_device(enum ps3_bus_type bus_type,
138 enum ps3_dev_type dev_type,
139 const struct ps3_repository_device *start_dev,
140 struct ps3_repository_device *dev);
141static inline int ps3_repository_find_first_device(
142 enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
143 struct ps3_repository_device *dev)
144{
145 return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
146}
147int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
148 enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
149int ps3_repository_find_reg(const struct ps3_repository_device *dev,
150 enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len);
151
152/* repository block device info */
153
154int ps3_repository_read_stor_dev_port(unsigned int bus_index,
155 unsigned int dev_index, u64 *port);
156int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
157 unsigned int dev_index, u64 *blk_size);
158int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
159 unsigned int dev_index, u64 *num_blocks);
160int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
161 unsigned int dev_index, unsigned int *num_regions);
162int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
163 unsigned int dev_index, unsigned int region_index,
164 unsigned int *region_id);
165int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
166 unsigned int dev_index, unsigned int region_index, u64 *region_size);
167int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
168 unsigned int dev_index, unsigned int region_index, u64 *region_start);
169int ps3_repository_read_stor_dev_info(unsigned int bus_index,
170 unsigned int dev_index, u64 *port, u64 *blk_size,
171 u64 *num_blocks, unsigned int *num_regions);
172int ps3_repository_read_stor_dev_region(unsigned int bus_index,
173 unsigned int dev_index, unsigned int region_index,
174 unsigned int *region_id, u64 *region_start, u64 *region_size);
175
176/* repository pu and memory info */
177
178int ps3_repository_read_num_pu(unsigned int *num_pu);
179int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
180int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
181int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
182int ps3_repository_read_region_total(u64 *region_total);
183int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
184 u64 *region_total);
185
186/* repository pme info */
187
188int ps3_repository_read_num_be(unsigned int *num_be);
189int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
190int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
191int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
192
193/* repository 'Other OS' area */
194
195int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
196int ps3_repository_read_boot_dat_size(unsigned int *size);
197int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
198
199/* repository spu info */
200
201/**
202 * enum spu_resource_type - Type of spu resource.
203 * @spu_resource_type_shared: Logical spu is shared with other partions.
204 * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
205 *
206 * Returned by ps3_repository_read_spu_resource_id().
207 */
208
209enum ps3_spu_resource_type {
210 PS3_SPU_RESOURCE_TYPE_SHARED = 0,
211 PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
212};
213
214int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
215int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
216int ps3_repository_read_spu_resource_id(unsigned int res_index,
217 enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
218
68#endif 219#endif
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 273a0d621bd..ae586a0e5d3 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -18,9 +18,10 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21#include <asm/ps3.h>
22#include <asm/lv1call.h> 21#include <asm/lv1call.h>
23 22
23#include "platform.h"
24
24enum ps3_vendor_id { 25enum ps3_vendor_id {
25 PS3_VENDOR_ID_NONE = 0, 26 PS3_VENDOR_ID_NONE = 0,
26 PS3_VENDOR_ID_SONY = 0x8000000000000000UL, 27 PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
@@ -257,7 +258,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index,
257 258
258int ps3_repository_read_dev_intr(unsigned int bus_index, 259int ps3_repository_read_dev_intr(unsigned int bus_index,
259 unsigned int dev_index, unsigned int intr_index, 260 unsigned int dev_index, unsigned int intr_index,
260 unsigned int *intr_type, unsigned int* interrupt_id) 261 enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id)
261{ 262{
262 int result; 263 int result;
263 u64 v1; 264 u64 v1;
@@ -275,7 +276,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index,
275} 276}
276 277
277int ps3_repository_read_dev_reg_type(unsigned int bus_index, 278int ps3_repository_read_dev_reg_type(unsigned int bus_index,
278 unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type) 279 unsigned int dev_index, unsigned int reg_index,
280 enum ps3_reg_type *reg_type)
279{ 281{
280 int result; 282 int result;
281 u64 v1; 283 u64 v1;
@@ -302,8 +304,8 @@ int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
302} 304}
303 305
304int ps3_repository_read_dev_reg(unsigned int bus_index, 306int ps3_repository_read_dev_reg(unsigned int bus_index,
305 unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type, 307 unsigned int dev_index, unsigned int reg_index,
306 u64 *bus_addr, u64 *len) 308 enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
307{ 309{
308 int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, 310 int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
309 reg_index, reg_type); 311 reg_index, reg_type);
@@ -343,7 +345,7 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
343 } 345 }
344 346
345 for (res_index = 0; res_index < 10; res_index++) { 347 for (res_index = 0; res_index < 10; res_index++) {
346 enum ps3_region_type reg_type; 348 enum ps3_reg_type reg_type;
347 u64 bus_addr; 349 u64 bus_addr;
348 u64 len; 350 u64 len;
349 351
@@ -367,7 +369,55 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
367 return result; 369 return result;
368} 370}
369 371
370static int dump_device_info(unsigned int bus_index, unsigned int num_dev) 372static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index)
373{
374 int result = 0;
375 unsigned int num_regions, region_index;
376 u64 port, blk_size, num_blocks;
377
378 pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
379 bus_index, dev_index);
380
381 result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port,
382 &blk_size, &num_blocks, &num_regions);
383 if (result) {
384 pr_debug("%s:%d ps3_repository_read_stor_dev_info"
385 " (%u:%u) failed\n", __func__, __LINE__,
386 bus_index, dev_index);
387 goto out;
388 }
389
390 pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
391 "%lu, num_regions %u\n",
392 __func__, __LINE__, bus_index, dev_index, port,
393 blk_size, num_blocks, num_regions);
394
395 for (region_index = 0; region_index < num_regions; region_index++) {
396 unsigned int region_id;
397 u64 region_start, region_size;
398
399 result = ps3_repository_read_stor_dev_region(bus_index,
400 dev_index, region_index, &region_id, &region_start,
401 &region_size);
402 if (result) {
403 pr_debug("%s:%d ps3_repository_read_stor_dev_region"
404 " (%u:%u) failed\n", __func__, __LINE__,
405 bus_index, dev_index);
406 break;
407 }
408
409 pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
410 __func__, __LINE__, bus_index, dev_index, region_id,
411 region_start, region_size);
412 }
413
414out:
415 pr_debug(" <- %s:%d\n", __func__, __LINE__);
416 return result;
417}
418
419static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type,
420 unsigned int num_dev)
371{ 421{
372 int result = 0; 422 int result = 0;
373 unsigned int dev_index; 423 unsigned int dev_index;
@@ -402,6 +452,9 @@ static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
402 __LINE__, bus_index, dev_index, dev_type, dev_id); 452 __LINE__, bus_index, dev_index, dev_type, dev_id);
403 453
404 ps3_repository_dump_resource_info(bus_index, dev_index); 454 ps3_repository_dump_resource_info(bus_index, dev_index);
455
456 if (bus_type == PS3_BUS_TYPE_STORAGE)
457 dump_stor_dev_info(bus_index, dev_index);
405 } 458 }
406 459
407 pr_debug(" <- %s:%d\n", __func__, __LINE__); 460 pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -452,7 +505,7 @@ int ps3_repository_dump_bus_info(void)
452 __func__, __LINE__, bus_index, bus_type, bus_id, 505 __func__, __LINE__, bus_index, bus_type, bus_id,
453 num_dev); 506 num_dev);
454 507
455 dump_device_info(bus_index, num_dev); 508 dump_device_info(bus_index, bus_type, num_dev);
456 } 509 }
457 510
458 pr_debug(" <- %s:%d\n", __func__, __LINE__); 511 pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -487,7 +540,8 @@ static int find_device(unsigned int bus_index, unsigned int num_dev,
487 break; 540 break;
488 } 541 }
489 542
490 BUG_ON(dev_index == num_dev); 543 if (dev_index == num_dev)
544 return -1;
491 545
492 pr_debug("%s:%d: found dev_type %u at dev_index %u\n", 546 pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
493 __func__, __LINE__, dev_type, dev_index); 547 __func__, __LINE__, dev_type, dev_index);
@@ -521,7 +575,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
521 pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, 575 pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
522 bus_type, dev_type); 576 bus_type, dev_type);
523 577
524 dev->bus_index = UINT_MAX; 578 BUG_ON(start_dev && start_dev->bus_index > 10);
525 579
526 for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; 580 for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
527 bus_index++) { 581 bus_index++) {
@@ -532,13 +586,15 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
532 if (result) { 586 if (result) {
533 pr_debug("%s:%d read_bus_type failed\n", 587 pr_debug("%s:%d read_bus_type failed\n",
534 __func__, __LINE__); 588 __func__, __LINE__);
589 dev->bus_index = UINT_MAX;
535 return result; 590 return result;
536 } 591 }
537 if (x == bus_type) 592 if (x == bus_type)
538 break; 593 break;
539 } 594 }
540 595
541 BUG_ON(bus_index == 10); 596 if (bus_index >= 10)
597 return -ENODEV;
542 598
543 pr_debug("%s:%d: found bus_type %u at bus_index %u\n", 599 pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
544 __func__, __LINE__, bus_type, bus_index); 600 __func__, __LINE__, bus_type, bus_index);
@@ -604,7 +660,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
604 } 660 }
605 } 661 }
606 662
607 BUG_ON(res_index == 10); 663 if (res_index == 10)
664 return -ENODEV;
608 665
609 pr_debug("%s:%d: found intr_type %u at res_index %u\n", 666 pr_debug("%s:%d: found intr_type %u at res_index %u\n",
610 __func__, __LINE__, intr_type, res_index); 667 __func__, __LINE__, intr_type, res_index);
@@ -612,8 +669,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
612 return result; 669 return result;
613} 670}
614 671
615int ps3_repository_find_region(const struct ps3_repository_device *dev, 672int ps3_repository_find_reg(const struct ps3_repository_device *dev,
616 enum ps3_region_type reg_type, u64 *bus_addr, u64 *len) 673 enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
617{ 674{
618 int result = 0; 675 int result = 0;
619 unsigned int res_index; 676 unsigned int res_index;
@@ -623,7 +680,7 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
623 *bus_addr = *len = 0; 680 *bus_addr = *len = 0;
624 681
625 for (res_index = 0; res_index < 10; res_index++) { 682 for (res_index = 0; res_index < 10; res_index++) {
626 enum ps3_region_type t; 683 enum ps3_reg_type t;
627 u64 a; 684 u64 a;
628 u64 l; 685 u64 l;
629 686
@@ -643,7 +700,8 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
643 } 700 }
644 } 701 }
645 702
646 BUG_ON(res_index == 10); 703 if (res_index == 10)
704 return -ENODEV;
647 705
648 pr_debug("%s:%d: found reg_type %u at res_index %u\n", 706 pr_debug("%s:%d: found reg_type %u at res_index %u\n",
649 __func__, __LINE__, reg_type, res_index); 707 __func__, __LINE__, reg_type, res_index);
@@ -651,6 +709,136 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
651 return result; 709 return result;
652} 710}
653 711
712int ps3_repository_read_stor_dev_port(unsigned int bus_index,
713 unsigned int dev_index, u64 *port)
714{
715 return read_node(PS3_LPAR_ID_PME,
716 make_first_field("bus", bus_index),
717 make_field("dev", dev_index),
718 make_field("port", 0),
719 0, port, 0);
720}
721
722int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
723 unsigned int dev_index, u64 *blk_size)
724{
725 return read_node(PS3_LPAR_ID_PME,
726 make_first_field("bus", bus_index),
727 make_field("dev", dev_index),
728 make_field("blk_size", 0),
729 0, blk_size, 0);
730}
731
732int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
733 unsigned int dev_index, u64 *num_blocks)
734{
735 return read_node(PS3_LPAR_ID_PME,
736 make_first_field("bus", bus_index),
737 make_field("dev", dev_index),
738 make_field("n_blocks", 0),
739 0, num_blocks, 0);
740}
741
742int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
743 unsigned int dev_index, unsigned int *num_regions)
744{
745 int result;
746 u64 v1;
747
748 result = read_node(PS3_LPAR_ID_PME,
749 make_first_field("bus", bus_index),
750 make_field("dev", dev_index),
751 make_field("n_regs", 0),
752 0, &v1, 0);
753 *num_regions = v1;
754 return result;
755}
756
757int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
758 unsigned int dev_index, unsigned int region_index,
759 unsigned int *region_id)
760{
761 int result;
762 u64 v1;
763
764 result = read_node(PS3_LPAR_ID_PME,
765 make_first_field("bus", bus_index),
766 make_field("dev", dev_index),
767 make_field("region", region_index),
768 make_field("id", 0),
769 &v1, 0);
770 *region_id = v1;
771 return result;
772}
773
774int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
775 unsigned int dev_index, unsigned int region_index, u64 *region_size)
776{
777 return read_node(PS3_LPAR_ID_PME,
778 make_first_field("bus", bus_index),
779 make_field("dev", dev_index),
780 make_field("region", region_index),
781 make_field("size", 0),
782 region_size, 0);
783}
784
785int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
786 unsigned int dev_index, unsigned int region_index, u64 *region_start)
787{
788 return read_node(PS3_LPAR_ID_PME,
789 make_first_field("bus", bus_index),
790 make_field("dev", dev_index),
791 make_field("region", region_index),
792 make_field("start", 0),
793 region_start, 0);
794}
795
796int ps3_repository_read_stor_dev_info(unsigned int bus_index,
797 unsigned int dev_index, u64 *port, u64 *blk_size,
798 u64 *num_blocks, unsigned int *num_regions)
799{
800 int result;
801
802 result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
803 if (result)
804 return result;
805
806 result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
807 blk_size);
808 if (result)
809 return result;
810
811 result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
812 num_blocks);
813 if (result)
814 return result;
815
816 result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
817 num_regions);
818 return result;
819}
820
821int ps3_repository_read_stor_dev_region(unsigned int bus_index,
822 unsigned int dev_index, unsigned int region_index,
823 unsigned int *region_id, u64 *region_start, u64 *region_size)
824{
825 int result;
826
827 result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
828 region_index, region_id);
829 if (result)
830 return result;
831
832 result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
833 region_index, region_start);
834 if (result)
835 return result;
836
837 result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
838 region_index, region_size);
839 return result;
840}
841
654int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) 842int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
655{ 843{
656 return read_node(PS3_LPAR_ID_CURRENT, 844 return read_node(PS3_LPAR_ID_CURRENT,
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index d8b5cadbe80..e62505e1881 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -41,10 +41,18 @@
41#define DBG(fmt...) do{if(0)printk(fmt);}while(0) 41#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
42#endif 42#endif
43 43
44static void ps3_show_cpuinfo(struct seq_file *m) 44int ps3_get_firmware_version(union ps3_firmware_version *v)
45{ 45{
46 seq_printf(m, "machine\t\t: %s\n", ppc_md.name); 46 int result = lv1_get_version_info(&v->raw);
47
48 if (result) {
49 v->raw = 0;
50 return -1;
51 }
52
53 return result;
47} 54}
55EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
48 56
49static void ps3_power_save(void) 57static void ps3_power_save(void)
50{ 58{
@@ -74,8 +82,14 @@ static void ps3_panic(char *str)
74 82
75static void __init ps3_setup_arch(void) 83static void __init ps3_setup_arch(void)
76{ 84{
85 union ps3_firmware_version v;
86
77 DBG(" -> %s:%d\n", __func__, __LINE__); 87 DBG(" -> %s:%d\n", __func__, __LINE__);
78 88
89 ps3_get_firmware_version(&v);
90 printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor,
91 v.rev);
92
79 ps3_spu_set_platform(); 93 ps3_spu_set_platform();
80 ps3_map_htab(); 94 ps3_map_htab();
81 95
@@ -156,7 +170,6 @@ define_machine(ps3) {
156 .name = "PS3", 170 .name = "PS3",
157 .probe = ps3_probe, 171 .probe = ps3_probe,
158 .setup_arch = ps3_setup_arch, 172 .setup_arch = ps3_setup_arch,
159 .show_cpuinfo = ps3_show_cpuinfo,
160 .init_IRQ = ps3_init_IRQ, 173 .init_IRQ = ps3_init_IRQ,
161 .panic = ps3_panic, 174 .panic = ps3_panic,
162 .get_boot_time = ps3_get_boot_time, 175 .get_boot_time = ps3_get_boot_time,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 11d2080607e..6fb887961a6 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -23,7 +23,6 @@
23 23
24#include <asm/machdep.h> 24#include <asm/machdep.h>
25#include <asm/udbg.h> 25#include <asm/udbg.h>
26#include <asm/ps3.h>
27 26
28#include "platform.h" 27#include "platform.h"
29 28
@@ -111,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu)
111 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); 110 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
112 111
113 for (i = 0; i < MSG_COUNT; i++) { 112 for (i = 0; i < MSG_COUNT; i++) {
114 result = ps3_alloc_event_irq(&virqs[i]); 113 result = ps3_alloc_event_irq(cpu, &virqs[i]);
115 114
116 if (result) 115 if (result)
117 continue; 116 continue;
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 644532c3b7c..d1929721b0e 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -26,9 +26,10 @@
26 26
27#include <asm/spu.h> 27#include <asm/spu.h>
28#include <asm/spu_priv1.h> 28#include <asm/spu_priv1.h>
29#include <asm/ps3.h>
30#include <asm/lv1call.h> 29#include <asm/lv1call.h>
31 30
31#include "platform.h"
32
32/* spu_management_ops */ 33/* spu_management_ops */
33 34
34/** 35/**
@@ -50,7 +51,7 @@ enum spe_type {
50 */ 51 */
51 52
52struct spe_shadow { 53struct spe_shadow {
53 u8 padding_0000[0x0140]; 54 u8 padding_0140[0x0140];
54 u64 int_status_class0_RW; /* 0x0140 */ 55 u64 int_status_class0_RW; /* 0x0140 */
55 u64 int_status_class1_RW; /* 0x0148 */ 56 u64 int_status_class1_RW; /* 0x0148 */
56 u64 int_status_class2_RW; /* 0x0150 */ 57 u64 int_status_class2_RW; /* 0x0150 */
@@ -67,8 +68,7 @@ struct spe_shadow {
67 u8 padding_0c08[0x0f00-0x0c08]; 68 u8 padding_0c08[0x0f00-0x0c08];
68 u64 spe_execution_status; /* 0x0f00 */ 69 u64 spe_execution_status; /* 0x0f00 */
69 u8 padding_0f08[0x1000-0x0f08]; 70 u8 padding_0f08[0x1000-0x0f08];
70} __attribute__ ((packed)); 71};
71
72 72
73/** 73/**
74 * enum spe_ex_state - Logical spe execution state. 74 * enum spe_ex_state - Logical spe execution state.
@@ -268,20 +268,20 @@ static int __init setup_interrupts(struct spu *spu)
268{ 268{
269 int result; 269 int result;
270 270
271 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, 271 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
272 &spu->irqs[0]); 272 0, &spu->irqs[0]);
273 273
274 if (result) 274 if (result)
275 goto fail_alloc_0; 275 goto fail_alloc_0;
276 276
277 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, 277 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
278 &spu->irqs[1]); 278 1, &spu->irqs[1]);
279 279
280 if (result) 280 if (result)
281 goto fail_alloc_1; 281 goto fail_alloc_1;
282 282
283 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, 283 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
284 &spu->irqs[2]); 284 2, &spu->irqs[2]);
285 285
286 if (result) 286 if (result)
287 goto fail_alloc_2; 287 goto fail_alloc_2;
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
new file mode 100644
index 00000000000..bce6136cbce
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -0,0 +1,382 @@
1/*
2 * PS3 system bus driver.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/dma-mapping.h>
25#include <linux/err.h>
26
27#include <asm/udbg.h>
28#include <asm/lv1call.h>
29#include <asm/firmware.h>
30
31#include "platform.h"
32
33#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
34static void _dump_mmio_region(const struct ps3_mmio_region* r,
35 const char* func, int line)
36{
37 pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
38 r->did.dev_id);
39 pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
40 pr_debug("%s:%d: len %lxh\n", func, line, r->len);
41 pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
42}
43
44int ps3_mmio_region_create(struct ps3_mmio_region *r)
45{
46 int result;
47
48 result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
49 r->bus_addr, r->len, r->page_size, &r->lpar_addr);
50
51 if (result) {
52 pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
53 __func__, __LINE__, ps3_result(result));
54 r->lpar_addr = 0;
55 }
56
57 dump_mmio_region(r);
58 return result;
59}
60
61int ps3_free_mmio_region(struct ps3_mmio_region *r)
62{
63 int result;
64
65 result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
66 r->lpar_addr);
67
68 if (result)
69 pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
70 __func__, __LINE__, ps3_result(result));
71
72 r->lpar_addr = 0;
73 return result;
74}
75
76static int ps3_system_bus_match(struct device *_dev,
77 struct device_driver *_drv)
78{
79 int result;
80 struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
81 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
82
83 result = dev->match_id == drv->match_id;
84
85 pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
86 dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
87 (result ? "match" : "miss"));
88 return result;
89}
90
91static int ps3_system_bus_probe(struct device *_dev)
92{
93 int result;
94 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
95 struct ps3_system_bus_driver *drv =
96 to_ps3_system_bus_driver(_dev->driver);
97
98 result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
99
100 if (result) {
101 pr_debug("%s:%d: lv1_open_device failed (%d)\n",
102 __func__, __LINE__, result);
103 result = -EACCES;
104 goto clean_none;
105 }
106
107 if (dev->d_region->did.bus_id) {
108 result = ps3_dma_region_create(dev->d_region);
109
110 if (result) {
111 pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
112 __func__, __LINE__, result);
113 BUG_ON("check region type");
114 result = -EINVAL;
115 goto clean_device;
116 }
117 }
118
119 BUG_ON(!drv);
120
121 if (drv->probe)
122 result = drv->probe(dev);
123 else
124 pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
125 dev->core.bus_id);
126
127 if (result) {
128 pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
129 goto clean_dma;
130 }
131
132 return result;
133
134clean_dma:
135 ps3_dma_region_free(dev->d_region);
136clean_device:
137 lv1_close_device(dev->did.bus_id, dev->did.dev_id);
138clean_none:
139 return result;
140}
141
142static int ps3_system_bus_remove(struct device *_dev)
143{
144 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
145 struct ps3_system_bus_driver *drv =
146 to_ps3_system_bus_driver(_dev->driver);
147
148 if (drv->remove)
149 drv->remove(dev);
150 else
151 pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
152 dev->core.bus_id);
153
154 ps3_dma_region_free(dev->d_region);
155 ps3_free_mmio_region(dev->m_region);
156 lv1_close_device(dev->did.bus_id, dev->did.dev_id);
157
158 return 0;
159}
160
161struct bus_type ps3_system_bus_type = {
162 .name = "ps3_system_bus",
163 .match = ps3_system_bus_match,
164 .probe = ps3_system_bus_probe,
165 .remove = ps3_system_bus_remove,
166};
167
168int __init ps3_system_bus_init(void)
169{
170 int result;
171
172 if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
173 return 0;
174
175 result = bus_register(&ps3_system_bus_type);
176 BUG_ON(result);
177 return result;
178}
179
180core_initcall(ps3_system_bus_init);
181
182/* Allocates a contiguous real buffer and creates mappings over it.
183 * Returns the virtual address of the buffer and sets dma_handle
184 * to the dma address (mapping) of the first page.
185 */
186
187static void * ps3_alloc_coherent(struct device *_dev, size_t size,
188 dma_addr_t *dma_handle, gfp_t flag)
189{
190 int result;
191 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
192 unsigned long virt_addr;
193
194 BUG_ON(!dev->d_region->bus_addr);
195
196 flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
197 flag |= __GFP_ZERO;
198
199 virt_addr = __get_free_pages(flag, get_order(size));
200
201 if (!virt_addr) {
202 pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
203 goto clean_none;
204 }
205
206 result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
207
208 if (result) {
209 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
210 __func__, __LINE__, result);
211 BUG_ON("check region type");
212 goto clean_alloc;
213 }
214
215 return (void*)virt_addr;
216
217clean_alloc:
218 free_pages(virt_addr, get_order(size));
219clean_none:
220 dma_handle = NULL;
221 return NULL;
222}
223
224static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
225 dma_addr_t dma_handle)
226{
227 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
228
229 ps3_dma_unmap(dev->d_region, dma_handle, size);
230 free_pages((unsigned long)vaddr, get_order(size));
231}
232
233/* Creates TCEs for a user provided buffer. The user buffer must be
234 * contiguous real kernel storage (not vmalloc). The address of the buffer
235 * passed here is the kernel (virtual) address of the buffer. The buffer
236 * need not be page aligned, the dma_addr_t returned will point to the same
237 * byte within the page as vaddr.
238 */
239
240static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
241 enum dma_data_direction direction)
242{
243 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
244 int result;
245 unsigned long bus_addr;
246
247 result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
248 &bus_addr);
249
250 if (result) {
251 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
252 __func__, __LINE__, result);
253 }
254
255 return bus_addr;
256}
257
258static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
259 size_t size, enum dma_data_direction direction)
260{
261 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
262 int result;
263
264 result = ps3_dma_unmap(dev->d_region, dma_addr, size);
265
266 if (result) {
267 pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
268 __func__, __LINE__, result);
269 }
270}
271
272static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
273 enum dma_data_direction direction)
274{
275 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
276 int i;
277
278#if defined(CONFIG_PS3_DYNAMIC_DMA)
279 BUG_ON("do");
280 return -EPERM;
281#else
282 for (i = 0; i < nents; i++, sg++) {
283 int result = ps3_dma_map(dev->d_region,
284 page_to_phys(sg->page) + sg->offset, sg->length,
285 &sg->dma_address);
286
287 if (result) {
288 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
289 __func__, __LINE__, result);
290 return -EINVAL;
291 }
292
293 sg->dma_length = sg->length;
294 }
295
296 return nents;
297#endif
298}
299
300static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
301 int nents, enum dma_data_direction direction)
302{
303#if defined(CONFIG_PS3_DYNAMIC_DMA)
304 BUG_ON("do");
305#endif
306}
307
308static int ps3_dma_supported(struct device *_dev, u64 mask)
309{
310 return mask >= DMA_32BIT_MASK;
311}
312
313static struct dma_mapping_ops ps3_dma_ops = {
314 .alloc_coherent = ps3_alloc_coherent,
315 .free_coherent = ps3_free_coherent,
316 .map_single = ps3_map_single,
317 .unmap_single = ps3_unmap_single,
318 .map_sg = ps3_map_sg,
319 .unmap_sg = ps3_unmap_sg,
320 .dma_supported = ps3_dma_supported
321};
322
323/**
324 * ps3_system_bus_release_device - remove a device from the system bus
325 */
326
327static void ps3_system_bus_release_device(struct device *_dev)
328{
329 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
330 kfree(dev);
331}
332
333/**
334 * ps3_system_bus_device_register - add a device to the system bus
335 *
336 * ps3_system_bus_device_register() expects the dev object to be allocated
337 * dynamically by the caller. The system bus takes ownership of the dev
338 * object and frees the object in ps3_system_bus_release_device().
339 */
340
341int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
342{
343 int result;
344 static unsigned int dev_count = 1;
345
346 dev->core.parent = NULL;
347 dev->core.bus = &ps3_system_bus_type;
348 dev->core.release = ps3_system_bus_release_device;
349
350 dev->core.archdata.of_node = NULL;
351 dev->core.archdata.dma_ops = &ps3_dma_ops;
352 dev->core.archdata.numa_node = 0;
353
354 snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
355 dev_count++);
356
357 pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
358
359 result = device_register(&dev->core);
360 return result;
361}
362
363EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
364
365int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
366{
367 int result;
368
369 drv->core.bus = &ps3_system_bus_type;
370
371 result = driver_register(&drv->core);
372 return result;
373}
374
375EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
376
377void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
378{
379 driver_unregister(&drv->core);
380}
381
382EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);