xref: /openbmc/linux/drivers/xen/pvcalls-front.c (revision 1853f11d72ed46310ff3c5a60264b2f8a53f8c25)
1416efba0SStefano Stabellini /*
2416efba0SStefano Stabellini  * (c) 2017 Stefano Stabellini <stefano@aporeto.com>
3416efba0SStefano Stabellini  *
4416efba0SStefano Stabellini  * This program is free software; you can redistribute it and/or modify
5416efba0SStefano Stabellini  * it under the terms of the GNU General Public License as published by
6416efba0SStefano Stabellini  * the Free Software Foundation; either version 2 of the License, or
7416efba0SStefano Stabellini  * (at your option) any later version.
8416efba0SStefano Stabellini  *
9416efba0SStefano Stabellini  * This program is distributed in the hope that it will be useful,
10416efba0SStefano Stabellini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11416efba0SStefano Stabellini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12416efba0SStefano Stabellini  * GNU General Public License for more details.
13416efba0SStefano Stabellini  */
14416efba0SStefano Stabellini 
15416efba0SStefano Stabellini #include <linux/module.h>
162195046bSStefano Stabellini #include <linux/net.h>
172195046bSStefano Stabellini #include <linux/socket.h>
182195046bSStefano Stabellini 
192195046bSStefano Stabellini #include <net/sock.h>
20416efba0SStefano Stabellini 
21416efba0SStefano Stabellini #include <xen/events.h>
22416efba0SStefano Stabellini #include <xen/grant_table.h>
23416efba0SStefano Stabellini #include <xen/xen.h>
24416efba0SStefano Stabellini #include <xen/xenbus.h>
25416efba0SStefano Stabellini #include <xen/interface/io/pvcalls.h>
26416efba0SStefano Stabellini 
272195046bSStefano Stabellini #include "pvcalls-front.h"
282195046bSStefano Stabellini 
29aa7ba376SStefano Stabellini #define PVCALLS_INVALID_ID UINT_MAX
30aa7ba376SStefano Stabellini #define PVCALLS_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER
31aa7ba376SStefano Stabellini #define PVCALLS_NR_RSP_PER_RING __CONST_RING_SIZE(xen_pvcalls, XEN_PAGE_SIZE)
32aa7ba376SStefano Stabellini 
33aa7ba376SStefano Stabellini struct pvcalls_bedata {
34aa7ba376SStefano Stabellini 	struct xen_pvcalls_front_ring ring;
35aa7ba376SStefano Stabellini 	grant_ref_t ref;
36aa7ba376SStefano Stabellini 	int irq;
37aa7ba376SStefano Stabellini 
38aa7ba376SStefano Stabellini 	struct list_head socket_mappings;
39aa7ba376SStefano Stabellini 	spinlock_t socket_lock;
40aa7ba376SStefano Stabellini 
41aa7ba376SStefano Stabellini 	wait_queue_head_t inflight_req;
42aa7ba376SStefano Stabellini 	struct xen_pvcalls_response rsp[PVCALLS_NR_RSP_PER_RING];
43aa7ba376SStefano Stabellini };
44aa7ba376SStefano Stabellini /* Only one front/back connection supported. */
45aa7ba376SStefano Stabellini static struct xenbus_device *pvcalls_front_dev;
46aa7ba376SStefano Stabellini static atomic_t pvcalls_refcount;
47aa7ba376SStefano Stabellini 
48aa7ba376SStefano Stabellini /* first increment refcount, then proceed */
49aa7ba376SStefano Stabellini #define pvcalls_enter() {               \
50aa7ba376SStefano Stabellini 	atomic_inc(&pvcalls_refcount);      \
51aa7ba376SStefano Stabellini }
52aa7ba376SStefano Stabellini 
53aa7ba376SStefano Stabellini /* first complete other operations, then decrement refcount */
54aa7ba376SStefano Stabellini #define pvcalls_exit() {                \
55aa7ba376SStefano Stabellini 	atomic_dec(&pvcalls_refcount);      \
56aa7ba376SStefano Stabellini }
57aa7ba376SStefano Stabellini 
58aa7ba376SStefano Stabellini struct sock_mapping {
59aa7ba376SStefano Stabellini 	bool active_socket;
60aa7ba376SStefano Stabellini 	struct list_head list;
61aa7ba376SStefano Stabellini 	struct socket *sock;
62cb1c7d9bSStefano Stabellini 	union {
63cb1c7d9bSStefano Stabellini 		struct {
64cb1c7d9bSStefano Stabellini 			int irq;
65cb1c7d9bSStefano Stabellini 			grant_ref_t ref;
66cb1c7d9bSStefano Stabellini 			struct pvcalls_data_intf *ring;
67cb1c7d9bSStefano Stabellini 			struct pvcalls_data data;
68cb1c7d9bSStefano Stabellini 			struct mutex in_mutex;
69cb1c7d9bSStefano Stabellini 			struct mutex out_mutex;
70cb1c7d9bSStefano Stabellini 
71cb1c7d9bSStefano Stabellini 			wait_queue_head_t inflight_conn_req;
72cb1c7d9bSStefano Stabellini 		} active;
7367ea9893SStefano Stabellini 		struct {
7467ea9893SStefano Stabellini 		/* Socket status */
7567ea9893SStefano Stabellini #define PVCALLS_STATUS_UNINITALIZED  0
7667ea9893SStefano Stabellini #define PVCALLS_STATUS_BIND          1
7767ea9893SStefano Stabellini #define PVCALLS_STATUS_LISTEN        2
7867ea9893SStefano Stabellini 			uint8_t status;
7967ea9893SStefano Stabellini 		} passive;
80cb1c7d9bSStefano Stabellini 	};
81aa7ba376SStefano Stabellini };
82aa7ba376SStefano Stabellini 
832195046bSStefano Stabellini static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
842195046bSStefano Stabellini {
852195046bSStefano Stabellini 	*req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
862195046bSStefano Stabellini 	if (RING_FULL(&bedata->ring) ||
872195046bSStefano Stabellini 	    bedata->rsp[*req_id].req_id != PVCALLS_INVALID_ID)
882195046bSStefano Stabellini 		return -EAGAIN;
892195046bSStefano Stabellini 	return 0;
902195046bSStefano Stabellini }
912195046bSStefano Stabellini 
92aa7ba376SStefano Stabellini static irqreturn_t pvcalls_front_event_handler(int irq, void *dev_id)
93aa7ba376SStefano Stabellini {
942195046bSStefano Stabellini 	struct xenbus_device *dev = dev_id;
952195046bSStefano Stabellini 	struct pvcalls_bedata *bedata;
962195046bSStefano Stabellini 	struct xen_pvcalls_response *rsp;
972195046bSStefano Stabellini 	uint8_t *src, *dst;
982195046bSStefano Stabellini 	int req_id = 0, more = 0, done = 0;
992195046bSStefano Stabellini 
1002195046bSStefano Stabellini 	if (dev == NULL)
1012195046bSStefano Stabellini 		return IRQ_HANDLED;
1022195046bSStefano Stabellini 
1032195046bSStefano Stabellini 	pvcalls_enter();
1042195046bSStefano Stabellini 	bedata = dev_get_drvdata(&dev->dev);
1052195046bSStefano Stabellini 	if (bedata == NULL) {
1062195046bSStefano Stabellini 		pvcalls_exit();
1072195046bSStefano Stabellini 		return IRQ_HANDLED;
1082195046bSStefano Stabellini 	}
1092195046bSStefano Stabellini 
1102195046bSStefano Stabellini again:
1112195046bSStefano Stabellini 	while (RING_HAS_UNCONSUMED_RESPONSES(&bedata->ring)) {
1122195046bSStefano Stabellini 		rsp = RING_GET_RESPONSE(&bedata->ring, bedata->ring.rsp_cons);
1132195046bSStefano Stabellini 
1142195046bSStefano Stabellini 		req_id = rsp->req_id;
1152195046bSStefano Stabellini 		dst = (uint8_t *)&bedata->rsp[req_id] + sizeof(rsp->req_id);
1162195046bSStefano Stabellini 		src = (uint8_t *)rsp + sizeof(rsp->req_id);
1172195046bSStefano Stabellini 		memcpy(dst, src, sizeof(*rsp) - sizeof(rsp->req_id));
1182195046bSStefano Stabellini 		/*
1192195046bSStefano Stabellini 		 * First copy the rest of the data, then req_id. It is
1202195046bSStefano Stabellini 		 * paired with the barrier when accessing bedata->rsp.
1212195046bSStefano Stabellini 		 */
1222195046bSStefano Stabellini 		smp_wmb();
1232195046bSStefano Stabellini 		bedata->rsp[req_id].req_id = rsp->req_id;
1242195046bSStefano Stabellini 
1252195046bSStefano Stabellini 		done = 1;
1262195046bSStefano Stabellini 		bedata->ring.rsp_cons++;
1272195046bSStefano Stabellini 	}
1282195046bSStefano Stabellini 
1292195046bSStefano Stabellini 	RING_FINAL_CHECK_FOR_RESPONSES(&bedata->ring, more);
1302195046bSStefano Stabellini 	if (more)
1312195046bSStefano Stabellini 		goto again;
1322195046bSStefano Stabellini 	if (done)
1332195046bSStefano Stabellini 		wake_up(&bedata->inflight_req);
1342195046bSStefano Stabellini 	pvcalls_exit();
135aa7ba376SStefano Stabellini 	return IRQ_HANDLED;
136aa7ba376SStefano Stabellini }
137aa7ba376SStefano Stabellini 
138aa7ba376SStefano Stabellini static void pvcalls_front_free_map(struct pvcalls_bedata *bedata,
139aa7ba376SStefano Stabellini 				   struct sock_mapping *map)
140aa7ba376SStefano Stabellini {
141aa7ba376SStefano Stabellini }
142aa7ba376SStefano Stabellini 
143cb1c7d9bSStefano Stabellini static irqreturn_t pvcalls_front_conn_handler(int irq, void *sock_map)
144cb1c7d9bSStefano Stabellini {
145cb1c7d9bSStefano Stabellini 	struct sock_mapping *map = sock_map;
146cb1c7d9bSStefano Stabellini 
147cb1c7d9bSStefano Stabellini 	if (map == NULL)
148cb1c7d9bSStefano Stabellini 		return IRQ_HANDLED;
149cb1c7d9bSStefano Stabellini 
150cb1c7d9bSStefano Stabellini 	wake_up_interruptible(&map->active.inflight_conn_req);
151cb1c7d9bSStefano Stabellini 
152cb1c7d9bSStefano Stabellini 	return IRQ_HANDLED;
153cb1c7d9bSStefano Stabellini }
154cb1c7d9bSStefano Stabellini 
1552195046bSStefano Stabellini int pvcalls_front_socket(struct socket *sock)
1562195046bSStefano Stabellini {
1572195046bSStefano Stabellini 	struct pvcalls_bedata *bedata;
1582195046bSStefano Stabellini 	struct sock_mapping *map = NULL;
1592195046bSStefano Stabellini 	struct xen_pvcalls_request *req;
1602195046bSStefano Stabellini 	int notify, req_id, ret;
1612195046bSStefano Stabellini 
1622195046bSStefano Stabellini 	/*
1632195046bSStefano Stabellini 	 * PVCalls only supports domain AF_INET,
1642195046bSStefano Stabellini 	 * type SOCK_STREAM and protocol 0 sockets for now.
1652195046bSStefano Stabellini 	 *
1662195046bSStefano Stabellini 	 * Check socket type here, AF_INET and protocol checks are done
1672195046bSStefano Stabellini 	 * by the caller.
1682195046bSStefano Stabellini 	 */
1692195046bSStefano Stabellini 	if (sock->type != SOCK_STREAM)
1702195046bSStefano Stabellini 		return -EOPNOTSUPP;
1712195046bSStefano Stabellini 
1722195046bSStefano Stabellini 	pvcalls_enter();
1732195046bSStefano Stabellini 	if (!pvcalls_front_dev) {
1742195046bSStefano Stabellini 		pvcalls_exit();
1752195046bSStefano Stabellini 		return -EACCES;
1762195046bSStefano Stabellini 	}
1772195046bSStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
1782195046bSStefano Stabellini 
1792195046bSStefano Stabellini 	map = kzalloc(sizeof(*map), GFP_KERNEL);
1802195046bSStefano Stabellini 	if (map == NULL) {
1812195046bSStefano Stabellini 		pvcalls_exit();
1822195046bSStefano Stabellini 		return -ENOMEM;
1832195046bSStefano Stabellini 	}
1842195046bSStefano Stabellini 
1852195046bSStefano Stabellini 	spin_lock(&bedata->socket_lock);
1862195046bSStefano Stabellini 
1872195046bSStefano Stabellini 	ret = get_request(bedata, &req_id);
1882195046bSStefano Stabellini 	if (ret < 0) {
1892195046bSStefano Stabellini 		kfree(map);
1902195046bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
1912195046bSStefano Stabellini 		pvcalls_exit();
1922195046bSStefano Stabellini 		return ret;
1932195046bSStefano Stabellini 	}
1942195046bSStefano Stabellini 
1952195046bSStefano Stabellini 	/*
1962195046bSStefano Stabellini 	 * sock->sk->sk_send_head is not used for ip sockets: reuse the
1972195046bSStefano Stabellini 	 * field to store a pointer to the struct sock_mapping
1982195046bSStefano Stabellini 	 * corresponding to the socket. This way, we can easily get the
1992195046bSStefano Stabellini 	 * struct sock_mapping from the struct socket.
2002195046bSStefano Stabellini 	 */
2012195046bSStefano Stabellini 	sock->sk->sk_send_head = (void *)map;
2022195046bSStefano Stabellini 	list_add_tail(&map->list, &bedata->socket_mappings);
2032195046bSStefano Stabellini 
2042195046bSStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
2052195046bSStefano Stabellini 	req->req_id = req_id;
2062195046bSStefano Stabellini 	req->cmd = PVCALLS_SOCKET;
2072195046bSStefano Stabellini 	req->u.socket.id = (uintptr_t) map;
2082195046bSStefano Stabellini 	req->u.socket.domain = AF_INET;
2092195046bSStefano Stabellini 	req->u.socket.type = SOCK_STREAM;
2102195046bSStefano Stabellini 	req->u.socket.protocol = IPPROTO_IP;
2112195046bSStefano Stabellini 
2122195046bSStefano Stabellini 	bedata->ring.req_prod_pvt++;
2132195046bSStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
2142195046bSStefano Stabellini 	spin_unlock(&bedata->socket_lock);
2152195046bSStefano Stabellini 	if (notify)
2162195046bSStefano Stabellini 		notify_remote_via_irq(bedata->irq);
2172195046bSStefano Stabellini 
2182195046bSStefano Stabellini 	wait_event(bedata->inflight_req,
2192195046bSStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
2202195046bSStefano Stabellini 
2212195046bSStefano Stabellini 	/* read req_id, then the content */
2222195046bSStefano Stabellini 	smp_rmb();
2232195046bSStefano Stabellini 	ret = bedata->rsp[req_id].ret;
2242195046bSStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
2252195046bSStefano Stabellini 
2262195046bSStefano Stabellini 	pvcalls_exit();
2272195046bSStefano Stabellini 	return ret;
2282195046bSStefano Stabellini }
2292195046bSStefano Stabellini 
230cb1c7d9bSStefano Stabellini static int create_active(struct sock_mapping *map, int *evtchn)
231cb1c7d9bSStefano Stabellini {
232cb1c7d9bSStefano Stabellini 	void *bytes;
233cb1c7d9bSStefano Stabellini 	int ret = -ENOMEM, irq = -1, i;
234cb1c7d9bSStefano Stabellini 
235cb1c7d9bSStefano Stabellini 	*evtchn = -1;
236cb1c7d9bSStefano Stabellini 	init_waitqueue_head(&map->active.inflight_conn_req);
237cb1c7d9bSStefano Stabellini 
238cb1c7d9bSStefano Stabellini 	map->active.ring = (struct pvcalls_data_intf *)
239cb1c7d9bSStefano Stabellini 		__get_free_page(GFP_KERNEL | __GFP_ZERO);
240cb1c7d9bSStefano Stabellini 	if (map->active.ring == NULL)
241cb1c7d9bSStefano Stabellini 		goto out_error;
242cb1c7d9bSStefano Stabellini 	map->active.ring->ring_order = PVCALLS_RING_ORDER;
243cb1c7d9bSStefano Stabellini 	bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
244cb1c7d9bSStefano Stabellini 					PVCALLS_RING_ORDER);
245cb1c7d9bSStefano Stabellini 	if (bytes == NULL)
246cb1c7d9bSStefano Stabellini 		goto out_error;
247cb1c7d9bSStefano Stabellini 	for (i = 0; i < (1 << PVCALLS_RING_ORDER); i++)
248cb1c7d9bSStefano Stabellini 		map->active.ring->ref[i] = gnttab_grant_foreign_access(
249cb1c7d9bSStefano Stabellini 			pvcalls_front_dev->otherend_id,
250cb1c7d9bSStefano Stabellini 			pfn_to_gfn(virt_to_pfn(bytes) + i), 0);
251cb1c7d9bSStefano Stabellini 
252cb1c7d9bSStefano Stabellini 	map->active.ref = gnttab_grant_foreign_access(
253cb1c7d9bSStefano Stabellini 		pvcalls_front_dev->otherend_id,
254cb1c7d9bSStefano Stabellini 		pfn_to_gfn(virt_to_pfn((void *)map->active.ring)), 0);
255cb1c7d9bSStefano Stabellini 
256cb1c7d9bSStefano Stabellini 	map->active.data.in = bytes;
257cb1c7d9bSStefano Stabellini 	map->active.data.out = bytes +
258cb1c7d9bSStefano Stabellini 		XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER);
259cb1c7d9bSStefano Stabellini 
260cb1c7d9bSStefano Stabellini 	ret = xenbus_alloc_evtchn(pvcalls_front_dev, evtchn);
261cb1c7d9bSStefano Stabellini 	if (ret)
262cb1c7d9bSStefano Stabellini 		goto out_error;
263cb1c7d9bSStefano Stabellini 	irq = bind_evtchn_to_irqhandler(*evtchn, pvcalls_front_conn_handler,
264cb1c7d9bSStefano Stabellini 					0, "pvcalls-frontend", map);
265cb1c7d9bSStefano Stabellini 	if (irq < 0) {
266cb1c7d9bSStefano Stabellini 		ret = irq;
267cb1c7d9bSStefano Stabellini 		goto out_error;
268cb1c7d9bSStefano Stabellini 	}
269cb1c7d9bSStefano Stabellini 
270cb1c7d9bSStefano Stabellini 	map->active.irq = irq;
271cb1c7d9bSStefano Stabellini 	map->active_socket = true;
272cb1c7d9bSStefano Stabellini 	mutex_init(&map->active.in_mutex);
273cb1c7d9bSStefano Stabellini 	mutex_init(&map->active.out_mutex);
274cb1c7d9bSStefano Stabellini 
275cb1c7d9bSStefano Stabellini 	return 0;
276cb1c7d9bSStefano Stabellini 
277cb1c7d9bSStefano Stabellini out_error:
278cb1c7d9bSStefano Stabellini 	if (irq >= 0)
279cb1c7d9bSStefano Stabellini 		unbind_from_irqhandler(irq, map);
280cb1c7d9bSStefano Stabellini 	else if (*evtchn >= 0)
281cb1c7d9bSStefano Stabellini 		xenbus_free_evtchn(pvcalls_front_dev, *evtchn);
282cb1c7d9bSStefano Stabellini 	kfree(map->active.data.in);
283cb1c7d9bSStefano Stabellini 	kfree(map->active.ring);
284cb1c7d9bSStefano Stabellini 	return ret;
285cb1c7d9bSStefano Stabellini }
286cb1c7d9bSStefano Stabellini 
287cb1c7d9bSStefano Stabellini int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
288cb1c7d9bSStefano Stabellini 				int addr_len, int flags)
289cb1c7d9bSStefano Stabellini {
290cb1c7d9bSStefano Stabellini 	struct pvcalls_bedata *bedata;
291cb1c7d9bSStefano Stabellini 	struct sock_mapping *map = NULL;
292cb1c7d9bSStefano Stabellini 	struct xen_pvcalls_request *req;
293cb1c7d9bSStefano Stabellini 	int notify, req_id, ret, evtchn;
294cb1c7d9bSStefano Stabellini 
295cb1c7d9bSStefano Stabellini 	if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
296cb1c7d9bSStefano Stabellini 		return -EOPNOTSUPP;
297cb1c7d9bSStefano Stabellini 
298cb1c7d9bSStefano Stabellini 	pvcalls_enter();
299cb1c7d9bSStefano Stabellini 	if (!pvcalls_front_dev) {
300cb1c7d9bSStefano Stabellini 		pvcalls_exit();
301cb1c7d9bSStefano Stabellini 		return -ENOTCONN;
302cb1c7d9bSStefano Stabellini 	}
303cb1c7d9bSStefano Stabellini 
304cb1c7d9bSStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
305cb1c7d9bSStefano Stabellini 
306cb1c7d9bSStefano Stabellini 	map = (struct sock_mapping *)sock->sk->sk_send_head;
307cb1c7d9bSStefano Stabellini 	if (!map) {
308cb1c7d9bSStefano Stabellini 		pvcalls_exit();
309cb1c7d9bSStefano Stabellini 		return -ENOTSOCK;
310cb1c7d9bSStefano Stabellini 	}
311cb1c7d9bSStefano Stabellini 
312cb1c7d9bSStefano Stabellini 	spin_lock(&bedata->socket_lock);
313cb1c7d9bSStefano Stabellini 	ret = get_request(bedata, &req_id);
314cb1c7d9bSStefano Stabellini 	if (ret < 0) {
315cb1c7d9bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
316cb1c7d9bSStefano Stabellini 		pvcalls_exit();
317cb1c7d9bSStefano Stabellini 		return ret;
318cb1c7d9bSStefano Stabellini 	}
319cb1c7d9bSStefano Stabellini 	ret = create_active(map, &evtchn);
320cb1c7d9bSStefano Stabellini 	if (ret < 0) {
321cb1c7d9bSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
322cb1c7d9bSStefano Stabellini 		pvcalls_exit();
323cb1c7d9bSStefano Stabellini 		return ret;
324cb1c7d9bSStefano Stabellini 	}
325cb1c7d9bSStefano Stabellini 
326cb1c7d9bSStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
327cb1c7d9bSStefano Stabellini 	req->req_id = req_id;
328cb1c7d9bSStefano Stabellini 	req->cmd = PVCALLS_CONNECT;
329cb1c7d9bSStefano Stabellini 	req->u.connect.id = (uintptr_t)map;
330cb1c7d9bSStefano Stabellini 	req->u.connect.len = addr_len;
331cb1c7d9bSStefano Stabellini 	req->u.connect.flags = flags;
332cb1c7d9bSStefano Stabellini 	req->u.connect.ref = map->active.ref;
333cb1c7d9bSStefano Stabellini 	req->u.connect.evtchn = evtchn;
334cb1c7d9bSStefano Stabellini 	memcpy(req->u.connect.addr, addr, sizeof(*addr));
335cb1c7d9bSStefano Stabellini 
336cb1c7d9bSStefano Stabellini 	map->sock = sock;
337cb1c7d9bSStefano Stabellini 
338cb1c7d9bSStefano Stabellini 	bedata->ring.req_prod_pvt++;
339cb1c7d9bSStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
340cb1c7d9bSStefano Stabellini 	spin_unlock(&bedata->socket_lock);
341cb1c7d9bSStefano Stabellini 
342cb1c7d9bSStefano Stabellini 	if (notify)
343cb1c7d9bSStefano Stabellini 		notify_remote_via_irq(bedata->irq);
344cb1c7d9bSStefano Stabellini 
345cb1c7d9bSStefano Stabellini 	wait_event(bedata->inflight_req,
346cb1c7d9bSStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
347cb1c7d9bSStefano Stabellini 
348cb1c7d9bSStefano Stabellini 	/* read req_id, then the content */
349cb1c7d9bSStefano Stabellini 	smp_rmb();
350cb1c7d9bSStefano Stabellini 	ret = bedata->rsp[req_id].ret;
351cb1c7d9bSStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
352cb1c7d9bSStefano Stabellini 	pvcalls_exit();
353cb1c7d9bSStefano Stabellini 	return ret;
354cb1c7d9bSStefano Stabellini }
355cb1c7d9bSStefano Stabellini 
35667ea9893SStefano Stabellini int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
35767ea9893SStefano Stabellini {
35867ea9893SStefano Stabellini 	struct pvcalls_bedata *bedata;
35967ea9893SStefano Stabellini 	struct sock_mapping *map = NULL;
36067ea9893SStefano Stabellini 	struct xen_pvcalls_request *req;
36167ea9893SStefano Stabellini 	int notify, req_id, ret;
36267ea9893SStefano Stabellini 
36367ea9893SStefano Stabellini 	if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
36467ea9893SStefano Stabellini 		return -EOPNOTSUPP;
36567ea9893SStefano Stabellini 
36667ea9893SStefano Stabellini 	pvcalls_enter();
36767ea9893SStefano Stabellini 	if (!pvcalls_front_dev) {
36867ea9893SStefano Stabellini 		pvcalls_exit();
36967ea9893SStefano Stabellini 		return -ENOTCONN;
37067ea9893SStefano Stabellini 	}
37167ea9893SStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
37267ea9893SStefano Stabellini 
37367ea9893SStefano Stabellini 	map = (struct sock_mapping *) sock->sk->sk_send_head;
37467ea9893SStefano Stabellini 	if (map == NULL) {
37567ea9893SStefano Stabellini 		pvcalls_exit();
37667ea9893SStefano Stabellini 		return -ENOTSOCK;
37767ea9893SStefano Stabellini 	}
37867ea9893SStefano Stabellini 
37967ea9893SStefano Stabellini 	spin_lock(&bedata->socket_lock);
38067ea9893SStefano Stabellini 	ret = get_request(bedata, &req_id);
38167ea9893SStefano Stabellini 	if (ret < 0) {
38267ea9893SStefano Stabellini 		spin_unlock(&bedata->socket_lock);
38367ea9893SStefano Stabellini 		pvcalls_exit();
38467ea9893SStefano Stabellini 		return ret;
38567ea9893SStefano Stabellini 	}
38667ea9893SStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
38767ea9893SStefano Stabellini 	req->req_id = req_id;
38867ea9893SStefano Stabellini 	map->sock = sock;
38967ea9893SStefano Stabellini 	req->cmd = PVCALLS_BIND;
39067ea9893SStefano Stabellini 	req->u.bind.id = (uintptr_t)map;
39167ea9893SStefano Stabellini 	memcpy(req->u.bind.addr, addr, sizeof(*addr));
39267ea9893SStefano Stabellini 	req->u.bind.len = addr_len;
39367ea9893SStefano Stabellini 
39467ea9893SStefano Stabellini 	map->active_socket = false;
39567ea9893SStefano Stabellini 
39667ea9893SStefano Stabellini 	bedata->ring.req_prod_pvt++;
39767ea9893SStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
39867ea9893SStefano Stabellini 	spin_unlock(&bedata->socket_lock);
39967ea9893SStefano Stabellini 	if (notify)
40067ea9893SStefano Stabellini 		notify_remote_via_irq(bedata->irq);
40167ea9893SStefano Stabellini 
40267ea9893SStefano Stabellini 	wait_event(bedata->inflight_req,
40367ea9893SStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
40467ea9893SStefano Stabellini 
40567ea9893SStefano Stabellini 	/* read req_id, then the content */
40667ea9893SStefano Stabellini 	smp_rmb();
40767ea9893SStefano Stabellini 	ret = bedata->rsp[req_id].ret;
40867ea9893SStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
40967ea9893SStefano Stabellini 
41067ea9893SStefano Stabellini 	map->passive.status = PVCALLS_STATUS_BIND;
41167ea9893SStefano Stabellini 	pvcalls_exit();
41267ea9893SStefano Stabellini 	return 0;
41367ea9893SStefano Stabellini }
41467ea9893SStefano Stabellini 
415*1853f11dSStefano Stabellini int pvcalls_front_listen(struct socket *sock, int backlog)
416*1853f11dSStefano Stabellini {
417*1853f11dSStefano Stabellini 	struct pvcalls_bedata *bedata;
418*1853f11dSStefano Stabellini 	struct sock_mapping *map;
419*1853f11dSStefano Stabellini 	struct xen_pvcalls_request *req;
420*1853f11dSStefano Stabellini 	int notify, req_id, ret;
421*1853f11dSStefano Stabellini 
422*1853f11dSStefano Stabellini 	pvcalls_enter();
423*1853f11dSStefano Stabellini 	if (!pvcalls_front_dev) {
424*1853f11dSStefano Stabellini 		pvcalls_exit();
425*1853f11dSStefano Stabellini 		return -ENOTCONN;
426*1853f11dSStefano Stabellini 	}
427*1853f11dSStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
428*1853f11dSStefano Stabellini 
429*1853f11dSStefano Stabellini 	map = (struct sock_mapping *) sock->sk->sk_send_head;
430*1853f11dSStefano Stabellini 	if (!map) {
431*1853f11dSStefano Stabellini 		pvcalls_exit();
432*1853f11dSStefano Stabellini 		return -ENOTSOCK;
433*1853f11dSStefano Stabellini 	}
434*1853f11dSStefano Stabellini 
435*1853f11dSStefano Stabellini 	if (map->passive.status != PVCALLS_STATUS_BIND) {
436*1853f11dSStefano Stabellini 		pvcalls_exit();
437*1853f11dSStefano Stabellini 		return -EOPNOTSUPP;
438*1853f11dSStefano Stabellini 	}
439*1853f11dSStefano Stabellini 
440*1853f11dSStefano Stabellini 	spin_lock(&bedata->socket_lock);
441*1853f11dSStefano Stabellini 	ret = get_request(bedata, &req_id);
442*1853f11dSStefano Stabellini 	if (ret < 0) {
443*1853f11dSStefano Stabellini 		spin_unlock(&bedata->socket_lock);
444*1853f11dSStefano Stabellini 		pvcalls_exit();
445*1853f11dSStefano Stabellini 		return ret;
446*1853f11dSStefano Stabellini 	}
447*1853f11dSStefano Stabellini 	req = RING_GET_REQUEST(&bedata->ring, req_id);
448*1853f11dSStefano Stabellini 	req->req_id = req_id;
449*1853f11dSStefano Stabellini 	req->cmd = PVCALLS_LISTEN;
450*1853f11dSStefano Stabellini 	req->u.listen.id = (uintptr_t) map;
451*1853f11dSStefano Stabellini 	req->u.listen.backlog = backlog;
452*1853f11dSStefano Stabellini 
453*1853f11dSStefano Stabellini 	bedata->ring.req_prod_pvt++;
454*1853f11dSStefano Stabellini 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&bedata->ring, notify);
455*1853f11dSStefano Stabellini 	spin_unlock(&bedata->socket_lock);
456*1853f11dSStefano Stabellini 	if (notify)
457*1853f11dSStefano Stabellini 		notify_remote_via_irq(bedata->irq);
458*1853f11dSStefano Stabellini 
459*1853f11dSStefano Stabellini 	wait_event(bedata->inflight_req,
460*1853f11dSStefano Stabellini 		   READ_ONCE(bedata->rsp[req_id].req_id) == req_id);
461*1853f11dSStefano Stabellini 
462*1853f11dSStefano Stabellini 	/* read req_id, then the content */
463*1853f11dSStefano Stabellini 	smp_rmb();
464*1853f11dSStefano Stabellini 	ret = bedata->rsp[req_id].ret;
465*1853f11dSStefano Stabellini 	bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
466*1853f11dSStefano Stabellini 
467*1853f11dSStefano Stabellini 	map->passive.status = PVCALLS_STATUS_LISTEN;
468*1853f11dSStefano Stabellini 	pvcalls_exit();
469*1853f11dSStefano Stabellini 	return ret;
470*1853f11dSStefano Stabellini }
471*1853f11dSStefano Stabellini 
472416efba0SStefano Stabellini static const struct xenbus_device_id pvcalls_front_ids[] = {
473416efba0SStefano Stabellini 	{ "pvcalls" },
474416efba0SStefano Stabellini 	{ "" }
475416efba0SStefano Stabellini };
476416efba0SStefano Stabellini 
477416efba0SStefano Stabellini static int pvcalls_front_remove(struct xenbus_device *dev)
478416efba0SStefano Stabellini {
479aa7ba376SStefano Stabellini 	struct pvcalls_bedata *bedata;
480aa7ba376SStefano Stabellini 	struct sock_mapping *map = NULL, *n;
481aa7ba376SStefano Stabellini 
482aa7ba376SStefano Stabellini 	bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
483aa7ba376SStefano Stabellini 	dev_set_drvdata(&dev->dev, NULL);
484aa7ba376SStefano Stabellini 	pvcalls_front_dev = NULL;
485aa7ba376SStefano Stabellini 	if (bedata->irq >= 0)
486aa7ba376SStefano Stabellini 		unbind_from_irqhandler(bedata->irq, dev);
487aa7ba376SStefano Stabellini 
488cb1c7d9bSStefano Stabellini 	list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) {
489cb1c7d9bSStefano Stabellini 		map->sock->sk->sk_send_head = NULL;
490cb1c7d9bSStefano Stabellini 		if (map->active_socket) {
491cb1c7d9bSStefano Stabellini 			map->active.ring->in_error = -EBADF;
492cb1c7d9bSStefano Stabellini 			wake_up_interruptible(&map->active.inflight_conn_req);
493cb1c7d9bSStefano Stabellini 		}
494cb1c7d9bSStefano Stabellini 	}
495cb1c7d9bSStefano Stabellini 
496aa7ba376SStefano Stabellini 	smp_mb();
497aa7ba376SStefano Stabellini 	while (atomic_read(&pvcalls_refcount) > 0)
498aa7ba376SStefano Stabellini 		cpu_relax();
499aa7ba376SStefano Stabellini 	list_for_each_entry_safe(map, n, &bedata->socket_mappings, list) {
500aa7ba376SStefano Stabellini 		if (map->active_socket) {
501aa7ba376SStefano Stabellini 			/* No need to lock, refcount is 0 */
502aa7ba376SStefano Stabellini 			pvcalls_front_free_map(bedata, map);
503aa7ba376SStefano Stabellini 		} else {
504aa7ba376SStefano Stabellini 			list_del(&map->list);
505aa7ba376SStefano Stabellini 			kfree(map);
506aa7ba376SStefano Stabellini 		}
507aa7ba376SStefano Stabellini 	}
508aa7ba376SStefano Stabellini 	if (bedata->ref >= 0)
509aa7ba376SStefano Stabellini 		gnttab_end_foreign_access(bedata->ref, 0, 0);
510aa7ba376SStefano Stabellini 	kfree(bedata->ring.sring);
511aa7ba376SStefano Stabellini 	kfree(bedata);
512aa7ba376SStefano Stabellini 	xenbus_switch_state(dev, XenbusStateClosed);
513416efba0SStefano Stabellini 	return 0;
514416efba0SStefano Stabellini }
515416efba0SStefano Stabellini 
516416efba0SStefano Stabellini static int pvcalls_front_probe(struct xenbus_device *dev,
517416efba0SStefano Stabellini 			  const struct xenbus_device_id *id)
518416efba0SStefano Stabellini {
51921968190SStefano Stabellini 	int ret = -ENOMEM, evtchn, i;
52021968190SStefano Stabellini 	unsigned int max_page_order, function_calls, len;
52121968190SStefano Stabellini 	char *versions;
52221968190SStefano Stabellini 	grant_ref_t gref_head = 0;
52321968190SStefano Stabellini 	struct xenbus_transaction xbt;
52421968190SStefano Stabellini 	struct pvcalls_bedata *bedata = NULL;
52521968190SStefano Stabellini 	struct xen_pvcalls_sring *sring;
52621968190SStefano Stabellini 
52721968190SStefano Stabellini 	if (pvcalls_front_dev != NULL) {
52821968190SStefano Stabellini 		dev_err(&dev->dev, "only one PV Calls connection supported\n");
52921968190SStefano Stabellini 		return -EINVAL;
53021968190SStefano Stabellini 	}
53121968190SStefano Stabellini 
53221968190SStefano Stabellini 	versions = xenbus_read(XBT_NIL, dev->otherend, "versions", &len);
53321968190SStefano Stabellini 	if (!len)
53421968190SStefano Stabellini 		return -EINVAL;
53521968190SStefano Stabellini 	if (strcmp(versions, "1")) {
53621968190SStefano Stabellini 		kfree(versions);
53721968190SStefano Stabellini 		return -EINVAL;
53821968190SStefano Stabellini 	}
53921968190SStefano Stabellini 	kfree(versions);
54021968190SStefano Stabellini 	max_page_order = xenbus_read_unsigned(dev->otherend,
54121968190SStefano Stabellini 					      "max-page-order", 0);
54221968190SStefano Stabellini 	if (max_page_order < PVCALLS_RING_ORDER)
54321968190SStefano Stabellini 		return -ENODEV;
54421968190SStefano Stabellini 	function_calls = xenbus_read_unsigned(dev->otherend,
54521968190SStefano Stabellini 					      "function-calls", 0);
54621968190SStefano Stabellini 	/* See XENBUS_FUNCTIONS_CALLS in pvcalls.h */
54721968190SStefano Stabellini 	if (function_calls != 1)
54821968190SStefano Stabellini 		return -ENODEV;
54921968190SStefano Stabellini 	pr_info("%s max-page-order is %u\n", __func__, max_page_order);
55021968190SStefano Stabellini 
55121968190SStefano Stabellini 	bedata = kzalloc(sizeof(struct pvcalls_bedata), GFP_KERNEL);
55221968190SStefano Stabellini 	if (!bedata)
55321968190SStefano Stabellini 		return -ENOMEM;
55421968190SStefano Stabellini 
55521968190SStefano Stabellini 	dev_set_drvdata(&dev->dev, bedata);
55621968190SStefano Stabellini 	pvcalls_front_dev = dev;
55721968190SStefano Stabellini 	init_waitqueue_head(&bedata->inflight_req);
55821968190SStefano Stabellini 	INIT_LIST_HEAD(&bedata->socket_mappings);
55921968190SStefano Stabellini 	spin_lock_init(&bedata->socket_lock);
56021968190SStefano Stabellini 	bedata->irq = -1;
56121968190SStefano Stabellini 	bedata->ref = -1;
56221968190SStefano Stabellini 
56321968190SStefano Stabellini 	for (i = 0; i < PVCALLS_NR_RSP_PER_RING; i++)
56421968190SStefano Stabellini 		bedata->rsp[i].req_id = PVCALLS_INVALID_ID;
56521968190SStefano Stabellini 
56621968190SStefano Stabellini 	sring = (struct xen_pvcalls_sring *) __get_free_page(GFP_KERNEL |
56721968190SStefano Stabellini 							     __GFP_ZERO);
56821968190SStefano Stabellini 	if (!sring)
56921968190SStefano Stabellini 		goto error;
57021968190SStefano Stabellini 	SHARED_RING_INIT(sring);
57121968190SStefano Stabellini 	FRONT_RING_INIT(&bedata->ring, sring, XEN_PAGE_SIZE);
57221968190SStefano Stabellini 
57321968190SStefano Stabellini 	ret = xenbus_alloc_evtchn(dev, &evtchn);
57421968190SStefano Stabellini 	if (ret)
57521968190SStefano Stabellini 		goto error;
57621968190SStefano Stabellini 
57721968190SStefano Stabellini 	bedata->irq = bind_evtchn_to_irqhandler(evtchn,
57821968190SStefano Stabellini 						pvcalls_front_event_handler,
57921968190SStefano Stabellini 						0, "pvcalls-frontend", dev);
58021968190SStefano Stabellini 	if (bedata->irq < 0) {
58121968190SStefano Stabellini 		ret = bedata->irq;
58221968190SStefano Stabellini 		goto error;
58321968190SStefano Stabellini 	}
58421968190SStefano Stabellini 
58521968190SStefano Stabellini 	ret = gnttab_alloc_grant_references(1, &gref_head);
58621968190SStefano Stabellini 	if (ret < 0)
58721968190SStefano Stabellini 		goto error;
58821968190SStefano Stabellini 	bedata->ref = gnttab_claim_grant_reference(&gref_head);
58921968190SStefano Stabellini 	if (bedata->ref < 0) {
59021968190SStefano Stabellini 		ret = bedata->ref;
59121968190SStefano Stabellini 		goto error;
59221968190SStefano Stabellini 	}
59321968190SStefano Stabellini 	gnttab_grant_foreign_access_ref(bedata->ref, dev->otherend_id,
59421968190SStefano Stabellini 					virt_to_gfn((void *)sring), 0);
59521968190SStefano Stabellini 
59621968190SStefano Stabellini  again:
59721968190SStefano Stabellini 	ret = xenbus_transaction_start(&xbt);
59821968190SStefano Stabellini 	if (ret) {
59921968190SStefano Stabellini 		xenbus_dev_fatal(dev, ret, "starting transaction");
60021968190SStefano Stabellini 		goto error;
60121968190SStefano Stabellini 	}
60221968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "version", "%u", 1);
60321968190SStefano Stabellini 	if (ret)
60421968190SStefano Stabellini 		goto error_xenbus;
60521968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "ring-ref", "%d", bedata->ref);
60621968190SStefano Stabellini 	if (ret)
60721968190SStefano Stabellini 		goto error_xenbus;
60821968190SStefano Stabellini 	ret = xenbus_printf(xbt, dev->nodename, "port", "%u",
60921968190SStefano Stabellini 			    evtchn);
61021968190SStefano Stabellini 	if (ret)
61121968190SStefano Stabellini 		goto error_xenbus;
61221968190SStefano Stabellini 	ret = xenbus_transaction_end(xbt, 0);
61321968190SStefano Stabellini 	if (ret) {
61421968190SStefano Stabellini 		if (ret == -EAGAIN)
61521968190SStefano Stabellini 			goto again;
61621968190SStefano Stabellini 		xenbus_dev_fatal(dev, ret, "completing transaction");
61721968190SStefano Stabellini 		goto error;
61821968190SStefano Stabellini 	}
61921968190SStefano Stabellini 	xenbus_switch_state(dev, XenbusStateInitialised);
62021968190SStefano Stabellini 
621416efba0SStefano Stabellini 	return 0;
62221968190SStefano Stabellini 
62321968190SStefano Stabellini  error_xenbus:
62421968190SStefano Stabellini 	xenbus_transaction_end(xbt, 1);
62521968190SStefano Stabellini 	xenbus_dev_fatal(dev, ret, "writing xenstore");
62621968190SStefano Stabellini  error:
62721968190SStefano Stabellini 	pvcalls_front_remove(dev);
62821968190SStefano Stabellini 	return ret;
629416efba0SStefano Stabellini }
630416efba0SStefano Stabellini 
631416efba0SStefano Stabellini static void pvcalls_front_changed(struct xenbus_device *dev,
632416efba0SStefano Stabellini 			    enum xenbus_state backend_state)
633416efba0SStefano Stabellini {
63421968190SStefano Stabellini 	switch (backend_state) {
63521968190SStefano Stabellini 	case XenbusStateReconfiguring:
63621968190SStefano Stabellini 	case XenbusStateReconfigured:
63721968190SStefano Stabellini 	case XenbusStateInitialising:
63821968190SStefano Stabellini 	case XenbusStateInitialised:
63921968190SStefano Stabellini 	case XenbusStateUnknown:
64021968190SStefano Stabellini 		break;
64121968190SStefano Stabellini 
64221968190SStefano Stabellini 	case XenbusStateInitWait:
64321968190SStefano Stabellini 		break;
64421968190SStefano Stabellini 
64521968190SStefano Stabellini 	case XenbusStateConnected:
64621968190SStefano Stabellini 		xenbus_switch_state(dev, XenbusStateConnected);
64721968190SStefano Stabellini 		break;
64821968190SStefano Stabellini 
64921968190SStefano Stabellini 	case XenbusStateClosed:
65021968190SStefano Stabellini 		if (dev->state == XenbusStateClosed)
65121968190SStefano Stabellini 			break;
65221968190SStefano Stabellini 		/* Missed the backend's CLOSING state -- fallthrough */
65321968190SStefano Stabellini 	case XenbusStateClosing:
65421968190SStefano Stabellini 		xenbus_frontend_closed(dev);
65521968190SStefano Stabellini 		break;
65621968190SStefano Stabellini 	}
657416efba0SStefano Stabellini }
658416efba0SStefano Stabellini 
659416efba0SStefano Stabellini static struct xenbus_driver pvcalls_front_driver = {
660416efba0SStefano Stabellini 	.ids = pvcalls_front_ids,
661416efba0SStefano Stabellini 	.probe = pvcalls_front_probe,
662416efba0SStefano Stabellini 	.remove = pvcalls_front_remove,
663416efba0SStefano Stabellini 	.otherend_changed = pvcalls_front_changed,
664416efba0SStefano Stabellini };
665416efba0SStefano Stabellini 
666416efba0SStefano Stabellini static int __init pvcalls_frontend_init(void)
667416efba0SStefano Stabellini {
668416efba0SStefano Stabellini 	if (!xen_domain())
669416efba0SStefano Stabellini 		return -ENODEV;
670416efba0SStefano Stabellini 
671416efba0SStefano Stabellini 	pr_info("Initialising Xen pvcalls frontend driver\n");
672416efba0SStefano Stabellini 
673416efba0SStefano Stabellini 	return xenbus_register_frontend(&pvcalls_front_driver);
674416efba0SStefano Stabellini }
675416efba0SStefano Stabellini 
676416efba0SStefano Stabellini module_init(pvcalls_frontend_init);
677