xref: /openbmc/linux/drivers/xen/pvcalls-front.c (revision 9774c6cca26610d065a75d2ac8c5e3fcf0a209b3)
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