diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-08 13:04:20 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-08 13:04:20 -0500 |
commit | 21eb4fa1700112d1420d72e1de708af671a251c8 (patch) | |
tree | 3afd9f526da50108c27e05ac69826be5e7c2ad6e /arch/powerpc/platforms/ps3 | |
parent | 0c0e8caf9fd6c9a49fb9fbdba14a8b7b4239adde (diff) | |
parent | d003e7a1a569501cbe9a5ca14748177498c4893a (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/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/htab.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 442 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/mm.c | 1 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/os-area.c | 22 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 151 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/repository.c | 220 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/setup.c | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/smp.c | 3 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 20 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 382 |
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 @@ | |||
1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o | 1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o |
2 | obj-y += interrupt.o exports.o os-area.o | 2 | obj-y += interrupt.o exports.o os-area.o |
3 | obj-y += system-bus.o | ||
3 | 4 | ||
4 | obj-$(CONFIG_SMP) += smp.o | 5 | obj-$(CONFIG_SMP) += smp.o |
5 | obj-$(CONFIG_SPU_BASE) += spu.o | 6 | obj-$(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 | |||
66 | struct 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 | |||
84 | struct ps3_private { | ||
85 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); | ||
86 | u64 node; | ||
87 | unsigned int cpu; | ||
88 | }; | ||
89 | |||
90 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | ||
91 | |||
92 | int 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 | |||
138 | fail_set: | ||
139 | lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); | ||
140 | fail_connect: | ||
141 | irq_dispose_mapping(*virq); | ||
142 | fail_create: | ||
143 | return result; | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(ps3_alloc_irq); | ||
146 | |||
147 | int 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 | } | ||
165 | EXPORT_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 | ||
47 | int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) | 178 | int 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 | ||
68 | int ps3_free_io_irq(unsigned int virq) | 198 | int 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 | ||
92 | int ps3_alloc_event_irq(unsigned int *virq) | 224 | int 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 | ||
114 | int ps3_free_event_irq(unsigned int virq) | 244 | int 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 | ||
147 | int ps3_connect_event_irq(const struct ps3_device_id *did, | 279 | int 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 | ||
206 | int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) | 341 | int 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 | ||
232 | int ps3_free_vuart_irq(unsigned int virq) | 366 | int 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 | ||
257 | int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | 393 | int 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 | ||
281 | int ps3_free_spe_irq(unsigned int virq) | 415 | int 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 | |||
314 | struct 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 | |||
332 | struct private { | ||
333 | unsigned long node; | ||
334 | unsigned int cpu; | ||
335 | struct bmp bmp; | ||
336 | }; | ||
337 | |||
338 | #if defined(DEBUG) | 425 | #if defined(DEBUG) |
339 | static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, | 426 | static 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 | ||
348 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, | 435 | static 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__) |
356 | static void _dump_bmp(struct private* pd, const char* func, int line) | 443 | static 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__) |
367 | static void __attribute__ ((unused)) _dump_mask(struct private* pd, | 454 | static 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 |
377 | static void dump_bmp(struct private* pd) {}; | 464 | static void dump_bmp(struct ps3_private* pd) {}; |
378 | #endif /* defined(DEBUG) */ | 465 | #endif /* defined(DEBUG) */ |
379 | 466 | ||
380 | static void chip_mask(unsigned int virq) | 467 | static 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 | ||
397 | static void chip_unmask(unsigned int virq) | 491 | static 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 | ||
414 | static void chip_eoi(unsigned int virq) | 515 | static 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 | ||
419 | static struct irq_chip irq_chip = { | 521 | static 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 | ||
426 | static void host_unmap(struct irq_host *h, unsigned int virq) | 528 | static 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 | ||
438 | static DEFINE_PER_CPU(struct private, private); | 533 | static int ps3_host_map(struct irq_host *h, unsigned int virq, |
439 | |||
440 | static 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 | ||
472 | static struct irq_host_ops host_ops = { | 544 | static 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 | ||
477 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | 549 | void __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 | ||
487 | static int bmp_get_and_clear_status_bit(struct bmp *m) | 559 | unsigned 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 | |||
518 | unsigned 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) | |||
544 | void __init ps3_init_IRQ(void) | 591 | void __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 | ||
64 | enum { | 63 | enum { |
65 | PARAM_BOOT_FLAG_GAME_OS = 0, | 64 | PARAM_BOOT_FLAG_GAME_OS = 0, |
@@ -67,13 +66,6 @@ enum { | |||
67 | }; | 66 | }; |
68 | 67 | ||
69 | enum { | 68 | enum { |
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 | |||
76 | enum { | ||
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 | |||
257 | enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void) | ||
258 | { | ||
259 | return saved_params.av_multi_out; | ||
260 | } | ||
261 | EXPORT_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); | |||
65 | static inline void ps3_spu_set_platform (void) {} | 68 | static inline void ps3_spu_set_platform (void) {} |
66 | #endif | 69 | #endif |
67 | 70 | ||
71 | /* repository bus info */ | ||
72 | |||
73 | enum ps3_bus_type { | ||
74 | PS3_BUS_TYPE_SB = 4, | ||
75 | PS3_BUS_TYPE_STORAGE = 5, | ||
76 | }; | ||
77 | |||
78 | enum 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 | |||
87 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | ||
88 | u64 *value); | ||
89 | int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); | ||
90 | int ps3_repository_read_bus_type(unsigned int bus_index, | ||
91 | enum ps3_bus_type *bus_type); | ||
92 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, | ||
93 | unsigned int *num_dev); | ||
94 | |||
95 | /* repository bus device info */ | ||
96 | |||
97 | enum 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 | |||
104 | enum 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 | |||
110 | int ps3_repository_read_dev_str(unsigned int bus_index, | ||
111 | unsigned int dev_index, const char *dev_str, u64 *value); | ||
112 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | ||
113 | unsigned int *dev_id); | ||
114 | int ps3_repository_read_dev_type(unsigned int bus_index, | ||
115 | unsigned int dev_index, enum ps3_dev_type *dev_type); | ||
116 | int 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); | ||
119 | int 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); | ||
122 | int 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); | ||
125 | int 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 | |||
131 | struct ps3_repository_device { | ||
132 | unsigned int bus_index; | ||
133 | unsigned int dev_index; | ||
134 | struct ps3_device_id did; | ||
135 | }; | ||
136 | |||
137 | int 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); | ||
141 | static 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 | } | ||
147 | int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | ||
148 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); | ||
149 | int 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 | |||
154 | int ps3_repository_read_stor_dev_port(unsigned int bus_index, | ||
155 | unsigned int dev_index, u64 *port); | ||
156 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | ||
157 | unsigned int dev_index, u64 *blk_size); | ||
158 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | ||
159 | unsigned int dev_index, u64 *num_blocks); | ||
160 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | ||
161 | unsigned int dev_index, unsigned int *num_regions); | ||
162 | int 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); | ||
165 | int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | ||
166 | unsigned int dev_index, unsigned int region_index, u64 *region_size); | ||
167 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | ||
168 | unsigned int dev_index, unsigned int region_index, u64 *region_start); | ||
169 | int 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); | ||
172 | int 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 | |||
178 | int ps3_repository_read_num_pu(unsigned int *num_pu); | ||
179 | int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); | ||
180 | int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); | ||
181 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); | ||
182 | int ps3_repository_read_region_total(u64 *region_total); | ||
183 | int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, | ||
184 | u64 *region_total); | ||
185 | |||
186 | /* repository pme info */ | ||
187 | |||
188 | int ps3_repository_read_num_be(unsigned int *num_be); | ||
189 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); | ||
190 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); | ||
191 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); | ||
192 | |||
193 | /* repository 'Other OS' area */ | ||
194 | |||
195 | int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); | ||
196 | int ps3_repository_read_boot_dat_size(unsigned int *size); | ||
197 | int 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 | |||
209 | enum ps3_spu_resource_type { | ||
210 | PS3_SPU_RESOURCE_TYPE_SHARED = 0, | ||
211 | PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL, | ||
212 | }; | ||
213 | |||
214 | int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved); | ||
215 | int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); | ||
216 | int 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 | |||
24 | enum ps3_vendor_id { | 25 | enum 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 | ||
258 | int ps3_repository_read_dev_intr(unsigned int bus_index, | 259 | int 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 | ||
277 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, | 278 | int 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 | ||
304 | int ps3_repository_read_dev_reg(unsigned int bus_index, | 306 | int 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 | ||
370 | static int dump_device_info(unsigned int bus_index, unsigned int num_dev) | 372 | static 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, ®ion_id, ®ion_start, | ||
401 | ®ion_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 | |||
414 | out: | ||
415 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
416 | return result; | ||
417 | } | ||
418 | |||
419 | static 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 | ||
615 | int ps3_repository_find_region(const struct ps3_repository_device *dev, | 672 | int 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 | ||
712 | int 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 | |||
722 | int 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 | |||
732 | int 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 | |||
742 | int 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 | |||
757 | int 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 | |||
774 | int 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 | |||
785 | int 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 | |||
796 | int 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 | |||
821 | int 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 | |||
654 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) | 842 | int 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 | ||
44 | static void ps3_show_cpuinfo(struct seq_file *m) | 44 | int 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 | } |
55 | EXPORT_SYMBOL_GPL(ps3_get_firmware_version); | ||
48 | 56 | ||
49 | static void ps3_power_save(void) | 57 | static void ps3_power_save(void) |
50 | { | 58 | { |
@@ -74,8 +82,14 @@ static void ps3_panic(char *str) | |||
74 | 82 | ||
75 | static void __init ps3_setup_arch(void) | 83 | static 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 | ||
52 | struct spe_shadow { | 53 | struct 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__) | ||
34 | static 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 | |||
44 | int 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 | |||
61 | int 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 | |||
76 | static 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 | |||
91 | static 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 | |||
134 | clean_dma: | ||
135 | ps3_dma_region_free(dev->d_region); | ||
136 | clean_device: | ||
137 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
138 | clean_none: | ||
139 | return result; | ||
140 | } | ||
141 | |||
142 | static 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 | |||
161 | struct 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 | |||
168 | int __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 | |||
180 | core_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 | |||
187 | static 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 | |||
217 | clean_alloc: | ||
218 | free_pages(virt_addr, get_order(size)); | ||
219 | clean_none: | ||
220 | dma_handle = NULL; | ||
221 | return NULL; | ||
222 | } | ||
223 | |||
224 | static 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 | |||
240 | static 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 | |||
258 | static 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 | |||
272 | static 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 | |||
300 | static 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 | |||
308 | static int ps3_dma_supported(struct device *_dev, u64 mask) | ||
309 | { | ||
310 | return mask >= DMA_32BIT_MASK; | ||
311 | } | ||
312 | |||
313 | static 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 | |||
327 | static 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 | |||
341 | int 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 | |||
363 | EXPORT_SYMBOL_GPL(ps3_system_bus_device_register); | ||
364 | |||
365 | int 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 | |||
375 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | ||
376 | |||
377 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | ||
378 | { | ||
379 | driver_unregister(&drv->core); | ||
380 | } | ||
381 | |||
382 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | ||