diff mbox series

[RFC,v2,4/6] hw/arm: Changes required to accommodate non-contiguous DT mem nodes

Message ID 20180516152026.2920-5-shameerali.kolothum.thodi@huawei.com
State New
Headers show
Series hw/arm: Add support for non-contiguous iova regions | expand

Commit Message

Shameerali Kolothum Thodi May 16, 2018, 3:20 p.m. UTC
This makes changes to the DT mem node creation such that its easier
to add non-contiguous mem modeled as non-pluggable and a pc-dimm
mem later.

Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>

---
 hw/arm/boot.c        | 91 ++++++++++++++++++++++++++++++++++++----------------
 include/hw/arm/arm.h | 12 +++++++
 2 files changed, 75 insertions(+), 28 deletions(-)

-- 
2.7.4

Comments

Eric Auger May 28, 2018, 2:21 p.m. UTC | #1
Hi Shameer,

On 05/16/2018 05:20 PM, Shameer Kolothum wrote:
> This makes changes to the DT mem node creation such that its easier

> to add non-contiguous mem modeled as non-pluggable and a pc-dimm

> mem later.

See comments below. I think you should augment the description here with
what the patch exactly adds:
- a new helper function
- a new dimm node?

and if possible split functional changes into separate patches?
> 

> Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>

> ---

>  hw/arm/boot.c        | 91 ++++++++++++++++++++++++++++++++++++----------------

>  include/hw/arm/arm.h | 12 +++++++

>  2 files changed, 75 insertions(+), 28 deletions(-)

> 

> diff --git a/hw/arm/boot.c b/hw/arm/boot.c

> index 26184bc..73db0aa 100644

> --- a/hw/arm/boot.c

> +++ b/hw/arm/boot.c

> @@ -486,6 +486,27 @@ static void fdt_add_psci_node(void *fdt)

>      qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);

>  }

>  

> +static char *create_memory_fdt(void *fdt, uint32_t acells, hwaddr mem_base,

> +                                          uint32_t scells, hwaddr mem_len)

Other dt node creation functions are named fdt_add_*_node
> +{

> +    char *nodename = NULL;

> +    int rc;

> +

> +    nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);

> +    qemu_fdt_add_subnode(fdt, nodename);

> +    qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");

> +    rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, mem_base,

> +                                      scells, mem_len);

> +    if (rc < 0) {

> +        fprintf(stderr, "couldn't set %s/reg\n", nodename);

> +        g_free(nodename);

> +        return NULL;

> +    }

> +

> +    return nodename;

> +}

> +

> +

>  /**

>   * load_dtb() - load a device tree binary image into memory

>   * @addr:       the address to load the image at

> @@ -567,50 +588,64 @@ static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,

>          goto fail;

>      }

>  

> +    /*

> +     * Turn the /memory node created before into a NOP node, then create

> +     * /memory@addr nodes for all numa nodes respectively.

> +     */

> +    qemu_fdt_nop_node(fdt, "/memory");

I don't really understand why this gets moved outside of the if
(nb_numa_nodes > 0) { check. Also the comment above mention numa nodes
whereas it are not necessarily in the numa case anymore.
> +

>      if (nb_numa_nodes > 0) {

> -        /*

> -         * Turn the /memory node created before into a NOP node, then create

> -         * /memory@addr nodes for all numa nodes respectively.

> -         */

> -        qemu_fdt_nop_node(fdt, "/memory");

> +        hwaddr mem_sz;

> +

>          mem_base = binfo->loader_start;

> +        mem_sz = binfo->ram_size;

>          for (i = 0; i < nb_numa_nodes; i++) {

> -            mem_len = numa_info[i].node_mem;

> -            nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);

> -            qemu_fdt_add_subnode(fdt, nodename);

> -            qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");

> -            rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",

> -                                              acells, mem_base,

> +            mem_len = MIN(numa_info[i].node_mem, mem_sz);

I fail to understand how this change relates to the topic of this patch.
If this adds a consistency check, this may be put in another patch?
> +

> +            nodename = create_memory_fdt(fdt, acells, mem_base,

>                                                scells, mem_len);

You could simplify the review by just introducing the new dt node
creation function in a 1st patch and then introduce the changes to
support non contiguous DT mem nodes.
> -            if (rc < 0) {

> -                fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename,

> -                        i);

> +            if (!nodename) {

>                  goto fail;

>              }

>  

>              qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i);

> -            mem_base += mem_len;

>              g_free(nodename);

> +            mem_base += mem_len;

> +            mem_sz -= mem_len;

> +            if (!mem_sz) {

> +                break;

So what does it mean practically if we break here. Not all the num nodes
will function? Outputting a mesg for the end user may be useful.
> +           }

>          }

