Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/mips/kernel/idle.c
26439 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* MIPS idle loop and WAIT instruction support.
4
*
5
* Copyright (C) xxxx the Anonymous
6
* Copyright (C) 1994 - 2006 Ralf Baechle
7
* Copyright (C) 2003, 2004 Maciej W. Rozycki
8
* Copyright (C) 2001, 2004, 2011, 2012 MIPS Technologies, Inc.
9
*/
10
#include <linux/cpu.h>
11
#include <linux/export.h>
12
#include <linux/init.h>
13
#include <linux/irqflags.h>
14
#include <linux/printk.h>
15
#include <linux/sched.h>
16
#include <asm/cpu.h>
17
#include <asm/cpu-info.h>
18
#include <asm/cpu-type.h>
19
#include <asm/idle.h>
20
#include <asm/mipsregs.h>
21
22
/*
23
* Not all of the MIPS CPUs have the "wait" instruction available. Moreover,
24
* the implementation of the "wait" feature differs between CPU families. This
25
* points to the function that implements CPU specific wait.
26
* The wait instruction stops the pipeline and reduces the power consumption of
27
* the CPU very much.
28
*/
29
void (*cpu_wait)(void);
30
EXPORT_SYMBOL(cpu_wait);
31
32
static void __cpuidle r3081_wait(void)
33
{
34
unsigned long cfg = read_c0_conf();
35
write_c0_conf(cfg | R30XX_CONF_HALT);
36
}
37
38
/*
39
* This variant is preferable as it allows testing need_resched and going to
40
* sleep depending on the outcome atomically. Unfortunately the "It is
41
* implementation-dependent whether the pipeline restarts when a non-enabled
42
* interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
43
* using this version a gamble.
44
*/
45
void __cpuidle r4k_wait_irqoff(void)
46
{
47
if (!need_resched())
48
__asm__(
49
" .set push \n"
50
" .set arch=r4000 \n"
51
" wait \n"
52
" .set pop \n");
53
}
54
55
/*
56
* The RM7000 variant has to handle erratum 38. The workaround is to not
57
* have any pending stores when the WAIT instruction is executed.
58
*/
59
static void __cpuidle rm7k_wait_irqoff(void)
60
{
61
if (!need_resched())
62
__asm__(
63
" .set push \n"
64
" .set arch=r4000 \n"
65
" .set noat \n"
66
" mfc0 $1, $12 \n"
67
" sync \n"
68
" mtc0 $1, $12 # stalls until W stage \n"
69
" wait \n"
70
" mtc0 $1, $12 # stalls until W stage \n"
71
" .set pop \n");
72
}
73
74
/*
75
* Au1 'wait' is only useful when the 32kHz counter is used as timer,
76
* since coreclock (and the cp0 counter) stops upon executing it. Only an
77
* interrupt can wake it, so they must be enabled before entering idle modes.
78
*/
79
static void __cpuidle au1k_wait(void)
80
{
81
unsigned long c0status = read_c0_status() | 1; /* irqs on */
82
83
__asm__(
84
" .set push \n"
85
" .set arch=r4000 \n"
86
" cache 0x14, 0(%0) \n"
87
" cache 0x14, 32(%0) \n"
88
" sync \n"
89
" mtc0 %1, $12 \n" /* wr c0status */
90
" wait \n"
91
" nop \n"
92
" nop \n"
93
" nop \n"
94
" nop \n"
95
" .set pop \n"
96
: : "r" (au1k_wait), "r" (c0status));
97
98
raw_local_irq_disable();
99
}
100
101
static int __initdata nowait;
102
103
static int __init wait_disable(char *s)
104
{
105
nowait = 1;
106
107
return 1;
108
}
109
110
__setup("nowait", wait_disable);
111
112
void __init check_wait(void)
113
{
114
struct cpuinfo_mips *c = &current_cpu_data;
115
116
if (nowait) {
117
printk("Wait instruction disabled.\n");
118
return;
119
}
120
121
/*
122
* MIPSr6 specifies that masked interrupts should unblock an executing
123
* wait instruction, and thus that it is safe for us to use
124
* r4k_wait_irqoff. Yippee!
125
*/
126
if (cpu_has_mips_r6) {
127
cpu_wait = r4k_wait_irqoff;
128
return;
129
}
130
131
switch (current_cpu_type()) {
132
case CPU_R3081:
133
case CPU_R3081E:
134
cpu_wait = r3081_wait;
135
break;
136
case CPU_R4200:
137
/* case CPU_R4300: */
138
case CPU_R4600:
139
case CPU_R4640:
140
case CPU_R4650:
141
case CPU_R4700:
142
case CPU_R5000:
143
case CPU_R5500:
144
case CPU_NEVADA:
145
case CPU_4KC:
146
case CPU_4KEC:
147
case CPU_4KSC:
148
case CPU_5KC:
149
case CPU_5KE:
150
case CPU_25KF:
151
case CPU_PR4450:
152
case CPU_BMIPS3300:
153
case CPU_BMIPS4350:
154
case CPU_BMIPS4380:
155
case CPU_CAVIUM_OCTEON:
156
case CPU_CAVIUM_OCTEON_PLUS:
157
case CPU_CAVIUM_OCTEON2:
158
case CPU_CAVIUM_OCTEON3:
159
case CPU_XBURST:
160
case CPU_LOONGSON32:
161
cpu_wait = r4k_wait;
162
break;
163
case CPU_LOONGSON64:
164
if ((c->processor_id & (PRID_IMP_MASK | PRID_REV_MASK)) >=
165
(PRID_IMP_LOONGSON_64C | PRID_REV_LOONGSON3A_R2_0) ||
166
(c->processor_id & PRID_IMP_MASK) == PRID_IMP_LOONGSON_64R)
167
cpu_wait = r4k_wait;
168
break;
169
170
case CPU_BMIPS5000:
171
cpu_wait = r4k_wait_irqoff;
172
break;
173
case CPU_RM7000:
174
cpu_wait = rm7k_wait_irqoff;
175
break;
176
177
case CPU_PROAPTIV:
178
case CPU_P5600:
179
/*
180
* Incoming Fast Debug Channel (FDC) data during a wait
181
* instruction causes the wait never to resume, even if an
182
* interrupt is received. Avoid using wait at all if FDC data is
183
* likely to be received.
184
*/
185
if (IS_ENABLED(CONFIG_MIPS_EJTAG_FDC_TTY))
186
break;
187
fallthrough;
188
case CPU_M14KC:
189
case CPU_M14KEC:
190
case CPU_24K:
191
case CPU_34K:
192
case CPU_1004K:
193
case CPU_1074K:
194
case CPU_INTERAPTIV:
195
case CPU_M5150:
196
case CPU_QEMU_GENERIC:
197
cpu_wait = r4k_wait;
198
if (read_c0_config7() & MIPS_CONF7_WII)
199
cpu_wait = r4k_wait_irqoff;
200
break;
201
202
case CPU_74K:
203
cpu_wait = r4k_wait;
204
if ((c->processor_id & 0xff) >= PRID_REV_ENCODE_332(2, 1, 0))
205
cpu_wait = r4k_wait_irqoff;
206
break;
207
208
case CPU_TX49XX:
209
cpu_wait = r4k_wait_irqoff;
210
break;
211
case CPU_ALCHEMY:
212
cpu_wait = au1k_wait;
213
break;
214
case CPU_20KC:
215
/*
216
* WAIT on Rev1.0 has E1, E2, E3 and E16.
217
* WAIT on Rev2.0 and Rev3.0 has E16.
218
* Rev3.1 WAIT is nop, why bother
219
*/
220
if ((c->processor_id & 0xff) <= 0x64)
221
break;
222
223
/*
224
* Another rev is incrementing c0_count at a reduced clock
225
* rate while in WAIT mode. So we basically have the choice
226
* between using the cp0 timer as clocksource or avoiding
227
* the WAIT instruction. Until more details are known,
228
* disable the use of WAIT for 20Kc entirely.
229
cpu_wait = r4k_wait;
230
*/
231
break;
232
default:
233
break;
234
}
235
}
236
237
__cpuidle void arch_cpu_idle(void)
238
{
239
if (cpu_wait)
240
cpu_wait();
241
}
242
243
#ifdef CONFIG_CPU_IDLE
244
245
__cpuidle int mips_cpuidle_wait_enter(struct cpuidle_device *dev,
246
struct cpuidle_driver *drv, int index)
247
{
248
arch_cpu_idle();
249
return index;
250
}
251
252
#endif
253
254