Commit b6cf1a42 authored by Kuppuswamy Sathyanarayanan's avatar Kuppuswamy Sathyanarayanan Committed by Bjorn Helgaas

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.comSigned-off-by: default avatarKuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent be06c1b4
...@@ -156,12 +156,6 @@ default reset_link function, but different upstream ports might ...@@ -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 ...@@ -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) ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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, ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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
......
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