@@ -20,6 +20,8 @@
#include <linux/pci-doe.h>
#include <linux/workqueue.h>
+#include "pci.h"
+
#define PCI_DOE_PROTOCOL_DISCOVERY 0
/* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */
@@ -658,3 +660,74 @@ int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
return task.rv;
}
EXPORT_SYMBOL_GPL(pci_doe);
+
+/**
+ * pci_find_doe_mailbox() - Find Data Object Exchange mailbox
+ *
+ * @pdev: PCI device
+ * @vendor: Vendor ID
+ * @type: Data Object Type
+ *
+ * Find first DOE mailbox of a PCI device which supports the given protocol.
+ *
+ * RETURNS: Pointer to the DOE mailbox or NULL if none was found.
+ */
+struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor,
+ u8 type)
+{
+ struct pci_doe_mb *doe_mb;
+ unsigned long index;
+
+ xa_for_each(&pdev->doe_mbs, index, doe_mb)
+ if (pci_doe_supports_prot(doe_mb, vendor, type))
+ return doe_mb;
+
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(pci_find_doe_mailbox);
+
+void pci_doe_init(struct pci_dev *pdev)
+{
+ struct pci_doe_mb *doe_mb;
+ u16 offset = 0;
+ int rc;
+
+ xa_init(&pdev->doe_mbs);
+
+ while ((offset = pci_find_next_ext_capability(pdev, offset,
+ PCI_EXT_CAP_ID_DOE))) {
+ doe_mb = pci_doe_create_mb(pdev, offset);
+ if (IS_ERR(doe_mb)) {
+ pci_err(pdev, "[%x] failed to create mailbox: %ld\n",
+ offset, PTR_ERR(doe_mb));
+ continue;
+ }
+
+ rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL);
+ if (rc) {
+ pci_err(pdev, "[%x] failed to insert mailbox: %d\n",
+ offset, rc);
+ pci_doe_destroy_mb(doe_mb);
+ }
+ }
+}
+
+void pci_doe_destroy(struct pci_dev *pdev)
+{
+ struct pci_doe_mb *doe_mb;
+ unsigned long index;
+
+ xa_for_each(&pdev->doe_mbs, index, doe_mb)
+ pci_doe_destroy_mb(doe_mb);
+
+ xa_destroy(&pdev->doe_mbs);
+}
+
+void pci_doe_disconnected(struct pci_dev *pdev)
+{
+ struct pci_doe_mb *doe_mb;
+ unsigned long index;
+
+ xa_for_each(&pdev->doe_mbs, index, doe_mb)
+ pci_doe_cancel_tasks(doe_mb);
+}
@@ -318,6 +318,16 @@ struct pci_sriov {
bool drivers_autoprobe; /* Auto probing of VFs by driver */
};
+#ifdef CONFIG_PCI_DOE
+void pci_doe_init(struct pci_dev *pdev);
+void pci_doe_destroy(struct pci_dev *pdev);
+void pci_doe_disconnected(struct pci_dev *pdev);
+#else
+static inline void pci_doe_init(struct pci_dev *pdev) { }
+static inline void pci_doe_destroy(struct pci_dev *pdev) { }
+static inline void pci_doe_disconnected(struct pci_dev *pdev) { }
+#endif
+
/**
* pci_dev_set_io_state - Set the new error state if possible.
*
@@ -354,6 +364,7 @@ static inline bool pci_dev_set_io_state(struct pci_dev *dev,
static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
{
pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
+ pci_doe_disconnected(dev);
return 0;
}
@@ -2479,6 +2479,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */
pci_rcec_init(dev); /* Root Complex Event Collector */
+ pci_doe_init(dev); /* Data Object Exchange */
pcie_report_downtraining(dev);
pci_init_reset_methods(dev);
@@ -39,6 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
+ pci_doe_destroy(dev);
pcie_aspm_exit_link_state(dev);
pci_bridge_d3_update(dev);
pci_free_resources(dev);
@@ -29,6 +29,8 @@ struct pci_doe_mb;
struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset);
bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type);
+struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor,
+ u8 type);
int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
const void *request, size_t request_sz,
@@ -511,6 +511,9 @@ struct pci_dev {
#endif
#ifdef CONFIG_PCI_P2PDMA
struct pci_p2pdma __rcu *p2pdma;
+#endif
+#ifdef CONFIG_PCI_DOE
+ struct xarray doe_mbs; /* Data Object Exchange mailboxes */
#endif
u16 acs_cap; /* ACS Capability offset */
phys_addr_t rom; /* Physical address if not from BAR */