do some code clean up. fix xseg callback to only take portno as argument
[archipelago] / xseg / drivers / kernel / xseg_segdev.c
1 /* xseg_segdev.c
2  *
3  */
4
5 #include <linux/module.h>
6 #include <linux/moduleparam.h>
7 #include <linux/init.h>
8 #include <linux/sched.h>
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11 #include <linux/fs.h>
12 #include <linux/errno.h>
13 #include <linux/timer.h>
14 #include <linux/types.h>
15 #include <linux/vmalloc.h>
16 #include <linux/genhd.h>
17 #include <linux/blkdev.h>
18 #include <linux/bio.h>
19 #include <linux/device.h>
20 #include <linux/completion.h>
21
22 #include <xseg/xseg.h>
23 #include <sys/kernel/segdev.h>
24 #include <sys/util.h>
25
26 MODULE_DESCRIPTION("xseg_segdev");
27 MODULE_AUTHOR("XSEG");
28 MODULE_LICENSE("GPL");
29
30 /* for now, support only one peer */
31 static struct xseg *xsegments[1];
32 static unsigned int nr_xsegments = 1;
33
34 struct segpriv {
35         unsigned int segno;
36 };
37
38 static void *segdev_malloc(uint64_t size)
39 {
40         return kmalloc((size_t)size, GFP_KERNEL);
41 }
42
43 static void *segdev_realloc(void *mem, uint64_t size)
44 {
45         return krealloc(mem, (size_t)size, GFP_KERNEL);
46 }
47
48 static void segdev_mfree(void *ptr)
49 {
50         return kfree(ptr);
51 }
52
53 static long segdev_allocate(const char *name, uint64_t size)
54 {
55         int r;
56         struct segdev *segdev = segdev_get(0);
57
58         r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
59         if (r) {
60                 XSEGLOG("cannot acquire segdev");
61                 goto out;
62         }
63
64         if (segdev->segment) {
65                 XSEGLOG("destroying existing segdev segment");
66                 r = segdev_destroy_segment(segdev);
67                 if (r)
68                         goto out;
69         }
70
71         XSEGLOG("creating segdev segment size %llu", size);
72         r = segdev_create_segment(segdev, size, 1);
73         if (r)
74                 goto out;
75
76         segdev_put(segdev);
77         r = 0;
78 out:
79         return r;
80 }
81
82 static long segdev_deallocate(const char *name)
83 {
84         struct segdev *segdev = segdev_get(0);
85         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
86         if (r)
87                 return r;
88
89         clear_bit(SEGDEV_RESERVED, &segdev->flags);
90         XSEGLOG("destroying segment");
91         r = segdev_destroy_segment(segdev);
92         if (r)
93                 XSEGLOG("   ...failed");
94         segdev_put(segdev);
95         return r;
96 }
97
98 static void *segdev_map(const char *name, uint64_t size, struct xseg *seg)
99 {
100         struct xseg *xseg = NULL;
101         /* map() holds a reference to the segment */
102         struct segdev *dev = segdev_get(0);
103         struct segpriv *priv;
104         int r;
105         r = IS_ERR(dev) ? PTR_ERR(dev) : 0;
106         if (r)
107                 goto out;
108
109         if (!dev->segment)
110                 goto out;
111
112         if (size > dev->segsize)
113                 goto out;
114
115         priv = dev->priv;
116         if (priv->segno >= nr_xsegments)
117                 goto out;
118
119         if (seg)
120                 xsegments[priv->segno] = seg;
121
122         xseg = (void *)dev->segment;
123 out:
124         return xseg;
125 }
126
127 static void segdev_unmap(void *ptr, uint64_t size)
128 {
129         struct segdev *segdev = segdev_get(0);
130         struct segpriv *priv;
131         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
132         if (r)
133                 return;
134
135         priv = segdev->priv;
136         if (priv->segno >= nr_xsegments)
137                 goto out;
138
139         xsegments[priv->segno] = NULL;
140
141 out:
142         /* unmap() releases the reference taken by map() */
143         segdev_put(segdev);
144
145         segdev_put(segdev);
146 }
147
148 static void segdev_callback(struct segdev *dev, xport portno)
149 {
150         struct xseg *xseg;
151         struct segpriv *priv = dev->priv;
152         struct xseg_private *xpriv;
153         struct xseg_port *port;
154         if (priv->segno >= nr_xsegments)
155                 return;
156
157         xseg = xsegments[priv->segno];
158         xpriv = xseg->priv;
159         port = xseg_get_port(xseg, portno);
160         if (!port || !port->waitcue)
161                 return;
162         
163         if (xpriv->wakeup) {
164                 xpriv->wakeup(portno);
165         }
166 }
167
168 static struct xseg_type xseg_segdev = {
169         /* xseg operations */
170         {
171                 .allocate = segdev_allocate,
172                 .deallocate = segdev_deallocate,
173                 .map = segdev_map,
174                 .unmap = segdev_unmap
175         },
176         /* name */
177         "segdev"
178 };
179
180 static int segdev_signal_init(void)
181 {
182         struct segdev *segdev = segdev_get(0);
183         struct segpriv *segpriv;
184         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
185         if (r)
186                 goto out;
187
188         r = -EADDRINUSE;
189         if (xsegments[0]) 
190                 goto out;
191
192         r = -ENOMEM;
193         segpriv = kmalloc(sizeof(struct segpriv), GFP_KERNEL);
194         if (!segpriv)
195                 goto out;
196
197         segpriv->segno = 0;
198         segdev->callback = segdev_callback;
199         segdev->priv = segpriv;
200         r = 0;
201 out:
202         segdev_put(segdev);
203         return r;
204 }
205
206 static void segdev_signal_quit(void)
207 {
208         struct segdev *segdev = segdev_get(0);
209         int r = IS_ERR(segdev) ? PTR_ERR(segdev) : 0;
210         xsegments[0] = NULL;
211         if (!r)
212                 segdev->callback = NULL;
213
214         segdev_put(segdev);
215         return;
216 }
217
218 static int segdev_prepare_wait(struct xseg *xseg, uint32_t portno)
219 {
220         struct xseg_port *port = xseg_get_port(xseg, portno);
221         if (!port)
222                 return -1;
223         /* true/false value */
224         port->waitcue = 1;
225         return 0;
226 }
227
228 static int segdev_cancel_wait(struct xseg *xseg, uint32_t portno)
229 {
230         struct xseg_port *port = xseg_get_port(xseg, portno);
231         if (!port)
232                 return -1;
233         /* true/false value */
234         port->waitcue = 0;
235         return -0;
236 }
237
238 static int segdev_wait_signal(struct xseg *xseg, uint32_t timeout)
239 {
240         return -1;
241 }
242
243 static int segdev_signal(struct xseg *xseg, uint32_t portno)
244 {
245         return -1;
246 }
247
248 static struct xseg_peer xseg_peer_segdev = {
249         /* xseg signal operations */
250         {
251                 .signal_init = segdev_signal_init,
252                 .signal_quit = segdev_signal_quit,
253                 .cancel_wait = segdev_cancel_wait,
254                 .prepare_wait = segdev_prepare_wait,
255                 .wait_signal = segdev_wait_signal,
256                 .signal = segdev_signal,
257                 .malloc = segdev_malloc,
258                 .realloc = segdev_realloc,
259                 .mfree = segdev_mfree
260         },
261         /* name */
262         "segdev"
263 };
264
265
266 /* ************************* */
267 /* ** XSEG Initialization ** */
268 /* ************************* */
269
270 static int segdev_init(void)
271 {
272         int r;
273
274         XSEGLOG("registering xseg types");
275         r = xseg_register_type(&xseg_segdev);
276         if (r)
277                 goto err0;
278
279         r = xseg_register_peer(&xseg_peer_segdev);
280         if (r)
281                 goto err1;
282
283         return 0;
284 err1:
285         xseg_unregister_type(xseg_segdev.name);
286 err0:
287         return r;
288 }
289
290 static int segdev_quit(void)
291 {
292         struct segdev *segdev;
293
294         /* make sure to unmap the segment first */
295         segdev = segdev_get(0);
296         clear_bit(SEGDEV_RESERVED, &segdev->flags);
297         segdev_put(segdev);
298
299         xseg_unregister_peer(xseg_peer_segdev.name);
300         xseg_unregister_type(xseg_segdev.name);
301
302         return 0;
303 }
304
305 /* *************************** */
306 /* ** Module Initialization ** */
307 /* *************************** */
308
309 static int __init xseg_segdev_init(void)
310 {
311         int ret = -ENOSYS;
312
313         ret = segdev_init();
314         if (ret)
315                 goto out;
316
317         XSEGLOG("initialization complete");
318 out:
319         return ret;
320 }
321
322 static void __exit xseg_segdev_exit(void)
323 {
324         segdev_quit();
325 }
326
327 module_init(xseg_segdev_init);
328 module_exit(xseg_segdev_exit);
329