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; 73*67ea9893SStefano Stabellini struct { 74*67ea9893SStefano Stabellini /* Socket status */ 75*67ea9893SStefano Stabellini #define PVCALLS_STATUS_UNINITALIZED 0 76*67ea9893SStefano Stabellini #define PVCALLS_STATUS_BIND 1 77*67ea9893SStefano Stabellini #define PVCALLS_STATUS_LISTEN 2 78*67ea9893SStefano Stabellini uint8_t status; 79*67ea9893SStefano Stabellini } passive; 80cb1c7d9bSStefano Stabellini }; 81aa7ba376SStefano Stabellini }; 82aa7ba376SStefano Stabellini 832195046bSStefano Stabellini static inline int get_request(struct pvcalls_bedata *bedata, int *req_id) 842195046bSStefano Stabellini { 852195046bSStefano Stabellini *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1); 862195046bSStefano Stabellini if (RING_FULL(&bedata->ring) || 872195046bSStefano Stabellini bedata->rsp[*req_id].req_id != PVCALLS_INVALID_ID) 882195046bSStefano Stabellini return -EAGAIN; 892195046bSStefano Stabellini return 0; 902195046bSStefano Stabellini } 912195046bSStefano Stabellini 92aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id) 93aa7ba376SStefano Stabellini { 942195046bSStefano Stabellini struct xenbus_device *dev = dev_id; 952195046bSStefano Stabellini struct pvcalls_bedata *bedata; 962195046bSStefano Stabellini struct xen_pvcalls_response *rsp; 972195046bSStefano Stabellini uint8_t *src, *dst; 982195046bSStefano Stabellini int req_id = 0, more = 0, done = 0; 992195046bSStefano Stabellini 1002195046bSStefano Stabellini if (dev == NULL) 1012195046bSStefano Stabellini return IRQ_HANDLED; 1022195046bSStefano Stabellini 1032195046bSStefano Stabellini pvcalls_enter(); 1042195046bSStefano Stabellini bedata = dev_get_drvdata(&dev->dev); 1052195046bSStefano Stabellini if (bedata == NULL) { 1062195046bSStefano Stabellini pvcalls_exit(); 1072195046bSStefano Stabellini return IRQ_HANDLED; 1082195046bSStefano Stabellini } 1092195046bSStefano Stabellini 1102195046bSStefano Stabellini again: 1112195046bSStefano Stabellini while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) { 1122195046bSStefano Stabellini rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons); 1132195046bSStefano Stabellini 1142195046bSStefano Stabellini req_id = rsp->req_id; 1152195046bSStefano Stabellini dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id); 1162195046bSStefano Stabellini src = (uint8_t *)rsp + sizeof(rsp->req_id); 1172195046bSStefano Stabellini memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id)); 1182195046bSStefano Stabellini /* 1192195046bSStefano Stabellini * First copy the rest of the data, then req_id. It is 1202195046bSStefano Stabellini * paired with the barrier when accessing bedata->rsp. 1212195046bSStefano Stabellini */ 1222195046bSStefano Stabellini smp_wmb(); 1232195046bSStefano Stabellini bedata->rsp[req_id].req_id = rsp->req_id; 1242195046bSStefano Stabellini 1252195046bSStefano Stabellini done = 1; 1262195046bSStefano Stabellini bedata->ring.rsp_cons++; 1272195046bSStefano Stabellini } 1282195046bSStefano Stabellini 1292195046bSStefano Stabellini RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more); 1302195046bSStefano Stabellini if (more) 1312195046bSStefano Stabellini goto again; 1322195046bSStefano Stabellini if (done) 1332195046bSStefano Stabellini wake_up(&bedata->inflight_req); 1342195046bSStefano Stabellini pvcalls_exit(); 135aa7ba376SStefano Stabellini return IRQ_HANDLED; 136aa7ba376SStefano Stabellini } 137aa7ba376SStefano Stabellini 138aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata, 139aa7ba376SStefano Stabellini struct sock_mapping *map) 140aa7ba376SStefano Stabellini { 141aa7ba376SStefano Stabellini } 142aa7ba376SStefano Stabellini 143cb1c7d9bSStefano Stabellini static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map) 144cb1c7d9bSStefano Stabellini { 145cb1c7d9bSStefano Stabellini struct sock_mapping *map = sock_map; 146cb1c7d9bSStefano Stabellini 147cb1c7d9bSStefano Stabellini if (map == NULL) 148cb1c7d9bSStefano Stabellini return IRQ_HANDLED; 149cb1c7d9bSStefano Stabellini 150cb1c7d9bSStefano Stabellini wake_up_interruptible(&map->active.inflight_conn_req); 151cb1c7d9bSStefano Stabellini 152cb1c7d9bSStefano Stabellini return IRQ_HANDLED; 153cb1c7d9bSStefano Stabellini } 154cb1c7d9bSStefano Stabellini 1552195046bSStefano Stabellini int pvcalls_front_socket(struct socket *sock) 1562195046bSStefano Stabellini { 1572195046bSStefano Stabellini struct pvcalls_bedata *bedata; 1582195046bSStefano Stabellini struct sock_mapping *map = NULL; 1592195046bSStefano Stabellini struct xen_pvcalls_request *req; 1602195046bSStefano Stabellini int notify, req_id, ret; 1612195046bSStefano Stabellini 1622195046bSStefano Stabellini /* 1632195046bSStefano Stabellini * PVCalls only supports domain AF_INET, 1642195046bSStefano Stabellini * type SOCK_STREAM and protocol 0 sockets for now. 1652195046bSStefano Stabellini * 1662195046bSStefano Stabellini * Check socket type here, AF_INET and protocol checks are done 1672195046bSStefano Stabellini * by the caller. 1682195046bSStefano Stabellini */ 1692195046bSStefano Stabellini if (sock->type != SOCK_STREAM) 1702195046bSStefano Stabellini return -EOPNOTSUPP; 1712195046bSStefano Stabellini 1722195046bSStefano Stabellini pvcalls_enter(); 1732195046bSStefano Stabellini if (!pvcalls_front_dev) { 1742195046bSStefano Stabellini pvcalls_exit(); 1752195046bSStefano Stabellini return -EACCES; 1762195046bSStefano Stabellini } 1772195046bSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 1782195046bSStefano Stabellini 1792195046bSStefano Stabellini map = kzalloc(sizeof(*map), GFP_KERNEL); 1802195046bSStefano Stabellini if (map == NULL) { 1812195046bSStefano Stabellini pvcalls_exit(); 1822195046bSStefano Stabellini return -ENOMEM; 1832195046bSStefano Stabellini } 1842195046bSStefano Stabellini 1852195046bSStefano Stabellini spin_lock(&bedata->socket_lock); 1862195046bSStefano Stabellini 1872195046bSStefano Stabellini ret = get_request(bedata, &req_id); 1882195046bSStefano Stabellini if (ret < 0) { 1892195046bSStefano Stabellini kfree(map); 1902195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 1912195046bSStefano Stabellini pvcalls_exit(); 1922195046bSStefano Stabellini return ret; 1932195046bSStefano Stabellini } 1942195046bSStefano Stabellini 1952195046bSStefano Stabellini /* 1962195046bSStefano Stabellini * sock->sk->sk_send_head is not used for ip sockets: reuse the 1972195046bSStefano Stabellini * field to store a pointer to the struct sock_mapping 1982195046bSStefano Stabellini * corresponding to the socket. This way, we can easily get the 1992195046bSStefano Stabellini * struct sock_mapping from the struct socket. 2002195046bSStefano Stabellini */ 2012195046bSStefano Stabellini sock->sk->sk_send_head = (void *)map; 2022195046bSStefano Stabellini list_add_tail(&map->list, &bedata->socket_mappings); 2032195046bSStefano Stabellini 2042195046bSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 2052195046bSStefano Stabellini req->req_id = req_id; 2062195046bSStefano Stabellini req->cmd = PVCALLS_SOCKET; 2072195046bSStefano Stabellini req->u.socket.id = (uintptr_t) map; 2082195046bSStefano Stabellini req->u.socket.domain = AF_INET; 2092195046bSStefano Stabellini req->u.socket.type = SOCK_STREAM; 2102195046bSStefano Stabellini req->u.socket.protocol = IPPROTO_IP; 2112195046bSStefano Stabellini 2122195046bSStefano Stabellini bedata->ring.req_prod_pvt++; 2132195046bSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 2142195046bSStefano Stabellini spin_unlock(&bedata->socket_lock); 2152195046bSStefano Stabellini if (notify) 2162195046bSStefano Stabellini notify_remote_via_irq(bedata->irq); 2172195046bSStefano Stabellini 2182195046bSStefano Stabellini wait_event(bedata->inflight_req, 2192195046bSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 2202195046bSStefano Stabellini 2212195046bSStefano Stabellini /* read req_id, then the content */ 2222195046bSStefano Stabellini smp_rmb(); 2232195046bSStefano Stabellini ret = bedata->rsp[req_id].ret; 2242195046bSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 2252195046bSStefano Stabellini 2262195046bSStefano Stabellini pvcalls_exit(); 2272195046bSStefano Stabellini return ret; 2282195046bSStefano Stabellini } 2292195046bSStefano Stabellini 230cb1c7d9bSStefano Stabellini static int create_active(struct sock_mapping *map, int *evtchn) 231cb1c7d9bSStefano Stabellini { 232cb1c7d9bSStefano Stabellini void *bytes; 233cb1c7d9bSStefano Stabellini int ret = -ENOMEM, irq = -1, i; 234cb1c7d9bSStefano Stabellini 235cb1c7d9bSStefano Stabellini *evtchn = -1; 236cb1c7d9bSStefano Stabellini init_waitqueue_head(&map->active.inflight_conn_req); 237cb1c7d9bSStefano Stabellini 238cb1c7d9bSStefano Stabellini map->active.ring = (struct pvcalls_data_intf *) 239cb1c7d9bSStefano Stabellini __get_free_page(GFP_KERNEL | __GFP_ZERO); 240cb1c7d9bSStefano Stabellini if (map->active.ring == NULL) 241cb1c7d9bSStefano Stabellini goto out_error; 242cb1c7d9bSStefano Stabellini map->active.ring->ring_order = PVCALLS_RING_ORDER; 243cb1c7d9bSStefano Stabellini bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 244cb1c7d9bSStefano Stabellini PVCALLS_RING_ORDER); 245cb1c7d9bSStefano Stabellini if (bytes == NULL) 246cb1c7d9bSStefano Stabellini goto out_error; 247cb1c7d9bSStefano Stabellini for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++) 248cb1c7d9bSStefano Stabellini map->active.ring->ref[i] = gnttab_grant_foreign_access( 249cb1c7d9bSStefano Stabellini pvcalls_front_dev->otherend_id, 250cb1c7d9bSStefano Stabellini pfn_to_gfn(virt_to_pfn(bytes) + i), 0); 251cb1c7d9bSStefano Stabellini 252cb1c7d9bSStefano Stabellini map->active.ref = gnttab_grant_foreign_access( 253cb1c7d9bSStefano Stabellini pvcalls_front_dev->otherend_id, 254cb1c7d9bSStefano Stabellini pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0); 255cb1c7d9bSStefano Stabellini 256cb1c7d9bSStefano Stabellini map->active.data.in = bytes; 257cb1c7d9bSStefano Stabellini map->active.data.out = bytes + 258cb1c7d9bSStefano Stabellini XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER); 259cb1c7d9bSStefano Stabellini 260cb1c7d9bSStefano Stabellini ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn); 261cb1c7d9bSStefano Stabellini if (ret) 262cb1c7d9bSStefano Stabellini goto out_error; 263cb1c7d9bSStefano Stabellini irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler, 264cb1c7d9bSStefano Stabellini 0, "pvcalls-frontend", map); 265cb1c7d9bSStefano Stabellini if (irq < 0) { 266cb1c7d9bSStefano Stabellini ret = irq; 267cb1c7d9bSStefano Stabellini goto out_error; 268cb1c7d9bSStefano Stabellini } 269cb1c7d9bSStefano Stabellini 270cb1c7d9bSStefano Stabellini map->active.irq = irq; 271cb1c7d9bSStefano Stabellini map->active_socket = true; 272cb1c7d9bSStefano Stabellini mutex_init(&map->active.in_mutex); 273cb1c7d9bSStefano Stabellini mutex_init(&map->active.out_mutex); 274cb1c7d9bSStefano Stabellini 275cb1c7d9bSStefano Stabellini return 0; 276cb1c7d9bSStefano Stabellini 277cb1c7d9bSStefano Stabellini out_error: 278cb1c7d9bSStefano Stabellini if (irq >= 0) 279cb1c7d9bSStefano Stabellini unbind_from_irqhandler(irq, map); 280cb1c7d9bSStefano Stabellini else if (*evtchn >= 0) 281cb1c7d9bSStefano Stabellini xenbus_free_evtchn(pvcalls_front_dev, *evtchn); 282cb1c7d9bSStefano Stabellini kfree(map->active.data.in); 283cb1c7d9bSStefano Stabellini kfree(map->active.ring); 284cb1c7d9bSStefano Stabellini return ret; 285cb1c7d9bSStefano Stabellini } 286cb1c7d9bSStefano Stabellini 287cb1c7d9bSStefano Stabellini int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr, 288cb1c7d9bSStefano Stabellini int addr_len, int flags) 289cb1c7d9bSStefano Stabellini { 290cb1c7d9bSStefano Stabellini struct pvcalls_bedata *bedata; 291cb1c7d9bSStefano Stabellini struct sock_mapping *map = NULL; 292cb1c7d9bSStefano Stabellini struct xen_pvcalls_request *req; 293cb1c7d9bSStefano Stabellini int notify, req_id, ret, evtchn; 294cb1c7d9bSStefano Stabellini 295cb1c7d9bSStefano Stabellini if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) 296cb1c7d9bSStefano Stabellini return -EOPNOTSUPP; 297cb1c7d9bSStefano Stabellini 298cb1c7d9bSStefano Stabellini pvcalls_enter(); 299cb1c7d9bSStefano Stabellini if (!pvcalls_front_dev) { 300cb1c7d9bSStefano Stabellini pvcalls_exit(); 301cb1c7d9bSStefano Stabellini return -ENOTCONN; 302cb1c7d9bSStefano Stabellini } 303cb1c7d9bSStefano Stabellini 304cb1c7d9bSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 305cb1c7d9bSStefano Stabellini 306cb1c7d9bSStefano Stabellini map = (struct sock_mapping *)sock->sk->sk_send_head; 307cb1c7d9bSStefano Stabellini if (!map) { 308cb1c7d9bSStefano Stabellini pvcalls_exit(); 309cb1c7d9bSStefano Stabellini return -ENOTSOCK; 310cb1c7d9bSStefano Stabellini } 311cb1c7d9bSStefano Stabellini 312cb1c7d9bSStefano Stabellini spin_lock(&bedata->socket_lock); 313cb1c7d9bSStefano Stabellini ret = get_request(bedata, &req_id); 314cb1c7d9bSStefano Stabellini if (ret < 0) { 315cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 316cb1c7d9bSStefano Stabellini pvcalls_exit(); 317cb1c7d9bSStefano Stabellini return ret; 318cb1c7d9bSStefano Stabellini } 319cb1c7d9bSStefano Stabellini ret = create_active(map, &evtchn); 320cb1c7d9bSStefano Stabellini if (ret < 0) { 321cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 322cb1c7d9bSStefano Stabellini pvcalls_exit(); 323cb1c7d9bSStefano Stabellini return ret; 324cb1c7d9bSStefano Stabellini } 325cb1c7d9bSStefano Stabellini 326cb1c7d9bSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 327cb1c7d9bSStefano Stabellini req->req_id = req_id; 328cb1c7d9bSStefano Stabellini req->cmd = PVCALLS_CONNECT; 329cb1c7d9bSStefano Stabellini req->u.connect.id = (uintptr_t)map; 330cb1c7d9bSStefano Stabellini req->u.connect.len = addr_len; 331cb1c7d9bSStefano Stabellini req->u.connect.flags = flags; 332cb1c7d9bSStefano Stabellini req->u.connect.ref = map->active.ref; 333cb1c7d9bSStefano Stabellini req->u.connect.evtchn = evtchn; 334cb1c7d9bSStefano Stabellini memcpy(req->u.connect.addr, addr, sizeof(*addr)); 335cb1c7d9bSStefano Stabellini 336cb1c7d9bSStefano Stabellini map->sock = sock; 337cb1c7d9bSStefano Stabellini 338cb1c7d9bSStefano Stabellini bedata->ring.req_prod_pvt++; 339cb1c7d9bSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 340cb1c7d9bSStefano Stabellini spin_unlock(&bedata->socket_lock); 341cb1c7d9bSStefano Stabellini 342cb1c7d9bSStefano Stabellini if (notify) 343cb1c7d9bSStefano Stabellini notify_remote_via_irq(bedata->irq); 344cb1c7d9bSStefano Stabellini 345cb1c7d9bSStefano Stabellini wait_event(bedata->inflight_req, 346cb1c7d9bSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 347cb1c7d9bSStefano Stabellini 348cb1c7d9bSStefano Stabellini /* read req_id, then the content */ 349cb1c7d9bSStefano Stabellini smp_rmb(); 350cb1c7d9bSStefano Stabellini ret = bedata->rsp[req_id].ret; 351cb1c7d9bSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 352cb1c7d9bSStefano Stabellini pvcalls_exit(); 353cb1c7d9bSStefano Stabellini return ret; 354cb1c7d9bSStefano Stabellini } 355cb1c7d9bSStefano Stabellini 356*67ea9893SStefano Stabellini int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 357*67ea9893SStefano Stabellini { 358*67ea9893SStefano Stabellini struct pvcalls_bedata *bedata; 359*67ea9893SStefano Stabellini struct sock_mapping *map = NULL; 360*67ea9893SStefano Stabellini struct xen_pvcalls_request *req; 361*67ea9893SStefano Stabellini int notify, req_id, ret; 362*67ea9893SStefano Stabellini 363*67ea9893SStefano Stabellini if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) 364*67ea9893SStefano Stabellini return -EOPNOTSUPP; 365*67ea9893SStefano Stabellini 366*67ea9893SStefano Stabellini pvcalls_enter(); 367*67ea9893SStefano Stabellini if (!pvcalls_front_dev) { 368*67ea9893SStefano Stabellini pvcalls_exit(); 369*67ea9893SStefano Stabellini return -ENOTCONN; 370*67ea9893SStefano Stabellini } 371*67ea9893SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 372*67ea9893SStefano Stabellini 373*67ea9893SStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 374*67ea9893SStefano Stabellini if (map == NULL) { 375*67ea9893SStefano Stabellini pvcalls_exit(); 376*67ea9893SStefano Stabellini return -ENOTSOCK; 377*67ea9893SStefano Stabellini } 378*67ea9893SStefano Stabellini 379*67ea9893SStefano Stabellini spin_lock(&bedata->socket_lock); 380*67ea9893SStefano Stabellini ret = get_request(bedata, &req_id); 381*67ea9893SStefano Stabellini if (ret < 0) { 382*67ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 383*67ea9893SStefano Stabellini pvcalls_exit(); 384*67ea9893SStefano Stabellini return ret; 385*67ea9893SStefano Stabellini } 386*67ea9893SStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 387*67ea9893SStefano Stabellini req->req_id = req_id; 388*67ea9893SStefano Stabellini map->sock = sock; 389*67ea9893SStefano Stabellini req->cmd = PVCALLS_BIND; 390*67ea9893SStefano Stabellini req->u.bind.id = (uintptr_t)map; 391*67ea9893SStefano Stabellini memcpy(req->u.bind.addr, addr, sizeof(*addr)); 392*67ea9893SStefano Stabellini req->u.bind.len = addr_len; 393*67ea9893SStefano Stabellini 394*67ea9893SStefano Stabellini map->active_socket = false; 395*67ea9893SStefano Stabellini 396*67ea9893SStefano Stabellini bedata->ring.req_prod_pvt++; 397*67ea9893SStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 398*67ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 399*67ea9893SStefano Stabellini if (notify) 400*67ea9893SStefano Stabellini notify_remote_via_irq(bedata->irq); 401*67ea9893SStefano Stabellini 402*67ea9893SStefano Stabellini wait_event(bedata->inflight_req, 403*67ea9893SStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 404*67ea9893SStefano Stabellini 405*67ea9893SStefano Stabellini /* read req_id, then the content */ 406*67ea9893SStefano Stabellini smp_rmb(); 407*67ea9893SStefano Stabellini ret = bedata->rsp[req_id].ret; 408*67ea9893SStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 409*67ea9893SStefano Stabellini 410*67ea9893SStefano Stabellini map->passive.status = PVCALLS_STATUS_BIND; 411*67ea9893SStefano Stabellini pvcalls_exit(); 412*67ea9893SStefano Stabellini return 0; 413*67ea9893SStefano Stabellini } 414*67ea9893SStefano Stabellini 415416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = { 416416efba0SStefano Stabellini { "pvcalls" }, 417416efba0SStefano Stabellini { "" } 418416efba0SStefano Stabellini }; 419416efba0SStefano Stabellini 420416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev) 421416efba0SStefano Stabellini { 422aa7ba376SStefano Stabellini struct pvcalls_bedata *bedata; 423aa7ba376SStefano Stabellini struct sock_mapping *map = NULL, *n; 424aa7ba376SStefano Stabellini 425aa7ba376SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 426aa7ba376SStefano Stabellini dev_set_drvdata(&dev->dev, NULL); 427aa7ba376SStefano Stabellini pvcalls_front_dev = NULL; 428aa7ba376SStefano Stabellini if (bedata->irq >= 0) 429aa7ba376SStefano Stabellini unbind_from_irqhandler(bedata->irq, dev); 430aa7ba376SStefano Stabellini 431cb1c7d9bSStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 432cb1c7d9bSStefano Stabellini map->sock->sk->sk_send_head = NULL; 433cb1c7d9bSStefano Stabellini if (map->active_socket) { 434cb1c7d9bSStefano Stabellini map->active.ring->in_error = -EBADF; 435cb1c7d9bSStefano Stabellini wake_up_interruptible(&map->active.inflight_conn_req); 436cb1c7d9bSStefano Stabellini } 437cb1c7d9bSStefano Stabellini } 438cb1c7d9bSStefano Stabellini 439aa7ba376SStefano Stabellini smp_mb(); 440aa7ba376SStefano Stabellini while (atomic_read(&pvcalls_refcount) > 0) 441aa7ba376SStefano Stabellini cpu_relax(); 442aa7ba376SStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 443aa7ba376SStefano Stabellini if (map->active_socket) { 444aa7ba376SStefano Stabellini /* No need to lock, refcount is 0 */ 445aa7ba376SStefano Stabellini pvcalls_front_free_map(bedata, map); 446aa7ba376SStefano Stabellini } else { 447aa7ba376SStefano Stabellini list_del(&map->list); 448aa7ba376SStefano Stabellini kfree(map); 449aa7ba376SStefano Stabellini } 450aa7ba376SStefano Stabellini } 451aa7ba376SStefano Stabellini if (bedata->ref >= 0) 452aa7ba376SStefano Stabellini gnttab_end_foreign_access(bedata->ref, 0, 0); 453aa7ba376SStefano Stabellini kfree(bedata->ring.sring); 454aa7ba376SStefano Stabellini kfree(bedata); 455aa7ba376SStefano Stabellini xenbus_switch_state(dev, XenbusStateClosed); 456416efba0SStefano Stabellini return 0; 457416efba0SStefano Stabellini } 458416efba0SStefano Stabellini 459416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev, 460416efba0SStefano Stabellini const struct xenbus_device_id *id) 461416efba0SStefano Stabellini { 46221968190SStefano Stabellini int ret = -ENOMEM, evtchn, i; 46321968190SStefano Stabellini unsigned int max_page_order, function_calls, len; 46421968190SStefano Stabellini char *versions; 46521968190SStefano Stabellini grant_ref_t gref_head = 0; 46621968190SStefano Stabellini struct xenbus_transaction xbt; 46721968190SStefano Stabellini struct pvcalls_bedata *bedata = NULL; 46821968190SStefano Stabellini struct xen_pvcalls_sring *sring; 46921968190SStefano Stabellini 47021968190SStefano Stabellini if (pvcalls_front_dev != NULL) { 47121968190SStefano Stabellini dev_err(&dev->dev, "only one PV Calls connection supported\n"); 47221968190SStefano Stabellini return -EINVAL; 47321968190SStefano Stabellini } 47421968190SStefano Stabellini 47521968190SStefano Stabellini versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); 47621968190SStefano Stabellini if (!len) 47721968190SStefano Stabellini return -EINVAL; 47821968190SStefano Stabellini if (strcmp(versions, "1")) { 47921968190SStefano Stabellini kfree(versions); 48021968190SStefano Stabellini return -EINVAL; 48121968190SStefano Stabellini } 48221968190SStefano Stabellini kfree(versions); 48321968190SStefano Stabellini max_page_order = xenbus_read_unsigned(dev->otherend, 48421968190SStefano Stabellini "max-page-order", 0); 48521968190SStefano Stabellini if (max_page_order < PVCALLS_RING_ORDER) 48621968190SStefano Stabellini return -ENODEV; 48721968190SStefano Stabellini function_calls = xenbus_read_unsigned(dev->otherend, 48821968190SStefano Stabellini "function-calls", 0); 48921968190SStefano Stabellini /* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */ 49021968190SStefano Stabellini if (function_calls != 1) 49121968190SStefano Stabellini return -ENODEV; 49221968190SStefano Stabellini pr_info("%s max-page-order is %u\n", __func__, max_page_order); 49321968190SStefano Stabellini 49421968190SStefano Stabellini bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL); 49521968190SStefano Stabellini if (!bedata) 49621968190SStefano Stabellini return -ENOMEM; 49721968190SStefano Stabellini 49821968190SStefano Stabellini dev_set_drvdata(&dev->dev, bedata); 49921968190SStefano Stabellini pvcalls_front_dev = dev; 50021968190SStefano Stabellini init_waitqueue_head(&bedata->inflight_req); 50121968190SStefano Stabellini INIT_LIST_HEAD(&bedata->socket_mappings); 50221968190SStefano Stabellini spin_lock_init(&bedata->socket_lock); 50321968190SStefano Stabellini bedata->irq = -1; 50421968190SStefano Stabellini bedata->ref = -1; 50521968190SStefano Stabellini 50621968190SStefano Stabellini for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++) 50721968190SStefano Stabellini bedata->rsp[i].req_id = PVCALLS_INVALID_ID; 50821968190SStefano Stabellini 50921968190SStefano Stabellini sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL | 51021968190SStefano Stabellini __GFP_ZERO); 51121968190SStefano Stabellini if (!sring) 51221968190SStefano Stabellini goto error; 51321968190SStefano Stabellini SHARED_RING_INIT(sring); 51421968190SStefano Stabellini FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE); 51521968190SStefano Stabellini 51621968190SStefano Stabellini ret = xenbus_alloc_evtchn(dev, &evtchn); 51721968190SStefano Stabellini if (ret) 51821968190SStefano Stabellini goto error; 51921968190SStefano Stabellini 52021968190SStefano Stabellini bedata->irq = bind_evtchn_to_irqhandler(evtchn, 52121968190SStefano Stabellini pvcalls_front_event_handler, 52221968190SStefano Stabellini 0, "pvcalls-frontend", dev); 52321968190SStefano Stabellini if (bedata->irq < 0) { 52421968190SStefano Stabellini ret = bedata->irq; 52521968190SStefano Stabellini goto error; 52621968190SStefano Stabellini } 52721968190SStefano Stabellini 52821968190SStefano Stabellini ret = gnttab_alloc_grant_references(1, &gref_head); 52921968190SStefano Stabellini if (ret < 0) 53021968190SStefano Stabellini goto error; 53121968190SStefano Stabellini bedata->ref = gnttab_claim_grant_reference(&gref_head); 53221968190SStefano Stabellini if (bedata->ref < 0) { 53321968190SStefano Stabellini ret = bedata->ref; 53421968190SStefano Stabellini goto error; 53521968190SStefano Stabellini } 53621968190SStefano Stabellini gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id, 53721968190SStefano Stabellini virt_to_gfn((void *)sring), 0); 53821968190SStefano Stabellini 53921968190SStefano Stabellini again: 54021968190SStefano Stabellini ret = xenbus_transaction_start(&xbt); 54121968190SStefano Stabellini if (ret) { 54221968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "starting transaction"); 54321968190SStefano Stabellini goto error; 54421968190SStefano Stabellini } 54521968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); 54621968190SStefano Stabellini if (ret) 54721968190SStefano Stabellini goto error_xenbus; 54821968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref); 54921968190SStefano Stabellini if (ret) 55021968190SStefano Stabellini goto error_xenbus; 55121968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "port", "%u", 55221968190SStefano Stabellini evtchn); 55321968190SStefano Stabellini if (ret) 55421968190SStefano Stabellini goto error_xenbus; 55521968190SStefano Stabellini ret = xenbus_transaction_end(xbt, 0); 55621968190SStefano Stabellini if (ret) { 55721968190SStefano Stabellini if (ret == -EAGAIN) 55821968190SStefano Stabellini goto again; 55921968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "completing transaction"); 56021968190SStefano Stabellini goto error; 56121968190SStefano Stabellini } 56221968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateInitialised); 56321968190SStefano Stabellini 564416efba0SStefano Stabellini return 0; 56521968190SStefano Stabellini 56621968190SStefano Stabellini error_xenbus: 56721968190SStefano Stabellini xenbus_transaction_end(xbt, 1); 56821968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "writing xenstore"); 56921968190SStefano Stabellini error: 57021968190SStefano Stabellini pvcalls_front_remove(dev); 57121968190SStefano Stabellini return ret; 572416efba0SStefano Stabellini } 573416efba0SStefano Stabellini 574416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev, 575416efba0SStefano Stabellini enum xenbus_state backend_state) 576416efba0SStefano Stabellini { 57721968190SStefano Stabellini switch (backend_state) { 57821968190SStefano Stabellini case XenbusStateReconfiguring: 57921968190SStefano Stabellini case XenbusStateReconfigured: 58021968190SStefano Stabellini case XenbusStateInitialising: 58121968190SStefano Stabellini case XenbusStateInitialised: 58221968190SStefano Stabellini case XenbusStateUnknown: 58321968190SStefano Stabellini break; 58421968190SStefano Stabellini 58521968190SStefano Stabellini case XenbusStateInitWait: 58621968190SStefano Stabellini break; 58721968190SStefano Stabellini 58821968190SStefano Stabellini case XenbusStateConnected: 58921968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateConnected); 59021968190SStefano Stabellini break; 59121968190SStefano Stabellini 59221968190SStefano Stabellini case XenbusStateClosed: 59321968190SStefano Stabellini if (dev->state == XenbusStateClosed) 59421968190SStefano Stabellini break; 59521968190SStefano Stabellini /* Missed the backend's CLOSING state -- fallthrough */ 59621968190SStefano Stabellini case XenbusStateClosing: 59721968190SStefano Stabellini xenbus_frontend_closed(dev); 59821968190SStefano Stabellini break; 59921968190SStefano Stabellini } 600416efba0SStefano Stabellini } 601416efba0SStefano Stabellini 602416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = { 603416efba0SStefano Stabellini .ids = pvcalls_front_ids, 604416efba0SStefano Stabellini .probe = pvcalls_front_probe, 605416efba0SStefano Stabellini .remove = pvcalls_front_remove, 606416efba0SStefano Stabellini .otherend_changed = pvcalls_front_changed, 607416efba0SStefano Stabellini }; 608416efba0SStefano Stabellini 609416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void) 610416efba0SStefano Stabellini { 611416efba0SStefano Stabellini if (!xen_domain()) 612416efba0SStefano Stabellini return -ENODEV; 613416efba0SStefano Stabellini 614416efba0SStefano Stabellini pr_info("Initialising Xen pvcalls frontend driver\n"); 615416efba0SStefano Stabellini 616416efba0SStefano Stabellini return xenbus_register_frontend(&pvcalls_front_driver); 617416efba0SStefano Stabellini } 618416efba0SStefano Stabellini 619416efba0SStefano Stabellini module_init(pvcalls_frontend_init); 620