> -    } else {

> -        Error *err = NULL;

>  

> -        rc = fdt_path_offset(fdt, "/memory");

> -        if (rc < 0) {

> -            qemu_fdt_add_subnode(fdt, "/memory");

> -        }

> +        /* Create the node for initial pc-dimm ram, if any */

> +        if (binfo->dimm_mem) {

>  

> -        if (!qemu_fdt_getprop(fdt, "/memory", "device_type", NULL, &err)) {

> -            qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");

> +            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem->base,

> +                                              scells, binfo->dimm_mem->size);

> +            if (!nodename) {

> +                goto fail;

> +            }

> +            qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id",

> +                                                 binfo->dimm_mem->node);

> +            g_free(nodename);

>          }

>  

> -        rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",

> -                                          acells, binfo->loader_start,

> -                                          scells, binfo->ram_size);

> -        if (rc < 0) {

> -            fprintf(stderr, "couldn't set /memory/reg\n");

> +    } else {

> +

> +        nodename = create_memory_fdt(fdt, acells, binfo->loader_start,

> +                                         scells, binfo->ram_size);

> +        if (!nodename) {

>              goto fail;

>          }

> +

> +        if (binfo->dimm_mem) {

> +            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem->base,

> +                                              scells, binfo->dimm_mem->size);

> +            if (!nodename) {

> +                goto fail;

> +            }

> +            g_free(nodename);

> +        }

as this code gets duplicated, a helper function may be relevant?

Thanks

Eric
>      }

>  

>      rc = fdt_path_offset(fdt, "/chosen");

> diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h

> index ce769bd..0ee3b4e 100644

> --- a/include/hw/arm/arm.h

> +++ b/include/hw/arm/arm.h

> @@ -48,6 +48,12 @@ typedef struct {

>      ARMCPU *cpu; /* handle to the first cpu object */

>  } ArmLoadKernelNotifier;

>  

> +struct dimm_mem_info {

> +    int node;

> +    hwaddr base;

> +    hwaddr size;

> +};

> +

>  /* arm_boot.c */

