|
@@ -78,6 +78,7 @@ struct acpi_memory_info {
|
|
|
unsigned short caching; /* memory cache attribute */
|
|
|
unsigned short write_protect; /* memory read/write attribute */
|
|
|
unsigned int enabled:1;
|
|
|
+ unsigned int failed:1;
|
|
|
};
|
|
|
|
|
|
struct acpi_memory_device {
|
|
@@ -257,9 +258,23 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
|
|
node = memory_add_physaddr_to_nid(info->start_addr);
|
|
|
|
|
|
result = add_memory(node, info->start_addr, info->length);
|
|
|
- if (result)
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the memory block has been used by the kernel, add_memory()
|
|
|
+ * returns -EEXIST. If add_memory() returns the other error, it
|
|
|
+ * means that this memory block is not used by the kernel.
|
|
|
+ */
|
|
|
+ if (result && result != -EEXIST) {
|
|
|
+ info->failed = 1;
|
|
|
continue;
|
|
|
- info->enabled = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!result)
|
|
|
+ info->enabled = 1;
|
|
|
+ /*
|
|
|
+ * Add num_enable even if add_memory() returns -EEXIST, so the
|
|
|
+ * device is bound to this driver.
|
|
|
+ */
|
|
|
num_enabled++;
|
|
|
}
|
|
|
if (!num_enabled) {
|
|
@@ -280,21 +295,30 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
|
|
|
|
|
|
static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
|
|
|
{
|
|
|
- int result;
|
|
|
+ int result = 0;
|
|
|
struct acpi_memory_info *info, *n;
|
|
|
|
|
|
list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
|
|
|
- if (info->enabled) {
|
|
|
- result = remove_memory(info->start_addr, info->length);
|
|
|
- if (result)
|
|
|
- return result;
|
|
|
- }
|
|
|
+ if (info->failed)
|
|
|
+ /* The kernel does not use this memory block */
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!info->enabled)
|
|
|
+ /*
|
|
|
+ * The kernel uses this memory block, but it may be not
|
|
|
+ * managed by us.
|
|
|
+ */
|
|
|
+ return -EBUSY;
|
|
|
+
|
|
|
+ result = remove_memory(info->start_addr, info->length);
|
|
|
+ if (result)
|
|
|
+ return result;
|
|
|
|
|
|
list_del(&info->list);
|
|
|
kfree(info);
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
|