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 19:50:57 +0100 |
commit | e2c6393fda98dde5534dd6f83bd15f76abed6555 (patch) | |
tree | 73f94bb441c10040c6527b07c86e74d4a2eb1b37 /drivers/vme/vme.c | |
parent | da5ae8a991d35d73b3875de0298afaf033d85363 (diff) |
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/vme.c')
-rw-r--r-- | drivers/vme/vme.c | 86 |
1 files changed, 86 insertions, 0 deletions
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 *); |