aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc64/kernel/pSeries_setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc64/kernel/pSeries_setup.c')
-rw-r--r--arch/ppc64/kernel/pSeries_setup.c127
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
421DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
422
423int 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
506static 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
421struct machdep_calls __initdata pSeries_md = { 548struct 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,