RE: [PATCH v7 2/2] cxl/pci: Add sysfs attribute for CXL 1.1 device link status

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

 



Jonathan Cameron wrote:
> On Fri, 10 May 2024 16:37:10 +0900
> "Kobayashi,Daisuke" <kobayashi.da-06@xxxxxxxxxxx> wrote:
> 
> > Add sysfs attribute for CXL 1.1 device link status to the cxl pci device.
> >
> > In CXL1.1, the link status of the device is included in the RCRB mapped to
> > the memory mapped register area. Critically, that arrangement makes the
> > link status and control registers invisible to existing PCI user tooling.
> >
> > Export those registers via sysfs with the expectation that PCI user
> > tooling will alternatively look for these sysfs files when attempting to
> > access to these CXL 1.1 endpoints registers.
> 
> The lspci support raced with this series and has landed.
> 
> https://github.com/pciutils/pciutils/commit/49efa87fcce4f7d5b351238668ae
> 1d4491802b88
> 
> A few follow up comments on suggestion to cache the offset, not the register
> value
> (which might change over time)
> >
> > Reviewed-by: Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx>
> > Signed-off-by: "Kobayashi,Daisuke" <kobayashi.da-06@xxxxxxxxxxx>
> > ---
> >  drivers/cxl/pci.c | 101
> ++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 101 insertions(+)
> >
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index 2ff361e756d6..c10797adde2c 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> > @@ -786,6 +786,106 @@ static int cxl_event_config(struct pci_host_bridge
> *host_bridge,
> >  	return 0;
> >  }
> >
> > +static ssize_t rcd_link_cap_show(struct device *dev,
> > +				   struct device_attribute *attr, char *buf)
> > +{
> > +	struct cxl_dev_state *cxlds = dev_get_drvdata(dev);
> > +	struct cxl_memdev *cxlmd = cxlds->cxlmd;
> > +	struct device *endpoint_parent;
> > +	struct cxl_dport *dport;
> > +	struct cxl_port *port;
> > +
> > +	port = cxl_mem_find_port(cxlmd, &dport);
> > +	if (!port)
> > +		return -EINVAL;
> > +
> > +	endpoint_parent = port->uport_dev;
> > +	if (!endpoint_parent)
> > +		return -ENXIO;
> > +
> > +	guard(device)(endpoint_parent);
> > +	if (!endpoint_parent->driver)
> > +		return -ENXIO;
> > +
> > +	return sysfs_emit(buf, "%x\n", dport->rcrb.rcd_lnkcap);
> 
> If you follow the suggestion of caching the offset, not the register
> content then, these are all very similar. Define one common
> function which takes a u8 offset and call that from each of the
> functions.
> 
> If you stick to separate caches (and ensure they are up to date),
> then you can add a utility function to take the dev here and
> get you to the rcrb structure.  Then you can call that and only
> have the final line in each instances of this code.
> 

Thank you for your comment.

To confirm my understanding of the proposed implementation approach, 
I would like to share my interpretation:

- The values stored in `cxl_rcrb_info` should be the offsets of the registers, 
rather than the register values themselves.
- Similar to aer, the values should be read from the memory-mapped region 
using the offset when they are needed.
- To achieve this, the offsets (like `cxl_rcrb_pcie_caps`) will be stored in `cxl_rcrb_info` 
during initialization, and the memory-mapped region will be accessed within the `rcd_*_show()`
functions where the values are actually used.
- Accessing the memory-mapped region only requires the `struct device *dev`, 
so a common utility function will be created and used for this purpose.

If the cost of accessing the memory-mapped region at runtime is not high, especially considering 
the avoidance of the walk to find the offset, then I believe it is more reasonable to access 
the memory-mapped region at runtime.

Could you let me know if there are any errors in my understanding.

If there are no issues, I will update the implementation with this approach 
and submit a v8 patch (hopefully tomorrow).

> > +}
> > +static DEVICE_ATTR_RO(rcd_link_cap);
> > +
> > +static ssize_t rcd_link_ctrl_show(struct device *dev,
> > +				   struct device_attribute *attr, char *buf)
> > +{
> > +	struct cxl_dev_state *cxlds = dev_get_drvdata(dev);
> > +	struct cxl_memdev *cxlmd = cxlds->cxlmd;
> > +	struct device *endpoint_parent;
> > +	struct cxl_dport *dport;
> > +	struct cxl_port *port;
> > +
> > +	port = cxl_mem_find_port(cxlmd, &dport);
> > +	if (!port)
> > +		return -EINVAL;
> > +
> > +	endpoint_parent = port->uport_dev;
> > +	if (!endpoint_parent)
> > +		return -ENXIO;
> > +
> > +	guard(device)(endpoint_parent);
> > +	if (!endpoint_parent->driver)
> > +		return -ENXIO;
> > +
> > +	return sysfs_emit(buf, "%x\n", dport->rcrb.rcd_lnkctrl);
> > +}
> > +static DEVICE_ATTR_RO(rcd_link_ctrl);
> > +
> > +static ssize_t rcd_link_status_show(struct device *dev,
> > +				   struct device_attribute *attr, char *buf)
> > +{
> > +	struct cxl_dev_state *cxlds = dev_get_drvdata(dev);
> > +	struct cxl_memdev *cxlmd = cxlds->cxlmd;
> > +	struct device *endpoint_parent;
> > +	struct cxl_dport *dport;
> > +	struct cxl_port *port;
> > +
> > +	port = cxl_mem_find_port(cxlmd, &dport);
> > +	if (!port)
> > +		return -EINVAL;
> > +
> > +	endpoint_parent = port->uport_dev;
> > +	if (!endpoint_parent)
> > +		return -ENXIO;
> > +
> > +	guard(device)(endpoint_parent);
> > +	if (!endpoint_parent->driver)
> > +		return -ENXIO;
> > +
> > +	return sysfs_emit(buf, "%x\n", dport->rcrb.rcd_lnkstatus);
> > +}
> > +static DEVICE_ATTR_RO(rcd_link_status);
> > +
> > +static struct attribute *cxl_rcd_attrs[] = {
> > +		&dev_attr_rcd_link_cap.attr,
> > +		&dev_attr_rcd_link_ctrl.attr,
> > +		&dev_attr_rcd_link_status.attr,
> > +		NULL
> > +};
> > +
> > +static umode_t cxl_rcd_visible(struct kobject *kobj,
> > +					  struct attribute *a, int n)
> > +{
> > +	struct device *dev = kobj_to_dev(kobj);
> > +	struct pci_dev *pdev = to_pci_dev(dev);
> > +
> > +	if (is_cxl_restricted(pdev))
> > +		return a->mode;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct attribute_group cxl_rcd_group = {
> > +		.attrs = cxl_rcd_attrs,
> > +		.is_visible = cxl_rcd_visible,
> > +};
> > +__ATTRIBUTE_GROUPS(cxl_rcd);
> > +
> >  static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id
> *id)
> >  {
> >  	struct pci_host_bridge *host_bridge =
> pci_find_host_bridge(pdev->bus);
> > @@ -969,6 +1069,7 @@ static struct pci_driver cxl_pci_driver = {
> >  	.id_table		= cxl_mem_pci_tbl,
> >  	.probe			= cxl_pci_probe,
> >  	.err_handler		= &cxl_error_handlers,
> > +	.dev_groups		= cxl_rcd_groups,
> >  	.driver	= {
> >  		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
> >  	},






[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