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:
commit
4917f7189b
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -367,24 +367,24 @@ error_disable:
|
|||
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 */
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Reference in New Issue