qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [RFC PATCH 3/4] hw/cxl/cxl-cdat: Initial CDAT implementation for use


From: Ben Widawsky
Subject: Re: [RFC PATCH 3/4] hw/cxl/cxl-cdat: Initial CDAT implementation for use by CXL devices
Date: Tue, 2 Feb 2021 10:49:23 -0800

On 21-02-01 23:16:28, Jonathan Cameron wrote:
> CDAT is an ACPI like format defined by the CXL consortium. It is
> available from
> 
> https://www.uefi.org/node/4093
> 
> Here support for managing all the entires is introduced, along with
> an implementation of a callback for a DOE mailbox which may be
> used to read these values from CXL hardware by either firmware or
> an OS.
> 
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

I seem to be missing one critical thing, where is the CDAT header (Table 1 from
the spec) actually populated, length, revision, checksum, etc?

General, probably underthought-out, comment:

With the CXLType3Class I added since you probably wrote these patches, I wonder
if that'd be a better fit for populating some of these tables, having them
populate dynamically when the DOE/CDAT request actually comes in.

I have no strong opinion. The one advantage I see to using the class is
operations like managing handles, length calculations, etc can be managed by the
helper library rather than the device implementation having to do it. OTTOH if
you have devices that want to do weird things, they might lose some flexibility.

I think with just a few methods added to the CXLType3Class you could pretty
trivially build up a nice sane default CDAT for any CXL device.

