Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0a9c75c2 authored by Stefano Stabellini's avatar Stefano Stabellini Committed by Boris Ostrovsky
Browse files

xen/pvcalls: xenbus state handling



Introduce the code to handle xenbus state changes.

Implement the probe function for the pvcalls backend. Write the
supported versions, max-page-order and function-calls nodes to xenstore,
as required by the protocol.

Introduce stub functions for disconnecting/connecting to a frontend.

Signed-off-by: default avatarStefano Stabellini <stefano@aporeto.com>
Reviewed-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: default avatarJuergen Gross <jgross@suse.com>
CC: boris.ostrovsky@oracle.com
CC: jgross@suse.com
Signed-off-by: default avatarBoris Ostrovsky <boris.ostrovsky@oracle.com>
parent 9be07334
Loading
Loading
Loading
Loading
+155 −0
Original line number Original line Diff line number Diff line
@@ -25,20 +25,175 @@
#include <xen/xenbus.h>
#include <xen/xenbus.h>
#include <xen/interface/io/pvcalls.h>
#include <xen/interface/io/pvcalls.h>


#define PVCALLS_VERSIONS "1"
#define MAX_RING_ORDER XENBUS_MAX_RING_GRANT_ORDER

struct pvcalls_back_global {
struct pvcalls_back_global {
	struct list_head frontends;
	struct list_head frontends;
	struct semaphore frontends_lock;
	struct semaphore frontends_lock;
} pvcalls_back_global;
} pvcalls_back_global;


static int backend_connect(struct xenbus_device *dev)
{
	return 0;
}

static int backend_disconnect(struct xenbus_device *dev)
{
	return 0;
}

static int pvcalls_back_probe(struct xenbus_device *dev,
static int pvcalls_back_probe(struct xenbus_device *dev,
			      const struct xenbus_device_id *id)
			      const struct xenbus_device_id *id)
{
{
	int err, abort;
	struct xenbus_transaction xbt;

again:
	abort = 1;

	err = xenbus_transaction_start(&xbt);
	if (err) {
		pr_warn("%s cannot create xenstore transaction\n", __func__);
		return err;
	}

	err = xenbus_printf(xbt, dev->nodename, "versions", "%s",
			    PVCALLS_VERSIONS);
	if (err) {
		pr_warn("%s write out 'versions' failed\n", __func__);
		goto abort;
	}

	err = xenbus_printf(xbt, dev->nodename, "max-page-order", "%u",
			    MAX_RING_ORDER);
	if (err) {
		pr_warn("%s write out 'max-page-order' failed\n", __func__);
		goto abort;
	}

	err = xenbus_printf(xbt, dev->nodename, "function-calls",
			    XENBUS_FUNCTIONS_CALLS);
	if (err) {
		pr_warn("%s write out 'function-calls' failed\n", __func__);
		goto abort;
	}

	abort = 0;
abort:
	err = xenbus_transaction_end(xbt, abort);
	if (err) {
		if (err == -EAGAIN && !abort)
			goto again;
		pr_warn("%s cannot complete xenstore transaction\n", __func__);
		return err;
	}

	if (abort)
		return -EFAULT;

	xenbus_switch_state(dev, XenbusStateInitWait);

	return 0;
	return 0;
}
}


static void set_backend_state(struct xenbus_device *dev,
			      enum xenbus_state state)
{
	while (dev->state != state) {
		switch (dev->state) {
		case XenbusStateClosed:
			switch (state) {
			case XenbusStateInitWait:
			case XenbusStateConnected:
				xenbus_switch_state(dev, XenbusStateInitWait);
				break;
			case XenbusStateClosing:
				xenbus_switch_state(dev, XenbusStateClosing);
				break;
			default:
				__WARN();
			}
			break;
		case XenbusStateInitWait:
		case XenbusStateInitialised:
			switch (state) {
			case XenbusStateConnected:
				backend_connect(dev);
				xenbus_switch_state(dev, XenbusStateConnected);
				break;
			case XenbusStateClosing:
			case XenbusStateClosed:
				xenbus_switch_state(dev, XenbusStateClosing);
				break;
			default:
				__WARN();
			}
			break;
		case XenbusStateConnected:
			switch (state) {
			case XenbusStateInitWait:
			case XenbusStateClosing:
			case XenbusStateClosed:
				down(&pvcalls_back_global.frontends_lock);
				backend_disconnect(dev);
				up(&pvcalls_back_global.frontends_lock);
				xenbus_switch_state(dev, XenbusStateClosing);
				break;
			default:
				__WARN();
			}
			break;
		case XenbusStateClosing:
			switch (state) {
			case XenbusStateInitWait:
			case XenbusStateConnected:
			case XenbusStateClosed:
				xenbus_switch_state(dev, XenbusStateClosed);
				break;
			default:
				__WARN();
			}
			break;
		default:
			__WARN();
		}
	}
}

static void pvcalls_back_changed(struct xenbus_device *dev,
static void pvcalls_back_changed(struct xenbus_device *dev,
				 enum xenbus_state frontend_state)
				 enum xenbus_state frontend_state)
{
{
	switch (frontend_state) {
	case XenbusStateInitialising:
		set_backend_state(dev, XenbusStateInitWait);
		break;

	case XenbusStateInitialised:
	case XenbusStateConnected:
		set_backend_state(dev, XenbusStateConnected);
		break;

	case XenbusStateClosing:
		set_backend_state(dev, XenbusStateClosing);
		break;

	case XenbusStateClosed:
		set_backend_state(dev, XenbusStateClosed);
		if (xenbus_dev_is_online(dev))
			break;
		device_unregister(&dev->dev);
		break;
	case XenbusStateUnknown:
		set_backend_state(dev, XenbusStateClosed);
		device_unregister(&dev->dev);
		break;

	default:
		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
				 frontend_state);
		break;
	}
}
}


static int pvcalls_back_remove(struct xenbus_device *dev)
static int pvcalls_back_remove(struct xenbus_device *dev)