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.c142
-rw-r--r--drivers/acpi/numa.c15
3 files changed, 124 insertions, 35 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index ce15aed1df3f..bc2652d72fdc 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -335,7 +335,7 @@ config ACPI_CONTAINER
335config ACPI_HOTPLUG_MEMORY 335config ACPI_HOTPLUG_MEMORY
336 tristate "Memory Hotplug" 336 tristate "Memory Hotplug"
337 depends on ACPI 337 depends on ACPI
338 depends on MEMORY_HOTPLUG || X86_64 338 depends on MEMORY_HOTPLUG
339 default n 339 default n
340 help 340 help
341 This driver adds supports for ACPI Memory Hotplug. This driver 341 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 b05469513842..6f5e395c78af 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,46 +66,77 @@ 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 131
89 /* Get the range from the _CRS */ 132 status = acpi_walk_resources(mem_device->handle, METHOD_NAME__CRS,
90 status = acpi_get_current_resources(mem_device->handle, &buffer); 133 acpi_memory_get_resource, mem_device);
91 if (ACPI_FAILURE(status)) 134 if (ACPI_FAILURE(status)) {
135 list_for_each_entry_safe(info, n, &mem_device->res_list, list)
136 kfree(info);
92 return -EINVAL; 137 return -EINVAL;
93
94 resource = (struct acpi_resource *)buffer.pointer;
95 status = acpi_resource_to_address64(resource, &address64);
96 if (ACPI_SUCCESS(status)) {
97 if (address64.resource_type == ACPI_MEMORY_RANGE) {
98 /* Populate the structure */
99 mem_device->caching = address64.info.mem.caching;
100 mem_device->write_protect =
101 address64.info.mem.write_protect;
102 mem_device->start_addr = address64.minimum;
103 mem_device->length = address64.address_length;
104 }
105 } 138 }
106 139
107 acpi_os_free(buffer.pointer);
108 return 0; 140 return 0;
109} 141}
110 142
@@ -177,7 +209,9 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
177 209
178static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) 210static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
179{ 211{
180 int result; 212 int result, num_enabled = 0;
213 struct acpi_memory_info *info;
214 int node;
181 215
182 216
183 /* Get the range from the _CRS */ 217 /* Get the range from the _CRS */
@@ -188,15 +222,35 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
188 return result; 222 return result;
189 } 223 }
190 224
225 node = acpi_get_node(mem_device->handle);
191 /* 226 /*
192 * Tell the VM there is more memory here... 227 * Tell the VM there is more memory here...
193 * Note: Assume that this function returns zero on success 228 * Note: Assume that this function returns zero on success
229 * We don't have memory-hot-add rollback function,now.
230 * (i.e. memory-hot-remove function)
194 */ 231 */
195 result = add_memory(mem_device->start_addr, mem_device->length); 232 list_for_each_entry(info, &mem_device->res_list, list) {
196 if (result) { 233 u64 start_pfn, end_pfn;
197 printk(KERN_ERR PREFIX "add_memory failed\n"); 234
235 start_pfn = info->start_addr >> PAGE_SHIFT;
236 end_pfn = (info->start_addr + info->length - 1) >> PAGE_SHIFT;
237
238 if (pfn_valid(start_pfn) || pfn_valid(end_pfn)) {
239 /* already enabled. try next area */
240 num_enabled++;
241 continue;
242 }
243
244 result = add_memory(node, info->start_addr, info->length);
245 if (result)
246 continue;
247 info->enabled = 1;
248 num_enabled++;
249 }
250 if (!num_enabled) {
251 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
198 mem_device->state = MEMORY_INVALID_STATE; 252 mem_device->state = MEMORY_INVALID_STATE;
199 return result; 253 return -EINVAL;
200 } 254 }
201 255
202 return result; 256 return result;
@@ -239,17 +293,21 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
239static int acpi_memory_disable_device(struct acpi_memory_device *mem_device) 293static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
240{ 294{
241 int result; 295 int result;
242 u64 start = mem_device->start_addr; 296 struct acpi_memory_info *info, *n;
243 u64 len = mem_device->length;
244 297
245 298
246 /* 299 /*
247 * Ask the VM to offline this memory range. 300 * Ask the VM to offline this memory range.
248 * Note: Assume that this function returns zero on success 301 * Note: Assume that this function returns zero on success
249 */ 302 */
250 result = remove_memory(start, len); 303 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
251 if (result) 304 if (info->enabled) {
252 return result; 305 result = remove_memory(info->start_addr, info->length);
306 if (result)
307 return result;
308 }
309 kfree(info);
310 }
253 311
254 /* Power-off and eject the device */ 312 /* Power-off and eject the device */
255 result = acpi_memory_powerdown_device(mem_device); 313 result = acpi_memory_powerdown_device(mem_device);
@@ -339,6 +397,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
339 return -ENOMEM; 397 return -ENOMEM;
340 memset(mem_device, 0, sizeof(struct acpi_memory_device)); 398 memset(mem_device, 0, sizeof(struct acpi_memory_device));
341 399
400 INIT_LIST_HEAD(&mem_device->res_list);
342 mem_device->handle = device->handle; 401 mem_device->handle = device->handle;
343 sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); 402 sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
344 sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); 403 sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
@@ -373,6 +432,23 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type)
373 return 0; 432 return 0;
374} 433}
375 434
435static int acpi_memory_device_start (struct acpi_device *device)
436{
437 struct acpi_memory_device *mem_device;
438 int result = 0;
439
440 mem_device = acpi_driver_data(device);
441
442 if (!acpi_memory_check_device(mem_device)) {
443 /* call add_memory func */
444 result = acpi_memory_enable_device(mem_device);
445 if (result)
446 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
447 "Error in acpi_memory_enable_device\n"));
448 }
449 return result;
450}
451
376/* 452/*
377 * Helper function to check for memory device 453 * Helper function to check for memory device
378 */ 454 */
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);