diff options
author | Geoff Levand <geoffrey.levand@am.sony.com> | 2007-06-15 17:52:02 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-06-28 05:16:38 -0400 |
commit | 6bb5cf1025414fe00b20f3bef56135849e4ed3b8 (patch) | |
tree | d8cc37288ce123dc790af37f99b7bcc7c9e1872d /arch/powerpc/platforms/ps3/system-bus.c | |
parent | 9263e85aa9e9d341ef238fffc040f586674d1709 (diff) |
[POWERPC] PS3: System-bus rework
Rework the PS3 system bus to unify device support.
- DMA region sizes must be a power of two
- storage bus DMA updates:
- Small fixes for the PS3 DMA core:
o fix alignment bug
o kill superfluous test
o indentation
o spelling
o export ps3_dma_region_{create,free}()
- ps3_dma_region_init():
o Add `addr' and `len' parameters, so you can create a DMA region that
does not cover all memory (use `NULL' and `0' to cover all memory).
This is needed because there are not sufficient IOMMU resources to have
all DMA regions cover all memory.
o Uninline
- Added remove and shutdown routines to all drivers.
- Added loadable module support to all drivers.
- Added HV calls for iopte management (needed by sound driver).
Signed-off-by: MOKUNO Masakazu <mokuno@sm.sony.co.jp>
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/ps3/system-bus.c')
-rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 533 |
1 files changed, 452 insertions, 81 deletions
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6bda51027cc6..14bbaff93e57 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -30,22 +30,228 @@ | |||
30 | 30 | ||
31 | #include "platform.h" | 31 | #include "platform.h" |
32 | 32 | ||
33 | static struct device ps3_system_bus = { | ||
34 | .bus_id = "ps3_system", | ||
35 | }; | ||
36 | |||
37 | /* FIXME: need device usage counters! */ | ||
38 | struct { | ||
39 | struct mutex mutex; | ||
40 | int sb_11; /* usb 0 */ | ||
41 | int sb_12; /* usb 0 */ | ||
42 | int gpu; | ||
43 | } static usage_hack; | ||
44 | |||
45 | static int ps3_is_device(struct ps3_system_bus_device *dev, | ||
46 | unsigned int bus_id, unsigned int dev_id) | ||
47 | { | ||
48 | return dev->bus_id == bus_id && dev->dev_id == dev_id; | ||
49 | } | ||
50 | |||
51 | static int ps3_open_hv_device_sb(struct ps3_system_bus_device *dev) | ||
52 | { | ||
53 | int result; | ||
54 | |||
55 | BUG_ON(!dev->bus_id); | ||
56 | mutex_lock(&usage_hack.mutex); | ||
57 | |||
58 | if (ps3_is_device(dev, 1, 1)) { | ||
59 | usage_hack.sb_11++; | ||
60 | if (usage_hack.sb_11 > 1) { | ||
61 | result = 0; | ||
62 | goto done; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | if (ps3_is_device(dev, 1, 2)) { | ||
67 | usage_hack.sb_12++; | ||
68 | if (usage_hack.sb_12 > 1) { | ||
69 | result = 0; | ||
70 | goto done; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | result = lv1_open_device(dev->bus_id, dev->dev_id, 0); | ||
75 | |||
76 | if (result) { | ||
77 | pr_debug("%s:%d: lv1_open_device failed: %s\n", __func__, | ||
78 | __LINE__, ps3_result(result)); | ||
79 | result = -EPERM; | ||
80 | } | ||
81 | |||
82 | done: | ||
83 | mutex_unlock(&usage_hack.mutex); | ||
84 | return result; | ||
85 | } | ||
86 | |||
87 | static int ps3_close_hv_device_sb(struct ps3_system_bus_device *dev) | ||
88 | { | ||
89 | int result; | ||
90 | |||
91 | BUG_ON(!dev->bus_id); | ||
92 | mutex_lock(&usage_hack.mutex); | ||
93 | |||
94 | if (ps3_is_device(dev, 1, 1)) { | ||
95 | usage_hack.sb_11--; | ||
96 | if (usage_hack.sb_11) { | ||
97 | result = 0; | ||
98 | goto done; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | if (ps3_is_device(dev, 1, 2)) { | ||
103 | usage_hack.sb_12--; | ||
104 | if (usage_hack.sb_12) { | ||
105 | result = 0; | ||
106 | goto done; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | result = lv1_close_device(dev->bus_id, dev->dev_id); | ||
111 | BUG_ON(result); | ||
112 | |||
113 | done: | ||
114 | mutex_unlock(&usage_hack.mutex); | ||
115 | return result; | ||
116 | } | ||
117 | |||
118 | static int ps3_open_hv_device_gpu(struct ps3_system_bus_device *dev) | ||
119 | { | ||
120 | int result; | ||
121 | |||
122 | mutex_lock(&usage_hack.mutex); | ||
123 | |||
124 | usage_hack.gpu++; | ||
125 | if (usage_hack.gpu > 1) { | ||
126 | result = 0; | ||
127 | goto done; | ||
128 | } | ||
129 | |||
130 | result = lv1_gpu_open(0); | ||
131 | |||
132 | if (result) { | ||
133 | pr_debug("%s:%d: lv1_gpu_open failed: %s\n", __func__, | ||
134 | __LINE__, ps3_result(result)); | ||
135 | result = -EPERM; | ||
136 | } | ||
137 | |||
138 | done: | ||
139 | mutex_unlock(&usage_hack.mutex); | ||
140 | return result; | ||
141 | } | ||
142 | |||
143 | static int ps3_close_hv_device_gpu(struct ps3_system_bus_device *dev) | ||
144 | { | ||
145 | int result; | ||
146 | |||
147 | mutex_lock(&usage_hack.mutex); | ||
148 | |||
149 | usage_hack.gpu--; | ||
150 | if (usage_hack.gpu) { | ||
151 | result = 0; | ||
152 | goto done; | ||
153 | } | ||
154 | |||
155 | result = lv1_gpu_close(); | ||
156 | BUG_ON(result); | ||
157 | |||
158 | done: | ||
159 | mutex_unlock(&usage_hack.mutex); | ||
160 | return result; | ||
161 | } | ||
162 | |||
163 | int ps3_open_hv_device(struct ps3_system_bus_device *dev) | ||
164 | { | ||
165 | BUG_ON(!dev); | ||
166 | pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); | ||
167 | |||
168 | switch (dev->match_id) { | ||
169 | case PS3_MATCH_ID_EHCI: | ||
170 | case PS3_MATCH_ID_OHCI: | ||
171 | case PS3_MATCH_ID_GELIC: | ||
172 | case PS3_MATCH_ID_STOR_DISK: | ||
173 | case PS3_MATCH_ID_STOR_ROM: | ||
174 | case PS3_MATCH_ID_STOR_FLASH: | ||
175 | return ps3_open_hv_device_sb(dev); | ||
176 | |||
177 | case PS3_MATCH_ID_SOUND: | ||
178 | case PS3_MATCH_ID_GRAPHICS: | ||
179 | return ps3_open_hv_device_gpu(dev); | ||
180 | |||
181 | case PS3_MATCH_ID_AV_SETTINGS: | ||
182 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
183 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | ||
184 | __LINE__, dev->match_id); | ||
185 | pr_debug("%s:%d: bus_id: %u\n", __func__, | ||
186 | __LINE__, dev->bus_id); | ||
187 | BUG(); | ||
188 | return -EINVAL; | ||
189 | |||
190 | default: | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, | ||
195 | dev->match_id); | ||
196 | BUG(); | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | EXPORT_SYMBOL_GPL(ps3_open_hv_device); | ||
200 | |||
201 | int ps3_close_hv_device(struct ps3_system_bus_device *dev) | ||
202 | { | ||
203 | BUG_ON(!dev); | ||
204 | pr_debug("%s:%d: match_id: %u\n", __func__, __LINE__, dev->match_id); | ||
205 | |||
206 | switch (dev->match_id) { | ||
207 | case PS3_MATCH_ID_EHCI: | ||
208 | case PS3_MATCH_ID_OHCI: | ||
209 | case PS3_MATCH_ID_GELIC: | ||
210 | case PS3_MATCH_ID_STOR_DISK: | ||
211 | case PS3_MATCH_ID_STOR_ROM: | ||
212 | case PS3_MATCH_ID_STOR_FLASH: | ||
213 | return ps3_close_hv_device_sb(dev); | ||
214 | |||
215 | case PS3_MATCH_ID_SOUND: | ||
216 | case PS3_MATCH_ID_GRAPHICS: | ||
217 | return ps3_close_hv_device_gpu(dev); | ||
218 | |||
219 | case PS3_MATCH_ID_AV_SETTINGS: | ||
220 | case PS3_MATCH_ID_SYSTEM_MANAGER: | ||
221 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | ||
222 | __LINE__, dev->match_id); | ||
223 | pr_debug("%s:%d: bus_id: %u\n", __func__, | ||
224 | __LINE__, dev->bus_id); | ||
225 | BUG(); | ||
226 | return -EINVAL; | ||
227 | |||
228 | default: | ||
229 | break; | ||
230 | } | ||
231 | |||
232 | pr_debug("%s:%d: unknown match_id: %u\n", __func__, __LINE__, | ||
233 | dev->match_id); | ||
234 | BUG(); | ||
235 | return -ENODEV; | ||
236 | } | ||
237 | EXPORT_SYMBOL_GPL(ps3_close_hv_device); | ||
238 | |||
33 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) | 239 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) |
34 | static void _dump_mmio_region(const struct ps3_mmio_region* r, | 240 | static void _dump_mmio_region(const struct ps3_mmio_region* r, |
35 | const char* func, int line) | 241 | const char* func, int line) |
36 | { | 242 | { |
37 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | 243 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, |
38 | r->did.dev_id); | 244 | r->dev->dev_id); |
39 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 245 | 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); | 246 | 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); | 247 | pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); |
42 | } | 248 | } |
43 | 249 | ||
44 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | 250 | static int ps3_sb_mmio_region_create(struct ps3_mmio_region *r) |
45 | { | 251 | { |
46 | int result; | 252 | int result; |
47 | 253 | ||
48 | result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, | 254 | result = lv1_map_device_mmio_region(r->dev->bus_id, r->dev->dev_id, |
49 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); | 255 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); |
50 | 256 | ||
51 | if (result) { | 257 | if (result) { |
@@ -57,13 +263,26 @@ int ps3_mmio_region_create(struct ps3_mmio_region *r) | |||
57 | dump_mmio_region(r); | 263 | dump_mmio_region(r); |
58 | return result; | 264 | return result; |
59 | } | 265 | } |
266 | |||
267 | static int ps3_ioc0_mmio_region_create(struct ps3_mmio_region *r) | ||
268 | { | ||
269 | /* device specific; do nothing currently */ | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | ||
274 | { | ||
275 | return r->mmio_ops->create(r); | ||
276 | } | ||
60 | EXPORT_SYMBOL_GPL(ps3_mmio_region_create); | 277 | EXPORT_SYMBOL_GPL(ps3_mmio_region_create); |
61 | 278 | ||
62 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | 279 | static int ps3_sb_free_mmio_region(struct ps3_mmio_region *r) |
63 | { | 280 | { |
64 | int result; | 281 | int result; |
65 | 282 | ||
66 | result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, | 283 | dump_mmio_region(r); |
284 | ; | ||
285 | result = lv1_unmap_device_mmio_region(r->dev->bus_id, r->dev->dev_id, | ||
67 | r->lpar_addr); | 286 | r->lpar_addr); |
68 | 287 | ||
69 | if (result) | 288 | if (result) |
@@ -73,14 +292,60 @@ int ps3_free_mmio_region(struct ps3_mmio_region *r) | |||
73 | r->lpar_addr = 0; | 292 | r->lpar_addr = 0; |
74 | return result; | 293 | return result; |
75 | } | 294 | } |
295 | |||
296 | static int ps3_ioc0_free_mmio_region(struct ps3_mmio_region *r) | ||
297 | { | ||
298 | /* device specific; do nothing currently */ | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | |||
303 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | ||
304 | { | ||
305 | return r->mmio_ops->free(r); | ||
306 | } | ||
307 | |||
76 | EXPORT_SYMBOL_GPL(ps3_free_mmio_region); | 308 | EXPORT_SYMBOL_GPL(ps3_free_mmio_region); |
77 | 309 | ||
310 | static const struct ps3_mmio_region_ops ps3_mmio_sb_region_ops = { | ||
311 | .create = ps3_sb_mmio_region_create, | ||
312 | .free = ps3_sb_free_mmio_region | ||
313 | }; | ||
314 | |||
315 | static const struct ps3_mmio_region_ops ps3_mmio_ioc0_region_ops = { | ||
316 | .create = ps3_ioc0_mmio_region_create, | ||
317 | .free = ps3_ioc0_free_mmio_region | ||
318 | }; | ||
319 | |||
320 | int ps3_mmio_region_init(struct ps3_system_bus_device *dev, | ||
321 | struct ps3_mmio_region *r, unsigned long bus_addr, unsigned long len, | ||
322 | enum ps3_mmio_page_size page_size) | ||
323 | { | ||
324 | r->dev = dev; | ||
325 | r->bus_addr = bus_addr; | ||
326 | r->len = len; | ||
327 | r->page_size = page_size; | ||
328 | switch (dev->dev_type) { | ||
329 | case PS3_DEVICE_TYPE_SB: | ||
330 | r->mmio_ops = &ps3_mmio_sb_region_ops; | ||
331 | break; | ||
332 | case PS3_DEVICE_TYPE_IOC0: | ||
333 | r->mmio_ops = &ps3_mmio_ioc0_region_ops; | ||
334 | break; | ||
335 | default: | ||
336 | BUG(); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | return 0; | ||
340 | } | ||
341 | EXPORT_SYMBOL_GPL(ps3_mmio_region_init); | ||
342 | |||
78 | static int ps3_system_bus_match(struct device *_dev, | 343 | static int ps3_system_bus_match(struct device *_dev, |
79 | struct device_driver *_drv) | 344 | struct device_driver *_drv) |
80 | { | 345 | { |
81 | int result; | 346 | int result; |
82 | struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); | 347 | struct ps3_system_bus_driver *drv = ps3_drv_to_system_bus_drv(_drv); |
83 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 348 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
84 | 349 | ||
85 | result = dev->match_id == drv->match_id; | 350 | result = dev->match_id == drv->match_id; |
86 | 351 | ||
@@ -92,32 +357,14 @@ static int ps3_system_bus_match(struct device *_dev, | |||
92 | 357 | ||
93 | static int ps3_system_bus_probe(struct device *_dev) | 358 | static int ps3_system_bus_probe(struct device *_dev) |
94 | { | 359 | { |
95 | int result; | 360 | int result = 0; |
96 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 361 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
97 | struct ps3_system_bus_driver *drv = | 362 | struct ps3_system_bus_driver *drv; |
98 | to_ps3_system_bus_driver(_dev->driver); | ||
99 | |||
100 | result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); | ||
101 | 363 | ||
102 | if (result) { | 364 | BUG_ON(!dev); |
103 | pr_debug("%s:%d: lv1_open_device failed (%d)\n", | 365 | pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); |
104 | __func__, __LINE__, result); | ||
105 | result = -EACCES; | ||
106 | goto clean_none; | ||
107 | } | ||
108 | |||
109 | if (dev->d_region->did.bus_id) { | ||
110 | result = ps3_dma_region_create(dev->d_region); | ||
111 | |||
112 | if (result) { | ||
113 | pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", | ||
114 | __func__, __LINE__, result); | ||
115 | BUG_ON("check region type"); | ||
116 | result = -EINVAL; | ||
117 | goto clean_device; | ||
118 | } | ||
119 | } | ||
120 | 366 | ||
367 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
121 | BUG_ON(!drv); | 368 | BUG_ON(!drv); |
122 | 369 | ||
123 | if (drv->probe) | 370 | if (drv->probe) |
@@ -126,38 +373,68 @@ static int ps3_system_bus_probe(struct device *_dev) | |||
126 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, | 373 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, |
127 | dev->core.bus_id); | 374 | dev->core.bus_id); |
128 | 375 | ||
129 | if (result) { | 376 | pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); |
130 | pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); | ||
131 | goto clean_dma; | ||
132 | } | ||
133 | |||
134 | return result; | ||
135 | |||
136 | clean_dma: | ||
137 | ps3_dma_region_free(dev->d_region); | ||
138 | clean_device: | ||
139 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
140 | clean_none: | ||
141 | return result; | 377 | return result; |
142 | } | 378 | } |
143 | 379 | ||
144 | static int ps3_system_bus_remove(struct device *_dev) | 380 | static int ps3_system_bus_remove(struct device *_dev) |
145 | { | 381 | { |
146 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 382 | int result = 0; |
147 | struct ps3_system_bus_driver *drv = | 383 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
148 | to_ps3_system_bus_driver(_dev->driver); | 384 | struct ps3_system_bus_driver *drv; |
385 | |||
386 | BUG_ON(!dev); | ||
387 | pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); | ||
388 | |||
389 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
390 | BUG_ON(!drv); | ||
149 | 391 | ||
150 | if (drv->remove) | 392 | if (drv->remove) |
151 | drv->remove(dev); | 393 | result = drv->remove(dev); |
152 | else | 394 | else |
153 | pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, | 395 | dev_dbg(&dev->core, "%s:%d %s: no remove method\n", |
154 | dev->core.bus_id); | 396 | __func__, __LINE__, drv->core.name); |
397 | |||
398 | pr_info(" <- %s:%d: %s\n", __func__, __LINE__, dev->core.bus_id); | ||
399 | return result; | ||
400 | } | ||
155 | 401 | ||
156 | ps3_dma_region_free(dev->d_region); | 402 | static void ps3_system_bus_shutdown(struct device *_dev) |
157 | ps3_free_mmio_region(dev->m_region); | 403 | { |
158 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | 404 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
405 | struct ps3_system_bus_driver *drv; | ||
159 | 406 | ||
160 | return 0; | 407 | BUG_ON(!dev); |
408 | |||
409 | dev_dbg(&dev->core, " -> %s:%d: match_id %d\n", __func__, __LINE__, | ||
410 | dev->match_id); | ||
411 | |||
412 | if (!dev->core.driver) { | ||
413 | dev_dbg(&dev->core, "%s:%d: no driver bound\n", __func__, | ||
414 | __LINE__); | ||
415 | return; | ||
416 | } | ||
417 | |||
418 | drv = ps3_system_bus_dev_to_system_bus_drv(dev); | ||
419 | |||
420 | BUG_ON(!drv); | ||
421 | |||
422 | dev_dbg(&dev->core, "%s:%d: %s -> %s\n", __func__, __LINE__, | ||
423 | dev->core.bus_id, drv->core.name); | ||
424 | |||
425 | if (drv->shutdown) | ||
426 | drv->shutdown(dev); | ||
427 | else if (drv->remove) { | ||
428 | dev_dbg(&dev->core, "%s:%d %s: no shutdown, calling remove\n", | ||
429 | __func__, __LINE__, drv->core.name); | ||
430 | drv->remove(dev); | ||
431 | } else { | ||
432 | dev_dbg(&dev->core, "%s:%d %s: no shutdown method\n", | ||
433 | __func__, __LINE__, drv->core.name); | ||
434 | BUG(); | ||
435 | } | ||
436 | |||
437 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | ||
161 | } | 438 | } |
162 | 439 | ||
163 | struct bus_type ps3_system_bus_type = { | 440 | struct bus_type ps3_system_bus_type = { |
@@ -165,17 +442,27 @@ struct bus_type ps3_system_bus_type = { | |||
165 | .match = ps3_system_bus_match, | 442 | .match = ps3_system_bus_match, |
166 | .probe = ps3_system_bus_probe, | 443 | .probe = ps3_system_bus_probe, |
167 | .remove = ps3_system_bus_remove, | 444 | .remove = ps3_system_bus_remove, |
445 | .shutdown = ps3_system_bus_shutdown, | ||
168 | }; | 446 | }; |
169 | 447 | ||
170 | int __init ps3_system_bus_init(void) | 448 | static int __init ps3_system_bus_init(void) |
171 | { | 449 | { |
172 | int result; | 450 | int result; |
173 | 451 | ||
174 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 452 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
175 | return -ENODEV; | 453 | return -ENODEV; |
176 | 454 | ||
455 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
456 | |||
457 | mutex_init(&usage_hack.mutex); | ||
458 | |||
459 | result = device_register(&ps3_system_bus); | ||
460 | BUG_ON(result); | ||
461 | |||
177 | result = bus_register(&ps3_system_bus_type); | 462 | result = bus_register(&ps3_system_bus_type); |
178 | BUG_ON(result); | 463 | BUG_ON(result); |
464 | |||
465 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
179 | return result; | 466 | return result; |
180 | } | 467 | } |
181 | 468 | ||
@@ -185,16 +472,13 @@ core_initcall(ps3_system_bus_init); | |||
185 | * Returns the virtual address of the buffer and sets dma_handle | 472 | * Returns the virtual address of the buffer and sets dma_handle |
186 | * to the dma address (mapping) of the first page. | 473 | * to the dma address (mapping) of the first page. |
187 | */ | 474 | */ |
188 | |||
189 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, | 475 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, |
190 | dma_addr_t *dma_handle, gfp_t flag) | 476 | dma_addr_t *dma_handle, gfp_t flag) |
191 | { | 477 | { |
192 | int result; | 478 | int result; |
193 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 479 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
194 | unsigned long virt_addr; | 480 | unsigned long virt_addr; |
195 | 481 | ||
196 | BUG_ON(!dev->d_region->bus_addr); | ||
197 | |||
198 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); | 482 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); |
199 | flag |= __GFP_ZERO; | 483 | flag |= __GFP_ZERO; |
200 | 484 | ||
@@ -205,7 +489,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, | |||
205 | goto clean_none; | 489 | goto clean_none; |
206 | } | 490 | } |
207 | 491 | ||
208 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); | 492 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, |
493 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); | ||
209 | 494 | ||
210 | if (result) { | 495 | if (result) { |
211 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 496 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -226,7 +511,7 @@ clean_none: | |||
226 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | 511 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, |
227 | dma_addr_t dma_handle) | 512 | dma_addr_t dma_handle) |
228 | { | 513 | { |
229 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 514 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
230 | 515 | ||
231 | ps3_dma_unmap(dev->d_region, dma_handle, size); | 516 | ps3_dma_unmap(dev->d_region, dma_handle, size); |
232 | free_pages((unsigned long)vaddr, get_order(size)); | 517 | free_pages((unsigned long)vaddr, get_order(size)); |
@@ -239,15 +524,16 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | |||
239 | * byte within the page as vaddr. | 524 | * byte within the page as vaddr. |
240 | */ | 525 | */ |
241 | 526 | ||
242 | static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | 527 | static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, |
243 | enum dma_data_direction direction) | 528 | enum dma_data_direction direction) |
244 | { | 529 | { |
245 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 530 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
246 | int result; | 531 | int result; |
247 | unsigned long bus_addr; | 532 | unsigned long bus_addr; |
248 | 533 | ||
249 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | 534 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, |
250 | &bus_addr); | 535 | &bus_addr, |
536 | IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); | ||
251 | 537 | ||
252 | if (result) { | 538 | if (result) { |
253 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 539 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -257,10 +543,44 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | |||
257 | return bus_addr; | 543 | return bus_addr; |
258 | } | 544 | } |
259 | 545 | ||
546 | static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, | ||
547 | size_t size, | ||
548 | enum dma_data_direction direction) | ||
549 | { | ||
550 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
551 | int result; | ||
552 | unsigned long bus_addr; | ||
553 | u64 iopte_flag; | ||
554 | |||
555 | iopte_flag = IOPTE_M; | ||
556 | switch (direction) { | ||
557 | case DMA_BIDIRECTIONAL: | ||
558 | iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; | ||
559 | break; | ||
560 | case DMA_TO_DEVICE: | ||
561 | iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; | ||
562 | break; | ||
563 | case DMA_FROM_DEVICE: | ||
564 | iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; | ||
565 | break; | ||
566 | default: | ||
567 | /* not happned */ | ||
568 | BUG(); | ||
569 | }; | ||
570 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | ||
571 | &bus_addr, iopte_flag); | ||
572 | |||
573 | if (result) { | ||
574 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
575 | __func__, __LINE__, result); | ||
576 | } | ||
577 | return bus_addr; | ||
578 | } | ||
579 | |||
260 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | 580 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, |
261 | size_t size, enum dma_data_direction direction) | 581 | size_t size, enum dma_data_direction direction) |
262 | { | 582 | { |
263 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 583 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
264 | int result; | 584 | int result; |
265 | 585 | ||
266 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); | 586 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); |
@@ -271,20 +591,20 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | |||
271 | } | 591 | } |
272 | } | 592 | } |
273 | 593 | ||
274 | static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | 594 | static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents, |
275 | enum dma_data_direction direction) | 595 | enum dma_data_direction direction) |
276 | { | 596 | { |
277 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 597 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
278 | BUG_ON("do"); | 598 | BUG_ON("do"); |
279 | return -EPERM; | 599 | return -EPERM; |
280 | #else | 600 | #else |
281 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 601 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
282 | int i; | 602 | int i; |
283 | 603 | ||
284 | for (i = 0; i < nents; i++, sg++) { | 604 | for (i = 0; i < nents; i++, sg++) { |
285 | int result = ps3_dma_map(dev->d_region, | 605 | int result = ps3_dma_map(dev->d_region, |
286 | page_to_phys(sg->page) + sg->offset, sg->length, | 606 | page_to_phys(sg->page) + sg->offset, sg->length, |
287 | &sg->dma_address); | 607 | &sg->dma_address, 0); |
288 | 608 | ||
289 | if (result) { | 609 | if (result) { |
290 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 610 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -299,7 +619,15 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | |||
299 | #endif | 619 | #endif |
300 | } | 620 | } |
301 | 621 | ||
302 | static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | 622 | static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, |
623 | int nents, | ||
624 | enum dma_data_direction direction) | ||
625 | { | ||
626 | BUG(); | ||
627 | return 0; | ||
628 | } | ||
629 | |||
630 | static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
303 | int nents, enum dma_data_direction direction) | 631 | int nents, enum dma_data_direction direction) |
304 | { | 632 | { |
305 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 633 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
@@ -307,18 +635,34 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | |||
307 | #endif | 635 | #endif |
308 | } | 636 | } |
309 | 637 | ||
638 | static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
639 | int nents, enum dma_data_direction direction) | ||
640 | { | ||
641 | BUG(); | ||
642 | } | ||
643 | |||
310 | static int ps3_dma_supported(struct device *_dev, u64 mask) | 644 | static int ps3_dma_supported(struct device *_dev, u64 mask) |
311 | { | 645 | { |
312 | return mask >= DMA_32BIT_MASK; | 646 | return mask >= DMA_32BIT_MASK; |
313 | } | 647 | } |
314 | 648 | ||
315 | static struct dma_mapping_ops ps3_dma_ops = { | 649 | static struct dma_mapping_ops ps3_sb_dma_ops = { |
650 | .alloc_coherent = ps3_alloc_coherent, | ||
651 | .free_coherent = ps3_free_coherent, | ||
652 | .map_single = ps3_sb_map_single, | ||
653 | .unmap_single = ps3_unmap_single, | ||
654 | .map_sg = ps3_sb_map_sg, | ||
655 | .unmap_sg = ps3_sb_unmap_sg, | ||
656 | .dma_supported = ps3_dma_supported | ||
657 | }; | ||
658 | |||
659 | static struct dma_mapping_ops ps3_ioc0_dma_ops = { | ||
316 | .alloc_coherent = ps3_alloc_coherent, | 660 | .alloc_coherent = ps3_alloc_coherent, |
317 | .free_coherent = ps3_free_coherent, | 661 | .free_coherent = ps3_free_coherent, |
318 | .map_single = ps3_map_single, | 662 | .map_single = ps3_ioc0_map_single, |
319 | .unmap_single = ps3_unmap_single, | 663 | .unmap_single = ps3_unmap_single, |
320 | .map_sg = ps3_map_sg, | 664 | .map_sg = ps3_ioc0_map_sg, |
321 | .unmap_sg = ps3_unmap_sg, | 665 | .unmap_sg = ps3_ioc0_unmap_sg, |
322 | .dma_supported = ps3_dma_supported | 666 | .dma_supported = ps3_dma_supported |
323 | }; | 667 | }; |
324 | 668 | ||
@@ -328,7 +672,7 @@ static struct dma_mapping_ops ps3_dma_ops = { | |||
328 | 672 | ||
329 | static void ps3_system_bus_release_device(struct device *_dev) | 673 | static void ps3_system_bus_release_device(struct device *_dev) |
330 | { | 674 | { |
331 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 675 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
332 | kfree(dev); | 676 | kfree(dev); |
333 | } | 677 | } |
334 | 678 | ||
@@ -343,19 +687,38 @@ static void ps3_system_bus_release_device(struct device *_dev) | |||
343 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | 687 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) |
344 | { | 688 | { |
345 | int result; | 689 | int result; |
346 | static unsigned int dev_count = 1; | 690 | static unsigned int dev_ioc0_count; |
691 | static unsigned int dev_sb_count; | ||
692 | static unsigned int dev_vuart_count; | ||
347 | 693 | ||
348 | dev->core.parent = NULL; | 694 | if (!dev->core.parent) |
695 | dev->core.parent = &ps3_system_bus; | ||
349 | dev->core.bus = &ps3_system_bus_type; | 696 | dev->core.bus = &ps3_system_bus_type; |
350 | dev->core.release = ps3_system_bus_release_device; | 697 | dev->core.release = ps3_system_bus_release_device; |
351 | 698 | ||
699 | switch (dev->dev_type) { | ||
700 | case PS3_DEVICE_TYPE_IOC0: | ||
701 | dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops; | ||
702 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
703 | "ioc0_%02x", ++dev_ioc0_count); | ||
704 | break; | ||
705 | case PS3_DEVICE_TYPE_SB: | ||
706 | dev->core.archdata.dma_ops = &ps3_sb_dma_ops; | ||
707 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
708 | "sb_%02x", ++dev_sb_count); | ||
709 | |||
710 | break; | ||
711 | case PS3_DEVICE_TYPE_VUART: | ||
712 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
713 | "vuart_%02x", ++dev_vuart_count); | ||
714 | break; | ||
715 | default: | ||
716 | BUG(); | ||
717 | }; | ||
718 | |||
352 | dev->core.archdata.of_node = NULL; | 719 | dev->core.archdata.of_node = NULL; |
353 | dev->core.archdata.dma_ops = &ps3_dma_ops; | ||
354 | dev->core.archdata.numa_node = 0; | 720 | dev->core.archdata.numa_node = 0; |
355 | 721 | ||
356 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", | ||
357 | dev_count++); | ||
358 | |||
359 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); | 722 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); |
360 | 723 | ||
361 | result = device_register(&dev->core); | 724 | result = device_register(&dev->core); |
@@ -368,9 +731,15 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) | |||
368 | { | 731 | { |
369 | int result; | 732 | int result; |
370 | 733 | ||
734 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
735 | |||
736 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
737 | return -ENODEV; | ||
738 | |||
371 | drv->core.bus = &ps3_system_bus_type; | 739 | drv->core.bus = &ps3_system_bus_type; |
372 | 740 | ||
373 | result = driver_register(&drv->core); | 741 | result = driver_register(&drv->core); |
742 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
374 | return result; | 743 | return result; |
375 | } | 744 | } |
376 | 745 | ||
@@ -378,7 +747,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | |||
378 | 747 | ||
379 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | 748 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) |
380 | { | 749 | { |
750 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
381 | driver_unregister(&drv->core); | 751 | driver_unregister(&drv->core); |
752 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
382 | } | 753 | } |
383 | 754 | ||
384 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | 755 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); |