1 /* 2 * Copyright (C) 2004, 2013 Intel Corporation 3 * Author: Naveen B S <naveen.b.s@intel.com> 4 * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> 5 * 6 * All rights reserved. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or (at 11 * your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 16 * NON INFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22 * 23 * 24 * ACPI based HotPlug driver that supports Memory Hotplug 25 * This driver fields notifications from firmware for memory add 26 * and remove operations and alerts the VM of the affected memory 27 * ranges. 28 */ 29 30 #include <linux/acpi.h> 31 #include <linux/memory_hotplug.h> 32 33 #include "internal.h" 34 35 #define ACPI_MEMORY_DEVICE_CLASS "memory" 36 #define ACPI_MEMORY_DEVICE_HID "PNP0C80" 37 #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" 38 39 #define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT 40 41 #undef PREFIX 42 #define PREFIX "ACPI:memory_hp:" 43 44 ACPI_MODULE_NAME("acpi_memhotplug"); 45 46 /* Memory Device States */ 47 #define MEMORY_INVALID_STATE 0 48 #define MEMORY_POWER_ON_STATE 1 49 #define MEMORY_POWER_OFF_STATE 2 50 51 static int acpi_memory_device_add(struct acpi_device *device, 52 const struct acpi_device_id *not_used); 53 static void acpi_memory_device_remove(struct acpi_device *device); 54 55 static const struct acpi_device_id memory_device_ids[] = { 56 {ACPI_MEMORY_DEVICE_HID, 0}, 57 {"", 0}, 58 }; 59 60 static struct acpi_scan_handler memory_device_handler = { 61 .ids = memory_device_ids, 62 .attach = acpi_memory_device_add, 63 .detach = acpi_memory_device_remove, 64 .hotplug = { 65 .enabled = true, 66 }, 67 }; 68 69 struct acpi_memory_info { 70 struct list_head list; 71 u64 start_addr; /* Memory Range start physical addr */ 72 u64 length; /* Memory Range length */ 73 unsigned short caching; /* memory cache attribute */ 74 unsigned short write_protect; /* memory read/write attribute */ 75 unsigned int enabled:1; 76 }; 77 78 struct acpi_memory_device { 79 struct acpi_device * device; 80 unsigned int state; /* State of the memory device */ 81 struct list_head res_list; 82 }; 83 84 static acpi_status 85 acpi_memory_get_resource(struct acpi_resource *resource, void *context) 86 { 87 struct acpi_memory_device *mem_device = context; 88 struct acpi_resource_address64 address64; 89 struct acpi_memory_info *info, *new; 90 acpi_status status; 91 92 status = acpi_resource_to_address64(resource, &address64); 93 if (ACPI_FAILURE(status) || 94 (address64.resource_type != ACPI_MEMORY_RANGE)) 95 return AE_OK; 96 97 list_for_each_entry(info, &mem_device->res_list, list) { 98 /* Can we combine the resource range information? */ 99 if ((info->caching == address64.info.mem.caching) && 100 (info->write_protect == address64.info.mem.write_protect) && 101 (info->start_addr + info->length == address64.minimum)) { 102 info->length += address64.address_length; 103 return AE_OK; 104 } 105 } 106 107 new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL); 108 if (!new) 109 return AE_ERROR; 110 111 INIT_LIST_HEAD(&new->list); 112 new->caching = address64.info.mem.caching; 113 new->write_protect = address64.info.mem.write_protect; 114 new->start_addr = address64.minimum; 115 new->length = address64.address_length; 116 list_add_tail(&new->list, &mem_device->res_list); 117 118 return AE_OK; 119 } 120 121 static void 122 acpi_memory_free_device_resources(struct acpi_memory_device *mem_device) 123 { 124 struct acpi_memory_info *info, *n; 125 126 list_for_each_entry_safe(info, n, &mem_device->res_list, list) 127 kfree(info); 128 INIT_LIST_HEAD(&mem_device->res_list); 129 } 130 131 static int 132 acpi_memory_get_device_resources(struct acpi_memory_device *mem_device) 133 { 134 acpi_status status; 135 136 if (!list_empty(&mem_device->res_list)) 137 return 0; 138 139 status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS, 140 acpi_memory_get_resource, mem_device); 141 if (ACPI_FAILURE(status)) { 142 acpi_memory_free_device_resources(mem_device); 143 return -EINVAL; 144 } 145 146 return 0; 147 } 148 149 static int acpi_memory_check_device(struct acpi_memory_device *mem_device) 150 { 151 unsigned long long current_status; 152 153 /* Get device present/absent information from the _STA */ 154 if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA", 155 NULL, ¤t_status))) 156 return -ENODEV; 157 /* 158 * Check for device status. Device should be 159 * present/enabled/functioning. 160 */ 161 if (!((current_status & ACPI_STA_DEVICE_PRESENT) 162 && (current_status & ACPI_STA_DEVICE_ENABLED) 163 && (current_status & ACPI_STA_DEVICE_FUNCTIONING))) 164 return -ENODEV; 165 166 return 0; 167 } 168 169 static int acpi_memory_enable_device(struct acpi_memory_device *mem_device) 170 { 171 int result, num_enabled = 0; 172 struct acpi_memory_info *info; 173 int node; 174 175 node = acpi_get_node(mem_device->device->handle); 176 /* 177 * Tell the VM there is more memory here... 178 * Note: Assume that this function returns zero on success 179 * We don't have memory-hot-add rollback function,now. 180 * (i.e. memory-hot-remove function) 181 */ 182 list_for_each_entry(info, &mem_device->res_list, list) { 183 if (info->enabled) { /* just sanity check...*/ 184 num_enabled++; 185 continue; 186 } 187 /* 188 * If the memory block size is zero, please ignore it. 189 * Don't try to do the following memory hotplug flowchart. 190 */ 191 if (!info->length) 192 continue; 193 if (node < 0) 194 node = memory_add_physaddr_to_nid(info->start_addr); 195 196 result = add_memory(node, info->start_addr, info->length); 197 198 /* 199 * If the memory block has been used by the kernel, add_memory() 200 * returns -EEXIST. If add_memory() returns the other error, it 201 * means that this memory block is not used by the kernel. 202 */ 203 if (result && result != -EEXIST) 204 continue; 205 206 info->enabled = 1; 207 208 /* 209 * Add num_enable even if add_memory() returns -EEXIST, so the 210 * device is bound to this driver. 211 */ 212 num_enabled++; 213 } 214 if (!num_enabled) { 215 dev_err(&mem_device->device->dev, "add_memory failed\n"); 216 mem_device->state = MEMORY_INVALID_STATE; 217 return -EINVAL; 218 } 219 /* 220 * Sometimes the memory device will contain several memory blocks. 221 * When one memory block is hot-added to the system memory, it will 222 * be regarded as a success. 223 * Otherwise if the last memory block can't be hot-added to the system 224 * memory, it will be failure and the memory device can't be bound with 225 * driver. 226 */ 227 return 0; 228 } 229 230 static int acpi_memory_remove_memory(struct acpi_memory_device *mem_device) 231 { 232 int result = 0, nid; 233 struct acpi_memory_info *info, *n; 234 235 nid = acpi_get_node(mem_device->device->handle); 236 237 list_for_each_entry_safe(info, n, &mem_device->res_list, list) { 238 if (!info->enabled) 239 continue; 240 241 if (nid < 0) 242 nid = memory_add_physaddr_to_nid(info->start_addr); 243 result = remove_memory(nid, info->start_addr, info->length); 244 if (result) 245 return result; 246 247 list_del(&info->list); 248 kfree(info); 249 } 250 251 return result; 252 } 253 254 static void acpi_memory_device_free(struct acpi_memory_device *mem_device) 255 { 256 if (!mem_device) 257 return; 258 259 acpi_memory_free_device_resources(mem_device); 260 mem_device->device->driver_data = NULL; 261 kfree(mem_device); 262 } 263 264 static int acpi_memory_device_add(struct acpi_device *device, 265 const struct acpi_device_id *not_used) 266 { 267 struct acpi_memory_device *mem_device; 268 int result; 269 270 if (!device) 271 return -EINVAL; 272 273 mem_device = kzalloc(sizeof(struct acpi_memory_device), GFP_KERNEL); 274 if (!mem_device) 275 return -ENOMEM; 276 277 INIT_LIST_HEAD(&mem_device->res_list); 278 mem_device->device = device; 279 sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME); 280 sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS); 281 device->driver_data = mem_device; 282 283 /* Get the range from the _CRS */ 284 result = acpi_memory_get_device_resources(mem_device); 285 if (result) { 286 kfree(mem_device); 287 return result; 288 } 289 290 /* Set the device state */ 291 mem_device->state = MEMORY_POWER_ON_STATE; 292 293 result = acpi_memory_check_device(mem_device); 294 if (result) { 295 acpi_memory_device_free(mem_device); 296 return 0; 297 } 298 299 result = acpi_memory_enable_device(mem_device); 300 if (result) { 301 dev_err(&device->dev, "acpi_memory_enable_device() error\n"); 302 acpi_memory_device_free(mem_device); 303 return -ENODEV; 304 } 305 306 dev_dbg(&device->dev, "Memory device configured by ACPI\n"); 307 return 1; 308 } 309 310 static void acpi_memory_device_remove(struct acpi_device *device) 311 { 312 struct acpi_memory_device *mem_device; 313 314 if (!device || !acpi_driver_data(device)) 315 return; 316 317 mem_device = acpi_driver_data(device); 318 acpi_memory_remove_memory(mem_device); 319 acpi_memory_device_free(mem_device); 320 } 321 322 void __init acpi_memory_hotplug_init(void) 323 { 324 acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory"); 325 } 326