diff options
Diffstat (limited to 'arch/ppc64/kernel/pSeries_setup.c')
-rw-r--r-- | arch/ppc64/kernel/pSeries_setup.c | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 44d9af72d225..849ed9ba7856 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c | |||
@@ -418,6 +418,133 @@ static int __init pSeries_probe(int platform) | |||
418 | return 1; | 418 | return 1; |
419 | } | 419 | } |
420 | 420 | ||
421 | DECLARE_PER_CPU(unsigned long, smt_snooze_delay); | ||
422 | |||
423 | int dedicated_idle(void) | ||
424 | { | ||
425 | long oldval; | ||
426 | struct paca_struct *lpaca = get_paca(), *ppaca; | ||
427 | unsigned long start_snooze; | ||
428 | unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); | ||
429 | unsigned int cpu = smp_processor_id(); | ||
430 | |||
431 | ppaca = &paca[cpu ^ 1]; | ||
432 | |||
433 | while (1) { | ||
434 | /* | ||
435 | * Indicate to the HV that we are idle. Now would be | ||
436 | * a good time to find other work to dispatch. | ||
437 | */ | ||
438 | lpaca->lppaca.idle = 1; | ||
439 | |||
440 | oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED); | ||
441 | if (!oldval) { | ||
442 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
443 | start_snooze = __get_tb() + | ||
444 | *smt_snooze_delay * tb_ticks_per_usec; | ||
445 | while (!need_resched() && !cpu_is_offline(cpu)) { | ||
446 | /* | ||
447 | * Go into low thread priority and possibly | ||
448 | * low power mode. | ||
449 | */ | ||
450 | HMT_low(); | ||
451 | HMT_very_low(); | ||
452 | |||
453 | if (*smt_snooze_delay == 0 || | ||
454 | __get_tb() < start_snooze) | ||
455 | continue; | ||
456 | |||
457 | HMT_medium(); | ||
458 | |||
459 | if (!(ppaca->lppaca.idle)) { | ||
460 | local_irq_disable(); | ||
461 | |||
462 | /* | ||
463 | * We are about to sleep the thread | ||
464 | * and so wont be polling any | ||
465 | * more. | ||
466 | */ | ||
467 | clear_thread_flag(TIF_POLLING_NRFLAG); | ||
468 | |||
469 | /* | ||
470 | * SMT dynamic mode. Cede will result | ||
471 | * in this thread going dormant, if the | ||
472 | * partner thread is still doing work. | ||
473 | * Thread wakes up if partner goes idle, | ||
474 | * an interrupt is presented, or a prod | ||
475 | * occurs. Returning from the cede | ||
476 | * enables external interrupts. | ||
477 | */ | ||
478 | if (!need_resched()) | ||
479 | cede_processor(); | ||
480 | else | ||
481 | local_irq_enable(); | ||
482 | } else { | ||
483 | /* | ||
484 | * Give the HV an opportunity at the | ||
485 | * processor, since we are not doing | ||
486 | * any work. | ||
487 | */ | ||
488 | poll_pending(); | ||
489 | } | ||
490 | } | ||
491 | |||
492 | clear_thread_flag(TIF_POLLING_NRFLAG); | ||
493 | } else { | ||
494 | set_need_resched(); | ||
495 | } | ||
496 | |||
497 | HMT_medium(); | ||
498 | lpaca->lppaca.idle = 0; | ||
499 | schedule(); | ||
500 | if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) | ||
501 | cpu_die(); | ||
502 | } | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int shared_idle(void) | ||
507 | { | ||
508 | struct paca_struct *lpaca = get_paca(); | ||
509 | unsigned int cpu = smp_processor_id(); | ||
510 | |||
511 | while (1) { | ||
512 | /* | ||
513 | * Indicate to the HV that we are idle. Now would be | ||
514 | * a good time to find other work to dispatch. | ||
515 | */ | ||
516 | lpaca->lppaca.idle = 1; | ||
517 | |||
518 | while (!need_resched() && !cpu_is_offline(cpu)) { | ||
519 | local_irq_disable(); | ||
520 | |||
521 | /* | ||
522 | * Yield the processor to the hypervisor. We return if | ||
523 | * an external interrupt occurs (which are driven prior | ||
524 | * to returning here) or if a prod occurs from another | ||
525 | * processor. When returning here, external interrupts | ||
526 | * are enabled. | ||
527 | * | ||
528 | * Check need_resched() again with interrupts disabled | ||
529 | * to avoid a race. | ||
530 | */ | ||
531 | if (!need_resched()) | ||
532 | cede_processor(); | ||
533 | else | ||
534 | local_irq_enable(); | ||
535 | } | ||
536 | |||
537 | HMT_medium(); | ||
538 | lpaca->lppaca.idle = 0; | ||
539 | schedule(); | ||
540 | if (cpu_is_offline(smp_processor_id()) && | ||
541 | system_state == SYSTEM_RUNNING) | ||
542 | cpu_die(); | ||
543 | } | ||
544 | |||
545 | return 0; | ||
546 | } | ||
547 | |||
421 | struct machdep_calls __initdata pSeries_md = { | 548 | struct machdep_calls __initdata pSeries_md = { |
422 | .probe = pSeries_probe, | 549 | .probe = pSeries_probe, |
423 | .setup_arch = pSeries_setup_arch, | 550 | .setup_arch = pSeries_setup_arch, |