Merge branch 'pci/hotplug'

- Ignore Link Down/Up caused by error-induced Hot Reset so endpoint driver
  can remain bound to device during error recovery (Lukas Wunner)

- Remove unused resume err_handler (Lukas Wunner)

- Remove unused pcie_port_bus_{,un}register() declarations (Lukas Wunner)

- Skip compiling err.c when CONFIG_PCIEAER not set (Lukas Wunner)

* pci/hotplug:
  PCI/ERR: Reduce compile time for CONFIG_PCIEAER=n
  PCI/portdrv: Remove unused pcie_port_bus_{,un}register() declarations
  PCI/portdrv: Remove unused resume err_handler
  PCI: pciehp: Ignore Link Down/Up caused by error-induced Hot Reset
  PCI/portdrv: Rename pm_iter() to pcie_port_device_iter()
This commit is contained in:
Bjorn Helgaas 2021-11-05 11:28:43 -05:00
commit 4917f7189b
9 changed files with 50 additions and 41 deletions

View file

@ -189,6 +189,8 @@ int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status);
int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);
int pciehp_slot_reset(struct pcie_device *dev);
static inline const char *slot_name(struct controller *ctrl)
{
return hotplug_slot_name(&ctrl->hotplug_slot);

View file

@ -351,6 +351,8 @@ static struct pcie_port_service_driver hpdriver_portdrv = {
.runtime_suspend = pciehp_runtime_suspend,
.runtime_resume = pciehp_runtime_resume,
#endif /* PM */
.slot_reset = pciehp_slot_reset,
};
int __init pcie_hp_init(void)

View file

@ -862,6 +862,32 @@ void pcie_disable_interrupt(struct controller *ctrl)
pcie_write_cmd(ctrl, 0, mask);
}
/**
* pciehp_slot_reset() - ignore link event caused by error-induced hot reset
* @dev: PCI Express port service device
*
* Called from pcie_portdrv_slot_reset() after AER or DPC initiated a reset
* further up in the hierarchy to recover from an error. The reset was
* propagated down to this hotplug port. Ignore the resulting link flap.
* If the link failed to retrain successfully, synthesize the ignored event.
* Surprise removal during reset is detected through Presence Detect Changed.
*/
int pciehp_slot_reset(struct pcie_device *dev)
{
struct controller *ctrl = get_service_data(dev);
if (ctrl->state != ON_STATE)
return 0;
pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_DLLSC);
if (!pciehp_check_link_active(ctrl))
pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
return 0;
}
/*
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
* bus reset of the bridge, but at the same time we want to ensure that it is

View file

@ -1537,7 +1537,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
#if defined(CONFIG_PCIEPORTBUS) || defined(CONFIG_EEH)
#if defined(CONFIG_PCIEAER) || defined(CONFIG_EEH)
/**
* pci_uevent_ers - emit a uevent during recovery path of PCI device
* @pdev: PCI device undergoing error recovery

View file

@ -2243,6 +2243,7 @@ int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state)
}
EXPORT_SYMBOL_GPL(pci_set_pcie_reset_state);
#ifdef CONFIG_PCIEAER
void pcie_clear_device_status(struct pci_dev *dev)
{
u16 sta;
@ -2250,6 +2251,7 @@ void pcie_clear_device_status(struct pci_dev *dev)
pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &sta);
pcie_capability_write_word(dev, PCI_EXP_DEVSTA, sta);
}
#endif
/**
* pcie_clear_root_pme_status - Clear root port PME interrupt status.

View file

@ -2,12 +2,12 @@
#
# Makefile for PCI Express features and port driver
pcieportdrv-y := portdrv_core.o portdrv_pci.o err.o rcec.o
pcieportdrv-y := portdrv_core.o portdrv_pci.o rcec.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
obj-$(CONFIG_PCIEASPM) += aspm.o
obj-$(CONFIG_PCIEAER) += aer.o
obj-$(CONFIG_PCIEAER) += aer.o err.o
obj-$(CONFIG_PCIEAER_INJECT) += aer_inject.o
obj-$(CONFIG_PCIE_PME) += pme.o
obj-$(CONFIG_PCIE_DPC) += dpc.o

View file

@ -85,8 +85,7 @@ struct pcie_port_service_driver {
int (*runtime_suspend)(struct pcie_device *dev);
int (*runtime_resume)(struct pcie_device *dev);
/* Device driver may resume normal operations */
void (*error_resume)(struct pci_dev *dev);
int (*slot_reset)(struct pcie_device *dev);
int port_type; /* Type of the port this driver can handle */
u32 service; /* Port service this device represents */
@ -110,6 +109,7 @@ void pcie_port_service_unregister(struct pcie_port_service_driver *new);
extern struct bus_type pcie_port_bus_type;
int pcie_port_device_register(struct pci_dev *dev);
int pcie_port_device_iter(struct device *dev, void *data);
#ifdef CONFIG_PM
int pcie_port_device_suspend(struct device *dev);
int pcie_port_device_resume_noirq(struct device *dev);
@ -118,8 +118,6 @@ int pcie_port_device_runtime_suspend(struct device *dev);
int pcie_port_device_runtime_resume(struct device *dev);
#endif
void pcie_port_device_remove(struct pci_dev *dev);
int __must_check pcie_port_bus_register(void);
void pcie_port_bus_unregister(void);
struct pci_dev;

