diff options
Diffstat (limited to 'arch/powerpc/platforms/ps3/system-bus.c')
-rw-r--r-- | arch/powerpc/platforms/ps3/system-bus.c | 562 |
1 files changed, 482 insertions, 80 deletions
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6bda51027cc6..4bb634a17e43 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 | |||
102 | if (result) { | ||
103 | pr_debug("%s:%d: lv1_open_device failed (%d)\n", | ||
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 | 363 | ||
112 | if (result) { | 364 | BUG_ON(!dev); |
113 | pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", | 365 | pr_info(" -> %s:%d: %s\n", __func__, __LINE__, _dev->bus_id); |
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,56 +373,127 @@ 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 | } | ||
401 | |||
402 | static void ps3_system_bus_shutdown(struct device *_dev) | ||
403 | { | ||
404 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
405 | struct ps3_system_bus_driver *drv; | ||
406 | |||
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__); | ||
438 | } | ||
439 | |||
440 | static int ps3_system_bus_uevent(struct device *_dev, char **envp, | ||
441 | int num_envp, char *buffer, int buffer_size) | ||
442 | { | ||
443 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
444 | int i = 0, length = 0; | ||
155 | 445 | ||
156 | ps3_dma_region_free(dev->d_region); | 446 | if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, |
157 | ps3_free_mmio_region(dev->m_region); | 447 | &length, "MODALIAS=ps3:%d", |
158 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | 448 | dev->match_id)) |
449 | return -ENOMEM; | ||
159 | 450 | ||
451 | envp[i] = NULL; | ||
160 | return 0; | 452 | return 0; |
161 | } | 453 | } |
162 | 454 | ||
455 | static ssize_t modalias_show(struct device *_dev, struct device_attribute *a, | ||
456 | char *buf) | ||
457 | { | ||
458 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
459 | int len = snprintf(buf, PAGE_SIZE, "ps3:%d\n", dev->match_id); | ||
460 | |||
461 | return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; | ||
462 | } | ||
463 | |||
464 | static struct device_attribute ps3_system_bus_dev_attrs[] = { | ||
465 | __ATTR_RO(modalias), | ||
466 | __ATTR_NULL, | ||
467 | }; | ||
468 | |||
163 | struct bus_type ps3_system_bus_type = { | 469 | struct bus_type ps3_system_bus_type = { |
164 | .name = "ps3_system_bus", | 470 | .name = "ps3_system_bus", |
165 | .match = ps3_system_bus_match, | 471 | .match = ps3_system_bus_match, |
472 | .uevent = ps3_system_bus_uevent, | ||
166 | .probe = ps3_system_bus_probe, | 473 | .probe = ps3_system_bus_probe, |
167 | .remove = ps3_system_bus_remove, | 474 | .remove = ps3_system_bus_remove, |
475 | .shutdown = ps3_system_bus_shutdown, | ||
476 | .dev_attrs = ps3_system_bus_dev_attrs, | ||
168 | }; | 477 | }; |
169 | 478 | ||
170 | int __init ps3_system_bus_init(void) | 479 | static int __init ps3_system_bus_init(void) |
171 | { | 480 | { |
172 | int result; | 481 | int result; |
173 | 482 | ||
174 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | 483 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) |
175 | return -ENODEV; | 484 | return -ENODEV; |
176 | 485 | ||
486 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
487 | |||
488 | mutex_init(&usage_hack.mutex); | ||
489 | |||
490 | result = device_register(&ps3_system_bus); | ||
491 | BUG_ON(result); | ||
492 | |||
177 | result = bus_register(&ps3_system_bus_type); | 493 | result = bus_register(&ps3_system_bus_type); |
178 | BUG_ON(result); | 494 | BUG_ON(result); |
495 | |||
496 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
179 | return result; | 497 | return result; |
180 | } | 498 | } |
181 | 499 | ||
@@ -185,16 +503,13 @@ core_initcall(ps3_system_bus_init); | |||
185 | * Returns the virtual address of the buffer and sets dma_handle | 503 | * Returns the virtual address of the buffer and sets dma_handle |
186 | * to the dma address (mapping) of the first page. | 504 | * to the dma address (mapping) of the first page. |
187 | */ | 505 | */ |
188 | |||
189 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, | 506 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, |
190 | dma_addr_t *dma_handle, gfp_t flag) | 507 | dma_addr_t *dma_handle, gfp_t flag) |
191 | { | 508 | { |
192 | int result; | 509 | int result; |
193 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 510 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
194 | unsigned long virt_addr; | 511 | unsigned long virt_addr; |
195 | 512 | ||
196 | BUG_ON(!dev->d_region->bus_addr); | ||
197 | |||
198 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); | 513 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); |
199 | flag |= __GFP_ZERO; | 514 | flag |= __GFP_ZERO; |
200 | 515 | ||
@@ -205,7 +520,8 @@ static void * ps3_alloc_coherent(struct device *_dev, size_t size, | |||
205 | goto clean_none; | 520 | goto clean_none; |
206 | } | 521 | } |
207 | 522 | ||
208 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); | 523 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle, |
524 | IOPTE_PP_W | IOPTE_PP_R | IOPTE_SO_RW | IOPTE_M); | ||
209 | 525 | ||
210 | if (result) { | 526 | if (result) { |
211 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 527 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -226,7 +542,7 @@ clean_none: | |||
226 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | 542 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, |
227 | dma_addr_t dma_handle) | 543 | dma_addr_t dma_handle) |
228 | { | 544 | { |
229 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 545 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
230 | 546 | ||
231 | ps3_dma_unmap(dev->d_region, dma_handle, size); | 547 | ps3_dma_unmap(dev->d_region, dma_handle, size); |
232 | free_pages((unsigned long)vaddr, get_order(size)); | 548 | free_pages((unsigned long)vaddr, get_order(size)); |
@@ -239,15 +555,16 @@ static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | |||
239 | * byte within the page as vaddr. | 555 | * byte within the page as vaddr. |
240 | */ | 556 | */ |
241 | 557 | ||
242 | static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | 558 | static dma_addr_t ps3_sb_map_single(struct device *_dev, void *ptr, size_t size, |
243 | enum dma_data_direction direction) | 559 | enum dma_data_direction direction) |
244 | { | 560 | { |
245 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 561 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
246 | int result; | 562 | int result; |
247 | unsigned long bus_addr; | 563 | unsigned long bus_addr; |
248 | 564 | ||
249 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | 565 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, |
250 | &bus_addr); | 566 | &bus_addr, |
567 | IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW | IOPTE_M); | ||
251 | 568 | ||
252 | if (result) { | 569 | if (result) { |
253 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 570 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -257,10 +574,44 @@ static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | |||
257 | return bus_addr; | 574 | return bus_addr; |
258 | } | 575 | } |
259 | 576 | ||
577 | static dma_addr_t ps3_ioc0_map_single(struct device *_dev, void *ptr, | ||
578 | size_t size, | ||
579 | enum dma_data_direction direction) | ||
580 | { | ||
581 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); | ||
582 | int result; | ||
583 | unsigned long bus_addr; | ||
584 | u64 iopte_flag; | ||
585 | |||
586 | iopte_flag = IOPTE_M; | ||
587 | switch (direction) { | ||
588 | case DMA_BIDIRECTIONAL: | ||
589 | iopte_flag |= IOPTE_PP_R | IOPTE_PP_W | IOPTE_SO_RW; | ||
590 | break; | ||
591 | case DMA_TO_DEVICE: | ||
592 | iopte_flag |= IOPTE_PP_R | IOPTE_SO_R; | ||
593 | break; | ||
594 | case DMA_FROM_DEVICE: | ||
595 | iopte_flag |= IOPTE_PP_W | IOPTE_SO_RW; | ||
596 | break; | ||
597 | default: | ||
598 | /* not happned */ | ||
599 | BUG(); | ||
600 | }; | ||
601 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | ||
602 | &bus_addr, iopte_flag); | ||
603 | |||
604 | if (result) { | ||
605 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
606 | __func__, __LINE__, result); | ||
607 | } | ||
608 | return bus_addr; | ||
609 | } | ||
610 | |||
260 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | 611 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, |
261 | size_t size, enum dma_data_direction direction) | 612 | size_t size, enum dma_data_direction direction) |
262 | { | 613 | { |
263 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 614 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
264 | int result; | 615 | int result; |
265 | 616 | ||
266 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); | 617 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); |
@@ -271,20 +622,20 @@ static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | |||
271 | } | 622 | } |
272 | } | 623 | } |
273 | 624 | ||
274 | static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | 625 | static int ps3_sb_map_sg(struct device *_dev, struct scatterlist *sg, int nents, |
275 | enum dma_data_direction direction) | 626 | enum dma_data_direction direction) |
276 | { | 627 | { |
277 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 628 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
278 | BUG_ON("do"); | 629 | BUG_ON("do"); |
279 | return -EPERM; | 630 | return -EPERM; |
280 | #else | 631 | #else |
281 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 632 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
282 | int i; | 633 | int i; |
283 | 634 | ||
284 | for (i = 0; i < nents; i++, sg++) { | 635 | for (i = 0; i < nents; i++, sg++) { |
285 | int result = ps3_dma_map(dev->d_region, | 636 | int result = ps3_dma_map(dev->d_region, |
286 | page_to_phys(sg->page) + sg->offset, sg->length, | 637 | page_to_phys(sg->page) + sg->offset, sg->length, |
287 | &sg->dma_address); | 638 | &sg->dma_address, 0); |
288 | 639 | ||
289 | if (result) { | 640 | if (result) { |
290 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | 641 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", |
@@ -299,7 +650,15 @@ static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | |||
299 | #endif | 650 | #endif |
300 | } | 651 | } |
301 | 652 | ||
302 | static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | 653 | static int ps3_ioc0_map_sg(struct device *_dev, struct scatterlist *sg, |
654 | int nents, | ||
655 | enum dma_data_direction direction) | ||
656 | { | ||
657 | BUG(); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static void ps3_sb_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
303 | int nents, enum dma_data_direction direction) | 662 | int nents, enum dma_data_direction direction) |
304 | { | 663 | { |
305 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 664 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
@@ -307,18 +666,34 @@ static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | |||
307 | #endif | 666 | #endif |
308 | } | 667 | } |
309 | 668 | ||
669 | static void ps3_ioc0_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
670 | int nents, enum dma_data_direction direction) | ||
671 | { | ||
672 | BUG(); | ||
673 | } | ||
674 | |||
310 | static int ps3_dma_supported(struct device *_dev, u64 mask) | 675 | static int ps3_dma_supported(struct device *_dev, u64 mask) |
311 | { | 676 | { |
312 | return mask >= DMA_32BIT_MASK; | 677 | return mask >= DMA_32BIT_MASK; |
313 | } | 678 | } |
314 | 679 | ||
315 | static struct dma_mapping_ops ps3_dma_ops = { | 680 | static struct dma_mapping_ops ps3_sb_dma_ops = { |
316 | .alloc_coherent = ps3_alloc_coherent, | 681 | .alloc_coherent = ps3_alloc_coherent, |
317 | .free_coherent = ps3_free_coherent, | 682 | .free_coherent = ps3_free_coherent, |
318 | .map_single = ps3_map_single, | 683 | .map_single = ps3_sb_map_single, |
319 | .unmap_single = ps3_unmap_single, | 684 | .unmap_single = ps3_unmap_single, |
320 | .map_sg = ps3_map_sg, | 685 | .map_sg = ps3_sb_map_sg, |
321 | .unmap_sg = ps3_unmap_sg, | 686 | .unmap_sg = ps3_sb_unmap_sg, |
687 | .dma_supported = ps3_dma_supported | ||
688 | }; | ||
689 | |||
690 | static struct dma_mapping_ops ps3_ioc0_dma_ops = { | ||
691 | .alloc_coherent = ps3_alloc_coherent, | ||
692 | .free_coherent = ps3_free_coherent, | ||
693 | .map_single = ps3_ioc0_map_single, | ||
694 | .unmap_single = ps3_unmap_single, | ||
695 | .map_sg = ps3_ioc0_map_sg, | ||
696 | .unmap_sg = ps3_ioc0_unmap_sg, | ||
322 | .dma_supported = ps3_dma_supported | 697 | .dma_supported = ps3_dma_supported |
323 | }; | 698 | }; |
324 | 699 | ||
@@ -328,7 +703,7 @@ static struct dma_mapping_ops ps3_dma_ops = { | |||
328 | 703 | ||
329 | static void ps3_system_bus_release_device(struct device *_dev) | 704 | static void ps3_system_bus_release_device(struct device *_dev) |
330 | { | 705 | { |
331 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | 706 | struct ps3_system_bus_device *dev = ps3_dev_to_system_bus_dev(_dev); |
332 | kfree(dev); | 707 | kfree(dev); |
333 | } | 708 | } |
334 | 709 | ||
@@ -343,19 +718,38 @@ static void ps3_system_bus_release_device(struct device *_dev) | |||
343 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | 718 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) |
344 | { | 719 | { |
345 | int result; | 720 | int result; |
346 | static unsigned int dev_count = 1; | 721 | static unsigned int dev_ioc0_count; |
722 | static unsigned int dev_sb_count; | ||
723 | static unsigned int dev_vuart_count; | ||
347 | 724 | ||
348 | dev->core.parent = NULL; | 725 | if (!dev->core.parent) |
726 | dev->core.parent = &ps3_system_bus; | ||
349 | dev->core.bus = &ps3_system_bus_type; | 727 | dev->core.bus = &ps3_system_bus_type; |
350 | dev->core.release = ps3_system_bus_release_device; | 728 | dev->core.release = ps3_system_bus_release_device; |
351 | 729 | ||
730 | switch (dev->dev_type) { | ||
731 | case PS3_DEVICE_TYPE_IOC0: | ||
732 | dev->core.archdata.dma_ops = &ps3_ioc0_dma_ops; | ||
733 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
734 | "ioc0_%02x", ++dev_ioc0_count); | ||
735 | break; | ||
736 | case PS3_DEVICE_TYPE_SB: | ||
737 | dev->core.archdata.dma_ops = &ps3_sb_dma_ops; | ||
738 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
739 | "sb_%02x", ++dev_sb_count); | ||
740 | |||
741 | break; | ||
742 | case PS3_DEVICE_TYPE_VUART: | ||
743 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
744 | "vuart_%02x", ++dev_vuart_count); | ||
745 | break; | ||
746 | default: | ||
747 | BUG(); | ||
748 | }; | ||
749 | |||
352 | dev->core.archdata.of_node = NULL; | 750 | dev->core.archdata.of_node = NULL; |
353 | dev->core.archdata.dma_ops = &ps3_dma_ops; | ||
354 | dev->core.archdata.numa_node = 0; | 751 | dev->core.archdata.numa_node = 0; |
355 | 752 | ||
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); | 753 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); |
360 | 754 | ||
361 | result = device_register(&dev->core); | 755 | result = device_register(&dev->core); |
@@ -368,9 +762,15 @@ int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) | |||
368 | { | 762 | { |
369 | int result; | 763 | int result; |
370 | 764 | ||
765 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
766 | |||
767 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
768 | return -ENODEV; | ||
769 | |||
371 | drv->core.bus = &ps3_system_bus_type; | 770 | drv->core.bus = &ps3_system_bus_type; |
372 | 771 | ||
373 | result = driver_register(&drv->core); | 772 | result = driver_register(&drv->core); |
773 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
374 | return result; | 774 | return result; |
375 | } | 775 | } |
376 | 776 | ||
@@ -378,7 +778,9 @@ EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | |||
378 | 778 | ||
379 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | 779 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) |
380 | { | 780 | { |
781 | pr_debug(" -> %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
381 | driver_unregister(&drv->core); | 782 | driver_unregister(&drv->core); |
783 | pr_debug(" <- %s:%d: %s\n", __func__, __LINE__, drv->core.name); | ||
382 | } | 784 | } |
383 | 785 | ||
384 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | 786 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); |