diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 77fff6f6b0fb..1272288b50ed 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -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
diff --git a/drivers/cxl/Makefile b/drivers/cxl/Makefile
index 02a4776e7ab9..a6104845a774 100644
--- a/drivers/cxl/Makefile
+++ b/drivers/cxl/Makefile
@@ -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
diff --git a/drivers/cxl/cxlpci.h b/drivers/cxl/cxlpci.h
index 2ad8715173ce..821fe05e8289 100644
--- a/drivers/cxl/cxlpci.h
+++ b/drivers/cxl/cxlpci.h
@@ -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__ */
diff --git a/drivers/cxl/doe.c b/drivers/cxl/doe.c
new file mode 100644
index 000000000000..5b13d5ec738e
--- /dev/null
+++ b/drivers/cxl/doe.c
@@ -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");
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 6249f2a30026..bc94811a8395 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -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);
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 4e96b45ee36d..c268df088dd4 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -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
