Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / unisys / visorutil / memregion_direct.c
1 /* memregion_direct.c
2  *
3  * Copyright (C) 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 "timskmod.h"
24 #include "memregion.h"
25
26 #define MYDRVNAME "memregion"
27
28 struct memregion {
29         HOSTADDRESS physaddr;
30         ulong nbytes;
31         void __iomem *mapped;
32         BOOL requested;
33         BOOL overlapped;
34 };
35
36 static BOOL mapit(struct memregion *memregion);
37 static void unmapit(struct memregion *memregion);
38
39 struct memregion *
40 visor_memregion_create(HOSTADDRESS physaddr, ulong nbytes)
41 {
42         struct memregion *rc = NULL;
43         struct memregion *memregion;
44
45         memregion = kzalloc(sizeof(*memregion), GFP_KERNEL | __GFP_NORETRY);
46         if (memregion == NULL)
47                 return NULL;
48
49         memregion->physaddr = physaddr;
50         memregion->nbytes = nbytes;
51         memregion->overlapped = FALSE;
52         if (!mapit(memregion)) {
53                 rc = NULL;
54                 goto cleanup;
55         }
56         rc = memregion;
57 cleanup:
58         if (rc == NULL) {
59                 visor_memregion_destroy(memregion);
60                 memregion = NULL;
61         }
62         return rc;
63 }
64 EXPORT_SYMBOL_GPL(visor_memregion_create);
65
66 struct memregion *
67 visor_memregion_create_overlapped(struct memregion *parent, ulong offset,
68                                   ulong nbytes)
69 {
70         struct memregion *memregion = NULL;
71
72         if (parent == NULL)
73                 return NULL;
74
75         if (parent->mapped == NULL)
76                 return NULL;
77
78         if ((offset >= parent->nbytes) ||
79             ((offset + nbytes) >= parent->nbytes))
80                 return NULL;
81
82         memregion = kzalloc(sizeof(*memregion), GFP_KERNEL|__GFP_NORETRY);
83         if (memregion == NULL)
84                 return NULL;
85
86         memregion->physaddr = parent->physaddr + offset;
87         memregion->nbytes = nbytes;
88         memregion->mapped = ((u8 __iomem *)(parent->mapped)) + offset;
89         memregion->requested = FALSE;
90         memregion->overlapped = TRUE;
91         return memregion;
92 }
93 EXPORT_SYMBOL_GPL(visor_memregion_create_overlapped);
94
95 static BOOL
96 mapit(struct memregion *memregion)
97 {
98         ulong physaddr = (ulong)(memregion->physaddr);
99         ulong nbytes = memregion->nbytes;
100
101         memregion->requested = FALSE;
102         if (request_mem_region(physaddr, nbytes, MYDRVNAME))
103                 memregion->requested = TRUE;
104         memregion->mapped = ioremap_cache(physaddr, nbytes);
105         if (!memregion->mapped)
106                 return FALSE;
107         return TRUE;
108 }
109
110 static void
111 unmapit(struct memregion *memregion)
112 {
113         if (memregion->mapped != NULL) {
114                 iounmap(memregion->mapped);
115                 memregion->mapped = NULL;
116         }
117         if (memregion->requested) {
118                 release_mem_region((ulong)(memregion->physaddr),
119                                    memregion->nbytes);
120                 memregion->requested = FALSE;
121         }
122 }
123
124 HOSTADDRESS
125 visor_memregion_get_physaddr(struct memregion *memregion)
126 {
127         return memregion->physaddr;
128 }
129 EXPORT_SYMBOL_GPL(visor_memregion_get_physaddr);
130
131 ulong
132 visor_memregion_get_nbytes(struct memregion *memregion)
133 {
134         return memregion->nbytes;
135 }
136 EXPORT_SYMBOL_GPL(visor_memregion_get_nbytes);
137
138 void __iomem *
139 visor_memregion_get_pointer(struct memregion *memregion)
140 {
141         return memregion->mapped;
142 }
143 EXPORT_SYMBOL_GPL(visor_memregion_get_pointer);
144
145 int
146 visor_memregion_resize(struct memregion *memregion, ulong newsize)
147 {
148         if (newsize == memregion->nbytes)
149                 return 0;
150         if (memregion->overlapped)
151                 /* no error check here - we no longer know the
152                  * parent's range!
153                  */
154                 memregion->nbytes = newsize;
155         else {
156                 unmapit(memregion);
157                 memregion->nbytes = newsize;
158                 if (!mapit(memregion))
159                         return -1;
160         }
161         return 0;
162 }
163 EXPORT_SYMBOL_GPL(visor_memregion_resize);
164
165 static int
166 memregion_readwrite(BOOL is_write,
167                     struct memregion *memregion, ulong offset,
168                     void *local, ulong nbytes)
169 {
170         if (offset + nbytes > memregion->nbytes)
171                 return -EIO;
172
173         if (is_write)
174                 memcpy_toio(memregion->mapped + offset, local, nbytes);
175         else
176                 memcpy_fromio(local, memregion->mapped + offset, nbytes);
177
178         return 0;
179 }
180
181 int
182 visor_memregion_read(struct memregion *memregion, ulong offset, void *dest,
183                      ulong nbytes)
184 {
185         return memregion_readwrite(FALSE, memregion, offset, dest, nbytes);
186 }
187 EXPORT_SYMBOL_GPL(visor_memregion_read);
188
189 int
190 visor_memregion_write(struct memregion *memregion, ulong offset, void *src,
191                       ulong nbytes)
192 {
193         return memregion_readwrite(TRUE, memregion, offset, src, nbytes);
194 }
195 EXPORT_SYMBOL_GPL(visor_memregion_write);
196
197 void
198 visor_memregion_destroy(struct memregion *memregion)
199 {
200         if (memregion == NULL)
201                 return;
202         if (!memregion->overlapped)
203                 unmapit(memregion);
204         kfree(memregion);
205 }
206 EXPORT_SYMBOL_GPL(visor_memregion_destroy);
207