[PATCH v5] target/riscv: Add isa extenstion strings to the device tree

Atish Patra posted 1 patch 2 years, 1 month ago
Test checkpatch passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20220314234250.846613-1-atishp@rivosinc.com
Maintainers: Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Bin Meng <bin.meng@windriver.com>
There is a newer version of this series
target/riscv/cpu.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 61 insertions(+)
[PATCH v5] target/riscv: Add isa extenstion strings to the device tree
Posted by Atish Patra 2 years, 1 month ago
The Linux kernel parses the ISA extensions from "riscv,isa" DT
property. It used to parse only the single letter base extensions
until now. A generic ISA extension parsing framework was proposed[1]
recently that can parse multi-letter ISA extensions as well.

Generate the extended ISA string by appending  the available ISA extensions
to the "riscv,isa" string if it is enabled so that kernel can process it.

[1] https://lkml.org/lkml/2022/2/15/263

Reviewed-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Suggested-by: Heiko Stubner <heiko@sntech.de>
Signed-off-by: Atish Patra <atishp@rivosinc.com>
---
Changes from v4->v5:
1. Fixed the order of Zxx extensions.
2. Added a comment clearly describing the rules of extension order.

Changes from v3->v4:
1. Fixed the order of the extension names.
2. Added all the available ISA extensions in Qemu.

Changes from v2->v3:
1. Used g_strconcat to replace snprintf & a max isa string length as
suggested by Anup.
2. I have not included the Tested-by Tag from Heiko because the
implementation changed from v2 to v3.

Changes from v1->v2:
1. Improved the code redability by using arrays instead of individual check
---
 target/riscv/cpu.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index ddda4906ffb7..097c42f5c50f 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -34,6 +34,12 @@
 
 /* RISC-V CPU definitions */
 
+/* This includes the null terminated character '\0' */
+struct isa_ext_data {
+        const char *name;
+        bool enabled;
+};
+
 static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
 
 const char * const riscv_int_regnames[] = {
@@ -898,6 +904,60 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
     device_class_set_props(dc, riscv_cpu_properties);
 }
 
+#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop}
+
+static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len)
+{
+    char *old = *isa_str;
+    char *new = *isa_str;
+    int i;
+
+    /**
+     * Here are the ordering rules of extension naming defined by RISC-V
+     * specification :
+     * 1. All extensions should be separated from other multi-letter extensions
+     *    from other multi-letter extensions by an underscore.
+     * 2. The first letter following the 'Z' conventionally indicates the most
+     *    closely related alphabetical extension category, IMAFDQLCBKJTPVH.
+     *    If multiple 'Z' extensions are named, they should be ordered first
+     *    by category, then alphabetically within a category.
+     * 3. Standard supervisor-level extensions (starts with 'S') should be
+     *    listed after standard unprivileged extensions.  If multiple
+     *    supervisor-level extensions are listed, they should be ordered
+     *    alphabetically.
+     * 4. Non-standard extensions (starts with 'X') must be listed after all
+     *    standard extensions. They must be separated from other multi-letter
+     *    extensions by an underscore.
+     */
+    struct isa_ext_data isa_edata_arr[] = {
+        ISA_EDATA_ENTRY(zfh, ext_zfhmin),
+        ISA_EDATA_ENTRY(zfhmin, ext_zfhmin),
+        ISA_EDATA_ENTRY(zfinx, ext_zfinx),
+        ISA_EDATA_ENTRY(zdinx, ext_zdinx),
+        ISA_EDATA_ENTRY(zba, ext_zba),
+        ISA_EDATA_ENTRY(zbb, ext_zbb),
+        ISA_EDATA_ENTRY(zbc, ext_zbc),
+        ISA_EDATA_ENTRY(zbs, ext_zbs),
+        ISA_EDATA_ENTRY(zve32f, ext_zve32f),
+        ISA_EDATA_ENTRY(zve64f, ext_zve64f),
+        ISA_EDATA_ENTRY(zhinx, ext_zhinx),
+        ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin),
+        ISA_EDATA_ENTRY(svinval, ext_svinval),
+        ISA_EDATA_ENTRY(svnapot, ext_svnapot),
+        ISA_EDATA_ENTRY(svpbmt, ext_svpbmt),
+    };
+
+    for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
+        if (isa_edata_arr[i].enabled) {
+            new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL);
+            g_free(old);
+            old = new;
+        }
+    }
+
+    *isa_str = new;
+}
+
 char *riscv_isa_string(RISCVCPU *cpu)
 {
     int i;
@@ -910,6 +970,7 @@ char *riscv_isa_string(RISCVCPU *cpu)
         }
     }
     *p = '\0';
+    riscv_isa_string_ext(cpu, &isa_str, maxlen);
     return isa_str;
 }
 
-- 
2.30.2
Re: [PATCH v5] target/riscv: Add isa extenstion strings to the device tree
Posted by Bin Meng 2 years, 1 month ago
On Tue, Mar 15, 2022 at 7:43 AM Atish Patra <atishp@rivosinc.com> wrote:
>
> The Linux kernel parses the ISA extensions from "riscv,isa" DT
> property. It used to parse only the single letter base extensions
> until now. A generic ISA extension parsing framework was proposed[1]
> recently that can parse multi-letter ISA extensions as well.
>
> Generate the extended ISA string by appending  the available ISA extensions

nits: remove one space after "appending"

> to the "riscv,isa" string if it is enabled so that kernel can process it.
>
> [1] https://lkml.org/lkml/2022/2/15/263

Could you please post a link to the "riscv,isa" DT bindings spec or
discussion thread? It seems not mentioned in the above LKML thread.

>
> Reviewed-by: Anup Patel <anup@brainfault.org>
> Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> Suggested-by: Heiko Stubner <heiko@sntech.de>
> Signed-off-by: Atish Patra <atishp@rivosinc.com>
> ---
> Changes from v4->v5:
> 1. Fixed the order of Zxx extensions.
> 2. Added a comment clearly describing the rules of extension order.
>
> Changes from v3->v4:
> 1. Fixed the order of the extension names.
> 2. Added all the available ISA extensions in Qemu.
>
> Changes from v2->v3:
> 1. Used g_strconcat to replace snprintf & a max isa string length as
> suggested by Anup.
> 2. I have not included the Tested-by Tag from Heiko because the
> implementation changed from v2 to v3.
>
> Changes from v1->v2:
> 1. Improved the code redability by using arrays instead of individual check
> ---
>  target/riscv/cpu.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 61 insertions(+)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index ddda4906ffb7..097c42f5c50f 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -34,6 +34,12 @@
>
>  /* RISC-V CPU definitions */
>
> +/* This includes the null terminated character '\0' */
> +struct isa_ext_data {
> +        const char *name;
> +        bool enabled;
> +};
> +
>  static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
>
>  const char * const riscv_int_regnames[] = {
> @@ -898,6 +904,60 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
>      device_class_set_props(dc, riscv_cpu_properties);
>  }
>
> +#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop}
> +
> +static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len)
> +{
> +    char *old = *isa_str;
> +    char *new = *isa_str;
> +    int i;
> +
> +    /**
> +     * Here are the ordering rules of extension naming defined by RISC-V
> +     * specification :
> +     * 1. All extensions should be separated from other multi-letter extensions
> +     *    from other multi-letter extensions by an underscore.

redundant "from other multi-letter extensions"

> +     * 2. The first letter following the 'Z' conventionally indicates the most

Should this be lower case "z"?

> +     *    closely related alphabetical extension category, IMAFDQLCBKJTPVH.
> +     *    If multiple 'Z' extensions are named, they should be ordered first
> +     *    by category, then alphabetically within a category.
> +     * 3. Standard supervisor-level extensions (starts with 'S') should be

lower case "s"?

> +     *    listed after standard unprivileged extensions.  If multiple
> +     *    supervisor-level extensions are listed, they should be ordered
> +     *    alphabetically.
> +     * 4. Non-standard extensions (starts with 'X') must be listed after all
> +     *    standard extensions. They must be separated from other multi-letter
> +     *    extensions by an underscore.
> +     */
> +    struct isa_ext_data isa_edata_arr[] = {
> +        ISA_EDATA_ENTRY(zfh, ext_zfhmin),

This should be (zfh, ext_zfh)

> +        ISA_EDATA_ENTRY(zfhmin, ext_zfhmin),
> +        ISA_EDATA_ENTRY(zfinx, ext_zfinx),
> +        ISA_EDATA_ENTRY(zdinx, ext_zdinx),

Should "zdinx" come before "zfinx" *alphabetically* ?

> +        ISA_EDATA_ENTRY(zba, ext_zba),
> +        ISA_EDATA_ENTRY(zbb, ext_zbb),
> +        ISA_EDATA_ENTRY(zbc, ext_zbc),
> +        ISA_EDATA_ENTRY(zbs, ext_zbs),

I don't understand why "zb*" come after "zf*". Alphabetically they
should come before.

> +        ISA_EDATA_ENTRY(zve32f, ext_zve32f),
> +        ISA_EDATA_ENTRY(zve64f, ext_zve64f),
> +        ISA_EDATA_ENTRY(zhinx, ext_zhinx),
> +        ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin),
> +        ISA_EDATA_ENTRY(svinval, ext_svinval),
> +        ISA_EDATA_ENTRY(svnapot, ext_svnapot),
> +        ISA_EDATA_ENTRY(svpbmt, ext_svpbmt),
> +    };
> +
> +    for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
> +        if (isa_edata_arr[i].enabled) {
> +            new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL);
> +            g_free(old);
> +            old = new;
> +        }
> +    }
> +
> +    *isa_str = new;
> +}
> +
>  char *riscv_isa_string(RISCVCPU *cpu)
>  {
>      int i;
> @@ -910,6 +970,7 @@ char *riscv_isa_string(RISCVCPU *cpu)
>          }
>      }
>      *p = '\0';
> +    riscv_isa_string_ext(cpu, &isa_str, maxlen);
>      return isa_str;
>  }
>

