aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/powerpc/kernel/rtas-rtc.c30
-rw-r--r--arch/powerpc/kernel/rtas.c85
-rw-r--r--arch/powerpc/kernel/rtas_flash.c25
-rw-r--r--include/asm-powerpc/rtas.h8
4 files changed, 57 insertions, 91 deletions
diff --git a/arch/powerpc/kernel/rtas-rtc.c b/arch/powerpc/kernel/rtas-rtc.c
index 34d073fb6091..77578c093dda 100644
--- a/arch/powerpc/kernel/rtas-rtc.c
+++ b/arch/powerpc/kernel/rtas-rtc.c
@@ -14,19 +14,20 @@
14unsigned long __init rtas_get_boot_time(void) 14unsigned long __init rtas_get_boot_time(void)
15{ 15{
16 int ret[8]; 16 int ret[8];
17 int error, wait_time; 17 int error;
18 unsigned int wait_time;
18 u64 max_wait_tb; 19 u64 max_wait_tb;
19 20
20 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; 21 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
21 do { 22 do {
22 error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); 23 error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
23 if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { 24
24 wait_time = rtas_extended_busy_delay_time(error); 25 wait_time = rtas_busy_delay_time(error);
26 if (wait_time) {
25 /* This is boot time so we spin. */ 27 /* This is boot time so we spin. */
26 udelay(wait_time*1000); 28 udelay(wait_time*1000);
27 error = RTAS_CLOCK_BUSY;
28 } 29 }
29 } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); 30 } while (wait_time && (get_tb() < max_wait_tb));
30 31
31 if (error != 0 && printk_ratelimit()) { 32 if (error != 0 && printk_ratelimit()) {
32 printk(KERN_WARNING "error: reading the clock failed (%d)\n", 33 printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -44,24 +45,25 @@ unsigned long __init rtas_get_boot_time(void)
44void rtas_get_rtc_time(struct rtc_time *rtc_tm) 45void rtas_get_rtc_time(struct rtc_time *rtc_tm)
45{ 46{
46 int ret[8]; 47 int ret[8];
47 int error, wait_time; 48 int error;
49 unsigned int wait_time;
48 u64 max_wait_tb; 50 u64 max_wait_tb;
49 51
50 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT; 52 max_wait_tb = get_tb() + tb_ticks_per_usec * 1000 * MAX_RTC_WAIT;
51 do { 53 do {
52 error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret); 54 error = rtas_call(rtas_token("get-time-of-day"), 0, 8, ret);
53 if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { 55
56 wait_time = rtas_busy_delay_time(error);
57 if (wait_time) {
54 if (in_interrupt() && printk_ratelimit()) { 58 if (in_interrupt() && printk_ratelimit()) {
55 memset(rtc_tm, 0, sizeof(struct rtc_time)); 59 memset(rtc_tm, 0, sizeof(struct rtc_time));
56 printk(KERN_WARNING "error: reading clock" 60 printk(KERN_WARNING "error: reading clock"
57 " would delay interrupt\n"); 61 " would delay interrupt\n");
58 return; /* delay not allowed */ 62 return; /* delay not allowed */
59 } 63 }
60 wait_time = rtas_extended_busy_delay_time(error);
61 msleep(wait_time); 64 msleep(wait_time);
62 error = RTAS_CLOCK_BUSY;
63 } 65 }
64 } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); 66 } while (wait_time && (get_tb() < max_wait_tb));
65 67
66 if (error != 0 && printk_ratelimit()) { 68 if (error != 0 && printk_ratelimit()) {
67 printk(KERN_WARNING "error: reading the clock failed (%d)\n", 69 printk(KERN_WARNING "error: reading the clock failed (%d)\n",
@@ -88,14 +90,14 @@ int rtas_set_rtc_time(struct rtc_time *tm)
88 tm->tm_year + 1900, tm->tm_mon + 1, 90 tm->tm_year + 1900, tm->tm_mon + 1,
89 tm->tm_mday, tm->tm_hour, tm->tm_min, 91 tm->tm_mday, tm->tm_hour, tm->tm_min,
90 tm->tm_sec, 0); 92 tm->tm_sec, 0);
91 if (error == RTAS_CLOCK_BUSY || rtas_is_extended_busy(error)) { 93
94 wait_time = rtas_busy_delay_time(error);
95 if (wait_time) {
92 if (in_interrupt()) 96 if (in_interrupt())
93 return 1; /* probably decrementer */ 97 return 1; /* probably decrementer */
94 wait_time = rtas_extended_busy_delay_time(error);
95 msleep(wait_time); 98 msleep(wait_time);
96 error = RTAS_CLOCK_BUSY;
97 } 99 }
98 } while (error == RTAS_CLOCK_BUSY && (get_tb() < max_wait_tb)); 100 } while (wait_time && (get_tb() < max_wait_tb));
99 101
100 if (error != 0 && printk_ratelimit()) 102 if (error != 0 && printk_ratelimit())
101 printk(KERN_WARNING "error: setting the clock failed (%d)\n", 103 printk(KERN_WARNING "error: setting the clock failed (%d)\n",
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);
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index aaf384c3f04a..1442b63a75da 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -365,20 +365,12 @@ static int rtas_excl_release(struct inode *inode, struct file *file)
365 365
366static void manage_flash(struct rtas_manage_flash_t *args_buf) 366static void manage_flash(struct rtas_manage_flash_t *args_buf)
367{ 367{
368 unsigned int wait_time;
369 s32 rc; 368 s32 rc;
370 369
371 while (1) { 370 do {
372 rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1, 371 rc = rtas_call(rtas_token("ibm,manage-flash-image"), 1,
373 1, NULL, args_buf->op); 372 1, NULL, args_buf->op);
374 if (rc == RTAS_RC_BUSY) 373 } while (rtas_busy_delay(rc));
375 udelay(1);
376 else if (rtas_is_extended_busy(rc)) {
377 wait_time = rtas_extended_busy_delay_time(rc);
378 udelay(wait_time * 1000);
379 } else
380 break;
381 }
382 374
383 args_buf->status = rc; 375 args_buf->status = rc;
384} 376}
@@ -451,27 +443,18 @@ static ssize_t manage_flash_write(struct file *file, const char __user *buf,
451static void validate_flash(struct rtas_validate_flash_t *args_buf) 443static void validate_flash(struct rtas_validate_flash_t *args_buf)
452{ 444{
453 int token = rtas_token("ibm,validate-flash-image"); 445 int token = rtas_token("ibm,validate-flash-image");
454 unsigned int wait_time;
455 int update_results; 446 int update_results;
456 s32 rc; 447 s32 rc;
457 448
458 rc = 0; 449 rc = 0;
459 while(1) { 450 do {
460 spin_lock(&rtas_data_buf_lock); 451 spin_lock(&rtas_data_buf_lock);
461 memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE); 452 memcpy(rtas_data_buf, args_buf->buf, VALIDATE_BUF_SIZE);
462 rc = rtas_call(token, 2, 2, &update_results, 453 rc = rtas_call(token, 2, 2, &update_results,
463 (u32) __pa(rtas_data_buf), args_buf->buf_size); 454 (u32) __pa(rtas_data_buf), args_buf->buf_size);
464 memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE); 455 memcpy(args_buf->buf, rtas_data_buf, VALIDATE_BUF_SIZE);
465 spin_unlock(&rtas_data_buf_lock); 456 spin_unlock(&rtas_data_buf_lock);
466 457 } while (rtas_busy_delay(rc));
467 if (rc == RTAS_RC_BUSY)
468 udelay(1);
469 else if (rtas_is_extended_busy(rc)) {
470 wait_time = rtas_extended_busy_delay_time(rc);
471 udelay(wait_time * 1000);
472 } else
473 break;
474 }
475 458
476 args_buf->status = rc; 459 args_buf->status = rc;
477 args_buf->update_results = update_results; 460 args_buf->update_results = update_results;
diff --git a/include/asm-powerpc/rtas.h b/include/asm-powerpc/rtas.h
index f43c6835e62a..a3b4e55569c7 100644
--- a/include/asm-powerpc/rtas.h
+++ b/include/asm-powerpc/rtas.h
@@ -177,12 +177,8 @@ extern unsigned long rtas_get_boot_time(void);
177extern void rtas_get_rtc_time(struct rtc_time *rtc_time); 177extern void rtas_get_rtc_time(struct rtc_time *rtc_time);
178extern int rtas_set_rtc_time(struct rtc_time *rtc_time); 178extern int rtas_set_rtc_time(struct rtc_time *rtc_time);
179 179
180/* Given an RTAS status code of 9900..9905 compute the hinted delay */ 180extern unsigned int rtas_busy_delay_time(int status);
181unsigned int rtas_extended_busy_delay_time(int status); 181extern unsigned int rtas_busy_delay(int status);
182static inline int rtas_is_extended_busy(int status)
183{
184 return status >= 9900 && status <= 9909;
185}
186 182
187extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal); 183extern void pSeries_log_error(char *buf, unsigned int err_type, int fatal);
188 184