alistair23-linux/drivers/staging/unisys/visorutil/memregion_direct.c
Sudip Mukherjee f9b64692e1 staging: unisys: unneeded NULL check
the NULL check for memregion is not required as it has already been
checked for NULL after kzalloc. so we can reach this part of the code
only if memregion is not NULL.

Signed-off-by: Sudip Mukherjee <sudip@vectorindia.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-11-07 09:22:46 -08:00

222 lines
5.4 KiB
C

/* 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 "uniklog.h"
#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 = kzalloc(sizeof(*memregion),
GFP_KERNEL | __GFP_NORETRY);
if (memregion == NULL) {
ERRDRV("visor_memregion_create allocation failed");
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) {
ERRDRV("%s parent is NULL", __func__);
return NULL;
}
if (parent->mapped == NULL) {
ERRDRV("%s parent is not mapped!", __func__);
return NULL;
}
if ((offset >= parent->nbytes) ||
((offset + nbytes) >= parent->nbytes)) {
ERRDRV("%s range (%lu,%lu) out of parent range",
__func__, offset, nbytes);
return NULL;
}
memregion = kzalloc(sizeof(*memregion), GFP_KERNEL|__GFP_NORETRY);
if (memregion == NULL) {
ERRDRV("%s allocation failed", __func__);
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))
ERRDRV("cannot reserve channel memory @0x%lx for 0x%lx-- no big deal",
physaddr, nbytes);
else
memregion->requested = TRUE;
memregion->mapped = ioremap_cache(physaddr, nbytes);
if (memregion->mapped == NULL) {
ERRDRV("cannot ioremap_cache channel memory @0x%lx for 0x%lx",
physaddr, nbytes);
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) {
ERRDRV("memregion_readwrite offset out of range!!");
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);