idle.c 3.04 KB
Newer Older
1
/*
2
 * idle.c
3 4 5 6 7 8
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version
 * 2 of the License, or (at your option) any later version.
 */
9

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/slab.h>

#include <asm/pgtable.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/mmu.h>
#include <asm/cache.h>
#include <asm/time.h>
30 31 32

#ifdef CONFIG_PPC_ISERIES

33 34 35 36 37 38 39 40 41 42 43 44
#include <asm/iSeries/LparData.h>
#include <asm/iSeries/HvCall.h>
#include <asm/iSeries/ItLpQueue.h>

unsigned long maxYieldTime = 0;
unsigned long minYieldTime = 0xffffffffffffffffUL;

static void yield_shared_processor(void)
{
	unsigned long tb;
	unsigned long yieldTime;

45 46 47 48
	HvCall_setEnabledInterrupts(HvCall_MaskIPI |
				    HvCall_MaskLpEvent |
				    HvCall_MaskLpProd |
				    HvCall_MaskTimeout);
49 50 51

	tb = get_tb();
	/* Compute future tb value when yield should expire */
52
	HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
53 54

	yieldTime = get_tb() - tb;
55
	if (yieldTime > maxYieldTime)
56 57
		maxYieldTime = yieldTime;

58
	if (yieldTime < minYieldTime)
59 60
		minYieldTime = yieldTime;
	
61 62
	/*
	 * The decrementer stops during the yield.  Force a fake decrementer
63 64
	 * here and let the timer_interrupt code sort out the actual time.
	 */
65
	get_paca()->xLpPaca.xIntDword.xFields.xDecrInt = 1;
66 67 68
	process_iSeries_events();
}

69
int cpu_idle(void)
70
{
Anton Blanchard's avatar
Anton Blanchard committed
71
	struct paca_struct *lpaca;
72 73 74
	long oldval;
	unsigned long CTRL;

Anton Blanchard's avatar
Anton Blanchard committed
75 76
#warning fix iseries run light
#if 0
77 78 79 80 81
	/* ensure iSeries run light will be out when idle */
	current->thread.flags &= ~PPC_FLAG_RUN_LIGHT;
	CTRL = mfspr(CTRLF);
	CTRL &= ~RUNLATCH;
	mtspr(CTRLT, CTRL);
Anton Blanchard's avatar
Anton Blanchard committed
82
#endif
83

84
	lpaca = get_paca();
85

86
	while (1) {
87 88
		if (lpaca->xLpPaca.xSharedProc) {
			if (ItLpQueue_isLpIntPending(lpaca->lpQueuePtr))
89 90 91
				process_iSeries_events();
			if (!need_resched())
				yield_shared_processor();
92 93 94 95
		} else {
			oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);

			if (!oldval) {
96
				set_thread_flag(TIF_POLLING_NRFLAG);
97 98

				while (!need_resched()) {
99
					HMT_medium();
100
					if (ItLpQueue_isLpIntPending(lpaca->lpQueuePtr))
101 102 103
						process_iSeries_events();
					HMT_low();
				}
104 105

				HMT_medium();
106
				clear_thread_flag(TIF_POLLING_NRFLAG);
107 108
			} else {
				set_need_resched();
109 110
			}
		}
111

112
		if (need_resched())
113 114
			schedule();
	}
115

116 117 118
	return 0;
}

119 120
#else /* CONFIG_PPC_ISERIES */

121 122
int cpu_idle(void)
{
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	long oldval;

	while (1) {
		oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);

		if (!oldval) {
			set_thread_flag(TIF_POLLING_NRFLAG);

			while (!need_resched()) {
				barrier();
				HMT_low();
			}

			HMT_medium();
			clear_thread_flag(TIF_POLLING_NRFLAG);
		} else {
			set_need_resched();
		}

		schedule();
	}

	return 0;
146
}
147 148

#endif /* CONFIG_PPC_ISERIES */
149 150 151 152 153

void default_idle(void)
{
	barrier();
}