Regards,
Bin
Re: [PATCH v5] target/riscv: Add isa extenstion strings to the device tree
Posted by Atish Kumar Patra 2 years, 1 month ago
On Tue, Mar 15, 2022 at 2:17 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Tue, Mar 15, 2022 at 7:43 AM Atish Patra <atishp@rivosinc.com> wrote:
> >
> > The Linux kernel parses the ISA extensions from "riscv,isa" DT
> > property. It used to parse only the single letter base extensions
> > until now. A generic ISA extension parsing framework was proposed[1]
> > recently that can parse multi-letter ISA extensions as well.
> >
> > Generate the extended ISA string by appending  the available ISA extensions
>
> nits: remove one space after "appending"
>

Will fix it.

> > to the "riscv,isa" string if it is enabled so that kernel can process it.
> >
> > [1] https://lkml.org/lkml/2022/2/15/263
>
> Could you please post a link to the "riscv,isa" DT bindings spec or
> discussion thread? It seems not mentioned in the above LKML thread.
>

Latest discussion on the discussion:
https://lkml.org/lkml/2022/3/10/1416

riscv,isa DT binding:
https://elixir.bootlin.com/linux/v5.17-rc8/source/Documentation/devicetree/bindings/riscv/cpus.yaml#L66

> >
> > Reviewed-by: Anup Patel <anup@brainfault.org>
> > Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
> > Suggested-by: Heiko Stubner <heiko@sntech.de>
> > Signed-off-by: Atish Patra <atishp@rivosinc.com>
> > ---
> > Changes from v4->v5:
> > 1. Fixed the order of Zxx extensions.
> > 2. Added a comment clearly describing the rules of extension order.
> >
> > Changes from v3->v4:
> > 1. Fixed the order of the extension names.
> > 2. Added all the available ISA extensions in Qemu.
> >
> > Changes from v2->v3:
> > 1. Used g_strconcat to replace snprintf & a max isa string length as
> > suggested by Anup.
> > 2. I have not included the Tested-by Tag from Heiko because the
> > implementation changed from v2 to v3.
> >
> > Changes from v1->v2:
> > 1. Improved the code redability by using arrays instead of individual check
> > ---
> >  target/riscv/cpu.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 61 insertions(+)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index ddda4906ffb7..097c42f5c50f 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -34,6 +34,12 @@
> >
> >  /* RISC-V CPU definitions */
> >
> > +/* This includes the null terminated character '\0' */
> > +struct isa_ext_data {
> > +        const char *name;
> > +        bool enabled;
> > +};
> > +
> >  static const char riscv_exts[26] = "IEMAFDQCLBJTPVNSUHKORWXYZG";
> >
> >  const char * const riscv_int_regnames[] = {
> > @@ -898,6 +904,60 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
> >      device_class_set_props(dc, riscv_cpu_properties);
> >  }
> >
> > +#define ISA_EDATA_ENTRY(name, prop) {#name, cpu->cfg.prop}
> > +
> > +static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, int max_str_len)
> > +{
> > +    char *old = *isa_str;
> > +    char *new = *isa_str;
> > +    int i;
> > +
> > +    /**
> > +     * Here are the ordering rules of extension naming defined by RISC-V
> > +     * specification :
> > +     * 1. All extensions should be separated from other multi-letter extensions
> > +     *    from other multi-letter extensions by an underscore.
>
> redundant "from other multi-letter extensions"
>

Oops. Will fix it.

> > +     * 2. The first letter following the 'Z' conventionally indicates the most
>
> Should this be lower case "z"?

Nope. I am just iterating the rules defined by the spec. The device
tree has lower case 'z'
as per the device binding which mandates all lower case.

>
> > +     *    closely related alphabetical extension category, IMAFDQLCBKJTPVH.
> > +     *    If multiple 'Z' extensions are named, they should be ordered first
> > +     *    by category, then alphabetically within a category.
> > +     * 3. Standard supervisor-level extensions (starts with 'S') should be
>
> lower case "s"?

Same reasoning as above.

>
> > +     *    listed after standard unprivileged extensions.  If multiple
> > +     *    supervisor-level extensions are listed, they should be ordered
> > +     *    alphabetically.
> > +     * 4. Non-standard extensions (starts with 'X') must be listed after all
> > +     *    standard extensions. They must be separated from other multi-letter
> > +     *    extensions by an underscore.
> > +     */
> > +    struct isa_ext_data isa_edata_arr[] = {
> > +        ISA_EDATA_ENTRY(zfh, ext_zfhmin),
>
> This should be (zfh, ext_zfh)

Yeah. It's a typo. Thanks for catching it.

>
> > +        ISA_EDATA_ENTRY(zfhmin, ext_zfhmin),
> > +        ISA_EDATA_ENTRY(zfinx, ext_zfinx),
> > +        ISA_EDATA_ENTRY(zdinx, ext_zdinx),
>
> Should "zdinx" come before "zfinx" *alphabetically* ?

As per the ISA naming rules,

"The first letter following the 'Z' conventionally indicates the most
closely related alphabetical extension category, IMAFDQLCBKJTPVH.
If multiple 'Z' extensions are named, they should be ordered first
by category, then alphabetically within a category."

That's why, zfinx comes before zdinx.
>
> > +        ISA_EDATA_ENTRY(zba, ext_zba),
> > +        ISA_EDATA_ENTRY(zbb, ext_zbb),
> > +        ISA_EDATA_ENTRY(zbc, ext_zbc),
> > +        ISA_EDATA_ENTRY(zbs, ext_zbs),
>
> I don't understand why "zb*" come after "zf*". Alphabetically they
> should come before.
>

Same reasoning as above. But for one category, they are ordered alphabetically.
That's why you see ext_zba, ext_zbb, ext_zbc, ext_zbs in alphabetical order.

> > +        ISA_EDATA_ENTRY(zve32f, ext_zve32f),
> > +        ISA_EDATA_ENTRY(zve64f, ext_zve64f),
> > +        ISA_EDATA_ENTRY(zhinx, ext_zhinx),
> > +        ISA_EDATA_ENTRY(zhinxmin, ext_zhinxmin),
> > +        ISA_EDATA_ENTRY(svinval, ext_svinval),
> > +        ISA_EDATA_ENTRY(svnapot, ext_svnapot),
> > +        ISA_EDATA_ENTRY(svpbmt, ext_svpbmt),
> > +    };
> > +
> > +    for (i = 0; i < ARRAY_SIZE(isa_edata_arr); i++) {
> > +        if (isa_edata_arr[i].enabled) {
> > +            new = g_strconcat(old, "_", isa_edata_arr[i].name, NULL);
> > +            g_free(old);
> > +            old = new;
> > +        }
> > +    }
> > +
> > +    *isa_str = new;
> > +}
> > +
> >  char *riscv_isa_string(RISCVCPU *cpu)
> >  {
> >      int i;
> > @@ -910,6 +970,7 @@ char *riscv_isa_string(RISCVCPU *cpu)
> >          }
> >      }
> >      *p = '\0';
> > +    riscv_isa_string_ext(cpu, &isa_str, maxlen);
> >      return isa_str;
> >  }
> >
>
> Regards,
> Bin