2021-05-25 15:58:53

by Lambert Wang

[permalink] [raw]
Subject: [PATCH] pci: add pci_dev_is_alive API

Device drivers use this API to proactively check if the device
is alive or not. It is helpful for some PCI devices to detect
surprise removal and do recovery when Hotplug function is disabled.

Note: Device in power states larger than D0 is also treated not alive
by this function.

Signed-off-by: Lambert Wang <[email protected]>
---
drivers/pci/pci.c | 23 +++++++++++++++++++++++
include/linux/pci.h | 1 +
2 files changed, 24 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b717680377a9..8a7c039b1cd5 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -4659,6 +4659,29 @@ int pcie_flr(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pcie_flr);

+/**
+ * pci_dev_is_alive - check the pci device is alive or not
+ * @pdev: the PCI device
+ *
+ * Device drivers use this API to proactively check if the device
+ * is alive or not. It is helpful for some PCI devices to detect
+ * surprise removal and do recovery when Hotplug function is disabled.
+ *
+ * Note: Device in power state larger than D0 is also treated not alive
+ * by this function.
+ *
+ * Returns true if the device is alive.
+ */
+bool pci_dev_is_alive(struct pci_dev *pdev)
+{
+ u16 vendor;
+
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
+
+ return vendor == pdev->vendor;
+}
+EXPORT_SYMBOL(pci_dev_is_alive);
+
static int pci_af_flr(struct pci_dev *dev, int probe)
{
int pos;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c20211e59a57..2a3ba06a7347 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1227,6 +1227,7 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
void pcie_print_link_status(struct pci_dev *dev);
bool pcie_has_flr(struct pci_dev *dev);
int pcie_flr(struct pci_dev *dev);
+bool pci_dev_is_alive(struct pci_dev *pdev);
int __pci_reset_function_locked(struct pci_dev *dev);
int pci_reset_function(struct pci_dev *dev);
int pci_reset_function_locked(struct pci_dev *dev);
--
2.30.2


2021-05-25 16:46:41

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH] pci: add pci_dev_is_alive API

[+cc Krzysztof]

On Tue, May 25, 2021 at 08:59:25PM +0800, Lambert Wang wrote:
> Device drivers use this API to proactively check if the device
> is alive or not. It is helpful for some PCI devices to detect
> surprise removal and do recovery when Hotplug function is disabled.
>
> Note: Device in power states larger than D0 is also treated not alive
> by this function.
>
> Signed-off-by: Lambert Wang <[email protected]>
> ---
> drivers/pci/pci.c | 23 +++++++++++++++++++++++
> include/linux/pci.h | 1 +
> 2 files changed, 24 insertions(+)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index b717680377a9..8a7c039b1cd5 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -4659,6 +4659,29 @@ int pcie_flr(struct pci_dev *dev)
> }
> EXPORT_SYMBOL_GPL(pcie_flr);
>
> +/**
> + * pci_dev_is_alive - check the pci device is alive or not
> + * @pdev: the PCI device
> + *
> + * Device drivers use this API to proactively check if the device
> + * is alive or not. It is helpful for some PCI devices to detect
> + * surprise removal and do recovery when Hotplug function is disabled.
> + *
> + * Note: Device in power state larger than D0 is also treated not alive
> + * by this function.
> + *
> + * Returns true if the device is alive.
> + */
> +bool pci_dev_is_alive(struct pci_dev *pdev)
> +{
> + u16 vendor;
> +
> + pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor);
> +
> + return vendor == pdev->vendor;
> +}
> +EXPORT_SYMBOL(pci_dev_is_alive);

This is quite similar to pci_device_is_present(). Does that not do
what you need?

I'm not a big fan of either pci_device_is_present() or
pci_dev_is_alive() because they are racy. You must assume that even
if they return "true," the device may disappear because of a surprise
removal before you can act on that information.

> static int pci_af_flr(struct pci_dev *dev, int probe)
> {
> int pos;
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index c20211e59a57..2a3ba06a7347 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1227,6 +1227,7 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
> void pcie_print_link_status(struct pci_dev *dev);
> bool pcie_has_flr(struct pci_dev *dev);
> int pcie_flr(struct pci_dev *dev);
> +bool pci_dev_is_alive(struct pci_dev *pdev);
> int __pci_reset_function_locked(struct pci_dev *dev);
> int pci_reset_function(struct pci_dev *dev);
> int pci_reset_function_locked(struct pci_dev *dev);
> --
> 2.30.2
>