aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpi_memhotplug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpi_memhotplug.c')
-rw-r--r--drivers/acpi/acpi_memhotplug.c42
1 files changed, 33 insertions, 9 deletions
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index e52ad5d3792d..f7e300769966 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -78,6 +78,7 @@ struct acpi_memory_info {
78 unsigned short caching; /* memory cache attribute */ 78 unsigned short caching; /* memory cache attribute */
79 unsigned short write_protect; /* memory read/write attribute */ 79 unsigned short write_protect; /* memory read/write attribute */
80 unsigned int enabled:1; 80 unsigned int enabled:1;
81 unsigned int failed:1;
81}; 82};
82 83
83struct acpi_memory_device { 84struct acpi_memory_device {
@@ -257,9 +258,23 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
257 node = memory_add_physaddr_to_nid(info->start_addr); 258 node = memory_add_physaddr_to_nid(info->start_addr);
258 259
259 result = add_memory(node, info->start_addr, info->length); 260 result = add_memory(node, info->start_addr, info->length);
260 if (result) 261
262 /*
263 * If the memory block has been used by the kernel, add_memory()
264 * returns -EEXIST. If add_memory() returns the other error, it
265 * means that this memory block is not used by the kernel.
266 */
267 if (result && result != -EEXIST) {
268 info->failed = 1;
261 continue; 269 continue;
262 info->enabled = 1; 270 }
271
272 if (!result)
273 info->enabled = 1;
274 /*
275 * Add num_enable even if add_memory() returns -EEXIST, so the
276 * device is bound to this driver.
277 */
263 num_enabled++; 278 num_enabled++;
264 } 279 }
265 if (!num_enabled) { 280 if (!num_enabled) {
@@ -280,21 +295,30 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
280 295
281static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) 296static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
282{ 297{
283 int result; 298 int result = 0;
284 struct acpi_memory_info *info, *n; 299 struct acpi_memory_info *info, *n;
285 300
286 list_for_each_entry_safe(info, n, &mem_device->res_list, list) { 301 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
287 if (info->enabled) { 302 if (info->failed)
288 result = remove_memory(info->start_addr, info->length); 303 /* The kernel does not use this memory block */
289 if (result) 304 continue;
290 return result; 305
291 } 306 if (!info->enabled)
307 /*
308 * The kernel uses this memory block, but it may be not
309 * managed by us.
310 */
311 return -EBUSY;
312
313 result = remove_memory(info->start_addr, info->length);
314 if (result)
315 return result;
292 316
293 list_del(&info->list); 317 list_del(&info->list);
294 kfree(info); 318 kfree(info);
295 } 319 }
296 320
297 return 0; 321 return result;
298} 322}
299 323
300static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data) 324static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)