2018-05-18 00:44:15 +03:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* This file implements the error recovery as a core part of PCIe error
|
|
|
|
* reporting. When a PCIe error is delivered, an error message will be
|
|
|
|
* collected and printed to console, then, an error recovery procedure
|
|
|
|
* will be executed by following the PCI error recovery rules.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Intel Corp.
|
|
|
|
* Tom Long Nguyen (tom.l.nguyen@intel.com)
|
|
|
|
* Zhang Yanmin (yanmin.zhang@intel.com)
|
|
|
|
*/
|
|
|
|
|
2019-12-14 01:46:05 +03:00
|
|
|
#define dev_fmt(fmt) "AER: " fmt
|
|
|
|
|
2018-05-18 00:44:15 +03:00
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/aer.h>
|
|
|
|
#include "portdrv.h"
|
|
|
|
#include "../pci.h"
|
|
|
|
|
|
|
|
static pci_ers_result_t merge_result(enum pci_ers_result orig,
|
|
|
|
enum pci_ers_result new)
|
|
|
|
{
|
|
|
|
if (new == PCI_ERS_RESULT_NO_AER_DRIVER)
|
|
|
|
return PCI_ERS_RESULT_NO_AER_DRIVER;
|
|
|
|
|
|
|
|
if (new == PCI_ERS_RESULT_NONE)
|
|
|
|
return orig;
|
|
|
|
|
|
|
|
switch (orig) {
|
|
|
|
case PCI_ERS_RESULT_CAN_RECOVER:
|
|
|
|
case PCI_ERS_RESULT_RECOVERED:
|
|
|
|
orig = new;
|
|
|
|
break;
|
|
|
|
case PCI_ERS_RESULT_DISCONNECT:
|
|
|
|
if (new == PCI_ERS_RESULT_NEED_RESET)
|
|
|
|
orig = PCI_ERS_RESULT_NEED_RESET;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return orig;
|
|
|
|
}
|
|
|
|
|
2018-09-20 19:27:14 +03:00
|
|
|
static int report_error_detected(struct pci_dev *dev,
|
2020-07-02 19:26:49 +03:00
|
|
|
pci_channel_state_t state,
|
2018-09-20 19:27:14 +03:00
|
|
|
enum pci_ers_result *result)
|
2018-05-18 00:44:15 +03:00
|
|
|
{
|
2021-10-13 01:20:06 +03:00
|
|
|
struct pci_driver *pdrv;
|
2018-05-18 00:44:15 +03:00
|
|
|
pci_ers_result_t vote;
|
|
|
|
const struct pci_error_handlers *err_handler;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
2021-11-10 21:03:34 +03:00
|
|
|
pdrv = dev->driver;
|
2018-09-20 19:27:16 +03:00
|
|
|
if (!pci_dev_set_io_state(dev, state) ||
|
2021-10-13 01:20:06 +03:00
|
|
|
!pdrv ||
|
|
|
|
!pdrv->err_handler ||
|
|
|
|
!pdrv->err_handler->error_detected) {
|
2018-05-18 00:44:15 +03:00
|
|
|
/*
|
PCI/ERR: Run error recovery callbacks for all affected devices
If an Endpoint reported an error with ERR_FATAL, we previously ran driver
error recovery callbacks only for the Endpoint's driver. But if we reset a
Link to recover from the error, all downstream components are affected,
including the Endpoint, any multi-function peers, and children of those
peers.
Initiate the Link reset from the deepest Downstream Port that is
reliable, and call the error recovery callbacks for all its children.
If a Downstream Port (including a Root Port) reports an error, we assume
the Port itself is reliable and we need to reset its downstream Link. In
all other cases (Switch Upstream Ports, Endpoints, Bridges, etc), we assume
the Link leading to the component needs to be reset, so we initiate the
reset at the parent Downstream Port.
This allows two other clean-ups. First, we currently only use a Link
reset, which can only be initiated using a Downstream Port, so we can
remove checks for Endpoints. Second, the Downstream Port where we initiate
the Link reset is reliable (unlike components downstream from it), so the
special cases for error detect and resume are no longer necessary.
Signed-off-by: Keith Busch <keith.busch@intel.com>
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
2018-09-20 19:27:13 +03:00
|
|
|
* If any device in the subtree does not have an error_detected
|
|
|
|
* callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
|
|
|
|
* error callbacks of "any" device in the subtree, and will
|
|
|
|
* exit in the disconnected error state.
|
2018-05-18 00:44:15 +03:00
|
|
|
*/
|
2019-12-13 14:44:34 +03:00
|
|
|
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
|
2018-05-18 00:44:15 +03:00
|
|
|
vote = PCI_ERS_RESULT_NO_AER_DRIVER;
|
2019-12-14 01:46:05 +03:00
|
|
|
pci_info(dev, "can't recover (no error_detected callback)\n");
|
2019-12-13 14:44:34 +03:00
|
|
|
} else {
|
2018-05-18 00:44:15 +03:00
|
|
|
vote = PCI_ERS_RESULT_NONE;
|
2019-12-13 14:44:34 +03:00
|
|
|
}
|
2018-05-18 00:44:15 +03:00
|
|
|
} else {
|
2021-10-13 01:20:06 +03:00
|
|
|
err_handler = pdrv->err_handler;
|
2018-09-20 19:27:14 +03:00
|
|
|
vote = err_handler->error_detected(dev, state);
|
2018-05-18 00:44:15 +03:00
|
|
|
}
|
2018-09-20 19:27:15 +03:00
|
|
|
pci_uevent_ers(dev, vote);
|
2018-09-20 19:27:14 +03:00
|
|
|
*result = merge_result(*result, vote);
|
2018-05-18 00:44:15 +03:00
|
|
|
device_unlock(&dev->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-20 19:27:14 +03:00
|
|
|
static int report_frozen_detected(struct pci_dev *dev, void *data)
|
|
|
|
{
|
|
|
|
return report_error_detected(dev, pci_channel_io_frozen, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int report_normal_detected(struct pci_dev *dev, void *data)
|
|
|
|
{
|
|
|
|
return report_error_detected(dev, pci_channel_io_normal, data);
|
|
|
|
}
|
|
|
|
|
2018-05-18 00:44:15 +03:00
|
|
|
static int report_mmio_enabled(struct pci_dev *dev, void *data)
|
|
|
|
{
|
2021-10-13 01:20:06 +03:00
|
|
|
struct pci_driver *pdrv;
|
2018-09-20 19:27:14 +03:00
|
|
|
pci_ers_result_t vote, *result = data;
|
2018-05-18 00:44:15 +03:00
|
|
|
const struct pci_error_handlers *err_handler;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
2021-11-10 21:03:34 +03:00
|
|
|
pdrv = dev->driver;
|
2021-10-13 01:20:06 +03:00
|
|
|
if (!pdrv ||
|
|
|
|
!pdrv->err_handler ||
|
|
|
|
!pdrv->err_handler->mmio_enabled)
|
2018-05-18 00:44:15 +03:00
|
|
|
goto out;
|
|
|
|
|
2021-10-13 01:20:06 +03:00
|
|
|
err_handler = pdrv->err_handler;
|
2018-05-18 00:44:15 +03:00
|
|
|
vote = err_handler->mmio_enabled(dev);
|
2018-09-20 19:27:14 +03:00
|
|
|
*result = merge_result(*result, vote);
|
2018-05-18 00:44:15 +03:00
|
|
|
out:
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int report_slot_reset(struct pci_dev *dev, void *data)
|
|
|
|
{
|
2021-10-13 01:20:06 +03:00
|
|
|
struct pci_driver *pdrv;
|
2018-09-20 19:27:14 +03:00
|
|
|
pci_ers_result_t vote, *result = data;
|
2018-05-18 00:44:15 +03:00
|
|
|
const struct pci_error_handlers *err_handler;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
2021-11-10 21:03:34 +03:00
|
|
|
pdrv = dev->driver;
|
2021-10-13 01:20:06 +03:00
|
|
|
if (!pdrv ||
|
|
|
|
!pdrv->err_handler ||
|
|
|
|
!pdrv->err_handler->slot_reset)
|
2018-05-18 00:44:15 +03:00
|
|
|
goto out;
|
|
|
|
|
2021-10-13 01:20:06 +03:00
|
|
|
err_handler = pdrv->err_handler;
|
2018-05-18 00:44:15 +03:00
|
|
|
vote = err_handler->slot_reset(dev);
|
2018-09-20 19:27:14 +03:00
|
|
|
*result = merge_result(*result, vote);
|
2018-05-18 00:44:15 +03:00
|
|
|
out:
|
|
|
|
device_unlock(&dev->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int report_resume(struct pci_dev *dev, void *data)
|
|
|
|
{
|
2021-10-13 01:20:06 +03:00
|
|
|
struct pci_driver *pdrv;
|
2018-05-18 00:44:15 +03:00
|
|
|
const struct pci_error_handlers *err_handler;
|
|
|
|
|
|
|
|
device_lock(&dev->dev);
|
2021-11-10 21:03:34 +03:00
|
|
|
pdrv = dev->driver;
|
2018-09-20 19:27:16 +03:00
|
|
|
if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
|
2021-10-13 01:20:06 +03:00
|
|
|
!pdrv ||
|
|
|
|
!pdrv->err_handler ||
|
|
|
|
!pdrv->err_handler->resume)
|
2018-05-18 00:44:15 +03:00
|
|
|
goto out;
|
|
|
|
|
2021-10-13 01:20:06 +03:00
|
|
|
err_handler = pdrv->err_handler;
|
2018-05-18 00:44:15 +03:00
|
|
|
err_handler->resume(dev);
|
|
|
|
out:
|
2018-09-20 19:27:15 +03:00
|
|
|
pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
|
2018-05-18 00:44:15 +03:00
|
|
|
device_unlock(&dev->dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-11-21 03:10:30 +03:00
|
|
|
/**
|
|
|
|
* pci_walk_bridge - walk bridges potentially AER affected
|
2020-11-21 03:10:33 +03:00
|
|
|
* @bridge: bridge which may be a Port, an RCEC, or an RCiEP
|
2020-11-21 03:10:30 +03:00
|
|
|
* @cb: callback to be called for each device found
|
|
|
|
* @userdata: arbitrary pointer to be passed to callback
|
|
|
|
*
|
|
|
|
* If the device provided is a bridge, walk the subordinate bus, including
|
|
|
|
* any bridged devices on buses under this bus. Call the provided callback
|
|
|
|
* on each device found.
|
2020-12-02 20:26:29 +03:00
|
|
|
*
|
2020-11-21 03:10:33 +03:00
|
|
|
* If the device provided has no subordinate bus, e.g., an RCEC or RCiEP,
|
|
|
|
* call the callback on the device itself.
|
2020-11-21 03:10:30 +03:00
|
|
|
*/
|
|
|
|
static void pci_walk_bridge(struct pci_dev *bridge,
|
|
|
|
int (*cb)(struct pci_dev *, void *),
|
|
|
|
void *userdata)
|
|
|
|
{
|
|
|
|
if (bridge->subordinate)
|
|
|
|
pci_walk_bus(bridge->subordinate, cb, userdata);
|
2020-12-02 20:26:29 +03:00
|
|
|
else
|
|
|
|
cb(bridge, userdata);
|
2020-11-21 03:10:30 +03:00
|
|
|
}
|
|
|
|
|
PCI/ERR: Return status of pcie_do_recovery()
As per the DPC Enhancements ECN [1], sec 4.5.1, table 4-4, if the OS
supports Error Disconnect Recover (EDR), it must invalidate the software
state associated with child devices of the port without attempting to
access the child device hardware. In addition, if the OS supports DPC, it
must attempt to recover the child devices if the port implements the DPC
Capability. If the OS continues operation, the OS must inform the firmware
of the status of the recovery operation via the _OST method.
Return the result of pcie_do_recovery() so we can report it to firmware via
_OST.
[1] Downstream Port Containment Related Enhancements ECN, Jan 28, 2019,
affecting PCI Firmware Specification, Rev. 3.2
https://members.pcisig.com/wg/PCI-SIG/document/12888
Link: https://lore.kernel.org/r/eb60ec89448769349c6722954ffbf2de163155b5.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>
2020-03-24 03:26:03 +03:00
|
|
|
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
|
2020-11-21 03:10:25 +03:00
|
|
|
pci_channel_state_t state,
|
|
|
|
pci_ers_result_t (*reset_subordinates)(struct pci_dev *pdev))
|
2018-05-18 00:44:15 +03:00
|
|
|
{
|
2020-11-21 03:10:27 +03:00
|
|
|
int type = pci_pcie_type(dev);
|
2020-11-21 03:10:28 +03:00
|
|
|
struct pci_dev *bridge;
|
|
|
|
pci_ers_result_t status = PCI_ERS_RESULT_CAN_RECOVER;
|
2020-11-24 19:55:30 +03:00
|
|
|
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
|
2018-05-18 00:44:15 +03:00
|
|
|
|
PCI/ERR: Run error recovery callbacks for all affected devices
If an Endpoint reported an error with ERR_FATAL, we previously ran driver
error recovery callbacks only for the Endpoint's driver. But if we reset a
Link to recover from the error, all downstream components are affected,
including the Endpoint, any multi-function peers, and children of those
peers.
Initiate the Link reset from the deepest Downstream Port that is
reliable, and call the error recovery callbacks for all its children.
If a Downstream Port (including a Root Port) reports an error, we assume
the Port itself is reliable and we need to reset its downstream Link. In
all other cases (Switch Upstream Ports, Endpoints, Bridges, etc), we assume
the Link leading to the component needs to be reset, so we initiate the
reset at the parent Downstream Port.
This allows two other clean-ups. First, we currently only use a Link
reset, which can only be initiated using a Downstream Port, so we can
remove checks for Endpoints. Second, the Downstream Port where we initiate
the Link reset is reliable (unlike components downstream from it), so the
special cases for error detect and resume are no longer necessary.
Signed-off-by: Keith Busch <keith.busch@intel.com>
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
2018-09-20 19:27:13 +03:00
|
|
|
/*
|
2020-11-21 03:10:33 +03:00
|
|
|
* If the error was detected by a Root Port, Downstream Port, RCEC,
|
|
|
|
* or RCiEP, recovery runs on the device itself. For Ports, that
|
|
|
|
* also includes any subordinate devices.
|
2020-12-02 20:26:29 +03:00
|
|
|
*
|
|
|
|
* If it was detected by another device (Endpoint, etc), recovery
|
|
|
|
* runs on the device and anything else under the same Port, i.e.,
|
|
|
|
* everything under "bridge".
|
PCI/ERR: Run error recovery callbacks for all affected devices
If an Endpoint reported an error with ERR_FATAL, we previously ran driver
error recovery callbacks only for the Endpoint's driver. But if we reset a
Link to recover from the error, all downstream components are affected,
including the Endpoint, any multi-function peers, and children of those
peers.
Initiate the Link reset from the deepest Downstream Port that is
reliable, and call the error recovery callbacks for all its children.
If a Downstream Port (including a Root Port) reports an error, we assume
the Port itself is reliable and we need to reset its downstream Link. In
all other cases (Switch Upstream Ports, Endpoints, Bridges, etc), we assume
the Link leading to the component needs to be reset, so we initiate the
reset at the parent Downstream Port.
This allows two other clean-ups. First, we currently only use a Link
reset, which can only be initiated using a Downstream Port, so we can
remove checks for Endpoints. Second, the Downstream Port where we initiate
the Link reset is reliable (unlike components downstream from it), so the
special cases for error detect and resume are no longer necessary.
Signed-off-by: Keith Busch <keith.busch@intel.com>
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
2018-09-20 19:27:13 +03:00
|
|
|
*/
|
2020-11-21 03:10:29 +03:00
|
|
|
if (type == PCI_EXP_TYPE_ROOT_PORT ||
|
2020-12-02 20:26:29 +03:00
|
|
|
type == PCI_EXP_TYPE_DOWNSTREAM ||
|
2020-11-21 03:10:33 +03:00
|
|
|
type == PCI_EXP_TYPE_RC_EC ||
|
|
|
|
type == PCI_EXP_TYPE_RC_END)
|
2020-11-21 03:10:28 +03:00
|
|
|
bridge = dev;
|
2020-11-21 03:10:29 +03:00
|
|
|
else
|
|
|
|
bridge = pci_upstream_bridge(dev);
|
PCI/ERR: Run error recovery callbacks for all affected devices
If an Endpoint reported an error with ERR_FATAL, we previously ran driver
error recovery callbacks only for the Endpoint's driver. But if we reset a
Link to recover from the error, all downstream components are affected,
including the Endpoint, any multi-function peers, and children of those
peers.
Initiate the Link reset from the deepest Downstream Port that is
reliable, and call the error recovery callbacks for all its children.
If a Downstream Port (including a Root Port) reports an error, we assume
the Port itself is reliable and we need to reset its downstream Link. In
all other cases (Switch Upstream Ports, Endpoints, Bridges, etc), we assume
the Link leading to the component needs to be reset, so we initiate the
reset at the parent Downstream Port.
This allows two other clean-ups. First, we currently only use a Link
reset, which can only be initiated using a Downstream Port, so we can
remove checks for Endpoints. Second, the Downstream Port where we initiate
the Link reset is reliable (unlike components downstream from it), so the
special cases for error detect and resume are no longer necessary.
Signed-off-by: Keith Busch <keith.busch@intel.com>
[bhelgaas: changelog]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
2018-09-20 19:27:13 +03:00
|
|
|
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_dbg(bridge, "broadcast error_detected message\n");
|
2020-03-28 01:33:24 +03:00
|
|
|
if (state == pci_channel_io_frozen) {
|
2020-11-21 03:10:30 +03:00
|
|
|
pci_walk_bridge(bridge, report_frozen_detected, &status);
|
2021-01-05 02:02:58 +03:00
|
|
|
if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) {
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_warn(bridge, "subordinate device reset failed\n");
|
2020-03-28 01:33:24 +03:00
|
|
|
goto failed;
|
2020-03-24 03:26:02 +03:00
|
|
|
}
|
2020-03-28 01:33:24 +03:00
|
|
|
} else {
|
2020-11-21 03:10:30 +03:00
|
|
|
pci_walk_bridge(bridge, report_normal_detected, &status);
|
2020-03-28 01:33:24 +03:00
|
|
|
}
|
2018-09-20 19:27:12 +03:00
|
|
|
|
2018-09-20 19:27:14 +03:00
|
|
|
if (status == PCI_ERS_RESULT_CAN_RECOVER) {
|
|
|
|
status = PCI_ERS_RESULT_RECOVERED;
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_dbg(bridge, "broadcast mmio_enabled message\n");
|
2020-11-21 03:10:30 +03:00
|
|
|
pci_walk_bridge(bridge, report_mmio_enabled, &status);
|
2018-09-20 19:27:14 +03:00
|
|
|
}
|
2018-05-18 00:44:15 +03:00
|
|
|
|
|
|
|
if (status == PCI_ERS_RESULT_NEED_RESET) {
|
|
|
|
/*
|
|
|
|
* TODO: Should call platform-specific
|
|
|
|
* functions to reset slot before calling
|
|
|
|
* drivers' slot_reset callbacks?
|
|
|
|
*/
|
2018-09-20 19:27:14 +03:00
|
|
|
status = PCI_ERS_RESULT_RECOVERED;
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_dbg(bridge, "broadcast slot_reset message\n");
|
2020-11-21 03:10:30 +03:00
|
|
|
pci_walk_bridge(bridge, report_slot_reset, &status);
|
2018-05-18 00:44:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (status != PCI_ERS_RESULT_RECOVERED)
|
|
|
|
goto failed;
|
|
|
|
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_dbg(bridge, "broadcast resume message\n");
|
2020-11-21 03:10:30 +03:00
|
|
|
pci_walk_bridge(bridge, report_resume, &status);
|
2018-05-18 00:44:15 +03:00
|
|
|
|
2020-11-24 19:55:30 +03:00
|
|
|
/*
|
2021-01-05 02:02:56 +03:00
|
|
|
* If we have native control of AER, clear error status in the device
|
|
|
|
* that detected the error. If the platform retained control of AER,
|
|
|
|
* it is responsible for clearing this status. In that case, the
|
|
|
|
* signaling device may not even be visible to the OS.
|
2020-11-24 19:55:30 +03:00
|
|
|
*/
|
|
|
|
if (host->native_aer || pcie_ports_native) {
|
2021-01-05 02:02:56 +03:00
|
|
|
pcie_clear_device_status(dev);
|
|
|
|
pci_aer_clear_nonfatal_status(dev);
|
2020-11-24 19:55:30 +03:00
|
|
|
}
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_info(bridge, "device recovery successful\n");
|
PCI/ERR: Return status of pcie_do_recovery()
As per the DPC Enhancements ECN [1], sec 4.5.1, table 4-4, if the OS
supports Error Disconnect Recover (EDR), it must invalidate the software
state associated with child devices of the port without attempting to
access the child device hardware. In addition, if the OS supports DPC, it
must attempt to recover the child devices if the port implements the DPC
Capability. If the OS continues operation, the OS must inform the firmware
of the status of the recovery operation via the _OST method.
Return the result of pcie_do_recovery() so we can report it to firmware via
_OST.
[1] Downstream Port Containment Related Enhancements ECN, Jan 28, 2019,
affecting PCI Firmware Specification, Rev. 3.2
https://members.pcisig.com/wg/PCI-SIG/document/12888
Link: https://lore.kernel.org/r/eb60ec89448769349c6722954ffbf2de163155b5.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>
2020-03-24 03:26:03 +03:00
|
|
|
return status;
|
2018-05-18 00:44:15 +03:00
|
|
|
|
|
|
|
failed:
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_uevent_ers(bridge, PCI_ERS_RESULT_DISCONNECT);
|
2018-05-18 00:44:15 +03:00
|
|
|
|
|
|
|
/* TODO: Should kernel panic here? */
|
2020-11-21 03:10:28 +03:00
|
|
|
pci_info(bridge, "device recovery failed\n");
|
PCI/ERR: Return status of pcie_do_recovery()
As per the DPC Enhancements ECN [1], sec 4.5.1, table 4-4, if the OS
supports Error Disconnect Recover (EDR), it must invalidate the software
state associated with child devices of the port without attempting to
access the child device hardware. In addition, if the OS supports DPC, it
must attempt to recover the child devices if the port implements the DPC
Capability. If the OS continues operation, the OS must inform the firmware
of the status of the recovery operation via the _OST method.
Return the result of pcie_do_recovery() so we can report it to firmware via
_OST.
[1] Downstream Port Containment Related Enhancements ECN, Jan 28, 2019,
affecting PCI Firmware Specification, Rev. 3.2
https://members.pcisig.com/wg/PCI-SIG/document/12888
Link: https://lore.kernel.org/r/eb60ec89448769349c6722954ffbf2de163155b5.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>
2020-03-24 03:26:03 +03:00
|
|
|
|
|
|
|
return status;
|
2018-05-18 00:44:15 +03:00
|
|
|
}
|