mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-28 13:22:57 +00:00
PCI/ERR: Remove service dependency in pcie_do_recovery()
Previously we passed the PCIe service type parameter to pcie_do_recovery(), where reset_link() looked up the underlying pci_port_service_driver and its .reset_link() function pointer. Instead of using this roundabout way, we can just pass the driver-specific .reset_link() callback function when calling pcie_do_recovery() function. This allows us to call pcie_do_recovery() from code that is not a PCIe port service driver, e.g., Error Disconnect Recover (EDR) support. Remove pcie_port_find_service() and pcie_port_service_driver.reset_link since they are now unused. Link: https://lore.kernel.org/r/60e02b87b526cdf2930400059d98704bf0a147d1.1585000084.git.sathyanarayanan.kuppuswamy@linux.intel.com Signed-off-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
be06c1b42e
commit
b6cf1a42f9
7 changed files with 18 additions and 96 deletions
|
@ -156,12 +156,6 @@ default reset_link function, but different upstream ports might
|
||||||
have different specifications to reset pci express link, so all
|
have different specifications to reset pci express link, so all
|
||||||
upstream ports should provide their own reset_link functions.
|
upstream ports should provide their own reset_link functions.
|
||||||
|
|
||||||
In struct pcie_port_service_driver, a new pointer, reset_link, is
|
|
||||||
added.
|
|
||||||
::
|
|
||||||
|
|
||||||
pci_ers_result_t (*reset_link) (struct pci_dev *dev);
|
|
||||||
|
|
||||||
Section 3.2.2.2 provides more detailed info on when to call
|
Section 3.2.2.2 provides more detailed info on when to call
|
||||||
reset_link.
|
reset_link.
|
||||||
|
|
||||||
|
@ -212,15 +206,10 @@ error_detected(dev, pci_channel_io_frozen) to all drivers within
|
||||||
a hierarchy in question. Then, performing link reset at upstream is
|
a hierarchy in question. Then, performing link reset at upstream is
|
||||||
necessary. As different kinds of devices might use different approaches
|
necessary. As different kinds of devices might use different approaches
|
||||||
to reset link, AER port service driver is required to provide the
|
to reset link, AER port service driver is required to provide the
|
||||||
function to reset link. Firstly, kernel looks for if the upstream
|
function to reset link via callback parameter of pcie_do_recovery()
|
||||||
component has an aer driver. If it has, kernel uses the reset_link
|
function. If reset_link is not NULL, recovery function will use it
|
||||||
callback of the aer driver. If the upstream component has no aer driver
|
to reset the link. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER
|
||||||
and the port is downstream port, we will perform a hot reset as the
|
and reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
|
||||||
default by setting the Secondary Bus Reset bit of the Bridge Control
|
|
||||||
register associated with the downstream port. As for upstream ports,
|
|
||||||
they should provide their own aer service drivers with reset_link
|
|
||||||
function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
|
|
||||||
reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
|
|
||||||
to mmio_enabled.
|
to mmio_enabled.
|
||||||
|
|
||||||
helper functions
|
helper functions
|
||||||
|
|
|
@ -548,7 +548,7 @@ static inline int pci_dev_specific_disable_acs_redir(struct pci_dev *dev)
|
||||||
|
|
||||||
/* PCI error reporting and recovery */
|
/* PCI error reporting and recovery */
|
||||||
void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
|
void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
|
||||||
u32 service);
|
pci_ers_result_t (*reset_link)(struct pci_dev *pdev));
|
||||||
|
|
||||||
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
|
bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
|
||||||
#ifdef CONFIG_PCIEASPM
|
#ifdef CONFIG_PCIEASPM
|
||||||
|
|
|
@ -102,6 +102,7 @@ struct aer_stats {
|
||||||
#define ERR_UNCOR_ID(d) (d >> 16)
|
#define ERR_UNCOR_ID(d) (d >> 16)
|
||||||
|
|
||||||
static int pcie_aer_disable;
|
static int pcie_aer_disable;
|
||||||
|
static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
|
||||||
|
|
||||||
void pci_no_aer(void)
|
void pci_no_aer(void)
|
||||||
{
|
{
|
||||||
|
@ -1053,11 +1054,9 @@ static void handle_error_source(struct pci_dev *dev, struct aer_err_info *info)
|
||||||
info->status);
|
info->status);
|
||||||
pci_aer_clear_device_status(dev);
|
pci_aer_clear_device_status(dev);
|
||||||
} else if (info->severity == AER_NONFATAL)
|
} else if (info->severity == AER_NONFATAL)
|
||||||
pcie_do_recovery(dev, pci_channel_io_normal,
|
pcie_do_recovery(dev, pci_channel_io_normal, aer_root_reset);
|
||||||
PCIE_PORT_SERVICE_AER);
|
|
||||||
else if (info->severity == AER_FATAL)
|
else if (info->severity == AER_FATAL)
|
||||||
pcie_do_recovery(dev, pci_channel_io_frozen,
|
pcie_do_recovery(dev, pci_channel_io_frozen, aer_root_reset);
|
||||||
PCIE_PORT_SERVICE_AER);
|
|
||||||
pci_dev_put(dev);
|
pci_dev_put(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,10 +1093,10 @@ static void aer_recover_work_func(struct work_struct *work)
|
||||||
cper_print_aer(pdev, entry.severity, entry.regs);
|
cper_print_aer(pdev, entry.severity, entry.regs);
|
||||||
if (entry.severity == AER_NONFATAL)
|
if (entry.severity == AER_NONFATAL)
|
||||||
pcie_do_recovery(pdev, pci_channel_io_normal,
|
pcie_do_recovery(pdev, pci_channel_io_normal,
|
||||||
PCIE_PORT_SERVICE_AER);
|
aer_root_reset);
|
||||||
else if (entry.severity == AER_FATAL)
|
else if (entry.severity == AER_FATAL)
|
||||||
pcie_do_recovery(pdev, pci_channel_io_frozen,
|
pcie_do_recovery(pdev, pci_channel_io_frozen,
|
||||||
PCIE_PORT_SERVICE_AER);
|
aer_root_reset);
|
||||||
pci_dev_put(pdev);
|
pci_dev_put(pdev);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1501,7 +1500,6 @@ static struct pcie_port_service_driver aerdriver = {
|
||||||
|
|
||||||
.probe = aer_probe,
|
.probe = aer_probe,
|
||||||
.remove = aer_remove,
|
.remove = aer_remove,
|
||||||
.reset_link = aer_root_reset,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -227,7 +227,7 @@ static irqreturn_t dpc_handler(int irq, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We configure DPC so it only triggers on ERR_FATAL */
|
/* We configure DPC so it only triggers on ERR_FATAL */
|
||||||
pcie_do_recovery(pdev, pci_channel_io_frozen, PCIE_PORT_SERVICE_DPC);
|
pcie_do_recovery(pdev, pci_channel_io_frozen, dpc_reset_link);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,6 @@ static struct pcie_port_service_driver dpcdriver = {
|
||||||
.service = PCIE_PORT_SERVICE_DPC,
|
.service = PCIE_PORT_SERVICE_DPC,
|
||||||
.probe = dpc_probe,
|
.probe = dpc_probe,
|
||||||
.remove = dpc_remove,
|
.remove = dpc_remove,
|
||||||
.reset_link = dpc_reset_link,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init pcie_dpc_init(void)
|
int __init pcie_dpc_init(void)
|
||||||
|
|
|
@ -146,49 +146,9 @@ static int report_resume(struct pci_dev *dev, void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void pcie_do_recovery(struct pci_dev *dev,
|
||||||
* default_reset_link - default reset function
|
enum pci_channel_state state,
|
||||||
* @dev: pointer to pci_dev data structure
|
pci_ers_result_t (*reset_link)(struct pci_dev *pdev))
|
||||||
*
|
|
||||||
* Invoked when performing link reset on a Downstream Port or a
|
|
||||||
* Root Port with no aer driver.
|
|
||||||
*/
|
|
||||||
static pci_ers_result_t default_reset_link(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = pci_bus_error_reset(dev);
|
|
||||||
pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n");
|
|
||||||
return rc ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pci_ers_result_t reset_link(struct pci_dev *dev, u32 service)
|
|
||||||
{
|
|
||||||
pci_ers_result_t status;
|
|
||||||
struct pcie_port_service_driver *driver = NULL;
|
|
||||||
|
|
||||||
driver = pcie_port_find_service(dev, service);
|
|
||||||
if (driver && driver->reset_link) {
|
|
||||||
status = driver->reset_link(dev);
|
|
||||||
} else if (pcie_downstream_port(dev)) {
|
|
||||||
status = default_reset_link(dev);
|
|
||||||
} else {
|
|
||||||
pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n",
|
|
||||||
pci_name(dev));
|
|
||||||
return PCI_ERS_RESULT_DISCONNECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status != PCI_ERS_RESULT_RECOVERED) {
|
|
||||||
pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n",
|
|
||||||
pci_name(dev));
|
|
||||||
return PCI_ERS_RESULT_DISCONNECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
|
|
||||||
u32 service)
|
|
||||||
{
|
{
|
||||||
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
|
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
|
||||||
struct pci_bus *bus;
|
struct pci_bus *bus;
|
||||||
|
@ -205,9 +165,11 @@ void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state,
|
||||||
pci_dbg(dev, "broadcast error_detected message\n");
|
pci_dbg(dev, "broadcast error_detected message\n");
|
||||||
if (state == pci_channel_io_frozen) {
|
if (state == pci_channel_io_frozen) {
|
||||||
pci_walk_bus(bus, report_frozen_detected, &status);
|
pci_walk_bus(bus, report_frozen_detected, &status);
|
||||||
status = reset_link(dev, service);
|
status = reset_link(dev);
|
||||||
if (status != PCI_ERS_RESULT_RECOVERED)
|
if (status != PCI_ERS_RESULT_RECOVERED) {
|
||||||
|
pci_warn(dev, "link reset failed\n");
|
||||||
goto failed;
|
goto failed;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pci_walk_bus(bus, report_normal_detected, &status);
|
pci_walk_bus(bus, report_normal_detected, &status);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,9 +92,6 @@ struct pcie_port_service_driver {
|
||||||
/* Device driver may resume normal operations */
|
/* Device driver may resume normal operations */
|
||||||
void (*error_resume)(struct pci_dev *dev);
|
void (*error_resume)(struct pci_dev *dev);
|
||||||
|
|
||||||
/* Link Reset Capability - AER service driver specific */
|
|
||||||
pci_ers_result_t (*reset_link)(struct pci_dev *dev);
|
|
||||||
|
|
||||||
int port_type; /* Type of the port this driver can handle */
|
int port_type; /* Type of the port this driver can handle */
|
||||||
u32 service; /* Port service this device represents */
|
u32 service; /* Port service this device represents */
|
||||||
|
|
||||||
|
@ -161,7 +158,5 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev,
|
|
||||||
u32 service);
|
|
||||||
struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
|
struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
|
||||||
#endif /* _PORTDRV_H_ */
|
#endif /* _PORTDRV_H_ */
|
||||||
|
|
|
@ -458,27 +458,6 @@ static int find_service_iter(struct device *device, void *data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* pcie_port_find_service - find the service driver
|
|
||||||
* @dev: PCI Express port the service is associated with
|
|
||||||
* @service: Service to find
|
|
||||||
*
|
|
||||||
* Find PCI Express port service driver associated with given service
|
|
||||||
*/
|
|
||||||
struct pcie_port_service_driver *pcie_port_find_service(struct pci_dev *dev,
|
|
||||||
u32 service)
|
|
||||||
{
|
|
||||||
struct pcie_port_service_driver *drv;
|
|
||||||
struct portdrv_service_data pdrvs;
|
|
||||||
|
|
||||||
pdrvs.drv = NULL;
|
|
||||||
pdrvs.service = service;
|
|
||||||
device_for_each_child(&dev->dev, &pdrvs, find_service_iter);
|
|
||||||
|
|
||||||
drv = pdrvs.drv;
|
|
||||||
return drv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pcie_port_find_device - find the struct device
|
* pcie_port_find_device - find the struct device
|
||||||
* @dev: PCI Express port the service is associated with
|
* @dev: PCI Express port the service is associated with
|
||||||
|
|
Loading…
Reference in a new issue