[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH v2 4/7] lib/ukconsdev: Configure console device



This patch introduces the API for configuring a Unikraft console device.
The configuration is done in the following order:
     (1) Configure main aspects of device (placeholder for future work)
     (2) Configure both rx and tx (tx is also a placeholder)
Configure API initializes the main data structures for rx/tx.

Signed-off-by: Birlea Costin <costin.birlea@xxxxxxxxx>
---
 lib/ukconsdev/Config.uk                   |  14 ++
 lib/ukconsdev/consdev.c                   | 218 ++++++++++++++++++++++++++++++
 lib/ukconsdev/exportsyms.uk               |   4 +
 lib/ukconsdev/include/uk/consdev.h        |  66 +++++++++
 lib/ukconsdev/include/uk/consdev_core.h   |  87 ++++++++++++
 lib/ukconsdev/include/uk/consdev_driver.h |  24 ++++
 6 files changed, 413 insertions(+)

diff --git a/lib/ukconsdev/Config.uk b/lib/ukconsdev/Config.uk
index e434f1d4..cf676388 100644
--- a/lib/ukconsdev/Config.uk
+++ b/lib/ukconsdev/Config.uk
@@ -4,3 +4,17 @@ menuconfig LIBUKCONSDEV
        select LIBUKALLOC
        select LIBNOLIBC if !HAVE_LIBC
 
+if LIBUKCONSDEV
+       config LIBUKCONSDEV_DISPATCHERTHREADS
+               bool "Dispatcher threads for event callbacks"
+               select LIBUKSCHED
+               select LIBUKLOCK
+               select LIBUKLOCK_SEMAPHORE
+               default n
+               help
+                       Event callbacks are dispatched in a bottom half
+                       thread context instead of the device interrupt context.
+                       When this option is enabled one dispatcher thread is
+                       allocated for each device to handle receive events.
+                       libuksched is required for this option.
+endif
diff --git a/lib/ukconsdev/consdev.c b/lib/ukconsdev/consdev.c
index 1b155190..98c063f4 100644
--- a/lib/ukconsdev/consdev.c
+++ b/lib/ukconsdev/consdev.c
@@ -58,6 +58,33 @@ void uk_consdev_info_get(struct uk_consdev *dev,
        dev->ops->info_get(dev, dev_info);
 }
 
