]> git.itanic.dy.fi Git - linux-stable/commitdiff
PCI/DOE: Create mailboxes on device enumeration
authorLukas Wunner <lukas@wunner.de>
Sat, 11 Mar 2023 14:40:12 +0000 (15:40 +0100)
committerDan Williams <dan.j.williams@intel.com>
Tue, 18 Apr 2023 17:36:58 +0000 (10:36 -0700)
Currently a DOE instance cannot be shared by multiple drivers because
each driver creates its own pci_doe_mb struct for a given DOE instance.
For the same reason a DOE instance cannot be shared between the PCI core
and a driver.

Moreover, finding out which protocols a DOE instance supports requires
creating a pci_doe_mb for it.  If a device has multiple DOE instances,
a driver looking for a specific protocol may need to create a pci_doe_mb
for each of the device's DOE instances and then destroy those which
do not support the desired protocol.  That's obviously an inefficient
way to do things.

Overcome these issues by creating mailboxes in the PCI core on device
enumeration.

Provide a pci_find_doe_mailbox() API call to allow drivers to get a
pci_doe_mb for a given (pci_dev, vendor, protocol) triple.  This API is
modeled after pci_find_capability() and can later be amended with a
pci_find_next_doe_mailbox() call to iterate over all mailboxes of a
given pci_dev which support a specific protocol.

On removal, destroy the mailboxes in pci_destroy_dev(), after the driver
is unbound.  This allows drivers to use DOE in their ->remove() hook.

On surprise removal, cancel ongoing DOE exchanges and prevent new ones
from being scheduled.  Thereby ensure that a hot-removed device doesn't
needlessly wait for a running exchange to time out.

Tested-by: Ira Weiny <ira.weiny@intel.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Ming Li <ming4.li@intel.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/40a6f973f72ef283d79dd55e7e6fddc7481199af.1678543498.git.lukas@wunner.de
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/pci/doe.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/pci/remove.c
include/linux/pci-doe.h
include/linux/pci.h

index 7539e72db5cb5903745c6766fa40c13048a5d2ad..9c577f5b3878bb7ad24e460d131dfb16b83d3698 100644 (file)
@@ -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);
+}
index d2c08670a20ed77823e65a748365d15f0a0bf875..815a4d2a41dad37e4a51c293090a50b8b62bc0f5 100644 (file)
@@ -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;
 }
index a3f68b6ba6ac2db4500e5f5f416b972e479746d9..02d2bf80eedb9a7c989fa110b8d241d00f41e4f7 100644 (file)
@@ -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);
index 0145aef1b9301823e3a406611353b596036e8a77..f25acf50879f05ea316d8e2f31a60404043ce705 100644 (file)
@@ -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);
index 7f16749c6aa3c4b235882896809130cb9762fc35..d6192ee0ac07530c0c3a69ae0f6192b74c95e345 100644 (file)
@@ -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,
index b50e5c79f7e32fd9fb9c4b118677bda46b387be7..29d99530ec17645d02e02dfee4479d0625cfcb7e 100644 (file)
@@ -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 */