From 1d614a819d0d204b6061cac49daa168047b45903 Mon Sep 17 00:00:00 2001 From: GUI <39894654+GuEe-GUI@users.noreply.github.com> Date: Fri, 31 May 2024 17:37:39 +0800 Subject: [PATCH] [DM/feature] Implement PIC irq state { get; set } (#9006) * [DM/feature] Implement PIC irq state { get; set } There are some common state for irq: 1. Pending: IRQ was triggered, but software not ACK. 2. Active: IRQ was ACK, but not EOI. 3. Masked: IRQ was masked or umasked. Signed-off-by: GuEe-GUI <2991707448@qq.com> * [DM/pic] Support IRQ state { get; set } for ARM GICv2/v3 Signed-off-by: GuEe-GUI <2991707448@qq.com> --------- Signed-off-by: GuEe-GUI <2991707448@qq.com> --- components/drivers/include/drivers/pic.h | 11 ++++ components/drivers/pic/pic-gicv2.c | 66 +++++++++++++++++++ components/drivers/pic/pic-gicv3.c | 83 ++++++++++++++++++++++++ components/drivers/pic/pic.c | 79 ++++++++++++++++++++++ 4 files changed, 239 insertions(+) diff --git a/components/drivers/include/drivers/pic.h b/components/drivers/include/drivers/pic.h index c2ca0e00796..2bfb04811b6 100755 --- a/components/drivers/include/drivers/pic.h +++ b/components/drivers/include/drivers/pic.h @@ -75,6 +75,12 @@ struct rt_pic_ops int (*irq_alloc_msi)(struct rt_pic *pic, struct rt_pci_msi_desc *msi_desc); void (*irq_free_msi)(struct rt_pic *pic, int irq); +#define RT_IRQ_STATE_PENDING 0 +#define RT_IRQ_STATE_ACTIVE 1 +#define RT_IRQ_STATE_MASKED 2 + rt_err_t (*irq_set_state)(struct rt_pic *pic, int hwirq, int type, rt_bool_t state); + rt_err_t (*irq_get_state)(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state); + int (*irq_map)(struct rt_pic *pic, int hwirq, rt_uint32_t mode); rt_err_t (*irq_parse)(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq); @@ -189,6 +195,11 @@ rt_err_t rt_pic_irq_set_triger_mode(int irq, rt_uint32_t mode); rt_uint32_t rt_pic_irq_get_triger_mode(int irq); void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask); +rt_err_t rt_pic_irq_set_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t state); +rt_err_t rt_pic_irq_get_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state); +rt_err_t rt_pic_irq_set_state(int irq, int type, rt_bool_t state); +rt_err_t rt_pic_irq_get_state(int irq, int type, rt_bool_t *out_state); + void rt_pic_irq_parent_enable(struct rt_pic_irq *pirq); void rt_pic_irq_parent_disable(struct rt_pic_irq *pirq); void rt_pic_irq_parent_ack(struct rt_pic_irq *pirq); diff --git a/components/drivers/pic/pic-gicv2.c b/components/drivers/pic/pic-gicv2.c index 96d62cbe2b8..adce046a8d3 100644 --- a/components/drivers/pic/pic-gicv2.c +++ b/components/drivers/pic/pic-gicv2.c @@ -276,6 +276,70 @@ static void gicv2_irq_send_ipi(struct rt_pic_irq *pirq, rt_bitmap_t *cpumask) } } +static rt_err_t gicv2_irq_set_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t state) +{ + rt_err_t err = RT_EOK; + rt_uint32_t offset = 0; + struct gicv2 *gic = raw_to_gicv2(pic); + + switch (type) + { + case RT_IRQ_STATE_PENDING: + offset = state ? GIC_DIST_PENDING_SET : GIC_DIST_PENDING_CLEAR; + break; + case RT_IRQ_STATE_ACTIVE: + offset = state ? GIC_DIST_ACTIVE_SET : GIC_DIST_ACTIVE_CLEAR; + break; + case RT_IRQ_STATE_MASKED: + offset = state ? GIC_DIST_ENABLE_CLEAR : GIC_DIST_ENABLE_SET; + break; + default: + err = -RT_EINVAL; + break; + } + + if (!err) + { + rt_uint32_t mask = 1 << (hwirq % 32); + + HWREG32(gic->dist_base + offset + (hwirq / 32) * 4) = mask; + } + + return err; +} + +static rt_err_t gicv2_irq_get_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state) +{ + rt_err_t err = RT_EOK; + rt_uint32_t offset = 0; + struct gicv2 *gic = raw_to_gicv2(pic); + + switch (type) + { + case RT_IRQ_STATE_PENDING: + offset = GIC_DIST_PENDING_SET; + break; + case RT_IRQ_STATE_ACTIVE: + offset = GIC_DIST_ACTIVE_SET; + break; + case RT_IRQ_STATE_MASKED: + offset = GIC_DIST_ENABLE_SET; + break; + default: + err = -RT_EINVAL; + break; + } + + if (!err) + { + rt_uint32_t mask = 1 << (hwirq % 32); + + *out_state = !!(HWREG32(gic->dist_base + offset + (hwirq / 32) * 4) & mask); + } + + return err; +} + static int gicv2_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) { int irq, irq_index = hwirq - GIC_SGI_NR; @@ -353,6 +417,8 @@ const static struct rt_pic_ops gicv2_ops = .irq_set_affinity = gicv2_irq_set_affinity, .irq_set_triger_mode = gicv2_irq_set_triger_mode, .irq_send_ipi = gicv2_irq_send_ipi, + .irq_set_state = gicv2_irq_set_state, + .irq_get_state = gicv2_irq_get_state, .irq_map = gicv2_irq_map, .irq_parse = gicv2_irq_parse, }; diff --git a/components/drivers/pic/pic-gicv3.c b/components/drivers/pic/pic-gicv3.c index ea7d5cfc7a4..c5e4bc780b8 100644 --- a/components/drivers/pic/pic-gicv3.c +++ b/components/drivers/pic/pic-gicv3.c @@ -187,6 +187,14 @@ static void *gicv3_hwirq_reg_base(int hwirq, rt_uint32_t offset, rt_uint32_t *in return base + gicv3_hwirq_convert_offset_index(hwirq, offset, index); } +static rt_bool_t gicv3_hwirq_peek(int hwirq, rt_uint32_t offset) +{ + rt_uint32_t index; + void *base = gicv3_hwirq_reg_base(hwirq, offset, &index); + + return !!HWREG32(base + (index / 32) * 4); +} + static void gicv3_hwirq_poke(int hwirq, rt_uint32_t offset) { rt_uint32_t index; @@ -600,6 +608,79 @@ static void gicv3_irq_send_ipi(struct rt_pic_irq *pirq, rt_bitmap_t *cpumask) #undef __mpidr_to_sgi_affinity } +static rt_err_t gicv3_irq_set_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t state) +{ + rt_err_t err = RT_EOK; + rt_uint32_t offset = 0; + + if (hwirq >= 8192) + { + type = -1; + } + + switch (type) + { + case RT_IRQ_STATE_PENDING: + offset = state ? GICD_ISPENDR : GICD_ICPENDR; + break; + case RT_IRQ_STATE_ACTIVE: + offset = state ? GICD_ISACTIVER : GICD_ICACTIVER; + break; + case RT_IRQ_STATE_MASKED: + if (state) + { + struct rt_pic_irq pirq = {}; + + pirq.hwirq = hwirq; + gicv3_irq_mask(&pirq); + } + else + { + offset = GICD_ISENABLER; + } + break; + default: + err = -RT_EINVAL; + break; + } + + if (!err && offset) + { + gicv3_hwirq_poke(hwirq, offset); + } + + return err; +} + +static rt_err_t gicv3_irq_get_state(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state) +{ + rt_err_t err = RT_EOK; + rt_uint32_t offset = 0; + + switch (type) + { + case RT_IRQ_STATE_PENDING: + offset = GICD_ISPENDR; + break; + case RT_IRQ_STATE_ACTIVE: + offset = GICD_ISACTIVER; + break; + case RT_IRQ_STATE_MASKED: + offset = GICD_ISENABLER; + break; + default: + err = -RT_EINVAL; + break; + } + + if (!err) + { + *out_state = gicv3_hwirq_peek(hwirq, offset); + } + + return err; +} + static int gicv3_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) { struct rt_pic_irq *pirq; @@ -716,6 +797,8 @@ const static struct rt_pic_ops gicv3_ops = .irq_set_affinity = gicv3_irq_set_affinity, .irq_set_triger_mode = gicv3_irq_set_triger_mode, .irq_send_ipi = gicv3_irq_send_ipi, + .irq_set_state = gicv3_irq_set_state, + .irq_get_state = gicv3_irq_get_state, .irq_map = gicv3_irq_map, .irq_parse = gicv3_irq_parse, }; diff --git a/components/drivers/pic/pic.c b/components/drivers/pic/pic.c index a6abd1c5268..4b7467a10b0 100644 --- a/components/drivers/pic/pic.c +++ b/components/drivers/pic/pic.c @@ -893,6 +893,85 @@ void rt_pic_irq_send_ipi(int irq, rt_bitmap_t *cpumask) } } +rt_err_t rt_pic_irq_set_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t state) +{ + rt_err_t err; + + if (pic && hwirq >= 0) + { + if (pic->ops->irq_set_state) + { + err = pic->ops->irq_set_state(pic, hwirq, type, state); + } + else + { + err = -RT_ENOSYS; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_pic_irq_get_state_raw(struct rt_pic *pic, int hwirq, int type, rt_bool_t *out_state) +{ + rt_err_t err; + + if (pic && hwirq >= 0) + { + if (pic->ops->irq_get_state) + { + rt_bool_t state; + + if (!(err = pic->ops->irq_get_state(pic, hwirq, type, &state)) && out_state) + { + *out_state = state; + } + } + else + { + err = -RT_ENOSYS; + } + } + else + { + err = -RT_EINVAL; + } + + return err; +} + +rt_err_t rt_pic_irq_set_state(int irq, int type, rt_bool_t state) +{ + rt_err_t err; + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_hw_spin_lock(&pirq->rw_lock.lock); + err = rt_pic_irq_set_state_raw(pirq->pic, pirq->hwirq, type, state); + rt_hw_spin_unlock(&pirq->rw_lock.lock); + + return err; +} + +rt_err_t rt_pic_irq_get_state(int irq, int type, rt_bool_t *out_state) +{ + rt_err_t err; + struct rt_pic_irq *pirq = irq2pirq(irq); + + RT_ASSERT(pirq != RT_NULL); + + rt_hw_spin_lock(&pirq->rw_lock.lock); + err = rt_pic_irq_get_state_raw(pirq->pic, pirq->hwirq, type, out_state); + rt_hw_spin_unlock(&pirq->rw_lock.lock); + + return err; +} + void rt_pic_irq_parent_enable(struct rt_pic_irq *pirq) { RT_ASSERT(pirq != RT_NULL);