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