diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/vme/vme.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/vme/vme.c')
-rw-r--r-- | kernel/drivers/vme/vme.c | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/kernel/drivers/vme/vme.c b/kernel/drivers/vme/vme.c index 6bab2c4ed..72924b063 100644 --- a/kernel/drivers/vme/vme.c +++ b/kernel/drivers/vme/vme.c @@ -177,8 +177,8 @@ size_t vme_get_size(struct vme_resource *resource) } EXPORT_SYMBOL(vme_get_size); -static int vme_check_window(u32 aspace, unsigned long long vme_base, - unsigned long long size) +int vme_check_window(u32 aspace, unsigned long long vme_base, + unsigned long long size) { int retval = 0; @@ -199,10 +199,8 @@ static int vme_check_window(u32 aspace, unsigned long long vme_base, retval = -EFAULT; break; case VME_A64: - /* - * Any value held in an unsigned long long can be used as the - * base - */ + if ((size != 0) && (vme_base > U64_MAX + 1 - size)) + retval = -EFAULT; break; case VME_CRCSR: if (((vme_base + size) > VME_CRCSR_MAX) || @@ -223,6 +221,40 @@ static int vme_check_window(u32 aspace, unsigned long long vme_base, return retval; } +EXPORT_SYMBOL(vme_check_window); + +static u32 vme_get_aspace(int am) +{ + switch (am) { + case 0x29: + case 0x2D: + return VME_A16; + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3C: + case 0x3D: + case 0x3E: + case 0x3F: + return VME_A24; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + return VME_A32; + case 0x0: + case 0x1: + case 0x3: + return VME_A64; + } + + return 0; +} /* * Request a slave image with specific attributes, return some unique @@ -991,6 +1023,63 @@ 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, int am) +{ + struct list_head *handler_pos = NULL; + struct vme_error_handler *handler; + int handler_triggered = 0; + u32 aspace = vme_get_aspace(am); + + list_for_each(handler_pos, &bridge->vme_error_handlers) { + handler = list_entry(handler_pos, struct vme_error_handler, + list); + if ((aspace == handler->aspace) && + (address >= handler->start) && + (address < handler->end)) { + if (!handler->num_errors) + handler->first_error = address; + if (handler->num_errors != UINT_MAX) + handler->num_errors++; + handler_triggered = 1; + } + } + + if (!handler_triggered) + dev_err(bridge->parent, + "Unhandled VME access error at address 0x%llx\n", + address); +} +EXPORT_SYMBOL(vme_bus_error_handler); + +struct vme_error_handler *vme_register_error_handler( + struct vme_bridge *bridge, u32 aspace, + unsigned long long address, size_t len) +{ + struct vme_error_handler *handler; + + handler = kmalloc(sizeof(*handler), GFP_KERNEL); + if (!handler) + return NULL; + + handler->aspace = aspace; + handler->start = address; + handler->end = address + len; + handler->num_errors = 0; + handler->first_error = 0; + list_add_tail(&handler->list, &bridge->vme_error_handlers); + + return handler; +} +EXPORT_SYMBOL(vme_register_error_handler); + +void vme_unregister_error_handler(struct vme_error_handler *handler) +{ + list_del(&handler->list); + kfree(handler); +} +EXPORT_SYMBOL(vme_unregister_error_handler); + void vme_irq_handler(struct vme_bridge *bridge, int level, int statid) { void (*call)(int, int, void *); |