[PATCH 1/1] riscv-aplic: manually set pending for the pre-existing interrupts

Anup Patel anup at brainfault.org
Thu Aug 8 06:26:32 PDT 2024


More appropriate patch subject should be:

irqchip: riscv-aplic: retrigger interrupt in MSI mode upon write to
sourcecfg register

On Thu, Aug 8, 2024 at 1:44 PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> The section 4.5.2 of the RISC-V AIA specification says that any write
> to a sourcecfg register of an APLIC might (or might not) cause the
> corresponding interrupt-pending bit to be set to one if the rectified
> input value is high (= 1) under the new source mode.

Add quotes around the text from RISC-V AIA specification.

>
> If an interrupt is asserted before the driver configs its interrupt
> type to APLIC, it's pending bit will not be set except a relevant
> write to a setip or setipnum register. When we write the interrupt
> type to sourcecfg register, if the APLIC device doesn't check and
> update the pending bit, the interrupt might never becomes pending.

The second sentence above can be re-written as follows:

When interrupt type is changed in sourcecfg register, the APLIC
device might not set the corresponding pending bit, the interrupt
might never become pending.

>
> For the level interrupts forwarded by MSI, we can manually set the
> pending bit if the interrupts have been asserted before the interrupt
> type configuration.

The above sentence can be re-writtern as follows:

To handle sourcecfg register changes for level-triggered interrupts in
MSI mode, manually set the pending bit for retriggering interrupt if it
was already asserted.

>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
> Reviewed-by: Vincent Chen <vincent.chen at sifive.com>
> ---
>  drivers/irqchip/irq-riscv-aplic-main.c |  4 ++++
>  drivers/irqchip/irq-riscv-aplic-main.h |  1 +
>  drivers/irqchip/irq-riscv-aplic-msi.c  | 17 +++++++++++------
>  3 files changed, 16 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c
> index 28dd175b5764..46c44d96123c 100644
> --- a/drivers/irqchip/irq-riscv-aplic-main.c
> +++ b/drivers/irqchip/irq-riscv-aplic-main.c
> @@ -58,6 +58,10 @@ int aplic_irq_set_type(struct irq_data *d, unsigned int type)
>         sourcecfg += (d->hwirq - 1) * sizeof(u32);
>         writel(val, sourcecfg);
>
> +       /* manually set pending for the asserting interrupts */
> +       if (!priv->nr_idcs)
> +               aplic_retrigger_asserting_irq(d);
> +

This is not the right place. See below.

>         return 0;
>  }
>
> diff --git a/drivers/irqchip/irq-riscv-aplic-main.h b/drivers/irqchip/irq-riscv-aplic-main.h
> index 4393927d8c80..c2be66f379b1 100644
> --- a/drivers/irqchip/irq-riscv-aplic-main.h
> +++ b/drivers/irqchip/irq-riscv-aplic-main.h
> @@ -34,6 +34,7 @@ struct aplic_priv {
>
>  void aplic_irq_unmask(struct irq_data *d);
>  void aplic_irq_mask(struct irq_data *d);
> +void aplic_retrigger_asserting_irq(struct irq_data *d);
>  int aplic_irq_set_type(struct irq_data *d, unsigned int type);
>  int aplic_irqdomain_translate(struct irq_fwspec *fwspec, u32 gsi_base,
>                               unsigned long *hwirq, unsigned int *type);
> diff --git a/drivers/irqchip/irq-riscv-aplic-msi.c b/drivers/irqchip/irq-riscv-aplic-msi.c
> index 028444af48bd..eaf4d730a49a 100644
> --- a/drivers/irqchip/irq-riscv-aplic-msi.c
> +++ b/drivers/irqchip/irq-riscv-aplic-msi.c
> @@ -32,15 +32,10 @@ static void aplic_msi_irq_unmask(struct irq_data *d)
>         aplic_irq_unmask(d);
>  }
>
> -static void aplic_msi_irq_eoi(struct irq_data *d)
> +void aplic_retrigger_asserting_irq(struct irq_data *d)

This needs to be a static function because we don't require
this for APLIC in direct mode.

Also, rename it to aplic_msi_irq_retrigger_level().

>  {
>         struct aplic_priv *priv = irq_data_get_irq_chip_data(d);
>
> -       /*
> -        * EOI handling is required only for level-triggered interrupts
> -        * when APLIC is in MSI mode.
> -        */
> -
>         switch (irqd_get_trigger_type(d)) {
>         case IRQ_TYPE_LEVEL_LOW:
>         case IRQ_TYPE_LEVEL_HIGH:
> @@ -59,6 +54,16 @@ static void aplic_msi_irq_eoi(struct irq_data *d)
>         }
>  }
>
> +static void aplic_msi_irq_eoi(struct irq_data *d)
> +{
> +       /*
> +        * EOI handling is required only for level-triggered interrupts
> +        * when APLIC is in MSI mode.
> +        */
> +
> +       aplic_retrigger_asserting_irq(d);
> +}
> +

Define APLIC MSI mode specific irq_set_type() like below:

int aplic_msi_irq_set_type(struct irq_data *d, unsigned int type)
{
       int rc;

       rc = aplic_irq_set_type(d, type);
       if (rc)
              return rc;

       /*
        * Updating sourcecfg register for level-triggered interrupts
        * requires interrupt retriggering when APLIC in MSI mode.
        */
       aplic_msi_irq_retrigger_level(d);
       return 0;
}

>  static void aplic_msi_write_msg(struct irq_data *d, struct msi_msg *msg)
>  {
>         unsigned int group_index, hart_index, guest_index, val;
> --
> 2.17.1
>

Regards,
Anup



More information about the linux-riscv mailing list