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> 162195046bSStefano Stabellini #include <linux/net.h> 172195046bSStefano Stabellini #include <linux/socket.h> 182195046bSStefano Stabellini 192195046bSStefano 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 272195046bSStefano Stabellini #include "pvcalls-front.h" 282195046bSStefano 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; 62cb1c7d9bSStefano Stabellini union { 63cb1c7d9bSStefano Stabellini struct { 64cb1c7d9bSStefano Stabellini int irq; 65cb1c7d9bSStefano Stabellini grant_ref_t ref; 66cb1c7d9bSStefano Stabellini struct pvcalls_data_intf *ring; 67cb1c7d9bSStefano Stabellini struct pvcalls_data data; 68cb1c7d9bSStefano Stabellini struct mutex in_mutex; 69cb1c7d9bSStefano Stabellini struct mutex out_mutex; 70cb1c7d9bSStefano Stabellini 71cb1c7d9bSStefano Stabellini wait_queue_head_t inflight_conn_req; 72cb1c7d9bSStefano Stabellini } active; 7367ea9893SStefano Stabellini struct { 7467ea9893SStefano Stabellini /* Socket status */ 7567ea9893SStefano Stabellini #define PVCALLS_STATUS_UNINITALIZED 0 7667ea9893SStefano Stabellini #define PVCALLS_STATUS_BIND 1 7767ea9893SStefano Stabellini #define PVCALLS_STATUS_LISTEN 2 7867ea9893SStefano Stabellini uint8_t status; 79*9774c6ccSStefano Stabellini /* 80*9774c6ccSStefano Stabellini * Internal state-machine flags. 81*9774c6ccSStefano Stabellini * Only one accept operation can be inflight for a socket. 82*9774c6ccSStefano Stabellini * Only one poll operation can be inflight for a given socket. 83*9774c6ccSStefano Stabellini */ 84*9774c6ccSStefano Stabellini #define PVCALLS_FLAG_ACCEPT_INFLIGHT 0 85*9774c6ccSStefano Stabellini uint8_t flags; 86*9774c6ccSStefano Stabellini uint32_t inflight_req_id; 87*9774c6ccSStefano Stabellini struct sock_mapping *accept_map; 88*9774c6ccSStefano Stabellini wait_queue_head_t inflight_accept_req; 8967ea9893SStefano Stabellini } passive; 90cb1c7d9bSStefano Stabellini }; 91aa7ba376SStefano Stabellini }; 92aa7ba376SStefano Stabellini 932195046bSStefano Stabellini static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) 942195046bSStefano Stabellini { 952195046bSStefano Stabellini *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1); 962195046bSStefano Stabellini if (RING_FULL(&bedata->ring) || 972195046bSStefano Stabellini bedata->rsp[*req_id].req_id != PVCALLS_INVALID_ID) 982195046bSStefano Stabellini return -EAGAIN; 992195046bSStefano Stabellini return 0; 1002195046bSStefano Stabellini } 1012195046bSStefano Stabellini 102aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) 103aa7ba376SStefano Stabellini { 1042195046bSStefano Stabellini struct xenbus_device *dev = dev_id; 1052195046bSStefano Stabellini struct pvcalls_bedata *bedata; 1062195046bSStefano Stabellini struct xen_pvcalls_response *rsp; 1072195046bSStefano Stabellini uint8_t *src, *dst; 1082195046bSStefano Stabellini int req_id = 0, more = 0, done = 0; 1092195046bSStefano Stabellini 1102195046bSStefano Stabellini if (dev == NULL) 1112195046bSStefano Stabellini return IRQ_HANDLED; 1122195046bSStefano Stabellini 1132195046bSStefano Stabellini pvcalls_enter(); 1142195046bSStefano Stabellini bedata = dev_get_drvdata(&dev->dev); 1152195046bSStefano Stabellini if (bedata == NULL) { 1162195046bSStefano Stabellini pvcalls_exit(); 1172195046bSStefano Stabellini return IRQ_HANDLED; 1182195046bSStefano Stabellini } 1192195046bSStefano Stabellini 1202195046bSStefano Stabellini again: 1212195046bSStefano Stabellini while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) { 1222195046bSStefano Stabellini rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons); 1232195046bSStefano Stabellini 1242195046bSStefano Stabellini req_id = rsp->req_id; 1252195046bSStefano Stabellini dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id); 1262195046bSStefano Stabellini src = (uint8_t *)rsp + sizeof(rsp->req_id); 1272195046bSStefano Stabellini memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id)); 1282195046bSStefano Stabellini /* 1292195046bSStefano Stabellini * First copy the rest of the data, then req_id. It is 1302195046bSStefano Stabellini * paired with the barrier when accessing bedata->rsp. 1312195046bSStefano Stabellini */ 1322195046bSStefano Stabellini smp_wmb(); 1332195046bSStefano Stabellini bedata->rsp[req_id].req_id = rsp->req_id; 1342195046bSStefano Stabellini 1352195046bSStefano Stabellini done = 1; 1362195046bSStefano Stabellini bedata->ring.rsp_cons++; 1372195046bSStefano Stabellini } 1382195046bSStefano Stabellini 1392195046bSStefano Stabellini RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more); 1402195046bSStefano Stabellini if (more) 1412195046bSStefano Stabellini goto again; 1422195046bSStefano Stabellini if (done) 1432195046bSStefano Stabellini wake_up(&bedata->inflight_req); 1442195046bSStefano Stabellini pvcalls_exit(); 145aa7ba376SStefano Stabellini return IRQ_HANDLED; 146aa7ba376SStefano Stabellini } 147aa7ba376SStefano Stabellini 148aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, 149aa7ba376SStefano Stabellini struct sock_mapping *map) 150aa7ba376SStefano Stabellini { 151aa7ba376SStefano Stabellini } 152aa7ba376SStefano Stabellini 153cb1c7d9bSStefano Stabellini static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map) 154cb1c7d9bSStefano Stabellini { 155cb1c7d9bSStefano Stabellini struct sock_mapping *map = sock_map; 156cb1c7d9bSStefano Stabellini 157cb1c7d9bSStefano Stabellini if (map == NULL) 158cb1c7d9bSStefano Stabellini return IRQ_HANDLED; 159cb1c7d9bSStefano Stabellini 160cb1c7d9bSStefano Stabellini wake_up_interruptible(&map->active.inflight_conn_req); 161cb1c7d9bSStefano Stabellini 162cb1c7d9bSStefano Stabellini return IRQ_HANDLED; 163cb1c7d9bSStefano Stabellini } 164cb1c7d9bSStefano Stabellini 1652195046bSStefano Stabellini int pvcalls_front_socket(struct socket *sock) 1662195046bSStefano Stabellini { 1672195046bSStefano Stabellini struct pvcalls_bedata *bedata; 1682195046bSStefano Stabellini struct sock_mapping *map = NULL; 1692195046bSStefano Stabellini struct xen_pvcalls_request *req; 1702195046bSStefano Stabellini int notify, req_id, ret; 1712195046bSStefano Stabellini 1722195046bSStefano Stabellini /* 1732195046bSStefano Stabellini * PVCalls only supports domain AF_INET, 1742195046bSStefano Stabellini * type SOCK_STREAM and protocol 0 sockets for now. 1752195046bSStefano Stabellini * 1762195046bSStefano Stabellini * Check socket type here, AF_INET and protocol checks are done 1772195046bSStefano Stabellini * by the caller. 1782195046bSStefano Stabellini */ 1792195046bSStefano Stabellini if (sock->type != SOCK_STREAM) 1802195046bSStefano Stabellini return -EOPNOTSUPP; 1812195046bSStefano Stabellini 1822195046bSStefano Stabellini pvcalls_enter(); 1832195046bSStefano Stabellini if (!pvcalls_front_dev) { 1842195046bSStefano Stabellini pvcalls_exit(); 1852195046bSStefano Stabellini return -EACCES; 1862195046bSStefano Stabellini } 1872195046bSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 1882195046bSStefano Stabellini 1892195046bSStefano Stabellini map = kzalloc(sizeof(*map), GFP_KERNEL); 1902195046bSStefano Stabellini if (map == NULL) { 1912195046bSStefano Stabellini pvcalls_exit(); 1922195046bSStefano Stabellini return -ENOMEM; 1932195046bSStefano Stabellini } 1942195046bSStefano Stabellini 1952195046bSStefano Stabellini spin_lock(&bedata->socket_lock); 1962195046bSStefano Stabellini 1972195046bSStefano Stabellini ret = get_request(bedata, &req_id); 1982195046bSStefano Stabellini if (ret < 0) { 1992195046bSStefano Stabellini kfree(map); 2002195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 2012195046bSStefano Stabellini pvcalls_exit(); 2022195046bSStefano Stabellini return ret; 2032195046bSStefano Stabellini } 2042195046bSStefano Stabellini 2052195046bSStefano Stabellini /* 2062195046bSStefano Stabellini * sock->sk->sk_send_head is not used for ip sockets: reuse the 2072195046bSStefano Stabellini * field to store a pointer to the struct sock_mapping 2082195046bSStefano Stabellini * corresponding to the socket. This way, we can easily get the 2092195046bSStefano Stabellini * struct sock_mapping from the struct socket. 2102195046bSStefano Stabellini */ 2112195046bSStefano Stabellini sock->sk->sk_send_head = (void *)map; 2122195046bSStefano Stabellini list_add_tail(&map->list, &bedata->socket_mappings); 2132195046bSStefano Stabellini 2142195046bSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 2152195046bSStefano Stabellini req->req_id = req_id; 2162195046bSStefano Stabellini req->cmd = PVCALLS_SOCKET; 2172195046bSStefano Stabellini req->u.socket.id = (uintptr_t) map; 2182195046bSStefano Stabellini req->u.socket.domain = AF_INET; 2192195046bSStefano Stabellini req->u.socket.type = SOCK_STREAM; 2202195046bSStefano Stabellini req->u.socket.protocol = IPPROTO_IP; 2212195046bSStefano Stabellini 2222195046bSStefano Stabellini bedata->ring.req_prod_pvt++; 2232195046bSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 2242195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 2252195046bSStefano Stabellini if (notify) 2262195046bSStefano Stabellini notify_remote_via_irq(bedata->irq); 2272195046bSStefano Stabellini 2282195046bSStefano Stabellini wait_event(bedata->inflight_req, 2292195046bSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 2302195046bSStefano Stabellini 2312195046bSStefano Stabellini /* read req_id, then the content */ 2322195046bSStefano Stabellini smp_rmb(); 2332195046bSStefano Stabellini ret = bedata->rsp[req_id].ret; 2342195046bSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 2352195046bSStefano Stabellini 2362195046bSStefano Stabellini pvcalls_exit(); 2372195046bSStefano Stabellini return ret; 2382195046bSStefano Stabellini } 2392195046bSStefano Stabellini 240cb1c7d9bSStefano Stabellini static int create_active(struct sock_mapping *map, int *evtchn) 241cb1c7d9bSStefano Stabellini { 242cb1c7d9bSStefano Stabellini void *bytes; 243cb1c7d9bSStefano Stabellini int ret = -ENOMEM, irq = -1, i; 244cb1c7d9bSStefano Stabellini 245cb1c7d9bSStefano Stabellini *evtchn = -1; 246cb1c7d9bSStefano Stabellini init_waitqueue_head(&map->active.inflight_conn_req); 247cb1c7d9bSStefano Stabellini 248cb1c7d9bSStefano Stabellini map->active.ring = (struct pvcalls_data_intf *) 249cb1c7d9bSStefano Stabellini __get_free_page(GFP_KERNEL | __GFP_ZERO); 250cb1c7d9bSStefano Stabellini if (map->active.ring == NULL) 251cb1c7d9bSStefano Stabellini goto out_error; 252cb1c7d9bSStefano Stabellini map->active.ring->ring_order = PVCALLS_RING_ORDER; 253cb1c7d9bSStefano Stabellini bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 254cb1c7d9bSStefano Stabellini PVCALLS_RING_ORDER); 255cb1c7d9bSStefano Stabellini if (bytes == NULL) 256cb1c7d9bSStefano Stabellini goto out_error; 257cb1c7d9bSStefano Stabellini for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) 258cb1c7d9bSStefano Stabellini map->active.ring->ref[i] = gnttab_grant_foreign_access( 259cb1c7d9bSStefano Stabellini pvcalls_front_dev->otherend_id, 260cb1c7d9bSStefano Stabellini pfn_to_gfn(virt_to_pfn(bytes) + i), 0); 261cb1c7d9bSStefano Stabellini 262cb1c7d9bSStefano Stabellini map->active.ref = gnttab_grant_foreign_access( 263cb1c7d9bSStefano Stabellini pvcalls_front_dev->otherend_id, 264cb1c7d9bSStefano Stabellini pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0); 265cb1c7d9bSStefano Stabellini 266cb1c7d9bSStefano Stabellini map->active.data.in = bytes; 267cb1c7d9bSStefano Stabellini map->active.data.out = bytes + 268cb1c7d9bSStefano Stabellini XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); 269cb1c7d9bSStefano Stabellini 270cb1c7d9bSStefano Stabellini ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn); 271cb1c7d9bSStefano Stabellini if (ret) 272cb1c7d9bSStefano Stabellini goto out_error; 273cb1c7d9bSStefano Stabellini irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler, 274cb1c7d9bSStefano Stabellini 0, "pvcalls-frontend", map); 275cb1c7d9bSStefano Stabellini if (irq < 0) { 276cb1c7d9bSStefano Stabellini ret = irq; 277cb1c7d9bSStefano Stabellini goto out_error; 278cb1c7d9bSStefano Stabellini } 279cb1c7d9bSStefano Stabellini 280cb1c7d9bSStefano Stabellini map->active.irq = irq; 281cb1c7d9bSStefano Stabellini map->active_socket = true; 282cb1c7d9bSStefano Stabellini mutex_init(&map->active.in_mutex); 283cb1c7d9bSStefano Stabellini mutex_init(&map->active.out_mutex); 284cb1c7d9bSStefano Stabellini 285cb1c7d9bSStefano Stabellini return 0; 286cb1c7d9bSStefano Stabellini 287cb1c7d9bSStefano Stabellini out_error: 288cb1c7d9bSStefano Stabellini if (irq >= 0) 289cb1c7d9bSStefano Stabellini unbind_from_irqhandler(irq, map); 290cb1c7d9bSStefano Stabellini else if (*evtchn >= 0) 291cb1c7d9bSStefano Stabellini xenbus_free_evtchn(pvcalls_front_dev, *evtchn); 292cb1c7d9bSStefano Stabellini kfree(map->active.data.in); 293cb1c7d9bSStefano Stabellini kfree(map->active.ring); 294cb1c7d9bSStefano Stabellini return ret; 295cb1c7d9bSStefano Stabellini } 296cb1c7d9bSStefano Stabellini 297cb1c7d9bSStefano Stabellini int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, 298cb1c7d9bSStefano Stabellini int addr_len, int flags) 299cb1c7d9bSStefano Stabellini { 300cb1c7d9bSStefano Stabellini struct pvcalls_bedata *bedata; 301cb1c7d9bSStefano Stabellini struct sock_mapping *map = NULL; 302cb1c7d9bSStefano Stabellini struct xen_pvcalls_request *req; 303cb1c7d9bSStefano Stabellini int notify, req_id, ret, evtchn; 304cb1c7d9bSStefano Stabellini 305cb1c7d9bSStefano Stabellini if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) 306cb1c7d9bSStefano Stabellini return -EOPNOTSUPP; 307cb1c7d9bSStefano Stabellini 308cb1c7d9bSStefano Stabellini pvcalls_enter(); 309cb1c7d9bSStefano Stabellini if (!pvcalls_front_dev) { 310cb1c7d9bSStefano Stabellini pvcalls_exit(); 311cb1c7d9bSStefano Stabellini return -ENOTCONN; 312cb1c7d9bSStefano Stabellini } 313cb1c7d9bSStefano Stabellini 314cb1c7d9bSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 315cb1c7d9bSStefano Stabellini 316cb1c7d9bSStefano Stabellini map = (struct sock_mapping *)sock->sk->sk_send_head; 317cb1c7d9bSStefano Stabellini if (!map) { 318cb1c7d9bSStefano Stabellini pvcalls_exit(); 319cb1c7d9bSStefano Stabellini return -ENOTSOCK; 320cb1c7d9bSStefano Stabellini } 321cb1c7d9bSStefano Stabellini 322cb1c7d9bSStefano Stabellini spin_lock(&bedata->socket_lock); 323cb1c7d9bSStefano Stabellini ret = get_request(bedata, &req_id); 324cb1c7d9bSStefano Stabellini if (ret < 0) { 325cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 326cb1c7d9bSStefano Stabellini pvcalls_exit(); 327cb1c7d9bSStefano Stabellini return ret; 328cb1c7d9bSStefano Stabellini } 329cb1c7d9bSStefano Stabellini ret = create_active(map, &evtchn); 330cb1c7d9bSStefano Stabellini if (ret < 0) { 331cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 332cb1c7d9bSStefano Stabellini pvcalls_exit(); 333cb1c7d9bSStefano Stabellini return ret; 334cb1c7d9bSStefano Stabellini } 335cb1c7d9bSStefano Stabellini 336cb1c7d9bSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 337cb1c7d9bSStefano Stabellini req->req_id = req_id; 338cb1c7d9bSStefano Stabellini req->cmd = PVCALLS_CONNECT; 339cb1c7d9bSStefano Stabellini req->u.connect.id = (uintptr_t)map; 340cb1c7d9bSStefano Stabellini req->u.connect.len = addr_len; 341cb1c7d9bSStefano Stabellini req->u.connect.flags = flags; 342cb1c7d9bSStefano Stabellini req->u.connect.ref = map->active.ref; 343cb1c7d9bSStefano Stabellini req->u.connect.evtchn = evtchn; 344cb1c7d9bSStefano Stabellini memcpy(req->u.connect.addr, addr, sizeof(*addr)); 345cb1c7d9bSStefano Stabellini 346cb1c7d9bSStefano Stabellini map->sock = sock; 347cb1c7d9bSStefano Stabellini 348cb1c7d9bSStefano Stabellini bedata->ring.req_prod_pvt++; 349cb1c7d9bSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 350cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 351cb1c7d9bSStefano Stabellini 352cb1c7d9bSStefano Stabellini if (notify) 353cb1c7d9bSStefano Stabellini notify_remote_via_irq(bedata->irq); 354cb1c7d9bSStefano Stabellini 355cb1c7d9bSStefano Stabellini wait_event(bedata->inflight_req, 356cb1c7d9bSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 357cb1c7d9bSStefano Stabellini 358cb1c7d9bSStefano Stabellini /* read req_id, then the content */ 359cb1c7d9bSStefano Stabellini smp_rmb(); 360cb1c7d9bSStefano Stabellini ret = bedata->rsp[req_id].ret; 361cb1c7d9bSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 362cb1c7d9bSStefano Stabellini pvcalls_exit(); 363cb1c7d9bSStefano Stabellini return ret; 364cb1c7d9bSStefano Stabellini } 365cb1c7d9bSStefano Stabellini 36667ea9893SStefano Stabellini int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 36767ea9893SStefano Stabellini { 36867ea9893SStefano Stabellini struct pvcalls_bedata *bedata; 36967ea9893SStefano Stabellini struct sock_mapping *map = NULL; 37067ea9893SStefano Stabellini struct xen_pvcalls_request *req; 37167ea9893SStefano Stabellini int notify, req_id, ret; 37267ea9893SStefano Stabellini 37367ea9893SStefano Stabellini if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) 37467ea9893SStefano Stabellini return -EOPNOTSUPP; 37567ea9893SStefano Stabellini 37667ea9893SStefano Stabellini pvcalls_enter(); 37767ea9893SStefano Stabellini if (!pvcalls_front_dev) { 37867ea9893SStefano Stabellini pvcalls_exit(); 37967ea9893SStefano Stabellini return -ENOTCONN; 38067ea9893SStefano Stabellini } 38167ea9893SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 38267ea9893SStefano Stabellini 38367ea9893SStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 38467ea9893SStefano Stabellini if (map == NULL) { 38567ea9893SStefano Stabellini pvcalls_exit(); 38667ea9893SStefano Stabellini return -ENOTSOCK; 38767ea9893SStefano Stabellini } 38867ea9893SStefano Stabellini 38967ea9893SStefano Stabellini spin_lock(&bedata->socket_lock); 39067ea9893SStefano Stabellini ret = get_request(bedata, &req_id); 39167ea9893SStefano Stabellini if (ret < 0) { 39267ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 39367ea9893SStefano Stabellini pvcalls_exit(); 39467ea9893SStefano Stabellini return ret; 39567ea9893SStefano Stabellini } 39667ea9893SStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 39767ea9893SStefano Stabellini req->req_id = req_id; 39867ea9893SStefano Stabellini map->sock = sock; 39967ea9893SStefano Stabellini req->cmd = PVCALLS_BIND; 40067ea9893SStefano Stabellini req->u.bind.id = (uintptr_t)map; 40167ea9893SStefano Stabellini memcpy(req->u.bind.addr, addr, sizeof(*addr)); 40267ea9893SStefano Stabellini req->u.bind.len = addr_len; 40367ea9893SStefano Stabellini 404*9774c6ccSStefano Stabellini init_waitqueue_head(&map->passive.inflight_accept_req); 405*9774c6ccSStefano Stabellini 40667ea9893SStefano Stabellini map->active_socket = false; 40767ea9893SStefano Stabellini 40867ea9893SStefano Stabellini bedata->ring.req_prod_pvt++; 40967ea9893SStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 41067ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 41167ea9893SStefano Stabellini if (notify) 41267ea9893SStefano Stabellini notify_remote_via_irq(bedata->irq); 41367ea9893SStefano Stabellini 41467ea9893SStefano Stabellini wait_event(bedata->inflight_req, 41567ea9893SStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 41667ea9893SStefano Stabellini 41767ea9893SStefano Stabellini /* read req_id, then the content */ 41867ea9893SStefano Stabellini smp_rmb(); 41967ea9893SStefano Stabellini ret = bedata->rsp[req_id].ret; 42067ea9893SStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 42167ea9893SStefano Stabellini 42267ea9893SStefano Stabellini map->passive.status = PVCALLS_STATUS_BIND; 42367ea9893SStefano Stabellini pvcalls_exit(); 42467ea9893SStefano Stabellini return 0; 42567ea9893SStefano Stabellini } 42667ea9893SStefano Stabellini 4271853f11dSStefano Stabellini int pvcalls_front_listen(struct socket *sock, int backlog) 4281853f11dSStefano Stabellini { 4291853f11dSStefano Stabellini struct pvcalls_bedata *bedata; 4301853f11dSStefano Stabellini struct sock_mapping *map; 4311853f11dSStefano Stabellini struct xen_pvcalls_request *req; 4321853f11dSStefano Stabellini int notify, req_id, ret; 4331853f11dSStefano Stabellini 4341853f11dSStefano Stabellini pvcalls_enter(); 4351853f11dSStefano Stabellini if (!pvcalls_front_dev) { 4361853f11dSStefano Stabellini pvcalls_exit(); 4371853f11dSStefano Stabellini return -ENOTCONN; 4381853f11dSStefano Stabellini } 4391853f11dSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 4401853f11dSStefano Stabellini 4411853f11dSStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 4421853f11dSStefano Stabellini if (!map) { 4431853f11dSStefano Stabellini pvcalls_exit(); 4441853f11dSStefano Stabellini return -ENOTSOCK; 4451853f11dSStefano Stabellini } 4461853f11dSStefano Stabellini 4471853f11dSStefano Stabellini if (map->passive.status != PVCALLS_STATUS_BIND) { 4481853f11dSStefano Stabellini pvcalls_exit(); 4491853f11dSStefano Stabellini return -EOPNOTSUPP; 4501853f11dSStefano Stabellini } 4511853f11dSStefano Stabellini 4521853f11dSStefano Stabellini spin_lock(&bedata->socket_lock); 4531853f11dSStefano Stabellini ret = get_request(bedata, &req_id); 4541853f11dSStefano Stabellini if (ret < 0) { 4551853f11dSStefano Stabellini spin_unlock(&bedata->socket_lock); 4561853f11dSStefano Stabellini pvcalls_exit(); 4571853f11dSStefano Stabellini return ret; 4581853f11dSStefano Stabellini } 4591853f11dSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 4601853f11dSStefano Stabellini req->req_id = req_id; 4611853f11dSStefano Stabellini req->cmd = PVCALLS_LISTEN; 4621853f11dSStefano Stabellini req->u.listen.id = (uintptr_t) map; 4631853f11dSStefano Stabellini req->u.listen.backlog = backlog; 4641853f11dSStefano Stabellini 4651853f11dSStefano Stabellini bedata->ring.req_prod_pvt++; 4661853f11dSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 4671853f11dSStefano Stabellini spin_unlock(&bedata->socket_lock); 4681853f11dSStefano Stabellini if (notify) 4691853f11dSStefano Stabellini notify_remote_via_irq(bedata->irq); 4701853f11dSStefano Stabellini 4711853f11dSStefano Stabellini wait_event(bedata->inflight_req, 4721853f11dSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 4731853f11dSStefano Stabellini 4741853f11dSStefano Stabellini /* read req_id, then the content */ 4751853f11dSStefano Stabellini smp_rmb(); 4761853f11dSStefano Stabellini ret = bedata->rsp[req_id].ret; 4771853f11dSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 4781853f11dSStefano Stabellini 4791853f11dSStefano Stabellini map->passive.status = PVCALLS_STATUS_LISTEN; 4801853f11dSStefano Stabellini pvcalls_exit(); 4811853f11dSStefano Stabellini return ret; 4821853f11dSStefano Stabellini } 4831853f11dSStefano Stabellini 484*9774c6ccSStefano Stabellini int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags) 485*9774c6ccSStefano Stabellini { 486*9774c6ccSStefano Stabellini struct pvcalls_bedata *bedata; 487*9774c6ccSStefano Stabellini struct sock_mapping *map; 488*9774c6ccSStefano Stabellini struct sock_mapping *map2 = NULL; 489*9774c6ccSStefano Stabellini struct xen_pvcalls_request *req; 490*9774c6ccSStefano Stabellini int notify, req_id, ret, evtchn, nonblock; 491*9774c6ccSStefano Stabellini 492*9774c6ccSStefano Stabellini pvcalls_enter(); 493*9774c6ccSStefano Stabellini if (!pvcalls_front_dev) { 494*9774c6ccSStefano Stabellini pvcalls_exit(); 495*9774c6ccSStefano Stabellini return -ENOTCONN; 496*9774c6ccSStefano Stabellini } 497*9774c6ccSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 498*9774c6ccSStefano Stabellini 499*9774c6ccSStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 500*9774c6ccSStefano Stabellini if (!map) { 501*9774c6ccSStefano Stabellini pvcalls_exit(); 502*9774c6ccSStefano Stabellini return -ENOTSOCK; 503*9774c6ccSStefano Stabellini } 504*9774c6ccSStefano Stabellini 505*9774c6ccSStefano Stabellini if (map->passive.status != PVCALLS_STATUS_LISTEN) { 506*9774c6ccSStefano Stabellini pvcalls_exit(); 507*9774c6ccSStefano Stabellini return -EINVAL; 508*9774c6ccSStefano Stabellini } 509*9774c6ccSStefano Stabellini 510*9774c6ccSStefano Stabellini nonblock = flags & SOCK_NONBLOCK; 511*9774c6ccSStefano Stabellini /* 512*9774c6ccSStefano Stabellini * Backend only supports 1 inflight accept request, will return 513*9774c6ccSStefano Stabellini * errors for the others 514*9774c6ccSStefano Stabellini */ 515*9774c6ccSStefano Stabellini if (test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 516*9774c6ccSStefano Stabellini (void *)&map->passive.flags)) { 517*9774c6ccSStefano Stabellini req_id = READ_ONCE(map->passive.inflight_req_id); 518*9774c6ccSStefano Stabellini if (req_id != PVCALLS_INVALID_ID && 519*9774c6ccSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id) { 520*9774c6ccSStefano Stabellini map2 = map->passive.accept_map; 521*9774c6ccSStefano Stabellini goto received; 522*9774c6ccSStefano Stabellini } 523*9774c6ccSStefano Stabellini if (nonblock) { 524*9774c6ccSStefano Stabellini pvcalls_exit(); 525*9774c6ccSStefano Stabellini return -EAGAIN; 526*9774c6ccSStefano Stabellini } 527*9774c6ccSStefano Stabellini if (wait_event_interruptible(map->passive.inflight_accept_req, 528*9774c6ccSStefano Stabellini !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 529*9774c6ccSStefano Stabellini (void *)&map->passive.flags))) { 530*9774c6ccSStefano Stabellini pvcalls_exit(); 531*9774c6ccSStefano Stabellini return -EINTR; 532*9774c6ccSStefano Stabellini } 533*9774c6ccSStefano Stabellini } 534*9774c6ccSStefano Stabellini 535*9774c6ccSStefano Stabellini spin_lock(&bedata->socket_lock); 536*9774c6ccSStefano Stabellini ret = get_request(bedata, &req_id); 537*9774c6ccSStefano Stabellini if (ret < 0) { 538*9774c6ccSStefano Stabellini clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 539*9774c6ccSStefano Stabellini (void *)&map->passive.flags); 540*9774c6ccSStefano Stabellini spin_unlock(&bedata->socket_lock); 541*9774c6ccSStefano Stabellini pvcalls_exit(); 542*9774c6ccSStefano Stabellini return ret; 543*9774c6ccSStefano Stabellini } 544*9774c6ccSStefano Stabellini map2 = kzalloc(sizeof(*map2), GFP_KERNEL); 545*9774c6ccSStefano Stabellini if (map2 == NULL) { 546*9774c6ccSStefano Stabellini clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 547*9774c6ccSStefano Stabellini (void *)&map->passive.flags); 548*9774c6ccSStefano Stabellini spin_unlock(&bedata->socket_lock); 549*9774c6ccSStefano Stabellini pvcalls_exit(); 550*9774c6ccSStefano Stabellini return -ENOMEM; 551*9774c6ccSStefano Stabellini } 552*9774c6ccSStefano Stabellini ret = create_active(map2, &evtchn); 553*9774c6ccSStefano Stabellini if (ret < 0) { 554*9774c6ccSStefano Stabellini kfree(map2); 555*9774c6ccSStefano Stabellini clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 556*9774c6ccSStefano Stabellini (void *)&map->passive.flags); 557*9774c6ccSStefano Stabellini spin_unlock(&bedata->socket_lock); 558*9774c6ccSStefano Stabellini pvcalls_exit(); 559*9774c6ccSStefano Stabellini return ret; 560*9774c6ccSStefano Stabellini } 561*9774c6ccSStefano Stabellini list_add_tail(&map2->list, &bedata->socket_mappings); 562*9774c6ccSStefano Stabellini 563*9774c6ccSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 564*9774c6ccSStefano Stabellini req->req_id = req_id; 565*9774c6ccSStefano Stabellini req->cmd = PVCALLS_ACCEPT; 566*9774c6ccSStefano Stabellini req->u.accept.id = (uintptr_t) map; 567*9774c6ccSStefano Stabellini req->u.accept.ref = map2->active.ref; 568*9774c6ccSStefano Stabellini req->u.accept.id_new = (uintptr_t) map2; 569*9774c6ccSStefano Stabellini req->u.accept.evtchn = evtchn; 570*9774c6ccSStefano Stabellini map->passive.accept_map = map2; 571*9774c6ccSStefano Stabellini 572*9774c6ccSStefano Stabellini bedata->ring.req_prod_pvt++; 573*9774c6ccSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 574*9774c6ccSStefano Stabellini spin_unlock(&bedata->socket_lock); 575*9774c6ccSStefano Stabellini if (notify) 576*9774c6ccSStefano Stabellini notify_remote_via_irq(bedata->irq); 577*9774c6ccSStefano Stabellini /* We could check if we have received a response before returning. */ 578*9774c6ccSStefano Stabellini if (nonblock) { 579*9774c6ccSStefano Stabellini WRITE_ONCE(map->passive.inflight_req_id, req_id); 580*9774c6ccSStefano Stabellini pvcalls_exit(); 581*9774c6ccSStefano Stabellini return -EAGAIN; 582*9774c6ccSStefano Stabellini } 583*9774c6ccSStefano Stabellini 584*9774c6ccSStefano Stabellini if (wait_event_interruptible(bedata->inflight_req, 585*9774c6ccSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) { 586*9774c6ccSStefano Stabellini pvcalls_exit(); 587*9774c6ccSStefano Stabellini return -EINTR; 588*9774c6ccSStefano Stabellini } 589*9774c6ccSStefano Stabellini /* read req_id, then the content */ 590*9774c6ccSStefano Stabellini smp_rmb(); 591*9774c6ccSStefano Stabellini 592*9774c6ccSStefano Stabellini received: 593*9774c6ccSStefano Stabellini map2->sock = newsock; 594*9774c6ccSStefano Stabellini newsock->sk = kzalloc(sizeof(*newsock->sk), GFP_KERNEL); 595*9774c6ccSStefano Stabellini if (!newsock->sk) { 596*9774c6ccSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 597*9774c6ccSStefano Stabellini map->passive.inflight_req_id = PVCALLS_INVALID_ID; 598*9774c6ccSStefano Stabellini clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, 599*9774c6ccSStefano Stabellini (void *)&map->passive.flags); 600*9774c6ccSStefano Stabellini pvcalls_front_free_map(bedata, map2); 601*9774c6ccSStefano Stabellini pvcalls_exit(); 602*9774c6ccSStefano Stabellini return -ENOMEM; 603*9774c6ccSStefano Stabellini } 604*9774c6ccSStefano Stabellini newsock->sk->sk_send_head = (void *)map2; 605*9774c6ccSStefano Stabellini 606*9774c6ccSStefano Stabellini ret = bedata->rsp[req_id].ret; 607*9774c6ccSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 608*9774c6ccSStefano Stabellini map->passive.inflight_req_id = PVCALLS_INVALID_ID; 609*9774c6ccSStefano Stabellini 610*9774c6ccSStefano Stabellini clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags); 611*9774c6ccSStefano Stabellini wake_up(&map->passive.inflight_accept_req); 612*9774c6ccSStefano Stabellini 613*9774c6ccSStefano Stabellini pvcalls_exit(); 614*9774c6ccSStefano Stabellini return ret; 615*9774c6ccSStefano Stabellini } 616*9774c6ccSStefano Stabellini 617416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = { 618416efba0SStefano Stabellini { "pvcalls" }, 619416efba0SStefano Stabellini { "" } 620416efba0SStefano Stabellini }; 621416efba0SStefano Stabellini 622416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev) 623416efba0SStefano Stabellini { 624aa7ba376SStefano Stabellini struct pvcalls_bedata *bedata; 625aa7ba376SStefano Stabellini struct sock_mapping *map = NULL, *n; 626aa7ba376SStefano Stabellini 627aa7ba376SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 628aa7ba376SStefano Stabellini dev_set_drvdata(&dev->dev, NULL); 629aa7ba376SStefano Stabellini pvcalls_front_dev = NULL; 630aa7ba376SStefano Stabellini if (bedata->irq >= 0) 631aa7ba376SStefano Stabellini unbind_from_irqhandler(bedata->irq, dev); 632aa7ba376SStefano Stabellini 633cb1c7d9bSStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 634cb1c7d9bSStefano Stabellini map->sock->sk->sk_send_head = NULL; 635cb1c7d9bSStefano Stabellini if (map->active_socket) { 636cb1c7d9bSStefano Stabellini map->active.ring->in_error = -EBADF; 637cb1c7d9bSStefano Stabellini wake_up_interruptible(&map->active.inflight_conn_req); 638cb1c7d9bSStefano Stabellini } 639cb1c7d9bSStefano Stabellini } 640cb1c7d9bSStefano Stabellini 641aa7ba376SStefano Stabellini smp_mb(); 642aa7ba376SStefano Stabellini while (atomic_read(&pvcalls_refcount) > 0) 643aa7ba376SStefano Stabellini cpu_relax(); 644aa7ba376SStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 645aa7ba376SStefano Stabellini if (map->active_socket) { 646aa7ba376SStefano Stabellini /* No need to lock, refcount is 0 */ 647aa7ba376SStefano Stabellini pvcalls_front_free_map(bedata, map); 648aa7ba376SStefano Stabellini } else { 649aa7ba376SStefano Stabellini list_del(&map->list); 650aa7ba376SStefano Stabellini kfree(map); 651aa7ba376SStefano Stabellini } 652aa7ba376SStefano Stabellini } 653aa7ba376SStefano Stabellini if (bedata->ref >= 0) 654aa7ba376SStefano Stabellini gnttab_end_foreign_access(bedata->ref, 0, 0); 655aa7ba376SStefano Stabellini kfree(bedata->ring.sring); 656aa7ba376SStefano Stabellini kfree(bedata); 657aa7ba376SStefano Stabellini xenbus_switch_state(dev, XenbusStateClosed); 658416efba0SStefano Stabellini return 0; 659416efba0SStefano Stabellini } 660416efba0SStefano Stabellini 661416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev, 662416efba0SStefano Stabellini const struct xenbus_device_id *id) 663416efba0SStefano Stabellini { 66421968190SStefano Stabellini int ret = -ENOMEM, evtchn, i; 66521968190SStefano Stabellini unsigned int max_page_order, function_calls, len; 66621968190SStefano Stabellini char *versions; 66721968190SStefano Stabellini grant_ref_t gref_head = 0; 66821968190SStefano Stabellini struct xenbus_transaction xbt; 66921968190SStefano Stabellini struct pvcalls_bedata *bedata = NULL; 67021968190SStefano Stabellini struct xen_pvcalls_sring *sring; 67121968190SStefano Stabellini 67221968190SStefano Stabellini if (pvcalls_front_dev != NULL) { 67321968190SStefano Stabellini dev_err(&dev->dev, "only one PV Calls connection supported\n"); 67421968190SStefano Stabellini return -EINVAL; 67521968190SStefano Stabellini } 67621968190SStefano Stabellini 67721968190SStefano Stabellini versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); 67821968190SStefano Stabellini if (!len) 67921968190SStefano Stabellini return -EINVAL; 68021968190SStefano Stabellini if (strcmp(versions, "1")) { 68121968190SStefano Stabellini kfree(versions); 68221968190SStefano Stabellini return -EINVAL; 68321968190SStefano Stabellini } 68421968190SStefano Stabellini kfree(versions); 68521968190SStefano Stabellini max_page_order = xenbus_read_unsigned(dev->otherend, 68621968190SStefano Stabellini "max-page-order", 0); 68721968190SStefano Stabellini if (max_page_order < PVCALLS_RING_ORDER) 68821968190SStefano Stabellini return -ENODEV; 68921968190SStefano Stabellini function_calls = xenbus_read_unsigned(dev->otherend, 69021968190SStefano Stabellini "function-calls", 0); 69121968190SStefano Stabellini /* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */ 69221968190SStefano Stabellini if (function_calls != 1) 69321968190SStefano Stabellini return -ENODEV; 69421968190SStefano Stabellini pr_info("%s max-page-order is %u\n", __func__, max_page_order); 69521968190SStefano Stabellini 69621968190SStefano Stabellini bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL); 69721968190SStefano Stabellini if (!bedata) 69821968190SStefano Stabellini return -ENOMEM; 69921968190SStefano Stabellini 70021968190SStefano Stabellini dev_set_drvdata(&dev->dev, bedata); 70121968190SStefano Stabellini pvcalls_front_dev = dev; 70221968190SStefano Stabellini init_waitqueue_head(&bedata->inflight_req); 70321968190SStefano Stabellini INIT_LIST_HEAD(&bedata->socket_mappings); 70421968190SStefano Stabellini spin_lock_init(&bedata->socket_lock); 70521968190SStefano Stabellini bedata->irq = -1; 70621968190SStefano Stabellini bedata->ref = -1; 70721968190SStefano Stabellini 70821968190SStefano Stabellini for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++) 70921968190SStefano Stabellini bedata->rsp[i].req_id = PVCALLS_INVALID_ID; 71021968190SStefano Stabellini 71121968190SStefano Stabellini sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL | 71221968190SStefano Stabellini __GFP_ZERO); 71321968190SStefano Stabellini if (!sring) 71421968190SStefano Stabellini goto error; 71521968190SStefano Stabellini SHARED_RING_INIT(sring); 71621968190SStefano Stabellini FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE); 71721968190SStefano Stabellini 71821968190SStefano Stabellini ret = xenbus_alloc_evtchn(dev, &evtchn); 71921968190SStefano Stabellini if (ret) 72021968190SStefano Stabellini goto error; 72121968190SStefano Stabellini 72221968190SStefano Stabellini bedata->irq = bind_evtchn_to_irqhandler(evtchn, 72321968190SStefano Stabellini pvcalls_front_event_handler, 72421968190SStefano Stabellini 0, "pvcalls-frontend", dev); 72521968190SStefano Stabellini if (bedata->irq < 0) { 72621968190SStefano Stabellini ret = bedata->irq; 72721968190SStefano Stabellini goto error; 72821968190SStefano Stabellini } 72921968190SStefano Stabellini 73021968190SStefano Stabellini ret = gnttab_alloc_grant_references(1, &gref_head); 73121968190SStefano Stabellini if (ret < 0) 73221968190SStefano Stabellini goto error; 73321968190SStefano Stabellini bedata->ref = gnttab_claim_grant_reference(&gref_head); 73421968190SStefano Stabellini if (bedata->ref < 0) { 73521968190SStefano Stabellini ret = bedata->ref; 73621968190SStefano Stabellini goto error; 73721968190SStefano Stabellini } 73821968190SStefano Stabellini gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id, 73921968190SStefano Stabellini virt_to_gfn((void *)sring), 0); 74021968190SStefano Stabellini 74121968190SStefano Stabellini again: 74221968190SStefano Stabellini ret = xenbus_transaction_start(&xbt); 74321968190SStefano Stabellini if (ret) { 74421968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "starting transaction"); 74521968190SStefano Stabellini goto error; 74621968190SStefano Stabellini } 74721968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); 74821968190SStefano Stabellini if (ret) 74921968190SStefano Stabellini goto error_xenbus; 75021968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref); 75121968190SStefano Stabellini if (ret) 75221968190SStefano Stabellini goto error_xenbus; 75321968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "port", "%u", 75421968190SStefano Stabellini evtchn); 75521968190SStefano Stabellini if (ret) 75621968190SStefano Stabellini goto error_xenbus; 75721968190SStefano Stabellini ret = xenbus_transaction_end(xbt, 0); 75821968190SStefano Stabellini if (ret) { 75921968190SStefano Stabellini if (ret == -EAGAIN) 76021968190SStefano Stabellini goto again; 76121968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "completing transaction"); 76221968190SStefano Stabellini goto error; 76321968190SStefano Stabellini } 76421968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateInitialised); 76521968190SStefano Stabellini 766416efba0SStefano Stabellini return 0; 76721968190SStefano Stabellini 76821968190SStefano Stabellini error_xenbus: 76921968190SStefano Stabellini xenbus_transaction_end(xbt, 1); 77021968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "writing xenstore"); 77121968190SStefano Stabellini error: 77221968190SStefano Stabellini pvcalls_front_remove(dev); 77321968190SStefano Stabellini return ret; 774416efba0SStefano Stabellini } 775416efba0SStefano Stabellini 776416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev, 777416efba0SStefano Stabellini enum xenbus_state backend_state) 778416efba0SStefano Stabellini { 77921968190SStefano Stabellini switch (backend_state) { 78021968190SStefano Stabellini case XenbusStateReconfiguring: 78121968190SStefano Stabellini case XenbusStateReconfigured: 78221968190SStefano Stabellini case XenbusStateInitialising: 78321968190SStefano Stabellini case XenbusStateInitialised: 78421968190SStefano Stabellini case XenbusStateUnknown: 78521968190SStefano Stabellini break; 78621968190SStefano Stabellini 78721968190SStefano Stabellini case XenbusStateInitWait: 78821968190SStefano Stabellini break; 78921968190SStefano Stabellini 79021968190SStefano Stabellini case XenbusStateConnected: 79121968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateConnected); 79221968190SStefano Stabellini break; 79321968190SStefano Stabellini 79421968190SStefano Stabellini case XenbusStateClosed: 79521968190SStefano Stabellini if (dev->state == XenbusStateClosed) 79621968190SStefano Stabellini break; 79721968190SStefano Stabellini /* Missed the backend's CLOSING state -- fallthrough */ 79821968190SStefano Stabellini case XenbusStateClosing: 79921968190SStefano Stabellini xenbus_frontend_closed(dev); 80021968190SStefano Stabellini break; 80121968190SStefano Stabellini } 802416efba0SStefano Stabellini } 803416efba0SStefano Stabellini 804416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = { 805416efba0SStefano Stabellini .ids = pvcalls_front_ids, 806416efba0SStefano Stabellini .probe = pvcalls_front_probe, 807416efba0SStefano Stabellini .remove = pvcalls_front_remove, 808416efba0SStefano Stabellini .otherend_changed = pvcalls_front_changed, 809416efba0SStefano Stabellini }; 810416efba0SStefano Stabellini 811416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void) 812416efba0SStefano Stabellini { 813416efba0SStefano Stabellini if (!xen_domain()) 814416efba0SStefano Stabellini return -ENODEV; 815416efba0SStefano Stabellini 816416efba0SStefano Stabellini pr_info("Initialising Xen pvcalls frontend driver\n"); 817416efba0SStefano Stabellini 818416efba0SStefano Stabellini return xenbus_register_frontend(&pvcalls_front_driver); 819416efba0SStefano Stabellini } 820416efba0SStefano Stabellini 821416efba0SStefano Stabellini module_init(pvcalls_frontend_init); 822