From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- .../staging/unisys/visorutil/memregion_direct.c | 207 +++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 drivers/staging/unisys/visorutil/memregion_direct.c (limited to 'drivers/staging/unisys/visorutil/memregion_direct.c') diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c new file mode 100644 index 000000000..eb7422fbe --- /dev/null +++ b/drivers/staging/unisys/visorutil/memregion_direct.c @@ -0,0 +1,207 @@ +/* memregion_direct.c + * + * Copyright (C) 2010 - 2013 UNISYS CORPORATION + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for more + * details. + */ + +/* + * This is an implementation of memory regions that can be used to read/write + * channel memory (in main memory of the host system) from code running in + * a virtual partition. + */ +#include "timskmod.h" +#include "memregion.h" + +#define MYDRVNAME "memregion" + +struct memregion { + HOSTADDRESS physaddr; + ulong nbytes; + void __iomem *mapped; + BOOL requested; + BOOL overlapped; +}; + +static BOOL mapit(struct memregion *memregion); +static void unmapit(struct memregion *memregion); + +struct memregion * +visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes) +{ + struct memregion *rc = NULL; + struct memregion *memregion; + + memregion = kzalloc(sizeof(*memregion), GFP_KERNEL | __GFP_NORETRY); + if (memregion == NULL) + return NULL; + + memregion->physaddr = physaddr; + memregion->nbytes = nbytes; + memregion->overlapped = FALSE; + if (!mapit(memregion)) { + rc = NULL; + goto cleanup; + } + rc = memregion; +cleanup: + if (rc == NULL) { + visor_memregion_destroy(memregion); + memregion = NULL; + } + return rc; +} +EXPORT_SYMBOL_GPL(visor_memregion_create); + +struct memregion * +visor_memregion_create_overlapped(struct memregion *parent, ulong offset, + ulong nbytes) +{ + struct memregion *memregion = NULL; + + if (parent == NULL) + return NULL; + + if (parent->mapped == NULL) + return NULL; + + if ((offset >= parent->nbytes) || + ((offset + nbytes) >= parent->nbytes)) + return NULL; + + memregion = kzalloc(sizeof(*memregion), GFP_KERNEL|__GFP_NORETRY); + if (memregion == NULL) + return NULL; + + memregion->physaddr = parent->physaddr + offset; + memregion->nbytes = nbytes; + memregion->mapped = ((u8 __iomem *)(parent->mapped)) + offset; + memregion->requested = FALSE; + memregion->overlapped = TRUE; + return memregion; +} +EXPORT_SYMBOL_GPL(visor_memregion_create_overlapped); + +static BOOL +mapit(struct memregion *memregion) +{ + ulong physaddr = (ulong)(memregion->physaddr); + ulong nbytes = memregion->nbytes; + + memregion->requested = FALSE; + if (request_mem_region(physaddr, nbytes, MYDRVNAME)) + memregion->requested = TRUE; + memregion->mapped = ioremap_cache(physaddr, nbytes); + if (!memregion->mapped) + return FALSE; + return TRUE; +} + +static void +unmapit(struct memregion *memregion) +{ + if (memregion->mapped != NULL) { + iounmap(memregion->mapped); + memregion->mapped = NULL; + } + if (memregion->requested) { + release_mem_region((ulong)(memregion->physaddr), + memregion->nbytes); + memregion->requested = FALSE; + } +} + +HOSTADDRESS +visor_memregion_get_physaddr(struct memregion *memregion) +{ + return memregion->physaddr; +} +EXPORT_SYMBOL_GPL(visor_memregion_get_physaddr); + +ulong +visor_memregion_get_nbytes(struct memregion *memregion) +{ + return memregion->nbytes; +} +EXPORT_SYMBOL_GPL(visor_memregion_get_nbytes); + +void __iomem * +visor_memregion_get_pointer(struct memregion *memregion) +{ + return memregion->mapped; +} +EXPORT_SYMBOL_GPL(visor_memregion_get_pointer); + +int +visor_memregion_resize(struct memregion *memregion, ulong newsize) +{ + if (newsize == memregion->nbytes) + return 0; + if (memregion->overlapped) + /* no error check here - we no longer know the + * parent's range! + */ + memregion->nbytes = newsize; + else { + unmapit(memregion); + memregion->nbytes = newsize; + if (!mapit(memregion)) + return -1; + } + return 0; +} +EXPORT_SYMBOL_GPL(visor_memregion_resize); + +static int +memregion_readwrite(BOOL is_write, + struct memregion *memregion, ulong offset, + void *local, ulong nbytes) +{ + if (offset + nbytes > memregion->nbytes) + return -EIO; + + if (is_write) + memcpy_toio(memregion->mapped + offset, local, nbytes); + else + memcpy_fromio(local, memregion->mapped + offset, nbytes); + + return 0; +} + +int +visor_memregion_read(struct memregion *memregion, ulong offset, void *dest, + ulong nbytes) +{ + return memregion_readwrite(FALSE, memregion, offset, dest, nbytes); +} +EXPORT_SYMBOL_GPL(visor_memregion_read); + +int +visor_memregion_write(struct memregion *memregion, ulong offset, void *src, + ulong nbytes) +{ + return memregion_readwrite(TRUE, memregion, offset, src, nbytes); +} +EXPORT_SYMBOL_GPL(visor_memregion_write); + +void +visor_memregion_destroy(struct memregion *memregion) +{ + if (memregion == NULL) + return; + if (!memregion->overlapped) + unmapit(memregion); + kfree(memregion); +} +EXPORT_SYMBOL_GPL(visor_memregion_destroy); + -- cgit v1.2.3-54-g00ecf