> ---
>  hw/cxl/cxl-cdat.c         | 252 ++++++++++++++++++++++++++++++++++++++
>  hw/cxl/meson.build        |   1 +
>  include/hw/cxl/cxl_cdat.h | 101 +++++++++++++++
>  3 files changed, 354 insertions(+)
> 
> diff --git a/hw/cxl/cxl-cdat.c b/hw/cxl/cxl-cdat.c
> new file mode 100644
> index 0000000000..6ed4c15cc0
> --- /dev/null
> +++ b/hw/cxl/cxl-cdat.c
> @@ -0,0 +1,252 @@
> +/*
> + * Support for CDAT entires as defined in
> + * Coherent Device Attribute Table (CDAT) Specification rev 1.02
> + * Available from uefi.org.
> + *
> + * Copyright (c) 2021 Jonathan Cameron <Jonathan.Cameron@huawei.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#include "qemu/osdep.h"
> +#include "qemu/units.h"
> +#include "qemu/error-report.h"
> +#include "hw/mem/memory-device.h"
> +#include "hw/mem/pc-dimm.h"
> +#include "hw/pci/pci.h"
> +#include "hw/pci/doe.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
> +#include "qemu/log.h"
> +#include "qemu/module.h"
> +#include "qemu/range.h"
> +#include "qemu/rcu.h"
> +#include "sysemu/hostmem.h"
> +#include "sysemu/numa.h"
> +#include "hw/cxl/cxl.h"
> +
> +void cdat_add_dsmas(CXLCDAT *cdat, uint8_t dsmad_handle, uint8_t flags,
> +                    uint64_t dpa_base, uint64_t dpa_length)
> +{
> +    struct cxl_cdat_dsmas *dsmas = g_malloc0(sizeof(*dsmas));
> +    dsmas->dsmad_handle = dsmad_handle;
> +    dsmas->flags = flags;
> +    dsmas->dpa_base = dpa_base;
> +    dsmas->dpa_length = dpa_length;
> +    cdat->dsmas_list = g_list_append(cdat->dsmas_list, dsmas);
> +}
> +
> +void cdat_add_dslbis(CXLCDAT *cdat, uint8_t handle, uint8_t flags,
> +                     uint8_t data_type, uint64_t base_unit,
> +                     uint16_t entry0, uint16_t entry1, uint16_t entry2)
> +{
> +    struct cxl_cdat_dslbis *dslbis = g_malloc0(sizeof(*dslbis));
> +    dslbis->handle = handle;
> +    dslbis->flags = flags;
> +    dslbis->data_type = data_type;
> +    dslbis->entry_base_unit = base_unit;
> +    dslbis->entries[0] = entry0;
> +    dslbis->entries[1] = entry1;
> +    dslbis->entries[2] = entry2;
> +    cdat->dslbis_list = g_list_append(cdat->dslbis_list, dslbis);
> +}
> +
> +void cdat_add_dsmscis(CXLCDAT *cdat, uint8_t dsmas_handle,
> +                      uint64_t memory_sc_size, uint64_t cache_attrs)
> +{
> +    struct cxl_cdat_dsmscis *dsmscis = g_malloc(sizeof(*dsmscis));
> +    dsmscis->dsmas_handle = dsmas_handle;
> +    dsmscis->memory_side_cache_size = memory_sc_size;
> +    dsmscis->cache_attributes = cache_attrs;
> +    cdat->dsmscis_list = g_list_append(cdat->dsmscis_list, dsmscis);
> +}
> +
> +void cdat_add_dsis(CXLCDAT *cdat, uint8_t flags, uint8_t handle)
> +{
> +    struct cxl_cdat_dsis *dsis = g_malloc(sizeof(*dsis));
> +    dsis->flags = flags;
> +    dsis->handle = handle;
> +    cdat->dsis_list = g_list_append(cdat->dsis_list, dsis);
> +}
> +
> +void cdat_add_dsemts(CXLCDAT *cdat, uint8_t dsmas_handle,
> +                     uint8_t efi_mem_type_attr, uint64_t dpa_offset,
> +                     uint64_t dpa_length)
> +{
> +    struct cxl_cdat_dsemts *dsemts = g_malloc(sizeof(*dsemts));
> +    dsemts->dsmas_handle = dsmas_handle;
> +    dsemts->efi_mem_type_attr = efi_mem_type_attr;
> +    dsemts->dpa_offset = dpa_offset;
> +    dsemts->dpa_length = dpa_length;
> +    cdat->dsemts_list = g_list_append(cdat->dsemts_list, dsemts);
> +}
> +
> +struct cxl_cdat_sslbis *cdat_add_sslbis(CXLCDAT *cdat, uint8_t num_entries,
> +                                        uint8_t data_type, uint64_t 
> base_unit)
> +{
> +    struct cxl_cdat_sslbis *sslbis =
> +        g_malloc(sizeof(*sslbis) + num_entries * sizeof(sslbis->entries[0]));
> +    sslbis->num_entries = num_entries;
> +    sslbis->data_type = data_type;
> +    sslbis->base_unit = base_unit;
> +    cdat->sslbis_list = g_list_append(cdat->sslbis_list, sslbis);
> +    return sslbis;
> +}
> +
> +int cdata_sslbis_set_entry(struct cxl_cdat_sslbis *sslbis, uint8_t index,
> +                           uint16_t portx, uint16_t porty, uint16_t val)
> +{
> +    struct cxl_cdat_sslbis_entry *entry;
> +    if (index >= sslbis->num_entries) {
> +        return -1;
> +    }
> +    entry = &sslbis->entries[index];
> +    entry->port_x_id = portx;
> +    entry->port_y_id = porty;
> +    entry->val = val;
> +    return 0;
> +}
> +
> +int cxl_table_access(PCIEDOE *doe, uint16_t vendor_id, uint8_t object_type,
> +                     void *priv)
> +{
> +    uint8_t table_type;
> +    int total_entries;
> +    uint16_t entry_handle;
> +    CXLCDAT *cdat = priv;
> +    uint16_t next_entry;
> +
> +    if (doe->req_length != 3) {
> +        /* optional error for unexpected command length */
> +        return -1;
> +    }
> +
> +    if ((doe->store[2] & CXL_DOE_TABLE_ACCESS_DW2_RCODE) != 0) {
> +        /*
> +         * Only table access code currently supported.
> +         * Error indication is lack of Data Object Ready
> +         */
> +        return -1;
> +    }
> +
> +    table_type = (doe->store[2] & CXL_DOE_TABLE_ACCESS_DW2_TYPE) >>
> +        ctz32(CXL_DOE_TABLE_ACCESS_DW2_TYPE);
> +    if (table_type != 0) {
> +        /* Unsuported table ID so just don't set Data Object Ready */
> +        return -1;
> +    }
> +    entry_handle = (doe->store[2] & CXL_DOE_TABLE_ACCESS_DW2_ENTRYHANDLE) >>
> +        ctz32(CXL_DOE_TABLE_ACCESS_DW2_ENTRYHANDLE);
> +
> +    /* Assume entry handle == CDAT structure index */
> +    total_entries = g_list_length(cdat->dsmas_list) +
> +        g_list_length(cdat->dslbis_list) +
> +        g_list_length(cdat->dsmscis_list) +
> +        g_list_length(cdat->dsis_list) +
> +        g_list_length(cdat->dsemts_list) +
> +        g_list_length(cdat->sslbis_list);
> +    if (entry_handle + 1 == total_entries) {
> +        next_entry = 0xFFFF;
> +    } else {
> +        next_entry = entry_handle + 1;
> +    }
> +
> +    if (entry_handle < g_list_length(cdat->dsmas_list)) {
> +        const int dsmas_len = 24;
> +        struct cxl_cdat_dsmas *dsmas =
> +            g_list_nth_data(cdat->dsmas_list, entry_handle);
> +
> +        doe->store[1] = 3 + dsmas_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (dsmas_len << 16) | CXL_CDAT_DSMAS_TYPE;
> +
> +        /* cxl version of proximity domain */
> +        doe->store[4] = dsmas->dsmad_handle;
> +        /* flags in 2nd byte of [4] (bit 2 is non volatile) */
> +        doe->store[4] |= (dsmas->flags << 8);
> +        doe->store[5] = dsmas->dpa_base & 0xFFFFFFFF;
> +        doe->store[6] = (dsmas->dpa_base >> 32) & 0xFFFFFFFF;
> +        doe->store[7] = dsmas->dpa_length & 0xFFFFFFFF;
> +        doe->store[8] = (dsmas->dpa_length >> 32) & 0xFFFFFFFF;
> +        return 0;
> +    }
> +    entry_handle -= g_list_length(cdat->dsmas_list);
> +    if (entry_handle < g_list_length(cdat->dslbis_list)) {
> +        const int dslbis_len = 24;
> +        struct cxl_cdat_dslbis *dslbis =
> +            g_list_nth_data(cdat->dslbis_list, entry_handle);
> +
> +        doe->store[1] = 3 + dslbis_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (dslbis_len << 16) | CXL_CDAT_DSLBIS_TYPE;
> +
> +        doe->store[4] = (dslbis->data_type << 24) | (dslbis->flags << 8) |
> +            dslbis->handle;
> +        doe->store[5] = dslbis->entry_base_unit & 0xFFFFFFFF;
> +        doe->store[6] = (dslbis->entry_base_unit >> 32) & 0xFFFFFFFF;
> +        doe->store[7] = (dslbis->entries[1] << 16) | dslbis->entries[0];
> +        doe->store[8] = dslbis->entries[2];
> +        return 0;
> +    }
> +    entry_handle -= g_list_length(cdat->dslbis_list);
> +    if (entry_handle < g_list_length(cdat->dsmscis_list)) {
> +        const int dsmscis_len = 20;
> +        struct cxl_cdat_dsmscis *dsmscis =
> +            g_list_nth_data(cdat->dsmscis_list, entry_handle);
> +
> +        doe->store[1] = 3 + dsmscis_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (dsmscis_len << 16) | CXL_CDAT_DSMSCIS_TYPE;
> +        doe->store[4] = dsmscis->dsmas_handle;
> +        doe->store[5] = dsmscis->memory_side_cache_size & 0xffffffff;
> +        doe->store[6] = (dsmscis->memory_side_cache_size >> 32) & 0xffffffff;
> +        doe->store[7] = dsmscis->cache_attributes;
> +    }
> +    entry_handle -= g_list_length(cdat->dsmscis_list);
> +    if (entry_handle < g_list_length(cdat->dsis_list)) {
> +        const int dsis_len = 8;
> +        struct cxl_cdat_dsis *dsis =
> +            g_list_nth_data(cdat->dsis_list, entry_handle);
> +
> +        doe->store[1] = 3 + dsis_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (dsis_len << 16) | CXL_CDAT_DSMSCIS_TYPE;
> +        doe->store[4] = (dsis->handle << 8) | dsis->flags;
> +    }
> +    entry_handle -= g_list_length(cdat->dsis_list);
> +    if (entry_handle < g_list_length(cdat->dsemts_list)) {
> +        const int dsemts_len = 24;
> +        struct cxl_cdat_dsemts *dsemts =
> +            g_list_nth_data(cdat->dsemts_list, entry_handle);
> +
> +        doe->store[1] = 3 + dsemts_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (dsemts_len << 16) | CXL_CDAT_DSEMTS_TYPE;
> +        doe->store[4] = (dsemts->efi_mem_type_attr << 8) | 
> dsemts->dsmas_handle;
> +        doe->store[5] = dsemts->dpa_offset & 0xffffffff;
> +        doe->store[6] = (dsemts->dpa_offset >> 32) & 0xffffffff;
> +        doe->store[7] = dsemts->dpa_length & 0xffffffff;
> +        doe->store[8] = (dsemts->dpa_length >> 32) & 0xffffffff;
> +    }
> +    entry_handle -= g_list_length(cdat->dsemts_list);
> +    if (entry_handle < g_list_length(cdat->sslbis_list)) {
> +        struct cxl_cdat_sslbis *sslbis =
> +            g_list_nth_data(cdat->sslbis_list, entry_handle);
> +        int sslbis_len = 16 + 8 * sslbis->num_entries;
> +        int i;
> +
> +        doe->store[1] = 3 + sslbis_len / sizeof(uint32_t);
> +        doe->store[2] = next_entry << 16;
> +        doe->store[3] = (sslbis_len << 16) | CXL_CDAT_SSLBIS_TYPE;
> +        doe->store[4] = sslbis->data_type;
> +        doe->store[5] = sslbis->base_unit & 0xffffffff;
> +        doe->store[6] = (sslbis->base_unit >> 32) & 0xffffffff;
> +        for (i = 0; i < sslbis->num_entries; i++) {
> +            doe->store[7 + i * 2] = (sslbis->entries[i].port_y_id << 8) |
> +                sslbis->entries[i].port_x_id;
> +            doe->store[7 + i * 2 + 1] = sslbis->entries[i].val;
> +        }
> +    }
> +
> +    return -1;
> +}
> diff --git a/hw/cxl/meson.build b/hw/cxl/meson.build
> index 0eca715d10..9e2e5f4094 100644
> --- a/hw/cxl/meson.build
> +++ b/hw/cxl/meson.build
> @@ -2,4 +2,5 @@ softmmu_ss.add(when: 'CONFIG_CXL', if_true: files(
>    'cxl-component-utils.c',
>    'cxl-device-utils.c',
>    'cxl-mailbox-utils.c',
> +  'cxl-cdat.c',
>  ))
> diff --git a/include/hw/cxl/cxl_cdat.h b/include/hw/cxl/cxl_cdat.h
> new file mode 100644
> index 0000000000..d0226c463c
> --- /dev/null
> +++ b/include/hw/cxl/cxl_cdat.h
> @@ -0,0 +1,101 @@
> +/*
> + * Support for CDAT entires as defined in
> + * Coherent Device Attribute Table (CDAT) Specification rev 1.02
> + * Available from uefi.org.
> + *
> + * Copyright (c) 2021 Jonathan Cameron <Jonathan.Cameron@huawei.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#ifndef QEMU_CXL_CDAT_H
> +#define QEMU_CXL_CDAT_H
> +#include "hw/pci/doe.h"
> +/* DW2 is common to the request and response */
> +#define CXL_DOE_TABLE_ACCESS_DW2_RCODE          0x000000ff
> +#define CXL_DOE_TABLE_ACCESS_DW2_TYPE           0x0000ff00
> +#define CXL_DOE_TABLE_ACCESS_DW2_ENTRYHANDLE    0xffff0000
> +
> +#define CXL_CDAT_DSMAS_TYPE     0
> +#define CXL_CDAT_DSLBIS_TYPE    1
> +#define CXL_CDAT_DSMSCIS_TYPE   2
> +#define CXL_CDAT_DSIS_TYPE      3
> +#define CXL_CDAT_DSEMTS_TYPE    4
> +#define CXL_CDAT_SSLBIS_TYPE    5
> +
> +struct cxl_cdat_dsmas {
> +    uint8_t dsmad_handle;
> +    uint8_t flags;
> +#define CDAT_DSMAS_FLAG_NV (1 << 2)
> +    uint64_t dpa_base;
> +    uint64_t dpa_length;
> +};
> +
> +struct cxl_cdat_dslbis {
> +    uint8_t handle;
> +    uint8_t flags;
> +    uint8_t data_type;
> +    uint64_t entry_base_unit;
> +    uint16_t entries[3]; /* 6 bytes */
> +};
> +
> +struct cxl_cdat_dsmscis {
> +    uint8_t dsmas_handle;
> +    uint64_t memory_side_cache_size;
> +    uint32_t cache_attributes;
> +};
> +
> +struct cxl_cdat_dsis {
> +    uint8_t flags;
> +#define CDAT_DSIS_MEMORY_ATTACHED 0x01
> +    uint8_t handle;
> +};
> +
> +struct cxl_cdat_dsemts {
> +    uint8_t dsmas_handle;
> +    uint8_t efi_mem_type_attr;
> +    uint64_t dpa_offset;
> +    uint64_t dpa_length;
> +};
> +
> +struct cxl_cdat_sslbis_entry {
> +    uint16_t port_x_id;
> +    uint16_t port_y_id;
> +    uint16_t val;
> +};
> +
> +struct cxl_cdat_sslbis {
> +    uint8_t num_entries; /* needed to compute length */
> +    uint8_t data_type;
> +    uint64_t base_unit;
> +    struct cxl_cdat_sslbis_entry entries[];
> +};
> +
> +typedef struct cxl_cdat {
> +    GList *dsmas_list;
> +    GList *dslbis_list;
> +    GList *dsmscis_list;
> +    GList *dsis_list;
> +    GList *dsemts_list;
> +    GList *sslbis_list;
> +} CXLCDAT;
> +
> +void cdat_add_dsmas(CXLCDAT *cdat, uint8_t dsmad_handle, uint8_t flags,
> +                    uint64_t dpa_base, uint64_t dpa_length);
> +void cdat_add_dslbis(CXLCDAT *cdat, uint8_t handle, uint8_t flags,
> +                     uint8_t data_type, uint64_t base_unit,
> +                     uint16_t entry0, uint16_t entry1, uint16_t entry2);
> +void cdat_add_dsmscis(CXLCDAT *cdat, uint8_t dsmas_handle,
> +                      uint64_t memory_sc_size, uint64_t cache_attrs);
> +void cdat_add_dsis(CXLCDAT *cdat, uint8_t flags, uint8_t handle);
> +void cdat_add_dsemts(CXLCDAT *cdat, uint8_t dsmas_handle,
> +                     uint8_t efi_mem_type_attr, uint64_t dpa_offset,
> +                     uint64_t dpa_length);
> +struct cxl_cdat_sslbis *cdat_add_sslbis(CXLCDAT *cdat, uint8_t num_entries,
> +                                        uint8_t data_type, uint64_t 
> base_unit);
> +int cdata_sslbis_set_entry(struct cxl_cdat_sslbis *sslbis, uint8_t index,
> +                           uint16_t portx, uint16_t pory, uint16_t val);
> +
> +int cxl_table_access(PCIEDOE *doe, uint16_t vendor_id, uint8_t object_type,
> +                     void *priv);
> +#endif
> -- 
> 2.19.1
> 
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]