xref: /openbmc/linux/drivers/xen/pvcalls-front.c (revision cb1c7d9bbc878a67af270ccd2d23f6d1450579db)
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;
62*cb1c7d9bSStefano Stabellini 	union {
63*cb1c7d9bSStefano Stabellini 		struct {
64*cb1c7d9bSStefano Stabellini 			int irq;
65*cb1c7d9bSStefano Stabellini 			grant_ref_t ref;
66*cb1c7d9bSStefano Stabellini 			struct pvcalls_data_intf *ring;
67*cb1c7d9bSStefano Stabellini 			struct pvcalls_data data;
68*cb1c7d9bSStefano Stabellini 			struct mutex in_mutex;
69*cb1c7d9bSStefano Stabellini 			struct mutex out_mutex;
70*cb1c7d9bSStefano Stabellini 
71*cb1c7d9bSStefano Stabellini 			wait_queue_head_t inflight_conn_req;
72*cb1c7d9bSStefano Stabellini 		} active;
73*cb1c7d9bSStefano Stabellini 	};
74aa7ba376SStefano Stabellini };
75aa7ba376SStefano Stabellini 
762195046bSStefano Stabellini static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
772195046bSStefano Stabellini {
782195046bSStefano Stabellini 	*req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
792195046bSStefano Stabellini 	if (RING_FULL(&bedata->ring) ||
802195046bSStefano Stabellini 	    bedata->rsp[*req_id].req_id != PVCALLS_INVALID_ID)
812195046bSStefano Stabellini 		return -EAGAIN;
822195046bSStefano Stabellini 	return 0;
832195046bSStefano Stabellini }
842195046bSStefano Stabellini 
85aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
86aa7ba376SStefano Stabellini {
872195046bSStefano Stabellini 	struct xenbus_device *dev = dev_id;
882195046bSStefano Stabellini 	struct pvcalls_bedata *bedata;
892195046bSStefano Stabellini 	struct xen_pvcalls_response *rsp;
902195046bSStefano Stabellini 	uint8_t *src, *dst;
912195046bSStefano Stabellini 	int req_id = 0, more = 0, done = 0;
922195046bSStefano Stabellini 
932195046bSStefano Stabellini 	if (dev == NULL)
942195046bSStefano Stabellini 		return IRQ_HANDLED;
952195046bSStefano Stabellini 
962195046bSStefano Stabellini 	pvcalls_enter();
972195046bSStefano Stabellini 	bedata = dev_get_drvdata(&dev->dev);
982195046bSStefano Stabellini 	if (bedata == NULL) {
992195046bSStefano Stabellini 		pvcalls_exit();
1002195046bSStefano Stabellini 		return IRQ_HANDLED;
1012195046bSStefano Stabellini 	}
1022195046bSStefano Stabellini 
1032195046bSStefano Stabellini again:
1042195046bSStefano Stabellini 	while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
1052195046bSStefano Stabellini 		rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
1062195046bSStefano Stabellini 
1072195046bSStefano Stabellini 		req_id = rsp->req_id;
1082195046bSStefano Stabellini 		dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id);
1092195046bSStefano Stabellini 		src = (uint8_t *)rsp + sizeof(rsp->req_id);
1102195046bSStefano Stabellini 		memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id));
1112195046bSStefano Stabellini 		/*
1122195046bSStefano Stabellini 		 * First copy the rest of the data, then req_id. It is
1132195046bSStefano Stabellini 		 * paired with the barrier when accessing bedata->rsp.
1142195046bSStefano Stabellini 		 */
1152195046bSStefano Stabellini 		smp_wmb();
1162195046bSStefano Stabellini 		bedata->rsp[req_id].req_id = rsp->req_id;
1172195046bSStefano Stabellini 
1182195046bSStefano Stabellini 		done = 1;
1192195046bSStefano Stabellini 		bedata->ring.rsp_cons++;
1202195046bSStefano Stabellini 	}
1212195046bSStefano Stabellini 
1222195046bSStefano Stabellini 	RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
1232195046bSStefano Stabellini 	if (more)
1242195046bSStefano Stabellini 		goto again;
1252195046bSStefano Stabellini 	if (done)
1262195046bSStefano Stabellini 		wake_up(&bedata->inflight_req);
1272195046bSStefano Stabellini 	pvcalls_exit();
128aa7ba376SStefano Stabellini 	return IRQ_HANDLED;
129aa7ba376SStefano Stabellini }
130aa7ba376SStefano Stabellini 
131aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
132aa7ba376SStefano Stabellini 				   struct sock_mapping *map)
133aa7ba376SStefano Stabellini {
134aa7ba376SStefano Stabellini }
135aa7ba376SStefano Stabellini 
136*cb1c7d9bSStefano Stabellini static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
137*cb1c7d9bSStefano Stabellini {
138*cb1c7d9bSStefano Stabellini 	struct sock_mapping *map = sock_map;
139*cb1c7d9bSStefano Stabellini 
140*cb1c7d9bSStefano Stabellini 	if (map == NULL)
141*cb1c7d9bSStefano Stabellini 		return IRQ_HANDLED;
142*cb1c7d9bSStefano Stabellini 
143*cb1c7d9bSStefano Stabellini 	wake_up_interruptible(&map->active.inflight_conn_req);
144*cb1c7d9bSStefano Stabellini 
145*cb1c7d9bSStefano Stabellini 	return IRQ_HANDLED;
146*cb1c7d9bSStefano Stabellini }
147*cb1c7d9bSStefano Stabellini 
1482195046bSStefano Stabellini int pvcalls_front_socket(struct socket *sock)
1492195046bSStefano Stabellini {
1502195046bSStefano Stabellini 	struct pvcalls_bedata *bedata;
1512195046bSStefano Stabellini 	struct sock_mapping *map = NULL;
1522195046bSStefano Stabellini 	struct xen_pvcalls_request *req;
1532195046bSStefano Stabellini 	int notify, req_id, ret;
1542195046bSStefano Stabellini 
1552195046bSStefano Stabellini 	/*
1562195046bSStefano Stabellini 	 * PVCalls only supports domain AF_INET,
1572195046bSStefano Stabellini 	 * type SOCK_STREAM and protocol 0 sockets for now.
1582195046bSStefano Stabellini 	 *
1592195046bSStefano Stabellini 	 * Check socket type here, AF_INET and protocol checks are done
1602195046bSStefano Stabellini 	 * by the caller.
1612195046bSStefano Stabellini 	 */
1622195046bSStefano Stabellini 	if (sock->type != SOCK_STREAM)
1632195046bSStefano Stabellini 		return -EOPNOTSUPP;
1642195046bSStefano Stabellini 
1652195046bSStefano Stabellini 	pvcalls_enter();
1662195046bSStefano Stabellini 	if (!pvcalls_front_dev) {
1672195046bSStefano Stabellini 		pvcalls_exit();
1682195046bSStefano Stabellini 		return -EACCES;
1692195046bSStefano Stabellini 	}
1702195046bSStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
1712195046bSStefano Stabellini 
1722195046bSStefano Stabellini 	map = kzalloc(sizeof(*map), GFP_KERNEL);
1732195046bSStefano Stabellini 	if (map == NULL) {
1742195046bSStefano Stabellini 		pvcalls_exit();
1752195046bSStefano Stabellini 		return -ENOMEM;
1762195046bSStefano Stabellini 	}
1772195046bSStefano Stabellini 
1782195046bSStefano Stabellini 	spin_lock(&bedata->socket_lock);
1792195046bSStefano Stabellini 
1802195046bSStefano Stabellini 	ret = get_request(bedata, &req_id);
1812195046bSStefano Stabellini 	if (ret < 0) {
1822195046bSStefano Stabellini 		kfree(map);
1832195046bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
1842195046bSStefano Stabellini 		pvcalls_exit();
1852195046bSStefano Stabellini 		return ret;
1862195046bSStefano Stabellini 	}
1872195046bSStefano Stabellini 
1882195046bSStefano Stabellini 	/*
1892195046bSStefano Stabellini 	 * sock->sk->sk_send_head is not used for ip sockets: reuse the
1902195046bSStefano Stabellini 	 * field to store a pointer to the struct sock_mapping
1912195046bSStefano Stabellini 	 * corresponding to the socket. This way, we can easily get the
1922195046bSStefano Stabellini 	 * struct sock_mapping from the struct socket.
1932195046bSStefano Stabellini 	 */
1942195046bSStefano Stabellini 	sock->sk->sk_send_head = (void *)map;
1952195046bSStefano Stabellini 	list_add_tail(&map->list, &bedata->socket_mappings);
1962195046bSStefano Stabellini 
1972195046bSStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
1982195046bSStefano Stabellini 	req->req_id = req_id;
1992195046bSStefano Stabellini 	req->cmd = PVCALLS_SOCKET;
2002195046bSStefano Stabellini 	req->u.socket.id = (uintptr_t) map;
2012195046bSStefano Stabellini 	req->u.socket.domain = AF_INET;
2022195046bSStefano Stabellini 	req->u.socket.type = SOCK_STREAM;
2032195046bSStefano Stabellini 	req->u.socket.protocol = IPPROTO_IP;
2042195046bSStefano Stabellini 
2052195046bSStefano Stabellini 	bedata->ring.req_prod_pvt++;
2062195046bSStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
2072195046bSStefano Stabellini 	spin_unlock(&bedata->socket_lock);
2082195046bSStefano Stabellini 	if (notify)
2092195046bSStefano Stabellini 		notify_remote_via_irq(bedata->irq);
2102195046bSStefano Stabellini 
2112195046bSStefano Stabellini 	wait_event(bedata->inflight_req,
2122195046bSStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
2132195046bSStefano Stabellini 
2142195046bSStefano Stabellini 	/* read req_id, then the content */
2152195046bSStefano Stabellini 	smp_rmb();
2162195046bSStefano Stabellini 	ret = bedata->rsp[req_id].ret;
2172195046bSStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
2182195046bSStefano Stabellini 
2192195046bSStefano Stabellini 	pvcalls_exit();
2202195046bSStefano Stabellini 	return ret;
2212195046bSStefano Stabellini }
2222195046bSStefano Stabellini 
223*cb1c7d9bSStefano Stabellini static int create_active(struct sock_mapping *map, int *evtchn)
224*cb1c7d9bSStefano Stabellini {
225*cb1c7d9bSStefano Stabellini 	void *bytes;
226*cb1c7d9bSStefano Stabellini 	int ret = -ENOMEM, irq = -1, i;
227*cb1c7d9bSStefano Stabellini 
228*cb1c7d9bSStefano Stabellini 	*evtchn = -1;
229*cb1c7d9bSStefano Stabellini 	init_waitqueue_head(&map->active.inflight_conn_req);
230*cb1c7d9bSStefano Stabellini 
231*cb1c7d9bSStefano Stabellini 	map->active.ring = (struct pvcalls_data_intf *)
232*cb1c7d9bSStefano Stabellini 		__get_free_page(GFP_KERNEL | __GFP_ZERO);
233*cb1c7d9bSStefano Stabellini 	if (map->active.ring == NULL)
234*cb1c7d9bSStefano Stabellini 		goto out_error;
235*cb1c7d9bSStefano Stabellini 	map->active.ring->ring_order = PVCALLS_RING_ORDER;
236*cb1c7d9bSStefano Stabellini 	bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
237*cb1c7d9bSStefano Stabellini 					PVCALLS_RING_ORDER);
238*cb1c7d9bSStefano Stabellini 	if (bytes == NULL)
239*cb1c7d9bSStefano Stabellini 		goto out_error;
240*cb1c7d9bSStefano Stabellini 	for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
241*cb1c7d9bSStefano Stabellini 		map->active.ring->ref[i] = gnttab_grant_foreign_access(
242*cb1c7d9bSStefano Stabellini 			pvcalls_front_dev->otherend_id,
243*cb1c7d9bSStefano Stabellini 			pfn_to_gfn(virt_to_pfn(bytes) + i), 0);
244*cb1c7d9bSStefano Stabellini 
245*cb1c7d9bSStefano Stabellini 	map->active.ref = gnttab_grant_foreign_access(
246*cb1c7d9bSStefano Stabellini 		pvcalls_front_dev->otherend_id,
247*cb1c7d9bSStefano Stabellini 		pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
248*cb1c7d9bSStefano Stabellini 
249*cb1c7d9bSStefano Stabellini 	map->active.data.in = bytes;
250*cb1c7d9bSStefano Stabellini 	map->active.data.out = bytes +
251*cb1c7d9bSStefano Stabellini 		XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER);
252*cb1c7d9bSStefano Stabellini 
253*cb1c7d9bSStefano Stabellini 	ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
254*cb1c7d9bSStefano Stabellini 	if (ret)
255*cb1c7d9bSStefano Stabellini 		goto out_error;
256*cb1c7d9bSStefano Stabellini 	irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler,
257*cb1c7d9bSStefano Stabellini 					0, "pvcalls-frontend", map);
258*cb1c7d9bSStefano Stabellini 	if (irq < 0) {
259*cb1c7d9bSStefano Stabellini 		ret = irq;
260*cb1c7d9bSStefano Stabellini 		goto out_error;
261*cb1c7d9bSStefano Stabellini 	}
262*cb1c7d9bSStefano Stabellini 
263*cb1c7d9bSStefano Stabellini 	map->active.irq = irq;
264*cb1c7d9bSStefano Stabellini 	map->active_socket = true;
265*cb1c7d9bSStefano Stabellini 	mutex_init(&map->active.in_mutex);
266*cb1c7d9bSStefano Stabellini 	mutex_init(&map->active.out_mutex);
267*cb1c7d9bSStefano Stabellini 
268*cb1c7d9bSStefano Stabellini 	return 0;
269*cb1c7d9bSStefano Stabellini 
270*cb1c7d9bSStefano Stabellini out_error:
271*cb1c7d9bSStefano Stabellini 	if (irq >= 0)
272*cb1c7d9bSStefano Stabellini 		unbind_from_irqhandler(irq, map);
273*cb1c7d9bSStefano Stabellini 	else if (*evtchn >= 0)
274*cb1c7d9bSStefano Stabellini 		xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
275*cb1c7d9bSStefano Stabellini 	kfree(map->active.data.in);
276*cb1c7d9bSStefano Stabellini 	kfree(map->active.ring);
277*cb1c7d9bSStefano Stabellini 	return ret;
278*cb1c7d9bSStefano Stabellini }
279*cb1c7d9bSStefano Stabellini 
280*cb1c7d9bSStefano Stabellini int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
281*cb1c7d9bSStefano Stabellini 				int addr_len, int flags)
282*cb1c7d9bSStefano Stabellini {
283*cb1c7d9bSStefano Stabellini 	struct pvcalls_bedata *bedata;
284*cb1c7d9bSStefano Stabellini 	struct sock_mapping *map = NULL;
285*cb1c7d9bSStefano Stabellini 	struct xen_pvcalls_request *req;
286*cb1c7d9bSStefano Stabellini 	int notify, req_id, ret, evtchn;
287*cb1c7d9bSStefano Stabellini 
288*cb1c7d9bSStefano Stabellini 	if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
289*cb1c7d9bSStefano Stabellini 		return -EOPNOTSUPP;
290*cb1c7d9bSStefano Stabellini 
291*cb1c7d9bSStefano Stabellini 	pvcalls_enter();
292*cb1c7d9bSStefano Stabellini 	if (!pvcalls_front_dev) {
293*cb1c7d9bSStefano Stabellini 		pvcalls_exit();
294*cb1c7d9bSStefano Stabellini 		return -ENOTCONN;
295*cb1c7d9bSStefano Stabellini 	}
296*cb1c7d9bSStefano Stabellini 
297*cb1c7d9bSStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
298*cb1c7d9bSStefano Stabellini 
299*cb1c7d9bSStefano Stabellini 	map = (struct sock_mapping *)sock->sk->sk_send_head;
300*cb1c7d9bSStefano Stabellini 	if (!map) {
301*cb1c7d9bSStefano Stabellini 		pvcalls_exit();
302*cb1c7d9bSStefano Stabellini 		return -ENOTSOCK;
303*cb1c7d9bSStefano Stabellini 	}
304*cb1c7d9bSStefano Stabellini 
305*cb1c7d9bSStefano Stabellini 	spin_lock(&bedata->socket_lock);
306*cb1c7d9bSStefano Stabellini 	ret = get_request(bedata, &req_id);
307*cb1c7d9bSStefano Stabellini 	if (ret < 0) {
308*cb1c7d9bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
309*cb1c7d9bSStefano Stabellini 		pvcalls_exit();
310*cb1c7d9bSStefano Stabellini 		return ret;
311*cb1c7d9bSStefano Stabellini 	}
312*cb1c7d9bSStefano Stabellini 	ret = create_active(map, &evtchn);
313*cb1c7d9bSStefano Stabellini 	if (ret < 0) {
314*cb1c7d9bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
315*cb1c7d9bSStefano Stabellini 		pvcalls_exit();
316*cb1c7d9bSStefano Stabellini 		return ret;
317*cb1c7d9bSStefano Stabellini 	}
318*cb1c7d9bSStefano Stabellini 
319*cb1c7d9bSStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
320*cb1c7d9bSStefano Stabellini 	req->req_id = req_id;
321*cb1c7d9bSStefano Stabellini 	req->cmd = PVCALLS_CONNECT;
322*cb1c7d9bSStefano Stabellini 	req->u.connect.id = (uintptr_t)map;
323*cb1c7d9bSStefano Stabellini 	req->u.connect.len = addr_len;
324*cb1c7d9bSStefano Stabellini 	req->u.connect.flags = flags;
325*cb1c7d9bSStefano Stabellini 	req->u.connect.ref = map->active.ref;
326*cb1c7d9bSStefano Stabellini 	req->u.connect.evtchn = evtchn;
327*cb1c7d9bSStefano Stabellini 	memcpy(req->u.connect.addr, addr, sizeof(*addr));
328*cb1c7d9bSStefano Stabellini 
329*cb1c7d9bSStefano Stabellini 	map->sock = sock;
330*cb1c7d9bSStefano Stabellini 
331*cb1c7d9bSStefano Stabellini 	bedata->ring.req_prod_pvt++;
332*cb1c7d9bSStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
333*cb1c7d9bSStefano Stabellini 	spin_unlock(&bedata->socket_lock);
334*cb1c7d9bSStefano Stabellini 
335*cb1c7d9bSStefano Stabellini 	if (notify)
336*cb1c7d9bSStefano Stabellini 		notify_remote_via_irq(bedata->irq);
337*cb1c7d9bSStefano Stabellini 
338*cb1c7d9bSStefano Stabellini 	wait_event(bedata->inflight_req,
339*cb1c7d9bSStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
340*cb1c7d9bSStefano Stabellini 
341*cb1c7d9bSStefano Stabellini 	/* read req_id, then the content */
342*cb1c7d9bSStefano Stabellini 	smp_rmb();
343*cb1c7d9bSStefano Stabellini 	ret = bedata->rsp[req_id].ret;
344*cb1c7d9bSStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
345*cb1c7d9bSStefano Stabellini 	pvcalls_exit();
346*cb1c7d9bSStefano Stabellini 	return ret;
347*cb1c7d9bSStefano Stabellini }
348*cb1c7d9bSStefano Stabellini 
349416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = {
350416efba0SStefano Stabellini 	{ "pvcalls" },
351416efba0SStefano Stabellini 	{ "" }
352416efba0SStefano Stabellini };
353416efba0SStefano Stabellini 
354416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev)
355416efba0SStefano Stabellini {
356aa7ba376SStefano Stabellini 	struct pvcalls_bedata *bedata;
357aa7ba376SStefano Stabellini 	struct sock_mapping *map = NULL, *n;
358aa7ba376SStefano Stabellini 
359aa7ba376SStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
360aa7ba376SStefano Stabellini 	dev_set_drvdata(&dev->dev, NULL);
361aa7ba376SStefano Stabellini 	pvcalls_front_dev = NULL;
362aa7ba376SStefano Stabellini 	if (bedata->irq >= 0)
363aa7ba376SStefano Stabellini 		unbind_from_irqhandler(bedata->irq, dev);
364aa7ba376SStefano Stabellini 
365*cb1c7d9bSStefano Stabellini 	list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) {
366*cb1c7d9bSStefano Stabellini 		map->sock->sk->sk_send_head = NULL;
367*cb1c7d9bSStefano Stabellini 		if (map->active_socket) {
368*cb1c7d9bSStefano Stabellini 			map->active.ring->in_error = -EBADF;
369*cb1c7d9bSStefano Stabellini 			wake_up_interruptible(&map->active.inflight_conn_req);
370*cb1c7d9bSStefano Stabellini 		}
371*cb1c7d9bSStefano Stabellini 	}
372*cb1c7d9bSStefano Stabellini 
373aa7ba376SStefano Stabellini 	smp_mb();
374aa7ba376SStefano Stabellini 	while (atomic_read(&pvcalls_refcount) > 0)
375aa7ba376SStefano Stabellini 		cpu_relax();
376aa7ba376SStefano Stabellini 	list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) {
377aa7ba376SStefano Stabellini 		if (map->active_socket) {
378aa7ba376SStefano Stabellini 			/* No need to lock, refcount is 0 */
379aa7ba376SStefano Stabellini 			pvcalls_front_free_map(bedata, map);
380aa7ba376SStefano Stabellini 		} else {
381aa7ba376SStefano Stabellini 			list_del(&map->list);
382aa7ba376SStefano Stabellini 			kfree(map);
383aa7ba376SStefano Stabellini 		}
384aa7ba376SStefano Stabellini 	}
385aa7ba376SStefano Stabellini 	if (bedata->ref >= 0)
386aa7ba376SStefano Stabellini 		gnttab_end_foreign_access(bedata->ref, 0, 0);
387aa7ba376SStefano Stabellini 	kfree(bedata->ring.sring);
388aa7ba376SStefano Stabellini 	kfree(bedata);
389aa7ba376SStefano Stabellini 	xenbus_switch_state(dev, XenbusStateClosed);
390416efba0SStefano Stabellini 	return 0;
391416efba0SStefano Stabellini }
392416efba0SStefano Stabellini 
393416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev,
394416efba0SStefano Stabellini 			  const struct xenbus_device_id *id)
395416efba0SStefano Stabellini {
39621968190SStefano Stabellini 	int ret = -ENOMEM, evtchn, i;
39721968190SStefano Stabellini 	unsigned int max_page_order, function_calls, len;
39821968190SStefano Stabellini 	char *versions;
39921968190SStefano Stabellini 	grant_ref_t gref_head = 0;
40021968190SStefano Stabellini 	struct xenbus_transaction xbt;
40121968190SStefano Stabellini 	struct pvcalls_bedata *bedata = NULL;
40221968190SStefano Stabellini 	struct xen_pvcalls_sring *sring;
40321968190SStefano Stabellini 
40421968190SStefano Stabellini 	if (pvcalls_front_dev != NULL) {
40521968190SStefano Stabellini 		dev_err(&dev->dev, "only one PV Calls connection supported\n");
40621968190SStefano Stabellini 		return -EINVAL;
40721968190SStefano Stabellini 	}
40821968190SStefano Stabellini 
40921968190SStefano Stabellini 	versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len);
41021968190SStefano Stabellini 	if (!len)
41121968190SStefano Stabellini 		return -EINVAL;
41221968190SStefano Stabellini 	if (strcmp(versions, "1")) {
41321968190SStefano Stabellini 		kfree(versions);
41421968190SStefano Stabellini 		return -EINVAL;
41521968190SStefano Stabellini 	}
41621968190SStefano Stabellini 	kfree(versions);
41721968190SStefano Stabellini 	max_page_order = xenbus_read_unsigned(dev->otherend,
41821968190SStefano Stabellini 					      "max-page-order", 0);
41921968190SStefano Stabellini 	if (max_page_order < PVCALLS_RING_ORDER)
42021968190SStefano Stabellini 		return -ENODEV;
42121968190SStefano Stabellini 	function_calls = xenbus_read_unsigned(dev->otherend,
42221968190SStefano Stabellini 					      "function-calls", 0);
42321968190SStefano Stabellini 	/* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */
42421968190SStefano Stabellini 	if (function_calls != 1)
42521968190SStefano Stabellini 		return -ENODEV;
42621968190SStefano Stabellini 	pr_info("%s max-page-order is %u\n", __func__, max_page_order);
42721968190SStefano Stabellini 
42821968190SStefano Stabellini 	bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL);
42921968190SStefano Stabellini 	if (!bedata)
43021968190SStefano Stabellini 		return -ENOMEM;
43121968190SStefano Stabellini 
43221968190SStefano Stabellini 	dev_set_drvdata(&dev->dev, bedata);
43321968190SStefano Stabellini 	pvcalls_front_dev = dev;
43421968190SStefano Stabellini 	init_waitqueue_head(&bedata->inflight_req);
43521968190SStefano Stabellini 	INIT_LIST_HEAD(&bedata->socket_mappings);
43621968190SStefano Stabellini 	spin_lock_init(&bedata->socket_lock);
43721968190SStefano Stabellini 	bedata->irq = -1;
43821968190SStefano Stabellini 	bedata->ref = -1;
43921968190SStefano Stabellini 
44021968190SStefano Stabellini 	for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++)
44121968190SStefano Stabellini 		bedata->rsp[i].req_id = PVCALLS_INVALID_ID;
44221968190SStefano Stabellini 
44321968190SStefano Stabellini 	sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL |
44421968190SStefano Stabellini 							     __GFP_ZERO);
44521968190SStefano Stabellini 	if (!sring)
44621968190SStefano Stabellini 		goto error;
44721968190SStefano Stabellini 	SHARED_RING_INIT(sring);
44821968190SStefano Stabellini 	FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE);
44921968190SStefano Stabellini 
45021968190SStefano Stabellini 	ret = xenbus_alloc_evtchn(dev, &evtchn);
45121968190SStefano Stabellini 	if (ret)
45221968190SStefano Stabellini 		goto error;
45321968190SStefano Stabellini 
45421968190SStefano Stabellini 	bedata->irq = bind_evtchn_to_irqhandler(evtchn,
45521968190SStefano Stabellini 						pvcalls_front_event_handler,
45621968190SStefano Stabellini 						0, "pvcalls-frontend", dev);
45721968190SStefano Stabellini 	if (bedata->irq < 0) {
45821968190SStefano Stabellini 		ret = bedata->irq;
45921968190SStefano Stabellini 		goto error;
46021968190SStefano Stabellini 	}
46121968190SStefano Stabellini 
46221968190SStefano Stabellini 	ret = gnttab_alloc_grant_references(1, &gref_head);
46321968190SStefano Stabellini 	if (ret < 0)
46421968190SStefano Stabellini 		goto error;
46521968190SStefano Stabellini 	bedata->ref = gnttab_claim_grant_reference(&gref_head);
46621968190SStefano Stabellini 	if (bedata->ref < 0) {
46721968190SStefano Stabellini 		ret = bedata->ref;
46821968190SStefano Stabellini 		goto error;
46921968190SStefano Stabellini 	}
47021968190SStefano Stabellini 	gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id,
47121968190SStefano Stabellini 					virt_to_gfn((void *)sring), 0);
47221968190SStefano Stabellini 
47321968190SStefano Stabellini  again:
47421968190SStefano Stabellini 	ret = xenbus_transaction_start(&xbt);
47521968190SStefano Stabellini 	if (ret) {
47621968190SStefano Stabellini 		xenbus_dev_fatal(dev, ret, "starting transaction");
47721968190SStefano Stabellini 		goto error;
47821968190SStefano Stabellini 	}
47921968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1);
48021968190SStefano Stabellini 	if (ret)
48121968190SStefano Stabellini 		goto error_xenbus;
48221968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref);
48321968190SStefano Stabellini 	if (ret)
48421968190SStefano Stabellini 		goto error_xenbus;
48521968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
48621968190SStefano Stabellini 			    evtchn);
48721968190SStefano Stabellini 	if (ret)
48821968190SStefano Stabellini 		goto error_xenbus;
48921968190SStefano Stabellini 	ret = xenbus_transaction_end(xbt, 0);
49021968190SStefano Stabellini 	if (ret) {
49121968190SStefano Stabellini 		if (ret == -EAGAIN)
49221968190SStefano Stabellini 			goto again;
49321968190SStefano Stabellini 		xenbus_dev_fatal(dev, ret, "completing transaction");
49421968190SStefano Stabellini 		goto error;
49521968190SStefano Stabellini 	}
49621968190SStefano Stabellini 	xenbus_switch_state(dev, XenbusStateInitialised);
49721968190SStefano Stabellini 
498416efba0SStefano Stabellini 	return 0;
49921968190SStefano Stabellini 
50021968190SStefano Stabellini  error_xenbus:
50121968190SStefano Stabellini 	xenbus_transaction_end(xbt, 1);
50221968190SStefano Stabellini 	xenbus_dev_fatal(dev, ret, "writing xenstore");
50321968190SStefano Stabellini  error:
50421968190SStefano Stabellini 	pvcalls_front_remove(dev);
50521968190SStefano Stabellini 	return ret;
506416efba0SStefano Stabellini }
507416efba0SStefano Stabellini 
508416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev,
509416efba0SStefano Stabellini 			    enum xenbus_state backend_state)
510416efba0SStefano Stabellini {
51121968190SStefano Stabellini 	switch (backend_state) {
51221968190SStefano Stabellini 	case XenbusStateReconfiguring:
51321968190SStefano Stabellini 	case XenbusStateReconfigured:
51421968190SStefano Stabellini 	case XenbusStateInitialising:
51521968190SStefano Stabellini 	case XenbusStateInitialised:
51621968190SStefano Stabellini 	case XenbusStateUnknown:
51721968190SStefano Stabellini 		break;
51821968190SStefano Stabellini 
51921968190SStefano Stabellini 	case XenbusStateInitWait:
52021968190SStefano Stabellini 		break;
52121968190SStefano Stabellini 
52221968190SStefano Stabellini 	case XenbusStateConnected:
52321968190SStefano Stabellini 		xenbus_switch_state(dev, XenbusStateConnected);
52421968190SStefano Stabellini 		break;
52521968190SStefano Stabellini 
52621968190SStefano Stabellini 	case XenbusStateClosed:
52721968190SStefano Stabellini 		if (dev->state == XenbusStateClosed)
52821968190SStefano Stabellini 			break;
52921968190SStefano Stabellini 		/* Missed the backend's CLOSING state -- fallthrough */
53021968190SStefano Stabellini 	case XenbusStateClosing:
53121968190SStefano Stabellini 		xenbus_frontend_closed(dev);
53221968190SStefano Stabellini 		break;
53321968190SStefano Stabellini 	}
534416efba0SStefano Stabellini }
535416efba0SStefano Stabellini 
536416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = {
537416efba0SStefano Stabellini 	.ids = pvcalls_front_ids,
538416efba0SStefano Stabellini 	.probe = pvcalls_front_probe,
539416efba0SStefano Stabellini 	.remove = pvcalls_front_remove,
540416efba0SStefano Stabellini 	.otherend_changed = pvcalls_front_changed,
541416efba0SStefano Stabellini };
542416efba0SStefano Stabellini 
543416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void)
544416efba0SStefano Stabellini {
545416efba0SStefano Stabellini 	if (!xen_domain())
546416efba0SStefano Stabellini 		return -ENODEV;
547416efba0SStefano Stabellini 
548416efba0SStefano Stabellini 	pr_info("Initialising Xen pvcalls frontend driver\n");
549416efba0SStefano Stabellini 
550416efba0SStefano Stabellini 	return xenbus_register_frontend(&pvcalls_front_driver);
551416efba0SStefano Stabellini }
552416efba0SStefano Stabellini 
553416efba0SStefano Stabellini module_init(pvcalls_frontend_init);
554