|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |