diff options
author | Dmitry Kalinkin <dmitry.kalinkin@gmail.com> | 2015-09-18 02:01:42 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-10-04 21:50:57 +0300 |
commit | e2c6393fda98dde5534dd6f83bd15f76abed6555 (patch) | |
tree | 73f94bb441c10040c6527b07c86e74d4a2eb1b37 /drivers/vme | |
parent | da5ae8a991d35d73b3875de0298afaf033d85363 (diff) | |
download | linux-e2c6393fda98dde5534dd6f83bd15f76abed6555.tar.xz |
vme: move tsi148 error handling into VME subsystem
Error handling code found in tsi148 is not device specific. In fact it
already relies on shared vme_bus_error struct and vme_bridge.vme_errors
field. The other bridge driver could reuse this code if it is shared.
This introduces a slight behavior change: vme error message won't be
triggered in a rare case when err_chk=1 and kmalloc fails.
Signed-off-by: Dmitry Kalinkin <dmitry.kalinkin@gmail.com>
Cc: Igor Alekseev <igor.alekseev@itep.ru>
Acked-by: Martyn Welch <martyn@welchs.me.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/vme')
-rw-r--r-- | drivers/vme/bridges/vme_tsi148.c | 93 | ||||
-rw-r--r-- | drivers/vme/vme.c | 86 | ||||
-rw-r--r-- | drivers/vme/vme_bridge.h | 6 |
3 files changed, 99 insertions, 86 deletions
diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 6c40f282c267..60c4933ca0c8 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -169,7 +169,6 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) unsigned int error_addr_high, error_addr_low; unsigned long long error_addr; u32 error_attrib; - struct vme_bus_error *error = NULL; struct tsi148_driver *bridge; bridge = tsi148_bridge->driver_priv; @@ -186,23 +185,12 @@ static u32 tsi148_VERR_irqhandler(struct vme_bridge *tsi148_bridge) "Occurred\n"); } - if (err_chk) { - error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC); - if (error) { - error->address = error_addr; - error->attributes = error_attrib; - list_add_tail(&error->list, &tsi148_bridge->vme_errors); - } else { - dev_err(tsi148_bridge->parent, - "Unable to alloc memory for VMEbus Error reporting\n"); - } - } - - if (!error) { + if (err_chk) + vme_bus_error_handler(tsi148_bridge, error_addr, error_attrib); + else dev_err(tsi148_bridge->parent, "VME Bus Error at address: 0x%llx, attributes: %08x\n", error_addr, error_attrib); - } /* Clear Status */ iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); @@ -483,73 +471,6 @@ static int tsi148_irq_generate(struct vme_bridge *tsi148_bridge, int level, } /* - * Find the first error in this address range - */ -static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, - u32 aspace, unsigned long long address, size_t count) -{ - struct list_head *err_pos; - struct vme_bus_error *vme_err, *valid = NULL; - unsigned long long bound; - - bound = address + count; - - /* - * XXX We are currently not looking at the address space when parsing - * for errors. This is because parsing the Address Modifier Codes - * is going to be quite resource intensive to do properly. We - * should be OK just looking at the addresses and this is certainly - * much better than what we had before. - */ - err_pos = NULL; - /* Iterate through errors */ - list_for_each(err_pos, &tsi148_bridge->vme_errors) { - vme_err = list_entry(err_pos, struct vme_bus_error, list); - if ((vme_err->address >= address) && - (vme_err->address < bound)) { - - valid = vme_err; - break; - } - } - - return valid; -} - -/* - * Clear errors in the provided address range. - */ -static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, - u32 aspace, unsigned long long address, size_t count) -{ - struct list_head *err_pos, *temp; - struct vme_bus_error *vme_err; - unsigned long long bound; - - bound = address + count; - - /* - * XXX We are currently not looking at the address space when parsing - * for errors. This is because parsing the Address Modifier Codes - * is going to be quite resource intensive to do properly. We - * should be OK just looking at the addresses and this is certainly - * much better than what we had before. - */ - err_pos = NULL; - /* Iterate through errors */ - list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) { - vme_err = list_entry(err_pos, struct vme_bus_error, list); - - if ((vme_err->address >= address) && - (vme_err->address < bound)) { - - list_del(err_pos); - kfree(vme_err); - } - } -} - -/* * Initialize a slave window with the requested attributes. */ static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, @@ -1323,14 +1244,14 @@ out: __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle, &dwidth); - vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, + vme_err = vme_find_error(tsi148_bridge, aspace, vme_base + offset, count); if (vme_err != NULL) { dev_err(image->parent->parent, "First VME read error detected " "an at address 0x%llx\n", vme_err->address); retval = vme_err->address - (vme_base + offset); /* Clear down save errors in this address range */ - tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, + vme_clear_errors(tsi148_bridge, aspace, vme_base + offset, count); } @@ -1422,14 +1343,14 @@ out: ioread16(bridge->flush_image->kern_base + 0x7F000); - vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, + vme_err = vme_find_error(tsi148_bridge, aspace, vme_base + offset, count); if (vme_err != NULL) { dev_warn(tsi148_bridge->parent, "First VME write error detected" " an at address 0x%llx\n", vme_err->address); retval = vme_err->address - (vme_base + offset); /* Clear down save errors in this address range */ - tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, + vme_clear_errors(tsi148_bridge, aspace, vme_base + offset, count); } diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 56708915ebbe..6803744978b2 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -990,6 +990,92 @@ int vme_dma_free(struct vme_resource *resource) } EXPORT_SYMBOL(vme_dma_free); +void vme_bus_error_handler(struct vme_bridge *bridge, + unsigned long long address, u32 attributes) +{ + struct vme_bus_error *error; + + error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC); + if (error) { + error->address = address; + error->attributes = attributes; + list_add_tail(&error->list, &bridge->vme_errors); + } else { + dev_err(bridge->parent, + "Unable to alloc memory for VMEbus Error reporting\n"); + } +} +EXPORT_SYMBOL(vme_bus_error_handler); + +/* + * Find the first error in this address range + */ +struct vme_bus_error *vme_find_error(struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t count) +{ + struct list_head *err_pos; + struct vme_bus_error *vme_err, *valid = NULL; + unsigned long long bound; + + bound = address + count; + + /* + * XXX We are currently not looking at the address space when parsing + * for errors. This is because parsing the Address Modifier Codes + * is going to be quite resource intensive to do properly. We + * should be OK just looking at the addresses and this is certainly + * much better than what we had before. + */ + err_pos = NULL; + /* Iterate through errors */ + list_for_each(err_pos, &bridge->vme_errors) { + vme_err = list_entry(err_pos, struct vme_bus_error, list); + if ((vme_err->address >= address) && + (vme_err->address < bound)) { + + valid = vme_err; + break; + } + } + + return valid; +} +EXPORT_SYMBOL(vme_find_error); + +/* + * Clear errors in the provided address range. + */ +void vme_clear_errors(struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t count) +{ + struct list_head *err_pos, *temp; + struct vme_bus_error *vme_err; + unsigned long long bound; + + bound = address + count; + + /* + * XXX We are currently not looking at the address space when parsing + * for errors. This is because parsing the Address Modifier Codes + * is going to be quite resource intensive to do properly. We + * should be OK just looking at the addresses and this is certainly + * much better than what we had before. + */ + err_pos = NULL; + /* Iterate through errors */ + list_for_each_safe(err_pos, temp, &bridge->vme_errors) { + vme_err = list_entry(err_pos, struct vme_bus_error, list); + + if ((vme_err->address >= address) && + (vme_err->address < bound)) { + + list_del(err_pos); + kfree(vme_err); + } + } +} +EXPORT_SYMBOL(vme_clear_errors); + void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) { void (*call)(int, int, void *); diff --git a/drivers/vme/vme_bridge.h b/drivers/vme/vme_bridge.h index 934949abd745..d8d6b144003b 100644 --- a/drivers/vme/vme_bridge.h +++ b/drivers/vme/vme_bridge.h @@ -166,6 +166,12 @@ struct vme_bridge { void *vaddr, dma_addr_t dma); }; +void vme_bus_error_handler(struct vme_bridge *bridge, + unsigned long long address, u32 attributes); +struct vme_bus_error *vme_find_error(struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t count); +void vme_clear_errors(struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t count); void vme_irq_handler(struct vme_bridge *, int, int); int vme_register_bridge(struct vme_bridge *); |