>  struct arm_boot_info {

>      uint64_t ram_size;

> @@ -124,6 +130,12 @@ struct arm_boot_info {

>      bool secure_board_setup;

>  

>      arm_endianness endianness;

> +

> +    /* This is used to model a pc-dimm based mem if the valid iova region

> +     * is non-contiguous.

> +     */

> +    struct dimm_mem_info *dimm_mem;

> +

>  };

>  

>  /**

>
Shameerali Kolothum Thodi May 30, 2018, 2:46 p.m. UTC | #2
Hi Eric,

> -----Original Message-----

> From: Auger Eric [mailto:eric.auger@redhat.com]

> Sent: Monday, May 28, 2018 3:22 PM

> To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>;

> qemu-devel@nongnu.org; qemu-arm@nongnu.org

> Cc: peter.maydell@linaro.org; drjones@redhat.com; Jonathan Cameron

> <jonathan.cameron@huawei.com>; Linuxarm <linuxarm@huawei.com>;

> alex.williamson@redhat.com; Zhaoshenglong <zhaoshenglong@huawei.com>;

> imammedo@redhat.com

> Subject: Re: [Qemu-devel] [RFC v2 4/6] hw/arm: Changes required to

> accommodate non-contiguous DT mem nodes

> 

> Hi Shameer,

> 

> On 05/16/2018 05:20 PM, Shameer Kolothum wrote:

> > This makes changes to the DT mem node creation such that its easier

> > to add non-contiguous mem modeled as non-pluggable and a pc-dimm

> > mem later.

> See comments below. I think you should augment the description here with

> what the patch exactly adds:

> - a new helper function

> - a new dimm node?

> 

> and if possible split functional changes into separate patches?


Agree. It is better to split this.

> > Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>

> > ---

> >  hw/arm/boot.c        | 91 ++++++++++++++++++++++++++++++++++++----------

> ------

> >  include/hw/arm/arm.h | 12 +++++++

> >  2 files changed, 75 insertions(+), 28 deletions(-)

> >

> > diff --git a/hw/arm/boot.c b/hw/arm/boot.c

> > index 26184bc..73db0aa 100644

> > --- a/hw/arm/boot.c

> > +++ b/hw/arm/boot.c

> > @@ -486,6 +486,27 @@ static void fdt_add_psci_node(void *fdt)

> >      qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);

> >  }

> >

> > +static char *create_memory_fdt(void *fdt, uint32_t acells, hwaddr

> mem_base,

> > +                                          uint32_t scells, hwaddr mem_len)

> Other dt node creation functions are named fdt_add_*_node


Ok.

> > +{

> > +    char *nodename = NULL;

> > +    int rc;

> > +

> > +    nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);

> > +    qemu_fdt_add_subnode(fdt, nodename);

> > +    qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");

> > +    rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells,

> mem_base,

> > +                                      scells, mem_len);

> > +    if (rc < 0) {

> > +        fprintf(stderr, "couldn't set %s/reg\n", nodename);

> > +        g_free(nodename);

> > +        return NULL;

> > +    }

> > +

> > +    return nodename;

> > +}

> > +

> > +

> >  /**

> >   * load_dtb() - load a device tree binary image into memory

> >   * @addr:       the address to load the image at

> > @@ -567,50 +588,64 @@ static int load_dtb(hwaddr addr, const struct

> arm_boot_info *binfo,

> >          goto fail;

> >      }

> >

> > +    /*

> > +     * Turn the /memory node created before into a NOP node, then create

> > +     * /memory@addr nodes for all numa nodes respectively.

> > +     */

> > +    qemu_fdt_nop_node(fdt, "/memory");

> I don't really understand why this gets moved outside of the if

> (nb_numa_nodes > 0) { check. Also the comment above mention numa nodes

> whereas it are not necessarily in the numa case anymore.


Hmm..I think this is because virt.c has a create_fdt() where "/memory " subnode
is created. May be I can keep that and update with non-plug mem and create a new
"/memory @" for pc-dimm case. I will double check.

> > +

> >      if (nb_numa_nodes > 0) {

> > -        /*

> > -         * Turn the /memory node created before into a NOP node, then create

> > -         * /memory@addr nodes for all numa nodes respectively.

> > -         */

> > -        qemu_fdt_nop_node(fdt, "/memory");

> > +        hwaddr mem_sz;

> > +

> >          mem_base = binfo->loader_start;

> > +        mem_sz = binfo->ram_size;

> >          for (i = 0; i < nb_numa_nodes; i++) {

> > -            mem_len = numa_info[i].node_mem;

> > -            nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);

> > -            qemu_fdt_add_subnode(fdt, nodename);

> > -            qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");

> > -            rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",

> > -                                              acells, mem_base,

> > +            mem_len = MIN(numa_info[i].node_mem, mem_sz);

> I fail to understand how this change relates to the topic of this patch.

> If this adds a consistency check, this may be put in another patch?


Yes. It is not related to this patch per se. But without this and some of the 
related mem_len/ mem_sz  changes below it will end up creating more num
of memory nodes as the numa mem info is populated much earlier than we
modify the ram_size(non-plug) info. I can move this and your related comment
for acpi patch (5/6) to a separate patch.

> > +

> > +            nodename = create_memory_fdt(fdt, acells, mem_base,

> >                                                scells, mem_len);

> You could simplify the review by just introducing the new dt node

> creation function in a 1st patch and then introduce the changes to

> support non contiguous DT mem nodes.


Ok. I will split.

> > -            if (rc < 0) {

> > -                fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename,

> > -                        i);

> > +            if (!nodename) {

> >                  goto fail;

> >              }

> >

> >              qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i);

> > -            mem_base += mem_len;

> >              g_free(nodename);

> > +            mem_base += mem_len;

> > +            mem_sz -= mem_len;

> > +            if (!mem_sz) {

> > +                break;

> So what does it mean practically if we break here. Not all the num nodes

> will function? Outputting a mesg for the end user may be useful.


The break here means we have populated mem nodes for non-plug ram case
and the remaining mem(if any) will be based on the pc-dimm case. Yes, it 
is possible that Guest kernel will report memory-less numa nodes. I will add
a msg here.

> > +           }

> >          }

> > -    } else {

> > -        Error *err = NULL;

> >

> > -        rc = fdt_path_offset(fdt, "/memory");

> > -        if (rc < 0) {

> > -            qemu_fdt_add_subnode(fdt, "/memory");

> > -        }

> > +        /* Create the node for initial pc-dimm ram, if any */

> > +        if (binfo->dimm_mem) {

> >

> > -        if (!qemu_fdt_getprop(fdt, "/memory", "device_type", NULL, &err)) {

> > -            qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");

> > +            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem-

> >base,

> > +                                              scells, binfo->dimm_mem->size);

> > +            if (!nodename) {

> > +                goto fail;

> > +            }

> > +            qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id",

> > +                                                 binfo->dimm_mem->node);

> > +            g_free(nodename);

> >          }

