blob: a92e81d25f078965ed7855705e0a2b4a7ea460d0 [file] [log] [blame]
Stefano Stabellini72e59c32017-07-05 13:08:39 -07001/*
2 * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <linux/kthread.h>
16#include <linux/list.h>
17#include <linux/radix-tree.h>
18#include <linux/module.h>
19#include <linux/semaphore.h>
20#include <linux/wait.h>
21
22#include <xen/events.h>
23#include <xen/grant_table.h>
24#include <xen/xen.h>
25#include <xen/xenbus.h>
26#include <xen/interface/io/pvcalls.h>
27
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -070028#define PVCALLS_VERSIONS "1"
29#define MAX_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
30
Stefano Stabellini9be07332017-07-05 13:08:48 -070031struct pvcalls_back_global {
32 struct list_head frontends;
33 struct semaphore frontends_lock;
34} pvcalls_back_global;
35
Stefano Stabellinid0e4d562017-07-06 10:59:29 -070036/*
37 * Per-frontend data structure. It contains pointers to the command
38 * ring, its event channel, a list of active sockets and a tree of
39 * passive sockets.
40 */
41struct pvcalls_fedata {
42 struct list_head list;
43 struct xenbus_device *dev;
44 struct xen_pvcalls_sring *sring;
45 struct xen_pvcalls_back_ring ring;
46 int irq;
47 struct list_head socket_mappings;
48 struct radix_tree_root socketpass_mappings;
49 struct semaphore socket_lock;
50};
51
Stefano Stabellinib1efa692017-07-06 11:00:00 -070052static int pvcalls_back_socket(struct xenbus_device *dev,
53 struct xen_pvcalls_request *req)
54{
55 return 0;
56}
57
58static int pvcalls_back_connect(struct xenbus_device *dev,
59 struct xen_pvcalls_request *req)
60{
61 return 0;
62}
63
64static int pvcalls_back_release(struct xenbus_device *dev,
65 struct xen_pvcalls_request *req)
66{
67 return 0;
68}
69
70static int pvcalls_back_bind(struct xenbus_device *dev,
71 struct xen_pvcalls_request *req)
72{
73 return 0;
74}
75
76static int pvcalls_back_listen(struct xenbus_device *dev,
77 struct xen_pvcalls_request *req)
78{
79 return 0;
80}
81
82static int pvcalls_back_accept(struct xenbus_device *dev,
83 struct xen_pvcalls_request *req)
84{
85 return 0;
86}
87
88static int pvcalls_back_poll(struct xenbus_device *dev,
89 struct xen_pvcalls_request *req)
90{
91 return 0;
92}
93
94static int pvcalls_back_handle_cmd(struct xenbus_device *dev,
95 struct xen_pvcalls_request *req)
96{
97 int ret = 0;
98
99 switch (req->cmd) {
100 case PVCALLS_SOCKET:
101 ret = pvcalls_back_socket(dev, req);
102 break;
103 case PVCALLS_CONNECT:
104 ret = pvcalls_back_connect(dev, req);
105 break;
106 case PVCALLS_RELEASE:
107 ret = pvcalls_back_release(dev, req);
108 break;
109 case PVCALLS_BIND:
110 ret = pvcalls_back_bind(dev, req);
111 break;
112 case PVCALLS_LISTEN:
113 ret = pvcalls_back_listen(dev, req);
114 break;
115 case PVCALLS_ACCEPT:
116 ret = pvcalls_back_accept(dev, req);
117 break;
118 case PVCALLS_POLL:
119 ret = pvcalls_back_poll(dev, req);
120 break;
121 default:
122 {
123 struct pvcalls_fedata *fedata;
124 struct xen_pvcalls_response *rsp;
125
126 fedata = dev_get_drvdata(&dev->dev);
127 rsp = RING_GET_RESPONSE(
128 &fedata->ring, fedata->ring.rsp_prod_pvt++);
129 rsp->req_id = req->req_id;
130 rsp->cmd = req->cmd;
131 rsp->ret = -ENOTSUPP;
132 break;
133 }
134 }
135 return ret;
136}
137
138static void pvcalls_back_work(struct pvcalls_fedata *fedata)
139{
140 int notify, notify_all = 0, more = 1;
141 struct xen_pvcalls_request req;
142 struct xenbus_device *dev = fedata->dev;
143
144 while (more) {
145 while (RING_HAS_UNCONSUMED_REQUESTS(&fedata->ring)) {
146 RING_COPY_REQUEST(&fedata->ring,
147 fedata->ring.req_cons++,
148 &req);
149
150 if (!pvcalls_back_handle_cmd(dev, &req)) {
151 RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(
152 &fedata->ring, notify);
153 notify_all += notify;
154 }
155 }
156
157 if (notify_all) {
158 notify_remote_via_irq(fedata->irq);
159 notify_all = 0;
160 }
161
162 RING_FINAL_CHECK_FOR_REQUESTS(&fedata->ring, more);
163 }
164}
165
Stefano Stabellinid0e4d562017-07-06 10:59:29 -0700166static irqreturn_t pvcalls_back_event(int irq, void *dev_id)
167{
Stefano Stabellinib1efa692017-07-06 11:00:00 -0700168 struct xenbus_device *dev = dev_id;
169 struct pvcalls_fedata *fedata = NULL;
170
171 if (dev == NULL)
172 return IRQ_HANDLED;
173
174 fedata = dev_get_drvdata(&dev->dev);
175 if (fedata == NULL)
176 return IRQ_HANDLED;
177
178 pvcalls_back_work(fedata);
Stefano Stabellinid0e4d562017-07-06 10:59:29 -0700179 return IRQ_HANDLED;
180}
181
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700182static int backend_connect(struct xenbus_device *dev)
183{
Stefano Stabellinid0e4d562017-07-06 10:59:29 -0700184 int err, evtchn;
185 grant_ref_t ring_ref;
186 struct pvcalls_fedata *fedata = NULL;
187
188 fedata = kzalloc(sizeof(struct pvcalls_fedata), GFP_KERNEL);
189 if (!fedata)
190 return -ENOMEM;
191
192 fedata->irq = -1;
193 err = xenbus_scanf(XBT_NIL, dev->otherend, "port", "%u",
194 &evtchn);
195 if (err != 1) {
196 err = -EINVAL;
197 xenbus_dev_fatal(dev, err, "reading %s/event-channel",
198 dev->otherend);
199 goto error;
200 }
201
202 err = xenbus_scanf(XBT_NIL, dev->otherend, "ring-ref", "%u", &ring_ref);
203 if (err != 1) {
204 err = -EINVAL;
205 xenbus_dev_fatal(dev, err, "reading %s/ring-ref",
206 dev->otherend);
207 goto error;
208 }
209
210 err = bind_interdomain_evtchn_to_irq(dev->otherend_id, evtchn);
211 if (err < 0)
212 goto error;
213 fedata->irq = err;
214
215 err = request_threaded_irq(fedata->irq, NULL, pvcalls_back_event,
216 IRQF_ONESHOT, "pvcalls-back", dev);
217 if (err < 0)
218 goto error;
219
220 err = xenbus_map_ring_valloc(dev, &ring_ref, 1,
221 (void **)&fedata->sring);
222 if (err < 0)
223 goto error;
224
225 BACK_RING_INIT(&fedata->ring, fedata->sring, XEN_PAGE_SIZE * 1);
226 fedata->dev = dev;
227
228 INIT_LIST_HEAD(&fedata->socket_mappings);
229 INIT_RADIX_TREE(&fedata->socketpass_mappings, GFP_KERNEL);
230 sema_init(&fedata->socket_lock, 1);
231 dev_set_drvdata(&dev->dev, fedata);
232
233 down(&pvcalls_back_global.frontends_lock);
234 list_add_tail(&fedata->list, &pvcalls_back_global.frontends);
235 up(&pvcalls_back_global.frontends_lock);
236
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700237 return 0;
Stefano Stabellinid0e4d562017-07-06 10:59:29 -0700238
239 error:
240 if (fedata->irq >= 0)
241 unbind_from_irqhandler(fedata->irq, dev);
242 if (fedata->sring != NULL)
243 xenbus_unmap_ring_vfree(dev, fedata->sring);
244 kfree(fedata);
245 return err;
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700246}
247
248static int backend_disconnect(struct xenbus_device *dev)
249{
250 return 0;
251}
252
Stefano Stabellini72e59c32017-07-05 13:08:39 -0700253static int pvcalls_back_probe(struct xenbus_device *dev,
254 const struct xenbus_device_id *id)
255{
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700256 int err, abort;
257 struct xenbus_transaction xbt;
258
259again:
260 abort = 1;
261
262 err = xenbus_transaction_start(&xbt);
263 if (err) {
264 pr_warn("%s cannot create xenstore transaction\n", __func__);
265 return err;
266 }
267
268 err = xenbus_printf(xbt, dev->nodename, "versions", "%s",
269 PVCALLS_VERSIONS);
270 if (err) {
271 pr_warn("%s write out 'versions' failed\n", __func__);
272 goto abort;
273 }
274
275 err = xenbus_printf(xbt, dev->nodename, "max-page-order", "%u",
276 MAX_RING_ORDER);
277 if (err) {
278 pr_warn("%s write out 'max-page-order' failed\n", __func__);
279 goto abort;
280 }
281
282 err = xenbus_printf(xbt, dev->nodename, "function-calls",
283 XENBUS_FUNCTIONS_CALLS);
284 if (err) {
285 pr_warn("%s write out 'function-calls' failed\n", __func__);
286 goto abort;
287 }
288
289 abort = 0;
290abort:
291 err = xenbus_transaction_end(xbt, abort);
292 if (err) {
293 if (err == -EAGAIN && !abort)
294 goto again;
295 pr_warn("%s cannot complete xenstore transaction\n", __func__);
296 return err;
297 }
298
299 if (abort)
300 return -EFAULT;
301
302 xenbus_switch_state(dev, XenbusStateInitWait);
303
Stefano Stabellini72e59c32017-07-05 13:08:39 -0700304 return 0;
305}
306
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700307static void set_backend_state(struct xenbus_device *dev,
308 enum xenbus_state state)
309{
310 while (dev->state != state) {
311 switch (dev->state) {
312 case XenbusStateClosed:
313 switch (state) {
314 case XenbusStateInitWait:
315 case XenbusStateConnected:
316 xenbus_switch_state(dev, XenbusStateInitWait);
317 break;
318 case XenbusStateClosing:
319 xenbus_switch_state(dev, XenbusStateClosing);
320 break;
321 default:
322 __WARN();
323 }
324 break;
325 case XenbusStateInitWait:
326 case XenbusStateInitialised:
327 switch (state) {
328 case XenbusStateConnected:
329 backend_connect(dev);
330 xenbus_switch_state(dev, XenbusStateConnected);
331 break;
332 case XenbusStateClosing:
333 case XenbusStateClosed:
334 xenbus_switch_state(dev, XenbusStateClosing);
335 break;
336 default:
337 __WARN();
338 }
339 break;
340 case XenbusStateConnected:
341 switch (state) {
342 case XenbusStateInitWait:
343 case XenbusStateClosing:
344 case XenbusStateClosed:
345 down(&pvcalls_back_global.frontends_lock);
346 backend_disconnect(dev);
347 up(&pvcalls_back_global.frontends_lock);
348 xenbus_switch_state(dev, XenbusStateClosing);
349 break;
350 default:
351 __WARN();
352 }
353 break;
354 case XenbusStateClosing:
355 switch (state) {
356 case XenbusStateInitWait:
357 case XenbusStateConnected:
358 case XenbusStateClosed:
359 xenbus_switch_state(dev, XenbusStateClosed);
360 break;
361 default:
362 __WARN();
363 }
364 break;
365 default:
366 __WARN();
367 }
368 }
369}
370
Stefano Stabellini72e59c32017-07-05 13:08:39 -0700371static void pvcalls_back_changed(struct xenbus_device *dev,
372 enum xenbus_state frontend_state)
373{
Stefano Stabellini0a9c75c2017-07-06 10:59:17 -0700374 switch (frontend_state) {
375 case XenbusStateInitialising:
376 set_backend_state(dev, XenbusStateInitWait);
377 break;
378
379 case XenbusStateInitialised:
380 case XenbusStateConnected:
381 set_backend_state(dev, XenbusStateConnected);
382 break;
383
384 case XenbusStateClosing:
385 set_backend_state(dev, XenbusStateClosing);
386 break;
387
388 case XenbusStateClosed:
389 set_backend_state(dev, XenbusStateClosed);
390 if (xenbus_dev_is_online(dev))
391 break;
392 device_unregister(&dev->dev);
393 break;
394 case XenbusStateUnknown:
395 set_backend_state(dev, XenbusStateClosed);
396 device_unregister(&dev->dev);
397 break;
398
399 default:
400 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
401 frontend_state);
402 break;
403 }
Stefano Stabellini72e59c32017-07-05 13:08:39 -0700404}
405
406static int pvcalls_back_remove(struct xenbus_device *dev)
407{
408 return 0;
409}
410
411static int pvcalls_back_uevent(struct xenbus_device *xdev,
412 struct kobj_uevent_env *env)
413{
414 return 0;
415}
416
417static const struct xenbus_device_id pvcalls_back_ids[] = {
418 { "pvcalls" },
419 { "" }
420};
421
422static struct xenbus_driver pvcalls_back_driver = {
423 .ids = pvcalls_back_ids,
424 .probe = pvcalls_back_probe,
425 .remove = pvcalls_back_remove,
426 .uevent = pvcalls_back_uevent,
427 .otherend_changed = pvcalls_back_changed,
428};
Stefano Stabellini9be07332017-07-05 13:08:48 -0700429
430static int __init pvcalls_back_init(void)
431{
432 int ret;
433
434 if (!xen_domain())
435 return -ENODEV;
436
437 ret = xenbus_register_backend(&pvcalls_back_driver);
438 if (ret < 0)
439 return ret;
440
441 sema_init(&pvcalls_back_global.frontends_lock, 1);
442 INIT_LIST_HEAD(&pvcalls_back_global.frontends);
443 return 0;
444}
445module_init(pvcalls_back_init);