All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frank Chang <frank.chang@sifive.com>
To: Anup Patel <anup@brainfault.org>
Cc: Peter Maydell <peter.maydell@linaro.org>,
	"open list:RISC-V" <qemu-riscv@nongnu.org>,
	Sagar Karandikar <sagark@eecs.berkeley.edu>,
	"qemu-devel@nongnu.org Developers" <qemu-devel@nongnu.org>,
	Alistair Francis <Alistair.Francis@wdc.com>,
	Atish Patra <atishp@atishpatra.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Bin Meng <bmeng.cn@gmail.com>
Subject: Re: [PATCH v6 09/23] target/riscv: Implement AIA local interrupt priorities
Date: Thu, 13 Jan 2022 22:21:19 +0800	[thread overview]
Message-ID: <CAE_xrPiatQhRZ+EOq+6BumPEA87jgzTZChT9Qn0Pp_wxN690LQ@mail.gmail.com> (raw)
In-Reply-To: <CAAhSdy2faOV1Z3rkJ1JDTi5RMEdFp27jPzLthVZgTaKv2MgmDg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 24630 bytes --]

On Thu, Jan 13, 2022 at 6:45 PM Anup Patel <anup@brainfault.org> wrote:

> On Wed, Jan 12, 2022 at 8:30 AM Frank Chang <frank.chang@sifive.com>
> wrote:
> >
> > On Wed, Jan 12, 2022 at 1:18 AM Anup Patel <anup@brainfault.org> wrote:
> >>
> >>
> >>
> >> On Mon, Jan 10, 2022 at 6:38 PM Frank Chang <frank.chang@sifive.com>
> wrote:
> >> >
> >> > Anup Patel <anup@brainfault.org> 於 2021年12月30日 週四 下午8:38寫道:
> >> >>
> >> >> From: Anup Patel <anup.patel@wdc.com>
> >> >>
> >> >> The AIA spec defines programmable 8-bit priority for each local
> interrupt
> >> >> at M-level, S-level and VS-level so we extend local interrupt
> processing
> >> >> to consider AIA interrupt priorities. The AIA CSRs which help
> software
> >> >> configure local interrupt priorities will be added by subsequent
> patches.
> >> >>
> >> >> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> >> >> Signed-off-by: Anup Patel <anup@brainfault.org>
> >> >> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> >> >> ---
> >> >>  target/riscv/cpu.c        |  19 ++++
> >> >>  target/riscv/cpu.h        |  12 ++
> >> >>  target/riscv/cpu_helper.c | 231
> ++++++++++++++++++++++++++++++++++----
> >> >>  target/riscv/machine.c    |   3 +
> >> >>  4 files changed, 244 insertions(+), 21 deletions(-)
> >> >>
> >> >> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> >> >> index 9f1a4d1088..9ad26035e1 100644
> >> >> --- a/target/riscv/cpu.c
> >> >> +++ b/target/riscv/cpu.c
> >> >> @@ -348,6 +348,10 @@ void restore_state_to_opc(CPURISCVState *env,
> TranslationBlock *tb,
> >> >>
> >> >>  static void riscv_cpu_reset(DeviceState *dev)
> >> >>  {
> >> >> +#ifndef CONFIG_USER_ONLY
> >> >> +    uint8_t iprio;
> >> >> +    int i, irq, rdzero;
> >> >> +#endif
> >> >>      CPUState *cs = CPU(dev);
> >> >>      RISCVCPU *cpu = RISCV_CPU(cs);
> >> >>      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> >> >> @@ -370,6 +374,21 @@ static void riscv_cpu_reset(DeviceState *dev)
> >> >>      env->miclaim = MIP_SGEIP;
> >> >>      env->pc = env->resetvec;
> >> >>      env->two_stage_lookup = false;
> >> >> +
> >> >> +    /* Initialized default priorities of local interrupts. */
> >> >> +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> >> >> +        iprio = riscv_cpu_default_priority(i);
> >> >> +        env->miprio[i] = (i == IRQ_M_EXT) ? 0 : iprio;
> >> >> +        env->siprio[i] = (i == IRQ_S_EXT) ? 0 : iprio;
> >> >> +        env->hviprio[i] = 0;
> >> >> +    }
> >> >> +    i = 0;
> >> >> +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> >> >> +        if (!rdzero) {
> >> >> +            env->hviprio[irq] = env->miprio[irq];
> >> >> +        }
> >> >> +        i++;
> >> >> +    }
> >> >>      /* mmte is supposed to have pm.current hardwired to 1 */
> >> >>      env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
> >> >>  #endif
> >> >> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> >> >> index 02f3ef2c3c..140fabfdf9 100644
> >> >> --- a/target/riscv/cpu.h
> >> >> +++ b/target/riscv/cpu.h
> >> >> @@ -182,6 +182,10 @@ struct CPURISCVState {
> >> >>      target_ulong mcause;
> >> >>      target_ulong mtval;  /* since: priv-1.10.0 */
> >> >>
> >> >> +    /* Machine and Supervisor interrupt priorities */
> >> >> +    uint8_t miprio[64];
> >> >> +    uint8_t siprio[64];
> >> >> +
> >> >>      /* Hypervisor CSRs */
> >> >>      target_ulong hstatus;
> >> >>      target_ulong hedeleg;
> >> >> @@ -194,6 +198,9 @@ struct CPURISCVState {
> >> >>      target_ulong hgeip;
> >> >>      uint64_t htimedelta;
> >> >>
> >> >> +    /* Hypervisor controlled virtual interrupt priorities */
> >> >> +    uint8_t hviprio[64];
> >> >> +
> >> >>      /* Virtual CSRs */
> >> >>      /*
> >> >>       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> >> >> @@ -379,6 +386,11 @@ int
> riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> >> >>                                 int cpuid, void *opaque);
> >> >>  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int
> reg);
> >> >>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int
> reg);
> >> >> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int
> *out_rdzero);
> >> >> +uint8_t riscv_cpu_default_priority(int irq);
> >> >> +int riscv_cpu_mirq_pending(CPURISCVState *env);
> >> >> +int riscv_cpu_sirq_pending(CPURISCVState *env);
> >> >> +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> >> >>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> >> >>  target_ulong riscv_cpu_get_geilen(CPURISCVState *env);
> >> >>  void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
> >> >> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> >> >> index f94a36fa89..e3532de4cf 100644
> >> >> --- a/target/riscv/cpu_helper.c
> >> >> +++ b/target/riscv/cpu_helper.c
> >> >> @@ -151,36 +151,225 @@ void cpu_get_tb_cpu_state(CPURISCVState *env,
> target_ulong *pc,
> >> >>  }
> >> >>
> >> >>  #ifndef CONFIG_USER_ONLY
> >> >> -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >> +
> >> >> +/*
> >> >> + * The HS-mode is allowed to configure priority only for the
> >> >> + * following VS-mode local interrupts:
> >> >> + *
> >> >> + * 0  (Reserved interrupt, reads as zero)
> >> >> + * 1  Supervisor software interrupt
> >> >> + * 4  (Reserved interrupt, reads as zero)
> >> >> + * 5  Supervisor timer interrupt
> >> >> + * 8  (Reserved interrupt, reads as zero)
> >> >> + * 13 (Reserved interrupt)
> >> >> + * 14 "
> >> >> + * 15 "
> >> >> + * 16 "
> >> >> + * 18 Debug/trace interrupt
> >> >> + * 20 (Reserved interrupt)
> >> >> + * 22 "
> >> >> + * 24 "
> >> >> + * 26 "
> >> >> + * 28 "
> >> >> + * 30 (Reserved for standard reporting of bus or system errors)
> >> >> + */
> >> >> +
> >> >> +static int hviprio_index2irq[] =
> >> >> +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> >> >> +static int hviprio_index2rdzero[] =
> >> >> +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> >> >> +
> >> >> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int
> *out_rdzero)
> >> >>  {
> >> >> -    target_ulong virt_enabled = riscv_cpu_virt_enabled(env);
> >> >> +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> >> >> +        return -EINVAL;
> >> >> +    }
> >> >> +
> >> >> +    if (out_irq) {
> >> >> +        *out_irq = hviprio_index2irq[index];
> >> >> +    }
> >> >>
> >> >> -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> >> >> -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> >> >> +    if (out_rdzero) {
> >> >> +        *out_rdzero = hviprio_index2rdzero[index];
> >> >> +    }
> >> >>
> >> >> -    target_ulong vsgemask =
> >> >> -                (target_ulong)1 << get_field(env->hstatus,
> HSTATUS_VGEIN);
> >> >> -    target_ulong vsgein = (env->hgeip & vsgemask) ? MIP_VSEIP : 0;
> >> >> +    return 0;
> >> >> +}
> >> >>
> >> >> -    target_ulong pending = (env->mip | vsgein) & env->mie;
> >> >> +uint8_t riscv_cpu_default_priority(int irq)
> >> >> +{
> >> >> +    int u, l;
> >> >> +    uint8_t iprio = IPRIO_MMAXIPRIO;
> >> >>
> >> >> -    target_ulong mie    = env->priv < PRV_M ||
> >> >> -                          (env->priv == PRV_M && mstatus_mie);
> >> >> -    target_ulong sie    = env->priv < PRV_S ||
> >> >> -                          (env->priv == PRV_S && mstatus_sie);
> >> >> -    target_ulong hsie   = virt_enabled || sie;
> >> >> -    target_ulong vsie   = virt_enabled && sie;
> >> >> +    if (irq < 0 || irq > 63) {
> >> >> +        return iprio;
> >> >> +    }
> >> >>
> >> >> -    target_ulong irqs =
> >> >> -            (pending & ~env->mideleg & -mie) |
> >> >> -            (pending &  env->mideleg & ~env->hideleg & -hsie) |
> >> >> -            (pending &  env->mideleg &  env->hideleg & -vsie);
> >> >> +    /*
> >> >> +     * Default priorities of local interrupts are defined in the
> >> >> +     * RISC-V Advanced Interrupt Architecture specification.
> >> >> +     *
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     *  Default  |
> >> >> +     *  Priority | Major Interrupt Numbers
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60
> (3c),
> >> >> +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56
> (38),
> >> >> +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52
> (34),
> >> >> +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48
> (30)
> >> >> +     *           |
> >> >> +     *           | 11 (0b),  3 (03),  7 (07)
> >> >> +     *           |  9 (09),  1 (01),  5 (05)
> >> >> +     *           | 12 (0c)
> >> >> +     *           | 10 (0a),  2 (02),  6 (06)
> >> >> +     *           |
> >> >> +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44
> (2c),
> >> >> +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40
> (28),
> >> >> +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36
> (24),
> >> >> +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32
> (20)
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     */
> >> >>
> >> >> -    if (irqs) {
> >> >> -        return ctz64(irqs); /* since non-zero */
> >> >> +    u = IPRIO_DEFAULT_U(irq);
> >> >> +    l = IPRIO_DEFAULT_L(irq);
> >> >> +    if (u == 0) {
> >> >> +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> >> >> +            irq == IRQ_VS_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_VS;
> >> >> +        } else if (irq == IRQ_S_GEXT) {
> >> >> +            iprio = IPRIO_DEFAULT_SGEXT;
> >> >> +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> >> >> +                   irq == IRQ_S_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_S;
> >> >> +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> >> >> +                   irq == IRQ_M_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_M;
> >> >> +        } else {
> >> >> +            iprio = IPRIO_DEFAULT_VS;
> >> >> +        }
> >> >> +    } else if (u == 1) {
> >> >> +        if (l < 8) {
> >> >> +            iprio = IPRIO_DEFAULT_16_23(irq);
> >> >> +        } else {
> >> >> +            iprio = IPRIO_DEFAULT_24_31(irq);
> >> >> +        }
> >> >> +    } else if (u == 2) {
> >> >> +        iprio = IPRIO_DEFAULT_32_47(irq);
> >> >> +    } else if (u == 3) {
> >> >> +        iprio = IPRIO_DEFAULT_48_63(irq);
> >> >> +    }
> >> >> +
> >> >> +    return iprio;
> >> >> +}
> >> >> +
> >> >> +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> >> >> +                                    uint64_t pending, uint8_t
> *iprio)
> >> >> +{
> >> >> +    int irq, best_irq = RISCV_EXCP_NONE;
> >> >> +    unsigned int prio, best_prio = UINT_MAX;
> >> >> +
> >> >> +    if (!pending) {
> >> >> +        return RISCV_EXCP_NONE;
> >> >> +    }
> >> >> +
> >> >> +    irq = ctz64(pending);
> >> >> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> >> >> +        return irq;
> >> >> +    }
> >> >> +
> >> >> +    pending = pending >> irq;
> >> >> +    while (pending) {
> >> >> +        prio = iprio[irq];
> >> >> +        if (!prio) {
> >> >> +            prio = (riscv_cpu_default_priority(irq) <
> IPRIO_DEFAULT_M) ?
> >> >> +                   1 : IPRIO_MMAXIPRIO;
> >> >
> >> >
> >> > Hi Anup,
> >> >
> >> > I have a question regarding configuring priorities of major
> interrupts.
> >> >
> >> > riscv_cpu_default_priority() for M-mode external interrupt would
> return IPRIO_DEFAULT_M (8).
> >> > but the comparison here is < IPRIO_DEFAULT_M,
> >> > so if M-mode external interrupt is pending, the prio would be
> assigned to IPRIO_MMAXIPRIO (255).
> >> > Is this the expected behavior?
> >>
> >> Actually, for irq == IRQ_M_EXT the prio should be IPRIO_DEFAULT_M
> >> same for irq == IRQ_S_EXT.
> >>
> >> Goot catch, I will fix this in next revision.
> >>
> >> >
> >> > Also, why is IPRIO_DEFAULT_M been compared?
> >> > Should IPRIO_DEFAULT_S and IPRIO_DEFAULT_VS be used for S-mode and
> VS-mode interrupts?
> >>
> >> For M-mode, we should compare IPRIO_DEFAULT_M.
> >> For S/VS-mode, we should compare IPRIO_DEFAULT_S
> >> but the priority registers used for S-mode and VS-mode
> >> are different.
> >>
> >> >
> >> >>
> >> >> +        }
> >> >> +        if ((pending & 0x1) && (prio < best_prio)) {
> >> >
> >> >
> >> > If both interrupt 63 and 62 are pending-and-enabled,
> >> > with their iprio values both assigned to zero.
> >> > Interrupt 62 would be picked, because best_prio will be 1 when
> interrupt 62 is been checked.
> >> > As the default priority order for interrupt 63 is also less than
> IPRIO_DEFAULT_M (8),
> >> > so prio would be assigned to 1 as well.
> >> > But as prio is not less than best_prio, so best_irq would still be
> interrupt 62.
> >> >
> >> > However, according to the default priority table in AIA spec,
> >> > interrupt 63 should have a higher priority than interrupt 62:
> >> >   Interrupt 63 has the highest default priority, and interrupt 32 has
> the lowest default priority.
> >>
> >> Argh, the comparision "prio < best_prio" should have been
> >> "prio <= best_prio".
> >>
> >> I am certainly aware of the fact that if two interrupts
> >> have same priority then higher interrupt number should be
> >> preferred. This is silly mistake on my part.
> >>
> >> I really appreciate your detailed review. Thanks.
> >>
> >> >
> >> >>
> >> >> +            best_irq = irq;
> >> >> +            best_prio = prio;
> >> >> +        }
> >> >> +        irq++;
> >> >> +        pending = pending >> 1;
> >> >> +    }
> >> >> +
> >> >> +    return best_irq;
> >> >> +}
> >> >
> >> >
> >> > Yet I have another question for major interrupts priorities.
> >> >
> >> > According to AIA spec (v0.2-draft.28):
> >> > ==========
> >> > The priority number for a machine-level external interrupt (bits
> 31:24 of register iprio2)
> >> > must also be read-only zero.
> >> >
> >> > When an interrupt’s priority number in the array is zero (either
> read-only zero or set to zero),
> >> > its priority is the default order from Section 6.1.
> >> > Setting an interrupt’s priority number instead to a nonzero value p
> gives that interrupt nominally
> >> > the same priority as a machine-level external interrupt with priority
> number p.
> >> > For a major interrupt that defaults to a higher priority than machine
> external interrupts,
> >> > setting its priority number to a nonzero value lowers its priority.
> >> > For a major interrupt that defaults to a lower priority than machine
> external interrupts,
> >> > setting its priority number to a nonzero value raises its priority.
> >> > ==========
> >> >
> >> > From the above sentences,
> >> > The M-mode external interrupt has iprio value of 0, so the default
> priority order is applied.
> >>
> >> Yes, that's correct and same logic applies to S/VS-mode external
> interrupts.
> >>
> >> >
> >> > What are the priorities for the major interrupt interrupts which are
> higher/lower than
> >> > M-mode external interrupt when their iprio values are not 0?
> >>
> >> For a major interrupt X (which is not an external interrupt) having
> iprio value 0,
> >> we take iprio of X as 1 or 255 based of comparison of default priority
> of X
> >> with default priority of external interrupt.
> >> (Refer, documentation of "mtopi" (Section 6.3.2) and "stopi" (Section
> 6.5.2))
> >>
> >> >
> >> > Which interrupt will be picked when:
> >> >   M-mode external interrupt is pending-and-enabled,
> >> >   Interrupt with higher default priority than M-mode external
> interrupt is pending-and-enabled, and
> >> >   Interrupt with lower default priority than M-mode external
> interrupt is pending-and-enabled/
> >> >
> >> > From the above riscv_cpu_pending_to_irq(),
> >> > If both interrupt 63 and interrupt 18's iprio values are assigned to
> the value of 10,
> >>
> >> You mean both these interrupt have iprio 0, right ?
> >
> >
> > I mean if both interrupt 63 and interrupt 18's iprio values are assigned
> with value 10.
> > If interrupt 63, interrupt 18, and M-mode external interrupt are
> pending-and-enabled.
> > Will M-mode external interrupt be picked as it has the default priority:
> 8,
> > which is less than 10 of interrupt 63 and interrupt 18?
>
> Yes, in this case "mtopi" CSR read will return M-mode external interrupt.
>
> >
> > What if, interrupt 63 has iprio value of 10 and interrupt 18 has iprio
> value of 6.
> > If interrupt 63, interrupt 18, and M-mode external interrupt are
> pending-and-enabled.
> > Will interrupt 18 be picked because it has the smallest iprio value
> (i.e. higher interrupt priority)?
>
> Yes, in this case "mtopi" CSR read will return interrupt 18.
>
> >
> > Can I say that for M-mode major interrupts:
> >
> > If interrupt X's iprio value is zero, its interrupt priority will be 1
> or 255,
> > base on its default priority which is higher (1) or less (255) than
> M-mode external interrupt.
>
> Yes, this is correct form M-mode (and "mtopi" CSR) perspective.
>
> For S-mode (and "stopi" or "vstopi" CSR) perspective, it will be
> compared against S-mode external interrupt default priority.
> (Note: I will fix this in next revision)
>
> >
> > And if interrupt X's iprio value is not zero, its interrupt priority
> will be the assigned iprio value.
>
> Yes, this is correct.
>
> > So it's possible for a lower default priority interrupt (e.g. 18) to
> have higher priority than M-mode external interrupt
> > if its iprio value is less than 8?
>
> Yes, this is correct. The fact that iprio of major interrupts are
> programmable
> it allow software to override the default priority assignement.
>
> >
> > The overall interrupt priority order is compared between the values of:
> >   * If iprio value is zero: 1 or 255
> >   * If iprio value is not zero: the iprio value been assigned
>
> This two statements are correct.
>
> >   * M-mode external interrupt: the default priority value: 8?
> > and the interrupt with the smallest value will be picked.
>
> I would like to clarify that it is QEMU implementation that has
> chosen to assign default priorities in 1 to 15 range hence we
> have M-mode external interrupt default priority as 8. Some
> other implementation may chose a different default priority
> assignments but it should comply with the table in the
> "Section 6.1" of the AIA specification.
>
> Regards,
> Anup
>

