Kobayashi,Daisuke 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. > > Signed-off-by: "Kobayashi,Daisuke" <kobayashi.da-06@xxxxxxxxxxx> > --- > drivers/cxl/pci.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 74 insertions(+) > > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c > index 2ff361e756d6..0ff15738b1ba 100644 > --- a/drivers/cxl/pci.c > +++ b/drivers/cxl/pci.c > @@ -786,6 +786,79 @@ 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_port *port; > + struct cxl_dport *dport; > + struct device *parent = dev->parent; > + struct pci_dev *parent_pdev = to_pci_dev(parent); > + > + port = cxl_pci_find_port(parent_pdev, &dport); > + if (!port) > + return -EINVAL; A few problems with this: 1/ No need to convert to the parent PCI device when there is a lookup routine to go from cxl_memdev to its upstream port. struct cxl_dev_state *cxlds = dev_get_drvdata(dev); struct cxl_memdev *cxlmd = cxlds->cxlmd; 2/ The port reference is leaked Add a put_cxl_port() __free() routine like this: diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 534e25e2f0a4..d81bc4cc0a4c 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -744,6 +744,7 @@ DEFINE_FREE(put_cxl_root, struct cxl_root *, if (_T) put_cxl_root(_T)) int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); void cxl_bus_rescan(void); void cxl_bus_drain(void); +DEFINE_FREE(put_cxl_port, struct cxl_port *, if (_T) put_cxl_port(_T)) struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev, struct cxl_dport **dport); struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, ...and then: struct cxl_port *port __free(put_cxl_port) = cxl_mem_find_port(cxlmd, &dport); 3/ The port corresponding to a memdev can disappear at any time so you need to do the same validation the cxl_mem_probe() does to keep the port active during the register access: guard(device)(&port->dev); if (!port->dev.driver) return -ENXIO; ...then you can read from the cached PCIe capability similar to how the error handler path reads from aer_cap.