View file

@ -367,24 +367,24 @@ int pcie_port_device_register(struct pci_dev *dev)
return status;
}
#ifdef CONFIG_PM
typedef int (*pcie_pm_callback_t)(struct pcie_device *);
typedef int (*pcie_callback_t)(struct pcie_device *);
static int pm_iter(struct device *dev, void *data)
int pcie_port_device_iter(struct device *dev, void *data)
{
struct pcie_port_service_driver *service_driver;
size_t offset = *(size_t *)data;
pcie_pm_callback_t cb;
pcie_callback_t cb;
if ((dev->bus == &pcie_port_bus_type) && dev->driver) {
service_driver = to_service_driver(dev->driver);
cb = *(pcie_pm_callback_t *)((void *)service_driver + offset);
cb = *(pcie_callback_t *)((void *)service_driver + offset);
if (cb)
return cb(to_pcie_device(dev));
}
return 0;
}
#ifdef CONFIG_PM
/**
* pcie_port_device_suspend - suspend port services associated with a PCIe port
* @dev: PCI Express port to handle
@ -392,13 +392,13 @@ static int pm_iter(struct device *dev, void *data)
int pcie_port_device_suspend(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, suspend);
return device_for_each_child(dev, &off, pm_iter);
return device_for_each_child(dev, &off, pcie_port_device_iter);
}
int pcie_port_device_resume_noirq(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
return device_for_each_child(dev, &off, pm_iter);
return device_for_each_child(dev, &off, pcie_port_device_iter);
}
/**
@ -408,7 +408,7 @@ int pcie_port_device_resume_noirq(struct device *dev)
int pcie_port_device_resume(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, resume);
return device_for_each_child(dev, &off, pm_iter);
return device_for_each_child(dev, &off, pcie_port_device_iter);
}
/**
@ -418,7 +418,7 @@ int pcie_port_device_resume(struct device *dev)
int pcie_port_device_runtime_suspend(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, runtime_suspend);
return device_for_each_child(dev, &off, pm_iter);
return device_for_each_child(dev, &off, pcie_port_device_iter);
}
/**
@ -428,7 +428,7 @@ int pcie_port_device_runtime_suspend(struct device *dev)
int pcie_port_device_runtime_resume(struct device *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, runtime_resume);
return device_for_each_child(dev, &off, pm_iter);
return device_for_each_child(dev, &off, pcie_port_device_iter);
}
#endif /* PM */

View file

@ -160,6 +160,9 @@ static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
{
size_t off = offsetof(struct pcie_port_service_driver, slot_reset);
device_for_each_child(&dev->dev, &off, pcie_port_device_iter);
pci_restore_state(dev);
pci_save_state(dev);
return PCI_ERS_RESULT_RECOVERED;
@ -170,29 +173,6 @@ static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
return PCI_ERS_RESULT_RECOVERED;
}
static int resume_iter(struct device *device, void *data)
{
struct pcie_device *pcie_device;
struct pcie_port_service_driver *driver;
if (device->bus == &pcie_port_bus_type && device->driver) {
driver = to_service_driver(device->driver);
if (driver && driver->error_resume) {
pcie_device = to_pcie_device(device);
/* Forward error message to service drivers */
driver->error_resume(pcie_device->port);
}
}
return 0;
}
static void pcie_portdrv_err_resume(struct pci_dev *dev)
{
device_for_each_child(&dev->dev, NULL, resume_iter);
}
/*
* LINUX Device Driver Model
*/
@ -210,7 +190,6 @@ static const struct pci_error_handlers pcie_portdrv_err_handler = {
.error_detected = pcie_portdrv_error_detected,
.slot_reset = pcie_portdrv_slot_reset,
.mmio_enabled = pcie_portdrv_mmio_enabled,
.resume = pcie_portdrv_err_resume,
};
static struct pci_driver pcie_portdriver = {