diff options
Diffstat (limited to 'arch')
51 files changed, 681 insertions, 396 deletions
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index 3b0a9538093c..c1b737097c95 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile | |||
@@ -98,7 +98,6 @@ obj-y += leds.o | |||
98 | # Power Management | 98 | # Power Management |
99 | obj-$(CONFIG_PM) += pm.o | 99 | obj-$(CONFIG_PM) += pm.o |
100 | obj-$(CONFIG_AT91_SLOW_CLOCK) += pm_slowclock.o | 100 | obj-$(CONFIG_AT91_SLOW_CLOCK) += pm_slowclock.o |
101 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | ||
102 | 101 | ||
103 | ifeq ($(CONFIG_PM_DEBUG),y) | 102 | ifeq ($(CONFIG_PM_DEBUG),y) |
104 | CFLAGS_pm.o += -DDEBUG | 103 | CFLAGS_pm.o += -DDEBUG |
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 4aad93d54d6f..25805f2f6010 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "generic.h" | 27 | #include "generic.h" |
28 | #include "clock.h" | 28 | #include "clock.h" |
29 | #include "sam9_smc.h" | 29 | #include "sam9_smc.h" |
30 | #include "pm.h" | ||
30 | 31 | ||
31 | /* -------------------------------------------------------------------- | 32 | /* -------------------------------------------------------------------- |
32 | * Clocks | 33 | * Clocks |
@@ -327,6 +328,7 @@ static void __init at91rm9200_ioremap_registers(void) | |||
327 | { | 328 | { |
328 | at91rm9200_ioremap_st(AT91RM9200_BASE_ST); | 329 | at91rm9200_ioremap_st(AT91RM9200_BASE_ST); |
329 | at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256); | 330 | at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256); |
331 | at91_pm_set_standby(at91rm9200_standby); | ||
330 | } | 332 | } |
331 | 333 | ||
332 | static void __init at91rm9200_initialize(void) | 334 | static void __init at91rm9200_initialize(void) |
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 5de6074b4f4f..f8629a3fa245 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "generic.h" | 28 | #include "generic.h" |
29 | #include "clock.h" | 29 | #include "clock.h" |
30 | #include "sam9_smc.h" | 30 | #include "sam9_smc.h" |
31 | #include "pm.h" | ||
31 | 32 | ||
32 | /* -------------------------------------------------------------------- | 33 | /* -------------------------------------------------------------------- |
33 | * Clocks | 34 | * Clocks |
@@ -342,6 +343,7 @@ static void __init at91sam9260_ioremap_registers(void) | |||
342 | at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT); | 343 | at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT); |
343 | at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC); | 344 | at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC); |
344 | at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX); | 345 | at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX); |
346 | at91_pm_set_standby(at91sam9_sdram_standby); | ||
345 | } | 347 | } |
346 | 348 | ||
347 | static void __init at91sam9260_initialize(void) | 349 | static void __init at91sam9260_initialize(void) |
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 0e0793241ab7..1f3867a17a28 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "generic.h" | 27 | #include "generic.h" |
28 | #include "clock.h" | 28 | #include "clock.h" |
29 | #include "sam9_smc.h" | 29 | #include "sam9_smc.h" |
30 | #include "pm.h" | ||
30 | 31 | ||
31 | /* -------------------------------------------------------------------- | 32 | /* -------------------------------------------------------------------- |
32 | * Clocks | 33 | * Clocks |
@@ -284,6 +285,7 @@ static void __init at91sam9261_ioremap_registers(void) | |||
284 | at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT); | 285 | at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT); |
285 | at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC); | 286 | at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC); |
286 | at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX); | 287 | at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX); |
288 | at91_pm_set_standby(at91sam9_sdram_standby); | ||
287 | } | 289 | } |
288 | 290 | ||
289 | static void __init at91sam9261_initialize(void) | 291 | static void __init at91sam9261_initialize(void) |
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 6ce7d1850893..90d455d294a1 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "generic.h" | 26 | #include "generic.h" |
27 | #include "clock.h" | 27 | #include "clock.h" |
28 | #include "sam9_smc.h" | 28 | #include "sam9_smc.h" |
29 | #include "pm.h" | ||
29 | 30 | ||
30 | /* -------------------------------------------------------------------- | 31 | /* -------------------------------------------------------------------- |
31 | * Clocks | 32 | * Clocks |
@@ -321,6 +322,7 @@ static void __init at91sam9263_ioremap_registers(void) | |||
321 | at91sam9_ioremap_smc(0, AT91SAM9263_BASE_SMC0); | 322 | at91sam9_ioremap_smc(0, AT91SAM9263_BASE_SMC0); |
322 | at91sam9_ioremap_smc(1, AT91SAM9263_BASE_SMC1); | 323 | at91sam9_ioremap_smc(1, AT91SAM9263_BASE_SMC1); |
323 | at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX); | 324 | at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX); |
325 | at91_pm_set_standby(at91sam9_sdram_standby); | ||
324 | } | 326 | } |
325 | 327 | ||
326 | static void __init at91sam9263_initialize(void) | 328 | static void __init at91sam9263_initialize(void) |
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 474ee04d24b9..e9bf0b8f40eb 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "generic.h" | 26 | #include "generic.h" |
27 | #include "clock.h" | 27 | #include "clock.h" |
28 | #include "sam9_smc.h" | 28 | #include "sam9_smc.h" |
29 | #include "pm.h" | ||
29 | 30 | ||
30 | /* -------------------------------------------------------------------- | 31 | /* -------------------------------------------------------------------- |
31 | * Clocks | 32 | * Clocks |
@@ -370,6 +371,7 @@ static void __init at91sam9g45_ioremap_registers(void) | |||
370 | at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT); | 371 | at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT); |
371 | at91sam9_ioremap_smc(0, AT91SAM9G45_BASE_SMC); | 372 | at91sam9_ioremap_smc(0, AT91SAM9G45_BASE_SMC); |
372 | at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX); | 373 | at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX); |
374 | at91_pm_set_standby(at91_ddr_standby); | ||
373 | } | 375 | } |
374 | 376 | ||
375 | static void __init at91sam9g45_initialize(void) | 377 | static void __init at91sam9g45_initialize(void) |
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index d4ec0d9a9872..88995af09c04 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "generic.h" | 27 | #include "generic.h" |
28 | #include "clock.h" | 28 | #include "clock.h" |
29 | #include "sam9_smc.h" | 29 | #include "sam9_smc.h" |
30 | #include "pm.h" | ||
30 | 31 | ||
31 | /* -------------------------------------------------------------------- | 32 | /* -------------------------------------------------------------------- |
32 | * Clocks | 33 | * Clocks |
@@ -287,6 +288,7 @@ static void __init at91sam9rl_ioremap_registers(void) | |||
287 | at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT); | 288 | at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT); |
288 | at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC); | 289 | at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC); |
289 | at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX); | 290 | at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX); |
291 | at91_pm_set_standby(at91sam9_sdram_standby); | ||
290 | } | 292 | } |
291 | 293 | ||
292 | static void __init at91sam9rl_initialize(void) | 294 | static void __init at91sam9rl_initialize(void) |
diff --git a/arch/arm/mach-at91/cpuidle.c b/arch/arm/mach-at91/cpuidle.c deleted file mode 100644 index 4ec6a6d9b9be..000000000000 --- a/arch/arm/mach-at91/cpuidle.c +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | /* | ||
2 | * based on arch/arm/mach-kirkwood/cpuidle.c | ||
3 | * | ||
4 | * CPU idle support for AT91 SoC | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | * | ||
10 | * The cpu idle uses wait-for-interrupt and RAM self refresh in order | ||
11 | * to implement two idle states - | ||
12 | * #1 wait-for-interrupt | ||
13 | * #2 wait-for-interrupt and RAM self refresh | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/cpuidle.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <asm/proc-fns.h> | ||
23 | #include <asm/cpuidle.h> | ||
24 | #include <mach/cpu.h> | ||
25 | |||
26 | #include "pm.h" | ||
27 | |||
28 | #define AT91_MAX_STATES 2 | ||
29 | |||
30 | /* Actual code that puts the SoC in different idle states */ | ||
31 | static int at91_enter_idle(struct cpuidle_device *dev, | ||
32 | struct cpuidle_driver *drv, | ||
33 | int index) | ||
34 | { | ||
35 | if (cpu_is_at91rm9200()) | ||
36 | at91rm9200_standby(); | ||
37 | else if (cpu_is_at91sam9g45()) | ||
38 | at91sam9g45_standby(); | ||
39 | else if (cpu_is_at91sam9263()) | ||
40 | at91sam9263_standby(); | ||
41 | else | ||
42 | at91sam9_standby(); | ||
43 | |||
44 | return index; | ||
45 | } | ||
46 | |||
47 | static struct cpuidle_driver at91_idle_driver = { | ||
48 | .name = "at91_idle", | ||
49 | .owner = THIS_MODULE, | ||
50 | .states[0] = ARM_CPUIDLE_WFI_STATE, | ||
51 | .states[1] = { | ||
52 | .enter = at91_enter_idle, | ||
53 | .exit_latency = 10, | ||
54 | .target_residency = 10000, | ||
55 | .flags = CPUIDLE_FLAG_TIME_VALID, | ||
56 | .name = "RAM_SR", | ||
57 | .desc = "WFI and DDR Self Refresh", | ||
58 | }, | ||
59 | .state_count = AT91_MAX_STATES, | ||
60 | }; | ||
61 | |||
62 | /* Initialize CPU idle by registering the idle states */ | ||
63 | static int __init at91_init_cpuidle(void) | ||
64 | { | ||
65 | return cpuidle_register(&at91_idle_driver, NULL); | ||
66 | } | ||
67 | |||
68 | device_initcall(at91_init_cpuidle); | ||
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 15afb5d9271f..9986542e8060 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c | |||
@@ -39,6 +39,8 @@ | |||
39 | #include "at91_rstc.h" | 39 | #include "at91_rstc.h" |
40 | #include "at91_shdwc.h" | 40 | #include "at91_shdwc.h" |
41 | 41 | ||
42 | static void (*at91_pm_standby)(void); | ||
43 | |||
42 | static void __init show_reset_status(void) | 44 | static void __init show_reset_status(void) |
43 | { | 45 | { |
44 | static char reset[] __initdata = "reset"; | 46 | static char reset[] __initdata = "reset"; |
@@ -266,14 +268,8 @@ static int at91_pm_enter(suspend_state_t state) | |||
266 | * For ARM 926 based chips, this requirement is weaker | 268 | * For ARM 926 based chips, this requirement is weaker |
267 | * as at91sam9 can access a RAM in self-refresh mode. | 269 | * as at91sam9 can access a RAM in self-refresh mode. |
268 | */ | 270 | */ |
269 | if (cpu_is_at91rm9200()) | 271 | if (at91_pm_standby) |
270 | at91rm9200_standby(); | 272 | at91_pm_standby(); |
271 | else if (cpu_is_at91sam9g45()) | ||
272 | at91sam9g45_standby(); | ||
273 | else if (cpu_is_at91sam9263()) | ||
274 | at91sam9263_standby(); | ||
275 | else | ||
276 | at91sam9_standby(); | ||
277 | break; | 273 | break; |
278 | 274 | ||
279 | case PM_SUSPEND_ON: | 275 | case PM_SUSPEND_ON: |
@@ -314,6 +310,18 @@ static const struct platform_suspend_ops at91_pm_ops = { | |||
314 | .end = at91_pm_end, | 310 | .end = at91_pm_end, |
315 | }; | 311 | }; |
316 | 312 | ||
313 | static struct platform_device at91_cpuidle_device = { | ||
314 | .name = "cpuidle-at91", | ||
315 | }; | ||
316 | |||
317 | void at91_pm_set_standby(void (*at91_standby)(void)) | ||
318 | { | ||
319 | if (at91_standby) { | ||
320 | at91_cpuidle_device.dev.platform_data = at91_standby; | ||
321 | at91_pm_standby = at91_standby; | ||
322 | } | ||
323 | } | ||
324 | |||
317 | static int __init at91_pm_init(void) | 325 | static int __init at91_pm_init(void) |
318 | { | 326 | { |
319 | #ifdef CONFIG_AT91_SLOW_CLOCK | 327 | #ifdef CONFIG_AT91_SLOW_CLOCK |
@@ -325,6 +333,9 @@ static int __init at91_pm_init(void) | |||
325 | /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ | 333 | /* AT91RM9200 SDRAM low-power mode cannot be used with self-refresh. */ |
326 | if (cpu_is_at91rm9200()) | 334 | if (cpu_is_at91rm9200()) |
327 | at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0); | 335 | at91_ramc_write(0, AT91RM9200_SDRAMC_LPR, 0); |
336 | |||
337 | if (at91_cpuidle_device.dev.platform_data) | ||
338 | platform_device_register(&at91_cpuidle_device); | ||
328 | 339 | ||
329 | suspend_set_ops(&at91_pm_ops); | 340 | suspend_set_ops(&at91_pm_ops); |
330 | 341 | ||
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h index 2f5908f0b8c5..3ed190ce062b 100644 --- a/arch/arm/mach-at91/pm.h +++ b/arch/arm/mach-at91/pm.h | |||
@@ -11,9 +11,13 @@ | |||
11 | #ifndef __ARCH_ARM_MACH_AT91_PM | 11 | #ifndef __ARCH_ARM_MACH_AT91_PM |
12 | #define __ARCH_ARM_MACH_AT91_PM | 12 | #define __ARCH_ARM_MACH_AT91_PM |
13 | 13 | ||
14 | #include <asm/proc-fns.h> | ||
15 | |||
14 | #include <mach/at91_ramc.h> | 16 | #include <mach/at91_ramc.h> |
15 | #include <mach/at91rm9200_sdramc.h> | 17 | #include <mach/at91rm9200_sdramc.h> |
16 | 18 | ||
19 | extern void at91_pm_set_standby(void (*at91_standby)(void)); | ||
20 | |||
17 | /* | 21 | /* |
18 | * The AT91RM9200 goes into self-refresh mode with this command, and will | 22 | * The AT91RM9200 goes into self-refresh mode with this command, and will |
19 | * terminate self-refresh automatically on the next SDRAM access. | 23 | * terminate self-refresh automatically on the next SDRAM access. |
@@ -45,16 +49,18 @@ static inline void at91rm9200_standby(void) | |||
45 | /* We manage both DDRAM/SDRAM controllers, we need more than one value to | 49 | /* We manage both DDRAM/SDRAM controllers, we need more than one value to |
46 | * remember. | 50 | * remember. |
47 | */ | 51 | */ |
48 | static inline void at91sam9g45_standby(void) | 52 | static inline void at91_ddr_standby(void) |
49 | { | 53 | { |
50 | /* Those two values allow us to delay self-refresh activation | 54 | /* Those two values allow us to delay self-refresh activation |
51 | * to the maximum. */ | 55 | * to the maximum. */ |
52 | u32 lpr0, lpr1; | 56 | u32 lpr0, lpr1 = 0; |
53 | u32 saved_lpr0, saved_lpr1; | 57 | u32 saved_lpr0, saved_lpr1 = 0; |
54 | 58 | ||
55 | saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); | 59 | if (at91_ramc_base[1]) { |
56 | lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; | 60 | saved_lpr1 = at91_ramc_read(1, AT91_DDRSDRC_LPR); |
57 | lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; | 61 | lpr1 = saved_lpr1 & ~AT91_DDRSDRC_LPCB; |
62 | lpr1 |= AT91_DDRSDRC_LPCB_SELF_REFRESH; | ||
63 | } | ||
58 | 64 | ||
59 | saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR); | 65 | saved_lpr0 = at91_ramc_read(0, AT91_DDRSDRC_LPR); |
60 | lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB; | 66 | lpr0 = saved_lpr0 & ~AT91_DDRSDRC_LPCB; |
@@ -62,25 +68,29 @@ static inline void at91sam9g45_standby(void) | |||
62 | 68 | ||
63 | /* self-refresh mode now */ | 69 | /* self-refresh mode now */ |
64 | at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); | 70 | at91_ramc_write(0, AT91_DDRSDRC_LPR, lpr0); |
65 | at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); | 71 | if (at91_ramc_base[1]) |
72 | at91_ramc_write(1, AT91_DDRSDRC_LPR, lpr1); | ||
66 | 73 | ||
67 | cpu_do_idle(); | 74 | cpu_do_idle(); |
68 | 75 | ||
69 | at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); | 76 | at91_ramc_write(0, AT91_DDRSDRC_LPR, saved_lpr0); |
70 | at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); | 77 | if (at91_ramc_base[1]) |
78 | at91_ramc_write(1, AT91_DDRSDRC_LPR, saved_lpr1); | ||
71 | } | 79 | } |
72 | 80 | ||
73 | /* We manage both DDRAM/SDRAM controllers, we need more than one value to | 81 | /* We manage both DDRAM/SDRAM controllers, we need more than one value to |
74 | * remember. | 82 | * remember. |
75 | */ | 83 | */ |
76 | static inline void at91sam9263_standby(void) | 84 | static inline void at91sam9_sdram_standby(void) |
77 | { | 85 | { |
78 | u32 lpr0, lpr1; | 86 | u32 lpr0, lpr1 = 0; |
79 | u32 saved_lpr0, saved_lpr1; | 87 | u32 saved_lpr0, saved_lpr1 = 0; |
80 | 88 | ||
81 | saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); | 89 | if (at91_ramc_base[1]) { |
82 | lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; | 90 | saved_lpr1 = at91_ramc_read(1, AT91_SDRAMC_LPR); |
83 | lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; | 91 | lpr1 = saved_lpr1 & ~AT91_SDRAMC_LPCB; |
92 | lpr1 |= AT91_SDRAMC_LPCB_SELF_REFRESH; | ||
93 | } | ||
84 | 94 | ||
85 | saved_lpr0 = at91_ramc_read(0, AT91_SDRAMC_LPR); | 95 | saved_lpr0 = at91_ramc_read(0, AT91_SDRAMC_LPR); |
86 | lpr0 = saved_lpr0 & ~AT91_SDRAMC_LPCB; | 96 | lpr0 = saved_lpr0 & ~AT91_SDRAMC_LPCB; |
@@ -88,27 +98,14 @@ static inline void at91sam9263_standby(void) | |||
88 | 98 | ||
89 | /* self-refresh mode now */ | 99 | /* self-refresh mode now */ |
90 | at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); | 100 | at91_ramc_write(0, AT91_SDRAMC_LPR, lpr0); |
91 | at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); | 101 | if (at91_ramc_base[1]) |
102 | at91_ramc_write(1, AT91_SDRAMC_LPR, lpr1); | ||
92 | 103 | ||
93 | cpu_do_idle(); | 104 | cpu_do_idle(); |
94 | 105 | ||
95 | at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); | 106 | at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr0); |
96 | at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); | 107 | if (at91_ramc_base[1]) |
97 | } | 108 | at91_ramc_write(1, AT91_SDRAMC_LPR, saved_lpr1); |
98 | |||
99 | static inline void at91sam9_standby(void) | ||
100 | { | ||
101 | u32 saved_lpr, lpr; | ||
102 | |||
103 | saved_lpr = at91_ramc_read(0, AT91_SDRAMC_LPR); | ||
104 | |||
105 | lpr = saved_lpr & ~AT91_SDRAMC_LPCB; | ||
106 | at91_ramc_write(0, AT91_SDRAMC_LPR, lpr | | ||
107 | AT91_SDRAMC_LPCB_SELF_REFRESH); | ||
108 | |||
109 | cpu_do_idle(); | ||
110 | |||
111 | at91_ramc_write(0, AT91_SDRAMC_LPR, saved_lpr); | ||
112 | } | 109 | } |
113 | 110 | ||
114 | #endif | 111 | #endif |
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index b17fbcf4d9e8..094b3459c288 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "at91_shdwc.h" | 23 | #include "at91_shdwc.h" |
24 | #include "soc.h" | 24 | #include "soc.h" |
25 | #include "generic.h" | 25 | #include "generic.h" |
26 | #include "pm.h" | ||
26 | 27 | ||
27 | struct at91_init_soc __initdata at91_boot_soc; | 28 | struct at91_init_soc __initdata at91_boot_soc; |
28 | 29 | ||
@@ -376,15 +377,16 @@ static void at91_dt_rstc(void) | |||
376 | } | 377 | } |
377 | 378 | ||
378 | static struct of_device_id ramc_ids[] = { | 379 | static struct of_device_id ramc_ids[] = { |
379 | { .compatible = "atmel,at91rm9200-sdramc" }, | 380 | { .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby }, |
380 | { .compatible = "atmel,at91sam9260-sdramc" }, | 381 | { .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby }, |
381 | { .compatible = "atmel,at91sam9g45-ddramc" }, | 382 | { .compatible = "atmel,at91sam9g45-ddramc", .data = at91_ddr_standby }, |
382 | { /*sentinel*/ } | 383 | { /*sentinel*/ } |
383 | }; | 384 | }; |
384 | 385 | ||
385 | static void at91_dt_ramc(void) | 386 | static void at91_dt_ramc(void) |
386 | { | 387 | { |
387 | struct device_node *np; | 388 | struct device_node *np; |
389 | const struct of_device_id *of_id; | ||
388 | 390 | ||
389 | np = of_find_matching_node(NULL, ramc_ids); | 391 | np = of_find_matching_node(NULL, ramc_ids); |
390 | if (!np) | 392 | if (!np) |
@@ -396,6 +398,12 @@ static void at91_dt_ramc(void) | |||
396 | /* the controller may have 2 banks */ | 398 | /* the controller may have 2 banks */ |
397 | at91_ramc_base[1] = of_iomap(np, 1); | 399 | at91_ramc_base[1] = of_iomap(np, 1); |
398 | 400 | ||
401 | of_id = of_match_node(ramc_ids, np); | ||
402 | if (!of_id) | ||
403 | pr_warn("AT91: ramc no standby function available\n"); | ||
404 | else | ||
405 | at91_pm_set_standby(of_id->data); | ||
406 | |||
399 | of_node_put(np); | 407 | of_node_put(np); |
400 | } | 408 | } |
401 | 409 | ||
diff --git a/arch/arm/mach-davinci/Kconfig b/arch/arm/mach-davinci/Kconfig index e026b19b23ea..a075b3e0c5c7 100644 --- a/arch/arm/mach-davinci/Kconfig +++ b/arch/arm/mach-davinci/Kconfig | |||
@@ -40,7 +40,6 @@ config ARCH_DAVINCI_DA850 | |||
40 | bool "DA850/OMAP-L138/AM18x based system" | 40 | bool "DA850/OMAP-L138/AM18x based system" |
41 | select ARCH_DAVINCI_DA8XX | 41 | select ARCH_DAVINCI_DA8XX |
42 | select ARCH_HAS_CPUFREQ | 42 | select ARCH_HAS_CPUFREQ |
43 | select CPU_FREQ_TABLE | ||
44 | select CP_INTC | 43 | select CP_INTC |
45 | 44 | ||
46 | config ARCH_DAVINCI_DA8XX | 45 | config ARCH_DAVINCI_DA8XX |
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index a4e7ba828810..61d2906ccefb 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/of_address.h> | 28 | #include <linux/of_address.h> |
29 | #include <linux/irqchip/arm-gic.h> | 29 | #include <linux/irqchip/arm-gic.h> |
30 | #include <linux/irqchip/chained_irq.h> | 30 | #include <linux/irqchip/chained_irq.h> |
31 | #include <linux/platform_device.h> | ||
31 | 32 | ||
32 | #include <asm/proc-fns.h> | 33 | #include <asm/proc-fns.h> |
33 | #include <asm/exception.h> | 34 | #include <asm/exception.h> |
@@ -292,6 +293,16 @@ void exynos5_restart(enum reboot_mode mode, const char *cmd) | |||
292 | __raw_writel(val, addr); | 293 | __raw_writel(val, addr); |
293 | } | 294 | } |
294 | 295 | ||
296 | static struct platform_device exynos_cpuidle = { | ||
297 | .name = "exynos_cpuidle", | ||
298 | .id = -1, | ||
299 | }; | ||
300 | |||
301 | void __init exynos_cpuidle_init(void) | ||
302 | { | ||
303 | platform_device_register(&exynos_cpuidle); | ||
304 | } | ||
305 | |||
295 | void __init exynos_init_late(void) | 306 | void __init exynos_init_late(void) |
296 | { | 307 | { |
297 | if (of_machine_is_compatible("samsung,exynos5440")) | 308 | if (of_machine_is_compatible("samsung,exynos5440")) |
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index f0fa2050d08d..ff9b6a9419b0 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h | |||
@@ -21,6 +21,7 @@ struct map_desc; | |||
21 | void exynos_init_io(void); | 21 | void exynos_init_io(void); |
22 | void exynos4_restart(enum reboot_mode mode, const char *cmd); | 22 | void exynos4_restart(enum reboot_mode mode, const char *cmd); |
23 | void exynos5_restart(enum reboot_mode mode, const char *cmd); | 23 | void exynos5_restart(enum reboot_mode mode, const char *cmd); |
24 | void exynos_cpuidle_init(void); | ||
24 | void exynos_init_late(void); | 25 | void exynos_init_late(void); |
25 | 26 | ||
26 | void exynos_firmware_init(void); | 27 | void exynos_firmware_init(void); |
diff --git a/arch/arm/mach-exynos/cpuidle.c b/arch/arm/mach-exynos/cpuidle.c index ac139226d63c..ddbfe8709fe7 100644 --- a/arch/arm/mach-exynos/cpuidle.c +++ b/arch/arm/mach-exynos/cpuidle.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <linux/export.h> | 16 | #include <linux/export.h> |
17 | #include <linux/time.h> | 17 | #include <linux/time.h> |
18 | #include <linux/platform_device.h> | ||
18 | 19 | ||
19 | #include <asm/proc-fns.h> | 20 | #include <asm/proc-fns.h> |
20 | #include <asm/smp_scu.h> | 21 | #include <asm/smp_scu.h> |
@@ -192,7 +193,7 @@ static void __init exynos5_core_down_clk(void) | |||
192 | __raw_writel(tmp, EXYNOS5_PWR_CTRL2); | 193 | __raw_writel(tmp, EXYNOS5_PWR_CTRL2); |
193 | } | 194 | } |
194 | 195 | ||
195 | static int __init exynos4_init_cpuidle(void) | 196 | static int exynos_cpuidle_probe(struct platform_device *pdev) |
196 | { | 197 | { |
197 | int cpu_id, ret; | 198 | int cpu_id, ret; |
198 | struct cpuidle_device *device; | 199 | struct cpuidle_device *device; |
@@ -205,7 +206,7 @@ static int __init exynos4_init_cpuidle(void) | |||
205 | 206 | ||
206 | ret = cpuidle_register_driver(&exynos4_idle_driver); | 207 | ret = cpuidle_register_driver(&exynos4_idle_driver); |
207 | if (ret) { | 208 | if (ret) { |
208 | printk(KERN_ERR "CPUidle failed to register driver\n"); | 209 | dev_err(&pdev->dev, "failed to register cpuidle driver\n"); |
209 | return ret; | 210 | return ret; |
210 | } | 211 | } |
211 | 212 | ||
@@ -219,11 +220,20 @@ static int __init exynos4_init_cpuidle(void) | |||
219 | 220 | ||
220 | ret = cpuidle_register_device(device); | 221 | ret = cpuidle_register_device(device); |
221 | if (ret) { | 222 | if (ret) { |
222 | printk(KERN_ERR "CPUidle register device failed\n"); | 223 | dev_err(&pdev->dev, "failed to register cpuidle device\n"); |
223 | return ret; | 224 | return ret; |
224 | } | 225 | } |
225 | } | 226 | } |
226 | 227 | ||
227 | return 0; | 228 | return 0; |
228 | } | 229 | } |
229 | device_initcall(exynos4_init_cpuidle); | 230 | |
231 | static struct platform_driver exynos_cpuidle_driver = { | ||
232 | .probe = exynos_cpuidle_probe, | ||
233 | .driver = { | ||
234 | .name = "exynos_cpuidle", | ||
235 | .owner = THIS_MODULE, | ||
236 | }, | ||
237 | }; | ||
238 | |||
239 | module_platform_driver(exynos_cpuidle_driver); | ||
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index 4b8f6e2ca163..4603e6bd424b 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c | |||
@@ -21,6 +21,8 @@ | |||
21 | 21 | ||
22 | static void __init exynos4_dt_machine_init(void) | 22 | static void __init exynos4_dt_machine_init(void) |
23 | { | 23 | { |
24 | exynos_cpuidle_init(); | ||
25 | |||
24 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 26 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
25 | } | 27 | } |
26 | 28 | ||
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 7976ab333192..1fe075a70c1e 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c | |||
@@ -43,6 +43,8 @@ static void __init exynos5_dt_machine_init(void) | |||
43 | } | 43 | } |
44 | } | 44 | } |
45 | 45 | ||
46 | exynos_cpuidle_init(); | ||
47 | |||
46 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); | 48 | of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); |
47 | } | 49 | } |
48 | 50 | ||
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c index 0f9f24116daa..d0cfb225ec9a 100644 --- a/arch/arm/mach-imx/mach-imx6q.c +++ b/arch/arm/mach-imx/mach-imx6q.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
23 | #include <linux/of_irq.h> | 23 | #include <linux/of_irq.h> |
24 | #include <linux/of_platform.h> | 24 | #include <linux/of_platform.h> |
25 | #include <linux/opp.h> | 25 | #include <linux/pm_opp.h> |
26 | #include <linux/phy.h> | 26 | #include <linux/phy.h> |
27 | #include <linux/reboot.h> | 27 | #include <linux/reboot.h> |
28 | #include <linux/regmap.h> | 28 | #include <linux/regmap.h> |
@@ -176,7 +176,7 @@ static void __init imx6q_opp_check_1p2ghz(struct device *cpu_dev) | |||
176 | val = readl_relaxed(base + OCOTP_CFG3); | 176 | val = readl_relaxed(base + OCOTP_CFG3); |
177 | val >>= OCOTP_CFG3_SPEED_SHIFT; | 177 | val >>= OCOTP_CFG3_SPEED_SHIFT; |
178 | if ((val & 0x3) != OCOTP_CFG3_SPEED_1P2GHZ) | 178 | if ((val & 0x3) != OCOTP_CFG3_SPEED_1P2GHZ) |
179 | if (opp_disable(cpu_dev, 1200000000)) | 179 | if (dev_pm_opp_disable(cpu_dev, 1200000000)) |
180 | pr_warn("failed to disable 1.2 GHz OPP\n"); | 180 | pr_warn("failed to disable 1.2 GHz OPP\n"); |
181 | 181 | ||
182 | put_node: | 182 | put_node: |
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index 8b9cd0690ce7..a516c1bda141 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include <linux/input.h> | 26 | #include <linux/input.h> |
27 | #include <linux/gpio_keys.h> | 27 | #include <linux/gpio_keys.h> |
28 | #include <linux/opp.h> | 28 | #include <linux/pm_opp.h> |
29 | #include <linux/cpu.h> | 29 | #include <linux/cpu.h> |
30 | 30 | ||
31 | #include <linux/mtd/mtd.h> | 31 | #include <linux/mtd/mtd.h> |
@@ -516,11 +516,11 @@ static int __init beagle_opp_init(void) | |||
516 | return -ENODEV; | 516 | return -ENODEV; |
517 | } | 517 | } |
518 | /* Enable MPU 1GHz and lower opps */ | 518 | /* Enable MPU 1GHz and lower opps */ |
519 | r = opp_enable(mpu_dev, 800000000); | 519 | r = dev_pm_opp_enable(mpu_dev, 800000000); |
520 | /* TODO: MPU 1GHz needs SR and ABB */ | 520 | /* TODO: MPU 1GHz needs SR and ABB */ |
521 | 521 | ||
522 | /* Enable IVA 800MHz and lower opps */ | 522 | /* Enable IVA 800MHz and lower opps */ |
523 | r |= opp_enable(iva_dev, 660000000); | 523 | r |= dev_pm_opp_enable(iva_dev, 660000000); |
524 | /* TODO: DSP 800MHz needs SR and ABB */ | 524 | /* TODO: DSP 800MHz needs SR and ABB */ |
525 | if (r) { | 525 | if (r) { |
526 | pr_err("%s: failed to enable higher opp %d\n", | 526 | pr_err("%s: failed to enable higher opp %d\n", |
@@ -529,8 +529,8 @@ static int __init beagle_opp_init(void) | |||
529 | * Cleanup - disable the higher freqs - we dont care | 529 | * Cleanup - disable the higher freqs - we dont care |
530 | * about the results | 530 | * about the results |
531 | */ | 531 | */ |
532 | opp_disable(mpu_dev, 800000000); | 532 | dev_pm_opp_disable(mpu_dev, 800000000); |
533 | opp_disable(iva_dev, 660000000); | 533 | dev_pm_opp_disable(iva_dev, 660000000); |
534 | } | 534 | } |
535 | } | 535 | } |
536 | return 0; | 536 | return 0; |
diff --git a/arch/arm/mach-omap2/omap-pm.h b/arch/arm/mach-omap2/omap-pm.h index 67faa7b8fe92..1d777e63e05c 100644 --- a/arch/arm/mach-omap2/omap-pm.h +++ b/arch/arm/mach-omap2/omap-pm.h | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/cpufreq.h> | 18 | #include <linux/cpufreq.h> |
19 | #include <linux/clk.h> | 19 | #include <linux/clk.h> |
20 | #include <linux/opp.h> | 20 | #include <linux/pm_opp.h> |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * agent_id values for use with omap_pm_set_min_bus_tput(): | 23 | * agent_id values for use with omap_pm_set_min_bus_tput(): |
diff --git a/arch/arm/mach-omap2/opp.c b/arch/arm/mach-omap2/opp.c index 82fd8c72f750..a358a07e18f2 100644 --- a/arch/arm/mach-omap2/opp.c +++ b/arch/arm/mach-omap2/opp.c | |||
@@ -18,7 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/opp.h> | 21 | #include <linux/pm_opp.h> |
22 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
23 | 23 | ||
24 | #include "omap_device.h" | 24 | #include "omap_device.h" |
@@ -85,14 +85,14 @@ int __init omap_init_opp_table(struct omap_opp_def *opp_def, | |||
85 | dev = &oh->od->pdev->dev; | 85 | dev = &oh->od->pdev->dev; |
86 | } | 86 | } |
87 | 87 | ||
88 | r = opp_add(dev, opp_def->freq, opp_def->u_volt); | 88 | r = dev_pm_opp_add(dev, opp_def->freq, opp_def->u_volt); |
89 | if (r) { | 89 | if (r) { |
90 | dev_err(dev, "%s: add OPP %ld failed for %s [%d] result=%d\n", | 90 | dev_err(dev, "%s: add OPP %ld failed for %s [%d] result=%d\n", |
91 | __func__, opp_def->freq, | 91 | __func__, opp_def->freq, |
92 | opp_def->hwmod_name, i, r); | 92 | opp_def->hwmod_name, i, r); |
93 | } else { | 93 | } else { |
94 | if (!opp_def->default_available) | 94 | if (!opp_def->default_available) |
95 | r = opp_disable(dev, opp_def->freq); | 95 | r = dev_pm_opp_disable(dev, opp_def->freq); |
96 | if (r) | 96 | if (r) |
97 | dev_err(dev, "%s: disable %ld failed for %s [%d] result=%d\n", | 97 | dev_err(dev, "%s: disable %ld failed for %s [%d] result=%d\n", |
98 | __func__, opp_def->freq, | 98 | __func__, opp_def->freq, |
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 360b2daf54dd..e1b41416fbf1 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
16 | #include <linux/opp.h> | 16 | #include <linux/pm_opp.h> |
17 | #include <linux/export.h> | 17 | #include <linux/export.h> |
18 | #include <linux/suspend.h> | 18 | #include <linux/suspend.h> |
19 | #include <linux/cpu.h> | 19 | #include <linux/cpu.h> |
@@ -131,7 +131,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | |||
131 | { | 131 | { |
132 | struct voltagedomain *voltdm; | 132 | struct voltagedomain *voltdm; |
133 | struct clk *clk; | 133 | struct clk *clk; |
134 | struct opp *opp; | 134 | struct dev_pm_opp *opp; |
135 | unsigned long freq, bootup_volt; | 135 | unsigned long freq, bootup_volt; |
136 | struct device *dev; | 136 | struct device *dev; |
137 | 137 | ||
@@ -172,7 +172,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | |||
172 | clk_put(clk); | 172 | clk_put(clk); |
173 | 173 | ||
174 | rcu_read_lock(); | 174 | rcu_read_lock(); |
175 | opp = opp_find_freq_ceil(dev, &freq); | 175 | opp = dev_pm_opp_find_freq_ceil(dev, &freq); |
176 | if (IS_ERR(opp)) { | 176 | if (IS_ERR(opp)) { |
177 | rcu_read_unlock(); | 177 | rcu_read_unlock(); |
178 | pr_err("%s: unable to find boot up OPP for vdd_%s\n", | 178 | pr_err("%s: unable to find boot up OPP for vdd_%s\n", |
@@ -180,7 +180,7 @@ static int __init omap2_set_init_voltage(char *vdd_name, char *clk_name, | |||
180 | goto exit; | 180 | goto exit; |
181 | } | 181 | } |
182 | 182 | ||
183 | bootup_volt = opp_get_voltage(opp); | 183 | bootup_volt = dev_pm_opp_get_voltage(opp); |
184 | rcu_read_unlock(); | 184 | rcu_read_unlock(); |
185 | if (!bootup_volt) { | 185 | if (!bootup_volt) { |
186 | pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n", | 186 | pr_err("%s: unable to find voltage corresponding to the bootup OPP for vdd_%s\n", |
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index a8427115ee07..96100dbf5a2e 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig | |||
@@ -615,14 +615,12 @@ endmenu | |||
615 | config PXA25x | 615 | config PXA25x |
616 | bool | 616 | bool |
617 | select CPU_XSCALE | 617 | select CPU_XSCALE |
618 | select CPU_FREQ_TABLE if CPU_FREQ | ||
619 | help | 618 | help |
620 | Select code specific to PXA21x/25x/26x variants | 619 | Select code specific to PXA21x/25x/26x variants |
621 | 620 | ||
622 | config PXA27x | 621 | config PXA27x |
623 | bool | 622 | bool |
624 | select CPU_XSCALE | 623 | select CPU_XSCALE |
625 | select CPU_FREQ_TABLE if CPU_FREQ | ||
626 | help | 624 | help |
627 | Select code specific to PXA27x variants | 625 | Select code specific to PXA27x variants |
628 | 626 | ||
@@ -635,7 +633,6 @@ config CPU_PXA26x | |||
635 | config PXA3xx | 633 | config PXA3xx |
636 | bool | 634 | bool |
637 | select CPU_XSC3 | 635 | select CPU_XSC3 |
638 | select CPU_FREQ_TABLE if CPU_FREQ | ||
639 | help | 636 | help |
640 | Select code specific to PXA3xx variants | 637 | Select code specific to PXA3xx variants |
641 | 638 | ||
diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index f25b6119e028..d4ea142c4edd 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c | |||
@@ -42,74 +42,31 @@ EXPORT_SYMBOL(reset_status); | |||
42 | /* | 42 | /* |
43 | * This table is setup for a 3.6864MHz Crystal. | 43 | * This table is setup for a 3.6864MHz Crystal. |
44 | */ | 44 | */ |
45 | static const unsigned short cclk_frequency_100khz[NR_FREQS] = { | 45 | struct cpufreq_frequency_table sa11x0_freq_table[NR_FREQS+1] = { |
46 | 590, /* 59.0 MHz */ | 46 | { .frequency = 59000, /* 59.0 MHz */}, |
47 | 737, /* 73.7 MHz */ | 47 | { .frequency = 73700, /* 73.7 MHz */}, |
48 | 885, /* 88.5 MHz */ | 48 | { .frequency = 88500, /* 88.5 MHz */}, |
49 | 1032, /* 103.2 MHz */ | 49 | { .frequency = 103200, /* 103.2 MHz */}, |
50 | 1180, /* 118.0 MHz */ | 50 | { .frequency = 118000, /* 118.0 MHz */}, |
51 | 1327, /* 132.7 MHz */ | 51 | { .frequency = 132700, /* 132.7 MHz */}, |
52 | 1475, /* 147.5 MHz */ | 52 | { .frequency = 147500, /* 147.5 MHz */}, |
53 | 1622, /* 162.2 MHz */ | 53 | { .frequency = 162200, /* 162.2 MHz */}, |
54 | 1769, /* 176.9 MHz */ | 54 | { .frequency = 176900, /* 176.9 MHz */}, |
55 | 1917, /* 191.7 MHz */ | 55 | { .frequency = 191700, /* 191.7 MHz */}, |
56 | 2064, /* 206.4 MHz */ | 56 | { .frequency = 206400, /* 206.4 MHz */}, |
57 | 2212, /* 221.2 MHz */ | 57 | { .frequency = 221200, /* 221.2 MHz */}, |
58 | 2359, /* 235.9 MHz */ | 58 | { .frequency = 235900, /* 235.9 MHz */}, |
59 | 2507, /* 250.7 MHz */ | 59 | { .frequency = 250700, /* 250.7 MHz */}, |
60 | 2654, /* 265.4 MHz */ | 60 | { .frequency = 265400, /* 265.4 MHz */}, |
61 | 2802 /* 280.2 MHz */ | 61 | { .frequency = 280200, /* 280.2 MHz */}, |
62 | { .frequency = CPUFREQ_TABLE_END, }, | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | /* rounds up(!) */ | ||
65 | unsigned int sa11x0_freq_to_ppcr(unsigned int khz) | ||
66 | { | ||
67 | int i; | ||
68 | |||
69 | khz /= 100; | ||
70 | |||
71 | for (i = 0; i < NR_FREQS; i++) | ||
72 | if (cclk_frequency_100khz[i] >= khz) | ||
73 | break; | ||
74 | |||
75 | return i; | ||
76 | } | ||
77 | |||
78 | unsigned int sa11x0_ppcr_to_freq(unsigned int idx) | ||
79 | { | ||
80 | unsigned int freq = 0; | ||
81 | if (idx < NR_FREQS) | ||
82 | freq = cclk_frequency_100khz[idx] * 100; | ||
83 | return freq; | ||
84 | } | ||
85 | |||
86 | |||
87 | /* make sure that only the "userspace" governor is run -- anything else wouldn't make sense on | ||
88 | * this platform, anyway. | ||
89 | */ | ||
90 | int sa11x0_verify_speed(struct cpufreq_policy *policy) | ||
91 | { | ||
92 | unsigned int tmp; | ||
93 | if (policy->cpu) | ||
94 | return -EINVAL; | ||
95 | |||
96 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); | ||
97 | |||
98 | /* make sure that at least one frequency is within the policy */ | ||
99 | tmp = cclk_frequency_100khz[sa11x0_freq_to_ppcr(policy->min)] * 100; | ||
100 | if (tmp > policy->max) | ||
101 | policy->max = tmp; | ||
102 | |||
103 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, policy->cpuinfo.max_freq); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | unsigned int sa11x0_getspeed(unsigned int cpu) | 65 | unsigned int sa11x0_getspeed(unsigned int cpu) |
109 | { | 66 | { |
110 | if (cpu) | 67 | if (cpu) |
111 | return 0; | 68 | return 0; |
112 | return cclk_frequency_100khz[PPCR & 0xf] * 100; | 69 | return sa11x0_freq_table[PPCR & 0xf].frequency; |
113 | } | 70 | } |
114 | 71 | ||
115 | /* | 72 | /* |
diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 9a33695c9492..0d92e119b36b 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Nicolas Pitre | 4 | * Author: Nicolas Pitre |
5 | */ | 5 | */ |
6 | #include <linux/cpufreq.h> | ||
6 | #include <linux/reboot.h> | 7 | #include <linux/reboot.h> |
7 | 8 | ||
8 | extern void sa1100_timer_init(void); | 9 | extern void sa1100_timer_init(void); |
@@ -19,12 +20,8 @@ extern void sa11x0_init_late(void); | |||
19 | extern void sa1110_mb_enable(void); | 20 | extern void sa1110_mb_enable(void); |
20 | extern void sa1110_mb_disable(void); | 21 | extern void sa1110_mb_disable(void); |
21 | 22 | ||
22 | struct cpufreq_policy; | 23 | extern struct cpufreq_frequency_table sa11x0_freq_table[]; |
23 | |||
24 | extern unsigned int sa11x0_freq_to_ppcr(unsigned int khz); | ||
25 | extern int sa11x0_verify_speed(struct cpufreq_policy *policy); | ||
26 | extern unsigned int sa11x0_getspeed(unsigned int cpu); | 24 | extern unsigned int sa11x0_getspeed(unsigned int cpu); |
27 | extern unsigned int sa11x0_ppcr_to_freq(unsigned int idx); | ||
28 | 25 | ||
29 | struct flash_platform_data; | 26 | struct flash_platform_data; |
30 | struct resource; | 27 | struct resource; |
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index c67f8ad5ccd5..0034d2cd6973 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig | |||
@@ -29,7 +29,6 @@ if ARCH_U8500 | |||
29 | 29 | ||
30 | config UX500_SOC_DB8500 | 30 | config UX500_SOC_DB8500 |
31 | bool | 31 | bool |
32 | select CPU_FREQ_TABLE if CPU_FREQ | ||
33 | select MFD_DB8500_PRCMU | 32 | select MFD_DB8500_PRCMU |
34 | select PINCTRL_DB8500 | 33 | select PINCTRL_DB8500 |
35 | select PINCTRL_DB8540 | 34 | select PINCTRL_DB8540 |
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index cbbb81e0e509..4a70be485ff8 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig | |||
@@ -65,10 +65,22 @@ config ARCH_VEXPRESS_DCSCB | |||
65 | This is needed to provide CPU and cluster power management | 65 | This is needed to provide CPU and cluster power management |
66 | on RTSM implementing big.LITTLE. | 66 | on RTSM implementing big.LITTLE. |
67 | 67 | ||
68 | config ARCH_VEXPRESS_SPC | ||
69 | bool "Versatile Express Serial Power Controller (SPC)" | ||
70 | select ARCH_HAS_CPUFREQ | ||
71 | select ARCH_HAS_OPP | ||
72 | select PM_OPP | ||
73 | help | ||
74 | The TC2 (A15x2 A7x3) versatile express core tile integrates a logic | ||
75 | block called Serial Power Controller (SPC) that provides the interface | ||
76 | between the dual cluster test-chip and the M3 microcontroller that | ||
77 | carries out power management. | ||
78 | |||
68 | config ARCH_VEXPRESS_TC2_PM | 79 | config ARCH_VEXPRESS_TC2_PM |
69 | bool "Versatile Express TC2 power management" | 80 | bool "Versatile Express TC2 power management" |
70 | depends on MCPM | 81 | depends on MCPM |
71 | select ARM_CCI | 82 | select ARM_CCI |
83 | select ARCH_VEXPRESS_SPC | ||
72 | help | 84 | help |
73 | Support for CPU and cluster power management on Versatile Express | 85 | Support for CPU and cluster power management on Versatile Express |
74 | with a TC2 (A15x2 A7x3) big.LITTLE core tile. | 86 | with a TC2 (A15x2 A7x3) big.LITTLE core tile. |
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 505e64ab3eae..0997e0b7494c 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile | |||
@@ -8,7 +8,8 @@ obj-y := v2m.o | |||
8 | obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o | 8 | obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o |
9 | obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o | 9 | obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o |
10 | CFLAGS_dcscb.o += -march=armv7-a | 10 | CFLAGS_dcscb.o += -march=armv7-a |
11 | obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o spc.o | 11 | obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o |
12 | obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o | ||
12 | CFLAGS_tc2_pm.o += -march=armv7-a | 13 | CFLAGS_tc2_pm.o += -march=armv7-a |
13 | obj-$(CONFIG_SMP) += platsmp.o | 14 | obj-$(CONFIG_SMP) += platsmp.o |
14 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 15 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index eefb029197ca..033d34dcbd3f 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c | |||
@@ -17,14 +17,31 @@ | |||
17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/clk-provider.h> | ||
21 | #include <linux/clkdev.h> | ||
22 | #include <linux/cpu.h> | ||
23 | #include <linux/delay.h> | ||
20 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/interrupt.h> | ||
21 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/pm_opp.h> | ||
22 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
30 | #include <linux/semaphore.h> | ||
23 | 31 | ||
24 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
25 | 33 | ||
26 | #define SPCLOG "vexpress-spc: " | 34 | #define SPCLOG "vexpress-spc: " |
27 | 35 | ||
36 | #define PERF_LVL_A15 0x00 | ||
37 | #define PERF_REQ_A15 0x04 | ||
38 | #define PERF_LVL_A7 0x08 | ||
39 | #define PERF_REQ_A7 0x0c | ||
40 | #define COMMS 0x10 | ||
41 | #define COMMS_REQ 0x14 | ||
42 | #define PWC_STATUS 0x18 | ||
43 | #define PWC_FLAG 0x1c | ||
44 | |||
28 | /* SPC wake-up IRQs status and mask */ | 45 | /* SPC wake-up IRQs status and mask */ |
29 | #define WAKE_INT_MASK 0x24 | 46 | #define WAKE_INT_MASK 0x24 |
30 | #define WAKE_INT_RAW 0x28 | 47 | #define WAKE_INT_RAW 0x28 |
@@ -36,12 +53,45 @@ | |||
36 | #define A15_BX_ADDR0 0x68 | 53 | #define A15_BX_ADDR0 0x68 |
37 | #define A7_BX_ADDR0 0x78 | 54 | #define A7_BX_ADDR0 0x78 |
38 | 55 | ||
56 | /* SPC system config interface registers */ | ||
57 | #define SYSCFG_WDATA 0x70 | ||
58 | #define SYSCFG_RDATA 0x74 | ||
59 | |||
60 | /* A15/A7 OPP virtual register base */ | ||
61 | #define A15_PERFVAL_BASE 0xC10 | ||
62 | #define A7_PERFVAL_BASE 0xC30 | ||
63 | |||
64 | /* Config interface control bits */ | ||
65 | #define SYSCFG_START (1 << 31) | ||
66 | #define SYSCFG_SCC (6 << 20) | ||
67 | #define SYSCFG_STAT (14 << 20) | ||
68 | |||
39 | /* wake-up interrupt masks */ | 69 | /* wake-up interrupt masks */ |
40 | #define GBL_WAKEUP_INT_MSK (0x3 << 10) | 70 | #define GBL_WAKEUP_INT_MSK (0x3 << 10) |
41 | 71 | ||
42 | /* TC2 static dual-cluster configuration */ | 72 | /* TC2 static dual-cluster configuration */ |
43 | #define MAX_CLUSTERS 2 | 73 | #define MAX_CLUSTERS 2 |
44 | 74 | ||
75 | /* | ||
76 | * Even though the SPC takes max 3-5 ms to complete any OPP/COMMS | ||
77 | * operation, the operation could start just before jiffie is about | ||
78 | * to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz | ||
79 | */ | ||
80 | #define TIMEOUT_US 20000 | ||
81 | |||
82 | #define MAX_OPPS 8 | ||
83 | #define CA15_DVFS 0 | ||
84 | #define CA7_DVFS 1 | ||
85 | #define SPC_SYS_CFG 2 | ||
86 | #define STAT_COMPLETE(type) ((1 << 0) << (type << 2)) | ||
87 | #define STAT_ERR(type) ((1 << 1) << (type << 2)) | ||
88 | #define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type)) | ||
89 | |||
90 | struct ve_spc_opp { | ||
91 | unsigned long freq; | ||
92 | unsigned long u_volt; | ||
93 | }; | ||
94 | |||
45 | struct ve_spc_drvdata { | 95 | struct ve_spc_drvdata { |
46 | void __iomem *baseaddr; | 96 | void __iomem *baseaddr; |
47 | /* | 97 | /* |
@@ -49,6 +99,12 @@ struct ve_spc_drvdata { | |||
49 | * It corresponds to A15 processors MPIDR[15:8] bitfield | 99 | * It corresponds to A15 processors MPIDR[15:8] bitfield |
50 | */ | 100 | */ |
51 | u32 a15_clusid; | 101 | u32 a15_clusid; |
102 | uint32_t cur_rsp_mask; | ||
103 | uint32_t cur_rsp_stat; | ||
104 | struct semaphore sem; | ||
105 | struct completion done; | ||
106 | struct ve_spc_opp *opps[MAX_CLUSTERS]; | ||
107 | int num_opps[MAX_CLUSTERS]; | ||
52 | }; | 108 | }; |
53 | 109 | ||
54 | static struct ve_spc_drvdata *info; | 110 | static struct ve_spc_drvdata *info; |
@@ -157,8 +213,197 @@ void ve_spc_powerdown(u32 cluster, bool enable) | |||
157 | writel_relaxed(enable, info->baseaddr + pwdrn_reg); | 213 | writel_relaxed(enable, info->baseaddr + pwdrn_reg); |
158 | } | 214 | } |
159 | 215 | ||
160 | int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | 216 | static int ve_spc_get_performance(int cluster, u32 *freq) |
217 | { | ||
218 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
219 | u32 perf_cfg_reg = 0; | ||
220 | u32 perf; | ||
221 | |||
222 | perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7; | ||
223 | |||
224 | perf = readl_relaxed(info->baseaddr + perf_cfg_reg); | ||
225 | if (perf >= info->num_opps[cluster]) | ||
226 | return -EINVAL; | ||
227 | |||
228 | opps += perf; | ||
229 | *freq = opps->freq; | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /* find closest match to given frequency in OPP table */ | ||
235 | static int ve_spc_round_performance(int cluster, u32 freq) | ||
236 | { | ||
237 | int idx, max_opp = info->num_opps[cluster]; | ||
238 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
239 | u32 fmin = 0, fmax = ~0, ftmp; | ||
240 | |||
241 | freq /= 1000; /* OPP entries in kHz */ | ||
242 | for (idx = 0; idx < max_opp; idx++, opps++) { | ||
243 | ftmp = opps->freq; | ||
244 | if (ftmp >= freq) { | ||
245 | if (ftmp <= fmax) | ||
246 | fmax = ftmp; | ||
247 | } else { | ||
248 | if (ftmp >= fmin) | ||
249 | fmin = ftmp; | ||
250 | } | ||
251 | } | ||
252 | if (fmax != ~0) | ||
253 | return fmax * 1000; | ||
254 | else | ||
255 | return fmin * 1000; | ||
256 | } | ||
257 | |||
258 | static int ve_spc_find_performance_index(int cluster, u32 freq) | ||
259 | { | ||
260 | int idx, max_opp = info->num_opps[cluster]; | ||
261 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
262 | |||
263 | for (idx = 0; idx < max_opp; idx++, opps++) | ||
264 | if (opps->freq == freq) | ||
265 | break; | ||
266 | return (idx == max_opp) ? -EINVAL : idx; | ||
267 | } | ||
268 | |||
269 | static int ve_spc_waitforcompletion(int req_type) | ||
270 | { | ||
271 | int ret = wait_for_completion_interruptible_timeout( | ||
272 | &info->done, usecs_to_jiffies(TIMEOUT_US)); | ||
273 | if (ret == 0) | ||
274 | ret = -ETIMEDOUT; | ||
275 | else if (ret > 0) | ||
276 | ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO; | ||
277 | return ret; | ||
278 | } | ||
279 | |||
280 | static int ve_spc_set_performance(int cluster, u32 freq) | ||
281 | { | ||
282 | u32 perf_cfg_reg, perf_stat_reg; | ||
283 | int ret, perf, req_type; | ||
284 | |||
285 | if (cluster_is_a15(cluster)) { | ||
286 | req_type = CA15_DVFS; | ||
287 | perf_cfg_reg = PERF_LVL_A15; | ||
288 | perf_stat_reg = PERF_REQ_A15; | ||
289 | } else { | ||
290 | req_type = CA7_DVFS; | ||
291 | perf_cfg_reg = PERF_LVL_A7; | ||
292 | perf_stat_reg = PERF_REQ_A7; | ||
293 | } | ||
294 | |||
295 | perf = ve_spc_find_performance_index(cluster, freq); | ||
296 | |||
297 | if (perf < 0) | ||
298 | return perf; | ||
299 | |||
300 | if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) | ||
301 | return -ETIME; | ||
302 | |||
303 | init_completion(&info->done); | ||
304 | info->cur_rsp_mask = RESPONSE_MASK(req_type); | ||
305 | |||
306 | writel(perf, info->baseaddr + perf_cfg_reg); | ||
307 | ret = ve_spc_waitforcompletion(req_type); | ||
308 | |||
309 | info->cur_rsp_mask = 0; | ||
310 | up(&info->sem); | ||
311 | |||
312 | return ret; | ||
313 | } | ||
314 | |||
315 | static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data) | ||
316 | { | ||
317 | int ret; | ||
318 | |||
319 | if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) | ||
320 | return -ETIME; | ||
321 | |||
322 | init_completion(&info->done); | ||
323 | info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG); | ||
324 | |||
325 | /* Set the control value */ | ||
326 | writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS); | ||
327 | ret = ve_spc_waitforcompletion(SPC_SYS_CFG); | ||
328 | |||
329 | if (ret == 0) | ||
330 | *data = readl(info->baseaddr + SYSCFG_RDATA); | ||
331 | |||
332 | info->cur_rsp_mask = 0; | ||
333 | up(&info->sem); | ||
334 | |||
335 | return ret; | ||
336 | } | ||
337 | |||
338 | static irqreturn_t ve_spc_irq_handler(int irq, void *data) | ||
339 | { | ||
340 | struct ve_spc_drvdata *drv_data = data; | ||
341 | uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS); | ||
342 | |||
343 | if (info->cur_rsp_mask & status) { | ||
344 | info->cur_rsp_stat = status; | ||
345 | complete(&drv_data->done); | ||
346 | } | ||
347 | |||
348 | return IRQ_HANDLED; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * +--------------------------+ | ||
353 | * | 31 20 | 19 0 | | ||
354 | * +--------------------------+ | ||
355 | * | u_volt | freq(kHz) | | ||
356 | * +--------------------------+ | ||
357 | */ | ||
358 | #define MULT_FACTOR 20 | ||
359 | #define VOLT_SHIFT 20 | ||
360 | #define FREQ_MASK (0xFFFFF) | ||
361 | static int ve_spc_populate_opps(uint32_t cluster) | ||
161 | { | 362 | { |
363 | uint32_t data = 0, off, ret, idx; | ||
364 | struct ve_spc_opp *opps; | ||
365 | |||
366 | opps = kzalloc(sizeof(*opps) * MAX_OPPS, GFP_KERNEL); | ||
367 | if (!opps) | ||
368 | return -ENOMEM; | ||
369 | |||
370 | info->opps[cluster] = opps; | ||
371 | |||
372 | off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE; | ||
373 | for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) { | ||
374 | ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data); | ||
375 | if (!ret) { | ||
376 | opps->freq = (data & FREQ_MASK) * MULT_FACTOR; | ||
377 | opps->u_volt = data >> VOLT_SHIFT; | ||
378 | } else { | ||
379 | break; | ||
380 | } | ||
381 | } | ||
382 | info->num_opps[cluster] = idx; | ||
383 | |||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | static int ve_init_opp_table(struct device *cpu_dev) | ||
388 | { | ||
389 | int cluster = topology_physical_package_id(cpu_dev->id); | ||
390 | int idx, ret = 0, max_opp = info->num_opps[cluster]; | ||
391 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
392 | |||
393 | for (idx = 0; idx < max_opp; idx++, opps++) { | ||
394 | ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt); | ||
395 | if (ret) { | ||
396 | dev_warn(cpu_dev, "failed to add opp %lu %lu\n", | ||
397 | opps->freq, opps->u_volt); | ||
398 | return ret; | ||
399 | } | ||
400 | } | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq) | ||
405 | { | ||
406 | int ret; | ||
162 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 407 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
163 | if (!info) { | 408 | if (!info) { |
164 | pr_err(SPCLOG "unable to allocate mem\n"); | 409 | pr_err(SPCLOG "unable to allocate mem\n"); |
@@ -168,6 +413,25 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | |||
168 | info->baseaddr = baseaddr; | 413 | info->baseaddr = baseaddr; |
169 | info->a15_clusid = a15_clusid; | 414 | info->a15_clusid = a15_clusid; |
170 | 415 | ||
416 | if (irq <= 0) { | ||
417 | pr_err(SPCLOG "Invalid IRQ %d\n", irq); | ||
418 | kfree(info); | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | |||
422 | init_completion(&info->done); | ||
423 | |||
424 | readl_relaxed(info->baseaddr + PWC_STATUS); | ||
425 | |||
426 | ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH | ||
427 | | IRQF_ONESHOT, "vexpress-spc", info); | ||
428 | if (ret) { | ||
429 | pr_err(SPCLOG "IRQ %d request failed\n", irq); | ||
430 | kfree(info); | ||
431 | return -ENODEV; | ||
432 | } | ||
433 | |||
434 | sema_init(&info->sem, 1); | ||
171 | /* | 435 | /* |
172 | * Multi-cluster systems may need this data when non-coherent, during | 436 | * Multi-cluster systems may need this data when non-coherent, during |
173 | * cluster power-up/power-down. Make sure driver info reaches main | 437 | * cluster power-up/power-down. Make sure driver info reaches main |
@@ -178,3 +442,103 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | |||
178 | 442 | ||
179 | return 0; | 443 | return 0; |
180 | } | 444 | } |
445 | |||
446 | struct clk_spc { | ||
447 | struct clk_hw hw; | ||
448 | int cluster; | ||
449 | }; | ||
450 | |||
451 | #define to_clk_spc(spc) container_of(spc, struct clk_spc, hw) | ||
452 | static unsigned long spc_recalc_rate(struct clk_hw *hw, | ||
453 | unsigned long parent_rate) | ||
454 | { | ||
455 | struct clk_spc *spc = to_clk_spc(hw); | ||
456 | u32 freq; | ||
457 | |||
458 | if (ve_spc_get_performance(spc->cluster, &freq)) | ||
459 | return -EIO; | ||
460 | |||
461 | return freq * 1000; | ||
462 | } | ||
463 | |||
464 | static long spc_round_rate(struct clk_hw *hw, unsigned long drate, | ||
465 | unsigned long *parent_rate) | ||
466 | { | ||
467 | struct clk_spc *spc = to_clk_spc(hw); | ||
468 | |||
469 | return ve_spc_round_performance(spc->cluster, drate); | ||
470 | } | ||
471 | |||
472 | static int spc_set_rate(struct clk_hw *hw, unsigned long rate, | ||
473 | unsigned long parent_rate) | ||
474 | { | ||
475 | struct clk_spc *spc = to_clk_spc(hw); | ||
476 | |||
477 | return ve_spc_set_performance(spc->cluster, rate / 1000); | ||
478 | } | ||
479 | |||
480 | static struct clk_ops clk_spc_ops = { | ||
481 | .recalc_rate = spc_recalc_rate, | ||
482 | .round_rate = spc_round_rate, | ||
483 | .set_rate = spc_set_rate, | ||
484 | }; | ||
485 | |||
486 | static struct clk *ve_spc_clk_register(struct device *cpu_dev) | ||
487 | { | ||
488 | struct clk_init_data init; | ||
489 | struct clk_spc *spc; | ||
490 | |||
491 | spc = kzalloc(sizeof(*spc), GFP_KERNEL); | ||
492 | if (!spc) { | ||
493 | pr_err("could not allocate spc clk\n"); | ||
494 | return ERR_PTR(-ENOMEM); | ||
495 | } | ||
496 | |||
497 | spc->hw.init = &init; | ||
498 | spc->cluster = topology_physical_package_id(cpu_dev->id); | ||
499 | |||
500 | init.name = dev_name(cpu_dev); | ||
501 | init.ops = &clk_spc_ops; | ||
502 | init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE; | ||
503 | init.num_parents = 0; | ||
504 | |||
505 | return devm_clk_register(cpu_dev, &spc->hw); | ||
506 | } | ||
507 | |||
508 | static int __init ve_spc_clk_init(void) | ||
509 | { | ||
510 | int cpu; | ||
511 | struct clk *clk; | ||
512 | |||
513 | if (!info) | ||
514 | return 0; /* Continue only if SPC is initialised */ | ||
515 | |||
516 | if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) { | ||
517 | pr_err("failed to build OPP table\n"); | ||
518 | return -ENODEV; | ||
519 | } | ||
520 | |||
521 | for_each_possible_cpu(cpu) { | ||
522 | struct device *cpu_dev = get_cpu_device(cpu); | ||
523 | if (!cpu_dev) { | ||
524 | pr_warn("failed to get cpu%d device\n", cpu); | ||
525 | continue; | ||
526 | } | ||
527 | clk = ve_spc_clk_register(cpu_dev); | ||
528 | if (IS_ERR(clk)) { | ||
529 | pr_warn("failed to register cpu%d clock\n", cpu); | ||
530 | continue; | ||
531 | } | ||
532 | if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { | ||
533 | pr_warn("failed to register cpu%d clock lookup\n", cpu); | ||
534 | continue; | ||
535 | } | ||
536 | |||
537 | if (ve_init_opp_table(cpu_dev)) | ||
538 | pr_warn("failed to initialise cpu%d opp table\n", cpu); | ||
539 | } | ||
540 | |||
541 | platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); | ||
542 | return 0; | ||
543 | } | ||
544 | module_init(ve_spc_clk_init); | ||
diff --git a/arch/arm/mach-vexpress/spc.h b/arch/arm/mach-vexpress/spc.h index 5f7e4a446a17..dbd44c3720f9 100644 --- a/arch/arm/mach-vexpress/spc.h +++ b/arch/arm/mach-vexpress/spc.h | |||
@@ -15,7 +15,7 @@ | |||
15 | #ifndef __SPC_H_ | 15 | #ifndef __SPC_H_ |
16 | #define __SPC_H_ | 16 | #define __SPC_H_ |
17 | 17 | ||
18 | int __init ve_spc_init(void __iomem *base, u32 a15_clusid); | 18 | int __init ve_spc_init(void __iomem *base, u32 a15_clusid, int irq); |
19 | void ve_spc_global_wakeup_irq(bool set); | 19 | void ve_spc_global_wakeup_irq(bool set); |
20 | void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); | 20 | void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); |
21 | void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); | 21 | void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); |
diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index 4eb92ebfd953..05a364c5077a 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
19 | #include <linux/of_irq.h> | ||
19 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
20 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
21 | #include <linux/irqchip/arm-gic.h> | 22 | #include <linux/irqchip/arm-gic.h> |
@@ -267,7 +268,7 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) | |||
267 | 268 | ||
268 | static int __init tc2_pm_init(void) | 269 | static int __init tc2_pm_init(void) |
269 | { | 270 | { |
270 | int ret; | 271 | int ret, irq; |
271 | void __iomem *scc; | 272 | void __iomem *scc; |
272 | u32 a15_cluster_id, a7_cluster_id, sys_info; | 273 | u32 a15_cluster_id, a7_cluster_id, sys_info; |
273 | struct device_node *np; | 274 | struct device_node *np; |
@@ -292,13 +293,15 @@ static int __init tc2_pm_init(void) | |||
292 | tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; | 293 | tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; |
293 | tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; | 294 | tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; |
294 | 295 | ||
296 | irq = irq_of_parse_and_map(np, 0); | ||
297 | |||
295 | /* | 298 | /* |
296 | * A subset of the SCC registers is also used to communicate | 299 | * A subset of the SCC registers is also used to communicate |
297 | * with the SPC (power controller). We need to be able to | 300 | * with the SPC (power controller). We need to be able to |
298 | * drive it very early in the boot process to power up | 301 | * drive it very early in the boot process to power up |
299 | * processors, so we initialize the SPC driver here. | 302 | * processors, so we initialize the SPC driver here. |
300 | */ | 303 | */ |
301 | ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id); | 304 | ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id, irq); |
302 | if (ret) | 305 | if (ret) |
303 | return ret; | 306 | return ret; |
304 | 307 | ||
diff --git a/arch/arm/mach-zynq/common.c b/arch/arm/mach-zynq/common.c index 5f252569c689..9a7bd137c8fd 100644 --- a/arch/arm/mach-zynq/common.c +++ b/arch/arm/mach-zynq/common.c | |||
@@ -44,6 +44,10 @@ static struct of_device_id zynq_of_bus_ids[] __initdata = { | |||
44 | {} | 44 | {} |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static struct platform_device zynq_cpuidle_device = { | ||
48 | .name = "cpuidle-zynq", | ||
49 | }; | ||
50 | |||
47 | /** | 51 | /** |
48 | * zynq_init_machine - System specific initialization, intended to be | 52 | * zynq_init_machine - System specific initialization, intended to be |
49 | * called from board specific initialization. | 53 | * called from board specific initialization. |
@@ -56,6 +60,8 @@ static void __init zynq_init_machine(void) | |||
56 | l2x0_of_init(0x02060000, 0xF0F0FFFF); | 60 | l2x0_of_init(0x02060000, 0xF0F0FFFF); |
57 | 61 | ||
58 | of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); | 62 | of_platform_bus_probe(NULL, zynq_of_bus_ids, NULL); |
63 | |||
64 | platform_device_register(&zynq_cpuidle_device); | ||
59 | } | 65 | } |
60 | 66 | ||
61 | static void __init zynq_timer_init(void) | 67 | static void __init zynq_timer_init(void) |
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 74314bd8be39..e887b57c3176 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig | |||
@@ -1440,7 +1440,6 @@ source "drivers/cpufreq/Kconfig" | |||
1440 | config BFIN_CPU_FREQ | 1440 | config BFIN_CPU_FREQ |
1441 | bool | 1441 | bool |
1442 | depends on CPU_FREQ | 1442 | depends on CPU_FREQ |
1443 | select CPU_FREQ_TABLE | ||
1444 | default y | 1443 | default y |
1445 | 1444 | ||
1446 | config CPU_VOLTAGE | 1445 | config CPU_VOLTAGE |
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 02380bed189c..9c957c81c688 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig | |||
@@ -130,13 +130,11 @@ config SVINTO_SIM | |||
130 | 130 | ||
131 | config ETRAXFS | 131 | config ETRAXFS |
132 | bool "ETRAX-FS-V32" | 132 | bool "ETRAX-FS-V32" |
133 | select CPU_FREQ_TABLE if CPU_FREQ | ||
134 | help | 133 | help |
135 | Support CRIS V32. | 134 | Support CRIS V32. |
136 | 135 | ||
137 | config CRIS_MACH_ARTPEC3 | 136 | config CRIS_MACH_ARTPEC3 |
138 | bool "ARTPEC-3" | 137 | bool "ARTPEC-3" |
139 | select CPU_FREQ_TABLE if CPU_FREQ | ||
140 | help | 138 | help |
141 | Support Axis ARTPEC-3. | 139 | Support Axis ARTPEC-3. |
142 | 140 | ||
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 5eb71d22c3d5..59d52e3aef12 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c | |||
@@ -882,40 +882,10 @@ __init void prefill_possible_map(void) | |||
882 | set_cpu_possible(i, true); | 882 | set_cpu_possible(i, true); |
883 | } | 883 | } |
884 | 884 | ||
885 | static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) | 885 | static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) |
886 | { | 886 | { |
887 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
888 | union acpi_object *obj; | ||
889 | struct acpi_madt_local_sapic *lsapic; | ||
890 | cpumask_t tmp_map; | 887 | cpumask_t tmp_map; |
891 | int cpu, physid; | 888 | int cpu; |
892 | |||
893 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
894 | return -EINVAL; | ||
895 | |||
896 | if (!buffer.length || !buffer.pointer) | ||
897 | return -EINVAL; | ||
898 | |||
899 | obj = buffer.pointer; | ||
900 | if (obj->type != ACPI_TYPE_BUFFER) | ||
901 | { | ||
902 | kfree(buffer.pointer); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | |||
906 | lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer; | ||
907 | |||
908 | if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) || | ||
909 | (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))) { | ||
910 | kfree(buffer.pointer); | ||
911 | return -EINVAL; | ||
912 | } | ||
913 | |||
914 | physid = ((lsapic->id << 8) | (lsapic->eid)); | ||
915 | |||
916 | kfree(buffer.pointer); | ||
917 | buffer.length = ACPI_ALLOCATE_BUFFER; | ||
918 | buffer.pointer = NULL; | ||
919 | 889 | ||
920 | cpumask_complement(&tmp_map, cpu_present_mask); | 890 | cpumask_complement(&tmp_map, cpu_present_mask); |
921 | cpu = cpumask_first(&tmp_map); | 891 | cpu = cpumask_first(&tmp_map); |
@@ -934,9 +904,9 @@ static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) | |||
934 | } | 904 | } |
935 | 905 | ||
936 | /* wrapper to silence section mismatch warning */ | 906 | /* wrapper to silence section mismatch warning */ |
937 | int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu) | 907 | int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) |
938 | { | 908 | { |
939 | return _acpi_map_lsapic(handle, pcpu); | 909 | return _acpi_map_lsapic(handle, physid, pcpu); |
940 | } | 910 | } |
941 | EXPORT_SYMBOL(acpi_map_lsapic); | 911 | EXPORT_SYMBOL(acpi_map_lsapic); |
942 | 912 | ||
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 8e59abc237d7..930cd8af3503 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -844,18 +844,6 @@ void __cpu_die(unsigned int cpu) | |||
844 | smp_ops->cpu_die(cpu); | 844 | smp_ops->cpu_die(cpu); |
845 | } | 845 | } |
846 | 846 | ||
847 | static DEFINE_MUTEX(powerpc_cpu_hotplug_driver_mutex); | ||
848 | |||
849 | void cpu_hotplug_driver_lock() | ||
850 | { | ||
851 | mutex_lock(&powerpc_cpu_hotplug_driver_mutex); | ||
852 | } | ||
853 | |||
854 | void cpu_hotplug_driver_unlock() | ||
855 | { | ||
856 | mutex_unlock(&powerpc_cpu_hotplug_driver_mutex); | ||
857 | } | ||
858 | |||
859 | void cpu_die(void) | 847 | void cpu_die(void) |
860 | { | 848 | { |
861 | if (ppc_md.cpu_die) | 849 | if (ppc_md.cpu_die) |
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 7cfdaae1721a..a8fe5aa3d34f 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -404,46 +404,38 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count) | |||
404 | unsigned long drc_index; | 404 | unsigned long drc_index; |
405 | int rc; | 405 | int rc; |
406 | 406 | ||
407 | cpu_hotplug_driver_lock(); | ||
408 | rc = strict_strtoul(buf, 0, &drc_index); | 407 | rc = strict_strtoul(buf, 0, &drc_index); |
409 | if (rc) { | 408 | if (rc) |
410 | rc = -EINVAL; | 409 | return -EINVAL; |
411 | goto out; | ||
412 | } | ||
413 | 410 | ||
414 | parent = of_find_node_by_path("/cpus"); | 411 | parent = of_find_node_by_path("/cpus"); |
415 | if (!parent) { | 412 | if (!parent) |
416 | rc = -ENODEV; | 413 | return -ENODEV; |
417 | goto out; | ||
418 | } | ||
419 | 414 | ||
420 | dn = dlpar_configure_connector(drc_index, parent); | 415 | dn = dlpar_configure_connector(drc_index, parent); |
421 | if (!dn) { | 416 | if (!dn) |
422 | rc = -EINVAL; | 417 | return -EINVAL; |
423 | goto out; | ||
424 | } | ||
425 | 418 | ||
426 | of_node_put(parent); | 419 | of_node_put(parent); |
427 | 420 | ||
428 | rc = dlpar_acquire_drc(drc_index); | 421 | rc = dlpar_acquire_drc(drc_index); |
429 | if (rc) { | 422 | if (rc) { |
430 | dlpar_free_cc_nodes(dn); | 423 | dlpar_free_cc_nodes(dn); |
431 | rc = -EINVAL; | 424 | return -EINVAL; |
432 | goto out; | ||
433 | } | 425 | } |
434 | 426 | ||
435 | rc = dlpar_attach_node(dn); | 427 | rc = dlpar_attach_node(dn); |
436 | if (rc) { | 428 | if (rc) { |
437 | dlpar_release_drc(drc_index); | 429 | dlpar_release_drc(drc_index); |
438 | dlpar_free_cc_nodes(dn); | 430 | dlpar_free_cc_nodes(dn); |
439 | goto out; | 431 | return rc; |
440 | } | 432 | } |
441 | 433 | ||
442 | rc = dlpar_online_cpu(dn); | 434 | rc = dlpar_online_cpu(dn); |
443 | out: | 435 | if (rc) |
444 | cpu_hotplug_driver_unlock(); | 436 | return rc; |
445 | 437 | ||
446 | return rc ? rc : count; | 438 | return count; |
447 | } | 439 | } |
448 | 440 | ||
449 | static int dlpar_offline_cpu(struct device_node *dn) | 441 | static int dlpar_offline_cpu(struct device_node *dn) |
@@ -516,30 +508,27 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count) | |||
516 | return -EINVAL; | 508 | return -EINVAL; |
517 | } | 509 | } |
518 | 510 | ||
519 | cpu_hotplug_driver_lock(); | ||
520 | rc = dlpar_offline_cpu(dn); | 511 | rc = dlpar_offline_cpu(dn); |
521 | if (rc) { | 512 | if (rc) { |
522 | of_node_put(dn); | 513 | of_node_put(dn); |
523 | rc = -EINVAL; | 514 | return -EINVAL; |
524 | goto out; | ||
525 | } | 515 | } |
526 | 516 | ||
527 | rc = dlpar_release_drc(*drc_index); | 517 | rc = dlpar_release_drc(*drc_index); |
528 | if (rc) { | 518 | if (rc) { |
529 | of_node_put(dn); | 519 | of_node_put(dn); |
530 | goto out; | 520 | return rc; |
531 | } | 521 | } |
532 | 522 | ||
533 | rc = dlpar_detach_node(dn); | 523 | rc = dlpar_detach_node(dn); |
534 | if (rc) { | 524 | if (rc) { |
535 | dlpar_acquire_drc(*drc_index); | 525 | dlpar_acquire_drc(*drc_index); |
536 | goto out; | 526 | return rc; |
537 | } | 527 | } |
538 | 528 | ||
539 | of_node_put(dn); | 529 | of_node_put(dn); |
540 | out: | 530 | |
541 | cpu_hotplug_driver_unlock(); | 531 | return count; |
542 | return rc ? rc : count; | ||
543 | } | 532 | } |
544 | 533 | ||
545 | static int __init pseries_dlpar_init(void) | 534 | static int __init pseries_dlpar_init(void) |
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 725e1573ea85..14dc9c797abb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
@@ -255,10 +255,6 @@ config ARCH_HWEIGHT_CFLAGS | |||
255 | default "-fcall-saved-ecx -fcall-saved-edx" if X86_32 | 255 | default "-fcall-saved-ecx -fcall-saved-edx" if X86_32 |
256 | default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64 | 256 | default "-fcall-saved-rdi -fcall-saved-rsi -fcall-saved-rdx -fcall-saved-rcx -fcall-saved-r8 -fcall-saved-r9 -fcall-saved-r10 -fcall-saved-r11" if X86_64 |
257 | 257 | ||
258 | config ARCH_CPU_PROBE_RELEASE | ||
259 | def_bool y | ||
260 | depends on HOTPLUG_CPU | ||
261 | |||
262 | config ARCH_SUPPORTS_UPROBES | 258 | config ARCH_SUPPORTS_UPROBES |
263 | def_bool y | 259 | def_bool y |
264 | 260 | ||
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index b1977bad5435..c8c1e700c26e 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <acpi/pdc_intel.h> | 26 | #include <acpi/pdc_intel.h> |
27 | 27 | ||
28 | #include <asm/numa.h> | 28 | #include <asm/numa.h> |
29 | #include <asm/fixmap.h> | ||
29 | #include <asm/processor.h> | 30 | #include <asm/processor.h> |
30 | #include <asm/mmu.h> | 31 | #include <asm/mmu.h> |
31 | #include <asm/mpspec.h> | 32 | #include <asm/mpspec.h> |
diff --git a/arch/x86/include/asm/mpspec.h b/arch/x86/include/asm/mpspec.h index 626cf70082d7..3142a94c7b4b 100644 --- a/arch/x86/include/asm/mpspec.h +++ b/arch/x86/include/asm/mpspec.h | |||
@@ -94,7 +94,7 @@ static inline void early_reserve_e820_mpc_new(void) { } | |||
94 | #define default_get_smp_config x86_init_uint_noop | 94 | #define default_get_smp_config x86_init_uint_noop |
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | void generic_processor_info(int apicid, int version); | 97 | int generic_processor_info(int apicid, int version); |
98 | #ifdef CONFIG_ACPI | 98 | #ifdef CONFIG_ACPI |
99 | extern void mp_register_ioapic(int id, u32 address, u32 gsi_base); | 99 | extern void mp_register_ioapic(int id, u32 address, u32 gsi_base); |
100 | extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, | 100 | extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, |
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index cb7502852acb..e139b13f2a33 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h | |||
@@ -218,10 +218,14 @@ void msrs_free(struct msr *msrs); | |||
218 | #ifdef CONFIG_SMP | 218 | #ifdef CONFIG_SMP |
219 | int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); | 219 | int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); |
220 | int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); | 220 | int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); |
221 | int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q); | ||
222 | int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q); | ||
221 | void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); | 223 | void rdmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); |
222 | void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); | 224 | void wrmsr_on_cpus(const struct cpumask *mask, u32 msr_no, struct msr *msrs); |
223 | int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); | 225 | int rdmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h); |
224 | int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); | 226 | int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h); |
227 | int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q); | ||
228 | int wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q); | ||
225 | int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); | 229 | int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); |
226 | int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); | 230 | int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]); |
227 | #else /* CONFIG_SMP */ | 231 | #else /* CONFIG_SMP */ |
@@ -235,6 +239,16 @@ static inline int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | |||
235 | wrmsr(msr_no, l, h); | 239 | wrmsr(msr_no, l, h); |
236 | return 0; | 240 | return 0; |
237 | } | 241 | } |
242 | static inline int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q) | ||
243 | { | ||
244 | rdmsrl(msr_no, *q); | ||
245 | return 0; | ||
246 | } | ||
247 | static inline int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q) | ||
248 | { | ||
249 | wrmsrl(msr_no, q); | ||
250 | return 0; | ||
251 | } | ||
238 | static inline void rdmsr_on_cpus(const struct cpumask *m, u32 msr_no, | 252 | static inline void rdmsr_on_cpus(const struct cpumask *m, u32 msr_no, |
239 | struct msr *msrs) | 253 | struct msr *msrs) |
240 | { | 254 | { |
@@ -254,6 +268,14 @@ static inline int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | |||
254 | { | 268 | { |
255 | return wrmsr_safe(msr_no, l, h); | 269 | return wrmsr_safe(msr_no, l, h); |
256 | } | 270 | } |
271 | static inline int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q) | ||
272 | { | ||
273 | return rdmsrl_safe(msr_no, q); | ||
274 | } | ||
275 | static inline int wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q) | ||
276 | { | ||
277 | return wrmsrl_safe(msr_no, q); | ||
278 | } | ||
257 | static inline int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) | 279 | static inline int rdmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) |
258 | { | 280 | { |
259 | return rdmsr_safe_regs(regs); | 281 | return rdmsr_safe_regs(regs); |
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 40c76604199f..6c0b43bd024b 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -189,24 +189,31 @@ static int __init acpi_parse_madt(struct acpi_table_header *table) | |||
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void acpi_register_lapic(int id, u8 enabled) | 192 | /** |
193 | * acpi_register_lapic - register a local apic and generates a logic cpu number | ||
194 | * @id: local apic id to register | ||
195 | * @enabled: this cpu is enabled or not | ||
196 | * | ||
197 | * Returns the logic cpu number which maps to the local apic | ||
198 | */ | ||
199 | static int acpi_register_lapic(int id, u8 enabled) | ||
193 | { | 200 | { |
194 | unsigned int ver = 0; | 201 | unsigned int ver = 0; |
195 | 202 | ||
196 | if (id >= MAX_LOCAL_APIC) { | 203 | if (id >= MAX_LOCAL_APIC) { |
197 | printk(KERN_INFO PREFIX "skipped apicid that is too big\n"); | 204 | printk(KERN_INFO PREFIX "skipped apicid that is too big\n"); |
198 | return; | 205 | return -EINVAL; |
199 | } | 206 | } |
200 | 207 | ||
201 | if (!enabled) { | 208 | if (!enabled) { |
202 | ++disabled_cpus; | 209 | ++disabled_cpus; |
203 | return; | 210 | return -EINVAL; |
204 | } | 211 | } |
205 | 212 | ||
206 | if (boot_cpu_physical_apicid != -1U) | 213 | if (boot_cpu_physical_apicid != -1U) |
207 | ver = apic_version[boot_cpu_physical_apicid]; | 214 | ver = apic_version[boot_cpu_physical_apicid]; |
208 | 215 | ||
209 | generic_processor_info(id, ver); | 216 | return generic_processor_info(id, ver); |
210 | } | 217 | } |
211 | 218 | ||
212 | static int __init | 219 | static int __init |
@@ -614,84 +621,27 @@ static void acpi_map_cpu2node(acpi_handle handle, int cpu, int physid) | |||
614 | #endif | 621 | #endif |
615 | } | 622 | } |
616 | 623 | ||
617 | static int _acpi_map_lsapic(acpi_handle handle, int *pcpu) | 624 | static int _acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) |
618 | { | 625 | { |
619 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
620 | union acpi_object *obj; | ||
621 | struct acpi_madt_local_apic *lapic; | ||
622 | cpumask_var_t tmp_map, new_map; | ||
623 | u8 physid; | ||
624 | int cpu; | 626 | int cpu; |
625 | int retval = -ENOMEM; | ||
626 | |||
627 | if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) | ||
628 | return -EINVAL; | ||
629 | |||
630 | if (!buffer.length || !buffer.pointer) | ||
631 | return -EINVAL; | ||
632 | |||
633 | obj = buffer.pointer; | ||
634 | if (obj->type != ACPI_TYPE_BUFFER || | ||
635 | obj->buffer.length < sizeof(*lapic)) { | ||
636 | kfree(buffer.pointer); | ||
637 | return -EINVAL; | ||
638 | } | ||
639 | 627 | ||
640 | lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; | 628 | cpu = acpi_register_lapic(physid, ACPI_MADT_ENABLED); |
641 | 629 | if (cpu < 0) { | |
642 | if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || | 630 | pr_info(PREFIX "Unable to map lapic to logical cpu number\n"); |
643 | !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { | 631 | return cpu; |
644 | kfree(buffer.pointer); | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | |||
648 | physid = lapic->id; | ||
649 | |||
650 | kfree(buffer.pointer); | ||
651 | buffer.length = ACPI_ALLOCATE_BUFFER; | ||
652 | buffer.pointer = NULL; | ||
653 | lapic = NULL; | ||
654 | |||
655 | if (!alloc_cpumask_var(&tmp_map, GFP_KERNEL)) | ||
656 | goto out; | ||
657 | |||
658 | if (!alloc_cpumask_var(&new_map, GFP_KERNEL)) | ||
659 | goto free_tmp_map; | ||
660 | |||
661 | cpumask_copy(tmp_map, cpu_present_mask); | ||
662 | acpi_register_lapic(physid, ACPI_MADT_ENABLED); | ||
663 | |||
664 | /* | ||
665 | * If acpi_register_lapic successfully generates a new logical cpu | ||
666 | * number, then the following will get us exactly what was mapped | ||
667 | */ | ||
668 | cpumask_andnot(new_map, cpu_present_mask, tmp_map); | ||
669 | if (cpumask_empty(new_map)) { | ||
670 | printk ("Unable to map lapic to logical cpu number\n"); | ||
671 | retval = -EINVAL; | ||
672 | goto free_new_map; | ||
673 | } | 632 | } |
674 | 633 | ||
675 | acpi_processor_set_pdc(handle); | 634 | acpi_processor_set_pdc(handle); |
676 | |||
677 | cpu = cpumask_first(new_map); | ||
678 | acpi_map_cpu2node(handle, cpu, physid); | 635 | acpi_map_cpu2node(handle, cpu, physid); |
679 | 636 | ||
680 | *pcpu = cpu; | 637 | *pcpu = cpu; |
681 | retval = 0; | 638 | return 0; |
682 | |||
683 | free_new_map: | ||
684 | free_cpumask_var(new_map); | ||
685 | free_tmp_map: | ||
686 | free_cpumask_var(tmp_map); | ||
687 | out: | ||
688 | return retval; | ||
689 | } | 639 | } |
690 | 640 | ||
691 | /* wrapper to silence section mismatch warning */ | 641 | /* wrapper to silence section mismatch warning */ |
692 | int __ref acpi_map_lsapic(acpi_handle handle, int *pcpu) | 642 | int __ref acpi_map_lsapic(acpi_handle handle, int physid, int *pcpu) |
693 | { | 643 | { |
694 | return _acpi_map_lsapic(handle, pcpu); | 644 | return _acpi_map_lsapic(handle, physid, pcpu); |
695 | } | 645 | } |
696 | EXPORT_SYMBOL(acpi_map_lsapic); | 646 | EXPORT_SYMBOL(acpi_map_lsapic); |
697 | 647 | ||
@@ -745,7 +695,7 @@ static int __init acpi_parse_sbf(struct acpi_table_header *table) | |||
745 | #ifdef CONFIG_HPET_TIMER | 695 | #ifdef CONFIG_HPET_TIMER |
746 | #include <asm/hpet.h> | 696 | #include <asm/hpet.h> |
747 | 697 | ||
748 | static struct __initdata resource *hpet_res; | 698 | static struct resource *hpet_res __initdata; |
749 | 699 | ||
750 | static int __init acpi_parse_hpet(struct acpi_table_header *table) | 700 | static int __init acpi_parse_hpet(struct acpi_table_header *table) |
751 | { | 701 | { |
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 33120100ff5e..3a2ae4c88948 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c | |||
@@ -26,6 +26,17 @@ static char temp_stack[4096]; | |||
26 | #endif | 26 | #endif |
27 | 27 | ||
28 | /** | 28 | /** |
29 | * x86_acpi_enter_sleep_state - enter sleep state | ||
30 | * @state: Sleep state to enter. | ||
31 | * | ||
32 | * Wrapper around acpi_enter_sleep_state() to be called by assmebly. | ||
33 | */ | ||
34 | acpi_status asmlinkage x86_acpi_enter_sleep_state(u8 state) | ||
35 | { | ||
36 | return acpi_enter_sleep_state(state); | ||
37 | } | ||
38 | |||
39 | /** | ||
29 | * x86_acpi_suspend_lowlevel - save kernel state | 40 | * x86_acpi_suspend_lowlevel - save kernel state |
30 | * | 41 | * |
31 | * Create an identity mapped page table and copy the wakeup routine to | 42 | * Create an identity mapped page table and copy the wakeup routine to |
diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h index c9c2c982d5e4..65c7b606b606 100644 --- a/arch/x86/kernel/acpi/sleep.h +++ b/arch/x86/kernel/acpi/sleep.h | |||
@@ -17,3 +17,5 @@ extern void wakeup_long64(void); | |||
17 | extern void do_suspend_lowlevel(void); | 17 | extern void do_suspend_lowlevel(void); |
18 | 18 | ||
19 | extern int x86_acpi_suspend_lowlevel(void); | 19 | extern int x86_acpi_suspend_lowlevel(void); |
20 | |||
21 | acpi_status asmlinkage x86_acpi_enter_sleep_state(u8 state); | ||
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S index d1daa66ab162..665c6b7d2ea9 100644 --- a/arch/x86/kernel/acpi/wakeup_32.S +++ b/arch/x86/kernel/acpi/wakeup_32.S | |||
@@ -73,7 +73,7 @@ ENTRY(do_suspend_lowlevel) | |||
73 | call save_processor_state | 73 | call save_processor_state |
74 | call save_registers | 74 | call save_registers |
75 | pushl $3 | 75 | pushl $3 |
76 | call acpi_enter_sleep_state | 76 | call x86_acpi_enter_sleep_state |
77 | addl $4, %esp | 77 | addl $4, %esp |
78 | 78 | ||
79 | # In case of S3 failure, we'll emerge here. Jump | 79 | # In case of S3 failure, we'll emerge here. Jump |
diff --git a/arch/x86/kernel/acpi/wakeup_64.S b/arch/x86/kernel/acpi/wakeup_64.S index 8ea5164cbd04..ae693b51ed8e 100644 --- a/arch/x86/kernel/acpi/wakeup_64.S +++ b/arch/x86/kernel/acpi/wakeup_64.S | |||
@@ -73,7 +73,7 @@ ENTRY(do_suspend_lowlevel) | |||
73 | addq $8, %rsp | 73 | addq $8, %rsp |
74 | movl $3, %edi | 74 | movl $3, %edi |
75 | xorl %eax, %eax | 75 | xorl %eax, %eax |
76 | call acpi_enter_sleep_state | 76 | call x86_acpi_enter_sleep_state |
77 | /* in case something went wrong, restore the machine status and go on */ | 77 | /* in case something went wrong, restore the machine status and go on */ |
78 | jmp resume_point | 78 | jmp resume_point |
79 | 79 | ||
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index a7eb82d9b012..ed165d657380 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -2107,7 +2107,7 @@ void disconnect_bsp_APIC(int virt_wire_setup) | |||
2107 | apic_write(APIC_LVT1, value); | 2107 | apic_write(APIC_LVT1, value); |
2108 | } | 2108 | } |
2109 | 2109 | ||
2110 | void generic_processor_info(int apicid, int version) | 2110 | int generic_processor_info(int apicid, int version) |
2111 | { | 2111 | { |
2112 | int cpu, max = nr_cpu_ids; | 2112 | int cpu, max = nr_cpu_ids; |
2113 | bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, | 2113 | bool boot_cpu_detected = physid_isset(boot_cpu_physical_apicid, |
@@ -2127,7 +2127,7 @@ void generic_processor_info(int apicid, int version) | |||
2127 | " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); | 2127 | " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); |
2128 | 2128 | ||
2129 | disabled_cpus++; | 2129 | disabled_cpus++; |
2130 | return; | 2130 | return -ENODEV; |
2131 | } | 2131 | } |
2132 | 2132 | ||
2133 | if (num_processors >= nr_cpu_ids) { | 2133 | if (num_processors >= nr_cpu_ids) { |
@@ -2138,7 +2138,7 @@ void generic_processor_info(int apicid, int version) | |||
2138 | " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); | 2138 | " Processor %d/0x%x ignored.\n", max, thiscpu, apicid); |
2139 | 2139 | ||
2140 | disabled_cpus++; | 2140 | disabled_cpus++; |
2141 | return; | 2141 | return -EINVAL; |
2142 | } | 2142 | } |
2143 | 2143 | ||
2144 | num_processors++; | 2144 | num_processors++; |
@@ -2183,6 +2183,8 @@ void generic_processor_info(int apicid, int version) | |||
2183 | #endif | 2183 | #endif |
2184 | set_cpu_possible(cpu, true); | 2184 | set_cpu_possible(cpu, true); |
2185 | set_cpu_present(cpu, true); | 2185 | set_cpu_present(cpu, true); |
2186 | |||
2187 | return cpu; | ||
2186 | } | 2188 | } |
2187 | 2189 | ||
2188 | int hard_smp_processor_id(void) | 2190 | int hard_smp_processor_id(void) |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 2a165580fa16..85dc05a3aa02 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -81,27 +81,6 @@ | |||
81 | /* State of each CPU */ | 81 | /* State of each CPU */ |
82 | DEFINE_PER_CPU(int, cpu_state) = { 0 }; | 82 | DEFINE_PER_CPU(int, cpu_state) = { 0 }; |
83 | 83 | ||
84 | #ifdef CONFIG_HOTPLUG_CPU | ||
85 | /* | ||
86 | * We need this for trampoline_base protection from concurrent accesses when | ||
87 | * off- and onlining cores wildly. | ||
88 | */ | ||
89 | static DEFINE_MUTEX(x86_cpu_hotplug_driver_mutex); | ||
90 | |||
91 | void cpu_hotplug_driver_lock(void) | ||
92 | { | ||
93 | mutex_lock(&x86_cpu_hotplug_driver_mutex); | ||
94 | } | ||
95 | |||
96 | void cpu_hotplug_driver_unlock(void) | ||
97 | { | ||
98 | mutex_unlock(&x86_cpu_hotplug_driver_mutex); | ||
99 | } | ||
100 | |||
101 | ssize_t arch_cpu_probe(const char *buf, size_t count) { return -1; } | ||
102 | ssize_t arch_cpu_release(const char *buf, size_t count) { return -1; } | ||
103 | #endif | ||
104 | |||
105 | /* Number of siblings per CPU package */ | 84 | /* Number of siblings per CPU package */ |
106 | int smp_num_siblings = 1; | 85 | int smp_num_siblings = 1; |
107 | EXPORT_SYMBOL(smp_num_siblings); | 86 | EXPORT_SYMBOL(smp_num_siblings); |
diff --git a/arch/x86/kernel/topology.c b/arch/x86/kernel/topology.c index 6e60b5fe2244..649b010da00b 100644 --- a/arch/x86/kernel/topology.c +++ b/arch/x86/kernel/topology.c | |||
@@ -65,29 +65,32 @@ int __ref _debug_hotplug_cpu(int cpu, int action) | |||
65 | if (!cpu_is_hotpluggable(cpu)) | 65 | if (!cpu_is_hotpluggable(cpu)) |
66 | return -EINVAL; | 66 | return -EINVAL; |
67 | 67 | ||
68 | cpu_hotplug_driver_lock(); | 68 | lock_device_hotplug(); |
69 | 69 | ||
70 | switch (action) { | 70 | switch (action) { |
71 | case 0: | 71 | case 0: |
72 | ret = cpu_down(cpu); | 72 | ret = cpu_down(cpu); |
73 | if (!ret) { | 73 | if (!ret) { |
74 | pr_info("CPU %u is now offline\n", cpu); | 74 | pr_info("CPU %u is now offline\n", cpu); |
75 | dev->offline = true; | ||
75 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | 76 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); |
76 | } else | 77 | } else |
77 | pr_debug("Can't offline CPU%d.\n", cpu); | 78 | pr_debug("Can't offline CPU%d.\n", cpu); |
78 | break; | 79 | break; |
79 | case 1: | 80 | case 1: |
80 | ret = cpu_up(cpu); | 81 | ret = cpu_up(cpu); |
81 | if (!ret) | 82 | if (!ret) { |
83 | dev->offline = false; | ||
82 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | 84 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); |
83 | else | 85 | } else { |
84 | pr_debug("Can't online CPU%d.\n", cpu); | 86 | pr_debug("Can't online CPU%d.\n", cpu); |
87 | } | ||
85 | break; | 88 | break; |
86 | default: | 89 | default: |
87 | ret = -EINVAL; | 90 | ret = -EINVAL; |
88 | } | 91 | } |
89 | 92 | ||
90 | cpu_hotplug_driver_unlock(); | 93 | unlock_device_hotplug(); |
91 | 94 | ||
92 | return ret; | 95 | return ret; |
93 | } | 96 | } |
diff --git a/arch/x86/lib/msr-smp.c b/arch/x86/lib/msr-smp.c index a6b1b86d2253..518532e6a3fa 100644 --- a/arch/x86/lib/msr-smp.c +++ b/arch/x86/lib/msr-smp.c | |||
@@ -47,6 +47,21 @@ int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h) | |||
47 | } | 47 | } |
48 | EXPORT_SYMBOL(rdmsr_on_cpu); | 48 | EXPORT_SYMBOL(rdmsr_on_cpu); |
49 | 49 | ||
50 | int rdmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 *q) | ||
51 | { | ||
52 | int err; | ||
53 | struct msr_info rv; | ||
54 | |||
55 | memset(&rv, 0, sizeof(rv)); | ||
56 | |||
57 | rv.msr_no = msr_no; | ||
58 | err = smp_call_function_single(cpu, __rdmsr_on_cpu, &rv, 1); | ||
59 | *q = rv.reg.q; | ||
60 | |||
61 | return err; | ||
62 | } | ||
63 | EXPORT_SYMBOL(rdmsrl_on_cpu); | ||
64 | |||
50 | int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | 65 | int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) |
51 | { | 66 | { |
52 | int err; | 67 | int err; |
@@ -63,6 +78,22 @@ int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | |||
63 | } | 78 | } |
64 | EXPORT_SYMBOL(wrmsr_on_cpu); | 79 | EXPORT_SYMBOL(wrmsr_on_cpu); |
65 | 80 | ||
81 | int wrmsrl_on_cpu(unsigned int cpu, u32 msr_no, u64 q) | ||
82 | { | ||
83 | int err; | ||
84 | struct msr_info rv; | ||
85 | |||
86 | memset(&rv, 0, sizeof(rv)); | ||
87 | |||
88 | rv.msr_no = msr_no; | ||
89 | rv.reg.q = q; | ||
90 | |||
91 | err = smp_call_function_single(cpu, __wrmsr_on_cpu, &rv, 1); | ||
92 | |||
93 | return err; | ||
94 | } | ||
95 | EXPORT_SYMBOL(wrmsrl_on_cpu); | ||
96 | |||
66 | static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no, | 97 | static void __rwmsr_on_cpus(const struct cpumask *mask, u32 msr_no, |
67 | struct msr *msrs, | 98 | struct msr *msrs, |
68 | void (*msr_func) (void *info)) | 99 | void (*msr_func) (void *info)) |
@@ -159,6 +190,37 @@ int wrmsr_safe_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h) | |||
159 | } | 190 | } |
160 | EXPORT_SYMBOL(wrmsr_safe_on_cpu); | 191 | EXPORT_SYMBOL(wrmsr_safe_on_cpu); |
161 | 192 | ||
193 | int wrmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 q) | ||
194 | { | ||
195 | int err; | ||
196 | struct msr_info rv; | ||
197 | |||
198 | memset(&rv, 0, sizeof(rv)); | ||
199 | |||
200 | rv.msr_no = msr_no; | ||
201 | rv.reg.q = q; | ||
202 | |||
203 | err = smp_call_function_single(cpu, __wrmsr_safe_on_cpu, &rv, 1); | ||
204 | |||
205 | return err ? err : rv.err; | ||
206 | } | ||
207 | EXPORT_SYMBOL(wrmsrl_safe_on_cpu); | ||
208 | |||
209 | int rdmsrl_safe_on_cpu(unsigned int cpu, u32 msr_no, u64 *q) | ||
210 | { | ||
211 | int err; | ||
212 | struct msr_info rv; | ||
213 | |||
214 | memset(&rv, 0, sizeof(rv)); | ||
215 | |||
216 | rv.msr_no = msr_no; | ||
217 | err = smp_call_function_single(cpu, __rdmsr_safe_on_cpu, &rv, 1); | ||
218 | *q = rv.reg.q; | ||
219 | |||
220 | return err ? err : rv.err; | ||
221 | } | ||
222 | EXPORT_SYMBOL(rdmsrl_safe_on_cpu); | ||
223 | |||
162 | /* | 224 | /* |
163 | * These variants are significantly slower, but allows control over | 225 | * These variants are significantly slower, but allows control over |
164 | * the entire 32-bit GPR set. | 226 | * the entire 32-bit GPR set. |
diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index fef7d0ba7e3a..649a12befba9 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c | |||
@@ -40,16 +40,9 @@ static bool lid_wake_on_close; | |||
40 | */ | 40 | */ |
41 | static int set_lid_wake_behavior(bool wake_on_close) | 41 | static int set_lid_wake_behavior(bool wake_on_close) |
42 | { | 42 | { |
43 | struct acpi_object_list arg_list; | ||
44 | union acpi_object arg; | ||
45 | acpi_status status; | 43 | acpi_status status; |
46 | 44 | ||
47 | arg_list.count = 1; | 45 | status = acpi_execute_simple_method(NULL, "\\_SB.PCI0.LID.LIDW", wake_on_close); |
48 | arg_list.pointer = &arg; | ||
49 | arg.type = ACPI_TYPE_INTEGER; | ||
50 | arg.integer.value = wake_on_close; | ||
51 | |||
52 | status = acpi_evaluate_object(NULL, "\\_SB.PCI0.LID.LIDW", &arg_list, NULL); | ||
53 | if (ACPI_FAILURE(status)) { | 46 | if (ACPI_FAILURE(status)) { |
54 | pr_warning(PFX "failed to set lid behavior\n"); | 47 | pr_warning(PFX "failed to set lid behavior\n"); |
55 | return 1; | 48 | return 1; |