1416efba0SStefano Stabellini /* 2416efba0SStefano Stabellini * (c) 2017 Stefano Stabellini <stefano@aporeto.com> 3416efba0SStefano Stabellini * 4416efba0SStefano Stabellini * This program is free software; you can redistribute it and/or modify 5416efba0SStefano Stabellini * it under the terms of the GNU General Public License as published by 6416efba0SStefano Stabellini * the Free Software Foundation; either version 2 of the License, or 7416efba0SStefano Stabellini * (at your option) any later version. 8416efba0SStefano Stabellini * 9416efba0SStefano Stabellini * This program is distributed in the hope that it will be useful, 10416efba0SStefano Stabellini * but WITHOUT ANY WARRANTY; without even the implied warranty of 11416efba0SStefano Stabellini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12416efba0SStefano Stabellini * GNU General Public License for more details. 13416efba0SStefano Stabellini */ 14416efba0SStefano Stabellini 15416efba0SStefano Stabellini #include <linux/module.h> 16*2195046bSStefano Stabellini #include <linux/net.h> 17*2195046bSStefano Stabellini #include <linux/socket.h> 18*2195046bSStefano Stabellini 19*2195046bSStefano Stabellini #include <net/sock.h> 20416efba0SStefano Stabellini 21416efba0SStefano Stabellini #include <xen/events.h> 22416efba0SStefano Stabellini #include <xen/grant_table.h> 23416efba0SStefano Stabellini #include <xen/xen.h> 24416efba0SStefano Stabellini #include <xen/xenbus.h> 25416efba0SStefano Stabellini #include <xen/interface/io/pvcalls.h> 26416efba0SStefano Stabellini 27*2195046bSStefano Stabellini #include "pvcalls-front.h" 28*2195046bSStefano Stabellini 29aa7ba376SStefano Stabellini #define PVCALLS_INVALID_ID UINT_MAX 30aa7ba376SStefano Stabellini #define PVCALLS_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER 31aa7ba376SStefano Stabellini #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE) 32aa7ba376SStefano Stabellini 33aa7ba376SStefano Stabellini struct pvcalls_bedata { 34aa7ba376SStefano Stabellini struct xen_pvcalls_front_ring ring; 35aa7ba376SStefano Stabellini grant_ref_t ref; 36aa7ba376SStefano Stabellini int irq; 37aa7ba376SStefano Stabellini 38aa7ba376SStefano Stabellini struct list_head socket_mappings; 39aa7ba376SStefano Stabellini spinlock_t socket_lock; 40aa7ba376SStefano Stabellini 41aa7ba376SStefano Stabellini wait_queue_head_t inflight_req; 42aa7ba376SStefano Stabellini struct xen_pvcalls_response rsp[PVCALLS_NR_RSP_PER_RING]; 43aa7ba376SStefano Stabellini }; 44aa7ba376SStefano Stabellini /* Only one front/back connection supported. */ 45aa7ba376SStefano Stabellini static struct xenbus_device *pvcalls_front_dev; 46aa7ba376SStefano Stabellini static atomic_t pvcalls_refcount; 47aa7ba376SStefano Stabellini 48aa7ba376SStefano Stabellini /* first increment refcount, then proceed */ 49aa7ba376SStefano Stabellini #define pvcalls_enter() { \ 50aa7ba376SStefano Stabellini atomic_inc(&pvcalls_refcount); \ 51aa7ba376SStefano Stabellini } 52aa7ba376SStefano Stabellini 53aa7ba376SStefano Stabellini /* first complete other operations, then decrement refcount */ 54aa7ba376SStefano Stabellini #define pvcalls_exit() { \ 55aa7ba376SStefano Stabellini atomic_dec(&pvcalls_refcount); \ 56aa7ba376SStefano Stabellini } 57aa7ba376SStefano Stabellini 58aa7ba376SStefano Stabellini struct sock_mapping { 59aa7ba376SStefano Stabellini bool active_socket; 60aa7ba376SStefano Stabellini struct list_head list; 61aa7ba376SStefano Stabellini struct socket *sock; 62aa7ba376SStefano Stabellini }; 63aa7ba376SStefano Stabellini 64*2195046bSStefano Stabellini static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) 65*2195046bSStefano Stabellini { 66*2195046bSStefano Stabellini *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1); 67*2195046bSStefano Stabellini if (RING_FULL(&bedata->ring) || 68*2195046bSStefano Stabellini bedata->rsp[*req_id].req_id != PVCALLS_INVALID_ID) 69*2195046bSStefano Stabellini return -EAGAIN; 70*2195046bSStefano Stabellini return 0; 71*2195046bSStefano Stabellini } 72*2195046bSStefano Stabellini 73aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) 74aa7ba376SStefano Stabellini { 75*2195046bSStefano Stabellini struct xenbus_device *dev = dev_id; 76*2195046bSStefano Stabellini struct pvcalls_bedata *bedata; 77*2195046bSStefano Stabellini struct xen_pvcalls_response *rsp; 78*2195046bSStefano Stabellini uint8_t *src, *dst; 79*2195046bSStefano Stabellini int req_id = 0, more = 0, done = 0; 80*2195046bSStefano Stabellini 81*2195046bSStefano Stabellini if (dev == NULL) 82*2195046bSStefano Stabellini return IRQ_HANDLED; 83*2195046bSStefano Stabellini 84*2195046bSStefano Stabellini pvcalls_enter(); 85*2195046bSStefano Stabellini bedata = dev_get_drvdata(&dev->dev); 86*2195046bSStefano Stabellini if (bedata == NULL) { 87*2195046bSStefano Stabellini pvcalls_exit(); 88*2195046bSStefano Stabellini return IRQ_HANDLED; 89*2195046bSStefano Stabellini } 90*2195046bSStefano Stabellini 91*2195046bSStefano Stabellini again: 92*2195046bSStefano Stabellini while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) { 93*2195046bSStefano Stabellini rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons); 94*2195046bSStefano Stabellini 95*2195046bSStefano Stabellini req_id = rsp->req_id; 96*2195046bSStefano Stabellini dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id); 97*2195046bSStefano Stabellini src = (uint8_t *)rsp + sizeof(rsp->req_id); 98*2195046bSStefano Stabellini memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id)); 99*2195046bSStefano Stabellini /* 100*2195046bSStefano Stabellini * First copy the rest of the data, then req_id. It is 101*2195046bSStefano Stabellini * paired with the barrier when accessing bedata->rsp. 102*2195046bSStefano Stabellini */ 103*2195046bSStefano Stabellini smp_wmb(); 104*2195046bSStefano Stabellini bedata->rsp[req_id].req_id = rsp->req_id; 105*2195046bSStefano Stabellini 106*2195046bSStefano Stabellini done = 1; 107*2195046bSStefano Stabellini bedata->ring.rsp_cons++; 108*2195046bSStefano Stabellini } 109*2195046bSStefano Stabellini 110*2195046bSStefano Stabellini RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more); 111*2195046bSStefano Stabellini if (more) 112*2195046bSStefano Stabellini goto again; 113*2195046bSStefano Stabellini if (done) 114*2195046bSStefano Stabellini wake_up(&bedata->inflight_req); 115*2195046bSStefano Stabellini pvcalls_exit(); 116aa7ba376SStefano Stabellini return IRQ_HANDLED; 117aa7ba376SStefano Stabellini } 118aa7ba376SStefano Stabellini 119aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, 120aa7ba376SStefano Stabellini struct sock_mapping *map) 121aa7ba376SStefano Stabellini { 122aa7ba376SStefano Stabellini } 123aa7ba376SStefano Stabellini 124*2195046bSStefano Stabellini int pvcalls_front_socket(struct socket *sock) 125*2195046bSStefano Stabellini { 126*2195046bSStefano Stabellini struct pvcalls_bedata *bedata; 127*2195046bSStefano Stabellini struct sock_mapping *map = NULL; 128*2195046bSStefano Stabellini struct xen_pvcalls_request *req; 129*2195046bSStefano Stabellini int notify, req_id, ret; 130*2195046bSStefano Stabellini 131*2195046bSStefano Stabellini /* 132*2195046bSStefano Stabellini * PVCalls only supports domain AF_INET, 133*2195046bSStefano Stabellini * type SOCK_STREAM and protocol 0 sockets for now. 134*2195046bSStefano Stabellini * 135*2195046bSStefano Stabellini * Check socket type here, AF_INET and protocol checks are done 136*2195046bSStefano Stabellini * by the caller. 137*2195046bSStefano Stabellini */ 138*2195046bSStefano Stabellini if (sock->type != SOCK_STREAM) 139*2195046bSStefano Stabellini return -EOPNOTSUPP; 140*2195046bSStefano Stabellini 141*2195046bSStefano Stabellini pvcalls_enter(); 142*2195046bSStefano Stabellini if (!pvcalls_front_dev) { 143*2195046bSStefano Stabellini pvcalls_exit(); 144*2195046bSStefano Stabellini return -EACCES; 145*2195046bSStefano Stabellini } 146*2195046bSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 147*2195046bSStefano Stabellini 148*2195046bSStefano Stabellini map = kzalloc(sizeof(*map), GFP_KERNEL); 149*2195046bSStefano Stabellini if (map == NULL) { 150*2195046bSStefano Stabellini pvcalls_exit(); 151*2195046bSStefano Stabellini return -ENOMEM; 152*2195046bSStefano Stabellini } 153*2195046bSStefano Stabellini 154*2195046bSStefano Stabellini spin_lock(&bedata->socket_lock); 155*2195046bSStefano Stabellini 156*2195046bSStefano Stabellini ret = get_request(bedata, &req_id); 157*2195046bSStefano Stabellini if (ret < 0) { 158*2195046bSStefano Stabellini kfree(map); 159*2195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 160*2195046bSStefano Stabellini pvcalls_exit(); 161*2195046bSStefano Stabellini return ret; 162*2195046bSStefano Stabellini } 163*2195046bSStefano Stabellini 164*2195046bSStefano Stabellini /* 165*2195046bSStefano Stabellini * sock->sk->sk_send_head is not used for ip sockets: reuse the 166*2195046bSStefano Stabellini * field to store a pointer to the struct sock_mapping 167*2195046bSStefano Stabellini * corresponding to the socket. This way, we can easily get the 168*2195046bSStefano Stabellini * struct sock_mapping from the struct socket. 169*2195046bSStefano Stabellini */ 170*2195046bSStefano Stabellini sock->sk->sk_send_head = (void *)map; 171*2195046bSStefano Stabellini list_add_tail(&map->list, &bedata->socket_mappings); 172*2195046bSStefano Stabellini 173*2195046bSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 174*2195046bSStefano Stabellini req->req_id = req_id; 175*2195046bSStefano Stabellini req->cmd = PVCALLS_SOCKET; 176*2195046bSStefano Stabellini req->u.socket.id = (uintptr_t) map; 177*2195046bSStefano Stabellini req->u.socket.domain = AF_INET; 178*2195046bSStefano Stabellini req->u.socket.type = SOCK_STREAM; 179*2195046bSStefano Stabellini req->u.socket.protocol = IPPROTO_IP; 180*2195046bSStefano Stabellini 181*2195046bSStefano Stabellini bedata->ring.req_prod_pvt++; 182*2195046bSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 183*2195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 184*2195046bSStefano Stabellini if (notify) 185*2195046bSStefano Stabellini notify_remote_via_irq(bedata->irq); 186*2195046bSStefano Stabellini 187*2195046bSStefano Stabellini wait_event(bedata->inflight_req, 188*2195046bSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 189*2195046bSStefano Stabellini 190*2195046bSStefano Stabellini /* read req_id, then the content */ 191*2195046bSStefano Stabellini smp_rmb(); 192*2195046bSStefano Stabellini ret = bedata->rsp[req_id].ret; 193*2195046bSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 194*2195046bSStefano Stabellini 195*2195046bSStefano Stabellini pvcalls_exit(); 196*2195046bSStefano Stabellini return ret; 197*2195046bSStefano Stabellini } 198*2195046bSStefano Stabellini 199416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = { 200416efba0SStefano Stabellini { "pvcalls" }, 201416efba0SStefano Stabellini { "" } 202416efba0SStefano Stabellini }; 203416efba0SStefano Stabellini 204416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev) 205416efba0SStefano Stabellini { 206aa7ba376SStefano Stabellini struct pvcalls_bedata *bedata; 207aa7ba376SStefano Stabellini struct sock_mapping *map = NULL, *n; 208aa7ba376SStefano Stabellini 209aa7ba376SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 210aa7ba376SStefano Stabellini dev_set_drvdata(&dev->dev, NULL); 211aa7ba376SStefano Stabellini pvcalls_front_dev = NULL; 212aa7ba376SStefano Stabellini if (bedata->irq >= 0) 213aa7ba376SStefano Stabellini unbind_from_irqhandler(bedata->irq, dev); 214aa7ba376SStefano Stabellini 215aa7ba376SStefano Stabellini smp_mb(); 216aa7ba376SStefano Stabellini while (atomic_read(&pvcalls_refcount) > 0) 217aa7ba376SStefano Stabellini cpu_relax(); 218aa7ba376SStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 219aa7ba376SStefano Stabellini if (map->active_socket) { 220aa7ba376SStefano Stabellini /* No need to lock, refcount is 0 */ 221aa7ba376SStefano Stabellini pvcalls_front_free_map(bedata, map); 222aa7ba376SStefano Stabellini } else { 223aa7ba376SStefano Stabellini list_del(&map->list); 224aa7ba376SStefano Stabellini kfree(map); 225aa7ba376SStefano Stabellini } 226aa7ba376SStefano Stabellini } 227aa7ba376SStefano Stabellini if (bedata->ref >= 0) 228aa7ba376SStefano Stabellini gnttab_end_foreign_access(bedata->ref, 0, 0); 229aa7ba376SStefano Stabellini kfree(bedata->ring.sring); 230aa7ba376SStefano Stabellini kfree(bedata); 231aa7ba376SStefano Stabellini xenbus_switch_state(dev, XenbusStateClosed); 232416efba0SStefano Stabellini return 0; 233416efba0SStefano Stabellini } 234416efba0SStefano Stabellini 235416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev, 236416efba0SStefano Stabellini const struct xenbus_device_id *id) 237416efba0SStefano Stabellini { 23821968190SStefano Stabellini int ret = -ENOMEM, evtchn, i; 23921968190SStefano Stabellini unsigned int max_page_order, function_calls, len; 24021968190SStefano Stabellini char *versions; 24121968190SStefano Stabellini grant_ref_t gref_head = 0; 24221968190SStefano Stabellini struct xenbus_transaction xbt; 24321968190SStefano Stabellini struct pvcalls_bedata *bedata = NULL; 24421968190SStefano Stabellini struct xen_pvcalls_sring *sring; 24521968190SStefano Stabellini 24621968190SStefano Stabellini if (pvcalls_front_dev != NULL) { 24721968190SStefano Stabellini dev_err(&dev->dev, "only one PV Calls connection supported\n"); 24821968190SStefano Stabellini return -EINVAL; 24921968190SStefano Stabellini } 25021968190SStefano Stabellini 25121968190SStefano Stabellini versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); 25221968190SStefano Stabellini if (!len) 25321968190SStefano Stabellini return -EINVAL; 25421968190SStefano Stabellini if (strcmp(versions, "1")) { 25521968190SStefano Stabellini kfree(versions); 25621968190SStefano Stabellini return -EINVAL; 25721968190SStefano Stabellini } 25821968190SStefano Stabellini kfree(versions); 25921968190SStefano Stabellini max_page_order = xenbus_read_unsigned(dev->otherend, 26021968190SStefano Stabellini "max-page-order", 0); 26121968190SStefano Stabellini if (max_page_order < PVCALLS_RING_ORDER) 26221968190SStefano Stabellini return -ENODEV; 26321968190SStefano Stabellini function_calls = xenbus_read_unsigned(dev->otherend, 26421968190SStefano Stabellini "function-calls", 0); 26521968190SStefano Stabellini /* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */ 26621968190SStefano Stabellini if (function_calls != 1) 26721968190SStefano Stabellini return -ENODEV; 26821968190SStefano Stabellini pr_info("%s max-page-order is %u\n", __func__, max_page_order); 26921968190SStefano Stabellini 27021968190SStefano Stabellini bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL); 27121968190SStefano Stabellini if (!bedata) 27221968190SStefano Stabellini return -ENOMEM; 27321968190SStefano Stabellini 27421968190SStefano Stabellini dev_set_drvdata(&dev->dev, bedata); 27521968190SStefano Stabellini pvcalls_front_dev = dev; 27621968190SStefano Stabellini init_waitqueue_head(&bedata->inflight_req); 27721968190SStefano Stabellini INIT_LIST_HEAD(&bedata->socket_mappings); 27821968190SStefano Stabellini spin_lock_init(&bedata->socket_lock); 27921968190SStefano Stabellini bedata->irq = -1; 28021968190SStefano Stabellini bedata->ref = -1; 28121968190SStefano Stabellini 28221968190SStefano Stabellini for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++) 28321968190SStefano Stabellini bedata->rsp[i].req_id = PVCALLS_INVALID_ID; 28421968190SStefano Stabellini 28521968190SStefano Stabellini sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL | 28621968190SStefano Stabellini __GFP_ZERO); 28721968190SStefano Stabellini if (!sring) 28821968190SStefano Stabellini goto error; 28921968190SStefano Stabellini SHARED_RING_INIT(sring); 29021968190SStefano Stabellini FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE); 29121968190SStefano Stabellini 29221968190SStefano Stabellini ret = xenbus_alloc_evtchn(dev, &evtchn); 29321968190SStefano Stabellini if (ret) 29421968190SStefano Stabellini goto error; 29521968190SStefano Stabellini 29621968190SStefano Stabellini bedata->irq = bind_evtchn_to_irqhandler(evtchn, 29721968190SStefano Stabellini pvcalls_front_event_handler, 29821968190SStefano Stabellini 0, "pvcalls-frontend", dev); 29921968190SStefano Stabellini if (bedata->irq < 0) { 30021968190SStefano Stabellini ret = bedata->irq; 30121968190SStefano Stabellini goto error; 30221968190SStefano Stabellini } 30321968190SStefano Stabellini 30421968190SStefano Stabellini ret = gnttab_alloc_grant_references(1, &gref_head); 30521968190SStefano Stabellini if (ret < 0) 30621968190SStefano Stabellini goto error; 30721968190SStefano Stabellini bedata->ref = gnttab_claim_grant_reference(&gref_head); 30821968190SStefano Stabellini if (bedata->ref < 0) { 30921968190SStefano Stabellini ret = bedata->ref; 31021968190SStefano Stabellini goto error; 31121968190SStefano Stabellini } 31221968190SStefano Stabellini gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id, 31321968190SStefano Stabellini virt_to_gfn((void *)sring), 0); 31421968190SStefano Stabellini 31521968190SStefano Stabellini again: 31621968190SStefano Stabellini ret = xenbus_transaction_start(&xbt); 31721968190SStefano Stabellini if (ret) { 31821968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "starting transaction"); 31921968190SStefano Stabellini goto error; 32021968190SStefano Stabellini } 32121968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); 32221968190SStefano Stabellini if (ret) 32321968190SStefano Stabellini goto error_xenbus; 32421968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref); 32521968190SStefano Stabellini if (ret) 32621968190SStefano Stabellini goto error_xenbus; 32721968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "port", "%u", 32821968190SStefano Stabellini evtchn); 32921968190SStefano Stabellini if (ret) 33021968190SStefano Stabellini goto error_xenbus; 33121968190SStefano Stabellini ret = xenbus_transaction_end(xbt, 0); 33221968190SStefano Stabellini if (ret) { 33321968190SStefano Stabellini if (ret == -EAGAIN) 33421968190SStefano Stabellini goto again; 33521968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "completing transaction"); 33621968190SStefano Stabellini goto error; 33721968190SStefano Stabellini } 33821968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateInitialised); 33921968190SStefano Stabellini 340416efba0SStefano Stabellini return 0; 34121968190SStefano Stabellini 34221968190SStefano Stabellini error_xenbus: 34321968190SStefano Stabellini xenbus_transaction_end(xbt, 1); 34421968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "writing xenstore"); 34521968190SStefano Stabellini error: 34621968190SStefano Stabellini pvcalls_front_remove(dev); 34721968190SStefano Stabellini return ret; 348416efba0SStefano Stabellini } 349416efba0SStefano Stabellini 350416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev, 351416efba0SStefano Stabellini enum xenbus_state backend_state) 352416efba0SStefano Stabellini { 35321968190SStefano Stabellini switch (backend_state) { 35421968190SStefano Stabellini case XenbusStateReconfiguring: 35521968190SStefano Stabellini case XenbusStateReconfigured: 35621968190SStefano Stabellini case XenbusStateInitialising: 35721968190SStefano Stabellini case XenbusStateInitialised: 35821968190SStefano Stabellini case XenbusStateUnknown: 35921968190SStefano Stabellini break; 36021968190SStefano Stabellini 36121968190SStefano Stabellini case XenbusStateInitWait: 36221968190SStefano Stabellini break; 36321968190SStefano Stabellini 36421968190SStefano Stabellini case XenbusStateConnected: 36521968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateConnected); 36621968190SStefano Stabellini break; 36721968190SStefano Stabellini 36821968190SStefano Stabellini case XenbusStateClosed: 36921968190SStefano Stabellini if (dev->state == XenbusStateClosed) 37021968190SStefano Stabellini break; 37121968190SStefano Stabellini /* Missed the backend's CLOSING state -- fallthrough */ 37221968190SStefano Stabellini case XenbusStateClosing: 37321968190SStefano Stabellini xenbus_frontend_closed(dev); 37421968190SStefano Stabellini break; 37521968190SStefano Stabellini } 376416efba0SStefano Stabellini } 377416efba0SStefano Stabellini 378416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = { 379416efba0SStefano Stabellini .ids = pvcalls_front_ids, 380416efba0SStefano Stabellini .probe = pvcalls_front_probe, 381416efba0SStefano Stabellini .remove = pvcalls_front_remove, 382416efba0SStefano Stabellini .otherend_changed = pvcalls_front_changed, 383416efba0SStefano Stabellini }; 384416efba0SStefano Stabellini 385416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void) 386416efba0SStefano Stabellini { 387416efba0SStefano Stabellini if (!xen_domain()) 388416efba0SStefano Stabellini return -ENODEV; 389416efba0SStefano Stabellini 390416efba0SStefano Stabellini pr_info("Initialising Xen pvcalls frontend driver\n"); 391416efba0SStefano Stabellini 392416efba0SStefano Stabellini return xenbus_register_frontend(&pvcalls_front_driver); 393416efba0SStefano Stabellini } 394416efba0SStefano Stabellini 395416efba0SStefano Stabellini module_init(pvcalls_frontend_init); 396