add license headers
[archipelago] / xseg / drivers / kernel / xseg_segdev.c
1 /*
2  * Copyright 2012 GRNET S.A. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or
5  * without modification, are permitted provided that the following
6  * conditions are met:
7  *
8  *   1. Redistributions of source code must retain the above
9  *      copyright notice, this list of conditions and the following
10  *      disclaimer.
11  *   2. Redistributions in binary form must reproduce the above
12  *      copyright notice, this list of conditions and the following
13  *      disclaimer in the documentation and/or other materials
14  *      provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and
30  * documentation are those of the authors and should not be
31  * interpreted as representing official policies, either expressed
32  * or implied, of GRNET S.A.
33  */
34
35 /* xseg_segdev.c
36  *
37  */
38
39 #include <linux/module.h>
40 #include <linux/moduleparam.h>
41 #include <linux/init.h>
42 #include <linux/sched.h>
43 #include <linux/kernel.h>
44 #include <linux/slab.h>
45 #include <linux/fs.h>
46 #include <linux/errno.h>
47 #include <linux/timer.h>
48 #include <linux/types.h>
49 #include <linux/vmalloc.h>
50 #include <linux/genhd.h>
51 #include <linux/blkdev.h>
52 #include <linux/bio.h>
53 #include <linux/device.h>
54 #include <linux/completion.h>
55
56 #include <xseg/xseg.h>
57 #include <sys/kernel/segdev.h>
58 #include <sys/util.h>
59 #include <drivers/xseg_segdev.h>
60 #include <peers/kernel/xsegbd.h>
61 MODULE_DESCRIPTION("xseg_segdev");
62 MODULE_AUTHOR("XSEG");
63 MODULE_LICENSE("BSD");
64
65 /* FIXME */
66 static struct xseg *xsegments[65536];
67 static unsigned int nr_xsegments = 1;
68
69 struct segpriv {
70         unsigned int segno;
71 };
72
73 static void *segdev_malloc(uint64_t size)
74 {
75         return kmalloc((size_t)size, GFP_KERNEL);
76 }
77
78 static void *segdev_realloc(void *mem, uint64_t size)
79 {
80         return krealloc(mem, (size_t)size, GFP_KERNEL);
81 }
82
83 static void segdev_mfree(void *ptr)
84 {
85         return kfree(ptr);
86 }
87
88 static long segdev_allocate(const char *name, uint64_t size)
89 {
90         int r;
91         struct segdev *segdev = segdev_get(0);
92
93         r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
94         if (r) {
95                 XSEGLOG("cannot acquire segdev");
96                 goto out;
97         }
98
99         if (segdev->segment) {
100                 XSEGLOG("destroying existing segdev segment");
101                 r = segdev_destroy_segment(segdev);
102                 if (r)
103                         goto out;
104         }
105
106         XSEGLOG("creating segdev segment size %llu", size);
107         r = segdev_create_segment(segdev, size, 1);
108         if (r)
109                 goto out;
110
111         segdev_put(segdev);
112         r = 0;
113 out:
114         return r;
115 }
116
117 static long segdev_deallocate(const char *name)
118 {
119         struct segdev *segdev = segdev_get(0);
120         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
121         if (r)
122                 return r;
123
124         clear_bit(SEGDEV_RESERVED, &segdev->flags);
125         XSEGLOG("destroying segment");
126         r = segdev_destroy_segment(segdev);
127         if (r)
128                 XSEGLOG("   ...failed");
129         segdev_put(segdev);
130         return r;
131 }
132
133 static void *segdev_map(const char *name, uint64_t size, struct xseg *seg)
134 {
135         struct xseg *xseg = NULL;
136         /* map() holds a reference to the segment */
137         struct segdev *dev = segdev_get(0);
138         struct segpriv *priv;
139         int r;
140         r = IS_ERR(dev) ? PTR_ERR(dev) : 0;
141         if (r)
142                 goto out;
143
144         if (!dev->segment)
145                 goto out;
146
147         if (size > dev->segsize)
148                 goto out;
149
150         priv = dev->priv;
151         if (priv->segno >= nr_xsegments)
152                 goto out;
153
154 //      if (seg)
155 //              xsegments[priv->segno] = seg;
156
157         xseg = (void *)dev->segment;
158 out:
159         return xseg;
160 }
161
162 static void segdev_unmap(void *ptr, uint64_t size)
163 {
164         struct segdev *segdev = segdev_get(0);
165         struct segpriv *priv;
166         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
167         if (r)
168                 return;
169
170         priv = segdev->priv;
171         if (priv->segno >= nr_xsegments)
172                 goto out;
173
174 //      xsegments[priv->segno] = NULL;
175
176 out:
177         /* unmap() releases the reference taken by map() */
178         segdev_put(segdev);
179
180         segdev_put(segdev);
181 }
182
183 static void segdev_callback(struct segdev *dev, xport portno)
184 {
185         struct xseg *xseg;
186         struct segpriv *priv = dev->priv;
187         struct xseg_private *xpriv;
188         struct xseg_port *port;
189         struct segdev_signal_desc *ssd;
190
191         xseg = xsegments[portno];
192         if (!xseg)
193                 return;
194         if (priv->segno >= nr_xsegments)
195                 return;
196
197         xpriv = xseg->priv;
198         port = xseg_get_port(xseg, portno);
199         if (!port)
200                 return;
201         ssd = xseg_get_signal_desc(xseg, port);
202         if (!ssd || !ssd->waitcue){
203                 return;
204         }
205
206         if (xpriv->wakeup) {
207                 xpriv->wakeup(portno);
208         }
209         return;
210 }
211
212 static struct xseg_type xseg_segdev = {
213         /* xseg operations */
214         {
215                 .allocate = segdev_allocate,
216                 .deallocate = segdev_deallocate,
217                 .map = segdev_map,
218                 .unmap = segdev_unmap
219         },
220         /* name */
221         "segdev"
222 };
223
224 static int segdev_remote_signal_init(void)
225 {
226         return 0;
227 }
228
229 static void segdev_remote_signal_quit(void)
230 {
231         return;
232 }
233
234 static int segdev_local_signal_init(struct xseg *xseg, xport portno)
235 {
236         //assert xsegments[portno] == NULL;
237         xsegments[portno] = xseg;
238 }
239
240 static void segdev_local_signal_quit(struct xseg *xseg, xport portno)
241 {
242         //assert xsegments[portno] == xseg;
243         xsegments[portno] = NULL;
244         return;
245 }
246
247 static int segdev_prepare_wait(struct xseg *xseg, uint32_t portno)
248 {
249         struct segdev_signal_desc *ssd; 
250         struct xseg_port *port = xseg_get_port(xseg, portno);
251         if (!port)
252                 return -1;
253         ssd = xseg_get_signal_desc(xseg, port);
254         if (!ssd)
255                 return -1;
256         /* true/false value */
257         ssd->waitcue = 1;
258         return 0;
259 }
260
261 static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno)
262 {
263         struct segdev_signal_desc *ssd; 
264         struct xseg_port *port = xseg_get_port(xseg, portno);
265         if (!port)
266                 return -1;
267         ssd = xseg_get_signal_desc(xseg, port);
268         if (!ssd)
269                 return -1;
270         /* true/false value */
271         ssd->waitcue = 0;
272         return -0;
273 }
274
275 static int segdev_wait_signal(struct xseg *xseg, uint32_t timeout)
276 {
277         return -1;
278 }
279
280 static int segdev_signal(struct xseg *xseg, uint32_t portno)
281 {
282         return -1;
283 }
284
285 static int segdev_init_signal_desc(struct xseg *xseg, void *sd)
286 {
287         struct segdev_signal_desc *ssd = sd;
288         if (!ssd)
289                 return -1;
290         ssd->waitcue = 0;
291         return 0;
292 }
293
294 static void segdev_quit_signal_desc(struct xseg *xseg, void *sd)
295 {
296         return;
297 }
298
299 static void *segdev_alloc_data(struct xseg *xseg)
300 {
301         struct xobject_h *sd_h = xseg_get_objh(xseg, MAGIC_SEGDEV_SD,
302                                 sizeof(struct segdev_signal_desc));
303         return sd_h;
304 }
305
306 static void segdev_free_data(struct xseg *xseg, void *data)
307 {
308         if (data)
309                 xseg_put_objh(xseg, (struct xobject_h *)data);
310 }
311
312 static void *segdev_alloc_signal_desc(struct xseg *xseg, void *data)
313 {
314         struct xobject_h *sd_h = (struct xobject_h *) data;
315         if (!sd_h)
316                 return NULL;
317         struct segdev_signal_desc *ssd = xobj_get_obj(sd_h, X_ALLOC);
318         if (!ssd)
319                 return NULL;
320         ssd->waitcue = 0;
321         return ssd;
322 }
323
324 static void segdev_free_signal_desc(struct xseg *xseg, void *data, void *sd)
325 {
326         struct xobject_h *sd_h = (struct xobject_h *) data;
327         if (!sd_h)
328                 return;
329         if (sd)
330                 xobj_put_obj(sd_h, sd);
331         return;
332 }
333
334 static struct xseg_peer xseg_peer_segdev = {
335         /* xseg signal operations */
336         {
337                 .init_signal_desc   = segdev_init_signal_desc,
338                 .quit_signal_desc   = segdev_quit_signal_desc,
339                 .alloc_data         = segdev_alloc_data,
340                 .free_data          = segdev_free_data,
341                 .alloc_signal_desc  = segdev_alloc_signal_desc,
342                 .free_signal_desc   = segdev_free_signal_desc,
343                 .local_signal_init  = segdev_local_signal_init,
344                 .local_signal_quit  = segdev_local_signal_quit,
345                 .remote_signal_init = segdev_remote_signal_init,
346                 .remote_signal_quit = segdev_remote_signal_quit,
347                 .cancel_wait = segdev_cancel_wait,
348                 .prepare_wait = segdev_prepare_wait,
349                 .wait_signal = segdev_wait_signal,
350                 .signal = segdev_signal,
351                 .malloc = segdev_malloc,
352                 .realloc = segdev_realloc,
353                 .mfree = segdev_mfree
354         },
355         /* name */
356         "segdev"
357 };
358
359
360 /* ************************* */
361 /* ** XSEG Initialization ** */
362 /* ************************* */
363
364 static int segdev_init(void)
365 {
366         struct segdev *segdev;
367         struct segpriv *segpriv;
368         int r;
369
370         XSEGLOG("registering xseg types");
371         r = xseg_register_type(&xseg_segdev);
372         if (r)
373                 goto err0;
374
375         r = xseg_register_peer(&xseg_peer_segdev);
376         if (r)
377                 goto err1;
378         
379         segdev = segdev_get(0);
380         r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
381         if (r)
382                 goto err2;
383
384         r = -ENOMEM;
385         segpriv = kmalloc(sizeof(struct segpriv), GFP_KERNEL);
386         if (!segpriv)
387                 goto err3;
388
389         segpriv->segno = 0;
390         segdev->callback = segdev_callback;
391         segdev->priv = segpriv;
392
393         return 0;
394
395 err3:
396         segdev_put(segdev);
397 err2:
398         xseg_unregister_peer(xseg_peer_segdev.name);
399 err1:
400         xseg_unregister_type(xseg_segdev.name);
401 err0:
402         return r;
403 }
404
405 static int segdev_quit(void)
406 {
407         struct segdev *segdev = segdev_get(0);
408         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
409         if (!r){
410                 /* make sure to unmap the segment first */
411                 clear_bit(SEGDEV_RESERVED, &segdev->flags);
412                 segdev->callback = NULL;
413                 //FIXME what aboud segdev->priv?
414                 segdev_put(segdev);
415         }
416         xseg_unregister_peer(xseg_peer_segdev.name);
417         xseg_unregister_type(xseg_segdev.name);
418
419         return 0;
420 }
421
422 /* *************************** */
423 /* ** Module Initialization ** */
424 /* *************************** */
425
426 static int __init xseg_segdev_init(void)
427 {
428         int ret = -ENOSYS;
429
430         ret = segdev_init();
431         if (ret)
432                 goto out;
433
434         XSEGLOG("initialization complete");
435 out:
436         return ret;
437 }
438
439 static void __exit xseg_segdev_exit(void)
440 {
441         segdev_quit();
442 }
443
444 module_init(xseg_segdev_init);
445 module_exit(xseg_segdev_exit);
446