// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2004, 2013 Intel Corporation * Author: Naveen B S <naveen.b.s@intel.com> * Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> * * All rights reserved. * * ACPI based HotPlug driver that supports Memory Hotplug * This driver fields notifications from firmware for memory add * and remove operations and alerts the VM of the affected memory * ranges.
*/
/* Get device present/absent information from the _STA */ if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle,
METHOD_NAME__STA, NULL,
¤t_status))) return -ENODEV; /* * Check for device status. Device should be * present/enabled/functioning.
*/ if (!((current_status & ACPI_STA_DEVICE_PRESENT)
&& (current_status & ACPI_STA_DEVICE_ENABLED)
&& (current_status & ACPI_STA_DEVICE_FUNCTIONING))) return -ENODEV;
list_for_each_entry(info, &mem_device->res_list, list) { if (!info->length) continue; /* We want a single node for the whole memory group */ if (node < 0)
node = memory_add_physaddr_to_nid(info->start_addr);
total_length += info->length;
}
if (!total_length) {
dev_err(&mem_device->device->dev, "device is empty\n"); return -EINVAL;
}
/* * Tell the VM there is more memory here... * Note: Assume that this function returns zero on success * We don't have memory-hot-add rollback function,now. * (i.e. memory-hot-remove function)
*/
list_for_each_entry(info, &mem_device->res_list, list) { /* * If the memory block size is zero, please ignore it. * Don't try to do the following memory hotplug flowchart.
*/ if (!info->length) continue;
mhp_flags |= MHP_MEMMAP_ON_MEMORY;
result = __add_memory(mgid, info->start_addr, info->length,
mhp_flags);
/* * 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) continue;
result = acpi_bind_memory_blocks(info, mem_device->device); if (result) {
acpi_unbind_memory_blocks(info); return -ENODEV;
}
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) {
dev_err(&mem_device->device->dev, "add_memory failed\n"); return -EINVAL;
} /* * Sometimes the memory device will contain several memory blocks. * When one memory block is hot-added to the system memory, it will * be regarded as a success. * Otherwise if the last memory block can't be hot-added to the system * memory, it will be failure and the memory device can't be bound with * driver.
*/ return 0;
}
/* Get the range from the _CRS */
result = acpi_memory_get_device_resources(mem_device); if (result) {
device->driver_data = NULL;
kfree(mem_device); return result;
}
result = acpi_memory_check_device(mem_device); if (result) {
acpi_memory_device_free(mem_device); return 0;
}
result = acpi_memory_enable_device(mem_device); if (result) {
dev_err(&device->dev, "acpi_memory_enable_device() error\n");
acpi_memory_device_free(mem_device); return result;
}
dev_dbg(&device->dev, "Memory device configured by ACPI\n"); return 1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.