aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>2007-06-21 10:14:22 -0400
committerPaul Mackerras <paulus@samba.org>2007-06-28 05:19:21 -0400
commita5c631b174e23cab773cf422c1f39b28e7224602 (patch)
treebfe9756b88557b12bc61e505d31abd50458fa22f /arch/powerpc/platforms
parent80071802cb9c622dbd44bc6ba292f0683891ef44 (diff)
[POWERPC] PS3: Storage device registration routines
Add support for storage devices to the device probe code. 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')
-rw-r--r--arch/powerpc/platforms/ps3/device-init.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c
index 864f313be8de..825ebb2cbc2a 100644
--- a/arch/powerpc/platforms/ps3/device-init.c
+++ b/arch/powerpc/platforms/ps3/device-init.c
@@ -26,6 +26,7 @@
26 26
27#include <asm/firmware.h> 27#include <asm/firmware.h>
28#include <asm/lv1call.h> 28#include <asm/lv1call.h>
29#include <asm/ps3stor.h>
29 30
30#include "platform.h" 31#include "platform.h"
31 32
@@ -237,6 +238,262 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id,
237 return result; 238 return result;
238} 239}
239 240
241static int ps3stor_wait_for_completion(u64 dev_id, u64 tag,
242 unsigned int timeout)
243{
244 int result = -1;
245 unsigned int retries = 0;
246 u64 status;
247
248 for (retries = 0; retries < timeout; retries++) {
249 result = lv1_storage_check_async_status(dev_id, tag, &status);
250 if (!result)
251 break;
252
253 msleep(1);
254 }
255
256 if (result)
257 pr_debug("%s:%u: check_async_status: %s, status %lx\n",
258 __func__, __LINE__, ps3_result(result), status);
259
260 return result;
261}
262
263/**
264 * ps3_storage_wait_for_device - Wait for a storage device to become ready.
265 * @repo: The repository device to wait for.
266 *
267 * Uses the hypervisor's storage device notification mechanism to wait until
268 * a storage device is ready. The device notification mechanism uses a
269 * psuedo device (id = -1) to asynchronously notify the guest when storage
270 * devices become ready. The notification device has a block size of 512
271 * bytes.
272 */
273
274static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo)
275{
276 int result;
277 const u64 notification_dev_id = (u64)-1LL;
278 const unsigned int timeout = HZ;
279 u64 lpar;
280 u64 tag;
281 struct {
282 u64 operation_code; /* must be zero */
283 u64 event_mask; /* 1 = device ready */
284 } *notify_cmd;
285 struct {
286 u64 event_type; /* notify_device_ready */
287 u64 bus_id;
288 u64 dev_id;
289 u64 dev_type;
290 u64 dev_port;
291 } *notify_event;
292 enum {
293 notify_device_ready = 1
294 };
295
296 pr_debug(" -> %s:%u: bus_id %u, dev_id %u, dev_type %u\n", __func__,
297 __LINE__, repo->bus_id, repo->dev_id, repo->dev_type);
298
299 notify_cmd = kzalloc(512, GFP_KERNEL);
300 notify_event = (void *)notify_cmd;
301 if (!notify_cmd)
302 return -ENOMEM;
303
304 lpar = ps3_mm_phys_to_lpar(__pa(notify_cmd));
305
306 result = lv1_open_device(repo->bus_id, notification_dev_id, 0);
307 if (result) {
308 printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__,
309 __LINE__, ps3_result(result));
310 result = -ENODEV;
311 goto fail_free;
312 }
313
314 /* Setup and write the request for device notification. */
315
316 notify_cmd->operation_code = 0; /* must be zero */
317 notify_cmd->event_mask = 0x01; /* device ready */
318
319 result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar,
320 &tag);
321 if (result) {
322 printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__,
323 ps3_result(result));
324 result = -ENODEV;
325 goto fail_close;
326 }
327
328 /* Wait for the write completion */
329
330 result = ps3stor_wait_for_completion(notification_dev_id, tag,
331 timeout);
332 if (result) {
333 printk(KERN_ERR "%s:%u: write not completed %s\n", __func__,
334 __LINE__, ps3_result(result));
335 result = -ENODEV;
336 goto fail_close;
337 }
338
339 /* Loop here processing the requested notification events. */
340
341 result = -ENODEV;
342 while (1) {
343 memset(notify_event, 0, sizeof(*notify_event));
344
345 result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0,
346 lpar, &tag);
347 if (result) {
348 printk(KERN_ERR "%s:%u: write failed %s\n", __func__,
349 __LINE__, ps3_result(result));
350 break;
351 }
352
353 result = ps3stor_wait_for_completion(notification_dev_id, tag,
354 timeout);
355 if (result) {
356 printk(KERN_ERR "%s:%u: read not completed %s\n",
357 __func__, __LINE__, ps3_result(result));
358 break;
359 }
360
361 if (notify_event->event_type != notify_device_ready ||
362 notify_event->bus_id != repo->bus_id) {
363 pr_debug("%s:%u: bad notify_event: event %lu, "
364 "dev_id %lu, dev_type %lu\n",
365 __func__, __LINE__, notify_event->event_type,
366 notify_event->dev_id, notify_event->dev_type);
367 break;
368 }
369
370 if (notify_event->dev_id == repo->dev_id &&
371 notify_event->dev_type == repo->dev_type) {
372 pr_debug("%s:%u: device ready: dev_id %u\n", __func__,
373 __LINE__, repo->dev_id);
374 result = 0;
375 break;
376 }
377
378 if (notify_event->dev_id == repo->dev_id &&
379 notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) {
380 pr_debug("%s:%u: no access: dev_id %u\n", __func__,
381 __LINE__, repo->dev_id);
382 break;
383 }
384 }
385
386fail_close:
387 lv1_close_device(repo->bus_id, notification_dev_id);
388fail_free:
389 kfree(notify_cmd);
390 pr_debug(" <- %s:%u\n", __func__, __LINE__);
391 return result;
392}
393
394static int ps3_setup_storage_dev(const struct ps3_repository_device *repo,
395 enum ps3_match_id match_id)
396{
397 int result;
398 struct ps3_storage_device *p;
399 u64 port, blk_size, num_blocks;
400 unsigned int num_regions, i;
401
402 pr_debug(" -> %s:%u: match_id %u\n", __func__, __LINE__, match_id);
403
404 result = ps3_repository_read_stor_dev_info(repo->bus_index,
405 repo->dev_index, &port,
406 &blk_size, &num_blocks,
407 &num_regions);
408 if (result) {
409 printk(KERN_ERR "%s:%u: _read_stor_dev_info failed %d\n",
410 __func__, __LINE__, result);
411 return -ENODEV;
412 }
413
414 pr_debug("%s:%u: index %u:%u: port %lu blk_size %lu num_blocks %lu "
415 "num_regions %u\n", __func__, __LINE__, repo->bus_index,
416 repo->dev_index, port, blk_size, num_blocks, num_regions);
417
418 p = kzalloc(sizeof(struct ps3_storage_device) +
419 num_regions * sizeof(struct ps3_storage_region),
420 GFP_KERNEL);
421 if (!p) {
422 result = -ENOMEM;
423 goto fail_malloc;
424 }
425
426 p->sbd.match_id = match_id;
427 p->sbd.dev_type = PS3_DEVICE_TYPE_SB;
428 p->sbd.bus_id = repo->bus_id;
429 p->sbd.dev_id = repo->dev_id;
430 p->sbd.d_region = &p->dma_region;
431 p->blk_size = blk_size;
432 p->num_regions = num_regions;
433
434 result = ps3_repository_find_interrupt(repo,
435 PS3_INTERRUPT_TYPE_EVENT_PORT,
436 &p->sbd.interrupt_id);
437 if (result) {
438 printk(KERN_ERR "%s:%u: find_interrupt failed %d\n", __func__,
439 __LINE__, result);
440 result = -ENODEV;
441 goto fail_find_interrupt;
442 }
443
444 /* FIXME: Arrange to only do this on a 'cold' boot */
445
446 result = ps3_storage_wait_for_device(repo);
447 if (result) {
448 printk(KERN_ERR "%s:%u: storage_notification failed %d\n",
449 __func__, __LINE__, result);
450 result = -ENODEV;
451 goto fail_probe_notification;
452 }
453
454 for (i = 0; i < num_regions; i++) {
455 unsigned int id;
456 u64 start, size;
457
458 result = ps3_repository_read_stor_dev_region(repo->bus_index,
459 repo->dev_index,
460 i, &id, &start,
461 &size);
462 if (result) {
463 printk(KERN_ERR
464 "%s:%u: read_stor_dev_region failed %d\n",
465 __func__, __LINE__, result);
466 result = -ENODEV;
467 goto fail_read_region;
468 }
469 pr_debug("%s:%u: region %u: id %u start %lu size %lu\n",
470 __func__, __LINE__, i, id, start, size);
471
472 p->regions[i].id = id;
473 p->regions[i].start = start;
474 p->regions[i].size = size;
475 }
476
477 result = ps3_system_bus_device_register(&p->sbd);
478 if (result) {
479 pr_debug("%s:%u ps3_system_bus_device_register failed\n",
480 __func__, __LINE__);
481 goto fail_device_register;
482 }
483
484 pr_debug(" <- %s:%u\n", __func__, __LINE__);
485 return 0;
486
487fail_device_register:
488fail_read_region:
489fail_probe_notification:
490fail_find_interrupt:
491 kfree(p);
492fail_malloc:
493 pr_debug(" <- %s:%u: fail.\n", __func__, __LINE__);
494 return result;
495}
496
240static int __init ps3_register_vuart_devices(void) 497static int __init ps3_register_vuart_devices(void)
241{ 498{
242 int result; 499 int result;
@@ -356,6 +613,35 @@ static int ps3_register_repository_device(
356 __func__, __LINE__); 613 __func__, __LINE__);
357 } 614 }
358 break; 615 break;
616 case PS3_DEV_TYPE_STOR_DISK:
617 result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_DISK);
618
619 /* Some devices are not accessable from the Other OS lpar. */
620 if (result == -ENODEV) {
621 result = 0;
622 pr_debug("%s:%u: not accessable\n", __func__,
623 __LINE__);
624 }
625
626 if (result)
627 pr_debug("%s:%u ps3_setup_storage_dev failed\n",
628 __func__, __LINE__);
629 break;
630
631 case PS3_DEV_TYPE_STOR_ROM:
632 result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_ROM);
633 if (result)
634 pr_debug("%s:%u ps3_setup_storage_dev failed\n",
635 __func__, __LINE__);
636 break;
637
638 case PS3_DEV_TYPE_STOR_FLASH:
639 result = ps3_setup_storage_dev(repo, PS3_MATCH_ID_STOR_FLASH);
640 if (result)
641 pr_debug("%s:%u ps3_setup_storage_dev failed\n",
642 __func__, __LINE__);
643 break;
644
359 default: 645 default:
360 result = 0; 646 result = 0;
361 pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__, 647 pr_debug("%s:%u: unsupported dev_type %u\n", __func__, __LINE__,