root/drivers/acpi/acpi_memhotplug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpi_memory_get_resource
  2. acpi_memory_free_device_resources
  3. acpi_memory_get_device_resources
  4. acpi_memory_check_device
  5. acpi_bind_memblk
  6. acpi_bind_memory_blocks
  7. acpi_unbind_memblk
  8. acpi_unbind_memory_blocks
  9. acpi_memory_enable_device
  10. acpi_memory_remove_memory
  11. acpi_memory_device_free
  12. acpi_memory_device_add
  13. acpi_memory_device_remove
  14. acpi_memory_hotplug_init
  15. disable_acpi_memory_hotplug
  16. acpi_memory_hotplug_init

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

/* [<][>][^][v][top][bottom][index][help] */