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> 16416efba0SStefano Stabellini 17416efba0SStefano Stabellini #include <xen/events.h> 18416efba0SStefano Stabellini #include <xen/grant_table.h> 19416efba0SStefano Stabellini #include <xen/xen.h> 20416efba0SStefano Stabellini #include <xen/xenbus.h> 21416efba0SStefano Stabellini #include <xen/interface/io/pvcalls.h> 22416efba0SStefano Stabellini 23aa7ba376SStefano Stabellini #define PVCALLS_INVALID_ID UINT_MAX 24aa7ba376SStefano Stabellini #define PVCALLS_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER 25aa7ba376SStefano Stabellini #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE) 26aa7ba376SStefano Stabellini 27aa7ba376SStefano Stabellini struct pvcalls_bedata { 28aa7ba376SStefano Stabellini struct xen_pvcalls_front_ring ring; 29aa7ba376SStefano Stabellini grant_ref_t ref; 30aa7ba376SStefano Stabellini int irq; 31aa7ba376SStefano Stabellini 32aa7ba376SStefano Stabellini struct list_head socket_mappings; 33aa7ba376SStefano Stabellini spinlock_t socket_lock; 34aa7ba376SStefano Stabellini 35aa7ba376SStefano Stabellini wait_queue_head_t inflight_req; 36aa7ba376SStefano Stabellini struct xen_pvcalls_response rsp[PVCALLS_NR_RSP_PER_RING]; 37aa7ba376SStefano Stabellini }; 38aa7ba376SStefano Stabellini /* Only one front/back connection supported. */ 39aa7ba376SStefano Stabellini static struct xenbus_device *pvcalls_front_dev; 40aa7ba376SStefano Stabellini static atomic_t pvcalls_refcount; 41aa7ba376SStefano Stabellini 42aa7ba376SStefano Stabellini /* first increment refcount, then proceed */ 43aa7ba376SStefano Stabellini #define pvcalls_enter() { \ 44aa7ba376SStefano Stabellini atomic_inc(&pvcalls_refcount); \ 45aa7ba376SStefano Stabellini } 46aa7ba376SStefano Stabellini 47aa7ba376SStefano Stabellini /* first complete other operations, then decrement refcount */ 48aa7ba376SStefano Stabellini #define pvcalls_exit() { \ 49aa7ba376SStefano Stabellini atomic_dec(&pvcalls_refcount); \ 50aa7ba376SStefano Stabellini } 51aa7ba376SStefano Stabellini 52aa7ba376SStefano Stabellini struct sock_mapping { 53aa7ba376SStefano Stabellini bool active_socket; 54aa7ba376SStefano Stabellini struct list_head list; 55aa7ba376SStefano Stabellini struct socket *sock; 56aa7ba376SStefano Stabellini }; 57aa7ba376SStefano Stabellini 58aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) 59aa7ba376SStefano Stabellini { 60aa7ba376SStefano Stabellini return IRQ_HANDLED; 61aa7ba376SStefano Stabellini } 62aa7ba376SStefano Stabellini 63aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, 64aa7ba376SStefano Stabellini struct sock_mapping *map) 65aa7ba376SStefano Stabellini { 66aa7ba376SStefano Stabellini } 67aa7ba376SStefano Stabellini 68416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = { 69416efba0SStefano Stabellini { "pvcalls" }, 70416efba0SStefano Stabellini { "" } 71416efba0SStefano Stabellini }; 72416efba0SStefano Stabellini 73416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev) 74416efba0SStefano Stabellini { 75aa7ba376SStefano Stabellini struct pvcalls_bedata *bedata; 76aa7ba376SStefano Stabellini struct sock_mapping *map = NULL, *n; 77aa7ba376SStefano Stabellini 78aa7ba376SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 79aa7ba376SStefano Stabellini dev_set_drvdata(&dev->dev, NULL); 80aa7ba376SStefano Stabellini pvcalls_front_dev = NULL; 81aa7ba376SStefano Stabellini if (bedata->irq >= 0) 82aa7ba376SStefano Stabellini unbind_from_irqhandler(bedata->irq, dev); 83aa7ba376SStefano Stabellini 84aa7ba376SStefano Stabellini smp_mb(); 85aa7ba376SStefano Stabellini while (atomic_read(&pvcalls_refcount) > 0) 86aa7ba376SStefano Stabellini cpu_relax(); 87aa7ba376SStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 88aa7ba376SStefano Stabellini if (map->active_socket) { 89aa7ba376SStefano Stabellini /* No need to lock, refcount is 0 */ 90aa7ba376SStefano Stabellini pvcalls_front_free_map(bedata, map); 91aa7ba376SStefano Stabellini } else { 92aa7ba376SStefano Stabellini list_del(&map->list); 93aa7ba376SStefano Stabellini kfree(map); 94aa7ba376SStefano Stabellini } 95aa7ba376SStefano Stabellini } 96aa7ba376SStefano Stabellini if (bedata->ref >= 0) 97aa7ba376SStefano Stabellini gnttab_end_foreign_access(bedata->ref, 0, 0); 98aa7ba376SStefano Stabellini kfree(bedata->ring.sring); 99aa7ba376SStefano Stabellini kfree(bedata); 100aa7ba376SStefano Stabellini xenbus_switch_state(dev, XenbusStateClosed); 101416efba0SStefano Stabellini return 0; 102416efba0SStefano Stabellini } 103416efba0SStefano Stabellini 104416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev, 105416efba0SStefano Stabellini const struct xenbus_device_id *id) 106416efba0SStefano Stabellini { 107*21968190SStefano Stabellini int ret = -ENOMEM, evtchn, i; 108*21968190SStefano Stabellini unsigned int max_page_order, function_calls, len; 109*21968190SStefano Stabellini char *versions; 110*21968190SStefano Stabellini grant_ref_t gref_head = 0; 111*21968190SStefano Stabellini struct xenbus_transaction xbt; 112*21968190SStefano Stabellini struct pvcalls_bedata *bedata = NULL; 113*21968190SStefano Stabellini struct xen_pvcalls_sring *sring; 114*21968190SStefano Stabellini 115*21968190SStefano Stabellini if (pvcalls_front_dev != NULL) { 116*21968190SStefano Stabellini dev_err(&dev->dev, "only one PV Calls connection supported\n"); 117*21968190SStefano Stabellini return -EINVAL; 118*21968190SStefano Stabellini } 119*21968190SStefano Stabellini 120*21968190SStefano Stabellini versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); 121*21968190SStefano Stabellini if (!len) 122*21968190SStefano Stabellini return -EINVAL; 123*21968190SStefano Stabellini if (strcmp(versions, "1")) { 124*21968190SStefano Stabellini kfree(versions); 125*21968190SStefano Stabellini return -EINVAL; 126*21968190SStefano Stabellini } 127*21968190SStefano Stabellini kfree(versions); 128*21968190SStefano Stabellini max_page_order = xenbus_read_unsigned(dev->otherend, 129*21968190SStefano Stabellini "max-page-order", 0); 130*21968190SStefano Stabellini if (max_page_order < PVCALLS_RING_ORDER) 131*21968190SStefano Stabellini return -ENODEV; 132*21968190SStefano Stabellini function_calls = xenbus_read_unsigned(dev->otherend, 133*21968190SStefano Stabellini "function-calls", 0); 134*21968190SStefano Stabellini /* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */ 135*21968190SStefano Stabellini if (function_calls != 1) 136*21968190SStefano Stabellini return -ENODEV; 137*21968190SStefano Stabellini pr_info("%s max-page-order is %u\n", __func__, max_page_order); 138*21968190SStefano Stabellini 139*21968190SStefano Stabellini bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL); 140*21968190SStefano Stabellini if (!bedata) 141*21968190SStefano Stabellini return -ENOMEM; 142*21968190SStefano Stabellini 143*21968190SStefano Stabellini dev_set_drvdata(&dev->dev, bedata); 144*21968190SStefano Stabellini pvcalls_front_dev = dev; 145*21968190SStefano Stabellini init_waitqueue_head(&bedata->inflight_req); 146*21968190SStefano Stabellini INIT_LIST_HEAD(&bedata->socket_mappings); 147*21968190SStefano Stabellini spin_lock_init(&bedata->socket_lock); 148*21968190SStefano Stabellini bedata->irq = -1; 149*21968190SStefano Stabellini bedata->ref = -1; 150*21968190SStefano Stabellini 151*21968190SStefano Stabellini for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++) 152*21968190SStefano Stabellini bedata->rsp[i].req_id = PVCALLS_INVALID_ID; 153*21968190SStefano Stabellini 154*21968190SStefano Stabellini sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL | 155*21968190SStefano Stabellini __GFP_ZERO); 156*21968190SStefano Stabellini if (!sring) 157*21968190SStefano Stabellini goto error; 158*21968190SStefano Stabellini SHARED_RING_INIT(sring); 159*21968190SStefano Stabellini FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE); 160*21968190SStefano Stabellini 161*21968190SStefano Stabellini ret = xenbus_alloc_evtchn(dev, &evtchn); 162*21968190SStefano Stabellini if (ret) 163*21968190SStefano Stabellini goto error; 164*21968190SStefano Stabellini 165*21968190SStefano Stabellini bedata->irq = bind_evtchn_to_irqhandler(evtchn, 166*21968190SStefano Stabellini pvcalls_front_event_handler, 167*21968190SStefano Stabellini 0, "pvcalls-frontend", dev); 168*21968190SStefano Stabellini if (bedata->irq < 0) { 169*21968190SStefano Stabellini ret = bedata->irq; 170*21968190SStefano Stabellini goto error; 171*21968190SStefano Stabellini } 172*21968190SStefano Stabellini 173*21968190SStefano Stabellini ret = gnttab_alloc_grant_references(1, &gref_head); 174*21968190SStefano Stabellini if (ret < 0) 175*21968190SStefano Stabellini goto error; 176*21968190SStefano Stabellini bedata->ref = gnttab_claim_grant_reference(&gref_head); 177*21968190SStefano Stabellini if (bedata->ref < 0) { 178*21968190SStefano Stabellini ret = bedata->ref; 179*21968190SStefano Stabellini goto error; 180*21968190SStefano Stabellini } 181*21968190SStefano Stabellini gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id, 182*21968190SStefano Stabellini virt_to_gfn((void *)sring), 0); 183*21968190SStefano Stabellini 184*21968190SStefano Stabellini again: 185*21968190SStefano Stabellini ret = xenbus_transaction_start(&xbt); 186*21968190SStefano Stabellini if (ret) { 187*21968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "starting transaction"); 188*21968190SStefano Stabellini goto error; 189*21968190SStefano Stabellini } 190*21968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); 191*21968190SStefano Stabellini if (ret) 192*21968190SStefano Stabellini goto error_xenbus; 193*21968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref); 194*21968190SStefano Stabellini if (ret) 195*21968190SStefano Stabellini goto error_xenbus; 196*21968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "port", "%u", 197*21968190SStefano Stabellini evtchn); 198*21968190SStefano Stabellini if (ret) 199*21968190SStefano Stabellini goto error_xenbus; 200*21968190SStefano Stabellini ret = xenbus_transaction_end(xbt, 0); 201*21968190SStefano Stabellini if (ret) { 202*21968190SStefano Stabellini if (ret == -EAGAIN) 203*21968190SStefano Stabellini goto again; 204*21968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "completing transaction"); 205*21968190SStefano Stabellini goto error; 206*21968190SStefano Stabellini } 207*21968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateInitialised); 208*21968190SStefano Stabellini 209416efba0SStefano Stabellini return 0; 210*21968190SStefano Stabellini 211*21968190SStefano Stabellini error_xenbus: 212*21968190SStefano Stabellini xenbus_transaction_end(xbt, 1); 213*21968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "writing xenstore"); 214*21968190SStefano Stabellini error: 215*21968190SStefano Stabellini pvcalls_front_remove(dev); 216*21968190SStefano Stabellini return ret; 217416efba0SStefano Stabellini } 218416efba0SStefano Stabellini 219416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev, 220416efba0SStefano Stabellini enum xenbus_state backend_state) 221416efba0SStefano Stabellini { 222*21968190SStefano Stabellini switch (backend_state) { 223*21968190SStefano Stabellini case XenbusStateReconfiguring: 224*21968190SStefano Stabellini case XenbusStateReconfigured: 225*21968190SStefano Stabellini case XenbusStateInitialising: 226*21968190SStefano Stabellini case XenbusStateInitialised: 227*21968190SStefano Stabellini case XenbusStateUnknown: 228*21968190SStefano Stabellini break; 229*21968190SStefano Stabellini 230*21968190SStefano Stabellini case XenbusStateInitWait: 231*21968190SStefano Stabellini break; 232*21968190SStefano Stabellini 233*21968190SStefano Stabellini case XenbusStateConnected: 234*21968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateConnected); 235*21968190SStefano Stabellini break; 236*21968190SStefano Stabellini 237*21968190SStefano Stabellini case XenbusStateClosed: 238*21968190SStefano Stabellini if (dev->state == XenbusStateClosed) 239*21968190SStefano Stabellini break; 240*21968190SStefano Stabellini /* Missed the backend's CLOSING state -- fallthrough */ 241*21968190SStefano Stabellini case XenbusStateClosing: 242*21968190SStefano Stabellini xenbus_frontend_closed(dev); 243*21968190SStefano Stabellini break; 244*21968190SStefano Stabellini } 245416efba0SStefano Stabellini } 246416efba0SStefano Stabellini 247416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = { 248416efba0SStefano Stabellini .ids = pvcalls_front_ids, 249416efba0SStefano Stabellini .probe = pvcalls_front_probe, 250416efba0SStefano Stabellini .remove = pvcalls_front_remove, 251416efba0SStefano Stabellini .otherend_changed = pvcalls_front_changed, 252416efba0SStefano Stabellini }; 253416efba0SStefano Stabellini 254416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void) 255416efba0SStefano Stabellini { 256416efba0SStefano Stabellini if (!xen_domain()) 257416efba0SStefano Stabellini return -ENODEV; 258416efba0SStefano Stabellini 259416efba0SStefano Stabellini pr_info("Initialising Xen pvcalls frontend driver\n"); 260416efba0SStefano Stabellini 261416efba0SStefano Stabellini return xenbus_register_frontend(&pvcalls_front_driver); 262416efba0SStefano Stabellini } 263416efba0SStefano Stabellini 264416efba0SStefano Stabellini module_init(pvcalls_frontend_init); 265