From: Jan Beulich <jbeulich@suse.com>
To: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Cc: "Alistair Francis" <alistair.francis@wdc.com>,
"Bob Eshleman" <bobbyeshleman@gmail.com>,
"Connor Davis" <connojdavis@gmail.com>,
"Andrew Cooper" <andrew.cooper3@citrix.com>,
"Anthony PERARD" <anthony.perard@vates.tech>,
"Michal Orzel" <michal.orzel@amd.com>,
"Julien Grall" <julien@xen.org>,
"Roger Pau Monné" <roger.pau@citrix.com>,
"Stefano Stabellini" <sstabellini@kernel.org>,
"Romain Caritey" <Romain.Caritey@microchip.com>,
xen-devel@lists.xenproject.org
Subject: Re: [PATCH v1 10/14] xen/riscv: implementation of aplic and imsic operations
Date: Tue, 15 Apr 2025 14:46:38 +0200 [thread overview]
Message-ID: <35075d73-ec3c-4e8f-b7ed-657b604904bd@suse.com> (raw)
In-Reply-To: <74a07ed7c596bbcf581010685e01bfdfa19164f5.1744126720.git.oleksii.kurochko@gmail.com>
On 08.04.2025 17:57, Oleksii Kurochko wrote:
> Introduce interrupt controller descriptor for host APLIC to describe
> the low-lovel hardare. It includes implementation of the following functions:
> - aplic_irq_startup()
> - aplic_irq_shutdown()
> - aplic_irq_enable()
> - aplic_irq_disable()
> - aplic_irq_ack()
> - aplic_host_irq_end()
> - aplic_set_irq_affinity()
>
> As APLIC is used in MSI mode it requires to enable/disable interrupts not
> only for APLIC but also for IMSIC. Thereby for the purpose of
> aplic_irq_{enable,disable}() it is introduced imsic_irq_{enable,disable)().
>
> For the purpose of aplic_set_irq_affinity() aplic_get_cpu_from_mask() is
> introduced to get hart id.
>
> Also, introduce additional interrupt controller h/w operations and
> host_irq_type for APLIC:
> - aplic_host_irq_type
> - aplic_set_irq_priority()
> - aplic_set_irq_type()
Yet these two functions nor the hooks they're used to populate are entirely
unused here. Since they're also outside of the common IRQ handling machinery,
it's unclear how one would sanely ack such a change.
> --- a/xen/arch/riscv/aplic.c
> +++ b/xen/arch/riscv/aplic.c
> @@ -15,6 +15,7 @@
> #include <xen/irq.h>
> #include <xen/mm.h>
> #include <xen/sections.h>
> +#include <xen/spinlock.h>
> #include <xen/types.h>
> #include <xen/vmap.h>
>
> @@ -110,9 +111,173 @@ static int __init aplic_init(void)
> return 0;
> }
>
> -static const struct intc_hw_operations __ro_after_init aplic_ops = {
> +static void aplic_set_irq_type(struct irq_desc *desc, unsigned int type)
> +{
> + unsigned int irq = desc->irq - 1;
Why this adjustment by 1 (and yet both items being named "irq")?
> + spin_lock(&aplic.lock);
> + switch(type) {
> + case IRQ_TYPE_EDGE_RISING:
Nit (style): Missing blanks, brace on its own line, case labels indented
like their containing switch().
> + aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_EDGE_RISE;
> + break;
> + case IRQ_TYPE_EDGE_FALLING:
Blank lines please between non-fall-through case blocks.
> + aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_EDGE_FALL;
> + break;
> + case IRQ_TYPE_LEVEL_HIGH:
> + aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_LEVEL_HIGH;
> + break;
> + case IRQ_TYPE_LEVEL_LOW:
> + aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_LEVEL_LOW;
> + break;
> + default:
> + aplic.regs->sourcecfg[irq] = APLIC_SOURCECFG_SM_INACTIVE;
> + break;
Is the default: label legitimate to be reached?
> + }
> + spin_unlock(&aplic.lock);
> +}
> +
> +static void aplic_set_irq_priority(struct irq_desc *desc,
> + unsigned int priority)
> +{
> + /* No priority, do nothing */
> +}
Since the function dopes nothing, wouldn't it be better to omit it and have
the (future) caller check for a NULL pointer ahead of making the (indirect)
call? Same remark for other handlers (below) which also do nothing.
> +static void aplic_irq_enable(struct irq_desc *desc)
> +{
> + unsigned long flags;
> +
> + /*
> + * TODO: Currently, APLIC is supported only with MSI interrupts.
> + * If APLIC without MSI interrupts is required in the future,
> + * this function will need to be updated accordingly.
> + */
> + ASSERT(aplic.imsic_cfg->is_used);
Such an extra field, used only for assertions, is pretty odd. Can't you
use any of the other fields to achieve the same effect?
> + ASSERT(spin_is_locked(&desc->lock));
If this lock (which is an IRQ-safe one) is necessarily held, ...
> + spin_lock_irqsave(&aplic.lock, flags);
... you can use just spin_lock() here.
> + clear_bit(_IRQ_DISABLED, &desc->status);
Why an atomic bitop when desc is locked? (And yes, I ought to raise the same
question on Arm code also doing so.)
I'm uncertain about this bit setting anyway - on x86 we would only fiddle
with it for IRQs not in use, not while enabling/disabling one.
In any event this can be done outside of the APLIC-locked region, I think.
> + /* enable interrupt in IMSIC */
May I remind you of Xen comment style?
> + imsic_irq_enable(desc->irq);
> +
> + /* enable interrupt in APLIC */
> + aplic.regs->setienum = desc->irq;
Are you sure you want to use plain assignments for MMIO accesses? I'd have
expected writel() to be used here. (And only later I realized that I didn't
spot the same already higher up from here.)
From the vague understanding I've gained so far: Isn't the APLIC closer to
the CPU and the IMSIC closer to the device? If so, wouldn't you want to
enable at the APLIC before enabling at the IMSIC? But of course that also
depends on what exactly happens in the window while one is already enabled
and the other is still disabled. (Later) From the code you add to imsic.c
it looks like it's the other way around, as the IMSIC is accessed through
CSRs.
> + spin_unlock_irqrestore(&aplic.lock, flags);
> +}
> +
> +static void aplic_irq_disable(struct irq_desc *desc)
> +{
> + unsigned long flags;
> +
> + /*
> + * TODO: Currently, APLIC is supported only with MSI interrupts.
> + * If APLIC without MSI interrupts is required in the future,
> + * this function will need to be updated accordingly.
> + */
> + ASSERT(aplic.imsic_cfg->is_used);
> +
> + ASSERT(spin_is_locked(&desc->lock));
> +
> + spin_lock_irqsave(&aplic.lock, flags);
> +
> + set_bit(_IRQ_DISABLED, &desc->status);
> +
> + /* disable interrupt in APLIC */
> + aplic.regs->clrienum = desc->irq;
> +
> + /* disable interrupt in IMSIC */
> + imsic_irq_disable(desc->irq);
> +
> + spin_unlock_irqrestore(&aplic.lock, flags);
> +}
> +
> +static unsigned int aplic_irq_startup(struct irq_desc *desc)
> +{
> + aplic_irq_enable(desc);
> +
> + return 0;
> +}
> +
> +static void aplic_irq_shutdown(struct irq_desc *desc)
> +{
> + aplic_irq_disable(desc);
> +}
You don't really need a separate hook function here, do you?
> +static void aplic_irq_ack(struct irq_desc *desc)
> +{
> + /* nothing to do */
> +}
> +
> +static void aplic_host_irq_end(struct irq_desc *desc)
What's the "host" in the identifier about?
> +{
> + /* nothing to do */
> +}
> +
> +static unsigned int aplic_get_cpu_from_mask(const cpumask_t *cpumask)
> +{
> + unsigned int cpu;
No real need for this variable?
> + cpumask_t possible_mask;
> +
> + cpumask_and(&possible_mask, cpumask, &cpu_possible_map);
> + cpu = cpumask_any(&possible_mask);
Why would you use cpu_possible_map here? That includes any offline CPUs.
I think you need to use cpu_online_map here.
> + return cpu;
> +}
> +
> +static void aplic_set_irq_affinity(struct irq_desc *desc, const cpumask_t *mask)
> +{
> + unsigned int cpu;
> + uint64_t group_index, base_ppn;
> + uint32_t hhxw, lhxw ,hhxs, value;
> + const struct imsic_config *imsic = aplic.imsic_cfg;
> +
> + /*
> + * TODO: Currently, APLIC is supported only with MSI interrupts.
> + * If APLIC without MSI interrupts is required in the future,
> + * this function will need to be updated accordingly.
> + */
> + ASSERT(aplic.imsic_cfg->is_used);
Use the local variable you have made yourself?
> + ASSERT(!cpumask_empty(mask));
> +
> + spin_lock(&aplic.lock);
Aiui the lock can be acquired quite a bit later. It ought to be needed only
around the actual write to the hardware register.
> + cpu = cpuid_to_hartid(aplic_get_cpu_from_mask(mask));
> + hhxw = imsic->group_index_bits;
> + lhxw = imsic->hart_index_bits;
> + hhxs = imsic->group_index_shift - IMSIC_MMIO_PAGE_SHIFT * 2;
> + base_ppn = imsic->msi[cpu].base_addr >> IMSIC_MMIO_PAGE_SHIFT;
> +
> + /* update hart and EEID in the target register */
> + group_index = (base_ppn >> (hhxs + 12)) & (BIT(hhxw, UL) - 1);
What's this magic 12 in here? Not IMSIC_MMIO_PAGE_SHIFT I suppose?
> + value = desc->irq;
> + value |= cpu << APLIC_TARGET_HART_IDX_SHIFT;
> + value |= group_index << (lhxw + APLIC_TARGET_HART_IDX_SHIFT) ;
> + aplic.regs->target[desc->irq - 1] = value;
> +
> + spin_unlock(&aplic.lock);
> +}
> +
> +static hw_irq_controller aplic_host_irq_type = {
const?
> --- a/xen/arch/riscv/imsic.c
> +++ b/xen/arch/riscv/imsic.c
> @@ -14,12 +14,68 @@
> #include <xen/errno.h>
> #include <xen/init.h>
> #include <xen/macros.h>
> +#include <xen/spinlock.h>
> #include <xen/xmalloc.h>
>
> #include <asm/imsic.h>
>
> static struct imsic_config imsic_cfg;
>
> +#define imsic_csr_set(c, v) \
> +do { \
> + csr_write(CSR_SISELECT, c); \
> + csr_set(CSR_SIREG, v); \
> +} while (0)
> +
> +#define imsic_csr_clear(c, v) \
> +do { \
> + csr_write(CSR_SISELECT, c); \
> + csr_clear(CSR_SIREG, v); \
> +} while (0)
> +
> +static void imsic_local_eix_update(unsigned long base_id, unsigned long num_id,
> + bool pend, bool val)
> +{
> + unsigned long i, isel, ireg;
These can be constrained to inside the outer loop below.
> + unsigned long id = base_id, last_id = base_id + num_id;
> +
> + while ( id < last_id )
> + {
> + isel = id / __riscv_xlen;
> + isel *= __riscv_xlen / IMSIC_EIPx_BITS;
> + isel += (pend) ? IMSIC_EIP0 : IMSIC_EIE0;
Nit: Why the parentheses?
> + ireg = 0;
> + for ( i = id & (__riscv_xlen - 1);
> + (id < last_id) && (i < __riscv_xlen);
> + i++, id++ )
> + ireg |= (1 << i);
I wonder if this calculation really needs a loop. Afaict it's just a
consecutive set of bits you mean to set.
> + if ( val )
> + imsic_csr_set(isel, ireg);
> + else
> + imsic_csr_clear(isel, ireg);
> + }
> +}
> +
> +void imsic_irq_enable(unsigned int hwirq)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&imsic_cfg.lock, flags);
> + imsic_local_eix_update(hwirq, 1, false, true);
No subtraction of 1 here? Also, why "hwirq" and not just "irq"?
> + spin_unlock_irqrestore(&imsic_cfg.lock, flags);
> +}
> +
> +void imsic_irq_disable(unsigned int hwirq)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&imsic_cfg.lock, flags);
> + imsic_local_eix_update(hwirq, 1, false, false);
> + spin_unlock_irqrestore(&imsic_cfg.lock, flags);
> +}
> +
> const struct imsic_config *imsic_get_config(void)
> {
> return &imsic_cfg;
> @@ -277,6 +333,13 @@ int __init imsic_init(struct dt_device_node *node)
> goto imsic_init_err;
> }
>
> + spin_lock_init(&imsic_cfg.lock);
> +
> + /* Enable local interrupt delivery */
> + imsic_ids_local_delivery(true);
What's this? I can't find the function/macro here, nor in patch 08, nor in
staging.
Jan
next prev parent reply other threads:[~2025-04-15 12:47 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-08 15:57 [PATCH v1 00/14] riscv: introduce basic UART support and interrupts for hypervisor mode Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 01/14] xen/riscv: implement get_s_time() Oleksii Kurochko
2025-04-10 12:52 ` Jan Beulich
2025-04-14 14:50 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 02/14] xen/riscv: introduce smp_clear_cpu_maps() Oleksii Kurochko
2025-04-10 13:10 ` Jan Beulich
2025-04-14 15:05 ` Oleksii Kurochko
2025-04-14 15:13 ` Jan Beulich
2025-04-08 15:57 ` [PATCH v1 03/14] xen/riscv: introduce ioremap() Oleksii Kurochko
2025-04-10 15:13 ` Jan Beulich
2025-04-15 10:29 ` Oleksii Kurochko
2025-04-15 11:02 ` Jan Beulich
2025-04-17 14:20 ` Oleksii Kurochko
2025-04-17 14:24 ` Jan Beulich
2025-04-17 14:37 ` Oleksii Kurochko
2025-04-17 14:49 ` Jan Beulich
2025-04-22 8:40 ` Oleksii Kurochko
2025-04-22 9:14 ` Jan Beulich
2025-04-24 13:30 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 04/14] xen/riscv: introduce init_IRQ() Oleksii Kurochko
2025-04-10 15:25 ` Jan Beulich
2025-04-15 10:36 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 05/14] xen/riscv: introduce platform_get_irq() Oleksii Kurochko
2025-04-10 15:35 ` Jan Beulich
2025-04-15 11:11 ` Oleksii Kurochko
2025-04-15 11:23 ` Jan Beulich
2025-04-17 14:43 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 06/14] xen/riscv: riscv_of_processor_hartid() implementation Oleksii Kurochko
2025-04-10 15:53 ` Jan Beulich
2025-04-15 13:39 ` Oleksii Kurochko
2025-04-15 13:45 ` Jan Beulich
2025-04-25 17:07 ` Oleksii Kurochko
2025-04-28 6:31 ` Jan Beulich
2025-04-28 10:43 ` Oleksii Kurochko
2025-04-28 11:09 ` Jan Beulich
2025-04-08 15:57 ` [PATCH v1 07/14] xen/riscv: Introduce intc_hw_operations abstraction Oleksii Kurochko
2025-04-10 16:02 ` Jan Beulich
2025-04-15 15:01 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 08/14] xen/riscv: imsic_init() implementation Oleksii Kurochko
2025-04-14 9:32 ` Jan Beulich
2025-04-15 19:11 ` Oleksii Kurochko
[not found] ` <9a13c625-cd33-485d-a91f-9f005522b5a4@suse.com>
2025-04-23 11:44 ` Oleksii Kurochko
2025-04-29 8:24 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 09/14] xen/riscv: aplic_init() implementation Oleksii Kurochko
2025-04-14 10:04 ` Jan Beulich
2025-04-16 10:15 ` Oleksii Kurochko
2025-04-16 10:30 ` Jan Beulich
2025-04-17 15:21 ` Oleksii Kurochko
2025-04-17 15:30 ` Jan Beulich
2025-04-18 11:31 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 10/14] xen/riscv: implementation of aplic and imsic operations Oleksii Kurochko
2025-04-15 12:46 ` Jan Beulich [this message]
2025-04-16 19:05 ` Oleksii Kurochko
2025-04-17 6:25 ` Jan Beulich
2025-04-28 8:12 ` Oleksii Kurochko
2025-04-28 8:54 ` Jan Beulich
2025-04-30 16:07 ` Oleksii Kurochko
2025-04-15 14:53 ` Jan Beulich
2025-04-18 10:43 ` Oleksii Kurochko
2025-04-22 7:02 ` Jan Beulich
2025-04-25 19:31 ` Oleksii Kurochko
2025-04-28 6:35 ` Jan Beulich
2025-04-08 15:57 ` [PATCH v1 11/14] xen/riscv: add external interrupt handling for hypervisor mode Oleksii Kurochko
2025-04-15 14:42 ` Jan Beulich
2025-04-17 8:44 ` Oleksii Kurochko
2025-04-17 9:13 ` Oleksii Kurochko
2025-04-08 15:57 ` [PATCH v1 12/14] xen/riscv: implement setup_irq() Oleksii Kurochko
2025-04-15 15:55 ` Jan Beulich
2025-04-17 10:10 ` Oleksii Kurochko
2025-04-17 11:51 ` Jan Beulich
2025-04-08 15:57 ` [PATCH v1 13/14] xen/riscv: initialize interrupt controller Oleksii Kurochko
2025-04-15 15:59 ` Jan Beulich
2025-04-17 10:11 ` Oleksii Kurochko
2025-04-30 15:34 ` Oleksii Kurochko
2025-04-30 15:39 ` Jan Beulich
2025-04-08 15:57 ` [PATCH v1 14/14] xen/riscv: add basic UART support Oleksii Kurochko
2025-04-15 16:03 ` Jan Beulich
2025-04-17 10:31 ` Oleksii Kurochko
2025-04-17 11:52 ` Jan Beulich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=35075d73-ec3c-4e8f-b7ed-657b604904bd@suse.com \
--to=jbeulich@suse.com \
--cc=Romain.Caritey@microchip.com \
--cc=alistair.francis@wdc.com \
--cc=andrew.cooper3@citrix.com \
--cc=anthony.perard@vates.tech \
--cc=bobbyeshleman@gmail.com \
--cc=connojdavis@gmail.com \
--cc=julien@xen.org \
--cc=michal.orzel@amd.com \
--cc=oleksii.kurochko@gmail.com \
--cc=roger.pau@citrix.com \
--cc=sstabellini@kernel.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.