diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2006-11-22 18:46:59 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-04 04:40:56 -0500 |
commit | de91a53429952875740692d1de36ae70d4cf81da (patch) | |
tree | 51e0a7127eac6fd3501f732e42119299e1fae38c | |
parent | 00a3e2e93cd3ce73ab2d200fff22a62548da06d6 (diff) |
[POWERPC] ps3: add spu support
Adds spu support for the PS3 platform.
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
-rw-r--r-- | arch/powerpc/platforms/ps3/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/platform.h | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/ps3/spu.c | 613 |
3 files changed, 623 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index 6eb697786367..3757cfabc8ce 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile | |||
@@ -1,2 +1,4 @@ | |||
1 | obj-y += setup.o mm.o smp.o time.o hvcall.o htab.o repository.o | 1 | obj-y += setup.o mm.o smp.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 | |||
4 | obj-$(CONFIG_SPU_BASE) += spu.o | ||
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index d9948df6ccd4..23b111bea9d0 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -57,4 +57,12 @@ int ps3_set_rtc_time(struct rtc_time *time); | |||
57 | int __init ps3_os_area_init(void); | 57 | int __init ps3_os_area_init(void); |
58 | u64 ps3_os_area_rtc_diff(void); | 58 | u64 ps3_os_area_rtc_diff(void); |
59 | 59 | ||
60 | /* spu */ | ||
61 | |||
62 | #if defined(CONFIG_SPU_BASE) | ||
63 | void ps3_spu_set_platform (void); | ||
64 | #else | ||
65 | static inline void ps3_spu_set_platform (void) {} | ||
66 | #endif | ||
67 | |||
60 | #endif | 68 | #endif |
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c new file mode 100644 index 000000000000..644532c3b7c4 --- /dev/null +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -0,0 +1,613 @@ | |||
1 | /* | ||
2 | * PS3 Platform spu routines. | ||
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/mmzone.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/mm.h> | ||
26 | |||
27 | #include <asm/spu.h> | ||
28 | #include <asm/spu_priv1.h> | ||
29 | #include <asm/ps3.h> | ||
30 | #include <asm/lv1call.h> | ||
31 | |||
32 | /* spu_management_ops */ | ||
33 | |||
34 | /** | ||
35 | * enum spe_type - Type of spe to create. | ||
36 | * @spe_type_logical: Standard logical spe. | ||
37 | * | ||
38 | * For use with lv1_construct_logical_spe(). The current HV does not support | ||
39 | * any types other than those listed. | ||
40 | */ | ||
41 | |||
42 | enum spe_type { | ||
43 | SPE_TYPE_LOGICAL = 0, | ||
44 | }; | ||
45 | |||
46 | /** | ||
47 | * struct spe_shadow - logical spe shadow register area. | ||
48 | * | ||
49 | * Read-only shadow of spe registers. | ||
50 | */ | ||
51 | |||
52 | struct spe_shadow { | ||
53 | u8 padding_0000[0x0140]; | ||
54 | u64 int_status_class0_RW; /* 0x0140 */ | ||
55 | u64 int_status_class1_RW; /* 0x0148 */ | ||
56 | u64 int_status_class2_RW; /* 0x0150 */ | ||
57 | u8 padding_0158[0x0610-0x0158]; | ||
58 | u64 mfc_dsisr_RW; /* 0x0610 */ | ||
59 | u8 padding_0618[0x0620-0x0618]; | ||
60 | u64 mfc_dar_RW; /* 0x0620 */ | ||
61 | u8 padding_0628[0x0800-0x0628]; | ||
62 | u64 mfc_dsipr_R; /* 0x0800 */ | ||
63 | u8 padding_0808[0x0810-0x0808]; | ||
64 | u64 mfc_lscrr_R; /* 0x0810 */ | ||
65 | u8 padding_0818[0x0c00-0x0818]; | ||
66 | u64 mfc_cer_R; /* 0x0c00 */ | ||
67 | u8 padding_0c08[0x0f00-0x0c08]; | ||
68 | u64 spe_execution_status; /* 0x0f00 */ | ||
69 | u8 padding_0f08[0x1000-0x0f08]; | ||
70 | } __attribute__ ((packed)); | ||
71 | |||
72 | |||
73 | /** | ||
74 | * enum spe_ex_state - Logical spe execution state. | ||
75 | * @spe_ex_state_unexecutable: Uninitialized. | ||
76 | * @spe_ex_state_executable: Enabled, not ready. | ||
77 | * @spe_ex_state_executed: Ready for use. | ||
78 | * | ||
79 | * The execution state (status) of the logical spe as reported in | ||
80 | * struct spe_shadow:spe_execution_status. | ||
81 | */ | ||
82 | |||
83 | enum spe_ex_state { | ||
84 | SPE_EX_STATE_UNEXECUTABLE = 0, | ||
85 | SPE_EX_STATE_EXECUTABLE = 2, | ||
86 | SPE_EX_STATE_EXECUTED = 3, | ||
87 | }; | ||
88 | |||
89 | /** | ||
90 | * struct priv1_cache - Cached values of priv1 registers. | ||
91 | * @masks[]: Array of cached spe interrupt masks, indexed by class. | ||
92 | * @sr1: Cached mfc_sr1 register. | ||
93 | * @tclass_id: Cached mfc_tclass_id register. | ||
94 | */ | ||
95 | |||
96 | struct priv1_cache { | ||
97 | u64 masks[3]; | ||
98 | u64 sr1; | ||
99 | u64 tclass_id; | ||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * struct spu_pdata - Platform state variables. | ||
104 | * @spe_id: HV spe id returned by lv1_construct_logical_spe(). | ||
105 | * @resource_id: HV spe resource id returned by | ||
106 | * ps3_repository_read_spe_resource_id(). | ||
107 | * @priv2_addr: lpar address of spe priv2 area returned by | ||
108 | * lv1_construct_logical_spe(). | ||
109 | * @shadow_addr: lpar address of spe register shadow area returned by | ||
110 | * lv1_construct_logical_spe(). | ||
111 | * @shadow: Virtual (ioremap) address of spe register shadow area. | ||
112 | * @cache: Cached values of priv1 registers. | ||
113 | */ | ||
114 | |||
115 | struct spu_pdata { | ||
116 | u64 spe_id; | ||
117 | u64 resource_id; | ||
118 | u64 priv2_addr; | ||
119 | u64 shadow_addr; | ||
120 | struct spe_shadow __iomem *shadow; | ||
121 | struct priv1_cache cache; | ||
122 | }; | ||
123 | |||
124 | static struct spu_pdata *spu_pdata(struct spu *spu) | ||
125 | { | ||
126 | return spu->pdata; | ||
127 | } | ||
128 | |||
129 | #define dump_areas(_a, _b, _c, _d, _e) \ | ||
130 | _dump_areas(_a, _b, _c, _d, _e, __func__, __LINE__) | ||
131 | static void _dump_areas(unsigned int spe_id, unsigned long priv2, | ||
132 | unsigned long problem, unsigned long ls, unsigned long shadow, | ||
133 | const char* func, int line) | ||
134 | { | ||
135 | pr_debug("%s:%d: spe_id: %xh (%u)\n", func, line, spe_id, spe_id); | ||
136 | pr_debug("%s:%d: priv2: %lxh\n", func, line, priv2); | ||
137 | pr_debug("%s:%d: problem: %lxh\n", func, line, problem); | ||
138 | pr_debug("%s:%d: ls: %lxh\n", func, line, ls); | ||
139 | pr_debug("%s:%d: shadow: %lxh\n", func, line, shadow); | ||
140 | } | ||
141 | |||
142 | static unsigned long get_vas_id(void) | ||
143 | { | ||
144 | unsigned long id; | ||
145 | |||
146 | lv1_get_logical_ppe_id(&id); | ||
147 | lv1_get_virtual_address_space_id_of_ppe(id, &id); | ||
148 | |||
149 | return id; | ||
150 | } | ||
151 | |||
152 | static int __init construct_spu(struct spu *spu) | ||
153 | { | ||
154 | int result; | ||
155 | unsigned long unused; | ||
156 | |||
157 | result = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT, | ||
158 | PAGE_SHIFT, PAGE_SHIFT, get_vas_id(), SPE_TYPE_LOGICAL, | ||
159 | &spu_pdata(spu)->priv2_addr, &spu->problem_phys, | ||
160 | &spu->local_store_phys, &unused, | ||
161 | &spu_pdata(spu)->shadow_addr, | ||
162 | &spu_pdata(spu)->spe_id); | ||
163 | |||
164 | if (result) { | ||
165 | pr_debug("%s:%d: lv1_construct_logical_spe failed: %s\n", | ||
166 | __func__, __LINE__, ps3_result(result)); | ||
167 | return result; | ||
168 | } | ||
169 | |||
170 | return result; | ||
171 | } | ||
172 | |||
173 | static int __init add_spu_pages(unsigned long start_addr, unsigned long size) | ||
174 | { | ||
175 | int result; | ||
176 | unsigned long start_pfn; | ||
177 | unsigned long nr_pages; | ||
178 | struct pglist_data *pgdata; | ||
179 | struct zone *zone; | ||
180 | |||
181 | BUG_ON(!mem_init_done); | ||
182 | |||
183 | start_pfn = start_addr >> PAGE_SHIFT; | ||
184 | nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
185 | |||
186 | pgdata = NODE_DATA(0); | ||
187 | zone = pgdata->node_zones; | ||
188 | |||
189 | result = __add_pages(zone, start_pfn, nr_pages); | ||
190 | |||
191 | if (result) | ||
192 | pr_debug("%s:%d: __add_pages failed: (%d)\n", | ||
193 | __func__, __LINE__, result); | ||
194 | |||
195 | return result; | ||
196 | } | ||
197 | |||
198 | static void spu_unmap(struct spu *spu) | ||
199 | { | ||
200 | iounmap(spu->priv2); | ||
201 | iounmap(spu->problem); | ||
202 | iounmap((__force u8 __iomem *)spu->local_store); | ||
203 | iounmap(spu_pdata(spu)->shadow); | ||
204 | } | ||
205 | |||
206 | static int __init setup_areas(struct spu *spu) | ||
207 | { | ||
208 | struct table {char* name; unsigned long addr; unsigned long size;}; | ||
209 | int result; | ||
210 | |||
211 | /* setup pages */ | ||
212 | |||
213 | result = add_spu_pages(spu->local_store_phys, LS_SIZE); | ||
214 | if (result) | ||
215 | goto fail_add; | ||
216 | |||
217 | result = add_spu_pages(spu->problem_phys, sizeof(struct spu_problem)); | ||
218 | if (result) | ||
219 | goto fail_add; | ||
220 | |||
221 | /* ioremap */ | ||
222 | |||
223 | spu_pdata(spu)->shadow = __ioremap( | ||
224 | spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), | ||
225 | PAGE_READONLY | _PAGE_NO_CACHE | _PAGE_GUARDED); | ||
226 | if (!spu_pdata(spu)->shadow) { | ||
227 | pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__); | ||
228 | goto fail_ioremap; | ||
229 | } | ||
230 | |||
231 | spu->local_store = ioremap(spu->local_store_phys, LS_SIZE); | ||
232 | if (!spu->local_store) { | ||
233 | pr_debug("%s:%d: ioremap local_store failed\n", | ||
234 | __func__, __LINE__); | ||
235 | goto fail_ioremap; | ||
236 | } | ||
237 | |||
238 | spu->problem = ioremap(spu->problem_phys, | ||
239 | sizeof(struct spu_problem)); | ||
240 | if (!spu->problem) { | ||
241 | pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__); | ||
242 | goto fail_ioremap; | ||
243 | } | ||
244 | |||
245 | spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr, | ||
246 | sizeof(struct spu_priv2)); | ||
247 | if (!spu->priv2) { | ||
248 | pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__); | ||
249 | goto fail_ioremap; | ||
250 | } | ||
251 | |||
252 | dump_areas(spu_pdata(spu)->spe_id, spu_pdata(spu)->priv2_addr, | ||
253 | spu->problem_phys, spu->local_store_phys, | ||
254 | spu_pdata(spu)->shadow_addr); | ||
255 | dump_areas(spu_pdata(spu)->spe_id, (unsigned long)spu->priv2, | ||
256 | (unsigned long)spu->problem, (unsigned long)spu->local_store, | ||
257 | (unsigned long)spu_pdata(spu)->shadow); | ||
258 | |||
259 | return 0; | ||
260 | |||
261 | fail_ioremap: | ||
262 | spu_unmap(spu); | ||
263 | fail_add: | ||
264 | return result; | ||
265 | } | ||
266 | |||
267 | static int __init setup_interrupts(struct spu *spu) | ||
268 | { | ||
269 | int result; | ||
270 | |||
271 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, | ||
272 | &spu->irqs[0]); | ||
273 | |||
274 | if (result) | ||
275 | goto fail_alloc_0; | ||
276 | |||
277 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, | ||
278 | &spu->irqs[1]); | ||
279 | |||
280 | if (result) | ||
281 | goto fail_alloc_1; | ||
282 | |||
283 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, | ||
284 | &spu->irqs[2]); | ||
285 | |||
286 | if (result) | ||
287 | goto fail_alloc_2; | ||
288 | |||
289 | return result; | ||
290 | |||
291 | fail_alloc_2: | ||
292 | ps3_free_spe_irq(spu->irqs[1]); | ||
293 | fail_alloc_1: | ||
294 | ps3_free_spe_irq(spu->irqs[0]); | ||
295 | fail_alloc_0: | ||
296 | spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; | ||
297 | return result; | ||
298 | } | ||
299 | |||
300 | static int __init enable_spu(struct spu *spu) | ||
301 | { | ||
302 | int result; | ||
303 | |||
304 | result = lv1_enable_logical_spe(spu_pdata(spu)->spe_id, | ||
305 | spu_pdata(spu)->resource_id); | ||
306 | |||
307 | if (result) { | ||
308 | pr_debug("%s:%d: lv1_enable_logical_spe failed: %s\n", | ||
309 | __func__, __LINE__, ps3_result(result)); | ||
310 | goto fail_enable; | ||
311 | } | ||
312 | |||
313 | result = setup_areas(spu); | ||
314 | |||
315 | if (result) | ||
316 | goto fail_areas; | ||
317 | |||
318 | result = setup_interrupts(spu); | ||
319 | |||
320 | if (result) | ||
321 | goto fail_interrupts; | ||
322 | |||
323 | return 0; | ||
324 | |||
325 | fail_interrupts: | ||
326 | spu_unmap(spu); | ||
327 | fail_areas: | ||
328 | lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0); | ||
329 | fail_enable: | ||
330 | return result; | ||
331 | } | ||
332 | |||
333 | static int ps3_destroy_spu(struct spu *spu) | ||
334 | { | ||
335 | int result; | ||
336 | |||
337 | pr_debug("%s:%d spu_%d\n", __func__, __LINE__, spu->number); | ||
338 | |||
339 | result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0); | ||
340 | BUG_ON(result); | ||
341 | |||
342 | ps3_free_spe_irq(spu->irqs[2]); | ||
343 | ps3_free_spe_irq(spu->irqs[1]); | ||
344 | ps3_free_spe_irq(spu->irqs[0]); | ||
345 | |||
346 | spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ; | ||
347 | |||
348 | spu_unmap(spu); | ||
349 | |||
350 | result = lv1_destruct_logical_spe(spu_pdata(spu)->spe_id); | ||
351 | BUG_ON(result); | ||
352 | |||
353 | kfree(spu->pdata); | ||
354 | spu->pdata = NULL; | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static int __init ps3_create_spu(struct spu *spu, void *data) | ||
360 | { | ||
361 | int result; | ||
362 | |||
363 | pr_debug("%s:%d spu_%d\n", __func__, __LINE__, spu->number); | ||
364 | |||
365 | spu->pdata = kzalloc(sizeof(struct spu_pdata), | ||
366 | GFP_KERNEL); | ||
367 | |||
368 | if (!spu->pdata) { | ||
369 | result = -ENOMEM; | ||
370 | goto fail_malloc; | ||
371 | } | ||
372 | |||
373 | spu_pdata(spu)->resource_id = (unsigned long)data; | ||
374 | |||
375 | /* Init cached reg values to HV defaults. */ | ||
376 | |||
377 | spu_pdata(spu)->cache.sr1 = 0x33; | ||
378 | |||
379 | result = construct_spu(spu); | ||
380 | |||
381 | if (result) | ||
382 | goto fail_construct; | ||
383 | |||
384 | /* For now, just go ahead and enable it. */ | ||
385 | |||
386 | result = enable_spu(spu); | ||
387 | |||
388 | if (result) | ||
389 | goto fail_enable; | ||
390 | |||
391 | /* Make sure the spu is in SPE_EX_STATE_EXECUTED. */ | ||
392 | |||
393 | /* need something better here!!! */ | ||
394 | while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status) | ||
395 | != SPE_EX_STATE_EXECUTED) | ||
396 | (void)0; | ||
397 | |||
398 | return result; | ||
399 | |||
400 | fail_enable: | ||
401 | fail_construct: | ||
402 | ps3_destroy_spu(spu); | ||
403 | fail_malloc: | ||
404 | return result; | ||
405 | } | ||
406 | |||
407 | static int __init ps3_enumerate_spus(int (*fn)(void *data)) | ||
408 | { | ||
409 | int result; | ||
410 | unsigned int num_resource_id; | ||
411 | unsigned int i; | ||
412 | |||
413 | result = ps3_repository_read_num_spu_resource_id(&num_resource_id); | ||
414 | |||
415 | pr_debug("%s:%d: num_resource_id %u\n", __func__, __LINE__, | ||
416 | num_resource_id); | ||
417 | |||
418 | /* | ||
419 | * For now, just create logical spus equal to the number | ||
420 | * of physical spus reserved for the partition. | ||
421 | */ | ||
422 | |||
423 | for (i = 0; i < num_resource_id; i++) { | ||
424 | enum ps3_spu_resource_type resource_type; | ||
425 | unsigned int resource_id; | ||
426 | |||
427 | result = ps3_repository_read_spu_resource_id(i, | ||
428 | &resource_type, &resource_id); | ||
429 | |||
430 | if (result) | ||
431 | break; | ||
432 | |||
433 | if (resource_type == PS3_SPU_RESOURCE_TYPE_EXCLUSIVE) { | ||
434 | result = fn((void*)(unsigned long)resource_id); | ||
435 | |||
436 | if (result) | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | |||
441 | if (result) | ||
442 | printk(KERN_WARNING "%s:%d: Error initializing spus\n", | ||
443 | __func__, __LINE__); | ||
444 | |||
445 | return result; | ||
446 | } | ||
447 | |||
448 | const struct spu_management_ops spu_management_ps3_ops = { | ||
449 | .enumerate_spus = ps3_enumerate_spus, | ||
450 | .create_spu = ps3_create_spu, | ||
451 | .destroy_spu = ps3_destroy_spu, | ||
452 | }; | ||
453 | |||
454 | /* spu_priv1_ops */ | ||
455 | |||
456 | static void int_mask_and(struct spu *spu, int class, u64 mask) | ||
457 | { | ||
458 | u64 old_mask; | ||
459 | |||
460 | /* are these serialized by caller??? */ | ||
461 | old_mask = spu_int_mask_get(spu, class); | ||
462 | spu_int_mask_set(spu, class, old_mask & mask); | ||
463 | } | ||
464 | |||
465 | static void int_mask_or(struct spu *spu, int class, u64 mask) | ||
466 | { | ||
467 | u64 old_mask; | ||
468 | |||
469 | old_mask = spu_int_mask_get(spu, class); | ||
470 | spu_int_mask_set(spu, class, old_mask | mask); | ||
471 | } | ||
472 | |||
473 | static void int_mask_set(struct spu *spu, int class, u64 mask) | ||
474 | { | ||
475 | spu_pdata(spu)->cache.masks[class] = mask; | ||
476 | lv1_set_spe_interrupt_mask(spu_pdata(spu)->spe_id, class, | ||
477 | spu_pdata(spu)->cache.masks[class]); | ||
478 | } | ||
479 | |||
480 | static u64 int_mask_get(struct spu *spu, int class) | ||
481 | { | ||
482 | return spu_pdata(spu)->cache.masks[class]; | ||
483 | } | ||
484 | |||
485 | static void int_stat_clear(struct spu *spu, int class, u64 stat) | ||
486 | { | ||
487 | /* Note that MFC_DSISR will be cleared when class1[MF] is set. */ | ||
488 | |||
489 | lv1_clear_spe_interrupt_status(spu_pdata(spu)->spe_id, class, | ||
490 | stat, 0); | ||
491 | } | ||
492 | |||
493 | static u64 int_stat_get(struct spu *spu, int class) | ||
494 | { | ||
495 | u64 stat; | ||
496 | |||
497 | lv1_get_spe_interrupt_status(spu_pdata(spu)->spe_id, class, &stat); | ||
498 | return stat; | ||
499 | } | ||
500 | |||
501 | static void cpu_affinity_set(struct spu *spu, int cpu) | ||
502 | { | ||
503 | /* No support. */ | ||
504 | } | ||
505 | |||
506 | static u64 mfc_dar_get(struct spu *spu) | ||
507 | { | ||
508 | return in_be64(&spu_pdata(spu)->shadow->mfc_dar_RW); | ||
509 | } | ||
510 | |||
511 | static void mfc_dsisr_set(struct spu *spu, u64 dsisr) | ||
512 | { | ||
513 | /* Nothing to do, cleared in int_stat_clear(). */ | ||
514 | } | ||
515 | |||
516 | static u64 mfc_dsisr_get(struct spu *spu) | ||
517 | { | ||
518 | return in_be64(&spu_pdata(spu)->shadow->mfc_dsisr_RW); | ||
519 | } | ||
520 | |||
521 | static void mfc_sdr_setup(struct spu *spu) | ||
522 | { | ||
523 | /* Nothing to do. */ | ||
524 | } | ||
525 | |||
526 | static void mfc_sr1_set(struct spu *spu, u64 sr1) | ||
527 | { | ||
528 | /* Check bits allowed by HV. */ | ||
529 | |||
530 | static const u64 allowed = ~(MFC_STATE1_LOCAL_STORAGE_DECODE_MASK | ||
531 | | MFC_STATE1_PROBLEM_STATE_MASK); | ||
532 | |||
533 | BUG_ON((sr1 & allowed) != (spu_pdata(spu)->cache.sr1 & allowed)); | ||
534 | |||
535 | spu_pdata(spu)->cache.sr1 = sr1; | ||
536 | lv1_set_spe_privilege_state_area_1_register( | ||
537 | spu_pdata(spu)->spe_id, | ||
538 | offsetof(struct spu_priv1, mfc_sr1_RW), | ||
539 | spu_pdata(spu)->cache.sr1); | ||
540 | } | ||
541 | |||
542 | static u64 mfc_sr1_get(struct spu *spu) | ||
543 | { | ||
544 | return spu_pdata(spu)->cache.sr1; | ||
545 | } | ||
546 | |||
547 | static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) | ||
548 | { | ||
549 | spu_pdata(spu)->cache.tclass_id = tclass_id; | ||
550 | lv1_set_spe_privilege_state_area_1_register( | ||
551 | spu_pdata(spu)->spe_id, | ||
552 | offsetof(struct spu_priv1, mfc_tclass_id_RW), | ||
553 | spu_pdata(spu)->cache.tclass_id); | ||
554 | } | ||
555 | |||
556 | static u64 mfc_tclass_id_get(struct spu *spu) | ||
557 | { | ||
558 | return spu_pdata(spu)->cache.tclass_id; | ||
559 | } | ||
560 | |||
561 | static void tlb_invalidate(struct spu *spu) | ||
562 | { | ||
563 | /* Nothing to do. */ | ||
564 | } | ||
565 | |||
566 | static void resource_allocation_groupID_set(struct spu *spu, u64 id) | ||
567 | { | ||
568 | /* No support. */ | ||
569 | } | ||
570 | |||
571 | static u64 resource_allocation_groupID_get(struct spu *spu) | ||
572 | { | ||
573 | return 0; /* No support. */ | ||
574 | } | ||
575 | |||
576 | static void resource_allocation_enable_set(struct spu *spu, u64 enable) | ||
577 | { | ||
578 | /* No support. */ | ||
579 | } | ||
580 | |||
581 | static u64 resource_allocation_enable_get(struct spu *spu) | ||
582 | { | ||
583 | return 0; /* No support. */ | ||
584 | } | ||
585 | |||
586 | const struct spu_priv1_ops spu_priv1_ps3_ops = { | ||
587 | .int_mask_and = int_mask_and, | ||
588 | .int_mask_or = int_mask_or, | ||
589 | .int_mask_set = int_mask_set, | ||
590 | .int_mask_get = int_mask_get, | ||
591 | .int_stat_clear = int_stat_clear, | ||
592 | .int_stat_get = int_stat_get, | ||
593 | .cpu_affinity_set = cpu_affinity_set, | ||
594 | .mfc_dar_get = mfc_dar_get, | ||
595 | .mfc_dsisr_set = mfc_dsisr_set, | ||
596 | .mfc_dsisr_get = mfc_dsisr_get, | ||
597 | .mfc_sdr_setup = mfc_sdr_setup, | ||
598 | .mfc_sr1_set = mfc_sr1_set, | ||
599 | .mfc_sr1_get = mfc_sr1_get, | ||
600 | .mfc_tclass_id_set = mfc_tclass_id_set, | ||
601 | .mfc_tclass_id_get = mfc_tclass_id_get, | ||
602 | .tlb_invalidate = tlb_invalidate, | ||
603 | .resource_allocation_groupID_set = resource_allocation_groupID_set, | ||
604 | .resource_allocation_groupID_get = resource_allocation_groupID_get, | ||
605 | .resource_allocation_enable_set = resource_allocation_enable_set, | ||
606 | .resource_allocation_enable_get = resource_allocation_enable_get, | ||
607 | }; | ||
608 | |||
609 | void ps3_spu_set_platform(void) | ||
610 | { | ||
611 | spu_priv1_ops = &spu_priv1_ps3_ops; | ||
612 | spu_management_ops = &spu_management_ps3_ops; | ||
613 | } | ||