@@ -104,4 +104,16 @@ config CXL_REGION
default CXL_BUS
tristate
+config CXL_PCI_DOE
+ tristate "CXL PCI Data Object Exchange (DOE) support"
+ depends on CXL_PCI
+ default CXL_BUS
+ help
+ Driver for DOE auxiliary devices.
+
+ The DOE capabilities provides a simple mailbox in PCI config space that
+ is used for a number of different protocols useful to CXL. The CXL PCI
+ subsystem creates auxiliary devices for each DOE mailbox capability
+ found. This driver is required for the kernel to use these devices.
+
endif
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CXL_BUS) += core/
obj-$(CONFIG_CXL_PCI) += cxl_pci.o
+obj-$(CONFIG_CXL_PCI_DOE) += cxl_doe.o
obj-$(CONFIG_CXL_MEM) += cxl_mem.o
obj-$(CONFIG_CXL_ACPI) += cxl_acpi.o
obj-$(CONFIG_CXL_PMEM) += cxl_pmem.o
@@ -9,6 +10,7 @@ obj-$(CONFIG_CXL_REGION) += cxl_region.o
cxl_mem-y := mem.o
cxl_pci-y := pci.o
+cxl_doe-y := doe.o
cxl_acpi-y := acpi.o
cxl_pmem-y := pmem.o
cxl_port-y := port.o
@@ -79,6 +79,7 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port);
*
* @adev: Auxiliary bus device
* @pdev: PCI device this belongs to
+ * @driver_access: Lock the driver during access
* @cap_offset: Capability offset
* @use_irq: Set if IRQs are to be used with this mailbox
*
@@ -88,9 +89,21 @@ int devm_cxl_port_enumerate_dports(struct cxl_port *port);
struct cxl_doe_dev {
struct auxiliary_device adev;
struct pci_dev *pdev;
+ struct rw_semaphore driver_access;
int cap_offset;
bool use_irq;
};
#define DOE_DEV_NAME "doe"
+/**
+ * struct cxl_doe_drv_state - state of the DOE Aux driver
+ *
+ * @doe_dev: The Auxiliary DOE device
+ * @doe_mb: PCI DOE mailbox state
+ */
+struct cxl_doe_drv_state {
+ struct cxl_doe_dev *doe_dev;
+ struct pci_doe_mb *doe_mb;
+};
+
#endif /* __CXL_PCI_H__ */
new file mode 100644
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
+
+#include <linux/pci.h>
+#include <linux/pci-doe.h>
+
+#include "cxlpci.h"
+
+static void doe_destroy_mb(void *ds)
+{
+ struct cxl_doe_drv_state *doe_ds = ds;
+
+ pci_doe_destroy_mb(doe_ds->doe_mb);
+}
+
+static int cxl_pci_doe_probe(struct auxiliary_device *aux_dev,
+ const struct auxiliary_device_id *id)
+{
+ struct cxl_doe_dev *doe_dev = container_of(aux_dev, struct cxl_doe_dev,
+ adev);
+ struct device *dev = &aux_dev->dev;
+ struct cxl_doe_drv_state *doe_ds;
+ struct pci_doe_mb *doe_mb;
+
+ doe_ds = devm_kzalloc(dev, sizeof(*doe_ds), GFP_KERNEL);
+ if (!doe_ds)
+ return -ENOMEM;
+
+ doe_mb = pci_doe_create_mb(doe_dev->pdev, doe_dev->cap_offset,
+ doe_dev->use_irq);
+ if (IS_ERR(doe_mb)) {
+ dev_err(dev, "Failed to create the DOE mailbox state machine\n");
+ return PTR_ERR(doe_mb);
+ }
+
+ doe_ds->doe_mb = doe_mb;
+ devm_add_action_or_reset(dev, doe_destroy_mb, doe_ds);
+
+ down_write(&doe_dev->driver_access);
+ auxiliary_set_drvdata(aux_dev, doe_ds);
+ up_write(&doe_dev->driver_access);
+
+ return 0;
+}
+
+static void cxl_pci_doe_remove(struct auxiliary_device *aux_dev)
+{
+ struct cxl_doe_dev *doe_dev = container_of(aux_dev, struct cxl_doe_dev,
+ adev);
+
+ down_write(&doe_dev->driver_access);
+ auxiliary_set_drvdata(aux_dev, NULL);
+ up_write(&doe_dev->driver_access);
+}
+
+static const struct auxiliary_device_id cxl_pci_doe_auxiliary_id_table[] = {
+ {.name = "cxl_pci." DOE_DEV_NAME, },
+ {},
+};
+
+MODULE_DEVICE_TABLE(auxiliary, cxl_pci_doe_auxiliary_id_table);
+
+struct auxiliary_driver cxl_pci_doe_auxiliary_drv = {
+ .name = "cxl_doe_drv",
+ .id_table = cxl_pci_doe_auxiliary_id_table,
+ .probe = cxl_pci_doe_probe,
+ .remove = cxl_pci_doe_remove,
+};
+
+static int __init cxl_pci_doe_init_module(void)
+{
+ int ret;
+
+ ret = auxiliary_driver_register(&cxl_pci_doe_auxiliary_drv);
+ if (ret) {
+ pr_err("Failed cxl_pci_doe auxiliary_driver_register() ret=%d\n",
+ ret);
+ }
+
+ return ret;
+}
+
+static void __exit cxl_pci_doe_exit_module(void)
+{
+ auxiliary_driver_unregister(&cxl_pci_doe_auxiliary_drv);
+}
+
+module_init(cxl_pci_doe_init_module);
+module_exit(cxl_pci_doe_exit_module);
+MODULE_LICENSE("GPL v2");
@@ -571,6 +571,17 @@ static void cxl_pci_doe_destroy_device(void *ad)
auxiliary_device_uninit(ad);
}
+static struct cxl_doe_drv_state *cxl_pci_doe_get_drv(struct cxl_doe_dev *doe_dev)
+{
+ down_read(&doe_dev->driver_access);
+ return auxiliary_get_drvdata(&doe_dev->adev);
+}
+
+static void cxl_pci_doe_put_drv(struct cxl_doe_dev *doe_dev)
+{
+ up_read(&doe_dev->driver_access);
+}
+
/**
* cxl_pci_create_doe_devices - Create auxiliary bus DOE devices for all DOE
* mailboxes found
@@ -633,6 +644,7 @@ int cxl_pci_create_doe_devices(struct pci_dev *pdev)
return -ENOMEM;
new_dev->pdev = pdev;
+ init_rwsem(&new_dev->driver_access);
new_dev->cap_offset = off;
new_dev->use_irq = use_irq;
@@ -663,6 +675,13 @@ int cxl_pci_create_doe_devices(struct pci_dev *pdev)
adev);
if (rc)
return rc;
+
+ if (device_attach(&adev->dev) != 1) {
+ dev_err(&adev->dev,
+ "Failed to attach a driver to DOE device %d\n",
+ adev->id);
+ return -ENODEV;
+ }
}
return 0;
@@ -777,6 +796,7 @@ static struct pci_driver cxl_pci_driver = {
},
};
+MODULE_SOFTDEP("pre: cxl_doe");
MODULE_LICENSE("GPL v2");
module_pci_driver(cxl_pci_driver);
MODULE_IMPORT_NS(CXL);
@@ -1118,6 +1118,7 @@
#define PCI_DOE_STATUS_DATA_OBJECT_READY 0x80000000 /* Data Object Ready */
#define PCI_DOE_WRITE 0x10 /* DOE Write Data Mailbox Register */
#define PCI_DOE_READ 0x14 /* DOE Read Data Mailbox Register */
+#define PCI_DOE_CAP_SIZE (0x14 + 4) /* Size of this register block */
/* DOE Data Object - note not actually registers */
#define PCI_DOE_DATA_OBJECT_HEADER_1_VID 0x0000ffff