+int uk_consdev_configure(struct uk_consdev *dev,
+               const struct uk_consdev_conf *dev_conf)
+{
+       int rc = 0;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(dev->_data);
+       UK_ASSERT(dev->ops);
+       UK_ASSERT(dev->ops->configure);
+       UK_ASSERT(dev_conf);
+
+       if (dev->_data->state != UK_CONSDEV_UNCONFIGURED)
+               return -EINVAL;
+
+       rc = dev->ops->configure(dev, dev_conf);
+       if (rc < 0) {
+               uk_pr_err("consdev%"PRIu16": Failed to configure device: %d\n",
+                               dev->_data->id, rc);
+               goto out;
+       }
+
+       dev->_data->state = UK_CONSDEV_CONFIGURED;
+
+out:
+       return rc;
+}
+
 int uk_consdev_rxq_info_get(struct uk_consdev *dev,
                struct uk_consdev_queue_info *queue_info)
 {
@@ -84,6 +111,192 @@ int uk_consdev_txq_info_get(struct uk_consdev *dev,
        return dev->ops->txq_info_get(dev, queue_info);
 }
 
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+static void _dispatcher(void *arg)
+{
+       struct uk_consdev_event_handler *handler =
+               (struct uk_consdev_event_handler *) arg;
+
+       UK_ASSERT(handler);
+       UK_ASSERT(handler->callback);
+
+       while (1) {
+               uk_semaphore_down(&handler->events);
+               handler->callback(handler->dev, handler->cookie);
+       }
+}
+#endif
+
+static int _create_event_handler(uk_consdev_event_t callback,
+               void *cookie,
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+               struct uk_consdev *dev,
+               const char *queue_type_str,
+               struct uk_sched *s,
+#endif
+               struct uk_consdev_event_handler *h)
+{
+       UK_ASSERT(h);
+       UK_ASSERT(callback || (!callback && !cookie));
+
+       h->callback = callback;
+       h->cookie = cookie;
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       /* If we do not have a callback, we do not need a thread */
+       if (!callback)
+               return 0;
+
+       h->dev = dev;
+       uk_semaphore_init(&h->events, 0);
+       h->dispatcher_s = s;
+
+
+       /* Create a name for the dispatcher thread.
+        * In case of errors, we just continue without a name
+        */
+       if (asprintf(&h->dispatcher_name,
+                        "consdev%"PRIu16"-%s",
+                        dev->_data->id, queue_type_str) < 0) {
+               h->dispatcher_name = NULL;
+       }
+
+       /* Create thread */
+       h->dispatcher = uk_sched_thread_create(h->dispatcher_s,
+               h->dispatcher_name, NULL, _dispatcher, (void *)h);
+       if (!h->dispatcher) {
+               if (h->dispatcher_name) {
+                       free(h->dispatcher_name);
+                       h->dispatcher_name = NULL;
+               }
+               return -ENOMEM;
+       }
+#endif
+
+       return 0;
+}
+
+static void _destroy_event_handler(struct uk_consdev_event_handler *h
+               __maybe_unused)
+{
+       UK_ASSERT(h);
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       if (h->dispatcher) {
+               uk_semaphore_up(&h->events);
+               UK_ASSERT(h->dispatcher_s);
+               uk_thread_kill(h->dispatcher);
+               uk_thread_wait(h->dispatcher);
+               h->dispatcher = NULL;
+       }
+
+       if (h->dispatcher_name) {
+               free(h->dispatcher_name);
+               h->dispatcher_name = NULL;
+       }
+#endif
+}
+
+int uk_consdev_rxq_configure(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_rxqueue_conf *rx_conf)
+{
+       int rc = 0;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(dev->_data);
+       UK_ASSERT(dev->ops);
+       UK_ASSERT(dev->ops->rxq_configure);
+       UK_ASSERT(rx_conf);
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       UK_ASSERT((rx_conf->callback && rx_conf->s)
+                       || !rx_conf->callback);
+#endif
+
+       if (dev->_data->state != UK_CONSDEV_CONFIGURED)
+               return -EINVAL;
+
+       rc = _create_event_handler(rx_conf->callback, rx_conf->cookie,
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+                       dev, "rx", rx_conf->s,
+#endif
+                       &dev->_data->rx_handler);
+       if (rc < 0)
+               goto out;
+
+       rc = dev->ops->rxq_configure(dev, size, rx_conf);
+       if (rc < 0) {
+               uk_pr_err("consdev%"PRIu16
+                               ": Failed to configure rx queue: %d\n",
+                               dev->_data->id, rc);
+               goto err_destroy_handler;
+       }
+
+out:
+       return rc;
+
+err_destroy_handler:
+       _destroy_event_handler(&dev->_data->rx_handler);
+       goto out;
+}
+
+int uk_consdev_txq_configure(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_txqueue_conf *tx_conf)
+{
+       int rc = 0;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(dev->_data);
+       UK_ASSERT(dev->ops);
+       UK_ASSERT(dev->ops->txq_configure);
+       UK_ASSERT(tx_conf);
+
+       if (dev->_data->state != UK_CONSDEV_CONFIGURED)
+               return -EINVAL;
+
+       rc = dev->ops->txq_configure(dev, size, tx_conf);
+       if (rc < 0) {
+               uk_pr_err("consdev%"PRIu16
+                               ": Failed to configure tx queue: %d\n",
+                               dev->_data->id, rc);
+               goto out;
+       }
+
+out:
+       return rc;
+}
+
+int uk_consdev_unconfigure(struct uk_consdev *dev)
+{
+       int rc = 0;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(dev->_data);
+       UK_ASSERT(dev->ops);
+       UK_ASSERT(dev->ops->unconfigure);
+       UK_ASSERT(dev->_data->state == UK_CONSDEV_CONFIGURED);
+
+       rc = dev->ops->unconfigure(dev);
+       if (rc < 0) {
+               uk_pr_err("Failed to unconfigure consdev%"PRIu16" device %d\n",
+                               dev->_data->id, rc);
+               goto out;
+       }
+
+#if CONFIG_LIBUKBLKDEV_DISPATCHERTHREADS
+       if (dev->_data->rx_handler.callback)
+               _destroy_event_handler(&dev->_data->rx_handler);
+#endif
+       dev->_data->state = UK_CONSDEV_UNCONFIGURED;
+       uk_pr_info("Unconfigured consdev%"PRIu16" device\n",
+                       dev->_data->id);
+
+out:
+       return rc;
+}
+
 unsigned int uk_consdev_count(void)
 {
        return (unsigned int) consdev_count;
@@ -152,8 +365,13 @@ int uk_consdev_drv_register(struct uk_consdev *dev, struct 
uk_alloc *a,
        /* Assert mandatory configuration. */
        UK_ASSERT(dev->ops);
        UK_ASSERT(dev->ops->info_get);
+       UK_ASSERT(dev->ops->configure);
        UK_ASSERT(dev->ops->rxq_info_get);
        UK_ASSERT(dev->ops->txq_info_get);
+       UK_ASSERT(dev->ops->rxq_configure);
+       UK_ASSERT(dev->ops->txq_configure);
+       UK_ASSERT(dev->ops->unconfigure);
+
        dev->_data = _alloc_data(a, consdev_count, drv_name);
        if (!dev->_data)
                return -ENOMEM;
diff --git a/lib/ukconsdev/exportsyms.uk b/lib/ukconsdev/exportsyms.uk
index 3e8944d1..f023aff3 100644
--- a/lib/ukconsdev/exportsyms.uk
+++ b/lib/ukconsdev/exportsyms.uk
@@ -1,6 +1,10 @@
 uk_consdev_info_get
+uk_consdev_configure
 uk_consdev_rxq_info_get
 uk_consdev_txq_info_get
+uk_consdev_rxq_configure
+uk_consdev_txq_configure
+uk_consdev_unconfigure
 uk_consdev_count
 uk_consdev_get
 uk_consdev_id_get
diff --git a/lib/ukconsdev/include/uk/consdev.h 
b/lib/ukconsdev/include/uk/consdev.h
index 2b61dcf0..e2d523eb 100644
--- a/lib/ukconsdev/include/uk/consdev.h
+++ b/lib/ukconsdev/include/uk/consdev.h
@@ -92,6 +92,21 @@ void uk_consdev_info_get(struct uk_consdev *dev,
                struct uk_consdev_info *dev_info);
 
 /**
+ * Configure an Unikraft console device.
+ *
+ * @param dev
+ *     The Unikraft Console Device in unconfigured state.
+ * @param dev_conf
+ *   The pointer to the configuration data to be used for the Unikraft
+ *   console device.
+ * @return
+ *     - (0): Success, device configured.
+ *     - (<0): Error code returned by the driver configuration function.
+ */
+int uk_consdev_configure(struct uk_consdev *dev,
+               const struct uk_consdev_conf *dev_conf);
+
+/**
  * Query receive device queue capabilities.
  * Information that is useful for device queue initialization (e.g.,
  * size of RX/maximum number of supported descriptors on RX).
@@ -124,6 +139,57 @@ int uk_consdev_txq_info_get(struct uk_consdev *dev,
                struct uk_consdev_queue_info *queue_info);
 
 /**
+ * Sets up receive queue for an Unikraft console device.
+ *
+ * @param dev
+ *   The Unikraft Console Device in configured state.
+ * @param size
+ *   Size of the queue. Inspect uk_consdev_rxq_info_get() to
+ *   retrieve limitations. If size is set to 0, the driver chooses a default
+ *   value.
+ * @param rx_conf
+ *   The pointer to the configuration data to be used for receive.
+ *   Its memory can be released after invoking this function.
+ * @return
+ *   - (0): Success, receive correctly set up.
+ *   - (<0): Unable to allocate the receive queue.
+ */
+int uk_consdev_rxq_configure(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_rxqueue_conf *rx_conf);
+
+/**
+ * Sets up transmit queue for an Unikraft console device.
+ *
+ * @param dev
+ *   The Unikraft Console Device in configured state.
+ * @param size
+ *   Size of the queue. Inspect uk_consdev_txq_info_get() to
+ *   retrieve limitations. If Size is set to 0, the driver chooses a default
+ *   value.
+ * @param tx_conf
+ *   The pointer to the configuration data to be used for transmit.
+ *   Its memory can be released after invoking this function.
+ * @return
+ *   - (0): Success, receive correctly set up.
+ *   - (<0): Unable to allocate the transmit queue.
+ */
+int uk_consdev_txq_configure(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_txqueue_conf *tx_conf);
+
+/**
+ * Unconfigure an Unikraft console device.
+ * Also unconfigures and frees rx and tx queues associated with device.
+ * The device can be reconfigured by calling uk_consdev_configure()
+ * and then uk_consdev_rxq/txq_configure().
+ *
+ * @param dev
+ *     The Unikraft Console Device in configured state.
+ */
+int uk_consdev_unconfigure(struct uk_consdev *dev);
+
+/**
  * Get the number of available Unikraft Console devices.
  *
  * @return
diff --git a/lib/ukconsdev/include/uk/consdev_core.h 
b/lib/ukconsdev/include/uk/consdev_core.h
index d3e8409b..cc34697b 100644
--- a/lib/ukconsdev/include/uk/consdev_core.h
+++ b/lib/ukconsdev/include/uk/consdev_core.h
@@ -38,6 +38,10 @@
 
 #include <uk/list.h>
 #include <uk/config.h>
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+#include <uk/sched.h>
+#include <uk/semaphore.h>
+#endif
 
 /**
  * Unikraft console API common declarations.
@@ -92,12 +96,55 @@ struct uk_consdev_queue_info {
        int size_is_power_of_two;
 };
 
+/**
+ * Structure used to configure a console device.
+ */
+struct uk_consdev_conf {
+
+};
+
+/**
+ * Function type used for event callbacks.
+ *
+ * @param dev
+ *   The Unikraft Console Device.
+ * @param argp
+ *   Extra argument that can be defined on callback registration.
+ */
+typedef void (*uk_consdev_event_t)(struct uk_consdev *dev, void *argp);
+
+/**
+ * Structure used to configure an Unikraft console device RX queue.
+ */
+struct uk_consdev_rxqueue_conf {
+       /* Event callback function. */
+       uk_consdev_event_t callback;
+       /* Argument pointer for callback. */
+       void *cookie;
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       /* Scheduler for dispatcher. */
+       struct uk_sched *s;
+#endif
+};
+
+/**
+ * Structure used to configure an Unikraft console device TX queue.
+ */
+struct uk_consdev_txqueue_conf {
+
+};
+
 /** Driver callback type to read device/driver capabilities,
  *  used for configuring the device
  */
 typedef void (*uk_consdev_info_t) (struct uk_consdev *dev,
                struct uk_consdev_info *dev_info);
 
+/** Driver callback type to configure a console device. */
+typedef int (*uk_consdev_configure_t)(struct uk_consdev *dev,
+               const struct uk_consdev_conf *dev_conf);
+
 /** Driver callback type to retrieve RX queue limitations,
  *  used for configuring the RX queue later
  */
@@ -110,12 +157,50 @@ typedef int (*uk_consdev_rxq_info_t) (struct uk_consdev 
*dev,
 typedef int (*uk_consdev_txq_info_t) (struct uk_consdev *dev,
                struct uk_consdev_queue_info *queue_info);
 
+/** Driver callback type to set up a RX queue of an Unikraft console device. */
+typedef int (*uk_consdev_rxq_configure_t)(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_rxqueue_conf *rx_conf);
+
+/** Driver callback type to set up a TX queue of an Unikraft console device. */
+typedef int (*uk_consdev_txq_configure_t)(struct uk_consdev *dev,
+               uint16_t size,
+               const struct uk_consdev_txqueue_conf *tx_conf);
+
+/** Driver callback type to unconfigure a configured Unikraft console device */
+typedef int (*uk_consdev_unconfigure_t)(struct uk_consdev *dev);
 
 struct uk_consdev_ops {
        uk_consdev_info_t                   info_get;
+       uk_consdev_configure_t              configure;
        uk_consdev_rxq_info_t               rxq_info_get;
        uk_consdev_txq_info_t               txq_info_get;
+       uk_consdev_rxq_configure_t          rxq_configure;
+       uk_consdev_txq_configure_t          txq_configure;
+       uk_consdev_unconfigure_t            unconfigure;
 
+/**
+ * @internal
+ * Event handler configuration (internal to libukconsdev)
+ */
+struct uk_consdev_event_handler {
+       /* Callback */
+       uk_consdev_event_t  callback;
+       /* Parameter for callback */
+       void                *cookie;
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       /* Semaphore to trigger events. */
+       struct uk_semaphore events;
+       /* Reference to console device */
+       struct uk_consdev   *dev;
+       /* Dispatcher thread. */
+       struct uk_thread    *dispatcher;
+       /* reference to thread name. */
+       char                *dispatcher_name;
+       /* Scheduler for dispatcher. */
+       struct uk_sched     *dispatcher_s;
+#endif
 };
 
 /**
@@ -127,6 +212,8 @@ struct uk_consdev_data {
        const uint16_t id;
        /* Device state */
        enum uk_consdev_state state;
+       /* Event handler for rx */
+       struct uk_consdev_event_handler rx_handler;
        /* Name of device*/
        const char *drv_name;
        /* Device allocator */
diff --git a/lib/ukconsdev/include/uk/consdev_driver.h 
b/lib/ukconsdev/include/uk/consdev_driver.h
index 75f12b43..cec391b6 100644
--- a/lib/ukconsdev/include/uk/consdev_driver.h
+++ b/lib/ukconsdev/include/uk/consdev_driver.h
@@ -51,6 +51,30 @@ extern "C" {
 #endif
 
 /**
+ * Forwards an rx event to the API user
+ * Can (and should) be called from device interrupt context
+ *
+ * @param dev
+ *     Unikraft console device to which the event relates to
+ */
+static inline void uk_consdev_drv_rx_event(struct uk_consdev *dev)
+{
+       struct uk_consdev_event_handler *rx_handler;
+
+       UK_ASSERT(dev);
+       UK_ASSERT(dev->_data);
+
+       rx_handler = &dev->_data->rx_handler;
+
+#ifdef CONFIG_LIBUKCONSDEV_DISPATCHERTHREADS
+       uk_semaphore_up(&rx_handler->events);
+#else
+       if (rx_handler->callback)
+               rx_handler->callback(dev, rx_handler->cookie);
+#endif
+}
+
+/**
  * Adds a Unikraft console device to the device list.
  * This should be called whenever a driver adds a new found device.
  *
-- 
2.11.0


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.