@@ -153,6 +153,8 @@ static inline bool cxl_is_interleave_granularity_valid(int ig)
#define CXLDEV_MBOX_BG_CMD_STATUS_OFFSET 0x18
#define CXLDEV_MBOX_PAYLOAD_OFFSET 0x20
+#define CXL_DOE_PROTOCOL_TABLE_ACCESS 2
+
/*
* Using struct_group() allows for per register-block-type helper routines,
* without requiring block-type agnostic code to include the prefix.
@@ -119,6 +119,7 @@ struct cxl_endpoint_dvsec_info {
* Currently only memory devices are represented.
*
* @dev: The device associated with this CXL state
+ * @cdat_doe: Auxiliary DOE device capabile of reading CDAT
* @regs: Parsed register blocks
* @cxl_dvsec: Offset to the PCIe device DVSEC
* @payload_size: Size of space for payload
@@ -151,6 +152,7 @@ struct cxl_endpoint_dvsec_info {
struct cxl_dev_state {
struct device *dev;
+ struct cxl_doe_dev *cdat_doe;
struct cxl_regs regs;
int cxl_dvsec;
@@ -687,12 +687,78 @@ int cxl_pci_create_doe_devices(struct pci_dev *pdev)
return 0;
}
+bool cxl_doe_dev_supports_prot(struct cxl_doe_dev *doe_dev, u16 vid, u16 pid)
+{
+ struct cxl_doe_drv_state *doe_ds;
+ bool ret;
+
+ doe_ds = cxl_pci_doe_get_drv(doe_dev);
+ if (!doe_ds) {
+ cxl_pci_doe_put_drv(doe_dev);
+ return false;
+ }
+ ret = pci_doe_supports_prot(doe_ds->doe_mb, vid, pid);
+ cxl_pci_doe_put_drv(doe_dev);
+ return ret;
+}
+
+static int cxl_match_cdat_doe_device(struct device *dev, const void *data)
+{
+ const struct cxl_dev_state *cxlds = data;
+ struct auxiliary_device *adev = to_auxiliary_dev(dev);
+ struct cxl_doe_dev *doe_dev;
+
+ /* Ensure this is a DOE device */
+ if (strcmp(DOE_DEV_NAME, adev->name))
+ return 0;
+
+ /* Determine if this auxiliary device belongs to the cxlds */
+ if (cxlds->dev != dev->parent)
+ return 0;
+
+ doe_dev = container_of(adev, struct cxl_doe_dev, adev);
+
+ /* If it is one of ours check for the CDAT protocol */
+ if (!cxl_doe_dev_supports_prot(doe_dev, PCI_DVSEC_VENDOR_ID_CXL,
+ CXL_DOE_PROTOCOL_TABLE_ACCESS))
+ return 0;
+
+ return 1;
+}
+
+static void drop_cdat_doe_ref(void *data)
+{
+ struct cxl_doe_dev *cdat_doe = data;
+
+ put_device(&cdat_doe->adev.dev);
+}
+
static int cxl_setup_doe_devices(struct cxl_dev_state *cxlds)
{
struct device *dev = cxlds->dev;
struct pci_dev *pdev = to_pci_dev(dev);
+ struct auxiliary_device *adev;
+ int rc;
+
+ rc = cxl_pci_create_doe_devices(pdev);
+ if (rc)
+ return rc;
- return cxl_pci_create_doe_devices(pdev);
+ adev = auxiliary_find_device(NULL, cxlds, &cxl_match_cdat_doe_device);
+
+ if (adev) {
+ struct cxl_doe_dev *doe_dev = container_of(adev,
+ struct cxl_doe_dev,
+ adev);
+
+ /* auxiliary_find_device() takes the reference */
+ rc = devm_add_action_or_reset(dev, drop_cdat_doe_ref, doe_dev);
+ if (rc)
+ return rc;
+ cxlds->cdat_doe = doe_dev;
+ }
+
+ return 0;
}
static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)