diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/Kconfig | 2 | ||||
-rw-r--r-- | drivers/acpi/acpi_memhotplug.c | 146 | ||||
-rw-r--r-- | drivers/acpi/numa.c | 15 | ||||
-rw-r--r-- | drivers/acpi/processor_idle.c | 21 |
4 files changed, 141 insertions, 43 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 94b8d820c512..610d2cc02cf8 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -328,7 +328,7 @@ config ACPI_CONTAINER | |||
328 | config ACPI_HOTPLUG_MEMORY | 328 | config ACPI_HOTPLUG_MEMORY |
329 | tristate "Memory Hotplug" | 329 | tristate "Memory Hotplug" |
330 | depends on ACPI | 330 | depends on ACPI |
331 | depends on MEMORY_HOTPLUG || X86_64 | 331 | depends on MEMORY_HOTPLUG |
332 | default n | 332 | default n |
333 | help | 333 | help |
334 | This driver adds supports for ACPI Memory Hotplug. This driver | 334 | This driver adds supports for ACPI Memory Hotplug. This driver |
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index e0a95ba72371..1012284ff4f7 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c | |||
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL"); | |||
57 | 57 | ||
58 | static int acpi_memory_device_add(struct acpi_device *device); | 58 | static int acpi_memory_device_add(struct acpi_device *device); |
59 | static int acpi_memory_device_remove(struct acpi_device *device, int type); | 59 | static int acpi_memory_device_remove(struct acpi_device *device, int type); |
60 | static int acpi_memory_device_start(struct acpi_device *device); | ||
60 | 61 | ||
61 | static struct acpi_driver acpi_memory_device_driver = { | 62 | static struct acpi_driver acpi_memory_device_driver = { |
62 | .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, | 63 | .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, |
@@ -65,48 +66,79 @@ static struct acpi_driver acpi_memory_device_driver = { | |||
65 | .ops = { | 66 | .ops = { |
66 | .add = acpi_memory_device_add, | 67 | .add = acpi_memory_device_add, |
67 | .remove = acpi_memory_device_remove, | 68 | .remove = acpi_memory_device_remove, |
69 | .start = acpi_memory_device_start, | ||
68 | }, | 70 | }, |
69 | }; | 71 | }; |
70 | 72 | ||
73 | struct acpi_memory_info { | ||
74 | struct list_head list; | ||
75 | u64 start_addr; /* Memory Range start physical addr */ | ||
76 | u64 length; /* Memory Range length */ | ||
77 | unsigned short caching; /* memory cache attribute */ | ||
78 | unsigned short write_protect; /* memory read/write attribute */ | ||
79 | unsigned int enabled:1; | ||
80 | }; | ||
81 | |||
71 | struct acpi_memory_device { | 82 | struct acpi_memory_device { |
72 | acpi_handle handle; | 83 | acpi_handle handle; |
73 | unsigned int state; /* State of the memory device */ | 84 | unsigned int state; /* State of the memory device */ |
74 | unsigned short caching; /* memory cache attribute */ | 85 | struct list_head res_list; |
75 | unsigned short write_protect; /* memory read/write attribute */ | ||
76 | u64 start_addr; /* Memory Range start physical addr */ | ||
77 | u64 length; /* Memory Range length */ | ||
78 | }; | 86 | }; |
79 | 87 | ||
88 | static acpi_status | ||
89 | acpi_memory_get_resource(struct acpi_resource *resource, void *context) | ||
90 | { | ||
91 | struct acpi_memory_device *mem_device = context; | ||
92 | struct acpi_resource_address64 address64; | ||
93 | struct acpi_memory_info *info, *new; | ||
94 | acpi_status status; | ||
95 | |||
96 | status = acpi_resource_to_address64(resource, &address64); | ||
97 | if (ACPI_FAILURE(status) || | ||
98 | (address64.resource_type != ACPI_MEMORY_RANGE)) | ||
99 | return AE_OK; | ||
100 | |||
101 | list_for_each_entry(info, &mem_device->res_list, list) { | ||
102 | /* Can we combine the resource range information? */ | ||
103 | if ((info->caching == address64.info.mem.caching) && | ||
104 | (info->write_protect == address64.info.mem.write_protect) && | ||
105 | (info->start_addr + info->length == address64.minimum)) { | ||
106 | info->length += address64.address_length; | ||
107 | return AE_OK; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); | ||
112 | if (!new) | ||
113 | return AE_ERROR; | ||
114 | |||
115 | INIT_LIST_HEAD(&new->list); | ||
116 | new->caching = address64.info.mem.caching; | ||
117 | new->write_protect = address64.info.mem.write_protect; | ||
118 | new->start_addr = address64.minimum; | ||
119 | new->length = address64.address_length; | ||
120 | list_add_tail(&new->list, &mem_device->res_list); | ||
121 | |||
122 | return AE_OK; | ||
123 | } | ||
124 | |||
80 | static int | 125 | static int |
81 | acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) | 126 | acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) |
82 | { | 127 | { |
83 | acpi_status status; | 128 | acpi_status status; |
84 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 129 | struct acpi_memory_info *info, *n; |
85 | struct acpi_resource *resource = NULL; | ||
86 | struct acpi_resource_address64 address64; | ||
87 | 130 | ||
88 | ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources"); | 131 | ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources"); |
89 | 132 | ||
90 | /* Get the range from the _CRS */ | 133 | status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS, |
91 | status = acpi_get_current_resources(mem_device->handle, &buffer); | 134 | acpi_memory_get_resource, mem_device); |
92 | if (ACPI_FAILURE(status)) | 135 | if (ACPI_FAILURE(status)) { |
93 | return_VALUE(-EINVAL); | 136 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) |
94 | 137 | kfree(info); | |
95 | resource = (struct acpi_resource *)buffer.pointer; | 138 | return -EINVAL; |
96 | status = acpi_resource_to_address64(resource, &address64); | ||
97 | if (ACPI_SUCCESS(status)) { | ||
98 | if (address64.resource_type == ACPI_MEMORY_RANGE) { | ||
99 | /* Populate the structure */ | ||
100 | mem_device->caching = address64.info.mem.caching; | ||
101 | mem_device->write_protect = | ||
102 | address64.info.mem.write_protect; | ||
103 | mem_device->start_addr = address64.minimum; | ||
104 | mem_device->length = address64.address_length; | ||
105 | } | ||
106 | } | 139 | } |
107 | 140 | ||
108 | acpi_os_free(buffer.pointer); | 141 | return 0; |
109 | return_VALUE(0); | ||
110 | } | 142 | } |
111 | 143 | ||
112 | static int | 144 | static int |
@@ -181,7 +213,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device) | |||
181 | 213 | ||
182 | static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | 214 | static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) |
183 | { | 215 | { |
184 | int result; | 216 | int result, num_enabled = 0; |
217 | struct acpi_memory_info *info; | ||
218 | int node; | ||
185 | 219 | ||
186 | ACPI_FUNCTION_TRACE("acpi_memory_enable_device"); | 220 | ACPI_FUNCTION_TRACE("acpi_memory_enable_device"); |
187 | 221 | ||
@@ -194,15 +228,35 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) | |||
194 | return result; | 228 | return result; |
195 | } | 229 | } |
196 | 230 | ||
231 | node = acpi_get_node(mem_device->handle); | ||
197 | /* | 232 | /* |
198 | * Tell the VM there is more memory here... | 233 | * Tell the VM there is more memory here... |
199 | * Note: Assume that this function returns zero on success | 234 | * Note: Assume that this function returns zero on success |
235 | * We don't have memory-hot-add rollback function,now. | ||
236 | * (i.e. memory-hot-remove function) | ||
200 | */ | 237 | */ |
201 | result = add_memory(mem_device->start_addr, mem_device->length); | 238 | list_for_each_entry(info, &mem_device->res_list, list) { |
202 | if (result) { | 239 | u64 start_pfn, end_pfn; |
240 | |||
241 | start_pfn = info->start_addr >> PAGE_SHIFT; | ||
242 | end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT; | ||
243 | |||
244 | if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) { | ||
245 | /* already enabled. try next area */ | ||
246 | num_enabled++; | ||
247 | continue; | ||
248 | } | ||
249 | |||
250 | result = add_memory(node, info->start_addr, info->length); | ||
251 | if (result) | ||
252 | continue; | ||
253 | info->enabled = 1; | ||
254 | num_enabled++; | ||
255 | } | ||
256 | if (!num_enabled) { | ||
203 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n")); | 257 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n")); |
204 | mem_device->state = MEMORY_INVALID_STATE; | 258 | mem_device->state = MEMORY_INVALID_STATE; |
205 | return result; | 259 | return -EINVAL; |
206 | } | 260 | } |
207 | 261 | ||
208 | return result; | 262 | return result; |
@@ -246,8 +300,7 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device) | |||
246 | static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) | 300 | static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) |
247 | { | 301 | { |
248 | int result; | 302 | int result; |
249 | u64 start = mem_device->start_addr; | 303 | struct acpi_memory_info *info, *n; |
250 | u64 len = mem_device->length; | ||
251 | 304 | ||
252 | ACPI_FUNCTION_TRACE("acpi_memory_disable_device"); | 305 | ACPI_FUNCTION_TRACE("acpi_memory_disable_device"); |
253 | 306 | ||
@@ -255,10 +308,13 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) | |||
255 | * Ask the VM to offline this memory range. | 308 | * Ask the VM to offline this memory range. |
256 | * Note: Assume that this function returns zero on success | 309 | * Note: Assume that this function returns zero on success |
257 | */ | 310 | */ |
258 | result = remove_memory(start, len); | 311 | list_for_each_entry_safe(info, n, &mem_device->res_list, list) { |
259 | if (result) { | 312 | if (info->enabled) { |
260 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n")); | 313 | result = remove_memory(info->start_addr, info->length); |
261 | return_VALUE(result); | 314 | if (result) |
315 | return result; | ||
316 | } | ||
317 | kfree(info); | ||
262 | } | 318 | } |
263 | 319 | ||
264 | /* Power-off and eject the device */ | 320 | /* Power-off and eject the device */ |
@@ -356,6 +412,7 @@ static int acpi_memory_device_add(struct acpi_device *device) | |||
356 | return_VALUE(-ENOMEM); | 412 | return_VALUE(-ENOMEM); |
357 | memset(mem_device, 0, sizeof(struct acpi_memory_device)); | 413 | memset(mem_device, 0, sizeof(struct acpi_memory_device)); |
358 | 414 | ||
415 | INIT_LIST_HEAD(&mem_device->res_list); | ||
359 | mem_device->handle = device->handle; | 416 | mem_device->handle = device->handle; |
360 | sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); | 417 | sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); |
361 | sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); | 418 | sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); |
@@ -391,6 +448,25 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type) | |||
391 | return_VALUE(0); | 448 | return_VALUE(0); |
392 | } | 449 | } |
393 | 450 | ||
451 | static int acpi_memory_device_start (struct acpi_device *device) | ||
452 | { | ||
453 | struct acpi_memory_device *mem_device; | ||
454 | int result = 0; | ||
455 | |||
456 | ACPI_FUNCTION_TRACE("acpi_memory_device_start"); | ||
457 | |||
458 | mem_device = acpi_driver_data(device); | ||
459 | |||
460 | if (!acpi_memory_check_device(mem_device)) { | ||
461 | /* call add_memory func */ | ||
462 | result = acpi_memory_enable_device(mem_device); | ||
463 | if (result) | ||
464 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
465 | "Error in acpi_memory_enable_device\n")); | ||
466 | } | ||
467 | return_VALUE(result); | ||
468 | } | ||
469 | |||
394 | /* | 470 | /* |
395 | * Helper function to check for memory device | 471 | * Helper function to check for memory device |
396 | */ | 472 | */ |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index e2c1a16078c9..13d6d5bdea26 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
@@ -254,5 +254,18 @@ int acpi_get_pxm(acpi_handle h) | |||
254 | } while (ACPI_SUCCESS(status)); | 254 | } while (ACPI_SUCCESS(status)); |
255 | return -1; | 255 | return -1; |
256 | } | 256 | } |
257 | |||
258 | EXPORT_SYMBOL(acpi_get_pxm); | 257 | EXPORT_SYMBOL(acpi_get_pxm); |
258 | |||
259 | int acpi_get_node(acpi_handle *handle) | ||
260 | { | ||
261 | int pxm, node = -1; | ||
262 | |||
263 | ACPI_FUNCTION_TRACE("acpi_get_node"); | ||
264 | |||
265 | pxm = acpi_get_pxm(handle); | ||
266 | if (pxm >= 0) | ||
267 | node = acpi_map_pxm_to_node(pxm); | ||
268 | |||
269 | return_VALUE(node); | ||
270 | } | ||
271 | EXPORT_SYMBOL(acpi_get_node); | ||
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 3b97a5eae9e8..8a74bf3efd8e 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -206,11 +206,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, | |||
206 | 206 | ||
207 | static void acpi_safe_halt(void) | 207 | static void acpi_safe_halt(void) |
208 | { | 208 | { |
209 | clear_thread_flag(TIF_POLLING_NRFLAG); | 209 | current_thread_info()->status &= ~TS_POLLING; |
210 | smp_mb__after_clear_bit(); | 210 | smp_mb__after_clear_bit(); |
211 | if (!need_resched()) | 211 | if (!need_resched()) |
212 | safe_halt(); | 212 | safe_halt(); |
213 | set_thread_flag(TIF_POLLING_NRFLAG); | 213 | current_thread_info()->status |= TS_POLLING; |
214 | } | 214 | } |
215 | 215 | ||
216 | static atomic_t c3_cpu_count; | 216 | static atomic_t c3_cpu_count; |
@@ -330,10 +330,10 @@ static void acpi_processor_idle(void) | |||
330 | * Invoke the current Cx state to put the processor to sleep. | 330 | * Invoke the current Cx state to put the processor to sleep. |
331 | */ | 331 | */ |
332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { | 332 | if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { |
333 | clear_thread_flag(TIF_POLLING_NRFLAG); | 333 | current_thread_info()->status &= ~TS_POLLING; |
334 | smp_mb__after_clear_bit(); | 334 | smp_mb__after_clear_bit(); |
335 | if (need_resched()) { | 335 | if (need_resched()) { |
336 | set_thread_flag(TIF_POLLING_NRFLAG); | 336 | current_thread_info()->status |= TS_POLLING; |
337 | local_irq_enable(); | 337 | local_irq_enable(); |
338 | return; | 338 | return; |
339 | } | 339 | } |
@@ -369,9 +369,14 @@ static void acpi_processor_idle(void) | |||
369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 369 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
370 | /* Get end time (ticks) */ | 370 | /* Get end time (ticks) */ |
371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); | 371 | t2 = inl(acpi_fadt.xpm_tmr_blk.address); |
372 | |||
373 | #ifdef CONFIG_GENERIC_TIME | ||
374 | /* TSC halts in C2, so notify users */ | ||
375 | mark_tsc_unstable(); | ||
376 | #endif | ||
372 | /* Re-enable interrupts */ | 377 | /* Re-enable interrupts */ |
373 | local_irq_enable(); | 378 | local_irq_enable(); |
374 | set_thread_flag(TIF_POLLING_NRFLAG); | 379 | current_thread_info()->status |= TS_POLLING; |
375 | /* Compute time (ticks) that we were actually asleep */ | 380 | /* Compute time (ticks) that we were actually asleep */ |
376 | sleep_ticks = | 381 | sleep_ticks = |
377 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; | 382 | ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; |
@@ -409,9 +414,13 @@ static void acpi_processor_idle(void) | |||
409 | ACPI_MTX_DO_NOT_LOCK); | 414 | ACPI_MTX_DO_NOT_LOCK); |
410 | } | 415 | } |
411 | 416 | ||
417 | #ifdef CONFIG_GENERIC_TIME | ||
418 | /* TSC halts in C3, so notify users */ | ||
419 | mark_tsc_unstable(); | ||
420 | #endif | ||
412 | /* Re-enable interrupts */ | 421 | /* Re-enable interrupts */ |
413 | local_irq_enable(); | 422 | local_irq_enable(); |
414 | set_thread_flag(TIF_POLLING_NRFLAG); | 423 | current_thread_info()->status |= TS_POLLING; |
415 | /* Compute time (ticks) that we were actually asleep */ | 424 | /* Compute time (ticks) that we were actually asleep */ |
416 | sleep_ticks = | 425 | sleep_ticks = |
417 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; | 426 | ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; |