Commit ac048403 authored by Lukas Wunner's avatar Lukas Wunner Committed by Dan Williams

PCI/DOE: Create mailboxes on device enumeration

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: default avatarIra Weiny <ira.weiny@intel.com>
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Reviewed-by: default avatarMing Li <ming4.li@intel.com>
Reviewed-by: default avatarIra Weiny <ira.weiny@intel.com>
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Link: https://lore.kernel.org/r/40a6f973f72ef283d79dd55e7e6fddc7481199af.1678543498.git.lukas@wunner.deSigned-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 022b66f3
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <linux/pci-doe.h> #include <linux/pci-doe.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include "pci.h"
#define PCI_DOE_PROTOCOL_DISCOVERY 0 #define PCI_DOE_PROTOCOL_DISCOVERY 0
/* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.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, ...@@ -658,3 +660,74 @@ int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
return task.rv; return task.rv;
} }
EXPORT_SYMBOL_GPL(pci_doe); 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 { ...@@ -318,6 +318,16 @@ struct pci_sriov {
bool drivers_autoprobe; /* Auto probing of VFs by driver */ 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. * 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, ...@@ -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) 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_dev_set_io_state(dev, pci_channel_io_perm_failure);
pci_doe_disconnected(dev);
return 0; return 0;
} }
......
...@@ -2479,6 +2479,7 @@ static void pci_init_capabilities(struct pci_dev *dev) ...@@ -2479,6 +2479,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_aer_init(dev); /* Advanced Error Reporting */ pci_aer_init(dev); /* Advanced Error Reporting */
pci_dpc_init(dev); /* Downstream Port Containment */ pci_dpc_init(dev); /* Downstream Port Containment */
pci_rcec_init(dev); /* Root Complex Event Collector */ pci_rcec_init(dev); /* Root Complex Event Collector */
pci_doe_init(dev); /* Data Object Exchange */
pcie_report_downtraining(dev); pcie_report_downtraining(dev);
pci_init_reset_methods(dev); pci_init_reset_methods(dev);
......
...@@ -39,6 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev) ...@@ -39,6 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
list_del(&dev->bus_list); list_del(&dev->bus_list);
up_write(&pci_bus_sem); up_write(&pci_bus_sem);
pci_doe_destroy(dev);
pcie_aspm_exit_link_state(dev); pcie_aspm_exit_link_state(dev);
pci_bridge_d3_update(dev); pci_bridge_d3_update(dev);
pci_free_resources(dev); pci_free_resources(dev);
......
...@@ -29,6 +29,8 @@ struct pci_doe_mb; ...@@ -29,6 +29,8 @@ struct pci_doe_mb;
struct pci_doe_mb *pcim_doe_create_mb(struct pci_dev *pdev, u16 cap_offset); 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); 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, int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
const void *request, size_t request_sz, const void *request, size_t request_sz,
......
...@@ -511,6 +511,9 @@ struct pci_dev { ...@@ -511,6 +511,9 @@ struct pci_dev {
#endif #endif
#ifdef CONFIG_PCI_P2PDMA #ifdef CONFIG_PCI_P2PDMA
struct pci_p2pdma __rcu *p2pdma; struct pci_p2pdma __rcu *p2pdma;
#endif
#ifdef CONFIG_PCI_DOE
struct xarray doe_mbs; /* Data Object Exchange mailboxes */
#endif #endif
u16 acs_cap; /* ACS Capability offset */ u16 acs_cap; /* ACS Capability offset */
phys_addr_t rom; /* Physical address if not from BAR */ phys_addr_t rom; /* Physical address if not from BAR */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment