|
@@ -418,6 +418,133 @@ static int __init pSeries_probe(int platform)
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
|
|
|
|
+
|
|
|
|
+int dedicated_idle(void)
|
|
|
|
+{
|
|
|
|
+ long oldval;
|
|
|
|
+ struct paca_struct *lpaca = get_paca(), *ppaca;
|
|
|
|
+ unsigned long start_snooze;
|
|
|
|
+ unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
|
|
|
|
+ unsigned int cpu = smp_processor_id();
|
|
|
|
+
|
|
|
|
+ ppaca = &paca[cpu ^ 1];
|
|
|
|
+
|
|
|
|
+ while (1) {
|
|
|
|
+ /*
|
|
|
|
+ * Indicate to the HV that we are idle. Now would be
|
|
|
|
+ * a good time to find other work to dispatch.
|
|
|
|
+ */
|
|
|
|
+ lpaca->lppaca.idle = 1;
|
|
|
|
+
|
|
|
|
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
|
|
|
|
+ if (!oldval) {
|
|
|
|
+ set_thread_flag(TIF_POLLING_NRFLAG);
|
|
|
|
+ start_snooze = __get_tb() +
|
|
|
|
+ *smt_snooze_delay * tb_ticks_per_usec;
|
|
|
|
+ while (!need_resched() && !cpu_is_offline(cpu)) {
|
|
|
|
+ /*
|
|
|
|
+ * Go into low thread priority and possibly
|
|
|
|
+ * low power mode.
|
|
|
|
+ */
|
|
|
|
+ HMT_low();
|
|
|
|
+ HMT_very_low();
|
|
|
|
+
|
|
|
|
+ if (*smt_snooze_delay == 0 ||
|
|
|
|
+ __get_tb() < start_snooze)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ HMT_medium();
|
|
|
|
+
|
|
|
|
+ if (!(ppaca->lppaca.idle)) {
|
|
|
|
+ local_irq_disable();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * We are about to sleep the thread
|
|
|
|
+ * and so wont be polling any
|
|
|
|
+ * more.
|
|
|
|
+ */
|
|
|
|
+ clear_thread_flag(TIF_POLLING_NRFLAG);
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * SMT dynamic mode. Cede will result
|
|
|
|
+ * in this thread going dormant, if the
|
|
|
|
+ * partner thread is still doing work.
|
|
|
|
+ * Thread wakes up if partner goes idle,
|
|
|
|
+ * an interrupt is presented, or a prod
|
|
|
|
+ * occurs. Returning from the cede
|
|
|
|
+ * enables external interrupts.
|
|
|
|
+ */
|
|
|
|
+ if (!need_resched())
|
|
|
|
+ cede_processor();
|
|
|
|
+ else
|
|
|
|
+ local_irq_enable();
|
|
|
|
+ } else {
|
|
|
|
+ /*
|
|
|
|
+ * Give the HV an opportunity at the
|
|
|
|
+ * processor, since we are not doing
|
|
|
|
+ * any work.
|
|
|
|
+ */
|
|
|
|
+ poll_pending();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ clear_thread_flag(TIF_POLLING_NRFLAG);
|
|
|
|
+ } else {
|
|
|
|
+ set_need_resched();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ HMT_medium();
|
|
|
|
+ lpaca->lppaca.idle = 0;
|
|
|
|
+ schedule();
|
|
|
|
+ if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
|
|
|
|
+ cpu_die();
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int shared_idle(void)
|
|
|
|
+{
|
|
|
|
+ struct paca_struct *lpaca = get_paca();
|
|
|
|
+ unsigned int cpu = smp_processor_id();
|
|
|
|
+
|
|
|
|
+ while (1) {
|
|
|
|
+ /*
|
|
|
|
+ * Indicate to the HV that we are idle. Now would be
|
|
|
|
+ * a good time to find other work to dispatch.
|
|
|
|
+ */
|
|
|
|
+ lpaca->lppaca.idle = 1;
|
|
|
|
+
|
|
|
|
+ while (!need_resched() && !cpu_is_offline(cpu)) {
|
|
|
|
+ local_irq_disable();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Yield the processor to the hypervisor. We return if
|
|
|
|
+ * an external interrupt occurs (which are driven prior
|
|
|
|
+ * to returning here) or if a prod occurs from another
|
|
|
|
+ * processor. When returning here, external interrupts
|
|
|
|
+ * are enabled.
|
|
|
|
+ *
|
|
|
|
+ * Check need_resched() again with interrupts disabled
|
|
|
|
+ * to avoid a race.
|
|
|
|
+ */
|
|
|
|
+ if (!need_resched())
|
|
|
|
+ cede_processor();
|
|
|
|
+ else
|
|
|
|
+ local_irq_enable();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ HMT_medium();
|
|
|
|
+ lpaca->lppaca.idle = 0;
|
|
|
|
+ schedule();
|
|
|
|
+ if (cpu_is_offline(smp_processor_id()) &&
|
|
|
|
+ system_state == SYSTEM_RUNNING)
|
|
|
|
+ cpu_die();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
struct machdep_calls __initdata pSeries_md = {
|
|
struct machdep_calls __initdata pSeries_md = {
|
|
.probe = pSeries_probe,
|
|
.probe = pSeries_probe,
|
|
.setup_arch = pSeries_setup_arch,
|
|
.setup_arch = pSeries_setup_arch,
|