* @id: This region's id. Id is globally unique across all regions
* @mode: Endpoint decoder allocation / access mode
* @type: Endpoint decoder target type
+ * @cxl_nvb: nvdimm bridge for coordinating @cxlr_pmem setup / shutdown
+ * @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge
+ * @flags: Region state flags
* @params: active + config params for the region
*/
struct cxl_region {
int id;
enum cxl_decoder_mode mode;
enum cxl_decoder_type type;
+ struct cxl_nvdimm_bridge *cxl_nvb;
+ struct cxl_pmem_region *cxlr_pmem;
+ unsigned long flags;
struct cxl_region_params params;
};
struct cxl_port *port;
struct nvdimm_bus *nvdimm_bus;
struct nvdimm_bus_descriptor nd_desc;
- struct work_struct state_work;
- enum cxl_nvdimm_brige_state state;
};
+ #define CXL_DEV_ID_LEN 19
+
struct cxl_nvdimm {
struct device dev;
struct cxl_memdev *cxlmd;
- struct cxl_nvdimm_bridge *bridge;
- struct xarray pmem_regions;
+ u8 dev_id[CXL_DEV_ID_LEN]; /* for nvdimm, string of 'serial' */
};
struct cxl_pmem_region_mapping {
#include "cxlmem.h"
#include "cxl.h"
-/*
- * Ordered workqueue for cxl nvdimm device arrival and departure
- * to coordinate bus rescans when a bridge arrives and trigger remove
- * operations when the bridge is removed.
- */
-static struct workqueue_struct *cxl_pmem_wq;
-
+ extern const struct nvdimm_security_ops *cxl_security_ops;
+
static __read_mostly DECLARE_BITMAP(exclusive_cmds, CXL_MEM_COMMAND_ID_MAX);
static void clear_exclusive(void *cxlds)
static void unregister_nvdimm(void *nvdimm)
{
- struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
- struct cxl_nvdimm_bridge *cxl_nvb = cxl_nvd->bridge;
- struct cxl_pmem_region *cxlr_pmem;
- unsigned long index;
-
- device_lock(&cxl_nvb->dev);
- dev_set_drvdata(&cxl_nvd->dev, NULL);
- xa_for_each(&cxl_nvd->pmem_regions, index, cxlr_pmem) {
- get_device(&cxlr_pmem->dev);
- device_unlock(&cxl_nvb->dev);
-
- device_release_driver(&cxlr_pmem->dev);
- put_device(&cxlr_pmem->dev);
-
- device_lock(&cxl_nvb->dev);
- }
- device_unlock(&cxl_nvb->dev);
-
nvdimm_delete(nvdimm);
- cxl_nvd->bridge = NULL;
}
+ static ssize_t provider_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+
+ return sysfs_emit(buf, "%s\n", dev_name(&cxl_nvd->dev));
+ }
+ static DEVICE_ATTR_RO(provider);
+
+ static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
+ {
+ struct nvdimm *nvdimm = to_nvdimm(dev);
+ struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
+ struct cxl_dev_state *cxlds = cxl_nvd->cxlmd->cxlds;
+
+ return sysfs_emit(buf, "%lld\n", cxlds->serial);
+ }
+ static DEVICE_ATTR_RO(id);
+
+ static struct attribute *cxl_dimm_attributes[] = {
+ &dev_attr_id.attr,
+ &dev_attr_provider.attr,
+ NULL
+ };
+
+ static const struct attribute_group cxl_dimm_attribute_group = {
+ .name = "cxl",
+ .attrs = cxl_dimm_attributes,
+ };
+
+ static const struct attribute_group *cxl_dimm_attribute_groups[] = {
+ &cxl_dimm_attribute_group,
+ NULL
+ };
+
static int cxl_nvdimm_probe(struct device *dev)
{
struct cxl_nvdimm *cxl_nvd = to_cxl_nvdimm(dev);
set_bit(ND_CMD_GET_CONFIG_SIZE, &cmd_mask);
set_bit(ND_CMD_GET_CONFIG_DATA, &cmd_mask);
set_bit(ND_CMD_SET_CONFIG_DATA, &cmd_mask);
- nvdimm = nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd, NULL, flags,
- cmd_mask, 0, NULL);
+ nvdimm = __nvdimm_create(cxl_nvb->nvdimm_bus, cxl_nvd,
+ cxl_dimm_attribute_groups, flags,
+ cmd_mask, 0, NULL, cxl_nvd->dev_id,
+ cxl_security_ops, NULL);
- if (!nvdimm) {
- rc = -ENOMEM;
- goto out;
- }
+ if (!nvdimm)
+ return -ENOMEM;
dev_set_drvdata(dev, nvdimm);
- cxl_nvd->bridge = cxl_nvb;
- rc = devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
-out:
- device_unlock(&cxl_nvb->dev);
- put_device(&cxl_nvb->dev);
-
- return rc;
+ return devm_add_action_or_reset(dev, unregister_nvdimm, nvdimm);
}
static struct cxl_driver cxl_nvdimm_driver = {
return 0;
}
+ static ssize_t security_lock_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+ {
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%u\n",
+ !!(mdata->security_state & CXL_PMEM_SEC_STATE_LOCKED));
+ }
+
+ static ssize_t security_lock_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+ {
+ struct cxl_mockmem_data *mdata = dev_get_drvdata(dev);
+ u32 mask = CXL_PMEM_SEC_STATE_FROZEN | CXL_PMEM_SEC_STATE_USER_PLIMIT |
+ CXL_PMEM_SEC_STATE_MASTER_PLIMIT;
+ int val;
+
+ if (kstrtoint(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val == 1) {
+ if (!(mdata->security_state & CXL_PMEM_SEC_STATE_USER_PASS_SET))
+ return -ENXIO;
+ mdata->security_state |= CXL_PMEM_SEC_STATE_LOCKED;
+ mdata->security_state &= ~mask;
+ } else {
+ return -EINVAL;
+ }
+ return count;
+ }
+
+ static DEVICE_ATTR_RW(security_lock);
+
+ static struct attribute *cxl_mock_mem_attrs[] = {
+ &dev_attr_security_lock.attr,
+ NULL
+ };
+ ATTRIBUTE_GROUPS(cxl_mock_mem);
+
static const struct platform_device_id cxl_mock_mem_ids[] = {
- { .name = "cxl_mem", },
+ { .name = "cxl_mem", 0 },
+ { .name = "cxl_rcd", 1 },
{ },
};
MODULE_DEVICE_TABLE(platform, cxl_mock_mem_ids);