1d747cf98SGregory Price // SPDX-License-Identifier: GPL-2.0-only 2d747cf98SGregory Price /* 3d747cf98SGregory Price * Copyright(c) 2022 Intel Corporation. All rights reserved. 4d747cf98SGregory Price * Copyright(c) 2026 Meta Technologies Inc. All rights reserved. 5d747cf98SGregory Price */ 6d747cf98SGregory Price #include <linux/device.h> 7d747cf98SGregory Price #include <linux/slab.h> 8d747cf98SGregory Price #include <cxlmem.h> 9d747cf98SGregory Price #include <cxl.h> 10d747cf98SGregory Price #include "core.h" 11d747cf98SGregory Price 12d747cf98SGregory Price static void cxl_dax_region_release(struct device *dev) 13d747cf98SGregory Price { 14d747cf98SGregory Price struct cxl_dax_region *cxlr_dax = to_cxl_dax_region(dev); 15d747cf98SGregory Price 16d747cf98SGregory Price kfree(cxlr_dax); 17d747cf98SGregory Price } 18d747cf98SGregory Price 19d747cf98SGregory Price static const struct attribute_group *cxl_dax_region_attribute_groups[] = { 20d747cf98SGregory Price &cxl_base_attribute_group, 21d747cf98SGregory Price NULL 22d747cf98SGregory Price }; 23d747cf98SGregory Price 24d747cf98SGregory Price const struct device_type cxl_dax_region_type = { 25d747cf98SGregory Price .name = "cxl_dax_region", 26d747cf98SGregory Price .release = cxl_dax_region_release, 27d747cf98SGregory Price .groups = cxl_dax_region_attribute_groups, 28d747cf98SGregory Price }; 29d747cf98SGregory Price 30d747cf98SGregory Price static bool is_cxl_dax_region(struct device *dev) 31d747cf98SGregory Price { 32d747cf98SGregory Price return dev->type == &cxl_dax_region_type; 33d747cf98SGregory Price } 34d747cf98SGregory Price 35d747cf98SGregory Price struct cxl_dax_region *to_cxl_dax_region(struct device *dev) 36d747cf98SGregory Price { 37d747cf98SGregory Price if (dev_WARN_ONCE(dev, !is_cxl_dax_region(dev), 38d747cf98SGregory Price "not a cxl_dax_region device\n")) 39d747cf98SGregory Price return NULL; 40d747cf98SGregory Price return container_of(dev, struct cxl_dax_region, dev); 41d747cf98SGregory Price } 42d747cf98SGregory Price EXPORT_SYMBOL_NS_GPL(to_cxl_dax_region, "CXL"); 43d747cf98SGregory Price 44d747cf98SGregory Price static struct lock_class_key cxl_dax_region_key; 45d747cf98SGregory Price 46d747cf98SGregory Price static struct cxl_dax_region *cxl_dax_region_alloc(struct cxl_region *cxlr) 47d747cf98SGregory Price { 48d747cf98SGregory Price struct cxl_region_params *p = &cxlr->params; 49d747cf98SGregory Price struct cxl_dax_region *cxlr_dax; 50d747cf98SGregory Price struct device *dev; 51d747cf98SGregory Price 52d747cf98SGregory Price guard(rwsem_read)(&cxl_rwsem.region); 53d747cf98SGregory Price if (p->state != CXL_CONFIG_COMMIT) 54d747cf98SGregory Price return ERR_PTR(-ENXIO); 55d747cf98SGregory Price 56d747cf98SGregory Price cxlr_dax = kzalloc_obj(*cxlr_dax); 57d747cf98SGregory Price if (!cxlr_dax) 58d747cf98SGregory Price return ERR_PTR(-ENOMEM); 59d747cf98SGregory Price 60d747cf98SGregory Price cxlr_dax->hpa_range.start = p->res->start; 61d747cf98SGregory Price cxlr_dax->hpa_range.end = p->res->end; 62d747cf98SGregory Price 63d747cf98SGregory Price dev = &cxlr_dax->dev; 64d747cf98SGregory Price cxlr_dax->cxlr = cxlr; 65d747cf98SGregory Price device_initialize(dev); 66d747cf98SGregory Price lockdep_set_class(&dev->mutex, &cxl_dax_region_key); 67d747cf98SGregory Price device_set_pm_not_required(dev); 68d747cf98SGregory Price dev->parent = &cxlr->dev; 69d747cf98SGregory Price dev->bus = &cxl_bus_type; 70d747cf98SGregory Price dev->type = &cxl_dax_region_type; 71d747cf98SGregory Price 72d747cf98SGregory Price return cxlr_dax; 73d747cf98SGregory Price } 74d747cf98SGregory Price 75d747cf98SGregory Price static void cxlr_dax_unregister(void *_cxlr_dax) 76d747cf98SGregory Price { 77d747cf98SGregory Price struct cxl_dax_region *cxlr_dax = _cxlr_dax; 78d747cf98SGregory Price 79d747cf98SGregory Price device_unregister(&cxlr_dax->dev); 80d747cf98SGregory Price } 81d747cf98SGregory Price 82d747cf98SGregory Price int devm_cxl_add_dax_region(struct cxl_region *cxlr) 83d747cf98SGregory Price { 84d747cf98SGregory Price struct device *dev; 85d747cf98SGregory Price int rc; 86d747cf98SGregory Price 87*29990ab5SGregory Price struct cxl_dax_region *cxlr_dax __free(put_cxl_dax_region) = 88*29990ab5SGregory Price cxl_dax_region_alloc(cxlr); 89d747cf98SGregory Price if (IS_ERR(cxlr_dax)) 90d747cf98SGregory Price return PTR_ERR(cxlr_dax); 91d747cf98SGregory Price 92d747cf98SGregory Price dev = &cxlr_dax->dev; 93d747cf98SGregory Price rc = dev_set_name(dev, "dax_region%d", cxlr->id); 94d747cf98SGregory Price if (rc) 95*29990ab5SGregory Price return rc; 96d747cf98SGregory Price 97d747cf98SGregory Price rc = device_add(dev); 98d747cf98SGregory Price if (rc) 99*29990ab5SGregory Price return rc; 100d747cf98SGregory Price 101d747cf98SGregory Price dev_dbg(&cxlr->dev, "%s: register %s\n", dev_name(dev->parent), 102d747cf98SGregory Price dev_name(dev)); 103d747cf98SGregory Price 104d747cf98SGregory Price return devm_add_action_or_reset(&cxlr->dev, cxlr_dax_unregister, 105*29990ab5SGregory Price no_free_ptr(cxlr_dax)); 106d747cf98SGregory Price } 107