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