memregion_direct.c revision a3acc83a4a2b8e1a6f8f3c5bdcfa3bb5f5f9e338
1/* memregion_direct.c 2 * 3 * Copyright � 2010 - 2013 UNISYS CORPORATION 4 * All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or (at 9 * your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 14 * NON INFRINGEMENT. See the GNU General Public License for more 15 * details. 16 */ 17 18/* 19 * This is an implementation of memory regions that can be used to read/write 20 * channel memory (in main memory of the host system) from code running in 21 * a virtual partition. 22 */ 23#include "uniklog.h" 24#include "timskmod.h" 25#include "memregion.h" 26 27#define MYDRVNAME "memregion" 28 29struct MEMREGION_Tag { 30 HOSTADDRESS physaddr; 31 ulong nbytes; 32 void *mapped; 33 BOOL requested; 34 BOOL overlapped; 35}; 36 37static BOOL mapit(MEMREGION *memregion); 38static void unmapit(MEMREGION *memregion); 39 40MEMREGION * 41visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes) 42{ 43 MEMREGION *rc = NULL; 44 MEMREGION *memregion = kzalloc(sizeof(MEMREGION), 45 GFP_KERNEL | __GFP_NORETRY); 46 if (memregion == NULL) { 47 ERRDRV("visor_memregion_create allocation failed"); 48 return NULL; 49 } 50 memregion->physaddr = physaddr; 51 memregion->nbytes = nbytes; 52 memregion->overlapped = FALSE; 53 if (!mapit(memregion)) 54 RETPTR(NULL); 55 RETPTR(memregion); 56 57Away: 58 if (rc == NULL) { 59 if (memregion != NULL) { 60 visor_memregion_destroy(memregion); 61 memregion = NULL; 62 } 63 } 64 return rc; 65} 66EXPORT_SYMBOL_GPL(visor_memregion_create); 67 68MEMREGION * 69visor_memregion_create_overlapped(MEMREGION *parent, ulong offset, ulong nbytes) 70{ 71 MEMREGION *memregion = NULL; 72 73 if (parent == NULL) { 74 ERRDRV("%s parent is NULL", __func__); 75 return NULL; 76 } 77 if (parent->mapped == NULL) { 78 ERRDRV("%s parent is not mapped!", __func__); 79 return NULL; 80 } 81 if ((offset >= parent->nbytes) || 82 ((offset + nbytes) >= parent->nbytes)) { 83 ERRDRV("%s range (%lu,%lu) out of parent range", 84 __func__, offset, nbytes); 85 return NULL; 86 } 87 memregion = kzalloc(sizeof(MEMREGION), GFP_KERNEL|__GFP_NORETRY); 88 if (memregion == NULL) { 89 ERRDRV("%s allocation failed", __func__); 90 return NULL; 91 } 92 93 memregion->physaddr = parent->physaddr + offset; 94 memregion->nbytes = nbytes; 95 memregion->mapped = ((u8 *) (parent->mapped)) + offset; 96 memregion->requested = FALSE; 97 memregion->overlapped = TRUE; 98 return memregion; 99} 100EXPORT_SYMBOL_GPL(visor_memregion_create_overlapped); 101 102 103static BOOL 104mapit(MEMREGION *memregion) 105{ 106 ulong physaddr = (ulong) (memregion->physaddr); 107 ulong nbytes = memregion->nbytes; 108 109 memregion->requested = FALSE; 110 if (!request_mem_region(physaddr, nbytes, MYDRVNAME)) 111 ERRDRV("cannot reserve channel memory @0x%lx for 0x%lx-- no big deal", physaddr, nbytes); 112 else 113 memregion->requested = TRUE; 114 memregion->mapped = ioremap_cache(physaddr, nbytes); 115 if (memregion->mapped == NULL) { 116 ERRDRV("cannot ioremap_cache channel memory @0x%lx for 0x%lx", 117 physaddr, nbytes); 118 return FALSE; 119 } 120 return TRUE; 121} 122 123static void 124unmapit(MEMREGION *memregion) 125{ 126 if (memregion->mapped != NULL) { 127 iounmap(memregion->mapped); 128 memregion->mapped = NULL; 129 } 130 if (memregion->requested) { 131 release_mem_region((ulong) (memregion->physaddr), 132 memregion->nbytes); 133 memregion->requested = FALSE; 134 } 135} 136 137HOSTADDRESS 138visor_memregion_get_physaddr(MEMREGION *memregion) 139{ 140 return memregion->physaddr; 141} 142EXPORT_SYMBOL_GPL(visor_memregion_get_physaddr); 143 144ulong 145visor_memregion_get_nbytes(MEMREGION *memregion) 146{ 147 return memregion->nbytes; 148} 149EXPORT_SYMBOL_GPL(visor_memregion_get_nbytes); 150 151void * 152visor_memregion_get_pointer(MEMREGION *memregion) 153{ 154 return memregion->mapped; 155} 156EXPORT_SYMBOL_GPL(visor_memregion_get_pointer); 157 158int 159visor_memregion_resize(MEMREGION *memregion, ulong newsize) 160{ 161 if (newsize == memregion->nbytes) 162 return 0; 163 if (memregion->overlapped) 164 /* no error check here - we no longer know the 165 * parent's range! 166 */ 167 memregion->nbytes = newsize; 168 else { 169 unmapit(memregion); 170 memregion->nbytes = newsize; 171 if (!mapit(memregion)) 172 return -1; 173 } 174 return 0; 175} 176EXPORT_SYMBOL_GPL(visor_memregion_resize); 177 178 179static int 180memregion_readwrite(BOOL is_write, 181 MEMREGION *memregion, ulong offset, 182 void *local, ulong nbytes) 183{ 184 if (offset + nbytes > memregion->nbytes) { 185 ERRDRV("memregion_readwrite offset out of range!!"); 186 return -EFAULT; 187 } 188 if (is_write) 189 memcpy_toio(memregion->mapped + offset, local, nbytes); 190 else 191 memcpy_fromio(local, memregion->mapped + offset, nbytes); 192 193 return 0; 194} 195 196int 197visor_memregion_read(MEMREGION *memregion, ulong offset, void *dest, 198 ulong nbytes) 199{ 200 return memregion_readwrite(FALSE, memregion, offset, dest, nbytes); 201} 202EXPORT_SYMBOL_GPL(visor_memregion_read); 203 204int 205visor_memregion_write(MEMREGION *memregion, ulong offset, void *src, 206 ulong nbytes) 207{ 208 return memregion_readwrite(TRUE, memregion, offset, src, nbytes); 209} 210EXPORT_SYMBOL_GPL(visor_memregion_write); 211 212void 213visor_memregion_destroy(MEMREGION *memregion) 214{ 215 if (memregion == NULL) 216 return; 217 if (!memregion->overlapped) 218 unmapit(memregion); 219 kfree(memregion); 220} 221EXPORT_SYMBOL_GPL(visor_memregion_destroy); 222 223