aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/rtas.c
diff options
context:
space:
mode:
authorJohn Rose <johnrose@austin.ibm.com>2006-06-05 17:31:48 -0400
committerPaul Mackerras <paulus@samba.org>2006-06-09 07:21:06 -0400
commit507279db1819aacf4022e790b3fc8bc8cf56debf (patch)
treee5e95d50b093f0eab31e7856b9f596caa6e097af /arch/powerpc/kernel/rtas.c
parent4a3ecc622465dbff7404139a8ad18bf4cb99f836 (diff)
[PATCH] powerpc: reorg RTAS delay code
This patch attempts to handle RTAS "busy" return codes in a more simple and consistent manner. Typical callers of RTAS shouldn't have to manage wait times and delay calls. This patch also changes the kernel to use msleep() rather than udelay() when a runtime delay is necessary. This will avoid CPU soft lockups for extended delay conditions. Signed-off-by: John Rose <johnrose@austin.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/rtas.c')
-rw-r--r--arch/powerpc/kernel/rtas.c85
1 files changed, 35 insertions, 50 deletions
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 0112318213ab..13496f319855 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;
@@ -789,7 +774,7 @@ EXPORT_SYMBOL(rtas_token);
789EXPORT_SYMBOL(rtas_call); 774EXPORT_SYMBOL(rtas_call);
790EXPORT_SYMBOL(rtas_data_buf); 775EXPORT_SYMBOL(rtas_data_buf);
791EXPORT_SYMBOL(rtas_data_buf_lock); 776EXPORT_SYMBOL(rtas_data_buf_lock);
792EXPORT_SYMBOL(rtas_extended_busy_delay_time); 777EXPORT_SYMBOL(rtas_busy_delay_time);
793EXPORT_SYMBOL(rtas_get_sensor); 778EXPORT_SYMBOL(rtas_get_sensor);
794EXPORT_SYMBOL(rtas_get_power_level); 779EXPORT_SYMBOL(rtas_get_power_level);
795EXPORT_SYMBOL(rtas_set_power_level); 780EXPORT_SYMBOL(rtas_set_power_level);