aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/acpi_memhotplug.c146
-rw-r--r--drivers/acpi/numa.c15
-rw-r--r--drivers/acpi/processor_idle.c21
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
328config ACPI_HOTPLUG_MEMORY 328config 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
58static int acpi_memory_device_add(struct acpi_device *device); 58static int acpi_memory_device_add(struct acpi_device *device);
59static int acpi_memory_device_remove(struct acpi_device *device, int type); 59static int acpi_memory_device_remove(struct acpi_device *device, int type);
60static int acpi_memory_device_start(struct acpi_device *device);
60 61
61static struct acpi_driver acpi_memory_device_driver = { 62static 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
73struct 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
71struct acpi_memory_device { 82struct 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
88static acpi_status
89acpi_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
80static int 125static int
81acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) 126acpi_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
112static int 144static int
@@ -181,7 +213,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
181 213
182static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) 214static 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)
246static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) 300static 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
451static 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
258EXPORT_SYMBOL(acpi_get_pxm); 257EXPORT_SYMBOL(acpi_get_pxm);
258
259int 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}
271EXPORT_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
207static void acpi_safe_halt(void) 207static 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
216static atomic_t c3_cpu_count; 216static 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;