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; 7967ea9893SStefano 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 35667ea9893SStefano Stabellini int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len) 35767ea9893SStefano Stabellini { 35867ea9893SStefano Stabellini struct pvcalls_bedata *bedata; 35967ea9893SStefano Stabellini struct sock_mapping *map = NULL; 36067ea9893SStefano Stabellini struct xen_pvcalls_request *req; 36167ea9893SStefano Stabellini int notify, req_id, ret; 36267ea9893SStefano Stabellini 36367ea9893SStefano Stabellini if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM) 36467ea9893SStefano Stabellini return -EOPNOTSUPP; 36567ea9893SStefano Stabellini 36667ea9893SStefano Stabellini pvcalls_enter(); 36767ea9893SStefano Stabellini if (!pvcalls_front_dev) { 36867ea9893SStefano Stabellini pvcalls_exit(); 36967ea9893SStefano Stabellini return -ENOTCONN; 37067ea9893SStefano Stabellini } 37167ea9893SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 37267ea9893SStefano Stabellini 37367ea9893SStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 37467ea9893SStefano Stabellini if (map == NULL) { 37567ea9893SStefano Stabellini pvcalls_exit(); 37667ea9893SStefano Stabellini return -ENOTSOCK; 37767ea9893SStefano Stabellini } 37867ea9893SStefano Stabellini 37967ea9893SStefano Stabellini spin_lock(&bedata->socket_lock); 38067ea9893SStefano Stabellini ret = get_request(bedata, &req_id); 38167ea9893SStefano Stabellini if (ret < 0) { 38267ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 38367ea9893SStefano Stabellini pvcalls_exit(); 38467ea9893SStefano Stabellini return ret; 38567ea9893SStefano Stabellini } 38667ea9893SStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 38767ea9893SStefano Stabellini req->req_id = req_id; 38867ea9893SStefano Stabellini map->sock = sock; 38967ea9893SStefano Stabellini req->cmd = PVCALLS_BIND; 39067ea9893SStefano Stabellini req->u.bind.id = (uintptr_t)map; 39167ea9893SStefano Stabellini memcpy(req->u.bind.addr, addr, sizeof(*addr)); 39267ea9893SStefano Stabellini req->u.bind.len = addr_len; 39367ea9893SStefano Stabellini 39467ea9893SStefano Stabellini map->active_socket = false; 39567ea9893SStefano Stabellini 39667ea9893SStefano Stabellini bedata->ring.req_prod_pvt++; 39767ea9893SStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 39867ea9893SStefano Stabellini spin_unlock(&bedata->socket_lock); 39967ea9893SStefano Stabellini if (notify) 40067ea9893SStefano Stabellini notify_remote_via_irq(bedata->irq); 40167ea9893SStefano Stabellini 40267ea9893SStefano Stabellini wait_event(bedata->inflight_req, 40367ea9893SStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 40467ea9893SStefano Stabellini 40567ea9893SStefano Stabellini /* read req_id, then the content */ 40667ea9893SStefano Stabellini smp_rmb(); 40767ea9893SStefano Stabellini ret = bedata->rsp[req_id].ret; 40867ea9893SStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 40967ea9893SStefano Stabellini 41067ea9893SStefano Stabellini map->passive.status = PVCALLS_STATUS_BIND; 41167ea9893SStefano Stabellini pvcalls_exit(); 41267ea9893SStefano Stabellini return 0; 41367ea9893SStefano Stabellini } 41467ea9893SStefano Stabellini 415*1853f11dSStefano Stabellini int pvcalls_front_listen(struct socket *sock, int backlog) 416*1853f11dSStefano Stabellini { 417*1853f11dSStefano Stabellini struct pvcalls_bedata *bedata; 418*1853f11dSStefano Stabellini struct sock_mapping *map; 419*1853f11dSStefano Stabellini struct xen_pvcalls_request *req; 420*1853f11dSStefano Stabellini int notify, req_id, ret; 421*1853f11dSStefano Stabellini 422*1853f11dSStefano Stabellini pvcalls_enter(); 423*1853f11dSStefano Stabellini if (!pvcalls_front_dev) { 424*1853f11dSStefano Stabellini pvcalls_exit(); 425*1853f11dSStefano Stabellini return -ENOTCONN; 426*1853f11dSStefano Stabellini } 427*1853f11dSStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 428*1853f11dSStefano Stabellini 429*1853f11dSStefano Stabellini map = (struct sock_mapping *) sock->sk->sk_send_head; 430*1853f11dSStefano Stabellini if (!map) { 431*1853f11dSStefano Stabellini pvcalls_exit(); 432*1853f11dSStefano Stabellini return -ENOTSOCK; 433*1853f11dSStefano Stabellini } 434*1853f11dSStefano Stabellini 435*1853f11dSStefano Stabellini if (map->passive.status != PVCALLS_STATUS_BIND) { 436*1853f11dSStefano Stabellini pvcalls_exit(); 437*1853f11dSStefano Stabellini return -EOPNOTSUPP; 438*1853f11dSStefano Stabellini } 439*1853f11dSStefano Stabellini 440*1853f11dSStefano Stabellini spin_lock(&bedata->socket_lock); 441*1853f11dSStefano Stabellini ret = get_request(bedata, &req_id); 442*1853f11dSStefano Stabellini if (ret < 0) { 443*1853f11dSStefano Stabellini spin_unlock(&bedata->socket_lock); 444*1853f11dSStefano Stabellini pvcalls_exit(); 445*1853f11dSStefano Stabellini return ret; 446*1853f11dSStefano Stabellini } 447*1853f11dSStefano Stabellini req = RING_GET_REQUEST(&bedata->ring, req_id); 448*1853f11dSStefano Stabellini req->req_id = req_id; 449*1853f11dSStefano Stabellini req->cmd = PVCALLS_LISTEN; 450*1853f11dSStefano Stabellini req->u.listen.id = (uintptr_t) map; 451*1853f11dSStefano Stabellini req->u.listen.backlog = backlog; 452*1853f11dSStefano Stabellini 453*1853f11dSStefano Stabellini bedata->ring.req_prod_pvt++; 454*1853f11dSStefano Stabellini RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify); 455*1853f11dSStefano Stabellini spin_unlock(&bedata->socket_lock); 456*1853f11dSStefano Stabellini if (notify) 457*1853f11dSStefano Stabellini notify_remote_via_irq(bedata->irq); 458*1853f11dSStefano Stabellini 459*1853f11dSStefano Stabellini wait_event(bedata->inflight_req, 460*1853f11dSStefano Stabellini READ_ONCE(bedata->rsp[req_id].req_id) == req_id); 461*1853f11dSStefano Stabellini 462*1853f11dSStefano Stabellini /* read req_id, then the content */ 463*1853f11dSStefano Stabellini smp_rmb(); 464*1853f11dSStefano Stabellini ret = bedata->rsp[req_id].ret; 465*1853f11dSStefano Stabellini bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID; 466*1853f11dSStefano Stabellini 467*1853f11dSStefano Stabellini map->passive.status = PVCALLS_STATUS_LISTEN; 468*1853f11dSStefano Stabellini pvcalls_exit(); 469*1853f11dSStefano Stabellini return ret; 470*1853f11dSStefano Stabellini } 471*1853f11dSStefano Stabellini 472416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = { 473416efba0SStefano Stabellini { "pvcalls" }, 474416efba0SStefano Stabellini { "" } 475416efba0SStefano Stabellini }; 476416efba0SStefano Stabellini 477416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev) 478416efba0SStefano Stabellini { 479aa7ba376SStefano Stabellini struct pvcalls_bedata *bedata; 480aa7ba376SStefano Stabellini struct sock_mapping *map = NULL, *n; 481aa7ba376SStefano Stabellini 482aa7ba376SStefano Stabellini bedata = dev_get_drvdata(&pvcalls_front_dev->dev); 483aa7ba376SStefano Stabellini dev_set_drvdata(&dev->dev, NULL); 484aa7ba376SStefano Stabellini pvcalls_front_dev = NULL; 485aa7ba376SStefano Stabellini if (bedata->irq >= 0) 486aa7ba376SStefano Stabellini unbind_from_irqhandler(bedata->irq, dev); 487aa7ba376SStefano Stabellini 488cb1c7d9bSStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 489cb1c7d9bSStefano Stabellini map->sock->sk->sk_send_head = NULL; 490cb1c7d9bSStefano Stabellini if (map->active_socket) { 491cb1c7d9bSStefano Stabellini map->active.ring->in_error = -EBADF; 492cb1c7d9bSStefano Stabellini wake_up_interruptible(&map->active.inflight_conn_req); 493cb1c7d9bSStefano Stabellini } 494cb1c7d9bSStefano Stabellini } 495cb1c7d9bSStefano Stabellini 496aa7ba376SStefano Stabellini smp_mb(); 497aa7ba376SStefano Stabellini while (atomic_read(&pvcalls_refcount) > 0) 498aa7ba376SStefano Stabellini cpu_relax(); 499aa7ba376SStefano Stabellini list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) { 500aa7ba376SStefano Stabellini if (map->active_socket) { 501aa7ba376SStefano Stabellini /* No need to lock, refcount is 0 */ 502aa7ba376SStefano Stabellini pvcalls_front_free_map(bedata, map); 503aa7ba376SStefano Stabellini } else { 504aa7ba376SStefano Stabellini list_del(&map->list); 505aa7ba376SStefano Stabellini kfree(map); 506aa7ba376SStefano Stabellini } 507aa7ba376SStefano Stabellini } 508aa7ba376SStefano Stabellini if (bedata->ref >= 0) 509aa7ba376SStefano Stabellini gnttab_end_foreign_access(bedata->ref, 0, 0); 510aa7ba376SStefano Stabellini kfree(bedata->ring.sring); 511aa7ba376SStefano Stabellini kfree(bedata); 512aa7ba376SStefano Stabellini xenbus_switch_state(dev, XenbusStateClosed); 513416efba0SStefano Stabellini return 0; 514416efba0SStefano Stabellini } 515416efba0SStefano Stabellini 516416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev, 517416efba0SStefano Stabellini const struct xenbus_device_id *id) 518416efba0SStefano Stabellini { 51921968190SStefano Stabellini int ret = -ENOMEM, evtchn, i; 52021968190SStefano Stabellini unsigned int max_page_order, function_calls, len; 52121968190SStefano Stabellini char *versions; 52221968190SStefano Stabellini grant_ref_t gref_head = 0; 52321968190SStefano Stabellini struct xenbus_transaction xbt; 52421968190SStefano Stabellini struct pvcalls_bedata *bedata = NULL; 52521968190SStefano Stabellini struct xen_pvcalls_sring *sring; 52621968190SStefano Stabellini 52721968190SStefano Stabellini if (pvcalls_front_dev != NULL) { 52821968190SStefano Stabellini dev_err(&dev->dev, "only one PV Calls connection supported\n"); 52921968190SStefano Stabellini return -EINVAL; 53021968190SStefano Stabellini } 53121968190SStefano Stabellini 53221968190SStefano Stabellini versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len); 53321968190SStefano Stabellini if (!len) 53421968190SStefano Stabellini return -EINVAL; 53521968190SStefano Stabellini if (strcmp(versions, "1")) { 53621968190SStefano Stabellini kfree(versions); 53721968190SStefano Stabellini return -EINVAL; 53821968190SStefano Stabellini } 53921968190SStefano Stabellini kfree(versions); 54021968190SStefano Stabellini max_page_order = xenbus_read_unsigned(dev->otherend, 54121968190SStefano Stabellini "max-page-order", 0); 54221968190SStefano Stabellini if (max_page_order < PVCALLS_RING_ORDER) 54321968190SStefano Stabellini return -ENODEV; 54421968190SStefano Stabellini function_calls = xenbus_read_unsigned(dev->otherend, 54521968190SStefano Stabellini "function-calls", 0); 54621968190SStefano Stabellini /* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */ 54721968190SStefano Stabellini if (function_calls != 1) 54821968190SStefano Stabellini return -ENODEV; 54921968190SStefano Stabellini pr_info("%s max-page-order is %u\n", __func__, max_page_order); 55021968190SStefano Stabellini 55121968190SStefano Stabellini bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL); 55221968190SStefano Stabellini if (!bedata) 55321968190SStefano Stabellini return -ENOMEM; 55421968190SStefano Stabellini 55521968190SStefano Stabellini dev_set_drvdata(&dev->dev, bedata); 55621968190SStefano Stabellini pvcalls_front_dev = dev; 55721968190SStefano Stabellini init_waitqueue_head(&bedata->inflight_req); 55821968190SStefano Stabellini INIT_LIST_HEAD(&bedata->socket_mappings); 55921968190SStefano Stabellini spin_lock_init(&bedata->socket_lock); 56021968190SStefano Stabellini bedata->irq = -1; 56121968190SStefano Stabellini bedata->ref = -1; 56221968190SStefano Stabellini 56321968190SStefano Stabellini for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++) 56421968190SStefano Stabellini bedata->rsp[i].req_id = PVCALLS_INVALID_ID; 56521968190SStefano Stabellini 56621968190SStefano Stabellini sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL | 56721968190SStefano Stabellini __GFP_ZERO); 56821968190SStefano Stabellini if (!sring) 56921968190SStefano Stabellini goto error; 57021968190SStefano Stabellini SHARED_RING_INIT(sring); 57121968190SStefano Stabellini FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE); 57221968190SStefano Stabellini 57321968190SStefano Stabellini ret = xenbus_alloc_evtchn(dev, &evtchn); 57421968190SStefano Stabellini if (ret) 57521968190SStefano Stabellini goto error; 57621968190SStefano Stabellini 57721968190SStefano Stabellini bedata->irq = bind_evtchn_to_irqhandler(evtchn, 57821968190SStefano Stabellini pvcalls_front_event_handler, 57921968190SStefano Stabellini 0, "pvcalls-frontend", dev); 58021968190SStefano Stabellini if (bedata->irq < 0) { 58121968190SStefano Stabellini ret = bedata->irq; 58221968190SStefano Stabellini goto error; 58321968190SStefano Stabellini } 58421968190SStefano Stabellini 58521968190SStefano Stabellini ret = gnttab_alloc_grant_references(1, &gref_head); 58621968190SStefano Stabellini if (ret < 0) 58721968190SStefano Stabellini goto error; 58821968190SStefano Stabellini bedata->ref = gnttab_claim_grant_reference(&gref_head); 58921968190SStefano Stabellini if (bedata->ref < 0) { 59021968190SStefano Stabellini ret = bedata->ref; 59121968190SStefano Stabellini goto error; 59221968190SStefano Stabellini } 59321968190SStefano Stabellini gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id, 59421968190SStefano Stabellini virt_to_gfn((void *)sring), 0); 59521968190SStefano Stabellini 59621968190SStefano Stabellini again: 59721968190SStefano Stabellini ret = xenbus_transaction_start(&xbt); 59821968190SStefano Stabellini if (ret) { 59921968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "starting transaction"); 60021968190SStefano Stabellini goto error; 60121968190SStefano Stabellini } 60221968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1); 60321968190SStefano Stabellini if (ret) 60421968190SStefano Stabellini goto error_xenbus; 60521968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref); 60621968190SStefano Stabellini if (ret) 60721968190SStefano Stabellini goto error_xenbus; 60821968190SStefano Stabellini ret = xenbus_printf(xbt, dev->nodename, "port", "%u", 60921968190SStefano Stabellini evtchn); 61021968190SStefano Stabellini if (ret) 61121968190SStefano Stabellini goto error_xenbus; 61221968190SStefano Stabellini ret = xenbus_transaction_end(xbt, 0); 61321968190SStefano Stabellini if (ret) { 61421968190SStefano Stabellini if (ret == -EAGAIN) 61521968190SStefano Stabellini goto again; 61621968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "completing transaction"); 61721968190SStefano Stabellini goto error; 61821968190SStefano Stabellini } 61921968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateInitialised); 62021968190SStefano Stabellini 621416efba0SStefano Stabellini return 0; 62221968190SStefano Stabellini 62321968190SStefano Stabellini error_xenbus: 62421968190SStefano Stabellini xenbus_transaction_end(xbt, 1); 62521968190SStefano Stabellini xenbus_dev_fatal(dev, ret, "writing xenstore"); 62621968190SStefano Stabellini error: 62721968190SStefano Stabellini pvcalls_front_remove(dev); 62821968190SStefano Stabellini return ret; 629416efba0SStefano Stabellini } 630416efba0SStefano Stabellini 631416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev, 632416efba0SStefano Stabellini enum xenbus_state backend_state) 633416efba0SStefano Stabellini { 63421968190SStefano Stabellini switch (backend_state) { 63521968190SStefano Stabellini case XenbusStateReconfiguring: 63621968190SStefano Stabellini case XenbusStateReconfigured: 63721968190SStefano Stabellini case XenbusStateInitialising: 63821968190SStefano Stabellini case XenbusStateInitialised: 63921968190SStefano Stabellini case XenbusStateUnknown: 64021968190SStefano Stabellini break; 64121968190SStefano Stabellini 64221968190SStefano Stabellini case XenbusStateInitWait: 64321968190SStefano Stabellini break; 64421968190SStefano Stabellini 64521968190SStefano Stabellini case XenbusStateConnected: 64621968190SStefano Stabellini xenbus_switch_state(dev, XenbusStateConnected); 64721968190SStefano Stabellini break; 64821968190SStefano Stabellini 64921968190SStefano Stabellini case XenbusStateClosed: 65021968190SStefano Stabellini if (dev->state == XenbusStateClosed) 65121968190SStefano Stabellini break; 65221968190SStefano Stabellini /* Missed the backend's CLOSING state -- fallthrough */ 65321968190SStefano Stabellini case XenbusStateClosing: 65421968190SStefano Stabellini xenbus_frontend_closed(dev); 65521968190SStefano Stabellini break; 65621968190SStefano Stabellini } 657416efba0SStefano Stabellini } 658416efba0SStefano Stabellini 659416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = { 660416efba0SStefano Stabellini .ids = pvcalls_front_ids, 661416efba0SStefano Stabellini .probe = pvcalls_front_probe, 662416efba0SStefano Stabellini .remove = pvcalls_front_remove, 663416efba0SStefano Stabellini .otherend_changed = pvcalls_front_changed, 664416efba0SStefano Stabellini }; 665416efba0SStefano Stabellini 666416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void) 667416efba0SStefano Stabellini { 668416efba0SStefano Stabellini if (!xen_domain()) 669416efba0SStefano Stabellini return -ENODEV; 670416efba0SStefano Stabellini 671416efba0SStefano Stabellini pr_info("Initialising Xen pvcalls frontend driver\n"); 672416efba0SStefano Stabellini 673416efba0SStefano Stabellini return xenbus_register_frontend(&pvcalls_front_driver); 674416efba0SStefano Stabellini } 675416efba0SStefano Stabellini 676416efba0SStefano Stabellini module_init(pvcalls_frontend_init); 677