> >

> > -        rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",

> > -                                          acells, binfo->loader_start,

> > -                                          scells, binfo->ram_size);

> > -        if (rc < 0) {

> > -            fprintf(stderr, "couldn't set /memory/reg\n");

> > +    } else {

> > +

> > +        nodename = create_memory_fdt(fdt, acells, binfo->loader_start,

> > +                                         scells, binfo->ram_size);

> > +        if (!nodename) {

> >              goto fail;

> >          }

> > +

> > +        if (binfo->dimm_mem) {

> > +            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem-

> >base,

> > +                                              scells, binfo->dimm_mem->size);

> > +            if (!nodename) {

> > +                goto fail;

> > +            }

> > +            g_free(nodename);

> > +        }

> as this code gets duplicated, a helper function may be relevant?


Ok.

Thanks,
Shameer

> Thanks

> 

> Eric

> >      }

> >

> >      rc = fdt_path_offset(fdt, "/chosen");

> > diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h

> > index ce769bd..0ee3b4e 100644

> > --- a/include/hw/arm/arm.h

> > +++ b/include/hw/arm/arm.h

> > @@ -48,6 +48,12 @@ typedef struct {

> >      ARMCPU *cpu; /* handle to the first cpu object */

> >  } ArmLoadKernelNotifier;

> >

> > +struct dimm_mem_info {

> > +    int node;

> > +    hwaddr base;

> > +    hwaddr size;

> > +};

> > +

> >  /* arm_boot.c */

