diff options
Diffstat (limited to 'arch/powerpc/kernel/rtas.c')
-rw-r--r-- | arch/powerpc/kernel/rtas.c | 108 |
1 files changed, 58 insertions, 50 deletions
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 0112318213ab..17dc79198515 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -370,24 +370,36 @@ int rtas_call(int token, int nargs, int nret, int *outputs, ...) | |||
370 | return ret; | 370 | return ret; |
371 | } | 371 | } |
372 | 372 | ||
373 | /* Given an RTAS status code of 990n compute the hinted delay of 10^n | 373 | /* For RTAS_BUSY (-2), delay for 1 millisecond. For an extended busy status |
374 | * (last digit) milliseconds. For now we bound at n=5 (100 sec). | 374 | * code of 990n, perform the hinted delay of 10^n (last digit) milliseconds. |
375 | */ | 375 | */ |
376 | unsigned int rtas_extended_busy_delay_time(int status) | 376 | unsigned int rtas_busy_delay_time(int status) |
377 | { | 377 | { |
378 | int order = status - 9900; | 378 | int order; |
379 | unsigned long ms; | 379 | unsigned int ms = 0; |
380 | |||
381 | if (status == RTAS_BUSY) { | ||
382 | ms = 1; | ||
383 | } else if (status >= 9900 && status <= 9905) { | ||
384 | order = status - 9900; | ||
385 | for (ms = 1; order > 0; order--) | ||
386 | ms *= 10; | ||
387 | } | ||
380 | 388 | ||
381 | if (order < 0) | 389 | return ms; |
382 | order = 0; /* RTC depends on this for -2 clock busy */ | 390 | } |
383 | else if (order > 5) | ||
384 | order = 5; /* bound */ | ||
385 | 391 | ||
386 | /* Use microseconds for reasonable accuracy */ | 392 | /* For an RTAS busy status code, perform the hinted delay. */ |
387 | for (ms = 1; order > 0; order--) | 393 | unsigned int rtas_busy_delay(int status) |
388 | ms *= 10; | 394 | { |
395 | unsigned int ms; | ||
389 | 396 | ||
390 | return ms; | 397 | might_sleep(); |
398 | ms = rtas_busy_delay_time(status); | ||
399 | if (ms) | ||
400 | msleep(ms); | ||
401 | |||
402 | return ms; | ||
391 | } | 403 | } |
392 | 404 | ||
393 | int rtas_error_rc(int rtas_rc) | 405 | int rtas_error_rc(int rtas_rc) |
@@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain, int *level) | |||
438 | int rtas_set_power_level(int powerdomain, int level, int *setlevel) | 450 | int rtas_set_power_level(int powerdomain, int level, int *setlevel) |
439 | { | 451 | { |
440 | int token = rtas_token("set-power-level"); | 452 | int token = rtas_token("set-power-level"); |
441 | unsigned int wait_time; | ||
442 | int rc; | 453 | int rc; |
443 | 454 | ||
444 | if (token == RTAS_UNKNOWN_SERVICE) | 455 | if (token == RTAS_UNKNOWN_SERVICE) |
445 | return -ENOENT; | 456 | return -ENOENT; |
446 | 457 | ||
447 | while (1) { | 458 | do { |
448 | rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); | 459 | rc = rtas_call(token, 2, 2, setlevel, powerdomain, level); |
449 | if (rc == RTAS_BUSY) | 460 | } while (rtas_busy_delay(rc)); |
450 | udelay(1); | ||
451 | else if (rtas_is_extended_busy(rc)) { | ||
452 | wait_time = rtas_extended_busy_delay_time(rc); | ||
453 | udelay(wait_time * 1000); | ||
454 | } else | ||
455 | break; | ||
456 | } | ||
457 | 461 | ||
458 | if (rc < 0) | 462 | if (rc < 0) |
459 | return rtas_error_rc(rc); | 463 | return rtas_error_rc(rc); |
@@ -463,22 +467,14 @@ int rtas_set_power_level(int powerdomain, int level, int *setlevel) | |||
463 | int rtas_get_sensor(int sensor, int index, int *state) | 467 | int rtas_get_sensor(int sensor, int index, int *state) |
464 | { | 468 | { |
465 | int token = rtas_token("get-sensor-state"); | 469 | int token = rtas_token("get-sensor-state"); |
466 | unsigned int wait_time; | ||
467 | int rc; | 470 | int rc; |
468 | 471 | ||
469 | if (token == RTAS_UNKNOWN_SERVICE) | 472 | if (token == RTAS_UNKNOWN_SERVICE) |
470 | return -ENOENT; | 473 | return -ENOENT; |
471 | 474 | ||
472 | while (1) { | 475 | do { |
473 | rc = rtas_call(token, 2, 2, state, sensor, index); | 476 | rc = rtas_call(token, 2, 2, state, sensor, index); |
474 | if (rc == RTAS_BUSY) | 477 | } while (rtas_busy_delay(rc)); |
475 | udelay(1); | ||
476 | else if (rtas_is_extended_busy(rc)) { | ||
477 | wait_time = rtas_extended_busy_delay_time(rc); | ||
478 | udelay(wait_time * 1000); | ||
479 | } else | ||
480 | break; | ||
481 | } | ||
482 | 478 | ||
483 | if (rc < 0) | 479 | if (rc < 0) |
484 | return rtas_error_rc(rc); | 480 | return rtas_error_rc(rc); |
@@ -488,23 +484,14 @@ int rtas_get_sensor(int sensor, int index, int *state) | |||
488 | int rtas_set_indicator(int indicator, int index, int new_value) | 484 | int rtas_set_indicator(int indicator, int index, int new_value) |
489 | { | 485 | { |
490 | int token = rtas_token("set-indicator"); | 486 | int token = rtas_token("set-indicator"); |
491 | unsigned int wait_time; | ||
492 | int rc; | 487 | int rc; |
493 | 488 | ||
494 | if (token == RTAS_UNKNOWN_SERVICE) | 489 | if (token == RTAS_UNKNOWN_SERVICE) |
495 | return -ENOENT; | 490 | return -ENOENT; |
496 | 491 | ||
497 | while (1) { | 492 | do { |
498 | rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); | 493 | rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); |
499 | if (rc == RTAS_BUSY) | 494 | } while (rtas_busy_delay(rc)); |
500 | udelay(1); | ||
501 | else if (rtas_is_extended_busy(rc)) { | ||
502 | wait_time = rtas_extended_busy_delay_time(rc); | ||
503 | udelay(wait_time * 1000); | ||
504 | } | ||
505 | else | ||
506 | break; | ||
507 | } | ||
508 | 495 | ||
509 | if (rc < 0) | 496 | if (rc < 0) |
510 | return rtas_error_rc(rc); | 497 | return rtas_error_rc(rc); |
@@ -555,13 +542,11 @@ void rtas_os_term(char *str) | |||
555 | do { | 542 | do { |
556 | status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, | 543 | status = rtas_call(rtas_token("ibm,os-term"), 1, 1, NULL, |
557 | __pa(rtas_os_term_buf)); | 544 | __pa(rtas_os_term_buf)); |
545 | } while (rtas_busy_delay(status)); | ||
558 | 546 | ||
559 | if (status == RTAS_BUSY) | 547 | if (status != 0) |
560 | udelay(1); | 548 | printk(KERN_EMERG "ibm,os-term call failed %d\n", |
561 | else if (status != 0) | ||
562 | printk(KERN_EMERG "ibm,os-term call failed %d\n", | ||
563 | status); | 549 | status); |
564 | } while (status == RTAS_BUSY); | ||
565 | } | 550 | } |
566 | 551 | ||
567 | static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; | 552 | static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; |
@@ -608,9 +593,31 @@ out: | |||
608 | static int rtas_ibm_suspend_me(struct rtas_args *args) | 593 | static int rtas_ibm_suspend_me(struct rtas_args *args) |
609 | { | 594 | { |
610 | int i; | 595 | int i; |
596 | long state; | ||
597 | long rc; | ||
598 | unsigned long dummy; | ||
611 | 599 | ||
612 | struct rtas_suspend_me_data data; | 600 | struct rtas_suspend_me_data data; |
613 | 601 | ||
602 | /* Make sure the state is valid */ | ||
603 | rc = plpar_hcall(H_VASI_STATE, | ||
604 | ((u64)args->args[0] << 32) | args->args[1], | ||
605 | 0, 0, 0, | ||
606 | &state, &dummy, &dummy); | ||
607 | |||
608 | if (rc) { | ||
609 | printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned %ld\n",rc); | ||
610 | return rc; | ||
611 | } else if (state == H_VASI_ENABLED) { | ||
612 | args->args[args->nargs] = RTAS_NOT_SUSPENDABLE; | ||
613 | return 0; | ||
614 | } else if (state != H_VASI_SUSPENDING) { | ||
615 | printk(KERN_ERR "rtas_ibm_suspend_me: vasi_state returned state %ld\n", | ||
616 | state); | ||
617 | args->args[args->nargs] = -1; | ||
618 | return 0; | ||
619 | } | ||
620 | |||
614 | data.waiting = 1; | 621 | data.waiting = 1; |
615 | data.args = args; | 622 | data.args = args; |
616 | 623 | ||
@@ -789,7 +796,8 @@ EXPORT_SYMBOL(rtas_token); | |||
789 | EXPORT_SYMBOL(rtas_call); | 796 | EXPORT_SYMBOL(rtas_call); |
790 | EXPORT_SYMBOL(rtas_data_buf); | 797 | EXPORT_SYMBOL(rtas_data_buf); |
791 | EXPORT_SYMBOL(rtas_data_buf_lock); | 798 | EXPORT_SYMBOL(rtas_data_buf_lock); |
792 | EXPORT_SYMBOL(rtas_extended_busy_delay_time); | 799 | EXPORT_SYMBOL(rtas_busy_delay_time); |
800 | EXPORT_SYMBOL(rtas_busy_delay); | ||
793 | EXPORT_SYMBOL(rtas_get_sensor); | 801 | EXPORT_SYMBOL(rtas_get_sensor); |
794 | EXPORT_SYMBOL(rtas_get_power_level); | 802 | EXPORT_SYMBOL(rtas_get_power_level); |
795 | EXPORT_SYMBOL(rtas_set_power_level); | 803 | EXPORT_SYMBOL(rtas_set_power_level); |