Re: [PATCH 35/46] cxl/region: Add a 'uuid' attribute

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 23 Jun 2022 21:19:39 -0700
Dan Williams <dan.j.williams@xxxxxxxxx> wrote:

> From: Ben Widawsky <bwidawsk@xxxxxxxxxx>
> 
> The process of provisioning a region involves triggering the creation of
> a new region object, pouring in the configuration, and then binding that
> configured object to the region driver to start is operation. For
> persistent memory regions the CXL specification mandates that it
> identified by a uuid. Add an ABI for userspace to specify a region's
> uuid.
> 
> Signed-off-by: Ben Widawsky <bwidawsk@xxxxxxxxxx>
> [djbw: simplify locking]
> Signed-off-by: Dan Williams <dan.j.williams@xxxxxxxxx>

I think this needs to be a little less restrictive as it currently errors
out on trying to write the same UUID to the same region twice.

Short cut that case and just return 0 if the UUID is same as already set.

Thanks,

Jonathan



> ---
>  Documentation/ABI/testing/sysfs-bus-cxl |  10 +++
>  drivers/cxl/core/region.c               | 115 ++++++++++++++++++++++++
>  drivers/cxl/cxl.h                       |  25 ++++++
>  3 files changed, 150 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
> index 9a4856066631..d30c95a758a9 100644
> --- a/Documentation/ABI/testing/sysfs-bus-cxl
> +++ b/Documentation/ABI/testing/sysfs-bus-cxl
> @@ -263,3 +263,13 @@ Contact:	linux-cxl@xxxxxxxxxxxxxxx
>  Description:
>  		(WO) Write a string in the form 'regionZ' to delete that region,
>  		provided it is currently idle / not bound to a driver.
> +
> +
> +What:		/sys/bus/cxl/devices/regionZ/uuid
> +Date:		May, 2022
> +KernelVersion:	v5.20
> +Contact:	linux-cxl@xxxxxxxxxxxxxxx
> +Description:
> +		(RW) Write a unique identifier for the region. This field must
> +		be set for persistent regions and it must not conflict with the
> +		UUID of another region.
> diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> index f2a0ead20ca7..f75978f846b9 100644
> --- a/drivers/cxl/core/region.c
> +++ b/drivers/cxl/core/region.c
> @@ -5,6 +5,7 @@
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/slab.h>
> +#include <linux/uuid.h>
>  #include <linux/idr.h>
>  #include <cxl.h>
>  #include "core.h"
> @@ -17,10 +18,123 @@
>   * Memory ranges, Regions represent the active mapped capacity by the HDM
>   * Decoder Capability structures throughout the Host Bridges, Switches, and
>   * Endpoints in the topology.
> + *
> + * Region configuration has ordering constraints. UUID may be set at any time
> + * but is only visible for persistent regions.
> + */
> +
> +/*
> + * All changes to the interleave configuration occur with this lock held
> + * for write.
>   */
> +static DECLARE_RWSEM(cxl_region_rwsem);
>  
>  static struct cxl_region *to_cxl_region(struct device *dev);
>  
> +static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
> +			 char *buf)
> +{
> +	struct cxl_region *cxlr = to_cxl_region(dev);
> +	struct cxl_region_params *p = &cxlr->params;
> +	ssize_t rc;
> +
> +	rc = down_read_interruptible(&cxl_region_rwsem);
> +	if (rc)
> +		return rc;
> +	rc = sysfs_emit(buf, "%pUb\n", &p->uuid);
> +	up_read(&cxl_region_rwsem);
> +
> +	return rc;
> +}
> +
> +static int is_dup(struct device *match, void *data)
> +{
> +	struct cxl_region_params *p;
> +	struct cxl_region *cxlr;
> +	uuid_t *uuid = data;
> +
> +	if (!is_cxl_region(match))
> +		return 0;
> +
> +	lockdep_assert_held(&cxl_region_rwsem);
> +	cxlr = to_cxl_region(match);
> +	p = &cxlr->params;
> +
> +	if (uuid_equal(&p->uuid, uuid)) {
> +		dev_dbg(match, "already has uuid: %pUb\n", uuid);
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static ssize_t uuid_store(struct device *dev, struct device_attribute *attr,
> +			  const char *buf, size_t len)
> +{
> +	struct cxl_region *cxlr = to_cxl_region(dev);
> +	struct cxl_region_params *p = &cxlr->params;
> +	uuid_t temp;
> +	ssize_t rc;
> +
> +	if (len != UUID_STRING_LEN + 1)
> +		return -EINVAL;
> +
> +	rc = uuid_parse(buf, &temp);
> +	if (rc)
> +		return rc;
> +
> +	if (uuid_is_null(&temp))
> +		return -EINVAL;
> +
> +	rc = down_write_killable(&cxl_region_rwsem);
> +	if (rc)
> +		return rc;
> +
> +	rc = -EBUSY;
> +	if (p->state >= CXL_CONFIG_ACTIVE)
> +		goto out;
> +
> +	rc = bus_for_each_dev(&cxl_bus_type, NULL, &temp, is_dup);
> +	if (rc < 0)
> +		goto out;
> +
> +	uuid_copy(&p->uuid, &temp);
> +out:
> +	up_write(&cxl_region_rwsem);
> +
> +	if (rc)
> +		return rc;
> +	return len;
> +}
> +static DEVICE_ATTR_RW(uuid);
> +
> +static umode_t cxl_region_visible(struct kobject *kobj, struct attribute *a,
> +				  int n)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct cxl_region *cxlr = to_cxl_region(dev);
> +
> +	if (a == &dev_attr_uuid.attr && cxlr->mode != CXL_DECODER_PMEM)
> +		return 0;
> +	return a->mode;
> +}
> +
> +static struct attribute *cxl_region_attrs[] = {
> +	&dev_attr_uuid.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group cxl_region_group = {
> +	.attrs = cxl_region_attrs,
> +	.is_visible = cxl_region_visible,
> +};
> +
> +static const struct attribute_group *region_groups[] = {
> +	&cxl_base_attribute_group,
> +	&cxl_region_group,
> +	NULL,
> +};
> +
>  static void cxl_region_release(struct device *dev)
>  {
>  	struct cxl_region *cxlr = to_cxl_region(dev);
> @@ -32,6 +146,7 @@ static void cxl_region_release(struct device *dev)
>  static const struct device_type cxl_region_type = {
>  	.name = "cxl_region",
>  	.release = cxl_region_release,
> +	.groups = region_groups
>  };
>  
>  bool is_cxl_region(struct device *dev)
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index 49b73b2e44a9..46a9f8acc602 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -288,18 +288,43 @@ struct cxl_root_decoder {
>  	struct cxl_switch_decoder cxlsd;
>  };
>  
> +/*
> + * enum cxl_config_state - State machine for region configuration
> + * @CXL_CONFIG_IDLE: Any sysfs attribute can be written freely
> + * @CXL_CONFIG_ACTIVE: All targets have been added the region is now
> + * active
> + */
> +enum cxl_config_state {
> +	CXL_CONFIG_IDLE,
> +	CXL_CONFIG_ACTIVE,
> +};
> +
> +/**
> + * struct cxl_region_params - region settings
> + * @state: allow the driver to lockdown further parameter changes
> + * @uuid: unique id for persistent regions
> + *
> + * State transitions are protected by the cxl_region_rwsem
> + */
> +struct cxl_region_params {
> +	enum cxl_config_state state;
> +	uuid_t uuid;
> +};
> +
>  /**
>   * struct cxl_region - CXL region
>   * @dev: This region's device
>   * @id: This region's id. Id is globally unique across all regions
>   * @mode: Endpoint decoder allocation / access mode
>   * @type: Endpoint decoder target type
> + * @params: active + config params for the region
>   */
>  struct cxl_region {
>  	struct device dev;
>  	int id;
>  	enum cxl_decoder_mode mode;
>  	enum cxl_decoder_type type;
> +	struct cxl_region_params params;
>  };
>  
>  /**




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux