On 13/05/2025 19:14, Jonathan Cameron via wrote:
> Previously these somewhat device like structures were tracked using a list
> in the CXLState in each machine.  This is proving restrictive in a few
> cases where we need to iterate through these without being aware of the
> machine type. Just make them sysbus devices.
Make sense.

Minor comments inline

> 
> Restrict them to not user created as they need to be visible to early
> stages of machine init given effects on the memory map.
> 
> This change both simplifies state tracking and enables features needed
> for performance optimization and hotness tracking by making it possible
> to retrieve the fixed memory window on actions elsewhere in the topology.
> 
> In some cases the ordering of the Fixed Memory Windows matters.
> For those utility functions provide a GSList sorted by the window index.
> This ensures that we get consistency across:
> - ordering in the command line
> - ordering of the host PA ranges
> - ordering of ACPI CEDT structures describing the CFMWS.
> 
> Other aspects don't have this constraint. For those direct iteration
> of the underlying hash structures is fine.
> 
> Signed-off-by: Jonathan Cameron <jonathan.came...@huawei.com>
> ---
> I think Peter Maydell suggested this a long time back when
> the original CXL support series was under review but not 100% sure.
> ---
>   include/hw/cxl/cxl.h      |   3 +
>   include/hw/cxl/cxl_host.h |   4 +-
>   hw/acpi/cxl.c             |  83 +++++++++++--------
>   hw/cxl/cxl-host-stubs.c   |   6 +-
>   hw/cxl/cxl-host.c         | 169 +++++++++++++++++++++++++++++++-------
>   hw/i386/pc.c              |  51 ++++++------
>   6 files changed, 223 insertions(+), 93 deletions(-)
> 
> diff --git a/include/hw/cxl/cxl.h b/include/hw/cxl/cxl.h
> index b2bcce7ed6..a610795c87 100644
> --- a/include/hw/cxl/cxl.h
> +++ b/include/hw/cxl/cxl.h
> @@ -27,6 +27,7 @@
>   typedef struct PXBCXLDev PXBCXLDev;
>   
>   typedef struct CXLFixedWindow {
> +    SysBusDevice parent_obj;
>       int index;
>       uint64_t size;
>       char **targets;
> @@ -38,6 +39,8 @@ typedef struct CXLFixedWindow {
>       MemoryRegion mr;
>       hwaddr base;
>   } CXLFixedWindow;
> +#define TYPE_CXL_FMW "cxl-fmw"
> +OBJECT_DECLARE_SIMPLE_TYPE(CXLFixedWindow, CXL_FMW)
>   
>   typedef struct CXLState {
>       bool is_enabled;
> diff --git a/include/hw/cxl/cxl_host.h b/include/hw/cxl/cxl_host.h
> index c9bc9c7c50..6dce2cde07 100644
> --- a/include/hw/cxl/cxl_host.h
> +++ b/include/hw/cxl/cxl_host.h
> @@ -14,8 +14,10 @@
>   #define CXL_HOST_H
>   
>   void cxl_machine_init(Object *obj, CXLState *state);
> -void cxl_fmws_link_targets(CXLState *stat, Error **errp);
> +void cxl_fmws_link_targets(Error **errp);
>   void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp);
> +hwaddr cxl_fmws_set_memmap_and_update_mmio(hwaddr base, hwaddr max_addr);
> +GSList *cxl_fmws_get_all_sorted(void);
>   
>   extern const MemoryRegionOps cfmws_ops;
>   
> diff --git a/hw/acpi/cxl.c b/hw/acpi/cxl.c
> index 9cd7905ea2..20806e5dd4 100644
> --- a/hw/acpi/cxl.c
> +++ b/hw/acpi/cxl.c
> @@ -22,6 +22,7 @@
>   #include "hw/pci/pci_bridge.h"
>   #include "hw/pci/pci_host.h"
>   #include "hw/cxl/cxl.h"
> +#include "hw/cxl/cxl_host.h"
>   #include "hw/mem/memory-device.h"
>   #include "hw/acpi/acpi.h"
>   #include "hw/acpi/aml-build.h"
> @@ -135,56 +136,62 @@ static void cedt_build_chbs(GArray *table_data, 
> PXBCXLDev *cxl)
>    * Interleave ways encoding in CXL 2.0 ECN: 3, 6, 12 and 16-way memory
>    * interleaving.
>    */
> -static void cedt_build_cfmws(GArray *table_data, CXLState *cxls)
> +static int cedt_build_cfmws(Object *obj, void *opaque)

Too much unrelated indent updates in this function


>   {
> -    GList *it;
> +    struct CXLFixedWindow *fw;
> +    Aml *cedt = opaque;
> +    GArray *table_data = cedt->buf;
> +    int i;
>   
> -    for (it = cxls->fixed_windows; it; it = it->next) {
> -        CXLFixedWindow *fw = it->data;
> -        int i;
> +    if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
> +        return 0;

Never reach here? It seems the caller has ensured passing TYPE_CXL_FMW obj.




> +    }
> +    fw = CXL_FMW(obj);
>   
> -        /* Type */
> -        build_append_int_noprefix(table_data, 1, 1);
> +    /* Type */
> +    build_append_int_noprefix(table_data, 1, 1);
>   
> -        /* Reserved */
> -        build_append_int_noprefix(table_data, 0, 1);
> +    /* Reserved */
> +    build_append_int_noprefix(table_data, 0, 1);
>   
> -        /* Record Length */
> -        build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
> +    /* Record Length */
> +    build_append_int_noprefix(table_data, 36 + 4 * fw->num_targets, 2);
>   
> -        /* Reserved */
> -        build_append_int_noprefix(table_data, 0, 4);
> +    /* Reserved */
> +    build_append_int_noprefix(table_data, 0, 4);
>   
> -        /* Base HPA */
> -        build_append_int_noprefix(table_data, fw->mr.addr, 8);
> +    /* Base HPA */
> +    build_append_int_noprefix(table_data, fw->mr.addr, 8);
>   
> -        /* Window Size */
> -        build_append_int_noprefix(table_data, fw->size, 8);
> +    /* Window Size */
> +    build_append_int_noprefix(table_data, fw->size, 8);
>   
> -        /* Host Bridge Interleave Ways */
> -        build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
> +    /* Host Bridge Interleave Ways */
> +    build_append_int_noprefix(table_data, fw->enc_int_ways, 1);
>   
> -        /* Host Bridge Interleave Arithmetic */
> -        build_append_int_noprefix(table_data, 0, 1);
> +    /* Host Bridge Interleave Arithmetic */
> +    build_append_int_noprefix(table_data, 0, 1);
>   
> -        /* Reserved */
> -        build_append_int_noprefix(table_data, 0, 2);
> +    /* Reserved */
> +    build_append_int_noprefix(table_data, 0, 2);
>   
> -        /* Host Bridge Interleave Granularity */
> -        build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
> +    /* Host Bridge Interleave Granularity */
> +    build_append_int_noprefix(table_data, fw->enc_int_gran, 4);
>   
> -        /* Window Restrictions */
> -        build_append_int_noprefix(table_data, 0x0f, 2); /* No restrictions */
> +    /* Window Restrictions */
> +    build_append_int_noprefix(table_data, 0x0f, 2);
>   
> -        /* QTG ID */
> -        build_append_int_noprefix(table_data, 0, 2);
> +    /* QTG ID */
> +    build_append_int_noprefix(table_data, 0, 2);
>   
> -        /* Host Bridge List (list of UIDs - currently bus_nr) */
> -        for (i = 0; i < fw->num_targets; i++) {
> -            g_assert(fw->target_hbs[i]);
> -            build_append_int_noprefix(table_data, 
> PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
> -        }
> +    /* Host Bridge List (list of UIDs - currently bus_nr) */
> +    for (i = 0; i < fw->num_targets; i++) {
> +        g_assert(fw->target_hbs[i]);
> +        build_append_int_noprefix(table_data,
> +                                  PXB_DEV(fw->target_hbs[i])->bus_nr, 4);
>       }
> +
> +    return 0;
>   }
>   
>   static int cxl_foreach_pxb_hb(Object *obj, void *opaque)
> @@ -202,6 +209,7 @@ void cxl_build_cedt(GArray *table_offsets, GArray 
> *table_data,
>                       BIOSLinker *linker, const char *oem_id,
>                       const char *oem_table_id, CXLState *cxl_state)
>   {
> +    GSList *cfmws_list, *iter;
>       Aml *cedt;
>       AcpiTable table = { .sig = "CEDT", .rev = 1, .oem_id = oem_id,
>                           .oem_table_id = oem_table_id };
> @@ -213,7 +221,12 @@ void cxl_build_cedt(GArray *table_offsets, GArray 
> *table_data,
>       /* reserve space for CEDT header */
>   
>       object_child_foreach_recursive(object_get_root(), cxl_foreach_pxb_hb, 
> cedt);
> -    cedt_build_cfmws(cedt->buf, cxl_state);
> +
> +    cfmws_list = cxl_fmws_get_all_sorted();
> +    for (iter = cfmws_list; iter; iter = iter->next) {
> +        cedt_build_cfmws(iter->data, cedt);
> +    }
> +    g_slist_free(cfmws_list);
>   
>       /* copy AML table into ACPI tables blob and patch header there */
>       g_array_append_vals(table_data, cedt->buf->data, cedt->buf->len);
> diff --git a/hw/cxl/cxl-host-stubs.c b/hw/cxl/cxl-host-stubs.c
> index cae4afcdde..13eb6bf6a4 100644
> --- a/hw/cxl/cxl-host-stubs.c
> +++ b/hw/cxl/cxl-host-stubs.c
> @@ -8,8 +8,12 @@
>   #include "hw/cxl/cxl.h"
>   #include "hw/cxl/cxl_host.h"
>   
> -void cxl_fmws_link_targets(CXLState *stat, Error **errp) {};
> +void cxl_fmws_link_targets(Error **errp) {};
>   void cxl_machine_init(Object *obj, CXLState *state) {};
>   void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState *state, Error **errp) 
> {};
> +hwaddr cxl_fmws_set_memmap_and_update_mmio(hwaddr base, hwaddr max_addr)
> +{
> +    return base;
> +};
>   
>   const MemoryRegionOps cfmws_ops;
> diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c
> index b7aa429ddf..438f2920e1 100644
> --- a/hw/cxl/cxl-host.c
> +++ b/hw/cxl/cxl-host.c
> @@ -22,12 +22,12 @@
>   #include "hw/pci/pcie_port.h"
>   #include "hw/pci-bridge/pci_expander_bridge.h"
>   
> -static void cxl_fixed_memory_window_config(CXLState *cxl_state,
> -                                           CXLFixedMemoryWindowOptions 
> *object,
> +static void cxl_fixed_memory_window_config(CXLFixedMemoryWindowOptions 
> *object,
>                                              int index, Error **errp)
>   {
>       ERRP_GUARD();
> -    g_autofree CXLFixedWindow *fw = g_malloc0(sizeof(*fw));
> +    DeviceState *dev = qdev_new(TYPE_CXL_FMW);
> +    CXLFixedWindow *fw = CXL_FMW(dev);
>       strList *target;
>       int i;
>   
> @@ -67,35 +67,41 @@ static void cxl_fixed_memory_window_config(CXLState 
> *cxl_state,
>           fw->targets[i] = g_strdup(target->value);
>       }
>   
> -    cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows,
> -                                             g_steal_pointer(&fw));
> +    sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), errp);
> +
> +    return;
>   }
>   
> -void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp)
> +static int cxl_fmws_link(Object *obj, void *opaque)
>   {
> -    if (cxl_state && cxl_state->fixed_windows) {
> -        GList *it;
> -
> -        for (it = cxl_state->fixed_windows; it; it = it->next) {
> -            CXLFixedWindow *fw = it->data;
> -            int i;
> -
> -            for (i = 0; i < fw->num_targets; i++) {
> -                Object *o;
> -                bool ambig;
> -
> -                o = object_resolve_path_type(fw->targets[i],
> -                                             TYPE_PXB_CXL_DEV,
> -                                             &ambig);
> -                if (!o) {
> -                    error_setg(errp, "Could not resolve CXLFM target %s",
> -                               fw->targets[i]);
> -                    return;
> -                }
> -                fw->target_hbs[i] = PXB_CXL_DEV(o);
> -            }
> +    struct CXLFixedWindow *fw;
> +    int i;
> +
> +    if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
> +        return 0;
> +    }
> +    fw = CXL_FMW(obj);
> +
> +    for (i = 0; i < fw->num_targets; i++) {
> +        Object *o;
> +        bool ambig;
> +
> +        o = object_resolve_path_type(fw->targets[i], TYPE_PXB_CXL_DEV,
> +                                     &ambig);
> +        if (!o) {
> +            error_setg(&error_fatal, "Could not resolve CXLFM target %s",
> +                       fw->targets[i]);
> +            return 1;
>           }
> +        fw->target_hbs[i] = PXB_CXL_DEV(o);
>       }
> +    return 0;
> +}
> +
> +void cxl_fmws_link_targets(Error **errp)
> +{
> +    /* Order doesn't matter for this, so no need to build list */
> +    object_child_foreach_recursive(object_get_root(), cxl_fmws_link, NULL);
>   }
>   
>   static bool cxl_hdm_find_target(uint32_t *cache_mem, hwaddr addr,
> @@ -335,7 +341,7 @@ static void machine_set_cfmw(Object *obj, Visitor *v, 
> const char *name,
>       }
>   
>       for (it = cfmw_list, index = 0; it; it = it->next, index++) {
> -        cxl_fixed_memory_window_config(state, it->value, index, errp);
> +        cxl_fixed_memory_window_config(it->value, index, errp);
>       }
>       state->cfmw_list = cfmw_list;
>   }
> @@ -373,3 +379,110 @@ void cxl_hook_up_pxb_registers(PCIBus *bus, CXLState 
> *state, Error **errp)
>           }
>       }
>   }
> +
> +struct cfmw_update_state {
> +    hwaddr base;
> +    hwaddr maxaddr;
> +};
> +
> +static void cxl_fmws_update(Object *obj, void *opaque)
> +{
> +    struct CXLFixedWindow *fw;
> +    struct cfmw_update_state *s = opaque;
> +
> +    if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {


Never reach here? It seems the caller has ensured passing TYPE_CXL_FMW obj.


Thanks
Zhijian

> +        return;
> +    }
> +
> +    fw = CXL_FMW(obj);
> +    if (s->base + fw->size <= s->maxaddr) {
> +        fw->base = s->base;
> +        sysbus_mmio_map(SYS_BUS_DEVICE(fw), 0, fw->base);
> +        s->base += fw->size;
> +    }
> +
> +    return;
> +}
> +
> +static int cxl_fmws_find(Object *obj, void *opaque)
> +{
> +    GSList **list = opaque;
> +
> +    if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
> +        return 0;
> +    }
> +    *list = g_slist_prepend(*list, obj);
> +
> +    return 0;
> +}
> +
> +static GSList *cxl_fmws_get_all(void)
> +{
> +    GSList *list = NULL;
> +
> +    object_child_foreach_recursive(object_get_root(), cxl_fmws_find, &list);
> +
> +    return list;
> +}
> +
> +static gint cfmws_cmp(gconstpointer a, gconstpointer b, gpointer d)
> +{
> +    const struct CXLFixedWindow *ap = a;
> +    const struct CXLFixedWindow *bp = b;
> +
> +    return ap->index > bp->index;
> +}
> +
> +GSList *cxl_fmws_get_all_sorted(void)
> +{
> +    return g_slist_sort_with_data(cxl_fmws_get_all(), cfmws_cmp, NULL);
> +}
> +
> +hwaddr cxl_fmws_set_memmap_and_update_mmio(hwaddr base, hwaddr max_addr)
> +{
> +    GSList *cfmws_list, *iter;
> +
> +    struct cfmw_update_state cfmwss = {
> +        .base = base,
> +        .maxaddr = max_addr,
> +    };
> +    cfmws_list = cxl_fmws_get_all_sorted();
> +    for (iter = cfmws_list; iter; iter = iter->next) {
> +        cxl_fmws_update(iter->data, &cfmwss);
> +    }
> +    g_slist_free(cfmws_list);
> +
> +    return cfmwss.base;
> +}
> +
> +static void cxl_fmw_realize(DeviceState *dev, Error **errp)
> +{
> +    CXLFixedWindow *fw = CXL_FMW(dev);
> +
> +    memory_region_init_io(&fw->mr, OBJECT(dev), &cfmws_ops, fw,
> +                          "cxl-fixed-memory-region", fw->size);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &fw->mr);
> +}
> +
> +static void cxl_fmw_class_init(ObjectClass *klass, const void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->desc = "CXL Fixed Memory Window";
> +    dc->realize = cxl_fmw_realize;
> +    /* Reason - created by machines as tightly coupled to machine memory map 
> */
> +    dc->user_creatable = false;
> +}
> +
> +static const TypeInfo cxl_fmw_info = {
> +    .name = TYPE_CXL_FMW,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(CXLFixedWindow),
> +    .class_init = cxl_fmw_class_init,
> +};
> +
> +static void cxl_host_register_types(void)
> +{
> +    type_register_static(&cxl_fmw_info);
> +}
> +type_init(cxl_host_register_types)
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index 70656157ca..9978398876 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -630,7 +630,7 @@ void pc_machine_done(Notifier *notifier, void *data)
>                                 &error_fatal);
>   
>       if (pcms->cxl_devices_state.is_enabled) {
> -        cxl_fmws_link_targets(&pcms->cxl_devices_state, &error_fatal);
> +        cxl_fmws_link_targets(&error_fatal);
>       }
>   
>       /* set the number of CPUs */
> @@ -739,20 +739,28 @@ static uint64_t pc_get_cxl_range_start(PCMachineState 
> *pcms)
>       return cxl_base;
>   }
>   
> -static uint64_t pc_get_cxl_range_end(PCMachineState *pcms)
> +static int cxl_get_fmw_end(Object *obj, void *opaque)
>   {
> -    uint64_t start = pc_get_cxl_range_start(pcms) + MiB;
> +    struct CXLFixedWindow *fw;
> +    uint64_t *start = opaque;
>   
> -    if (pcms->cxl_devices_state.fixed_windows) {
> -        GList *it;
> -
> -        start = ROUND_UP(start, 256 * MiB);
> -        for (it = pcms->cxl_devices_state.fixed_windows; it; it = it->next) {
> -            CXLFixedWindow *fw = it->data;
> -            start += fw->size;
> -        }
> +    if (!object_dynamic_cast(obj, TYPE_CXL_FMW)) {
> +        return 0;
>       }
> +    fw = CXL_FMW(obj);
> +
> +    *start += fw->size;
>   
> +    return 0;
> +}
> +
> +static uint64_t pc_get_cxl_range_end(PCMachineState *pcms)
> +{
> +    uint64_t start = pc_get_cxl_range_start(pcms) + MiB;
> +
> +    /* Ordering doesn't matter so no need to build a sorted list */
> +    object_child_foreach_recursive(object_get_root(), cxl_get_fmw_end,
> +                                   &start);
>       return start;
>   }
>   
> @@ -954,23 +962,10 @@ void pc_memory_init(PCMachineState *pcms,
>           cxl_base = pc_get_cxl_range_start(pcms);
>           memory_region_init(mr, OBJECT(machine), "cxl_host_reg", cxl_size);
>           memory_region_add_subregion(system_memory, cxl_base, mr);
> -        cxl_resv_end = cxl_base + cxl_size;
> -        if (pcms->cxl_devices_state.fixed_windows) {
> -            hwaddr cxl_fmw_base;
> -            GList *it;
> -
> -            cxl_fmw_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
> -            for (it = pcms->cxl_devices_state.fixed_windows; it; it = 
> it->next) {
> -                CXLFixedWindow *fw = it->data;
> -
> -                fw->base = cxl_fmw_base;
> -                memory_region_init_io(&fw->mr, OBJECT(machine), &cfmws_ops, 
> fw,
> -                                      "cxl-fixed-memory-region", fw->size);
> -                memory_region_add_subregion(system_memory, fw->base, 
> &fw->mr);
> -                cxl_fmw_base += fw->size;
> -                cxl_resv_end = cxl_fmw_base;
> -            }
> -        }
> +        cxl_base = ROUND_UP(cxl_base + cxl_size, 256 * MiB);
> +
> +        cxl_resv_end = cxl_fmws_set_memmap_and_update_mmio(cxl_base,
> +                                                           maxphysaddr);
>       }
>   
>       /* Initialize PC system firmware */

Reply via email to