Thanks for the detailed explanation :)

Regards,
Frank Chang


>
> >
> >>
> >> > and interrupt 63, interrupt 18 and M-mode external interrupts are
> pending-and-enabled.
> >> > Interrupt 18 would be picked.
> >> > Is this the correct expectation?
> >>
> >> If both 63 and 18 have iprio 0 then interrupt 63 would be picked
> >> because 63 has higher default priority compared to default
> >> priorities of both M-mode external interrupt and interrupt 18.
> >>
> >> > I'm a bit confused with the correct priority order of the interrupts
> with/without non-zero value iprio and the default priority.
> >>
> >> Whenever iprio of an interrupt X is 0, the default priority of
> >> interrupt X compared against default external interrupt
> >> priority and based on this comparison 1 (highest) or 255 (lowest)
> >> priority is used for interrupt X.
> >>
> >> In other, a saturated priority is used on interrupt X when
> >> it's iprio is set to zero.
> >
> >
> > Thanks for the detailed explanation.
> >
> > Regards,
> > Frank Chang
> >
> >>
> >>
> >> Regards,
> >> Anup
> >>
> >> >
> >> > Thanks,
> >> > Frank Chang
> >> >
> >> >>
> >> >> +
> >> >> +static uint64_t riscv_cpu_all_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
> >> >> +    uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
> >> >> +
> >> >> +    return (env->mip | vsgein) & env->mie;
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_mirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & ~env->mideleg &
> >> >> +                    ~(MIP_SGEIP | MIP_VSSIP | MIP_VSTIP |
> MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_sirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
> >> >> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
> >> >> +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> >> >> +}
> >> >> +
> >> >> +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    int virq;
> >> >> +    uint64_t irqs, pending, mie, hsie, vsie;
> >> >> +
> >> >> +    /* Determine interrupt enable state of all privilege modes */
> >> >> +    if (riscv_cpu_virt_enabled(env)) {
> >> >> +        mie = 1;
> >> >> +        hsie = 1;
> >> >> +        vsie = (env->priv < PRV_S) ||
> >> >> +               (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_SIE));
> >> >>      } else {
> >> >> -        return RISCV_EXCP_NONE; /* indicates no pending interrupt */
> >> >> +        mie = (env->priv < PRV_M) ||
> >> >> +              (env->priv == PRV_M && get_field(env->mstatus,
> MSTATUS_MIE));
> >> >> +        hsie = (env->priv < PRV_S) ||
> >> >> +               (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_SIE));
> >> >> +        vsie = 0;
> >> >>      }
> >> >> +
> >> >> +    /* Determine all pending interrupts */
> >> >> +    pending = riscv_cpu_all_pending(env);
> >> >> +
> >> >> +    /* Check M-mode interrupts */
> >> >> +    irqs = pending & ~env->mideleg & -mie;
> >> >> +    if (irqs) {
> >> >> +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> >> >> +    }
> >> >> +
> >> >> +    /* Check HS-mode interrupts */
> >> >> +    irqs = pending & env->mideleg & ~env->hideleg & -hsie;
> >> >> +    if (irqs) {
> >> >> +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> >> >> +    }
> >> >> +
> >> >> +    /* Check VS-mode interrupts */
> >> >> +    irqs = pending & env->mideleg & env->hideleg & -vsie;
> >> >> +    if (irqs) {
> >> >> +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1,
> env->hviprio);
> >> >> +        return (virq <= 0) ? virq : virq + 1;
> >> >> +    }
> >> >> +
> >> >> +    /* Indicate no pending interrupt */
> >> >> +    return RISCV_EXCP_NONE;
> >> >>  }
> >> >>
> >> >>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> >> >> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> >> >> index 76dd0d415c..cffc444969 100644
> >> >> --- a/target/riscv/machine.c
> >> >> +++ b/target/riscv/machine.c
> >> >> @@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = {
> >> >>          VMSTATE_UINTTL(env.hgeie, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.hgeip, RISCVCPU),
> >> >>          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> >> >> +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> >> >>
> >> >>          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> >> >> @@ -173,6 +174,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> >> >>      .fields = (VMStateField[]) {
> >> >>          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> >> >>          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> >> >> +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> >> >> +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> >> >>          VMSTATE_UINTTL(env.pc, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> >> >> --
> >> >> 2.25.1
> >> >>
> >> >>
>

[-- Attachment #2: Type: text/html, Size: 33562 bytes --]

WARNING: multiple messages have this Message-ID (diff)
From: Frank Chang <frank.chang@sifive.com>
To: Anup Patel <anup@brainfault.org>
Cc: Peter Maydell <peter.maydell@linaro.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	 Alistair Francis <Alistair.Francis@wdc.com>,
	Sagar Karandikar <sagark@eecs.berkeley.edu>,
	 "open list:RISC-V" <qemu-riscv@nongnu.org>,
	 "qemu-devel@nongnu.org Developers" <qemu-devel@nongnu.org>,
	Atish Patra <atishp@atishpatra.org>,
	Bin Meng <bmeng.cn@gmail.com>
Subject: Re: [PATCH v6 09/23] target/riscv: Implement AIA local interrupt priorities
Date: Thu, 13 Jan 2022 22:21:19 +0800	[thread overview]
Message-ID: <CAE_xrPiatQhRZ+EOq+6BumPEA87jgzTZChT9Qn0Pp_wxN690LQ@mail.gmail.com> (raw)
In-Reply-To: <CAAhSdy2faOV1Z3rkJ1JDTi5RMEdFp27jPzLthVZgTaKv2MgmDg@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 24630 bytes --]

On Thu, Jan 13, 2022 at 6:45 PM Anup Patel <anup@brainfault.org> wrote:

> On Wed, Jan 12, 2022 at 8:30 AM Frank Chang <frank.chang@sifive.com>
> wrote:
> >
> > On Wed, Jan 12, 2022 at 1:18 AM Anup Patel <anup@brainfault.org> wrote:
> >>
> >>
> >>
> >> On Mon, Jan 10, 2022 at 6:38 PM Frank Chang <frank.chang@sifive.com>
> wrote:
> >> >
> >> > Anup Patel <anup@brainfault.org> 於 2021年12月30日 週四 下午8:38寫道:
> >> >>
> >> >> From: Anup Patel <anup.patel@wdc.com>
> >> >>
> >> >> The AIA spec defines programmable 8-bit priority for each local
> interrupt
> >> >> at M-level, S-level and VS-level so we extend local interrupt
> processing
> >> >> to consider AIA interrupt priorities. The AIA CSRs which help
> software
> >> >> configure local interrupt priorities will be added by subsequent
> patches.
> >> >>
> >> >> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> >> >> Signed-off-by: Anup Patel <anup@brainfault.org>
> >> >> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> >> >> ---
> >> >>  target/riscv/cpu.c        |  19 ++++
> >> >>  target/riscv/cpu.h        |  12 ++
> >> >>  target/riscv/cpu_helper.c | 231
> ++++++++++++++++++++++++++++++++++----
> >> >>  target/riscv/machine.c    |   3 +
> >> >>  4 files changed, 244 insertions(+), 21 deletions(-)
> >> >>
> >> >> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> >> >> index 9f1a4d1088..9ad26035e1 100644
> >> >> --- a/target/riscv/cpu.c
> >> >> +++ b/target/riscv/cpu.c
> >> >> @@ -348,6 +348,10 @@ void restore_state_to_opc(CPURISCVState *env,
> TranslationBlock *tb,
> >> >>
> >> >>  static void riscv_cpu_reset(DeviceState *dev)
> >> >>  {
> >> >> +#ifndef CONFIG_USER_ONLY
> >> >> +    uint8_t iprio;
> >> >> +    int i, irq, rdzero;
> >> >> +#endif
> >> >>      CPUState *cs = CPU(dev);
> >> >>      RISCVCPU *cpu = RISCV_CPU(cs);
> >> >>      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> >> >> @@ -370,6 +374,21 @@ static void riscv_cpu_reset(DeviceState *dev)
> >> >>      env->miclaim = MIP_SGEIP;
> >> >>      env->pc = env->resetvec;
> >> >>      env->two_stage_lookup = false;
> >> >> +
> >> >> +    /* Initialized default priorities of local interrupts. */
> >> >> +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> >> >> +        iprio = riscv_cpu_default_priority(i);
> >> >> +        env->miprio[i] = (i == IRQ_M_EXT) ? 0 : iprio;
> >> >> +        env->siprio[i] = (i == IRQ_S_EXT) ? 0 : iprio;
> >> >> +        env->hviprio[i] = 0;
> >> >> +    }
> >> >> +    i = 0;
> >> >> +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> >> >> +        if (!rdzero) {
> >> >> +            env->hviprio[irq] = env->miprio[irq];
> >> >> +        }
> >> >> +        i++;
> >> >> +    }
> >> >>      /* mmte is supposed to have pm.current hardwired to 1 */
> >> >>      env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
> >> >>  #endif
> >> >> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> >> >> index 02f3ef2c3c..140fabfdf9 100644
> >> >> --- a/target/riscv/cpu.h
> >> >> +++ b/target/riscv/cpu.h
> >> >> @@ -182,6 +182,10 @@ struct CPURISCVState {
> >> >>      target_ulong mcause;
> >> >>      target_ulong mtval;  /* since: priv-1.10.0 */
> >> >>
> >> >> +    /* Machine and Supervisor interrupt priorities */
> >> >> +    uint8_t miprio[64];
> >> >> +    uint8_t siprio[64];
> >> >> +
> >> >>      /* Hypervisor CSRs */
> >> >>      target_ulong hstatus;
> >> >>      target_ulong hedeleg;
> >> >> @@ -194,6 +198,9 @@ struct CPURISCVState {
> >> >>      target_ulong hgeip;
> >> >>      uint64_t htimedelta;
> >> >>
> >> >> +    /* Hypervisor controlled virtual interrupt priorities */
> >> >> +    uint8_t hviprio[64];
> >> >> +
> >> >>      /* Virtual CSRs */
> >> >>      /*
> >> >>       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> >> >> @@ -379,6 +386,11 @@ int
> riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> >> >>                                 int cpuid, void *opaque);
> >> >>  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int
> reg);
> >> >>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int
> reg);
> >> >> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int
> *out_rdzero);
> >> >> +uint8_t riscv_cpu_default_priority(int irq);
> >> >> +int riscv_cpu_mirq_pending(CPURISCVState *env);
> >> >> +int riscv_cpu_sirq_pending(CPURISCVState *env);
> >> >> +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> >> >>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> >> >>  target_ulong riscv_cpu_get_geilen(CPURISCVState *env);
> >> >>  void riscv_cpu_set_geilen(CPURISCVState *env, target_ulong geilen);
> >> >> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> >> >> index f94a36fa89..e3532de4cf 100644
> >> >> --- a/target/riscv/cpu_helper.c
> >> >> +++ b/target/riscv/cpu_helper.c
> >> >> @@ -151,36 +151,225 @@ void cpu_get_tb_cpu_state(CPURISCVState *env,
> target_ulong *pc,
> >> >>  }
> >> >>
> >> >>  #ifndef CONFIG_USER_ONLY
> >> >> -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >> +
> >> >> +/*
> >> >> + * The HS-mode is allowed to configure priority only for the
> >> >> + * following VS-mode local interrupts:
> >> >> + *
> >> >> + * 0  (Reserved interrupt, reads as zero)
> >> >> + * 1  Supervisor software interrupt
> >> >> + * 4  (Reserved interrupt, reads as zero)
> >> >> + * 5  Supervisor timer interrupt
> >> >> + * 8  (Reserved interrupt, reads as zero)
> >> >> + * 13 (Reserved interrupt)
> >> >> + * 14 "
> >> >> + * 15 "
> >> >> + * 16 "
> >> >> + * 18 Debug/trace interrupt
> >> >> + * 20 (Reserved interrupt)
> >> >> + * 22 "
> >> >> + * 24 "
> >> >> + * 26 "
> >> >> + * 28 "
> >> >> + * 30 (Reserved for standard reporting of bus or system errors)
> >> >> + */
> >> >> +
> >> >> +static int hviprio_index2irq[] =
> >> >> +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> >> >> +static int hviprio_index2rdzero[] =
> >> >> +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> >> >> +
> >> >> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int
> *out_rdzero)
> >> >>  {
> >> >> -    target_ulong virt_enabled = riscv_cpu_virt_enabled(env);
> >> >> +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> >> >> +        return -EINVAL;
> >> >> +    }
> >> >> +
> >> >> +    if (out_irq) {
> >> >> +        *out_irq = hviprio_index2irq[index];
> >> >> +    }
> >> >>
> >> >> -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> >> >> -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> >> >> +    if (out_rdzero) {
> >> >> +        *out_rdzero = hviprio_index2rdzero[index];
> >> >> +    }
> >> >>
> >> >> -    target_ulong vsgemask =
> >> >> -                (target_ulong)1 << get_field(env->hstatus,
> HSTATUS_VGEIN);
> >> >> -    target_ulong vsgein = (env->hgeip & vsgemask) ? MIP_VSEIP : 0;
> >> >> +    return 0;
> >> >> +}
> >> >>
> >> >> -    target_ulong pending = (env->mip | vsgein) & env->mie;
> >> >> +uint8_t riscv_cpu_default_priority(int irq)
> >> >> +{
> >> >> +    int u, l;
> >> >> +    uint8_t iprio = IPRIO_MMAXIPRIO;
> >> >>
> >> >> -    target_ulong mie    = env->priv < PRV_M ||
> >> >> -                          (env->priv == PRV_M && mstatus_mie);
> >> >> -    target_ulong sie    = env->priv < PRV_S ||
> >> >> -                          (env->priv == PRV_S && mstatus_sie);
> >> >> -    target_ulong hsie   = virt_enabled || sie;
> >> >> -    target_ulong vsie   = virt_enabled && sie;
> >> >> +    if (irq < 0 || irq > 63) {
> >> >> +        return iprio;
> >> >> +    }
> >> >>
> >> >> -    target_ulong irqs =
> >> >> -            (pending & ~env->mideleg & -mie) |
> >> >> -            (pending &  env->mideleg & ~env->hideleg & -hsie) |
> >> >> -            (pending &  env->mideleg &  env->hideleg & -vsie);
> >> >> +    /*
> >> >> +     * Default priorities of local interrupts are defined in the
> >> >> +     * RISC-V Advanced Interrupt Architecture specification.
> >> >> +     *
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     *  Default  |
> >> >> +     *  Priority | Major Interrupt Numbers
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60
> (3c),
> >> >> +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56
> (38),
> >> >> +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52
> (34),
> >> >> +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48
> (30)
> >> >> +     *           |
> >> >> +     *           | 11 (0b),  3 (03),  7 (07)
> >> >> +     *           |  9 (09),  1 (01),  5 (05)
> >> >> +     *           | 12 (0c)
> >> >> +     *           | 10 (0a),  2 (02),  6 (06)
> >> >> +     *           |
> >> >> +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44
> (2c),
> >> >> +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40
> (28),
> >> >> +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36
> (24),
> >> >> +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32
> (20)
> >> >> +     *
> ----------------------------------------------------------------
> >> >> +     */
> >> >>
> >> >> -    if (irqs) {
> >> >> -        return ctz64(irqs); /* since non-zero */
> >> >> +    u = IPRIO_DEFAULT_U(irq);
> >> >> +    l = IPRIO_DEFAULT_L(irq);
> >> >> +    if (u == 0) {
> >> >> +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> >> >> +            irq == IRQ_VS_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_VS;
> >> >> +        } else if (irq == IRQ_S_GEXT) {
> >> >> +            iprio = IPRIO_DEFAULT_SGEXT;
> >> >> +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> >> >> +                   irq == IRQ_S_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_S;
> >> >> +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> >> >> +                   irq == IRQ_M_SOFT) {
> >> >> +            iprio = IPRIO_DEFAULT_M;
> >> >> +        } else {
> >> >> +            iprio = IPRIO_DEFAULT_VS;
> >> >> +        }
> >> >> +    } else if (u == 1) {
> >> >> +        if (l < 8) {
> >> >> +            iprio = IPRIO_DEFAULT_16_23(irq);
> >> >> +        } else {
> >> >> +            iprio = IPRIO_DEFAULT_24_31(irq);
> >> >> +        }
> >> >> +    } else if (u == 2) {
> >> >> +        iprio = IPRIO_DEFAULT_32_47(irq);
> >> >> +    } else if (u == 3) {
> >> >> +        iprio = IPRIO_DEFAULT_48_63(irq);
> >> >> +    }
> >> >> +
> >> >> +    return iprio;
> >> >> +}
> >> >> +
> >> >> +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> >> >> +                                    uint64_t pending, uint8_t
> *iprio)
> >> >> +{
> >> >> +    int irq, best_irq = RISCV_EXCP_NONE;
> >> >> +    unsigned int prio, best_prio = UINT_MAX;
> >> >> +
> >> >> +    if (!pending) {
> >> >> +        return RISCV_EXCP_NONE;
> >> >> +    }
> >> >> +
> >> >> +    irq = ctz64(pending);
> >> >> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> >> >> +        return irq;
> >> >> +    }
> >> >> +
> >> >> +    pending = pending >> irq;
> >> >> +    while (pending) {
> >> >> +        prio = iprio[irq];
> >> >> +        if (!prio) {
> >> >> +            prio = (riscv_cpu_default_priority(irq) <
> IPRIO_DEFAULT_M) ?
> >> >> +                   1 : IPRIO_MMAXIPRIO;
> >> >
> >> >
> >> > Hi Anup,
> >> >
> >> > I have a question regarding configuring priorities of major
> interrupts.
> >> >
> >> > riscv_cpu_default_priority() for M-mode external interrupt would
> return IPRIO_DEFAULT_M (8).
> >> > but the comparison here is < IPRIO_DEFAULT_M,
> >> > so if M-mode external interrupt is pending, the prio would be
> assigned to IPRIO_MMAXIPRIO (255).
> >> > Is this the expected behavior?
> >>
> >> Actually, for irq == IRQ_M_EXT the prio should be IPRIO_DEFAULT_M
> >> same for irq == IRQ_S_EXT.
> >>
> >> Goot catch, I will fix this in next revision.
> >>
> >> >
> >> > Also, why is IPRIO_DEFAULT_M been compared?
> >> > Should IPRIO_DEFAULT_S and IPRIO_DEFAULT_VS be used for S-mode and
> VS-mode interrupts?
> >>
> >> For M-mode, we should compare IPRIO_DEFAULT_M.
> >> For S/VS-mode, we should compare IPRIO_DEFAULT_S
> >> but the priority registers used for S-mode and VS-mode
> >> are different.
> >>
> >> >
> >> >>
> >> >> +        }
> >> >> +        if ((pending & 0x1) && (prio < best_prio)) {
> >> >
> >> >
> >> > If both interrupt 63 and 62 are pending-and-enabled,
> >> > with their iprio values both assigned to zero.
> >> > Interrupt 62 would be picked, because best_prio will be 1 when
> interrupt 62 is been checked.
> >> > As the default priority order for interrupt 63 is also less than
> IPRIO_DEFAULT_M (8),
> >> > so prio would be assigned to 1 as well.
> >> > But as prio is not less than best_prio, so best_irq would still be
> interrupt 62.
> >> >
> >> > However, according to the default priority table in AIA spec,
> >> > interrupt 63 should have a higher priority than interrupt 62:
> >> >   Interrupt 63 has the highest default priority, and interrupt 32 has
> the lowest default priority.
> >>
> >> Argh, the comparision "prio < best_prio" should have been
> >> "prio <= best_prio".
> >>
> >> I am certainly aware of the fact that if two interrupts
> >> have same priority then higher interrupt number should be
> >> preferred. This is silly mistake on my part.
> >>
> >> I really appreciate your detailed review. Thanks.
> >>
> >> >
> >> >>
> >> >> +            best_irq = irq;
> >> >> +            best_prio = prio;
> >> >> +        }
> >> >> +        irq++;
> >> >> +        pending = pending >> 1;
> >> >> +    }
> >> >> +
> >> >> +    return best_irq;
> >> >> +}
> >> >
> >> >
> >> > Yet I have another question for major interrupts priorities.
> >> >
> >> > According to AIA spec (v0.2-draft.28):
> >> > ==========
> >> > The priority number for a machine-level external interrupt (bits
> 31:24 of register iprio2)
> >> > must also be read-only zero.
> >> >
> >> > When an interrupt’s priority number in the array is zero (either
> read-only zero or set to zero),
> >> > its priority is the default order from Section 6.1.
> >> > Setting an interrupt’s priority number instead to a nonzero value p
> gives that interrupt nominally
> >> > the same priority as a machine-level external interrupt with priority
> number p.
> >> > For a major interrupt that defaults to a higher priority than machine
> external interrupts,
> >> > setting its priority number to a nonzero value lowers its priority.
> >> > For a major interrupt that defaults to a lower priority than machine
> external interrupts,
> >> > setting its priority number to a nonzero value raises its priority.
> >> > ==========
> >> >
> >> > From the above sentences,
> >> > The M-mode external interrupt has iprio value of 0, so the default
> priority order is applied.
> >>
> >> Yes, that's correct and same logic applies to S/VS-mode external
> interrupts.
> >>
> >> >
> >> > What are the priorities for the major interrupt interrupts which are
> higher/lower than
> >> > M-mode external interrupt when their iprio values are not 0?
> >>
> >> For a major interrupt X (which is not an external interrupt) having
> iprio value 0,
> >> we take iprio of X as 1 or 255 based of comparison of default priority
> of X
> >> with default priority of external interrupt.
> >> (Refer, documentation of "mtopi" (Section 6.3.2) and "stopi" (Section
> 6.5.2))
> >>
> >> >
> >> > Which interrupt will be picked when:
> >> >   M-mode external interrupt is pending-and-enabled,
> >> >   Interrupt with higher default priority than M-mode external
> interrupt is pending-and-enabled, and
> >> >   Interrupt with lower default priority than M-mode external
> interrupt is pending-and-enabled/
> >> >
> >> > From the above riscv_cpu_pending_to_irq(),
> >> > If both interrupt 63 and interrupt 18's iprio values are assigned to
> the value of 10,
> >>
> >> You mean both these interrupt have iprio 0, right ?
> >
> >
> > I mean if both interrupt 63 and interrupt 18's iprio values are assigned
> with value 10.
> > If interrupt 63, interrupt 18, and M-mode external interrupt are
> pending-and-enabled.
> > Will M-mode external interrupt be picked as it has the default priority:
> 8,
> > which is less than 10 of interrupt 63 and interrupt 18?
>
> Yes, in this case "mtopi" CSR read will return M-mode external interrupt.
>
> >
> > What if, interrupt 63 has iprio value of 10 and interrupt 18 has iprio
> value of 6.
> > If interrupt 63, interrupt 18, and M-mode external interrupt are
> pending-and-enabled.
> > Will interrupt 18 be picked because it has the smallest iprio value
> (i.e. higher interrupt priority)?
>
> Yes, in this case "mtopi" CSR read will return interrupt 18.
>
> >
> > Can I say that for M-mode major interrupts:
> >
> > If interrupt X's iprio value is zero, its interrupt priority will be 1
> or 255,
> > base on its default priority which is higher (1) or less (255) than
> M-mode external interrupt.
>
> Yes, this is correct form M-mode (and "mtopi" CSR) perspective.
>
> For S-mode (and "stopi" or "vstopi" CSR) perspective, it will be
> compared against S-mode external interrupt default priority.
> (Note: I will fix this in next revision)
>
> >
> > And if interrupt X's iprio value is not zero, its interrupt priority
> will be the assigned iprio value.
>
> Yes, this is correct.
>
> > So it's possible for a lower default priority interrupt (e.g. 18) to
> have higher priority than M-mode external interrupt
> > if its iprio value is less than 8?
>
> Yes, this is correct. The fact that iprio of major interrupts are
> programmable
> it allow software to override the default priority assignement.
>
> >
> > The overall interrupt priority order is compared between the values of:
> >   * If iprio value is zero: 1 or 255
> >   * If iprio value is not zero: the iprio value been assigned
>
> This two statements are correct.
>
> >   * M-mode external interrupt: the default priority value: 8?
> > and the interrupt with the smallest value will be picked.
>
> I would like to clarify that it is QEMU implementation that has
> chosen to assign default priorities in 1 to 15 range hence we
> have M-mode external interrupt default priority as 8. Some
> other implementation may chose a different default priority
> assignments but it should comply with the table in the
> "Section 6.1" of the AIA specification.
>
> Regards,
> Anup
>

Thanks for the detailed explanation :)

