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