1*779dd20cSBen Widawsky // SPDX-License-Identifier: GPL-2.0-only 2*779dd20cSBen Widawsky /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3*779dd20cSBen Widawsky #include <linux/memregion.h> 4*779dd20cSBen Widawsky #include <linux/genalloc.h> 5*779dd20cSBen Widawsky #include <linux/device.h> 6*779dd20cSBen Widawsky #include <linux/module.h> 7*779dd20cSBen Widawsky #include <linux/slab.h> 8*779dd20cSBen Widawsky #include <linux/idr.h> 9*779dd20cSBen Widawsky #include <cxl.h> 10*779dd20cSBen Widawsky #include "core.h" 11*779dd20cSBen Widawsky 12*779dd20cSBen Widawsky /** 13*779dd20cSBen Widawsky * DOC: cxl core region 14*779dd20cSBen Widawsky * 15*779dd20cSBen Widawsky * CXL Regions represent mapped memory capacity in system physical address 16*779dd20cSBen Widawsky * space. Whereas the CXL Root Decoders identify the bounds of potential CXL 17*779dd20cSBen Widawsky * Memory ranges, Regions represent the active mapped capacity by the HDM 18*779dd20cSBen Widawsky * Decoder Capability structures throughout the Host Bridges, Switches, and 19*779dd20cSBen Widawsky * Endpoints in the topology. 20*779dd20cSBen Widawsky */ 21*779dd20cSBen Widawsky 22*779dd20cSBen Widawsky static struct cxl_region *to_cxl_region(struct device *dev); 23*779dd20cSBen Widawsky 24*779dd20cSBen Widawsky static void cxl_region_release(struct device *dev) 25*779dd20cSBen Widawsky { 26*779dd20cSBen Widawsky struct cxl_region *cxlr = to_cxl_region(dev); 27*779dd20cSBen Widawsky 28*779dd20cSBen Widawsky memregion_free(cxlr->id); 29*779dd20cSBen Widawsky kfree(cxlr); 30*779dd20cSBen Widawsky } 31*779dd20cSBen Widawsky 32*779dd20cSBen Widawsky static const struct device_type cxl_region_type = { 33*779dd20cSBen Widawsky .name = "cxl_region", 34*779dd20cSBen Widawsky .release = cxl_region_release, 35*779dd20cSBen Widawsky }; 36*779dd20cSBen Widawsky 37*779dd20cSBen Widawsky bool is_cxl_region(struct device *dev) 38*779dd20cSBen Widawsky { 39*779dd20cSBen Widawsky return dev->type == &cxl_region_type; 40*779dd20cSBen Widawsky } 41*779dd20cSBen Widawsky EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL); 42*779dd20cSBen Widawsky 43*779dd20cSBen Widawsky static struct cxl_region *to_cxl_region(struct device *dev) 44*779dd20cSBen Widawsky { 45*779dd20cSBen Widawsky if (dev_WARN_ONCE(dev, dev->type != &cxl_region_type, 46*779dd20cSBen Widawsky "not a cxl_region device\n")) 47*779dd20cSBen Widawsky return NULL; 48*779dd20cSBen Widawsky 49*779dd20cSBen Widawsky return container_of(dev, struct cxl_region, dev); 50*779dd20cSBen Widawsky } 51*779dd20cSBen Widawsky 52*779dd20cSBen Widawsky static void unregister_region(void *dev) 53*779dd20cSBen Widawsky { 54*779dd20cSBen Widawsky device_unregister(dev); 55*779dd20cSBen Widawsky } 56*779dd20cSBen Widawsky 57*779dd20cSBen Widawsky static struct lock_class_key cxl_region_key; 58*779dd20cSBen Widawsky 59*779dd20cSBen Widawsky static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int id) 60*779dd20cSBen Widawsky { 61*779dd20cSBen Widawsky struct cxl_region *cxlr; 62*779dd20cSBen Widawsky struct device *dev; 63*779dd20cSBen Widawsky 64*779dd20cSBen Widawsky cxlr = kzalloc(sizeof(*cxlr), GFP_KERNEL); 65*779dd20cSBen Widawsky if (!cxlr) { 66*779dd20cSBen Widawsky memregion_free(id); 67*779dd20cSBen Widawsky return ERR_PTR(-ENOMEM); 68*779dd20cSBen Widawsky } 69*779dd20cSBen Widawsky 70*779dd20cSBen Widawsky dev = &cxlr->dev; 71*779dd20cSBen Widawsky device_initialize(dev); 72*779dd20cSBen Widawsky lockdep_set_class(&dev->mutex, &cxl_region_key); 73*779dd20cSBen Widawsky dev->parent = &cxlrd->cxlsd.cxld.dev; 74*779dd20cSBen Widawsky device_set_pm_not_required(dev); 75*779dd20cSBen Widawsky dev->bus = &cxl_bus_type; 76*779dd20cSBen Widawsky dev->type = &cxl_region_type; 77*779dd20cSBen Widawsky cxlr->id = id; 78*779dd20cSBen Widawsky 79*779dd20cSBen Widawsky return cxlr; 80*779dd20cSBen Widawsky } 81*779dd20cSBen Widawsky 82*779dd20cSBen Widawsky /** 83*779dd20cSBen Widawsky * devm_cxl_add_region - Adds a region to a decoder 84*779dd20cSBen Widawsky * @cxlrd: root decoder 85*779dd20cSBen Widawsky * @id: memregion id to create, or memregion_free() on failure 86*779dd20cSBen Widawsky * @mode: mode for the endpoint decoders of this region 87*779dd20cSBen Widawsky * @type: select whether this is an expander or accelerator (type-2 or type-3) 88*779dd20cSBen Widawsky * 89*779dd20cSBen Widawsky * This is the second step of region initialization. Regions exist within an 90*779dd20cSBen Widawsky * address space which is mapped by a @cxlrd. 91*779dd20cSBen Widawsky * 92*779dd20cSBen Widawsky * Return: 0 if the region was added to the @cxlrd, else returns negative error 93*779dd20cSBen Widawsky * code. The region will be named "regionZ" where Z is the unique region number. 94*779dd20cSBen Widawsky */ 95*779dd20cSBen Widawsky static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, 96*779dd20cSBen Widawsky int id, 97*779dd20cSBen Widawsky enum cxl_decoder_mode mode, 98*779dd20cSBen Widawsky enum cxl_decoder_type type) 99*779dd20cSBen Widawsky { 100*779dd20cSBen Widawsky struct cxl_port *port = to_cxl_port(cxlrd->cxlsd.cxld.dev.parent); 101*779dd20cSBen Widawsky struct cxl_region *cxlr; 102*779dd20cSBen Widawsky struct device *dev; 103*779dd20cSBen Widawsky int rc; 104*779dd20cSBen Widawsky 105*779dd20cSBen Widawsky cxlr = cxl_region_alloc(cxlrd, id); 106*779dd20cSBen Widawsky if (IS_ERR(cxlr)) 107*779dd20cSBen Widawsky return cxlr; 108*779dd20cSBen Widawsky cxlr->mode = mode; 109*779dd20cSBen Widawsky cxlr->type = type; 110*779dd20cSBen Widawsky 111*779dd20cSBen Widawsky dev = &cxlr->dev; 112*779dd20cSBen Widawsky rc = dev_set_name(dev, "region%d", id); 113*779dd20cSBen Widawsky if (rc) 114*779dd20cSBen Widawsky goto err; 115*779dd20cSBen Widawsky 116*779dd20cSBen Widawsky rc = device_add(dev); 117*779dd20cSBen Widawsky if (rc) 118*779dd20cSBen Widawsky goto err; 119*779dd20cSBen Widawsky 120*779dd20cSBen Widawsky rc = devm_add_action_or_reset(port->uport, unregister_region, cxlr); 121*779dd20cSBen Widawsky if (rc) 122*779dd20cSBen Widawsky return ERR_PTR(rc); 123*779dd20cSBen Widawsky 124*779dd20cSBen Widawsky dev_dbg(port->uport, "%s: created %s\n", 125*779dd20cSBen Widawsky dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev)); 126*779dd20cSBen Widawsky return cxlr; 127*779dd20cSBen Widawsky 128*779dd20cSBen Widawsky err: 129*779dd20cSBen Widawsky put_device(dev); 130*779dd20cSBen Widawsky return ERR_PTR(rc); 131*779dd20cSBen Widawsky } 132*779dd20cSBen Widawsky 133*779dd20cSBen Widawsky static ssize_t create_pmem_region_show(struct device *dev, 134*779dd20cSBen Widawsky struct device_attribute *attr, char *buf) 135*779dd20cSBen Widawsky { 136*779dd20cSBen Widawsky struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 137*779dd20cSBen Widawsky 138*779dd20cSBen Widawsky return sysfs_emit(buf, "region%u\n", atomic_read(&cxlrd->region_id)); 139*779dd20cSBen Widawsky } 140*779dd20cSBen Widawsky 141*779dd20cSBen Widawsky static ssize_t create_pmem_region_store(struct device *dev, 142*779dd20cSBen Widawsky struct device_attribute *attr, 143*779dd20cSBen Widawsky const char *buf, size_t len) 144*779dd20cSBen Widawsky { 145*779dd20cSBen Widawsky struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 146*779dd20cSBen Widawsky struct cxl_region *cxlr; 147*779dd20cSBen Widawsky int id, rc; 148*779dd20cSBen Widawsky 149*779dd20cSBen Widawsky rc = sscanf(buf, "region%d\n", &id); 150*779dd20cSBen Widawsky if (rc != 1) 151*779dd20cSBen Widawsky return -EINVAL; 152*779dd20cSBen Widawsky 153*779dd20cSBen Widawsky rc = memregion_alloc(GFP_KERNEL); 154*779dd20cSBen Widawsky if (rc < 0) 155*779dd20cSBen Widawsky return rc; 156*779dd20cSBen Widawsky 157*779dd20cSBen Widawsky if (atomic_cmpxchg(&cxlrd->region_id, id, rc) != id) { 158*779dd20cSBen Widawsky memregion_free(rc); 159*779dd20cSBen Widawsky return -EBUSY; 160*779dd20cSBen Widawsky } 161*779dd20cSBen Widawsky 162*779dd20cSBen Widawsky cxlr = devm_cxl_add_region(cxlrd, id, CXL_DECODER_PMEM, 163*779dd20cSBen Widawsky CXL_DECODER_EXPANDER); 164*779dd20cSBen Widawsky if (IS_ERR(cxlr)) 165*779dd20cSBen Widawsky return PTR_ERR(cxlr); 166*779dd20cSBen Widawsky 167*779dd20cSBen Widawsky return len; 168*779dd20cSBen Widawsky } 169*779dd20cSBen Widawsky DEVICE_ATTR_RW(create_pmem_region); 170*779dd20cSBen Widawsky 171*779dd20cSBen Widawsky static struct cxl_region * 172*779dd20cSBen Widawsky cxl_find_region_by_name(struct cxl_root_decoder *cxlrd, const char *name) 173*779dd20cSBen Widawsky { 174*779dd20cSBen Widawsky struct cxl_decoder *cxld = &cxlrd->cxlsd.cxld; 175*779dd20cSBen Widawsky struct device *region_dev; 176*779dd20cSBen Widawsky 177*779dd20cSBen Widawsky region_dev = device_find_child_by_name(&cxld->dev, name); 178*779dd20cSBen Widawsky if (!region_dev) 179*779dd20cSBen Widawsky return ERR_PTR(-ENODEV); 180*779dd20cSBen Widawsky 181*779dd20cSBen Widawsky return to_cxl_region(region_dev); 182*779dd20cSBen Widawsky } 183*779dd20cSBen Widawsky 184*779dd20cSBen Widawsky static ssize_t delete_region_store(struct device *dev, 185*779dd20cSBen Widawsky struct device_attribute *attr, 186*779dd20cSBen Widawsky const char *buf, size_t len) 187*779dd20cSBen Widawsky { 188*779dd20cSBen Widawsky struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev); 189*779dd20cSBen Widawsky struct cxl_port *port = to_cxl_port(dev->parent); 190*779dd20cSBen Widawsky struct cxl_region *cxlr; 191*779dd20cSBen Widawsky 192*779dd20cSBen Widawsky cxlr = cxl_find_region_by_name(cxlrd, buf); 193*779dd20cSBen Widawsky if (IS_ERR(cxlr)) 194*779dd20cSBen Widawsky return PTR_ERR(cxlr); 195*779dd20cSBen Widawsky 196*779dd20cSBen Widawsky devm_release_action(port->uport, unregister_region, cxlr); 197*779dd20cSBen Widawsky put_device(&cxlr->dev); 198*779dd20cSBen Widawsky 199*779dd20cSBen Widawsky return len; 200*779dd20cSBen Widawsky } 201*779dd20cSBen Widawsky DEVICE_ATTR_WO(delete_region); 202