162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/platform_device.h> 362306a36Sopenharmony_ci#include <linux/memregion.h> 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/dax.h> 662306a36Sopenharmony_ci#include <linux/mm.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_cistatic bool nohmem; 962306a36Sopenharmony_cimodule_param_named(disable, nohmem, bool, 0444); 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_cistatic bool platform_initialized; 1262306a36Sopenharmony_cistatic DEFINE_MUTEX(hmem_resource_lock); 1362306a36Sopenharmony_cistatic struct resource hmem_active = { 1462306a36Sopenharmony_ci .name = "HMEM devices", 1562306a36Sopenharmony_ci .start = 0, 1662306a36Sopenharmony_ci .end = -1, 1762306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ciint walk_hmem_resources(struct device *host, walk_hmem_fn fn) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct resource *res; 2362306a36Sopenharmony_ci int rc = 0; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci mutex_lock(&hmem_resource_lock); 2662306a36Sopenharmony_ci for (res = hmem_active.child; res; res = res->sibling) { 2762306a36Sopenharmony_ci rc = fn(host, (int) res->desc, res); 2862306a36Sopenharmony_ci if (rc) 2962306a36Sopenharmony_ci break; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci mutex_unlock(&hmem_resource_lock); 3262306a36Sopenharmony_ci return rc; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(walk_hmem_resources); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void __hmem_register_resource(int target_nid, struct resource *res) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct platform_device *pdev; 3962306a36Sopenharmony_ci struct resource *new; 4062306a36Sopenharmony_ci int rc; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci new = __request_region(&hmem_active, res->start, resource_size(res), "", 4362306a36Sopenharmony_ci 0); 4462306a36Sopenharmony_ci if (!new) { 4562306a36Sopenharmony_ci pr_debug("hmem range %pr already active\n", res); 4662306a36Sopenharmony_ci return; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci new->desc = target_nid; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (platform_initialized) 5262306a36Sopenharmony_ci return; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci pdev = platform_device_alloc("hmem_platform", 0); 5562306a36Sopenharmony_ci if (!pdev) { 5662306a36Sopenharmony_ci pr_err_once("failed to register device-dax hmem_platform device\n"); 5762306a36Sopenharmony_ci return; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci rc = platform_device_add(pdev); 6162306a36Sopenharmony_ci if (rc) 6262306a36Sopenharmony_ci platform_device_put(pdev); 6362306a36Sopenharmony_ci else 6462306a36Sopenharmony_ci platform_initialized = true; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_civoid hmem_register_resource(int target_nid, struct resource *res) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci if (nohmem) 7062306a36Sopenharmony_ci return; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci mutex_lock(&hmem_resource_lock); 7362306a36Sopenharmony_ci __hmem_register_resource(target_nid, res); 7462306a36Sopenharmony_ci mutex_unlock(&hmem_resource_lock); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic __init int hmem_register_one(struct resource *res, void *data) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci hmem_register_resource(phys_to_target_node(res->start), res); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic __init int hmem_init(void) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci walk_iomem_res_desc(IORES_DESC_SOFT_RESERVED, 8762306a36Sopenharmony_ci IORESOURCE_MEM, 0, -1, NULL, hmem_register_one); 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * As this is a fallback for address ranges unclaimed by the ACPI HMAT 9362306a36Sopenharmony_ci * parsing it must be at an initcall level greater than hmat_init(). 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cidevice_initcall(hmem_init); 96