0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <linux/acpi.h>
0016 #include <linux/memory.h>
0017 #include <linux/memory_hotplug.h>
0018
0019 #include "internal.h"
0020
0021 #define ACPI_MEMORY_DEVICE_CLASS "memory"
0022 #define ACPI_MEMORY_DEVICE_HID "PNP0C80"
0023 #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
0024
0025 static const struct acpi_device_id memory_device_ids[] = {
0026 {ACPI_MEMORY_DEVICE_HID, 0},
0027 {"", 0},
0028 };
0029
0030 #ifdef CONFIG_ACPI_HOTPLUG_MEMORY
0031
0032 static int acpi_memory_device_add(struct acpi_device *device,
0033 const struct acpi_device_id *not_used);
0034 static void acpi_memory_device_remove(struct acpi_device *device);
0035
0036 static struct acpi_scan_handler memory_device_handler = {
0037 .ids = memory_device_ids,
0038 .attach = acpi_memory_device_add,
0039 .detach = acpi_memory_device_remove,
0040 .hotplug = {
0041 .enabled = true,
0042 },
0043 };
0044
0045 struct acpi_memory_info {
0046 struct list_head list;
0047 u64 start_addr;
0048 u64 length;
0049 unsigned short caching;
0050 unsigned short write_protect;
0051 unsigned int enabled:1;
0052 };
0053
0054 struct acpi_memory_device {
0055 struct acpi_device *device;
0056 struct list_head res_list;
0057 int mgid;
0058 };
0059
0060 static acpi_status
0061 acpi_memory_get_resource(struct acpi_resource *resource, void *context)
0062 {
0063 struct acpi_memory_device *mem_device = context;
0064 struct acpi_resource_address64 address64;
0065 struct acpi_memory_info *info, *new;
0066 acpi_status status;
0067
0068 status = acpi_resource_to_address64(resource, &address64);
0069 if (ACPI_FAILURE(status) ||
0070 (address64.resource_type != ACPI_MEMORY_RANGE))
0071 return AE_OK;
0072
0073 list_for_each_entry(info, &mem_device->res_list, list) {
0074
0075 if ((info->caching == address64.info.mem.caching) &&
0076 (info->write_protect == address64.info.mem.write_protect) &&
0077 (info->start_addr + info->length == address64.address.minimum)) {
0078 info->length += address64.address.address_length;
0079 return AE_OK;
0080 }
0081 }
0082
0083 new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
0084 if (!new)
0085 return AE_ERROR;
0086
0087 INIT_LIST_HEAD(&new->list);
0088 new->caching = address64.info.mem.caching;
0089 new->write_protect = address64.info.mem.write_protect;
0090 new->start_addr = address64.address.minimum;
0091 new->length = address64.address.address_length;
0092 list_add_tail(&new->list, &mem_device->res_list);
0093
0094 return AE_OK;
0095 }
0096
0097 static void
0098 acpi_memory_free_device_resources(struct acpi_memory_device *mem_device)
0099 {
0100 struct acpi_memory_info *info, *n;
0101
0102 list_for_each_entry_safe(info, n, &mem_device->res_list, list)
0103 kfree(info);
0104 INIT_LIST_HEAD(&mem_device->res_list);
0105 }
0106
0107 static int
0108 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
0109 {
0110 acpi_status status;
0111
0112 if (!list_empty(&mem_device->res_list))
0113 return 0;
0114
0115 status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
0116 acpi_memory_get_resource, mem_device);
0117 if (ACPI_FAILURE(status)) {
0118 acpi_memory_free_device_resources(mem_device);
0119 return -EINVAL;
0120 }
0121
0122 return 0;
0123 }
0124
0125 static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
0126 {
0127 unsigned long long current_status;
0128
0129
0130 if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle,
0131 METHOD_NAME__STA, NULL,
0132 ¤t_status)))
0133 return -ENODEV;
0134
0135
0136
0137
0138 if (!((current_status & ACPI_STA_DEVICE_PRESENT)
0139 && (current_status & ACPI_STA_DEVICE_ENABLED)
0140 && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
0141 return -ENODEV;
0142
0143 return 0;
0144 }
0145
0146 static int acpi_bind_memblk(struct memory_block *mem, void *arg)
0147 {
0148 return acpi_bind_one(&mem->dev, arg);
0149 }
0150
0151 static int acpi_bind_memory_blocks(struct acpi_memory_info *info,
0152 struct acpi_device *adev)
0153 {
0154 return walk_memory_blocks(info->start_addr, info->length, adev,
0155 acpi_bind_memblk);
0156 }
0157
0158 static int acpi_unbind_memblk(struct memory_block *mem, void *arg)
0159 {
0160 acpi_unbind_one(&mem->dev);
0161 return 0;
0162 }
0163
0164 static void acpi_unbind_memory_blocks(struct acpi_memory_info *info)
0165 {
0166 walk_memory_blocks(info->start_addr, info->length, NULL,
0167 acpi_unbind_memblk);
0168 }
0169
0170 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
0171 {
0172 acpi_handle handle = mem_device->device->handle;
0173 mhp_t mhp_flags = MHP_NID_IS_MGID;
0174 int result, num_enabled = 0;
0175 struct acpi_memory_info *info;
0176 u64 total_length = 0;
0177 int node, mgid;
0178
0179 node = acpi_get_node(handle);
0180
0181 list_for_each_entry(info, &mem_device->res_list, list) {
0182 if (!info->length)
0183 continue;
0184
0185 if (node < 0)
0186 node = memory_add_physaddr_to_nid(info->start_addr);
0187 total_length += info->length;
0188 }
0189
0190 if (!total_length) {
0191 dev_err(&mem_device->device->dev, "device is empty\n");
0192 return -EINVAL;
0193 }
0194
0195 mgid = memory_group_register_static(node, PFN_UP(total_length));
0196 if (mgid < 0)
0197 return mgid;
0198 mem_device->mgid = mgid;
0199
0200
0201
0202
0203
0204
0205
0206 list_for_each_entry(info, &mem_device->res_list, list) {
0207
0208
0209
0210
0211 if (!info->length)
0212 continue;
0213
0214 if (mhp_supports_memmap_on_memory(info->length))
0215 mhp_flags |= MHP_MEMMAP_ON_MEMORY;
0216 result = __add_memory(mgid, info->start_addr, info->length,
0217 mhp_flags);
0218
0219
0220
0221
0222
0223
0224 if (result && result != -EEXIST)
0225 continue;
0226
0227 result = acpi_bind_memory_blocks(info, mem_device->device);
0228 if (result) {
0229 acpi_unbind_memory_blocks(info);
0230 return -ENODEV;
0231 }
0232
0233 info->enabled = 1;
0234
0235
0236
0237
0238
0239 num_enabled++;
0240 }
0241 if (!num_enabled) {
0242 dev_err(&mem_device->device->dev, "add_memory failed\n");
0243 return -EINVAL;
0244 }
0245
0246
0247
0248
0249
0250
0251
0252
0253 return 0;
0254 }
0255
0256 static void acpi_memory_remove_memory(struct acpi_memory_device *mem_device)
0257 {
0258 struct acpi_memory_info *info, *n;
0259
0260 list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
0261 if (!info->enabled)
0262 continue;
0263
0264 acpi_unbind_memory_blocks(info);
0265 __remove_memory(info->start_addr, info->length);
0266 list_del(&info->list);
0267 kfree(info);
0268 }
0269 }
0270
0271 static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
0272 {
0273 if (!mem_device)
0274 return;
0275
0276
0277 if (mem_device->mgid >= 0)
0278 memory_group_unregister(mem_device->mgid);
0279
0280 acpi_memory_free_device_resources(mem_device);
0281 mem_device->device->driver_data = NULL;
0282 kfree(mem_device);
0283 }
0284
0285 static int acpi_memory_device_add(struct acpi_device *device,
0286 const struct acpi_device_id *not_used)
0287 {
0288 struct acpi_memory_device *mem_device;
0289 int result;
0290
0291 if (!device)
0292 return -EINVAL;
0293
0294 mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
0295 if (!mem_device)
0296 return -ENOMEM;
0297
0298 INIT_LIST_HEAD(&mem_device->res_list);
0299 mem_device->device = device;
0300 mem_device->mgid = -1;
0301 sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
0302 sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
0303 device->driver_data = mem_device;
0304
0305
0306 result = acpi_memory_get_device_resources(mem_device);
0307 if (result) {
0308 device->driver_data = NULL;
0309 kfree(mem_device);
0310 return result;
0311 }
0312
0313 result = acpi_memory_check_device(mem_device);
0314 if (result) {
0315 acpi_memory_device_free(mem_device);
0316 return 0;
0317 }
0318
0319 result = acpi_memory_enable_device(mem_device);
0320 if (result) {
0321 dev_err(&device->dev, "acpi_memory_enable_device() error\n");
0322 acpi_memory_device_free(mem_device);
0323 return result;
0324 }
0325
0326 dev_dbg(&device->dev, "Memory device configured by ACPI\n");
0327 return 1;
0328 }
0329
0330 static void acpi_memory_device_remove(struct acpi_device *device)
0331 {
0332 struct acpi_memory_device *mem_device;
0333
0334 if (!device || !acpi_driver_data(device))
0335 return;
0336
0337 mem_device = acpi_driver_data(device);
0338 acpi_memory_remove_memory(mem_device);
0339 acpi_memory_device_free(mem_device);
0340 }
0341
0342 static bool __initdata acpi_no_memhotplug;
0343
0344 void __init acpi_memory_hotplug_init(void)
0345 {
0346 if (acpi_no_memhotplug) {
0347 memory_device_handler.attach = NULL;
0348 acpi_scan_add_handler(&memory_device_handler);
0349 return;
0350 }
0351 acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
0352 }
0353
0354 static int __init disable_acpi_memory_hotplug(char *str)
0355 {
0356 acpi_no_memhotplug = true;
0357 return 1;
0358 }
0359 __setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);
0360
0361 #else
0362
0363 static struct acpi_scan_handler memory_device_handler = {
0364 .ids = memory_device_ids,
0365 };
0366
0367 void __init acpi_memory_hotplug_init(void)
0368 {
0369 acpi_scan_add_handler(&memory_device_handler);
0370 }
0371
0372 #endif