> >  struct arm_boot_info {

> >      uint64_t ram_size;

> > @@ -124,6 +130,12 @@ struct arm_boot_info {

> >      bool secure_board_setup;

> >

> >      arm_endianness endianness;

> > +

> > +    /* This is used to model a pc-dimm based mem if the valid iova region

> > +     * is non-contiguous.

> > +     */

> > +    struct dimm_mem_info *dimm_mem;

> > +

> >  };

> >

> >  /**

> >
diff mbox series

Patch

diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 26184bc..73db0aa 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -486,6 +486,27 @@  static void fdt_add_psci_node(void *fdt)
     qemu_fdt_setprop_cell(fdt, "/psci", "migrate", migrate_fn);
 }
 
+static char *create_memory_fdt(void *fdt, uint32_t acells, hwaddr mem_base,
+                                          uint32_t scells, hwaddr mem_len)
+{
+    char *nodename = NULL;
+    int rc;
+
+    nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
+    qemu_fdt_add_subnode(fdt, nodename);
+    qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
+    rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, mem_base,
+                                      scells, mem_len);
+    if (rc < 0) {
+        fprintf(stderr, "couldn't set %s/reg\n", nodename);
+        g_free(nodename);
+        return NULL;
+    }
+
+    return nodename;
+}
+
+
 /**
  * load_dtb() - load a device tree binary image into memory
  * @addr:       the address to load the image at
@@ -567,50 +588,64 @@  static int load_dtb(hwaddr addr, const struct arm_boot_info *binfo,
         goto fail;
     }
 
+    /*
+     * Turn the /memory node created before into a NOP node, then create
+     * /memory@addr nodes for all numa nodes respectively.
+     */
+    qemu_fdt_nop_node(fdt, "/memory");
+
     if (nb_numa_nodes > 0) {
-        /*
-         * Turn the /memory node created before into a NOP node, then create
-         * /memory@addr nodes for all numa nodes respectively.
-         */
-        qemu_fdt_nop_node(fdt, "/memory");
+        hwaddr mem_sz;
+
         mem_base = binfo->loader_start;
+        mem_sz = binfo->ram_size;
         for (i = 0; i < nb_numa_nodes; i++) {
-            mem_len = numa_info[i].node_mem;
-            nodename = g_strdup_printf("/memory@%" PRIx64, mem_base);
-            qemu_fdt_add_subnode(fdt, nodename);
-            qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
-            rc = qemu_fdt_setprop_sized_cells(fdt, nodename, "reg",
-                                              acells, mem_base,
+            mem_len = MIN(numa_info[i].node_mem, mem_sz);
+
+            nodename = create_memory_fdt(fdt, acells, mem_base,
                                               scells, mem_len);
-            if (rc < 0) {
-                fprintf(stderr, "couldn't set %s/reg for node %d\n", nodename,
-                        i);
+            if (!nodename) {
                 goto fail;
             }
 
             qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id", i);
-            mem_base += mem_len;
             g_free(nodename);
+            mem_base += mem_len;
+            mem_sz -= mem_len;
+            if (!mem_sz) {
+                break;
+           }
         }
-    } else {
-        Error *err = NULL;
 
-        rc = fdt_path_offset(fdt, "/memory");
-        if (rc < 0) {
-            qemu_fdt_add_subnode(fdt, "/memory");
-        }
+        /* Create the node for initial pc-dimm ram, if any */
+        if (binfo->dimm_mem) {
 
-        if (!qemu_fdt_getprop(fdt, "/memory", "device_type", NULL, &err)) {
-            qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
+            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem->base,
+                                              scells, binfo->dimm_mem->size);
+            if (!nodename) {
+                goto fail;
+            }
+            qemu_fdt_setprop_cell(fdt, nodename, "numa-node-id",
+                                                 binfo->dimm_mem->node);
+            g_free(nodename);
         }
 
-        rc = qemu_fdt_setprop_sized_cells(fdt, "/memory", "reg",
-                                          acells, binfo->loader_start,
-                                          scells, binfo->ram_size);
-        if (rc < 0) {
-            fprintf(stderr, "couldn't set /memory/reg\n");
+    } else {
+
+        nodename = create_memory_fdt(fdt, acells, binfo->loader_start,
+                                         scells, binfo->ram_size);
+        if (!nodename) {
             goto fail;
         }
+
+        if (binfo->dimm_mem) {
+            nodename = create_memory_fdt(fdt, acells, binfo->dimm_mem->base,
+                                              scells, binfo->dimm_mem->size);
+            if (!nodename) {
+                goto fail;
+            }
+            g_free(nodename);
+        }
     }
 
     rc = fdt_path_offset(fdt, "/chosen");
diff --git a/include/hw/arm/arm.h b/include/hw/arm/arm.h
index ce769bd..0ee3b4e 100644
--- a/include/hw/arm/arm.h
+++ b/include/hw/arm/arm.h
@@ -48,6 +48,12 @@  typedef struct {
     ARMCPU *cpu; /* handle to the first cpu object */
 } ArmLoadKernelNotifier;
 
+struct dimm_mem_info {
+    int node;
+    hwaddr base;
+    hwaddr size;
+};
+
 /* arm_boot.c */
 struct arm_boot_info {
     uint64_t ram_size;
@@ -124,6 +130,12 @@  struct arm_boot_info {
     bool secure_board_setup;
 
     arm_endianness endianness;
+
+    /* This is used to model a pc-dimm based mem if the valid iova region
+     * is non-contiguous.
+     */
+    struct dimm_mem_info *dimm_mem;
+
 };
 
 /**