aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/rtas.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/rtas.c')
-rw-r--r--arch/powerpc/kernel/rtas.c108
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 */
376unsigned int rtas_extended_busy_delay_time(int status) 376unsigned 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--) 393unsigned 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
393int rtas_error_rc(int rtas_rc) 405int rtas_error_rc(int rtas_rc)
@@ -438,22 +450,14 @@ int rtas_get_power_level(int powerdomain, int *level)
438int rtas_set_power_level(int powerdomain, int level, int *setlevel) 450int 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)
463int rtas_get_sensor(int sensor, int index, int *state) 467int 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)
488int rtas_set_indicator(int indicator, int index, int new_value) 484int 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
567static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; 552static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE;
@@ -608,9 +593,31 @@ out:
608static int rtas_ibm_suspend_me(struct rtas_args *args) 593static 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);
789EXPORT_SYMBOL(rtas_call); 796EXPORT_SYMBOL(rtas_call);
790EXPORT_SYMBOL(rtas_data_buf); 797EXPORT_SYMBOL(rtas_data_buf);
791EXPORT_SYMBOL(rtas_data_buf_lock); 798EXPORT_SYMBOL(rtas_data_buf_lock);
792EXPORT_SYMBOL(rtas_extended_busy_delay_time); 799EXPORT_SYMBOL(rtas_busy_delay_time);
800EXPORT_SYMBOL(rtas_busy_delay);
793EXPORT_SYMBOL(rtas_get_sensor); 801EXPORT_SYMBOL(rtas_get_sensor);
794EXPORT_SYMBOL(rtas_get_power_level); 802EXPORT_SYMBOL(rtas_get_power_level);
795EXPORT_SYMBOL(rtas_set_power_level); 803EXPORT_SYMBOL(rtas_set_power_level);