Regards,
Frank Chang


>
> >
> >>
> >> > and interrupt 63, interrupt 18 and M-mode external interrupts are
> pending-and-enabled.
> >> > Interrupt 18 would be picked.
> >> > Is this the correct expectation?
> >>
> >> If both 63 and 18 have iprio 0 then interrupt 63 would be picked
> >> because 63 has higher default priority compared to default
> >> priorities of both M-mode external interrupt and interrupt 18.
> >>
> >> > I'm a bit confused with the correct priority order of the interrupts
> with/without non-zero value iprio and the default priority.
> >>
> >> Whenever iprio of an interrupt X is 0, the default priority of
> >> interrupt X compared against default external interrupt
> >> priority and based on this comparison 1 (highest) or 255 (lowest)
> >> priority is used for interrupt X.
> >>
> >> In other, a saturated priority is used on interrupt X when
> >> it's iprio is set to zero.
> >
> >
> > Thanks for the detailed explanation.
> >
> > Regards,
> > Frank Chang
> >
> >>
> >>
> >> Regards,
> >> Anup
> >>
> >> >
> >> > Thanks,
> >> > Frank Chang
> >> >
> >> >>
> >> >> +
> >> >> +static uint64_t riscv_cpu_all_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
> >> >> +    uint64_t vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
> >> >> +
> >> >> +    return (env->mip | vsgein) & env->mie;
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_mirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & ~env->mideleg &
> >> >> +                    ~(MIP_SGEIP | MIP_VSSIP | MIP_VSTIP |
> MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_sirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
> >> >> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> >> >> +}
> >> >> +
> >> >> +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
> >> >> +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> >> >> +
> >> >> +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> >> >> +}
> >> >> +
> >> >> +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> >> >> +{
> >> >> +    int virq;
> >> >> +    uint64_t irqs, pending, mie, hsie, vsie;
> >> >> +
> >> >> +    /* Determine interrupt enable state of all privilege modes */
> >> >> +    if (riscv_cpu_virt_enabled(env)) {
> >> >> +        mie = 1;
> >> >> +        hsie = 1;
> >> >> +        vsie = (env->priv < PRV_S) ||
> >> >> +               (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_SIE));
> >> >>      } else {
> >> >> -        return RISCV_EXCP_NONE; /* indicates no pending interrupt */
> >> >> +        mie = (env->priv < PRV_M) ||
> >> >> +              (env->priv == PRV_M && get_field(env->mstatus,
> MSTATUS_MIE));
> >> >> +        hsie = (env->priv < PRV_S) ||
> >> >> +               (env->priv == PRV_S && get_field(env->mstatus,
> MSTATUS_SIE));
> >> >> +        vsie = 0;
> >> >>      }
> >> >> +
> >> >> +    /* Determine all pending interrupts */
> >> >> +    pending = riscv_cpu_all_pending(env);
> >> >> +
> >> >> +    /* Check M-mode interrupts */
> >> >> +    irqs = pending & ~env->mideleg & -mie;
> >> >> +    if (irqs) {
> >> >> +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> >> >> +    }
> >> >> +
> >> >> +    /* Check HS-mode interrupts */
> >> >> +    irqs = pending & env->mideleg & ~env->hideleg & -hsie;
> >> >> +    if (irqs) {
> >> >> +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> >> >> +    }
> >> >> +
> >> >> +    /* Check VS-mode interrupts */
> >> >> +    irqs = pending & env->mideleg & env->hideleg & -vsie;
> >> >> +    if (irqs) {
> >> >> +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1,
> env->hviprio);
> >> >> +        return (virq <= 0) ? virq : virq + 1;
> >> >> +    }
> >> >> +
> >> >> +    /* Indicate no pending interrupt */
> >> >> +    return RISCV_EXCP_NONE;
> >> >>  }
> >> >>
> >> >>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
> >> >> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> >> >> index 76dd0d415c..cffc444969 100644
> >> >> --- a/target/riscv/machine.c
> >> >> +++ b/target/riscv/machine.c
> >> >> @@ -92,6 +92,7 @@ static const VMStateDescription vmstate_hyper = {
> >> >>          VMSTATE_UINTTL(env.hgeie, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.hgeip, RISCVCPU),
> >> >>          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> >> >> +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> >> >>
> >> >>          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> >> >> @@ -173,6 +174,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> >> >>      .fields = (VMStateField[]) {
> >> >>          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> >> >>          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> >> >> +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> >> >> +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> >> >>          VMSTATE_UINTTL(env.pc, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> >> >>          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> >> >> --
> >> >> 2.25.1
> >> >>
> >> >>
>

[-- Attachment #2: Type: text/html, Size: 33562 bytes --]

  reply	other threads:[~2022-01-13 14:24 UTC|newest]

Thread overview: 120+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-30 12:35 [PATCH v6 00/23] QEMU RISC-V AIA support Anup Patel
2021-12-30 12:35 ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 01/23] target/riscv: Fix trap cause for RV32 HS-mode CSR access from RV64 HS-mode Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:29   ` Frank Chang
2022-01-12 12:29     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 02/23] target/riscv: Implement SGEIP bit in hip and hie CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-13 14:35   ` Frank Chang
2022-01-13 14:35     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 03/23] target/riscv: Implement hgeie and hgeip CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-14  6:37   ` Frank Chang
2022-01-14  6:37     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 04/23] target/riscv: Improve delivery of guest external interrupts Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-13  7:51   ` Frank Chang
2022-01-13  7:51     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 05/23] target/riscv: Allow setting CPU feature from machine/device emulation Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:34   ` Frank Chang
2022-01-12 12:34     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 06/23] target/riscv: Add AIA cpu feature Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:34   ` Frank Chang
2022-01-12 12:34     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 07/23] target/riscv: Add defines for AIA CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:57   ` Frank Chang
2022-01-12 12:57     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 08/23] target/riscv: Allow AIA device emulation to set ireg rmw callback Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:59   ` Frank Chang
2022-01-12 12:59     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 09/23] target/riscv: Implement AIA local interrupt priorities Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-10 13:08   ` Frank Chang
2022-01-10 13:08     ` Frank Chang
2022-01-11 17:18     ` Anup Patel
2022-01-11 17:18       ` Anup Patel
2022-01-12  3:00       ` Frank Chang
2022-01-12  3:00         ` Frank Chang
2022-01-13 10:45         ` Anup Patel
2022-01-13 10:45           ` Anup Patel
2022-01-13 14:21           ` Frank Chang [this message]
2022-01-13 14:21             ` Frank Chang
2022-01-10 13:25   ` Frank Chang
2022-01-10 13:25     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 10/23] target/riscv: Implement AIA CSRs for 64 local interrupts on RV32 Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-14  9:48   ` Frank Chang
2022-01-14  9:48     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 11/23] target/riscv: Implement AIA hvictl and hviprioX CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 13:15   ` Frank Chang
2022-01-12 13:15     ` Frank Chang
2022-01-13 10:49     ` Anup Patel
2022-01-13 10:49       ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 12/23] target/riscv: Implement AIA interrupt filtering CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-11  6:00   ` Frank Chang
2022-01-11  6:00     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 13/23] target/riscv: Implement AIA mtopi, stopi, and vstopi CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 12:15   ` Frank Chang
2022-01-12 12:15     ` Frank Chang
2022-01-13 10:48     ` Anup Patel
2022-01-13 10:48       ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 14/23] target/riscv: Implement AIA xiselect and xireg CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 16:40   ` Frank Chang
2022-01-12 16:40     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 15/23] target/riscv: Implement AIA IMSIC interface CSRs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-05  3:30   ` Frank Chang
2022-01-05  3:30     ` Frank Chang
2022-01-08 12:03     ` Anup Patel
2022-01-08 12:03       ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 16/23] hw/riscv: virt: Use AIA INTC compatible string when available Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 16:47   ` Frank Chang
2022-01-12 16:47     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 17/23] target/riscv: Allow users to force enable AIA CSRs in HART Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 13:19   ` Frank Chang
2022-01-12 13:19     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 18/23] hw/intc: Add RISC-V AIA APLIC device emulation Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-07  8:52   ` Frank Chang
2022-01-07  8:52     ` Frank Chang
2022-01-08 13:28     ` Anup Patel
2022-01-08 13:28       ` Anup Patel
2022-01-08  6:35   ` Frank Chang
2022-01-08  6:35     ` Frank Chang
2022-01-08 12:00     ` Anup Patel
2022-01-08 12:00       ` Anup Patel
2022-01-14 12:02   ` Frank Chang
2022-01-14 12:02     ` Frank Chang
2022-01-14 12:59     ` Anup Patel
2022-01-14 12:59       ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 19/23] hw/riscv: virt: Add optional AIA APLIC support to virt machine Anup Patel
2021-12-30 12:35   ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 20/23] hw/intc: Add RISC-V AIA IMSIC device emulation Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-13  7:26   ` Frank Chang
2022-01-13  7:26     ` Frank Chang
2022-01-13 12:22     ` Anup Patel
2022-01-13 12:22       ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 21/23] hw/riscv: virt: Add optional AIA IMSIC support to virt machine Anup Patel
2021-12-30 12:35   ` Anup Patel
2021-12-30 12:35 ` [PATCH v6 22/23] docs/system: riscv: Document AIA options for " Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-12 13:23   ` Frank Chang
2022-01-12 13:23     ` Frank Chang
2021-12-30 12:35 ` [PATCH v6 23/23] hw/riscv: virt: Increase maximum number of allowed CPUs Anup Patel
2021-12-30 12:35   ` Anup Patel
2022-01-05 21:50   ` Alistair Francis
2022-01-05 21:50     ` Alistair Francis
2022-01-12 13:26   ` Frank Chang
2022-01-12 13:26     ` Frank Chang

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=CAE_xrPiatQhRZ+EOq+6BumPEA87jgzTZChT9Qn0Pp_wxN690LQ@mail.gmail.com \
    --to=frank.chang@sifive.com \
    --cc=Alistair.Francis@wdc.com \
    --cc=anup@brainfault.org \
    --cc=atishp@atishpatra.org \
    --cc=bmeng.cn@gmail.com \
    --cc=palmer@dabbelt.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=sagark@eecs.berkeley.edu \
    /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.