PCI: aerdrv: introduce default_downstream_reset_link
I noticed that when I inject a fatal error to an endpoint via aer-inject, aer_root_reset() is called as reset_link for a downstream port at upstream of the endpoint: pcieport 0000:00:06.0: AER: Uncorrected (Fatal) error received: id=5401 : pcieport 0000:52:02.0: Root Port link has been reset It externally appears to be working, but internally issues some accesses to PCI_ERR_ROOT_COMMAND/STATUS registers that is for root port so not available on downstream port. This patch introduces default_downstream_reset_link that is a version of aer_root_reset() with no accesses to root port's register. It is used for downstream ports that has no reset_link function its specific. This patch also updates related description in pcieaer-howto.txt. Some minor fixes are included. Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com> Reviewed-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:

committed by
Jesse Barnes

parent
517cae3829
commit
89713422a7
@@ -341,7 +341,6 @@ static int __devinit aer_probe(struct pcie_device *dev)
|
||||
**/
|
||||
static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
||||
{
|
||||
u16 p2p_ctrl;
|
||||
u32 reg32;
|
||||
int pos;
|
||||
|
||||
@@ -352,27 +351,7 @@ static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
|
||||
reg32 &= ~ROOT_PORT_INTR_ON_MESG_MASK;
|
||||
pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, reg32);
|
||||
|
||||
/* Assert Secondary Bus Reset */
|
||||
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
|
||||
p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
|
||||
|
||||
/*
|
||||
* we should send hot reset message for 2ms to allow it time to
|
||||
* propogate to all downstream ports
|
||||
*/
|
||||
msleep(2);
|
||||
|
||||
/* De-assert Secondary Bus Reset */
|
||||
p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
|
||||
|
||||
/*
|
||||
* System software must wait for at least 100ms from the end
|
||||
* of a reset of one or more device before it is permitted
|
||||
* to issue Configuration Requests to those devices.
|
||||
*/
|
||||
msleep(200);
|
||||
aer_do_secondary_bus_reset(dev);
|
||||
dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
|
||||
|
||||
/* Clear Root Error Status */
|
||||
|
@@ -114,6 +114,7 @@ static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
|
||||
}
|
||||
|
||||
extern struct bus_type pcie_port_bus_type;
|
||||
extern void aer_do_secondary_bus_reset(struct pci_dev *dev);
|
||||
extern int aer_init(struct pcie_device *dev);
|
||||
extern void aer_isr(struct work_struct *work);
|
||||
extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
|
||||
|
@@ -373,6 +373,53 @@ static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
|
||||
return result_data.result;
|
||||
}
|
||||
|
||||
/**
|
||||
* aer_do_secondary_bus_reset - perform secondary bus reset
|
||||
* @dev: pointer to bridge's pci_dev data structure
|
||||
*
|
||||
* Invoked when performing link reset at Root Port or Downstream Port.
|
||||
*/
|
||||
void aer_do_secondary_bus_reset(struct pci_dev *dev)
|
||||
{
|
||||
u16 p2p_ctrl;
|
||||
|
||||
/* Assert Secondary Bus Reset */
|
||||
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
|
||||
p2p_ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
|
||||
|
||||
/*
|
||||
* we should send hot reset message for 2ms to allow it time to
|
||||
* propagate to all downstream ports
|
||||
*/
|
||||
msleep(2);
|
||||
|
||||
/* De-assert Secondary Bus Reset */
|
||||
p2p_ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
|
||||
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
|
||||
|
||||
/*
|
||||
* System software must wait for at least 100ms from the end
|
||||
* of a reset of one or more device before it is permitted
|
||||
* to issue Configuration Requests to those devices.
|
||||
*/
|
||||
msleep(200);
|
||||
}
|
||||
|
||||
/**
|
||||
* default_downstream_reset_link - default reset function for Downstream Port
|
||||
* @dev: pointer to downstream port's pci_dev data structure
|
||||
*
|
||||
* Invoked when performing link reset at Downstream Port w/ no aer driver.
|
||||
*/
|
||||
static pci_ers_result_t default_downstream_reset_link(struct pci_dev *dev)
|
||||
{
|
||||
aer_do_secondary_bus_reset(dev);
|
||||
dev_printk(KERN_DEBUG, &dev->dev,
|
||||
"Downstream Port link has been reset\n");
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
}
|
||||
|
||||
static int find_aer_service_iter(struct device *device, void *data)
|
||||
{
|
||||
struct pcie_port_service_driver *service_driver, **drv;
|
||||
@@ -406,31 +453,28 @@ static pci_ers_result_t reset_link(struct pcie_device *aerdev,
|
||||
pci_ers_result_t status;
|
||||
struct pcie_port_service_driver *driver;
|
||||
|
||||
if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
|
||||
if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
|
||||
/* Reset this port for all subordinates */
|
||||
udev = dev;
|
||||
else
|
||||
} else {
|
||||
/* Reset the upstream component (likely downstream port) */
|
||||
udev = dev->bus->self;
|
||||
}
|
||||
|
||||
/* Use the aer driver of the component firstly */
|
||||
driver = find_aer_service(udev);
|
||||
|
||||
/*
|
||||
* If it hasn't the driver and is downstream port, use the root port's
|
||||
*/
|
||||
if (!driver || !driver->reset_link) {
|
||||
if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM &&
|
||||
aerdev->device.driver &&
|
||||
to_service_driver(aerdev->device.driver)->reset_link) {
|
||||
driver = to_service_driver(aerdev->device.driver);
|
||||
} else {
|
||||
dev_printk(KERN_DEBUG, &dev->dev,
|
||||
"no link-reset support at upstream device %s\n",
|
||||
pci_name(udev));
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
if (driver && driver->reset_link) {
|
||||
status = driver->reset_link(udev);
|
||||
} else if (udev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) {
|
||||
status = default_downstream_reset_link(udev);
|
||||
} else {
|
||||
dev_printk(KERN_DEBUG, &dev->dev,
|
||||
"no link-reset support at upstream device %s\n",
|
||||
pci_name(udev));
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
status = driver->reset_link(udev);
|
||||
if (status != PCI_ERS_RESULT_RECOVERED) {
|
||||
dev_printk(KERN_DEBUG, &dev->dev,
|
||||
"link reset at upstream device %s failed\n",
|
||||
|
Reference in New Issue
Block a user