[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 |