]> xenbits.xensource.com Git - unikraft/unikraft.git/commitdiff
plat/kvm: Migrate ukplat_irq implementation to libukintctlr
authorMichalis Pappas <michalis@unikraft.io>
Tue, 19 Sep 2023 08:27:56 +0000 (10:27 +0200)
committerRazvan Deaconescu <razvand@unikraft.io>
Fri, 20 Oct 2023 16:35:55 +0000 (19:35 +0300)
Migrate the implementation of the ukplat_irq API from `plat/kvm/irq.c`
to `lib/ukintctlr/`. The code is moved without changes, and will be
updated once the new uk_intctlr API is defined.

Deprecate the old headers. These will be replaced by new headers that
define the uk_intctlr API.

Notice: Picking individual commits in this PR will break the build.

Signed-off-by: Michalis Pappas <michalis@unikraft.io>
Reviewed-by: Marco Schlumpp <marco@unikraft.io>
Reviewed-by: Sergiu Moga <sergiu@unikraft.io>
Approved-by: Razvan Deaconescu <razvand@unikraft.io>
GitHub-Closes: #1103

include/uk/plat/irq.h [deleted file]
lib/ukintctlr/Config.uk
lib/ukintctlr/Makefile.uk
lib/ukintctlr/ukintctlr.c [new file with mode: 0644]
plat/Config.uk
plat/common/include/uk/plat/common/irq.h
plat/kvm/Config.uk
plat/kvm/Makefile.uk
plat/kvm/irq.c [deleted file]

diff --git a/include/uk/plat/irq.h b/include/uk/plat/irq.h
deleted file mode 100644 (file)
index 8f7104d..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause */
-/*
- * Authors: Costin Lupu <costin.lupu@cs.pub.ro>
- *
- * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holder nor the names of its
- *    contributors may be used to endorse or promote products derived from
- *    this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef __UKPLAT_IRQ_H__
-#define __UKPLAT_IRQ_H__
-
-#include <uk/arch/lcpu.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct uk_alloc;
-
-/**
- * Initializes platform IRQ subsystem
- * @param a The allocator to be used for internal memory allocations
- * @return initialization status
- */
-int ukplat_irq_init(struct uk_alloc *a);
-
-typedef int (*irq_handler_func_t)(void *);
-
-/**
- * Registers an interrupt handler
- * @param irq Interrupt number
- * @param func Interrupt funciton
- * @param arg Extra argument to be handover to interrupt function
- * @return 0 on success, a negative errno value on errors
- */
-int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg);
-
-/** The event payload for the #UKPLAT_EVENT_IRQ event */
-struct ukplat_event_irq_data {
-       /** The registers of the interrupted code */
-       struct __regs *regs;
-       /** The platform specific interrupt vector number */
-       unsigned long irq;
-};
-
-/**
- * This event is raised before the platform code handles an IRQ. The normal
- * IRQ handling will continue or stop according to the returned `UK_EVENT_*`
- * value.
- * Note: this event is usually raised in an interrupt context.
- */
-#define UKPLAT_EVENT_IRQ ukplat_event_irq
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __UKPLAT_IRQ_H__ */
index c961fa1848bbb75b21c50476197f76193d314399..cc10d8e13edb24e3c97c87f6d6a4b1e4e7f084ea 100644 (file)
@@ -1,3 +1,14 @@
 config LIBUKINTCTLR
-    bool "ukintctlr: Interrupt Controller API"
-    default n
+       bool "ukintctlr: Interrupt Controller API"
+
+if LIBUKINTCTLR
+
+config LIBUKINTCTLR_MAX_HANDLERS_PER_IRQ
+       int "Maximum number of handlers per IRQ"
+       default 8
+
+config LIBUKINTCTLR_ISR_ECTX_ASSERTIONS
+       bool "Check for unmodified ECTX in interrupt handlers"
+       depends on ARCH_X86_64
+
+endif
index d6ce7025b69b05ddf0c4b80155b5ecce85ea9df0..a37a768e27989198a20194e6ec9c153136b487da 100644 (file)
@@ -15,3 +15,5 @@ endif
 ifeq ($(filter $(CONFIG_ARCH_ARM_64) $(CONFIG_ARCH_ARM_32),y), y)
 LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/arch/arm/intctlr.c
 endif
+
+LIBUKINTCTLR_SRCS-y += $(LIBUKINTCTLR_BASE)/ukintctlr.c
diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c
new file mode 100644 (file)
index 0000000..41f95b0
--- /dev/null
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Authors: Dan Williams
+ *          Martin Lucina
+ *          Ricardo Koller
+ *          Costin Lupu <costin.lupu@cs.pub.ro>
+ *
+ * Copyright (c) 2015-2017 IBM
+ * Copyright (c) 2016-2017 Docker, Inc.
+ * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software
+ * for any purpose with or without fee is hereby granted, provided
+ * that the above copyright notice and this permission notice appear
+ * in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* Taken from solo5 intr.c */
+
+#include <stdlib.h>
+#include <uk/alloc.h>
+#include <uk/plat/lcpu.h>
+#include <uk/plat/time.h>
+#include <uk/plat/irq.h>
+#include <uk/plat/common/irq.h>
+#include <uk/intctlr.h>
+#include <uk/assert.h>
+#include <uk/event.h>
+#include <uk/trace.h>
+#include <uk/print.h>
+#include <errno.h>
+#include <uk/bitops.h>
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+#include <uk/arch/ctx.h>
+#endif
+
+UK_EVENT(UKPLAT_EVENT_IRQ);
+
+UK_TRACEPOINT(trace_plat_kvm_unhandled_irq, "Unhandled irq=%lu\n",
+             unsigned long);
+
+/* IRQ handlers declarations */
+struct irq_handler {
+       irq_handler_func_t func;
+       void *arg;
+};
+
+static struct irq_handler irq_handlers[__MAX_IRQ]
+                               [CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES];
+
+static inline struct irq_handler *allocate_handler(unsigned long irq)
+{
+       UK_ASSERT(irq < __MAX_IRQ);
+       for (int i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++)
+               if (irq_handlers[irq][i].func == NULL)
+                       return &irq_handlers[irq][i];
+       return NULL;
+}
+
+int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg)
+{
+       struct irq_handler *h;
+       unsigned long flags;
+
+       UK_ASSERT(func);
+       if (irq >= __MAX_IRQ)
+               return -EINVAL;
+
+       flags = ukplat_lcpu_save_irqf();
+       h = allocate_handler(irq);
+       if (!h) {
+               ukplat_lcpu_restore_irqf(flags);
+               return -ENOMEM;
+       }
+
+       h->func = func;
+       h->arg = arg;
+
+       ukplat_lcpu_restore_irqf(flags);
+
+       intctrl_clear_irq(irq);
+       return 0;
+}
+
+/*
+ * TODO: This is a temporary solution used to identify non TSC clock
+ * interrupts in order to stop waiting for interrupts with deadline.
+ */
+extern unsigned long sched_have_pending_events;
+
+void _ukplat_irq_handle(struct __regs *regs, unsigned long irq)
+{
+       struct irq_handler *h;
+       int i;
+       int rc;
+       struct ukplat_event_irq_data ctx;
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+       __sz ectx_align = ukarch_ectx_align();
+       __u8 ectxbuf[ukarch_ectx_size() + ectx_align];
+       struct ukarch_ectx *ectx = (struct ukarch_ectx *)
+               ALIGN_UP((__uptr) ectxbuf, ectx_align);
+
+       ukarch_ectx_init(ectx);
+#endif
+
+       UK_ASSERT(irq < __MAX_IRQ);
+
+       ctx.regs = regs;
+       ctx.irq = irq;
+       rc = uk_raise_event(UKPLAT_EVENT_IRQ, &ctx);
+       if (unlikely(rc < 0))
+               UK_CRASH("IRQ event handler returned error: %d\n", rc);
+       if (rc == UK_EVENT_HANDLED) {
+               /* Skip all normal handlers if an event handler handled the
+                * event
+                */
+               goto exit_ack;
+       }
+
+       for (i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++) {
+               if (irq_handlers[irq][i].func == NULL)
+                       break;
+               h = &irq_handlers[irq][i];
+               if (irq != ukplat_time_get_irq())
+                       /* ukplat_time_get_irq() gives the IRQ reserved for a timer,
+                        * responsible to wake up cpu from halt, so it can check if
+                        * it has something to do. Effectively it is OS ticks.
+                        *
+                        * If interrupt comes not from the timer, the
+                        * chances are some work have just
+                        * arrived. Let's kick the scheduler out of
+                        * the halting loop, and let it take care of
+                        * that work.
+                        */
+                       __uk_test_and_set_bit(0, &sched_have_pending_events);
+
+               if (h->func(h->arg) == 1)
+                       goto exit_ack;
+       }
+       /*
+        * Acknowledge interrupts even in the case when there was no handler for
+        * it. We do this to (1) compensate potential spurious interrupts of
+        * devices, and (2) to minimize impact on drivers that share one
+        * interrupt line that would then stay disabled.
+        */
+       trace_plat_kvm_unhandled_irq(irq);
+
+exit_ack:
+#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
+       ukarch_ectx_assert_equal(ectx);
+#endif
+       intctrl_ack_irq(irq);
+}
+
+int ukplat_irq_init(struct uk_alloc *a __unused)
+{
+       UK_ASSERT(ukplat_lcpu_irqs_disabled());
+
+       /* Nothing for now */
+       return 0;
+}
index ba62b1c3d991ff1d5fd943da4e33db6dfa1da5dc..ce6ee79035d0a7945465fdcbd769bf934d26499f 100644 (file)
@@ -68,11 +68,6 @@ config UKPLAT_LCPU_WAKEUP_IRQ
 
 endmenu
 
-config UKPLAT_ISR_ECTX_ASSERTIONS
-       bool "Check for unmodified ECTX in interrupt handlers"
-       default n
-       depends on (ARCH_X86_64 && PLAT_KVM)
-
 menuconfig PAGING
        bool "Virtual memory API"
        default n
index 06e16171dbfedac5173311e1d7304c5be551c32b..fa08f8af18845f658911627579685dbb28304b59 100644 (file)
 #ifndef __PLAT_CMN_IRQ_H__
 #define __PLAT_CMN_IRQ_H__
 
-#include <uk/plat/irq.h>
-
+/* Saving /restoring CPU IRQ flags and enabling / disabling IRQs on the
+ * CPU were previously part of the ukplat_irq API. These are not managed
+ * by the interrupt controller, so they need to be part of the lcpu
+ * low-level API. As some platforms may have their own implementation of
+ * these (linuxu, xen) keep them on a separate header.
+ * TODO: Remove this comment after migrating lcpu into drivers.
+ */
 #if defined(__X86_64__)
 #include <x86/irq.h>
 #elif defined(__ARM_64__)
 #error "Add irq.h for current architecture."
 #endif
 
-/* define IRQ trigger types */
-enum uk_irq_trigger {
-       UK_IRQ_TRIGGER_NONE = 0,
-       UK_IRQ_TRIGGER_EDGE = 1,
-       UK_IRQ_TRIGGER_LEVEL = 2,
-       UK_IRQ_TRIGGER_MAX
-};
-
-/* define IRQ trigger polarities */
-enum uk_irq_polarity {
-       UK_IRQ_POLARITY_NONE = 0,
-       UK_IRQ_POLARITY_HIGH = 1,
-       UK_IRQ_POLARITY_LOW = 2,
-       UK_IRQ_POLARITY_MAX
-};
-
-/**
- * Calls the registered IRQ handlers for the given IRQ vector. This will
- * acknowledge the IRQ.
- *
- * @param regs the registers of the interrupted code
- * @param irq IRQ vector
- */
-void _ukplat_irq_handle(struct __regs *regs, unsigned long irq);
-
 #endif /* __PLAT_CMN_IRQ_H__ */
index 4958722c0a39846c45c37b1b266ecfc86a87aa1a..e23bd7c6e6921ef839cab448c0a41703788ffb25 100644 (file)
@@ -208,11 +208,6 @@ endif
 
 endmenu
 
-config KVM_MAX_IRQ_HANDLER_ENTRIES
-       int "Maximum number of handlers per IRQ"
-       default 8
-       depends on (ARCH_X86_64 || ARCH_ARM_64)
-
 config RTC_PL031
        bool "Arm platform RTC (PL031) driver"
        default y if ARCH_ARM_64
index 4b0949d85944c80e393e64d87c6c25f33f327a4a..459b3a7438652b11ac4704048fa38774bcfc4a22 100644 (file)
@@ -119,7 +119,6 @@ LIBKVMPLAT_SRCS-$(CONFIG_ARCH_ARM_64) += $(LIBKVMPLAT_BASE)/arm/lcpu.c
 
 LIBKVMPLAT_SRCS-y                          += $(LIBKVMPLAT_BASE)/shutdown.c
 LIBKVMPLAT_SRCS-y                          += $(LIBKVMPLAT_BASE)/memory.c
-LIBKVMPLAT_SRCS-y                          += $(LIBKVMPLAT_BASE)/irq.c
 LIBKVMPLAT_SRCS-y                          += $(LIBKVMPLAT_BASE)/io.c
 LIBKVMPLAT_SRCS-y                          += $(UK_PLAT_COMMON_BASE)/lcpu.c|common
 LIBKVMPLAT_SRCS-y                          += $(UK_PLAT_COMMON_BASE)/memory.c|common
diff --git a/plat/kvm/irq.c b/plat/kvm/irq.c
deleted file mode 100644 (file)
index 41f95b0..0000000
+++ /dev/null
@@ -1,169 +0,0 @@
-/* SPDX-License-Identifier: ISC */
-/*
- * Authors: Dan Williams
- *          Martin Lucina
- *          Ricardo Koller
- *          Costin Lupu <costin.lupu@cs.pub.ro>
- *
- * Copyright (c) 2015-2017 IBM
- * Copyright (c) 2016-2017 Docker, Inc.
- * Copyright (c) 2018, NEC Europe Ltd., NEC Corporation
- *
- * Permission to use, copy, modify, and/or distribute this software
- * for any purpose with or without fee is hereby granted, provided
- * that the above copyright notice and this permission notice appear
- * in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/* Taken from solo5 intr.c */
-
-#include <stdlib.h>
-#include <uk/alloc.h>
-#include <uk/plat/lcpu.h>
-#include <uk/plat/time.h>
-#include <uk/plat/irq.h>
-#include <uk/plat/common/irq.h>
-#include <uk/intctlr.h>
-#include <uk/assert.h>
-#include <uk/event.h>
-#include <uk/trace.h>
-#include <uk/print.h>
-#include <errno.h>
-#include <uk/bitops.h>
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
-#include <uk/arch/ctx.h>
-#endif
-
-UK_EVENT(UKPLAT_EVENT_IRQ);
-
-UK_TRACEPOINT(trace_plat_kvm_unhandled_irq, "Unhandled irq=%lu\n",
-             unsigned long);
-
-/* IRQ handlers declarations */
-struct irq_handler {
-       irq_handler_func_t func;
-       void *arg;
-};
-
-static struct irq_handler irq_handlers[__MAX_IRQ]
-                               [CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES];
-
-static inline struct irq_handler *allocate_handler(unsigned long irq)
-{
-       UK_ASSERT(irq < __MAX_IRQ);
-       for (int i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++)
-               if (irq_handlers[irq][i].func == NULL)
-                       return &irq_handlers[irq][i];
-       return NULL;
-}
-
-int ukplat_irq_register(unsigned long irq, irq_handler_func_t func, void *arg)
-{
-       struct irq_handler *h;
-       unsigned long flags;
-
-       UK_ASSERT(func);
-       if (irq >= __MAX_IRQ)
-               return -EINVAL;
-
-       flags = ukplat_lcpu_save_irqf();
-       h = allocate_handler(irq);
-       if (!h) {
-               ukplat_lcpu_restore_irqf(flags);
-               return -ENOMEM;
-       }
-
-       h->func = func;
-       h->arg = arg;
-
-       ukplat_lcpu_restore_irqf(flags);
-
-       intctrl_clear_irq(irq);
-       return 0;
-}
-
-/*
- * TODO: This is a temporary solution used to identify non TSC clock
- * interrupts in order to stop waiting for interrupts with deadline.
- */
-extern unsigned long sched_have_pending_events;
-
-void _ukplat_irq_handle(struct __regs *regs, unsigned long irq)
-{
-       struct irq_handler *h;
-       int i;
-       int rc;
-       struct ukplat_event_irq_data ctx;
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
-       __sz ectx_align = ukarch_ectx_align();
-       __u8 ectxbuf[ukarch_ectx_size() + ectx_align];
-       struct ukarch_ectx *ectx = (struct ukarch_ectx *)
-               ALIGN_UP((__uptr) ectxbuf, ectx_align);
-
-       ukarch_ectx_init(ectx);
-#endif
-
-       UK_ASSERT(irq < __MAX_IRQ);
-
-       ctx.regs = regs;
-       ctx.irq = irq;
-       rc = uk_raise_event(UKPLAT_EVENT_IRQ, &ctx);
-       if (unlikely(rc < 0))
-               UK_CRASH("IRQ event handler returned error: %d\n", rc);
-       if (rc == UK_EVENT_HANDLED) {
-               /* Skip all normal handlers if an event handler handled the
-                * event
-                */
-               goto exit_ack;
-       }
-
-       for (i = 0; i < CONFIG_KVM_MAX_IRQ_HANDLER_ENTRIES; i++) {
-               if (irq_handlers[irq][i].func == NULL)
-                       break;
-               h = &irq_handlers[irq][i];
-               if (irq != ukplat_time_get_irq())
-                       /* ukplat_time_get_irq() gives the IRQ reserved for a timer,
-                        * responsible to wake up cpu from halt, so it can check if
-                        * it has something to do. Effectively it is OS ticks.
-                        *
-                        * If interrupt comes not from the timer, the
-                        * chances are some work have just
-                        * arrived. Let's kick the scheduler out of
-                        * the halting loop, and let it take care of
-                        * that work.
-                        */
-                       __uk_test_and_set_bit(0, &sched_have_pending_events);
-
-               if (h->func(h->arg) == 1)
-                       goto exit_ack;
-       }
-       /*
-        * Acknowledge interrupts even in the case when there was no handler for
-        * it. We do this to (1) compensate potential spurious interrupts of
-        * devices, and (2) to minimize impact on drivers that share one
-        * interrupt line that would then stay disabled.
-        */
-       trace_plat_kvm_unhandled_irq(irq);
-
-exit_ack:
-#ifdef CONFIG_UKPLAT_ISR_ECTX_ASSERTIONS
-       ukarch_ectx_assert_equal(ectx);
-#endif
-       intctrl_ack_irq(irq);
-}
-
-int ukplat_irq_init(struct uk_alloc *a __unused)
-{
-       UK_ASSERT(ukplat_lcpu_irqs_disabled());
-
-       /* Nothing for now */
-       return 0;
-}