From b22fc94509978fd0abf46cd7874d699d939632aa Mon Sep 17 00:00:00 2001 From: cheng2000160 Date: Mon, 11 Mar 2024 15:21:15 +0800 Subject: [PATCH 1/2] lib/ukintctlr: add APIs intended for setting irq priority and affinity, ukintctlr drivers modified to match Signed-off-by: cheng2000160 --- .../ukintctlr/bcm_intc/bcm_intc_initialize.c | 6 +- drivers/ukintctlr/gic/gic-v3.c | 175 ++++++++++++------ .../ukintctlr/gic/include/uk/intctlr/gic-v3.h | 18 +- .../ukintctlr/gic/include/uk/intctlr/gic.h | 2 +- drivers/ukintctlr/gic/ukintctlr.c | 6 +- drivers/ukintctlr/xpic/ukintctlr.c | 6 +- drivers/virtio/mmio/virtio_mmio.c | 2 +- lib/ukintctlr/exportsyms.uk | 4 +- lib/ukintctlr/include/uk/intctlr.h | 37 +++- lib/ukintctlr/tests/test_intctlr.c | 173 ++++++++++++++++- lib/ukintctlr/ukintctlr.c | 31 +++- plat/common/arm/time.c | 2 +- plat/drivers/rtc/pl031.c | 2 +- 13 files changed, 376 insertions(+), 88 deletions(-) diff --git a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c index 4ed040cd..f5e06f01 100644 --- a/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c +++ b/drivers/ukintctlr/bcm_intc/bcm_intc_initialize.c @@ -69,7 +69,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, #endif /* CONFIG_LIBUKOFW */ /* 根据设备树参数来设置中断属性 */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int irq_set_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) /* 调用函数配置irq_trigger */ @@ -101,10 +101,12 @@ init: intctlr.name = "BCM-INTC"; ops.initialize = bcm_intc->ops.initialize; ops.percpu_init = __NULL; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = irq_set_trigger; ops.mask_irq = bcm_intc->ops.disable_irq; ops.unmask_irq = bcm_intc->ops.enable_irq; ops.handle = bcm_intc->ops.handle_irq; + ops.irq_set_affinity = __NULL; + ops.irq_set_priority = __NULL; /* reserved for software general interrupt to specified core */ ops.sgi_op = __NULL; #if CONFIG_LIBUKOFW diff --git a/drivers/ukintctlr/gic/gic-v3.c b/drivers/ukintctlr/gic/gic-v3.c index 7dc092cc..7d40be53 100644 --- a/drivers/ukintctlr/gic/gic-v3.c +++ b/drivers/ukintctlr/gic/gic-v3.c @@ -160,6 +160,26 @@ static uint32_t get_cpu_affinity(void) } #endif /* CONFIG_HAVE_SMP */ +/** + * Affinitize all SPI interrupts to the current cpu + * + * @param irq_number SPI interrupt number + */ +static void affinitize_to_cpu(uint32_t irq_number) +{ + uint32_t i; + uint64_t mpidr = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((mpidr & MPIDR_AFF3_MASK) >> 8) | + (mpidr & MPIDR_AFF2_MASK) | + (mpidr & MPIDR_AFF1_MASK) | + (mpidr & MPIDR_AFF0_MASK); + /* Route all global SPIs to this CPU */ + uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); + + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), irouter_val); +} + /** * Acknowledge IRQ and retrieve highest priority pending interrupt * @@ -203,20 +223,6 @@ static void gicv3_enable_irq(uint32_t irq) dist_lock(gicv3_drv); -#ifdef CONFIG_HAVE_SMP - /* Route this IRQ to the running core, i.e., route to the CPU interface - * of the core calling this function - */ - if (irq >= GIC_SPI_BASE) { - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - write_gicd64(GICD_IROUTER(irq), irouter_val); - uk_pr_debug("IRQ %d routed to 0x%lx (REG: 0x%lx)\n", - irq, aff, irouter_val); - } -#endif /* CONFIG_HAVE_SMP */ - if (irq >= GIC_SPI_BASE) write_gicd32(GICD_ISENABLER(irq), UK_BIT(irq % GICD_I_PER_ISENABLERn)); @@ -228,50 +234,86 @@ static void gicv3_enable_irq(uint32_t irq) } /** - * Send a software generated interrupt to the specified core. + * Send a software generated interrupt to the specified cores. * - * @sgintid the software generated interrupt id - * @cpuid the id of the targeted cpu + * @param sgintid the software generated interrupt id + * @param target_count the number of target cpus, + * zero means sending sgi to a11 PEs in the system except the current one. + * @param va_list argument list of cpuid, could be empty. type: uint32_t + * @return */ -static void gicv3_sgi_gen(uint8_t sgintid, uint32_t cpuid) +static int gicv3_sgi_gen(uint8_t sgintid, + uint32_t target_count, va_list cpuid_args) { uint64_t sgi_register = 0, control_register_rss, type_register_rss; uint64_t range_selector = 0, extended_cpuid; + uint64_t previous_rs = 0; uint32_t aff0; - extended_cpuid = (uint64_t) cpuid; - /* Only INTID 0-15 allocated to sgi */ UK_ASSERT(sgintid <= GICD_SGI_MAX_INITID); sgi_register |= (sgintid << 24); - /* Set affinity fields and optional range selector */ - sgi_register |= (extended_cpuid & MPIDR_AFF3_MASK) << 48; - sgi_register |= (extended_cpuid & MPIDR_AFF2_MASK) << 32; - sgi_register |= (extended_cpuid & MPIDR_AFF1_MASK) << 16; - /** - ** For affinity 0, we need to find which group of 16 values is - ** represented by the TargetList field in ICC_SGI1R_EL1. - **/ - aff0 = extended_cpuid & MPIDR_AFF0_MASK; - if (aff0 >= 16) { - control_register_rss = SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); - type_register_rss = read_gicd32(GICD_TYPER) & (1 << 26); - if (control_register_rss == 1 && type_register_rss == 1) { - range_selector = aff0 / 16; - sgi_register |= (range_selector << 44); - } else { - uk_pr_err("Can't generate interrupt!\n"); - return; + if (target_count) { + uint8_t i; + + sgi_register |= ICC_SGI1R_EL1_IRM; + for (i = 0; i < target_count; i++) { + extended_cpuid = (uint64_t)va_arg(cpuid_args, uint32_t); + /* Set affinity fields and optional range selector */ + sgi_register |= + (extended_cpuid & MPIDR_AFF3_MASK) << 48; + sgi_register |= + (extended_cpuid & MPIDR_AFF2_MASK) << 32; + sgi_register |= + (extended_cpuid & MPIDR_AFF1_MASK) << 16; + + /** + ** For affinity 0, we need to find + ** which group of 16 values is represented + ** by the TargetList field in ICC_SGI1R_EL1. + **/ + aff0 = extended_cpuid & MPIDR_AFF0_MASK; + + if (aff0 >= 16) { + control_register_rss = + SYSREG_READ64(ICC_CTLR_EL1) & (1 << 18); + type_register_rss = + read_gicd32(GICD_TYPER) & (1 << 26); + if (control_register_rss == 1 && + type_register_rss == 1) { + range_selector = aff0 / 16; + sgi_register |= (range_selector << 44); + } else { + uk_pr_err("Can't generate interrupt!\n"); + return -1; + } + } else { + range_selector = 0; + sgi_register |= (range_selector << 44); + } + + if (i >= 1 && range_selector != previous_rs) { + uk_pr_warn("RS values mismatch!\n"); + return -1; + } + + previous_rs = range_selector; + + sgi_register |= (1 << (aff0 % 16)); + /* Generate interrupt */ + dist_lock(gicv3_drv); + SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); + dist_unlock(gicv3_drv); } + } else { + sgi_register |= ICC_SGI1R_EL1_IRM_ALL; + dist_lock(gicv3_drv); + SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); + dist_unlock(gicv3_drv); } - sgi_register |= (1 << (aff0 % 16)); - - /* Generate interrupt */ - dist_lock(gicv3_drv); - SYSREG_WRITE64(ICC_SGI1R_EL1, sgi_register); - dist_unlock(gicv3_drv); + return 0; } /** @@ -323,7 +365,6 @@ static void gicv3_set_irq_affinity(uint32_t irq, uint32_t affinity) static void gicv3_set_irq_prio(uint32_t irq, uint8_t priority) { dist_lock(gicv3_drv); - if (irq < GIC_SPI_BASE) /* Change in redistributor */ write_gicrd8(GICR_IPRIORITYR(irq), priority); else @@ -411,7 +452,7 @@ static void gicv3_init_redist(void) /* Set PPI and SGI to a default value */ for (i = 0; i < GIC_SPI_BASE; i += GICD_I_PER_IPRIORITYn) - write_gicrd32(GICR_IPRIORITYR4(i), GICD_IPRIORITY_DEF); + write_gicrd32(GICR_IPRIORITYR4(i), GICD_IPRIORITY_DEF_SINGLE); /* Deactivate SGIs and PPIs as the state is unknown at boot */ write_gicrd32(GICR_ICACTIVER0, GICD_DEF_ICACTIVERn); @@ -441,7 +482,7 @@ static void gicv3_init_redist(void) SYSREG_WRITE32(ICC_PMR_EL1, 0xff); /* EOI drops priority, DIR deactivates the interrupt (mode 1) */ - SYSREG_WRITE32(ICC_CTLR_EL1, GICC_CTLR_EL1_EOImode_drop); + SYSREG_WRITE32(ICC_CTLR_EL1, GICC_CTLR_EL1_EOImode_drop_deactivation); /* Enable Group 1 interrupts */ SYSREG_WRITE32(ICC_IGRPEN1_EL1, 1); @@ -475,22 +516,36 @@ static void gicv3_init_dist(void) for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_IGROUPRn) write_gicd32(GICD_IGROUPR(i), GICD_DEF_IGROUPRn); -#ifdef CONFIG_HAVE_SMP - /* Route all global SPIs to this CPU */ - uint64_t aff = (uint64_t)get_cpu_affinity(); - uint64_t irouter_val = GIC_AFF_TO_ROUTER(aff, 0); - - for (i = GIC_SPI_BASE; i < irq_number; i++) - write_gicd64(GICD_IROUTER(i), irouter_val); -#endif /* CONFIG_HAVE_SMP */ + /* Check for 1 of N SPI interrupts support */ + if (val & GICD_TYPE_NO1N) { + #ifndef CONFIG_HAVE_SMP + affinitize_to_cpu(irq_number); + #endif /* CONFIG_HAVE_SMP */ + for (i = GIC_SPI_BASE; i < irq_number; i++) + write_gicd64(GICD_IROUTER(i), + GIC_AFF_TO_ROUTER(0ULL, 1)); + } else { + uk_pr_warn("1 to N support is not implemented by this driver!\n"); + affinitize_to_cpu(irq_number); + } /* Set all SPI's interrupt type to be level-sensitive */ for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICFGRn) write_gicd32(GICD_ICFGR(i), GICD_ICFGR_DEF_TYPE); - /* Set all SPI's priority to a default value */ - for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_IPRIORITYn) - write_gicd32(GICD_IPRIORITYR4(i), GICD_IPRIORITY_DEF); + if (val & GICD_TYPE_SECURITY) { + /* Single Security State, Set all SPI's priority to 128 */ + for (i = GIC_SPI_BASE; i < irq_number; + i += GICD_I_PER_IPRIORITYn) + write_gicd32(GICD_IPRIORITYR4(i), + GICD_IPRIORITY_DEF_SINGLE); + } else { + /* Two Security States, Set all SPI's priority to 255 */ + for (i = GIC_SPI_BASE; i < irq_number; + i += GICD_I_PER_IPRIORITYn) + write_gicd32(GICD_IPRIORITYR4(i), + GICD_IPRIORITY_DEF_TWO); + } /* Deactivate and disable all SPIs */ for (i = GIC_SPI_BASE; i < irq_number; i += GICD_I_PER_ICACTIVERn) { @@ -557,14 +612,14 @@ static int gicv3_initialize(void) } #endif /* CONFIG_HAVE_SMP */ - gicv3_drv.is_initialized = 1; - /* Initialize GICv3 distributor */ gicv3_init_dist(); /* Initialize GICv3 CPU redistributor */ gicv3_init_redist(); + gicv3_drv.is_initialized = 1; + return 0; } diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h index 03380003..df940ffb 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic-v3.h @@ -62,10 +62,22 @@ #define ICC_SRE_EL1 S3_0_C12_C12_5 #define ICC_IGRPEN1_EL1 S3_0_C12_C12_7 +/* + * Set Group 1 SGIs routing mode + * ICC_SGI1R_EL1_IRM_ALL, SGI routed to all PEs, excluding "self". + * ICC_SGI1R_EL1_IRM, SGI routeD to the PEs specified by Aff3.Aff2.Aff1. + */ +#define ICC_SGI1R_EL1_IRM_ALL (1UL << 40) +#define ICC_SGI1R_EL1_IRM (0UL << 40) + /* * Distributor and Redistributor registers + * GICC_CTLR_EL1_EOImode_drop provide priority drop functionality only + * GICC_CTLR_EL1_EOImode_drop_deactivation + * provide both priority drop and interrupt deactivation functionality */ #define GICC_CTLR_EL1_EOImode_drop (1U << 1) +#define GICC_CTLR_EL1_EOImode_drop_deactivation (0U << 1) /* Default size according to ARM Generic Interrupt Controller Architecture * Specification GIC Architecture version 3 and version 4 Issue H. @@ -80,6 +92,7 @@ #define GICD_IROUTER_BASE (0x6000) #define GICD_IROUTER32 (0x6100) #define GICD_IROUTER1019 (0x7FD8) +#define GICD_IROUTER_IRM (1UL << 31) #define GICD_PIDR2 (0xFFE8) #define GICD_CTLR_RWP (1UL << 31) @@ -98,6 +111,8 @@ ((((r) >> GICD_TYPE_ID_BITS_SHIFT) & 0x1f) + 1) #define GICD_TYPE_LPIS (1U << 17) +#define GICD_TYPE_NO1N (0U << 25) +#define GICD_TYPE_SECURITY (0U << 10) #define GICR_WAKER_ProcessorSleep (1U << 1) #define GICR_WAKER_ChildrenAsleep (1U << 2) @@ -286,7 +301,8 @@ #define GICD_IPRIORITYR4(n) (0x0400 + 4 * ((n) >> 2)) #define GICR_IPRIORITYR4(n) (GICR_SGI_BASE + 0x0400 + 4 * ((n) >> 2)) #define GICD_I_PER_IPRIORITYn 4 -#define GICD_IPRIORITY_DEF 0x80808080 +#define GICD_IPRIORITY_DEF_SINGLE 0x80808080 +#define GICD_IPRIORITY_DEF_TWO 0xFFFFFFFF /* * Interrupt Processor Targets Registers, GICD_ITARGETSRn diff --git a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h index 6c7591a8..9c565e6c 100644 --- a/drivers/ukintctlr/gic/include/uk/intctlr/gic.h +++ b/drivers/ukintctlr/gic/include/uk/intctlr/gic.h @@ -88,7 +88,7 @@ struct _gic_operations { /** Handle IRQ */ void (*handle_irq)(struct __regs *regs); /** Send a SGI to the specifiec core */ - void (*gic_sgi_gen)(uint8_t sgintid, uint32_t cpuid); + void (*gic_sgi_gen)(uint8_t sgintid, uint32_t target_amount, ...); }; /** GIC controller structure */ diff --git a/drivers/ukintctlr/gic/ukintctlr.c b/drivers/ukintctlr/gic/ukintctlr.c index 4b50c337..691b43df 100644 --- a/drivers/ukintctlr/gic/ukintctlr.c +++ b/drivers/ukintctlr/gic/ukintctlr.c @@ -75,7 +75,7 @@ static int fdt_xlat(const void *fdt, int nodeoffset, __u32 index, } #endif /* CONFIG_LIBUKOFW */ -static int configure_irq(struct uk_intctlr_irq *irq) +static int irq_set_trigger(struct uk_intctlr_irq *irq) { if (irq->trigger != UK_INTCTLR_IRQ_TRIGGER_NONE) gic->ops.set_irq_trigger(irq->id, irq->trigger); @@ -111,9 +111,11 @@ init: if (unlikely(rc)) return rc; - ops.configure_irq = configure_irq; + ops.irq_set_trigger = irq_set_trigger; ops.mask_irq = gic->ops.disable_irq; ops.unmask_irq = gic->ops.enable_irq; + ops.irq_set_priority = gic->ops.set_irq_prio; + ops.irq_set_affinity = gic->ops.set_irq_affinity; #if CONFIG_LIBUKOFW ops.fdt_xlat = fdt_xlat; #endif /* CONFIG_LIBUKOFW */ diff --git a/drivers/ukintctlr/xpic/ukintctlr.c b/drivers/ukintctlr/xpic/ukintctlr.c index 5581aa9d..c2950e3c 100644 --- a/drivers/ukintctlr/xpic/ukintctlr.c +++ b/drivers/ukintctlr/xpic/ukintctlr.c @@ -15,7 +15,7 @@ static struct uk_intctlr_desc intctlr; -static int configure_irq(struct uk_intctlr_irq *irq __unused) +static int irq_set_trigger(struct uk_intctlr_irq *irq __unused) { return 0; } @@ -56,12 +56,14 @@ int uk_intctlr_probe(void) #endif /* CONFIG_LIBUKINTCTLR_APIC */ intctlr.ops = ops; - intctlr.ops->configure_irq = configure_irq; + intctlr.ops->irq_set_trigger = irq_set_trigger; intctlr.ops->initialize = __NULL; intctlr.ops->handle = uk_intctlr_xpic_handle_irq; intctlr.ops->fdt_xlat = __NULL; intctlr.ops->sgi_op = __NULL; intctlr.ops->percpu_init = __NULL; + intctlr.ops->irq_set_priority = __NULL; + intctlr.ops->irq_set_affinity = __NULL; return uk_intctlr_register(&intctlr); } diff --git a/drivers/virtio/mmio/virtio_mmio.c b/drivers/virtio/mmio/virtio_mmio.c index 881a3181..cb957be4 100644 --- a/drivers/virtio/mmio/virtio_mmio.c +++ b/drivers/virtio/mmio/virtio_mmio.c @@ -439,7 +439,7 @@ static int virtio_mmio_probe_fdt(struct pf_device *pfdev) if (unlikely(rc < 0)) return -EINVAL; - uk_intctlr_irq_configure(&irq); + uk_intctlr_set_irq_trigger(&irq); prop = fdt_getprop(dtb, offs, "reg", &prop_len); if (unlikely(!prop)) diff --git a/lib/ukintctlr/exportsyms.uk b/lib/ukintctlr/exportsyms.uk index 80ce0e8b..0a0c729c 100644 --- a/lib/ukintctlr/exportsyms.uk +++ b/lib/ukintctlr/exportsyms.uk @@ -1,6 +1,6 @@ uk_intctlr uk_intctlr_init -uk_intctlr_irq_configure +uk_intctlr_set_irq_trigger uk_intctlr_irq_fdt_xlat uk_intctlr_irq_alloc uk_intctlr_irq_free @@ -11,3 +11,5 @@ uk_intctlr_percpu_init uk_intctlr_irq_register uk_intctlr_irq_unregister uk_intctlr_register +uk_intctlr_irq_set_priority +uk_intctlr_irq_set_affinity \ No newline at end of file diff --git a/lib/ukintctlr/include/uk/intctlr.h b/lib/ukintctlr/include/uk/intctlr.h index 7ae83256..3f29fc87 100644 --- a/lib/ukintctlr/include/uk/intctlr.h +++ b/lib/ukintctlr/include/uk/intctlr.h @@ -54,14 +54,16 @@ struct uk_intctlr_irq { * These must be implemented by the interrupt controller */ struct uk_intctlr_driver_ops { - int (*configure_irq)(struct uk_intctlr_irq *irq); + int (*irq_set_trigger)(struct uk_intctlr_irq *irq); int (*fdt_xlat)(const void *fdt, int nodeoffset, __u32 index, struct uk_intctlr_irq *irq); void (*mask_irq)(unsigned int irq); void (*unmask_irq)(unsigned int irq); void (*initialize)(void); void (*handle)(struct __regs *regs); - void (*sgi_op)(uint8_t sgintid, uint32_t cpuid); + int (*sgi_op)(uint8_t sgintid, uint32_t target_count, ...); + void (*irq_set_priority)(unsigned int irq, uint8_t priority); + void (*irq_set_affinity)(unsigned int irq, uint32_t cpuid); int (*percpu_init)(uint64_t cpuid __maybe_unused); }; @@ -96,12 +98,12 @@ int uk_intctlr_probe(void); void uk_intctlr_irq_handle(struct __regs *regs, unsigned int irq); /** - * Configure an interrupt + * Configure trigger type for an interrupt * * @param irq Interrupt configuration * @return zero on success or negative value on error */ -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq); +int uk_intctlr_set_irq_trigger(struct uk_intctlr_irq *irq); /** * Register interrupt controller driver with the uk_intctlr subsystem @@ -198,13 +200,15 @@ int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, void uk_intctlr_handle(struct __regs *regs); /** - * Handle function for interrupt controller + * Send a SGI to the specified core(s). * * @param sgintid the software generated interrupt id - * @param cpuid the id of the targeted cpu - * @return zero on success , error code on failure + * @param target_count the number of target cpus, + * zero means sending sgi to all PEs in the system except the current one. + * @param ... optional argument list of cpuid,type:uint32_t + * @return zero on success , -1 on failure */ -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid); +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...); /** * extra initialize function for each cpu core @@ -213,6 +217,23 @@ int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid); * @return zero on success , error code on failure */ int uk_intctlr_percpu_init(uint64_t cpuid __maybe_unused); + +/** + * set priority for interrupt + * + * @param irq SPI Interrupt to set priority + * @param priority priority number value 0-255 + */ +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority); + +/** + * set affinity for SPI interrupt + * + * @param irq SPI Interrupt to set affinity + * @param cpuid target CPU id to cope with SPI + */ +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid); + #endif /* __ASSEMBLY__ */ #ifdef __cplusplus diff --git a/lib/ukintctlr/tests/test_intctlr.c b/lib/ukintctlr/tests/test_intctlr.c index f9a9906d..e0798631 100644 --- a/lib/ukintctlr/tests/test_intctlr.c +++ b/lib/ukintctlr/tests/test_intctlr.c @@ -17,6 +17,8 @@ #include #include +#define TEST_GIC_DIST_REG(r) ((void *)(uintptr_t)(0xfd400000 + (r))) + static struct uk_intctlr_desc *ori_intctlr; static struct uk_intctlr_desc test_intctlr; struct uk_intctlr_driver_ops test_ops; @@ -90,7 +92,7 @@ static inline void test_intctlr_init(void) ret = 0; test_intctlr.name = "TEST_INTCTLR"; - test_ops.configure_irq = test_configure_irq; + test_ops.irq_set_trigger = test_configure_irq; test_ops.fdt_xlat = test_fdt_xlat; test_ops.mask_irq = test_mask_irq; test_ops.unmask_irq = test_unmask_irq; @@ -98,6 +100,8 @@ static inline void test_intctlr_init(void) test_ops.sgi_op = test_sgi_op; test_ops.percpu_init = test_percpu_init; test_intctlr.ops = &test_ops; + test_ops.irq_set_priority = NULL; + test_ops.irq_set_affinity = NULL; uk_intctlr_register(&test_intctlr); } @@ -112,7 +116,7 @@ UK_TESTCASE(ukintctlr, call_intctlr_configure_irq) test_intctlr_init(); /* 2.通过统一接口调用configure_irq,并校验调用结果 */ - (void)uk_intctlr_irq_configure(p_irq); + (void)uk_intctlr_set_irq_trigger(p_irq); UK_TEST_EXPECT_SNUM_EQ(ret, TEST_CONFIGURE_IRQ_SUCCESS); /* 3.恢复环境 */ @@ -222,4 +226,169 @@ UK_TESTCASE(ukintctlr, call_percpu_init) uk_intctlr_register(ori_intctlr); } +#ifdef CONFIG_ARCH_ARM_64 +static void simulate_interrupt_pend_togther(uint32_t irq) +{ + uint32_t offset = (0x0200 + 4 * ((irq) >> 5)); + + /* 需要确保中断40/50 pending位同时被置位 18 = 50 % 32 */ + ioreg_write32(TEST_GIC_DIST_REG(offset), ((1UL << 18)|(1UL << 8))); +} + + +static void simulate_interrupt_pend(uint32_t irq) +{ + uint32_t offset = (0x0200 + 4 * ((irq) >> 5)); + + ioreg_write32(TEST_GIC_DIST_REG(offset), (1UL << (irq % 32))); +} + +static void simulate_interrupt_clear_pend(uint32_t irq) +{ + uint32_t offset = (0x0280 + 4 * ((irq) >> 5)); + + ioreg_write32(TEST_GIC_DIST_REG(offset), (1UL << (irq % 32))); +} + +static int lowpriority_spi_handler(void *args __unused) +{ + printf("lowpriority spi handler start.\n"); + + return 1; +} + +static int highpriority_spi_handler(void *args __unused) +{ + printf("highpriority spi handler start.\n"); + + return 1; +} + +static int highpriority_spi_preemption_handler(void *args __unused) +{ + printf("step into highpriority spi4 preemption handler.\n"); + + return 1; +} + +static int lowpriority_spi_preemption_handler(void *args __unused) +{ + uint64_t count = 1000000000; + + printf("step into lowpriority spi3 handler.\n"); + do { + count--; + if (count == 1) + printf("spi3 handler already done.\n"); + } while (count > 0); + + return 1; +} + +static int sgi_handler(void *args __unused) +{ + + printf("step into sgi1 handler.\n"); + + return 1; +} +#endif + +/* 测试配置优先级 */ +UK_TESTCASE(ukintctlr, call_SPIs) +{ + /* 模拟中断 irq1/2 */ +#ifdef CONFIG_ARCH_ARM_64 + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + + uint64_t aff = ((current_cpu & 0xff00000000) >> 8) | + (current_cpu & 0x0000ff0000) | + (current_cpu & 0x000000ff00) | + (current_cpu & 0x00000000ff); + /* irq1中断号50,亲和至当前cpu 优先级50*/ + + + uk_intctlr_irq_set_priority(50, 50); + uk_intctlr_irq_set_affinity(50, (uint32_t)aff); + uk_intctlr_irq_register(50, lowpriority_spi_handler, NULL); + isb(); + printf("irq1 set done.\n"); + + /* irq2中断号40,亲和至当前cpu 优先级40*/ + uk_intctlr_irq_set_priority(40, 40); + uk_intctlr_irq_set_affinity(40, (uint32_t)aff); + uk_intctlr_irq_register(40, highpriority_spi_handler, NULL); + isb(); + printf("irq2 set done.\n"); + + /* 中断号50/40位于同一寄存器中 + * 故可以传入irq1的值以同时打开pending位 + */ + simulate_interrupt_pend_togther(50); + isb(); + + simulate_interrupt_clear_pend(50); + isb(); + simulate_interrupt_clear_pend(40); + isb(); +#else + printf("skip x86.\n"); +#endif + +} + +/* TODO 当前尚未支持中断抢占 */ +UK_TESTCASE(ukintctlr, call_SPIs_preemption) +{ +#ifdef CONFIG_ARCH_ARM_64 + /* 模拟中断 irq3/4 */ + uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); + uint64_t aff = ((current_cpu & 0xff00000000) >> 8) | + (current_cpu & 0x0000ff0000) | + (current_cpu & 0x000000ff00) | + (current_cpu & 0x00000000ff); + /* irq3中断号70,亲和至当前cpu 优先级70*/ + uk_intctlr_irq_set_priority(70, 70); + uk_intctlr_irq_set_affinity(70, (uint32_t)aff); + uk_intctlr_irq_register(70, lowpriority_spi_preemption_handler, NULL); + isb(); + printf("irq3 set done.\n"); + + /* irq4中断号60,亲和至当前cpu 优先级60*/ + uk_intctlr_irq_set_priority(60, 60); + uk_intctlr_irq_set_affinity(60, (uint32_t)aff); + uk_intctlr_irq_register(60, highpriority_spi_preemption_handler, NULL); + isb(); + printf("irq4 set done.\n"); + + simulate_interrupt_pend(70); + isb(); + /* 当前进入irq3处理函数之后 中断被屏蔽 irq4不执行*/ + simulate_interrupt_pend(60); + isb(); + + simulate_interrupt_clear_pend(70); + isb(); + simulate_interrupt_clear_pend(60); + isb(); +#else + printf("skip x86.\n"); +#endif +} + +/* 测试sgi亲和性配置*/ +UK_TESTCASE(ukintctlr, call_SGIs) +{ +#ifdef CONFIG_ARCH_ARM_64 + /* sgi中断号5,亲和至当前cpu 优先级30*/ + + uk_intctlr_irq_set_priority(5, 30); + uk_intctlr_irq_register(5, sgi_handler, NULL); + isb(); + + /* 将sgi路由到当前cpu */ + uk_intctlr_sgi_op(5, 1, 0); +#endif +} + uk_testsuite_register(ukintctlr, NULL); diff --git a/lib/ukintctlr/ukintctlr.c b/lib/ukintctlr/ukintctlr.c index 88aa1cfd..e50fd2a0 100644 --- a/lib/ukintctlr/ukintctlr.c +++ b/lib/ukintctlr/ukintctlr.c @@ -232,12 +232,12 @@ void uk_intctlr_irq_unmask(unsigned int irq) return uk_intctlr->ops->unmask_irq(irq); } -int uk_intctlr_irq_configure(struct uk_intctlr_irq *irq) +int uk_intctlr_set_irq_trigger(struct uk_intctlr_irq *irq) { - UK_ASSERT(uk_intctlr && uk_intctlr->ops->configure_irq); + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_trigger); UK_ASSERT(irq); - return uk_intctlr->ops->configure_irq(irq); + return uk_intctlr->ops->irq_set_trigger(irq); } int uk_intctlr_irq_fdt_xlat(const void *fdt, int nodeoffset, __u32 index, @@ -318,12 +318,17 @@ void uk_intctlr_handle(struct __regs *regs) return uk_intctlr->ops->handle(regs); } -int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t cpuid) +int uk_intctlr_sgi_op(uint8_t sgintid, uint32_t target_count, ...) { - UK_ASSERT(uk_intctlr->ops->sgi_op); + UK_ASSERT(uk_intctlr && uk_intctlr->ops->sgi_op); + va_list cpuid_args; - uk_intctlr->ops->sgi_op(sgintid, cpuid); + va_start(cpuid_args, target_count); + if (uk_intctlr->ops->sgi_op(sgintid, target_count, cpuid_args)) + return -1; + + va_end(cpuid_args); return 0; } @@ -334,3 +339,17 @@ int uk_intctlr_percpu_init(uint64_t cpuid __maybe_unused) /* initialize interrupt controller of specified cpu core */ return uk_intctlr->ops->percpu_init(cpuid); } + +void uk_intctlr_irq_set_priority(unsigned int irq, uint8_t priority) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_priority); + + return uk_intctlr->ops->irq_set_priority(irq, priority); +} + +void uk_intctlr_irq_set_affinity(unsigned int irq, uint32_t cpuid) +{ + UK_ASSERT(uk_intctlr && uk_intctlr->ops->irq_set_affinity); + + return uk_intctlr->ops->irq_set_affinity(irq, cpuid); +} diff --git a/plat/common/arm/time.c b/plat/common/arm/time.c index 8d89036a..b6c116da 100644 --- a/plat/common/arm/time.c +++ b/plat/common/arm/time.c @@ -131,7 +131,7 @@ void ukplat_time_init(void) if (unlikely(rc < 0)) UK_CRASH("Could not get IRQ from dtb (%d)\n", rc); - uk_intctlr_irq_configure(&irq); + uk_intctlr_set_irq_trigger(&irq); rc = uk_intctlr_irq_register(irq.id, generic_timer_irq_handler, NULL); if (unlikely(rc < 0)) diff --git a/plat/drivers/rtc/pl031.c b/plat/drivers/rtc/pl031.c index 805085df..14ed4482 100644 --- a/plat/drivers/rtc/pl031.c +++ b/plat/drivers/rtc/pl031.c @@ -181,7 +181,7 @@ int pl031_init_rtc(void *dtb) if (unlikely(rc)) return rc; - uk_intctlr_irq_configure(&irq); + uk_intctlr_set_irq_trigger(&irq); pl031_irq = irq.id; -- Gitee From 8f8daefc29e48e2946241e6f0a512616c56f71cf Mon Sep 17 00:00:00 2001 From: cheng2000160 Date: Thu, 14 Mar 2024 14:26:15 +0800 Subject: [PATCH 2/2] lib/ukintctlr: support test cases when gicv3 driver Signed-off-by: cheng2000160 --- lib/ukintctlr/tests/test_intctlr.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/ukintctlr/tests/test_intctlr.c b/lib/ukintctlr/tests/test_intctlr.c index e0798631..62236baf 100644 --- a/lib/ukintctlr/tests/test_intctlr.c +++ b/lib/ukintctlr/tests/test_intctlr.c @@ -226,7 +226,7 @@ UK_TESTCASE(ukintctlr, call_percpu_init) uk_intctlr_register(ori_intctlr); } -#ifdef CONFIG_ARCH_ARM_64 +#ifdef CONFIG_LIBUKINTCTLR_GICV3 static void simulate_interrupt_pend_togther(uint32_t irq) { uint32_t offset = (0x0200 + 4 * ((irq) >> 5)); @@ -235,7 +235,6 @@ static void simulate_interrupt_pend_togther(uint32_t irq) ioreg_write32(TEST_GIC_DIST_REG(offset), ((1UL << 18)|(1UL << 8))); } - static void simulate_interrupt_pend(uint32_t irq) { uint32_t offset = (0x0200 + 4 * ((irq) >> 5)); @@ -292,13 +291,11 @@ static int sgi_handler(void *args __unused) return 1; } -#endif /* 测试配置优先级 */ UK_TESTCASE(ukintctlr, call_SPIs) { /* 模拟中断 irq1/2 */ -#ifdef CONFIG_ARCH_ARM_64 uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); uint64_t aff = ((current_cpu & 0xff00000000) >> 8) | @@ -331,16 +328,16 @@ UK_TESTCASE(ukintctlr, call_SPIs) isb(); simulate_interrupt_clear_pend(40); isb(); -#else - printf("skip x86.\n"); -#endif + uk_intctlr_irq_set_priority(50, 255); + uk_intctlr_irq_set_priority(40, 255); + uk_intctlr_irq_unregister(50, lowpriority_spi_handler); + uk_intctlr_irq_unregister(40, highpriority_spi_handler); } /* TODO 当前尚未支持中断抢占 */ UK_TESTCASE(ukintctlr, call_SPIs_preemption) { -#ifdef CONFIG_ARCH_ARM_64 /* 模拟中断 irq3/4 */ uint64_t current_cpu = SYSREG_READ64(MPIDR_EL1); uint64_t aff = ((current_cpu & 0xff00000000) >> 8) | @@ -371,15 +368,16 @@ UK_TESTCASE(ukintctlr, call_SPIs_preemption) isb(); simulate_interrupt_clear_pend(60); isb(); -#else - printf("skip x86.\n"); -#endif + + uk_intctlr_irq_set_priority(60, 255); + uk_intctlr_irq_set_priority(70, 255); + uk_intctlr_irq_unregister(60, highpriority_spi_preemption_handler); + uk_intctlr_irq_unregister(70, lowpriority_spi_preemption_handler); } /* 测试sgi亲和性配置*/ UK_TESTCASE(ukintctlr, call_SGIs) { -#ifdef CONFIG_ARCH_ARM_64 /* sgi中断号5,亲和至当前cpu 优先级30*/ uk_intctlr_irq_set_priority(5, 30); @@ -388,7 +386,9 @@ UK_TESTCASE(ukintctlr, call_SGIs) /* 将sgi路由到当前cpu */ uk_intctlr_sgi_op(5, 1, 0); -#endif + uk_intctlr_irq_set_priority(5, 128); + uk_intctlr_irq_unregister(5, sgi_handler); } +#endif uk_testsuite_register(ukintctlr, NULL); -- Gitee