From 70298c6e6c1ba68346336b4ea54bd5c0abbf73c8 Mon Sep 17 00:00:00 2001 From: "Zhang, Yanmin" Date: Tue, 16 Jun 2009 13:34:38 +0800 Subject: PCI AER: support Multiple Error Received and no error source id Based on PCI Express AER specs, a root port might receive multiple TLP errors while it could only save a correctable error source id and an uncorrectable error source id at the same time. In addition, some root port hardware might be unable to provide a correct source id, i.e., the source id, or the bus id part of the source id provided by root port might be equal to 0. The patchset implements the support in kernel by searching the device tree under the root port. Patch 1 changes parameter cb of function pci_walk_bus to return a value. When cb return non-zero, pci_walk_bus stops more searching on the device tree. Reviewed-by: Andrew Patterson Signed-off-by: Zhang Yanmin Signed-off-by: Jesse Barnes --- drivers/pci/bus.c | 11 +++++++++-- drivers/pci/pcie/aer/aerdrv_core.c | 30 ++++++++++++++++-------------- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 40af27f3104..cef28a79103 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -206,13 +206,18 @@ void pci_enable_bridges(struct pci_bus *bus) * Walk the given bus, including any bridged devices * on buses under this bus. Call the provided callback * on each device found. + * + * We check the return of @cb each time. If it returns anything + * other than 0, we break out. + * */ -void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), +void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), void *userdata) { struct pci_dev *dev; struct pci_bus *bus; struct list_head *next; + int retval; bus = top; down_read(&pci_bus_sem); @@ -236,8 +241,10 @@ void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *), /* Run device routines with the device locked */ down(&dev->dev.sem); - cb(dev, userdata); + retval = cb(dev, userdata); up(&dev->dev.sem); + if (retval) + break; } up_read(&pci_bus_sem); } diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c index dd3829e68e3..a7a3919904b 100644 --- a/drivers/pci/pcie/aer/aerdrv_core.c +++ b/drivers/pci/pcie/aer/aerdrv_core.c @@ -109,7 +109,7 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev) #endif /* 0 */ -static void set_device_error_reporting(struct pci_dev *dev, void *data) +static int set_device_error_reporting(struct pci_dev *dev, void *data) { bool enable = *((bool *)data); @@ -124,6 +124,8 @@ static void set_device_error_reporting(struct pci_dev *dev, void *data) if (enable) pcie_set_ecrc_checking(dev); + + return 0; } /** @@ -207,7 +209,7 @@ static struct device* find_source_device(struct pci_dev *parent, u16 id) return NULL; } -static void report_error_detected(struct pci_dev *dev, void *data) +static int report_error_detected(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -232,16 +234,16 @@ static void report_error_detected(struct pci_dev *dev, void *data) dev->driver ? "no AER-aware driver" : "no driver"); } - return; + return 0; } err_handler = dev->driver->err_handler; vote = err_handler->error_detected(dev, result_data->state); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_mmio_enabled(struct pci_dev *dev, void *data) +static int report_mmio_enabled(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -251,15 +253,15 @@ static void report_mmio_enabled(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->mmio_enabled) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->mmio_enabled(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_slot_reset(struct pci_dev *dev, void *data) +static int report_slot_reset(struct pci_dev *dev, void *data) { pci_ers_result_t vote; struct pci_error_handlers *err_handler; @@ -269,15 +271,15 @@ static void report_slot_reset(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->slot_reset) - return; + return 0; err_handler = dev->driver->err_handler; vote = err_handler->slot_reset(dev); result_data->result = merge_result(result_data->result, vote); - return; + return 0; } -static void report_resume(struct pci_dev *dev, void *data) +static int report_resume(struct pci_dev *dev, void *data) { struct pci_error_handlers *err_handler; @@ -286,11 +288,11 @@ static void report_resume(struct pci_dev *dev, void *data) if (!dev->driver || !dev->driver->err_handler || !dev->driver->err_handler->resume) - return; + return 0; err_handler = dev->driver->err_handler; err_handler->resume(dev); - return; + return 0; } /** @@ -307,7 +309,7 @@ static void report_resume(struct pci_dev *dev, void *data) static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, enum pci_channel_state state, char *error_mesg, - void (*cb)(struct pci_dev *, void *)) + int (*cb)(struct pci_dev *, void *)) { struct aer_broadcast_data result_data; -- cgit v1.2.3-70-g09d2