|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH 5/9] plat/xen/drivers/9p: Connect to xenbus device
From: Cristian Banu <cristb@xxxxxxxxx>
This patch implements ring allocation, reference granting and event channel
allocation, with the purpose of establishing the connection to the
backend 9pfs device.
Signed-off-by: Cristian Banu <cristb@xxxxxxxxx>
---
plat/xen/Config.uk | 19 ++-
plat/xen/drivers/9p/9pfront.c | 167 +++++++++++++++++++++++++
plat/xen/drivers/9p/9pfront.h | 29 +++++
plat/xen/drivers/9p/9pfront_xb.h | 12 ++
plat/xen/drivers/9p/9pfront_xs.c | 204 +++++++++++++++++++++++++++++++
5 files changed, 430 insertions(+), 1 deletion(-)
diff --git a/plat/xen/Config.uk b/plat/xen/Config.uk
index dfffb320..1ad7f7e4 100644
--- a/plat/xen/Config.uk
+++ b/plat/xen/Config.uk
@@ -73,11 +73,28 @@ menu "Xenbus Drivers"
depends on XEN_XENBUS
depends on XEN_GNTTAB
-config XEN_9PFRONT
+menuconfig XEN_9PFRONT
bool "Xenbus 9pfront Driver"
default n
depends on LIBUK9P
help
Driver for 9pfs devices
+
+config XEN_9PFRONT_NB_RINGS
+ int "Xen 9P ring number"
+ default 2
+ depends on XEN_9PFRONT
+ help
+ Number of rings to allocate.
+ Will be clamped to the maximum value allowed by the backend.
+
+config XEN_9PFRONT_RING_ORDER
+ int "Xen 9P ring order"
+ default 6
+ depends on XEN_9PFRONT
+ help
+ Ring order for xen 9P devices. Orders of 0, 1, 2, ..., 9 will
+ create rings of size 4K, 8K, 16K, ..., 2M respectively.
+ Will be clamped to the maximum value allowed by the backend.
endmenu
endif
diff --git a/plat/xen/drivers/9p/9pfront.c b/plat/xen/drivers/9p/9pfront.c
index f289cd05..3898cb85 100644
--- a/plat/xen/drivers/9p/9pfront.c
+++ b/plat/xen/drivers/9p/9pfront.c
@@ -32,12 +32,15 @@
* THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
*/
+#include <stdbool.h>
#include <uk/config.h>
#include <uk/alloc.h>
#include <uk/assert.h>
#include <uk/essentials.h>
#include <uk/list.h>
#include <uk/plat/spinlock.h>
+#include <xen-x86/mm.h>
+#include <xen-x86/irq.h>
#include <xenbus/xenbus.h>
#include "9pfront_xb.h"
@@ -48,6 +51,142 @@ static struct uk_alloc *a;
static UK_LIST_HEAD(p9front_device_list);
static DEFINE_SPINLOCK(p9front_device_list_lock);
+static void p9front_handler(evtchn_port_t evtchn __unused,
+ struct __regs *regs __unused,
+ void *arg __unused)
+{
+}
+
+static void p9front_free_dev_ring(struct p9front_dev *p9fdev, int idx)
+{
+ struct p9front_dev_ring *ring = &p9fdev->rings[idx];
+ int i;
+
+ UK_ASSERT(ring->initialized);
+
+ unbind_evtchn(ring->evtchn);
+ for (i = 0; i < (1 << p9fdev->ring_order); i++)
+ gnttab_end_access(ring->intf->ref[i]);
+ uk_pfree(a, ring->data.in,
+ p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
+ gnttab_end_access(ring->ref);
+ uk_pfree(a, ring->intf, 0);
+ ring->initialized = false;
+}
+
+static void p9front_free_dev_rings(struct p9front_dev *p9fdev)
+{
+ int i;
+
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ if (!p9fdev->rings[i].initialized)
+ continue;
+ p9front_free_dev_ring(p9fdev, i);
+ }
+
+ uk_free(a, p9fdev->rings);
+}
+
+static int p9front_allocate_dev_ring(struct p9front_dev *p9fdev, int idx)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ struct p9front_dev_ring *ring;
+ int rc, i;
+ void *data_bytes;
+
+ /* Sanity checks. */
+ UK_ASSERT(idx >= 0 && idx < p9fdev->nb_rings);
+
+ ring = &p9fdev->rings[idx];
+ UK_ASSERT(!ring->initialized);
+
+ ukarch_spin_lock_init(&ring->spinlock);
+ ring->dev = p9fdev;
+
+ /* Allocate ring intf page. */
+ ring->intf = uk_palloc(a, 0);
+ if (!ring->intf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ring->intf, 0, PAGE_SIZE);
+
+ /* Grant access to the allocated page to the backend. */
+ ring->ref = gnttab_grant_access(xendev->otherend_id,
+ virt_to_mfn(ring->intf), 0);
+ UK_ASSERT(ring->ref != GRANT_INVALID_REF);
+
+ /* Allocate memory for the data. */
+ data_bytes = uk_palloc(a,
+ p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
+ if (!data_bytes) {
+ rc = -ENOMEM;
+ goto out_free_intf;
+ }
+ memset(data_bytes, 0, XEN_FLEX_RING_SIZE(p9fdev->ring_order) * 2);
+
+ /* Grant refs to the entire data. */
+ for (i = 0; i < (1 << p9fdev->ring_order); i++) {
+ ring->intf->ref[i] = gnttab_grant_access(xendev->otherend_id,
+ virt_to_mfn(data_bytes) + i, 0);
+ UK_ASSERT(ring->intf->ref[i] != GRANT_INVALID_REF);
+ }
+
+ ring->intf->ring_order = p9fdev->ring_order;
+ ring->data.in = data_bytes;
+ ring->data.out = data_bytes + XEN_FLEX_RING_SIZE(p9fdev->ring_order);
+
+ /* Allocate event channel. */
+ rc = evtchn_alloc_unbound(xendev->otherend_id, p9front_handler, ring,
+ &ring->evtchn);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Error creating evt channel: %d\n", rc);
+ goto out_free_grants;
+ }
+
+ unmask_evtchn(ring->evtchn);
+
+ /* Mark ring as initialized. */
+ ring->initialized = true;
+
+ return 0;
+
+out_free_grants:
+ for (i = 0; i < (1 << p9fdev->ring_order); i++)
+ gnttab_end_access(ring->intf->ref[i]);
+ uk_pfree(a, data_bytes,
+ p9fdev->ring_order + XEN_PAGE_SHIFT - PAGE_SHIFT);
+out_free_intf:
+ gnttab_end_access(ring->ref);
+ uk_pfree(a, ring->intf, 0);
+out:
+ return rc;
+}
+
+static int p9front_allocate_dev_rings(struct p9front_dev *p9fdev)
+{
+ int rc, i;
+
+ p9fdev->rings = uk_calloc(a, p9fdev->nb_rings, sizeof(*p9fdev->rings));
+ if (!p9fdev->rings) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ rc = p9front_allocate_dev_ring(p9fdev, i);
+ if (rc)
+ goto out_free;
+ }
+
+ return 0;
+
+out_free:
+ p9front_free_dev_rings(p9fdev);
+out:
+ return rc;
+}
+
static int p9front_drv_init(struct uk_alloc *drv_allocator)
{
if (!drv_allocator)
@@ -75,11 +214,39 @@ static int p9front_add_dev(struct xenbus_device *xendev)
if (rc)
goto out_free;
+ uk_pr_info("Initialized 9pfront dev: tag=%s,maxrings=%d,maxorder=%d\n",
+ p9fdev->tag, p9fdev->nb_max_rings, p9fdev->max_ring_page_order);
+
+ p9fdev->nb_rings = MIN(CONFIG_XEN_9PFRONT_NB_RINGS,
+ p9fdev->nb_max_rings);
+ p9fdev->ring_order = MIN(CONFIG_XEN_9PFRONT_RING_ORDER,
+ p9fdev->max_ring_page_order);
+
+ rc = p9front_allocate_dev_rings(p9fdev);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Could not initialize device rings:
%d\n",
+ rc);
+ goto out_free;
+ }
+
+ rc = p9front_xb_connect(p9fdev);
+ if (rc) {
+ uk_pr_err(DRIVER_NAME": Could not connect: %d\n", rc);
+ goto out_free_rings;
+ }
+
rc = 0;
ukplat_spin_lock_irqsave(&p9front_device_list_lock, flags);
uk_list_add(&p9fdev->_list, &p9front_device_list);
ukplat_spin_unlock_irqrestore(&p9front_device_list_lock, flags);
+ uk_pr_info(DRIVER_NAME": Connected 9pfront dev:
tag=%s,rings=%d,order=%d\n",
+ p9fdev->tag, p9fdev->nb_rings, p9fdev->ring_order);
+
+ goto out;
+
+out_free_rings:
+ p9front_free_dev_rings(p9fdev);
out_free:
uk_free(a, p9fdev);
out:
diff --git a/plat/xen/drivers/9p/9pfront.h b/plat/xen/drivers/9p/9pfront.h
index e77f315a..97c986d8 100644
--- a/plat/xen/drivers/9p/9pfront.h
+++ b/plat/xen/drivers/9p/9pfront.h
@@ -35,9 +35,31 @@
#ifndef __9PFRONT_H__
#define __9PFRONT_H__
+#include <string.h>
#include <uk/config.h>
#include <uk/essentials.h>
#include <uk/list.h>
+#include <uk/plat/spinlock.h>
+#include <xen/io/9pfs.h>
+#include <common/events.h>
+#include <common/gnttab.h>
+
+struct p9front_dev_ring {
+ /* Backpointer to the p9front device. */
+ struct p9front_dev *dev;
+ /* The 9pfs data interface, as dedfined by the xen headers. */
+ struct xen_9pfs_data_intf *intf;
+ /* The 9pfs data, as defined by the xen headers. */
+ struct xen_9pfs_data data;
+ /* The event channel for this ring. */
+ evtchn_port_t evtchn;
+ /* Grant reference for the interface. */
+ grant_ref_t ref;
+ /* Per-ring spinlock. */
+ spinlock_t spinlock;
+ /* Tracks if this ring was initialized. */
+ bool initialized;
+};
struct p9front_dev {
/* Xenbus device. */
@@ -50,6 +72,13 @@ struct p9front_dev {
int max_ring_page_order;
/* Mount tag for this device, read from xenstore. */
char *tag;
+
+ /* Number of rings to use. */
+ int nb_rings;
+ /* Ring page order. */
+ int ring_order;
+ /* Device data rings. */
+ struct p9front_dev_ring *rings;
};
#endif /* __9PFRONT_H__ */
diff --git a/plat/xen/drivers/9p/9pfront_xb.h b/plat/xen/drivers/9p/9pfront_xb.h
index 224df7af..6e2697f9 100644
--- a/plat/xen/drivers/9p/9pfront_xb.h
+++ b/plat/xen/drivers/9p/9pfront_xb.h
@@ -50,4 +50,16 @@
*/
int p9front_xb_init(struct p9front_dev *p9fdev);
+/**
+ * Connects to the backend by setting up the communication between
+ * frontend and backend.
+ *
+ * @param p9fdev
+ * 9P frontend device
+ * @return
+ * - (0): Successful.
+ * - (< 0): Error while committing XenStore transaction.
+ */
+int p9front_xb_connect(struct p9front_dev *p9fdev);
+
#endif /* __9PFRONT_XB_H__ */
diff --git a/plat/xen/drivers/9p/9pfront_xs.c b/plat/xen/drivers/9p/9pfront_xs.c
index 5b5dc2e4..7185061c 100644
--- a/plat/xen/drivers/9p/9pfront_xs.c
+++ b/plat/xen/drivers/9p/9pfront_xs.c
@@ -154,3 +154,207 @@ int p9front_xb_init(struct p9front_dev *p9fdev)
out:
return rc;
}
+
+static int xs_write_ring(struct p9front_dev *p9fdev,
+ int i,
+ xenbus_transaction_t xbt)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ struct p9front_dev_ring *ring = &p9fdev->rings[i];
+ char *path;
+ int rc;
+
+ rc = asprintf(&path, "ring-ref%u", i);
+ if (rc < 0)
+ goto out;
+
+ rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->ref);
+ if (rc < 0)
+ goto out_path;
+
+ free(path);
+ rc = asprintf(&path, "event-channel-%u", i);
+ if (rc < 0)
+ goto out;
+
+ rc = xs_printf(xbt, xendev->nodename, path, "%u", ring->evtchn);
+ if (rc < 0)
+ goto out_path;
+
+ rc = 0;
+
+out_path:
+ free(path);
+out:
+ return rc;
+}
+
+static void xs_delete_ring(struct p9front_dev *p9fdev,
+ int i,
+ xenbus_transaction_t xbt)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ int rc;
+ char *path;
+
+ rc = asprintf(&path, "%s/ring-ref%u", xendev->nodename, i);
+ if (rc < 0)
+ return;
+ xs_rm(xbt, path);
+ free(path);
+
+ rc = asprintf(&path, "%s/event-channel-%u", xendev->nodename, i);
+ if (rc < 0)
+ return;
+ xs_rm(xbt, path);
+ free(path);
+}
+
+static int p9front_xb_front_init(struct p9front_dev *p9fdev,
+ xenbus_transaction_t xbt)
+{
+ int i, rc;
+ struct xenbus_device *xendev = p9fdev->xendev;
+
+ /*
+ * Assert that the p9fdev ring information has been properly
+ * configured before attempting to connect.
+ */
+ UK_ASSERT(p9fdev->nb_rings != 0 && p9fdev->nb_rings <= 9);
+ UK_ASSERT(p9fdev->ring_order != 0);
+
+ /*
+ * Assert that the p9fdev rings have been initialized.
+ */
+ UK_ASSERT(p9fdev->rings != NULL);
+
+ /* Write version... */
+ rc = xs_printf(xbt, xendev->nodename, "version", "%u", 1);
+ if (rc < 0)
+ goto out;
+
+ /* ... and num-rings... */
+ rc = xs_printf(xbt, xendev->nodename, "num-rings", "%u",
+ p9fdev->nb_rings);
+ if (rc < 0)
+ goto out;
+
+ /* ... and each ring. */
+ for (i = 0; i < p9fdev->nb_rings; i++) {
+ rc = xs_write_ring(p9fdev, i, xbt);
+ if (rc)
+ goto out;
+ }
+
+out:
+ return rc;
+}
+
+static void p9front_xb_front_fini(struct p9front_dev *p9fdev,
+ xenbus_transaction_t xbt)
+{
+ int i;
+
+ for (i = 0; i < p9fdev->nb_rings; i++)
+ xs_delete_ring(p9fdev, i, xbt);
+}
+
+static int be_watch_start(struct xenbus_device *xendev, const char *path)
+{
+ struct xenbus_watch *watch;
+
+ watch = xs_watch_path(XBT_NIL, path);
+ if (PTRISERR(watch))
+ return PTR2ERR(watch);
+
+ xendev->otherend_watch = watch;
+
+ return 0;
+}
+
+static int be_watch_stop(struct xenbus_device *xendev)
+{
+ return xs_unwatch(XBT_NIL, xendev->otherend_watch);
+}
+
+#define WAIT_BE_STATE_CHANGE_WHILE_COND(state_cond) \
+ do { \
+ rc = xs_read_integer(XBT_NIL, be_state_path, \
+ (int *) &be_state); \
+ if (rc) \
+ goto out; \
+ while (!rc && (state_cond)) \
+ rc = xenbus_wait_for_state_change(be_state_path, \
+ &be_state, xendev->otherend_watch); \
+ if (rc) \
+ goto out; \
+ } while (0)
+
+static int p9front_xb_wait_be_connect(struct p9front_dev *p9fdev)
+{
+ struct xenbus_device *xendev = p9fdev->xendev;
+ char be_state_path[strlen(xendev->otherend) + sizeof("/state")];
+ XenbusState be_state;
+ int rc;
+
+ sprintf(be_state_path, "%s/state", xendev->otherend);
+
+ rc = be_watch_start(xendev, be_state_path);
+ if (rc)
+ goto out;
+
+ WAIT_BE_STATE_CHANGE_WHILE_COND(be_state < XenbusStateConnected);
+
+ if (be_state != XenbusStateConnected) {
+ uk_pr_err("Backend not available, state=%s\n",
+ xenbus_state_to_str(be_state));
+ be_watch_stop(xendev);
+ goto out;
+ }
+
+ rc = xenbus_switch_state(XBT_NIL, xendev, XenbusStateConnected);
+ if (rc)
+ goto out;
+
+out:
+ return rc;
+}
+
+int p9front_xb_connect(struct p9front_dev *p9fdev)
+{
+ struct xenbus_device *xendev;
+ xenbus_transaction_t xbt;
+ int rc;
+
+ UK_ASSERT(p9fdev != NULL);
+
+ xendev = p9fdev->xendev;
+ UK_ASSERT(xendev != NULL);
+
+again:
+ rc = xs_transaction_start(&xbt);
+ if (rc)
+ goto abort_transaction;
+
+ rc = p9front_xb_front_init(p9fdev, xbt);
+ if (rc)
+ goto abort_transaction;
+
+ rc = xenbus_switch_state(xbt, xendev, XenbusStateInitialised);
+ if (rc)
+ goto abort_transaction;
+
+ rc = xs_transaction_end(xbt, 0);
+ if (rc == -EAGAIN)
+ goto again;
+
+ rc = p9front_xb_wait_be_connect(p9fdev);
+ if (rc)
+ p9front_xb_front_fini(p9fdev, XBT_NIL);
+
+ return rc;
+
+abort_transaction:
+ xs_transaction_end(xbt, 1);
+ return rc;
+}
--
2.20.1
_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |