1de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/*
2de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  PS3 Platform spu routines.
3de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
4de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  Copyright (C) 2006 Sony Computer Entertainment Inc.
5de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  Copyright 2006 Sony Corp.
6de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
7de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  This program is free software; you can redistribute it and/or modify
8de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  it under the terms of the GNU General Public License as published by
9de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  the Free Software Foundation; version 2 of the License.
10de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
11de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  This program is distributed in the hope that it will be useful,
12de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  GNU General Public License for more details.
15de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
16de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  You should have received a copy of the GNU General Public License
17de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  along with this program; if not, write to the Free Software
18de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
20de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
21de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <linux/kernel.h>
22de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <linux/init.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
24de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <linux/mmzone.h>
2566b15db69c2553036cc25f6e2e74fe7e3aa2761ePaul Gortmaker#include <linux/export.h>
26de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <linux/io.h>
27de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <linux/mm.h>
28de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
29de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <asm/spu.h>
30de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <asm/spu_priv1.h>
31de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#include <asm/lv1call.h>
3223afcb4e0061c591776a3350db89512d085397c2Takashi Yamamoto#include <asm/ps3.h>
33de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
34c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi#include "../cell/spufs/spufs.h"
352a08ea69a3e448a5cc94e5da9eccc40cf13f9532Geoff Levand#include "platform.h"
362a08ea69a3e448a5cc94e5da9eccc40cf13f9532Geoff Levand
37de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/* spu_management_ops */
38de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
39de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/**
40de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * enum spe_type - Type of spe to create.
41de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @spe_type_logical: Standard logical spe.
42de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
43de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * For use with lv1_construct_logical_spe().  The current HV does not support
44de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * any types other than those listed.
45de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
46de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
47de91a53429952875740692d1de36ae70d4cf81daGeoff Levandenum spe_type {
48de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	SPE_TYPE_LOGICAL = 0,
49de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
50de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
51de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/**
52de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * struct spe_shadow - logical spe shadow register area.
53de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
54de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * Read-only shadow of spe registers.
55de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
56de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
57de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstruct spe_shadow {
58a8229a9e5211a52839268b82ae14cdf528d48f58Geoff Levand	u8 padding_0140[0x0140];
59de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 int_status_class0_RW;       /* 0x0140 */
60de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 int_status_class1_RW;       /* 0x0148 */
61de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 int_status_class2_RW;       /* 0x0150 */
62de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0158[0x0610-0x0158];
63de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 mfc_dsisr_RW;               /* 0x0610 */
64de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0618[0x0620-0x0618];
65de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 mfc_dar_RW;                 /* 0x0620 */
66de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0628[0x0800-0x0628];
67de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 mfc_dsipr_R;                /* 0x0800 */
68de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0808[0x0810-0x0808];
69de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 mfc_lscrr_R;                /* 0x0810 */
70de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0818[0x0c00-0x0818];
71de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 mfc_cer_R;                  /* 0x0c00 */
72de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0c08[0x0f00-0x0c08];
73de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 spe_execution_status;       /* 0x0f00 */
74de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u8 padding_0f08[0x1000-0x0f08];
75a8229a9e5211a52839268b82ae14cdf528d48f58Geoff Levand};
76de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
77de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/**
78de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * enum spe_ex_state - Logical spe execution state.
79de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @spe_ex_state_unexecutable: Uninitialized.
80de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @spe_ex_state_executable: Enabled, not ready.
81de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @spe_ex_state_executed: Ready for use.
82de91a53429952875740692d1de36ae70d4cf81daGeoff Levand *
83de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * The execution state (status) of the logical spe as reported in
84de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * struct spe_shadow:spe_execution_status.
85de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
86de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
87de91a53429952875740692d1de36ae70d4cf81daGeoff Levandenum spe_ex_state {
88de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	SPE_EX_STATE_UNEXECUTABLE = 0,
89de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	SPE_EX_STATE_EXECUTABLE = 2,
90de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	SPE_EX_STATE_EXECUTED = 3,
91de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
92de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
93de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/**
94de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * struct priv1_cache - Cached values of priv1 registers.
95de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @masks[]: Array of cached spe interrupt masks, indexed by class.
96de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @sr1: Cached mfc_sr1 register.
97de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @tclass_id: Cached mfc_tclass_id register.
98de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
99de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
100de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstruct priv1_cache {
101de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 masks[3];
102de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 sr1;
103de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 tclass_id;
104de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
105de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
106de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/**
107de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * struct spu_pdata - Platform state variables.
108de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @spe_id: HV spe id returned by lv1_construct_logical_spe().
109de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @resource_id: HV spe resource id returned by
110de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * 	ps3_repository_read_spe_resource_id().
111de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @priv2_addr: lpar address of spe priv2 area returned by
112de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * 	lv1_construct_logical_spe().
113de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @shadow_addr: lpar address of spe register shadow area returned by
114de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * 	lv1_construct_logical_spe().
115de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @shadow: Virtual (ioremap) address of spe register shadow area.
116de91a53429952875740692d1de36ae70d4cf81daGeoff Levand * @cache: Cached values of priv1 registers.
117de91a53429952875740692d1de36ae70d4cf81daGeoff Levand */
118de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
119de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstruct spu_pdata {
120de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 spe_id;
121de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 resource_id;
122de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 priv2_addr;
123de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 shadow_addr;
124de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	struct spe_shadow __iomem *shadow;
125de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	struct priv1_cache cache;
126de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
127de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
128de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic struct spu_pdata *spu_pdata(struct spu *spu)
129de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
130de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return spu->pdata;
131de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
132de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
133de91a53429952875740692d1de36ae70d4cf81daGeoff Levand#define dump_areas(_a, _b, _c, _d, _e) \
134de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	_dump_areas(_a, _b, _c, _d, _e, __func__, __LINE__)
135de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void _dump_areas(unsigned int spe_id, unsigned long priv2,
136de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	unsigned long problem, unsigned long ls, unsigned long shadow,
137de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	const char* func, int line)
138de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
139de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: spe_id:  %xh (%u)\n", func, line, spe_id, spe_id);
140de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: priv2:   %lxh\n", func, line, priv2);
141de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: problem: %lxh\n", func, line, problem);
142de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: ls:      %lxh\n", func, line, ls);
143de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: shadow:  %lxh\n", func, line, shadow);
144de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
145de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
14623afcb4e0061c591776a3350db89512d085397c2Takashi Yamamotoinline u64 ps3_get_spe_id(void *arg)
14723afcb4e0061c591776a3350db89512d085397c2Takashi Yamamoto{
14823afcb4e0061c591776a3350db89512d085397c2Takashi Yamamoto	return spu_pdata(arg)->spe_id;
14923afcb4e0061c591776a3350db89512d085397c2Takashi Yamamoto}
15023afcb4e0061c591776a3350db89512d085397c2Takashi YamamotoEXPORT_SYMBOL_GPL(ps3_get_spe_id);
15123afcb4e0061c591776a3350db89512d085397c2Takashi Yamamoto
152de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic unsigned long get_vas_id(void)
153de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
154b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	u64 id;
155de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
156de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_get_logical_ppe_id(&id);
157b5ecc5595e4fb2992093b3d2d0e15b4630eb233bGeoff Levand	lv1_get_virtual_address_space_id_of_ppe(&id);
158de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
159de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return id;
160de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
161de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
162de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init construct_spu(struct spu *spu)
163de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
164de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
165b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	u64 unused;
166b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	u64 problem_phys;
167b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	u64 local_store_phys;
168de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
169de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = lv1_construct_logical_spe(PAGE_SHIFT, PAGE_SHIFT, PAGE_SHIFT,
170de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		PAGE_SHIFT, PAGE_SHIFT, get_vas_id(), SPE_TYPE_LOGICAL,
171b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell		&spu_pdata(spu)->priv2_addr, &problem_phys,
172b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell		&local_store_phys, &unused,
173de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		&spu_pdata(spu)->shadow_addr,
174de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		&spu_pdata(spu)->spe_id);
175b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	spu->problem_phys = problem_phys;
176b17b3df161814c43c03dbc8dbf8d32741bb30ba4Stephen Rothwell	spu->local_store_phys = local_store_phys;
177de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
178de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result) {
179de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: lv1_construct_logical_spe failed: %s\n",
180de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			__func__, __LINE__, ps3_result(result));
181de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		return result;
182de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
183de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
184de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
185de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
186de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
187de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void spu_unmap(struct spu *spu)
188de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
189de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	iounmap(spu->priv2);
190de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	iounmap(spu->problem);
191de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	iounmap((__force u8 __iomem *)spu->local_store);
192de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	iounmap(spu_pdata(spu)->shadow);
193de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
194de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
195b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno/**
196b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno * setup_areas - Map the spu regions into the address space.
197b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno *
198b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno * The current HV requires the spu shadow regs to be mapped with the
199b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno * PTE page protection bits set as read-only (PP=3).  This implementation
200b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno * uses the low level __ioremap() to bypass the page protection settings
20140f1ce7fb7e8b5d4d0821c0f3dc866cb1d47d99cAnton Blanchard * inforced by ioremap_prot() to get the needed PTE bits set for the
202b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno * shadow regs.
203b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno */
204b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno
205de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init setup_areas(struct spu *spu)
206de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
207de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	struct table {char* name; unsigned long addr; unsigned long size;};
208b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno	static const unsigned long shadow_flags = _PAGE_NO_CACHE | 3;
209de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
210b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno	spu_pdata(spu)->shadow = __ioremap(spu_pdata(spu)->shadow_addr,
211b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno					   sizeof(struct spe_shadow),
212b47027795a22fe61f93de6010c120f26273fc693Masakazu Mokuno					   shadow_flags);
213de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (!spu_pdata(spu)->shadow) {
214de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: ioremap shadow failed\n", __func__, __LINE__);
215de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_ioremap;
216de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
217de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
21840f1ce7fb7e8b5d4d0821c0f3dc866cb1d47d99cAnton Blanchard	spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys,
21953f7c5453dfd3ba66a2d80bd2fda98a2438c3dc0Geoff Levand		LS_SIZE, _PAGE_NO_CACHE);
22053f7c5453dfd3ba66a2d80bd2fda98a2438c3dc0Geoff Levand
221de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (!spu->local_store) {
222de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: ioremap local_store failed\n",
223de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			__func__, __LINE__);
224de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_ioremap;
225de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
226de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
227de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->problem = ioremap(spu->problem_phys,
228de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		sizeof(struct spu_problem));
22953f7c5453dfd3ba66a2d80bd2fda98a2438c3dc0Geoff Levand
230de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (!spu->problem) {
231de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: ioremap problem failed\n", __func__, __LINE__);
232de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_ioremap;
233de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
234de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
235de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->priv2 = ioremap(spu_pdata(spu)->priv2_addr,
236de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		sizeof(struct spu_priv2));
23753f7c5453dfd3ba66a2d80bd2fda98a2438c3dc0Geoff Levand
238de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (!spu->priv2) {
239de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: ioremap priv2 failed\n", __func__, __LINE__);
240de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_ioremap;
241de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
242de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
243de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	dump_areas(spu_pdata(spu)->spe_id, spu_pdata(spu)->priv2_addr,
244de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu->problem_phys, spu->local_store_phys,
245de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->shadow_addr);
246de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	dump_areas(spu_pdata(spu)->spe_id, (unsigned long)spu->priv2,
247de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		(unsigned long)spu->problem, (unsigned long)spu->local_store,
248de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		(unsigned long)spu_pdata(spu)->shadow);
249de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
250de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return 0;
251de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
252de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_ioremap:
253de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_unmap(spu);
25444430e0d3916ab6aaf0451fdb811f4f1803b741eBenjamin Herrenschmidt
25544430e0d3916ab6aaf0451fdb811f4f1803b741eBenjamin Herrenschmidt	return -ENOMEM;
256de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
257de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
258de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init setup_interrupts(struct spu *spu)
259de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
260de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
261de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
262dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
263861be32ce7f1cf272a3f809e77213b83117a0bd2Geoff Levand		0, &spu->irqs[0]);
264de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
265de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
266de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_alloc_0;
267de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
268dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
269861be32ce7f1cf272a3f809e77213b83117a0bd2Geoff Levand		1, &spu->irqs[1]);
270de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
271de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
272de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_alloc_1;
273de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
274dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	result = ps3_spe_irq_setup(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
275861be32ce7f1cf272a3f809e77213b83117a0bd2Geoff Levand		2, &spu->irqs[2]);
276de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
277de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
278de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_alloc_2;
279de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
280de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
281de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
282de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_alloc_2:
283dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	ps3_spe_irq_destroy(spu->irqs[1]);
284de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_alloc_1:
285dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	ps3_spe_irq_destroy(spu->irqs[0]);
286de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_alloc_0:
287de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
288de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
289de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
290de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
291de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init enable_spu(struct spu *spu)
292de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
293de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
294de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
295de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = lv1_enable_logical_spe(spu_pdata(spu)->spe_id,
296de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->resource_id);
297de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
298de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result) {
299de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		pr_debug("%s:%d: lv1_enable_logical_spe failed: %s\n",
300de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			__func__, __LINE__, ps3_result(result));
301de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_enable;
302de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
303de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
304de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = setup_areas(spu);
305de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
306de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
307de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_areas;
308de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
309de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = setup_interrupts(spu);
310de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
311de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
312de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_interrupts;
313de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
314de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return 0;
315de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
316de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_interrupts:
317de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_unmap(spu);
318de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_areas:
319de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0);
320de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_enable:
321de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
322de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
323de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
324de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int ps3_destroy_spu(struct spu *spu)
325de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
326de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
327de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
328de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d spu_%d\n", __func__, __LINE__, spu->number);
329de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
330de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = lv1_disable_logical_spe(spu_pdata(spu)->spe_id, 0);
331de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	BUG_ON(result);
332de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
333dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	ps3_spe_irq_destroy(spu->irqs[2]);
334dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	ps3_spe_irq_destroy(spu->irqs[1]);
335dc4f60c25ae71e8278dcf909486e4aa34de7eecbGeoff Levand	ps3_spe_irq_destroy(spu->irqs[0]);
336de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
337de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->irqs[0] = spu->irqs[1] = spu->irqs[2] = NO_IRQ;
338de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
339de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_unmap(spu);
340de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
341de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = lv1_destruct_logical_spe(spu_pdata(spu)->spe_id);
342de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	BUG_ON(result);
343de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
344de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	kfree(spu->pdata);
345de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->pdata = NULL;
346de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
347de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return 0;
348de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
349de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
350de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init ps3_create_spu(struct spu *spu, void *data)
351de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
352de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
353de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
354de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d spu_%d\n", __func__, __LINE__, spu->number);
355de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
356de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu->pdata = kzalloc(sizeof(struct spu_pdata),
357de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		GFP_KERNEL);
358de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
359de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (!spu->pdata) {
360de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		result = -ENOMEM;
361de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_malloc;
362de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
363de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
364de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_pdata(spu)->resource_id = (unsigned long)data;
365de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
366de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Init cached reg values to HV defaults. */
367de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
368de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_pdata(spu)->cache.sr1 = 0x33;
369de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
370de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = construct_spu(spu);
371de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
372de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
373de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_construct;
374de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
375de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* For now, just go ahead and enable it. */
376de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
377de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = enable_spu(spu);
378de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
379de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	if (result)
380de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		goto fail_enable;
381de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
382de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Make sure the spu is in SPE_EX_STATE_EXECUTED. */
383de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
384de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* need something better here!!! */
385de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	while (in_be64(&spu_pdata(spu)->shadow->spe_execution_status)
386de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		!= SPE_EX_STATE_EXECUTED)
387de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		(void)0;
388de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
389de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
390de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
391de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_enable:
392de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_construct:
393de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	ps3_destroy_spu(spu);
394de91a53429952875740692d1de36ae70d4cf81daGeoff Levandfail_malloc:
395de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return result;
396de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
397de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
398de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic int __init ps3_enumerate_spus(int (*fn)(void *data))
399de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
400de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	int result;
401de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	unsigned int num_resource_id;
402de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	unsigned int i;
403de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
404de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	result = ps3_repository_read_num_spu_resource_id(&num_resource_id);
405de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
406de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	pr_debug("%s:%d: num_resource_id %u\n", __func__, __LINE__,
407de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		num_resource_id);
408de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
409de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/*
410de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	 * For now, just create logical spus equal to the number
411de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	 * of physical spus reserved for the partition.
412de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	 */
413de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
414de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	for (i = 0; i < num_resource_id; i++) {
415de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		enum ps3_spu_resource_type resource_type;
416de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		unsigned int resource_id;
417de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
418de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		result = ps3_repository_read_spu_resource_id(i,
419de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			&resource_type, &resource_id);
420de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
421de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		if (result)
422de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			break;
423de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
424de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		if (resource_type == PS3_SPU_RESOURCE_TYPE_EXCLUSIVE) {
425de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			result = fn((void*)(unsigned long)resource_id);
426de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
427de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			if (result)
428de91a53429952875740692d1de36ae70d4cf81daGeoff Levand				break;
429de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		}
430de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	}
431de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
432bce9451310eb66fbbd77bf22e8160079700691f8Geert Uytterhoeven	if (result) {
433de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		printk(KERN_WARNING "%s:%d: Error initializing spus\n",
434de91a53429952875740692d1de36ae70d4cf81daGeoff Levand			__func__, __LINE__);
435bce9451310eb66fbbd77bf22e8160079700691f8Geert Uytterhoeven		return result;
436bce9451310eb66fbbd77bf22e8160079700691f8Geert Uytterhoeven	}
437de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
438bce9451310eb66fbbd77bf22e8160079700691f8Geert Uytterhoeven	return num_resource_id;
439de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
440de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
441f5996449e3244524cab0ba709a4bd87047a8175fAndre Detschstatic int ps3_init_affinity(void)
442f5996449e3244524cab0ba709a4bd87047a8175fAndre Detsch{
443f5996449e3244524cab0ba709a4bd87047a8175fAndre Detsch	return 0;
444f5996449e3244524cab0ba709a4bd87047a8175fAndre Detsch}
445f5996449e3244524cab0ba709a4bd87047a8175fAndre Detsch
446c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi/**
447c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * ps3_enable_spu - Enable SPU run control.
448c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi *
449c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * An outstanding enhancement for the PS3 would be to add a guard to check
450c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * for incorrect access to the spu problem state when the spu context is
451c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * disabled.  This check could be implemented with a flag added to the spu
452c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * context that would inhibit mapping problem state pages, and a routine
453c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * to unmap spu problem state pages.  When the spu is enabled with
454c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * ps3_enable_spu() the flag would be set allowing pages to be mapped,
455c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * and when the spu is disabled with ps3_disable_spu() the flag would be
456c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi * cleared and the mapped problem state pages would be unmapped.
457c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi */
458c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi
459c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchistatic void ps3_enable_spu(struct spu_context *ctx)
460c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi{
461c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi}
462c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi
463c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchistatic void ps3_disable_spu(struct spu_context *ctx)
464c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi{
465c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi	ctx->ops->runcntl_stop(ctx);
466c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi}
467c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi
468de91a53429952875740692d1de36ae70d4cf81daGeoff Levandconst struct spu_management_ops spu_management_ps3_ops = {
469de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.enumerate_spus = ps3_enumerate_spus,
470de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.create_spu = ps3_create_spu,
471de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.destroy_spu = ps3_destroy_spu,
472c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi	.enable_spu = ps3_enable_spu,
473c25620d7663fef41c373d42c4923c1d6b9847684Masato Noguchi	.disable_spu = ps3_disable_spu,
474f5996449e3244524cab0ba709a4bd87047a8175fAndre Detsch	.init_affinity = ps3_init_affinity,
475de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
476de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
477de91a53429952875740692d1de36ae70d4cf81daGeoff Levand/* spu_priv1_ops */
478de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
479de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void int_mask_and(struct spu *spu, int class, u64 mask)
480de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
481de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 old_mask;
482de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
483de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* are these serialized by caller??? */
484de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	old_mask = spu_int_mask_get(spu, class);
485de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_int_mask_set(spu, class, old_mask & mask);
486de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
487de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
488de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void int_mask_or(struct spu *spu, int class, u64 mask)
489de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
490de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 old_mask;
491de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
492de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	old_mask = spu_int_mask_get(spu, class);
493de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_int_mask_set(spu, class, old_mask | mask);
494de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
495de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
496de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void int_mask_set(struct spu *spu, int class, u64 mask)
497de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
498de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_pdata(spu)->cache.masks[class] = mask;
499de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_set_spe_interrupt_mask(spu_pdata(spu)->spe_id, class,
500de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->cache.masks[class]);
501de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
502de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
503de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 int_mask_get(struct spu *spu, int class)
504de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
505de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return spu_pdata(spu)->cache.masks[class];
506de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
507de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
508de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void int_stat_clear(struct spu *spu, int class, u64 stat)
509de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
510de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Note that MFC_DSISR will be cleared when class1[MF] is set. */
511de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
512de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_clear_spe_interrupt_status(spu_pdata(spu)->spe_id, class,
513de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		stat, 0);
514de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
515de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
516de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 int_stat_get(struct spu *spu, int class)
517de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
518de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	u64 stat;
519de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
520de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_get_spe_interrupt_status(spu_pdata(spu)->spe_id, class, &stat);
521de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return stat;
522de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
523de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
524de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void cpu_affinity_set(struct spu *spu, int cpu)
525de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
526de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* No support. */
527de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
528de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
529de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 mfc_dar_get(struct spu *spu)
530de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
531de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return in_be64(&spu_pdata(spu)->shadow->mfc_dar_RW);
532de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
533de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
534de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void mfc_dsisr_set(struct spu *spu, u64 dsisr)
535de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
536de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Nothing to do, cleared in int_stat_clear(). */
537de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
538de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
539de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 mfc_dsisr_get(struct spu *spu)
540de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
541de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return in_be64(&spu_pdata(spu)->shadow->mfc_dsisr_RW);
542de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
543de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
544de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void mfc_sdr_setup(struct spu *spu)
545de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
546de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Nothing to do. */
547de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
548de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
549de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void mfc_sr1_set(struct spu *spu, u64 sr1)
550de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
551de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Check bits allowed by HV. */
552de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
553de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	static const u64 allowed = ~(MFC_STATE1_LOCAL_STORAGE_DECODE_MASK
554de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		| MFC_STATE1_PROBLEM_STATE_MASK);
555de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
556de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	BUG_ON((sr1 & allowed) != (spu_pdata(spu)->cache.sr1 & allowed));
557de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
558de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_pdata(spu)->cache.sr1 = sr1;
559de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_set_spe_privilege_state_area_1_register(
560de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->spe_id,
561de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		offsetof(struct spu_priv1, mfc_sr1_RW),
562de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->cache.sr1);
563de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
564de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
565de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 mfc_sr1_get(struct spu *spu)
566de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
567de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return spu_pdata(spu)->cache.sr1;
568de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
569de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
570de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
571de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
572de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_pdata(spu)->cache.tclass_id = tclass_id;
573de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	lv1_set_spe_privilege_state_area_1_register(
574de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->spe_id,
575de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		offsetof(struct spu_priv1, mfc_tclass_id_RW),
576de91a53429952875740692d1de36ae70d4cf81daGeoff Levand		spu_pdata(spu)->cache.tclass_id);
577de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
578de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
579de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 mfc_tclass_id_get(struct spu *spu)
580de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
581de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return spu_pdata(spu)->cache.tclass_id;
582de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
583de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
584de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void tlb_invalidate(struct spu *spu)
585de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
586de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* Nothing to do. */
587de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
588de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
589de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void resource_allocation_groupID_set(struct spu *spu, u64 id)
590de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
591de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* No support. */
592de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
593de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
594de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 resource_allocation_groupID_get(struct spu *spu)
595de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
596de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return 0; /* No support. */
597de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
598de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
599de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic void resource_allocation_enable_set(struct spu *spu, u64 enable)
600de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
601de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	/* No support. */
602de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
603de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
604de91a53429952875740692d1de36ae70d4cf81daGeoff Levandstatic u64 resource_allocation_enable_get(struct spu *spu)
605de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
606de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	return 0; /* No support. */
607de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
608de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
609de91a53429952875740692d1de36ae70d4cf81daGeoff Levandconst struct spu_priv1_ops spu_priv1_ps3_ops = {
610de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_mask_and = int_mask_and,
611de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_mask_or = int_mask_or,
612de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_mask_set = int_mask_set,
613de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_mask_get = int_mask_get,
614de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_stat_clear = int_stat_clear,
615de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.int_stat_get = int_stat_get,
616de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.cpu_affinity_set = cpu_affinity_set,
617de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_dar_get = mfc_dar_get,
618de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_dsisr_set = mfc_dsisr_set,
619de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_dsisr_get = mfc_dsisr_get,
620de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_sdr_setup = mfc_sdr_setup,
621de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_sr1_set = mfc_sr1_set,
622de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_sr1_get = mfc_sr1_get,
623de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_tclass_id_set = mfc_tclass_id_set,
624de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.mfc_tclass_id_get = mfc_tclass_id_get,
625de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.tlb_invalidate = tlb_invalidate,
626de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.resource_allocation_groupID_set = resource_allocation_groupID_set,
627de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.resource_allocation_groupID_get = resource_allocation_groupID_get,
628de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.resource_allocation_enable_set = resource_allocation_enable_set,
629de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	.resource_allocation_enable_get = resource_allocation_enable_get,
630de91a53429952875740692d1de36ae70d4cf81daGeoff Levand};
631de91a53429952875740692d1de36ae70d4cf81daGeoff Levand
632de91a53429952875740692d1de36ae70d4cf81daGeoff Levandvoid ps3_spu_set_platform(void)
633de91a53429952875740692d1de36ae70d4cf81daGeoff Levand{
634de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_priv1_ops = &spu_priv1_ps3_ops;
635de91a53429952875740692d1de36ae70d4cf81daGeoff Levand	spu_management_ops = &spu_management_ps3_ops;
636de91a53429952875740692d1de36ae70d4cf81daGeoff Levand}
637