diff mbox series

[v10,06/10] ACPI ERST: build the ACPI ERST table

Message ID 1639072655-19271-7-git-send-email-eric.devolder@oracle.com (mailing list archive)
State New, archived
Headers show
Series acpi: Error Record Serialization Table, ERST, support for QEMU | expand

Commit Message

Eric DeVolder Dec. 9, 2021, 5:57 p.m. UTC
This builds the ACPI ERST table to inform OSPM how to communicate
with the acpi-erst device.

Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
---
 hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 241 insertions(+)

Comments

Ani Sinha Dec. 12, 2021, 1:43 p.m. UTC | #1
.

On Thu, Dec 9, 2021 at 11:28 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
>
> This builds the ACPI ERST table to inform OSPM how to communicate
> with the acpi-erst device.

This patch starts in the middle of pci device code addition, between
erst_reg_ops and erst_post_load. I do not like this :(

>
> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> ---
>  hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 241 insertions(+)
>
> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
> index 81f5435..753425a 100644
> --- a/hw/acpi/erst.c
> +++ b/hw/acpi/erst.c
> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>
> +
> +/*******************************************************************/
> +/*******************************************************************/
> +
> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
> +#define INST_READ_REGISTER                 0x00
> +#define INST_READ_REGISTER_VALUE           0x01
> +#define INST_WRITE_REGISTER                0x02
> +#define INST_WRITE_REGISTER_VALUE          0x03
> +#define INST_NOOP                          0x04
> +#define INST_LOAD_VAR1                     0x05
> +#define INST_LOAD_VAR2                     0x06
> +#define INST_STORE_VAR1                    0x07
> +#define INST_ADD                           0x08
> +#define INST_SUBTRACT                      0x09
> +#define INST_ADD_VALUE                     0x0A
> +#define INST_SUBTRACT_VALUE                0x0B
> +#define INST_STALL                         0x0C
> +#define INST_STALL_WHILE_TRUE              0x0D
> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
> +#define INST_GOTO                          0x0F
> +#define INST_SET_SRC_ADDRESS_BASE          0x10
> +#define INST_SET_DST_ADDRESS_BASE          0x11
> +#define INST_MOVE_DATA                     0x12

I prefer these definitions to come at the top of the file along with
other definitions.

> +
> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
> +static void build_serialization_instruction_entry(GArray *table_data,

This function and buiild_erst() can come at the end of erst.c. They go
together and are doing a common but different operation from the
operations of the pci device - building the erst table. Hence, ther
code should be separate from pci device code. A new file would be an
overkill at this state IMHO but in the future if erst table generation
code gains more weight, it can be split into two files.

> +    uint8_t serialization_action,
> +    uint8_t instruction,
> +    uint8_t flags,
> +    uint8_t register_bit_width,
> +    uint64_t register_address,
> +    uint64_t value,
> +    uint64_t mask)
> +{
> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
> +    struct AcpiGenericAddress gas;
> +
> +    /* Serialization Action */
> +    build_append_int_noprefix(table_data, serialization_action, 1);
> +    /* Instruction */
> +    build_append_int_noprefix(table_data, instruction         , 1);
> +    /* Flags */
> +    build_append_int_noprefix(table_data, flags               , 1);
> +    /* Reserved */
> +    build_append_int_noprefix(table_data, 0                   , 1);
> +    /* Register Region */
> +    gas.space_id = AML_SYSTEM_MEMORY;
> +    gas.bit_width = register_bit_width;
> +    gas.bit_offset = 0;
> +    switch (register_bit_width) {
> +    case 8:
> +        gas.access_width = 1;
> +        break;
> +    case 16:
> +        gas.access_width = 2;
> +        break;
> +    case 32:
> +        gas.access_width = 3;
> +        break;
> +    case 64:
> +        gas.access_width = 4;
> +        break;
> +    default:
> +        gas.access_width = 0;
> +        break;
> +    }
> +    gas.address = register_address;
> +    build_append_gas_from_struct(table_data, &gas);
> +    /* Value */
> +    build_append_int_noprefix(table_data, value  , 8);
> +    /* Mask */
> +    build_append_int_noprefix(table_data, mask   , 8);
> +}
> +
> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
> +    const char *oem_id, const char *oem_table_id)
> +{
> +    GArray *table_instruction_data;
> +    unsigned action;
> +    pcibus_t bar0, bar1;
> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
> +                        .oem_table_id = oem_table_id };
> +
> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
> +    trace_acpi_erst_pci_bar_0(bar0);
> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
> +    trace_acpi_erst_pci_bar_1(bar1);
> +
> +#define MASK8  0x00000000000000FFUL
> +#define MASK16 0x000000000000FFFFUL
> +#define MASK32 0x00000000FFFFFFFFUL
> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
> +
> +    /*
> +     * Serialization Action Table
> +     * The serialization action table must be generated first
> +     * so that its size can be known in order to populate the
> +     * Instruction Entry Count field.
> +     */
> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
> +
> +    /* Serialization Instruction Entries */
> +    action = ACTION_BEGIN_WRITE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_BEGIN_READ_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_BEGIN_CLEAR_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_END_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_SET_RECORD_OFFSET;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER      , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_EXECUTE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_CHECK_BUSY_STATUS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER_VALUE , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
> +
> +    action = ACTION_GET_COMMAND_STATUS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
> +
> +    action = ACTION_GET_RECORD_IDENTIFIER;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    action = ACTION_SET_RECORD_IDENTIFIER;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER      , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_GET_RECORD_COUNT;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    /* Serialization Header */
> +    acpi_table_begin(&table, table_data);
> +
> +    /* Serialization Header Size */
> +    build_append_int_noprefix(table_data, 48, 4);
> +
> +    /* Reserved */
> +    build_append_int_noprefix(table_data,  0, 4);
> +
> +    /*
> +     * Instruction Entry Count
> +     * Each instruction entry is 32 bytes
> +     */
> +    build_append_int_noprefix(table_data,
> +        (table_instruction_data->len / 32), 4);
> +
> +    /* Serialization Instruction Entries */
> +    g_array_append_vals(table_data, table_instruction_data->data,
> +        table_instruction_data->len);
> +    g_array_free(table_instruction_data, TRUE);
> +
> +    acpi_table_end(linker, &table);
> +}
> +
>  /*******************************************************************/
>  /*******************************************************************/
>  static int erst_post_load(void *opaque, int version_id)
> --
> 1.8.3.1
>
Michael S. Tsirkin Dec. 12, 2021, 10:56 p.m. UTC | #2
On Thu, Dec 09, 2021 at 12:57:31PM -0500, Eric DeVolder wrote:
> This builds the ACPI ERST table to inform OSPM how to communicate
> with the acpi-erst device.
> 
> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> ---
>  hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 241 insertions(+)
> 
> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
> index 81f5435..753425a 100644
> --- a/hw/acpi/erst.c
> +++ b/hw/acpi/erst.c
> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
>      .endianness = DEVICE_NATIVE_ENDIAN,
>  };
>  
> +
> +/*******************************************************************/
> +/*******************************************************************/
> +
> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
> +#define INST_READ_REGISTER                 0x00
> +#define INST_READ_REGISTER_VALUE           0x01
> +#define INST_WRITE_REGISTER                0x02
> +#define INST_WRITE_REGISTER_VALUE          0x03
> +#define INST_NOOP                          0x04
> +#define INST_LOAD_VAR1                     0x05
> +#define INST_LOAD_VAR2                     0x06
> +#define INST_STORE_VAR1                    0x07
> +#define INST_ADD                           0x08
> +#define INST_SUBTRACT                      0x09
> +#define INST_ADD_VALUE                     0x0A
> +#define INST_SUBTRACT_VALUE                0x0B
> +#define INST_STALL                         0x0C
> +#define INST_STALL_WHILE_TRUE              0x0D
> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
> +#define INST_GOTO                          0x0F
> +#define INST_SET_SRC_ADDRESS_BASE          0x10
> +#define INST_SET_DST_ADDRESS_BASE          0x11
> +#define INST_MOVE_DATA                     0x12
> +

I would create wrappers for the specific uses that we do have. Leave the
rest alone.
You just use 4 of these right? And a bunch of parameters are
always the same. E.g. flags always 0, address always same.

> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
> +static void build_serialization_instruction_entry(GArray *table_data,
> +    uint8_t serialization_action,
> +    uint8_t instruction,
> +    uint8_t flags,
> +    uint8_t register_bit_width,

maybe make it width in bytes, then you do not need a switch.

> +    uint64_t register_address,
> +    uint64_t value,
> +    uint64_t mask)
> +{
> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
> +    struct AcpiGenericAddress gas;
> +
> +    /* Serialization Action */
> +    build_append_int_noprefix(table_data, serialization_action, 1);
> +    /* Instruction */
> +    build_append_int_noprefix(table_data, instruction         , 1);
> +    /* Flags */
> +    build_append_int_noprefix(table_data, flags               , 1);
> +    /* Reserved */
> +    build_append_int_noprefix(table_data, 0                   , 1);
> +    /* Register Region */
> +    gas.space_id = AML_SYSTEM_MEMORY;
> +    gas.bit_width = register_bit_width;
> +    gas.bit_offset = 0;
> +    switch (register_bit_width) {
> +    case 8:
> +        gas.access_width = 1;
> +        break;
> +    case 16:
> +        gas.access_width = 2;
> +        break;
> +    case 32:
> +        gas.access_width = 3;
> +        break;
> +    case 64:
> +        gas.access_width = 4;
> +        break;
> +    default:
> +        gas.access_width = 0;
> +        break;

does this default actually work?

> +    }
> +    gas.address = register_address;
> +    build_append_gas_from_struct(table_data, &gas);
> +    /* Value */
> +    build_append_int_noprefix(table_data, value  , 8);
> +    /* Mask */
> +    build_append_int_noprefix(table_data, mask   , 8);
> +}
> +
> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
> +    const char *oem_id, const char *oem_table_id)
> +{
> +    GArray *table_instruction_data;
> +    unsigned action;
> +    pcibus_t bar0, bar1;
> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
> +                        .oem_table_id = oem_table_id };
> +
> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
> +    trace_acpi_erst_pci_bar_0(bar0);
> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);

why do we need the cast here?
Also assignment at declaration point will be cleaner, won't it?

> +    trace_acpi_erst_pci_bar_1(bar1);

bar1 seems unused ... why do we bother with it just for trace?

> +
> +#define MASK8  0x00000000000000FFUL
> +#define MASK16 0x000000000000FFFFUL
> +#define MASK32 0x00000000FFFFFFFFUL
> +#define MASK64 0xFFFFFFFFFFFFFFFFUL


can't we just pass # of bytes?

> +
> +    /*
> +     * Serialization Action Table
> +     * The serialization action table must be generated first
> +     * so that its size can be known in order to populate the
> +     * Instruction Entry Count field.
> +     */
> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
> +
> +    /* Serialization Instruction Entries */
> +    action = ACTION_BEGIN_WRITE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_BEGIN_READ_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_BEGIN_CLEAR_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_END_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_SET_RECORD_OFFSET;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER      , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_EXECUTE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_CHECK_BUSY_STATUS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER_VALUE , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
> +
> +    action = ACTION_GET_COMMAND_STATUS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
> +
> +    action = ACTION_GET_RECORD_IDENTIFIER;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    action = ACTION_SET_RECORD_IDENTIFIER;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER      , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_GET_RECORD_COUNT;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 32,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> +
> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> +    build_serialization_instruction_entry(table_instruction_data,
> +        action, INST_READ_REGISTER       , 0, 64,
> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> +
> +    /* Serialization Header */
> +    acpi_table_begin(&table, table_data);
> +
> +    /* Serialization Header Size */
> +    build_append_int_noprefix(table_data, 48, 4);
> +
> +    /* Reserved */
> +    build_append_int_noprefix(table_data,  0, 4);
> +
> +    /*
> +     * Instruction Entry Count
> +     * Each instruction entry is 32 bytes
> +     */

assert that it's a multiple of 32 maybe

> +    build_append_int_noprefix(table_data,
> +        (table_instruction_data->len / 32), 4);
> +
> +    /* Serialization Instruction Entries */
> +    g_array_append_vals(table_data, table_instruction_data->data,
> +        table_instruction_data->len);
> +    g_array_free(table_instruction_data, TRUE);
> +
> +    acpi_table_end(linker, &table);
> +}
> +
>  /*******************************************************************/
>  /*******************************************************************/
>  static int erst_post_load(void *opaque, int version_id)
> -- 
> 1.8.3.1
Eric DeVolder Dec. 13, 2021, 9:26 p.m. UTC | #3
Hi Ani,
inline response below.
Eric

On 12/12/21 07:43, Ani Sinha wrote:
> .
> 
> On Thu, Dec 9, 2021 at 11:28 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
>>
>> This builds the ACPI ERST table to inform OSPM how to communicate
>> with the acpi-erst device.
> 
> This patch starts in the middle of pci device code addition, between
> erst_reg_ops and erst_post_load. I do not like this :(

Below you suggest moving the contents of this patch to the bottom of erst.c.
Before I do that, consider moving the contents to the top of the file instead, I believe that would 
address the concerns cited here, and it would allow for the last line of the file to be the 
type_init(), like other files.

I'll move it, just let me know if top or bottom.
Thanks!
eric


> 
>>
>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>> ---
>>   hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 241 insertions(+)
>>
>> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
>> index 81f5435..753425a 100644
>> --- a/hw/acpi/erst.c
>> +++ b/hw/acpi/erst.c
>> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
>>       .endianness = DEVICE_NATIVE_ENDIAN,
>>   };
>>
>> +
>> +/*******************************************************************/
>> +/*******************************************************************/
>> +
>> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
>> +#define INST_READ_REGISTER                 0x00
>> +#define INST_READ_REGISTER_VALUE           0x01
>> +#define INST_WRITE_REGISTER                0x02
>> +#define INST_WRITE_REGISTER_VALUE          0x03
>> +#define INST_NOOP                          0x04
>> +#define INST_LOAD_VAR1                     0x05
>> +#define INST_LOAD_VAR2                     0x06
>> +#define INST_STORE_VAR1                    0x07
>> +#define INST_ADD                           0x08
>> +#define INST_SUBTRACT                      0x09
>> +#define INST_ADD_VALUE                     0x0A
>> +#define INST_SUBTRACT_VALUE                0x0B
>> +#define INST_STALL                         0x0C
>> +#define INST_STALL_WHILE_TRUE              0x0D
>> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
>> +#define INST_GOTO                          0x0F
>> +#define INST_SET_SRC_ADDRESS_BASE          0x10
>> +#define INST_SET_DST_ADDRESS_BASE          0x11
>> +#define INST_MOVE_DATA                     0x12
> 
> I prefer these definitions to come at the top of the file along with
> other definitions.
> 
>> +
>> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
>> +static void build_serialization_instruction_entry(GArray *table_data,
> 
> This function and buiild_erst() can come at the end of erst.c. They go
> together and are doing a common but different operation from the
> operations of the pci device - building the erst table. Hence, ther
> code should be separate from pci device code. A new file would be an
> overkill at this state IMHO but in the future if erst table generation
> code gains more weight, it can be split into two files.
> 
>> +    uint8_t serialization_action,
>> +    uint8_t instruction,
>> +    uint8_t flags,
>> +    uint8_t register_bit_width,
>> +    uint64_t register_address,
>> +    uint64_t value,
>> +    uint64_t mask)
>> +{
>> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
>> +    struct AcpiGenericAddress gas;
>> +
>> +    /* Serialization Action */
>> +    build_append_int_noprefix(table_data, serialization_action, 1);
>> +    /* Instruction */
>> +    build_append_int_noprefix(table_data, instruction         , 1);
>> +    /* Flags */
>> +    build_append_int_noprefix(table_data, flags               , 1);
>> +    /* Reserved */
>> +    build_append_int_noprefix(table_data, 0                   , 1);
>> +    /* Register Region */
>> +    gas.space_id = AML_SYSTEM_MEMORY;
>> +    gas.bit_width = register_bit_width;
>> +    gas.bit_offset = 0;
>> +    switch (register_bit_width) {
>> +    case 8:
>> +        gas.access_width = 1;
>> +        break;
>> +    case 16:
>> +        gas.access_width = 2;
>> +        break;
>> +    case 32:
>> +        gas.access_width = 3;
>> +        break;
>> +    case 64:
>> +        gas.access_width = 4;
>> +        break;
>> +    default:
>> +        gas.access_width = 0;
>> +        break;
>> +    }
>> +    gas.address = register_address;
>> +    build_append_gas_from_struct(table_data, &gas);
>> +    /* Value */
>> +    build_append_int_noprefix(table_data, value  , 8);
>> +    /* Mask */
>> +    build_append_int_noprefix(table_data, mask   , 8);
>> +}
>> +
>> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
>> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
>> +    const char *oem_id, const char *oem_table_id)
>> +{
>> +    GArray *table_instruction_data;
>> +    unsigned action;
>> +    pcibus_t bar0, bar1;
>> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
>> +                        .oem_table_id = oem_table_id };
>> +
>> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
>> +    trace_acpi_erst_pci_bar_0(bar0);
>> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
>> +    trace_acpi_erst_pci_bar_1(bar1);
>> +
>> +#define MASK8  0x00000000000000FFUL
>> +#define MASK16 0x000000000000FFFFUL
>> +#define MASK32 0x00000000FFFFFFFFUL
>> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
>> +
>> +    /*
>> +     * Serialization Action Table
>> +     * The serialization action table must be generated first
>> +     * so that its size can be known in order to populate the
>> +     * Instruction Entry Count field.
>> +     */
>> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
>> +
>> +    /* Serialization Instruction Entries */
>> +    action = ACTION_BEGIN_WRITE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_BEGIN_READ_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_BEGIN_CLEAR_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_END_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_SET_RECORD_OFFSET;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER      , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_EXECUTE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_CHECK_BUSY_STATUS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER_VALUE , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
>> +
>> +    action = ACTION_GET_COMMAND_STATUS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
>> +
>> +    action = ACTION_GET_RECORD_IDENTIFIER;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    action = ACTION_SET_RECORD_IDENTIFIER;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER      , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_GET_RECORD_COUNT;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    /* Serialization Header */
>> +    acpi_table_begin(&table, table_data);
>> +
>> +    /* Serialization Header Size */
>> +    build_append_int_noprefix(table_data, 48, 4);
>> +
>> +    /* Reserved */
>> +    build_append_int_noprefix(table_data,  0, 4);
>> +
>> +    /*
>> +     * Instruction Entry Count
>> +     * Each instruction entry is 32 bytes
>> +     */
>> +    build_append_int_noprefix(table_data,
>> +        (table_instruction_data->len / 32), 4);
>> +
>> +    /* Serialization Instruction Entries */
>> +    g_array_append_vals(table_data, table_instruction_data->data,
>> +        table_instruction_data->len);
>> +    g_array_free(table_instruction_data, TRUE);
>> +
>> +    acpi_table_end(linker, &table);
>> +}
>> +
>>   /*******************************************************************/
>>   /*******************************************************************/
>>   static int erst_post_load(void *opaque, int version_id)
>> --
>> 1.8.3.1
>>
Eric DeVolder Dec. 13, 2021, 10:02 p.m. UTC | #4
Michael,
Thanks for reviewing! Inline responses below.
eric

On 12/12/21 16:56, Michael S. Tsirkin wrote:
> On Thu, Dec 09, 2021 at 12:57:31PM -0500, Eric DeVolder wrote:
>> This builds the ACPI ERST table to inform OSPM how to communicate
>> with the acpi-erst device.
>>
>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>> ---
>>   hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 241 insertions(+)
>>
>> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
>> index 81f5435..753425a 100644
>> --- a/hw/acpi/erst.c
>> +++ b/hw/acpi/erst.c
>> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
>>       .endianness = DEVICE_NATIVE_ENDIAN,
>>   };
>>   
>> +
>> +/*******************************************************************/
>> +/*******************************************************************/
>> +
>> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
>> +#define INST_READ_REGISTER                 0x00
>> +#define INST_READ_REGISTER_VALUE           0x01
>> +#define INST_WRITE_REGISTER                0x02
>> +#define INST_WRITE_REGISTER_VALUE          0x03
>> +#define INST_NOOP                          0x04
>> +#define INST_LOAD_VAR1                     0x05
>> +#define INST_LOAD_VAR2                     0x06
>> +#define INST_STORE_VAR1                    0x07
>> +#define INST_ADD                           0x08
>> +#define INST_SUBTRACT                      0x09
>> +#define INST_ADD_VALUE                     0x0A
>> +#define INST_SUBTRACT_VALUE                0x0B
>> +#define INST_STALL                         0x0C
>> +#define INST_STALL_WHILE_TRUE              0x0D
>> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
>> +#define INST_GOTO                          0x0F
>> +#define INST_SET_SRC_ADDRESS_BASE          0x10
>> +#define INST_SET_DST_ADDRESS_BASE          0x11
>> +#define INST_MOVE_DATA                     0x12
>> +
> 
> I would create wrappers for the specific uses that we do have. Leave the
> rest alone.
> You just use 4 of these right? And a bunch of parameters are
> always the same. E.g. flags always 0, address always same.

If I understand correctly, I think you are suggesting making wrappers for the 4 in use (ie WRITE, 
WRITE_VALUE, READ, READ_VALUE). in an effort to simplify/hide the underlying call to 
build_serialization_instruction_entry(). OK, I'll do that.

> 
>> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
>> +static void build_serialization_instruction_entry(GArray *table_data,
>> +    uint8_t serialization_action,
>> +    uint8_t instruction,
>> +    uint8_t flags,
>> +    uint8_t register_bit_width,
> 
> maybe make it width in bytes, then you do not need a switch.

I can make it bytes, but the switch is still needed as the corresponding field is an encoding (ie 
1,2,3,4 vs 1, 2, 4, 8).

> 
>> +    uint64_t register_address,
>> +    uint64_t value,
>> +    uint64_t mask)
>> +{
>> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
>> +    struct AcpiGenericAddress gas;
>> +
>> +    /* Serialization Action */
>> +    build_append_int_noprefix(table_data, serialization_action, 1);
>> +    /* Instruction */
>> +    build_append_int_noprefix(table_data, instruction         , 1);
>> +    /* Flags */
>> +    build_append_int_noprefix(table_data, flags               , 1);
>> +    /* Reserved */
>> +    build_append_int_noprefix(table_data, 0                   , 1);
>> +    /* Register Region */
>> +    gas.space_id = AML_SYSTEM_MEMORY;
>> +    gas.bit_width = register_bit_width;
>> +    gas.bit_offset = 0;
>> +    switch (register_bit_width) {
>> +    case 8:
>> +        gas.access_width = 1;
>> +        break;
>> +    case 16:
>> +        gas.access_width = 2;
>> +        break;
>> +    case 32:
>> +        gas.access_width = 3;
>> +        break;
>> +    case 64:
>> +        gas.access_width = 4;
>> +        break;
>> +    default:
>> +        gas.access_width = 0;
>> +        break;
> 
> does this default actually work?
I actually have no idea. But given that this is driven by code in this file, I'll set an assert 
there instead; this should never happen.

> 
>> +    }
>> +    gas.address = register_address;
>> +    build_append_gas_from_struct(table_data, &gas);
>> +    /* Value */
>> +    build_append_int_noprefix(table_data, value  , 8);
>> +    /* Mask */
>> +    build_append_int_noprefix(table_data, mask   , 8);
>> +}
>> +
>> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
>> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
>> +    const char *oem_id, const char *oem_table_id)
>> +{
>> +    GArray *table_instruction_data;
>> +    unsigned action;
>> +    pcibus_t bar0, bar1;
>> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
>> +                        .oem_table_id = oem_table_id };
>> +
>> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
>> +    trace_acpi_erst_pci_bar_0(bar0);
>> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
> 
> why do we need the cast here?
> Also assignment at declaration point will be cleaner, won't it?
Corrected; cast removed and assigned at declaration.
> 
>> +    trace_acpi_erst_pci_bar_1(bar1);
> 
> bar1 seems unused ... why do we bother with it just for trace?
Corrected; bar1 not needed.

> 
>> +
>> +#define MASK8  0x00000000000000FFUL
>> +#define MASK16 0x000000000000FFFFUL
>> +#define MASK32 0x00000000FFFFFFFFUL
>> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
> 
> 
> can't we just pass # of bytes?
I could, but then I'd need a switch statement to convert to one of these masks. The full mask is 
embedded in the generic address structure.

Perhaps in the wrapper I can use width in bytes and the switch statement can producing the encoding 
and the mask...
> 
>> +
>> +    /*
>> +     * Serialization Action Table
>> +     * The serialization action table must be generated first
>> +     * so that its size can be known in order to populate the
>> +     * Instruction Entry Count field.
>> +     */
>> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
>> +
>> +    /* Serialization Instruction Entries */
>> +    action = ACTION_BEGIN_WRITE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_BEGIN_READ_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_BEGIN_CLEAR_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_END_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_SET_RECORD_OFFSET;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER      , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_EXECUTE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_CHECK_BUSY_STATUS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER_VALUE , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
>> +
>> +    action = ACTION_GET_COMMAND_STATUS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
>> +
>> +    action = ACTION_GET_RECORD_IDENTIFIER;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    action = ACTION_SET_RECORD_IDENTIFIER;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER      , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_GET_RECORD_COUNT;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 32,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>> +
>> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>> +    build_serialization_instruction_entry(table_instruction_data,
>> +        action, INST_READ_REGISTER       , 0, 64,
>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>> +
>> +    /* Serialization Header */
>> +    acpi_table_begin(&table, table_data);
>> +
>> +    /* Serialization Header Size */
>> +    build_append_int_noprefix(table_data, 48, 4);
>> +
>> +    /* Reserved */
>> +    build_append_int_noprefix(table_data,  0, 4);
>> +
>> +    /*
>> +     * Instruction Entry Count
>> +     * Each instruction entry is 32 bytes
>> +     */
> 
> assert that it's a multiple of 32 maybe
done!

> 
>> +    build_append_int_noprefix(table_data,
>> +        (table_instruction_data->len / 32), 4);
>> +
>> +    /* Serialization Instruction Entries */
>> +    g_array_append_vals(table_data, table_instruction_data->data,
>> +        table_instruction_data->len);
>> +    g_array_free(table_instruction_data, TRUE);
>> +
>> +    acpi_table_end(linker, &table);
>> +}
>> +
>>   /*******************************************************************/
>>   /*******************************************************************/
>>   static int erst_post_load(void *opaque, int version_id)
>> -- 
>> 1.8.3.1
>
Michael S. Tsirkin Dec. 14, 2021, 12:05 a.m. UTC | #5
On Mon, Dec 13, 2021 at 04:02:26PM -0600, Eric DeVolder wrote:
> Michael,
> Thanks for reviewing! Inline responses below.
> eric
> 
> On 12/12/21 16:56, Michael S. Tsirkin wrote:
> > On Thu, Dec 09, 2021 at 12:57:31PM -0500, Eric DeVolder wrote:
> > > This builds the ACPI ERST table to inform OSPM how to communicate
> > > with the acpi-erst device.
> > > 
> > > Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> > > ---
> > >   hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > >   1 file changed, 241 insertions(+)
> > > 
> > > diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
> > > index 81f5435..753425a 100644
> > > --- a/hw/acpi/erst.c
> > > +++ b/hw/acpi/erst.c
> > > @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
> > >       .endianness = DEVICE_NATIVE_ENDIAN,
> > >   };
> > > +
> > > +/*******************************************************************/
> > > +/*******************************************************************/
> > > +
> > > +/* ACPI 4.0: Table 17-19 Serialization Instructions */
> > > +#define INST_READ_REGISTER                 0x00
> > > +#define INST_READ_REGISTER_VALUE           0x01
> > > +#define INST_WRITE_REGISTER                0x02
> > > +#define INST_WRITE_REGISTER_VALUE          0x03
> > > +#define INST_NOOP                          0x04
> > > +#define INST_LOAD_VAR1                     0x05
> > > +#define INST_LOAD_VAR2                     0x06
> > > +#define INST_STORE_VAR1                    0x07
> > > +#define INST_ADD                           0x08
> > > +#define INST_SUBTRACT                      0x09
> > > +#define INST_ADD_VALUE                     0x0A
> > > +#define INST_SUBTRACT_VALUE                0x0B
> > > +#define INST_STALL                         0x0C
> > > +#define INST_STALL_WHILE_TRUE              0x0D
> > > +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
> > > +#define INST_GOTO                          0x0F
> > > +#define INST_SET_SRC_ADDRESS_BASE          0x10
> > > +#define INST_SET_DST_ADDRESS_BASE          0x11
> > > +#define INST_MOVE_DATA                     0x12
> > > +
> > 
> > I would create wrappers for the specific uses that we do have. Leave the
> > rest alone.
> > You just use 4 of these right? And a bunch of parameters are
> > always the same. E.g. flags always 0, address always same.
> 
> If I understand correctly, I think you are suggesting making wrappers for
> the 4 in use (ie WRITE, WRITE_VALUE, READ, READ_VALUE). in an effort to
> simplify/hide the underlying call to
> build_serialization_instruction_entry(). OK, I'll do that.
> 
> > 
> > > +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
> > > +static void build_serialization_instruction_entry(GArray *table_data,
> > > +    uint8_t serialization_action,
> > > +    uint8_t instruction,
> > > +    uint8_t flags,
> > > +    uint8_t register_bit_width,
> > 
> > maybe make it width in bytes, then you do not need a switch.
> 
> I can make it bytes, but the switch is still needed as the corresponding
> field is an encoding (ie 1,2,3,4 vs 1, 2, 4, 8).

So it's ffs basically?

> > 
> > > +    uint64_t register_address,
> > > +    uint64_t value,
> > > +    uint64_t mask)
> > > +{
> > > +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
> > > +    struct AcpiGenericAddress gas;
> > > +
> > > +    /* Serialization Action */
> > > +    build_append_int_noprefix(table_data, serialization_action, 1);
> > > +    /* Instruction */
> > > +    build_append_int_noprefix(table_data, instruction         , 1);
> > > +    /* Flags */
> > > +    build_append_int_noprefix(table_data, flags               , 1);
> > > +    /* Reserved */
> > > +    build_append_int_noprefix(table_data, 0                   , 1);
> > > +    /* Register Region */
> > > +    gas.space_id = AML_SYSTEM_MEMORY;
> > > +    gas.bit_width = register_bit_width;
> > > +    gas.bit_offset = 0;
> > > +    switch (register_bit_width) {
> > > +    case 8:
> > > +        gas.access_width = 1;
> > > +        break;
> > > +    case 16:
> > > +        gas.access_width = 2;
> > > +        break;
> > > +    case 32:
> > > +        gas.access_width = 3;
> > > +        break;
> > > +    case 64:
> > > +        gas.access_width = 4;
> > > +        break;
> > > +    default:
> > > +        gas.access_width = 0;
> > > +        break;
> > 
> > does this default actually work?
> I actually have no idea. But given that this is driven by code in this file,
> I'll set an assert there instead; this should never happen.
> 
> > 
> > > +    }
> > > +    gas.address = register_address;
> > > +    build_append_gas_from_struct(table_data, &gas);
> > > +    /* Value */
> > > +    build_append_int_noprefix(table_data, value  , 8);
> > > +    /* Mask */
> > > +    build_append_int_noprefix(table_data, mask   , 8);
> > > +}
> > > +
> > > +/* ACPI 4.0: 17.4.1 Serialization Action Table */
> > > +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
> > > +    const char *oem_id, const char *oem_table_id)
> > > +{
> > > +    GArray *table_instruction_data;
> > > +    unsigned action;
> > > +    pcibus_t bar0, bar1;
> > > +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
> > > +                        .oem_table_id = oem_table_id };
> > > +
> > > +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
> > > +    trace_acpi_erst_pci_bar_0(bar0);
> > > +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
> > 
> > why do we need the cast here?
> > Also assignment at declaration point will be cleaner, won't it?
> Corrected; cast removed and assigned at declaration.
> > 
> > > +    trace_acpi_erst_pci_bar_1(bar1);
> > 
> > bar1 seems unused ... why do we bother with it just for trace?
> Corrected; bar1 not needed.
> 
> > 
> > > +
> > > +#define MASK8  0x00000000000000FFUL
> > > +#define MASK16 0x000000000000FFFFUL
> > > +#define MASK32 0x00000000FFFFFFFFUL
> > > +#define MASK64 0xFFFFFFFFFFFFFFFFUL
> > 
> > 
> > can't we just pass # of bytes?
> I could, but then I'd need a switch statement to convert to one of these
> masks. The full mask is embedded in the generic address structure.
> 
> Perhaps in the wrapper I can use width in bytes and the switch statement can
> producing the encoding and the mask...

we don't need a switch, mask is just (1ULL << (bytes * BITS_PER_BYTE - 1) << 1) - 1
encoding is just ffs(bytes)


> > 
> > > +
> > > +    /*
> > > +     * Serialization Action Table
> > > +     * The serialization action table must be generated first
> > > +     * so that its size can be known in order to populate the
> > > +     * Instruction Entry Count field.
> > > +     */
> > > +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
> > > +
> > > +    /* Serialization Instruction Entries */
> > > +    action = ACTION_BEGIN_WRITE_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_BEGIN_READ_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_BEGIN_CLEAR_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_END_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_SET_RECORD_OFFSET;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER      , 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_EXECUTE_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_CHECK_BUSY_STATUS;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER_VALUE , 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
> > > +
> > > +    action = ACTION_GET_COMMAND_STATUS;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
> > > +
> > > +    action = ACTION_GET_RECORD_IDENTIFIER;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 64,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> > > +
> > > +    action = ACTION_SET_RECORD_IDENTIFIER;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER      , 0, 64,
> > > +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_GET_RECORD_COUNT;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> > > +
> > > +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +
> > > +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 64,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> > > +
> > > +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 64,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> > > +
> > > +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 32,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> > > +
> > > +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> > > +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> > > +    build_serialization_instruction_entry(table_instruction_data,
> > > +        action, INST_READ_REGISTER       , 0, 64,
> > > +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> > > +
> > > +    /* Serialization Header */
> > > +    acpi_table_begin(&table, table_data);
> > > +
> > > +    /* Serialization Header Size */
> > > +    build_append_int_noprefix(table_data, 48, 4);
> > > +
> > > +    /* Reserved */
> > > +    build_append_int_noprefix(table_data,  0, 4);
> > > +
> > > +    /*
> > > +     * Instruction Entry Count
> > > +     * Each instruction entry is 32 bytes
> > > +     */
> > 
> > assert that it's a multiple of 32 maybe
> done!
> 
> > 
> > > +    build_append_int_noprefix(table_data,
> > > +        (table_instruction_data->len / 32), 4);
> > > +
> > > +    /* Serialization Instruction Entries */
> > > +    g_array_append_vals(table_data, table_instruction_data->data,
> > > +        table_instruction_data->len);
> > > +    g_array_free(table_instruction_data, TRUE);
> > > +
> > > +    acpi_table_end(linker, &table);
> > > +}
> > > +
> > >   /*******************************************************************/
> > >   /*******************************************************************/
> > >   static int erst_post_load(void *opaque, int version_id)
> > > -- 
> > > 1.8.3.1
> >
Ani Sinha Dec. 14, 2021, 2:58 a.m. UTC | #6
On Tue, Dec 14, 2021 at 2:57 AM Eric DeVolder <eric.devolder@oracle.com> wrote:
>
> Hi Ani,
> inline response below.
> Eric
>
> On 12/12/21 07:43, Ani Sinha wrote:
> > .
> >
> > On Thu, Dec 9, 2021 at 11:28 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
> >>
> >> This builds the ACPI ERST table to inform OSPM how to communicate
> >> with the acpi-erst device.
> >
> > This patch starts in the middle of pci device code addition, between
> > erst_reg_ops and erst_post_load. I do not like this :(
>
> Below you suggest moving the contents of this patch to the bottom of erst.c.
> Before I do that, consider moving the contents to the top of the file instead, I believe that would
> address the concerns cited here, and it would allow for the last line of the file to be the
> type_init(), like other files.
>
> I'll move it, just let me know if top or bottom.

Moving to the top is fine.

> Thanks!
> eric
>
>
> >
> >>
> >> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> >> ---
> >>   hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >>   1 file changed, 241 insertions(+)
> >>
> >> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
> >> index 81f5435..753425a 100644
> >> --- a/hw/acpi/erst.c
> >> +++ b/hw/acpi/erst.c
> >> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
> >>       .endianness = DEVICE_NATIVE_ENDIAN,
> >>   };
> >>
> >> +
> >> +/*******************************************************************/
> >> +/*******************************************************************/
> >> +
> >> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
> >> +#define INST_READ_REGISTER                 0x00
> >> +#define INST_READ_REGISTER_VALUE           0x01
> >> +#define INST_WRITE_REGISTER                0x02
> >> +#define INST_WRITE_REGISTER_VALUE          0x03
> >> +#define INST_NOOP                          0x04
> >> +#define INST_LOAD_VAR1                     0x05
> >> +#define INST_LOAD_VAR2                     0x06
> >> +#define INST_STORE_VAR1                    0x07
> >> +#define INST_ADD                           0x08
> >> +#define INST_SUBTRACT                      0x09
> >> +#define INST_ADD_VALUE                     0x0A
> >> +#define INST_SUBTRACT_VALUE                0x0B
> >> +#define INST_STALL                         0x0C
> >> +#define INST_STALL_WHILE_TRUE              0x0D
> >> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
> >> +#define INST_GOTO                          0x0F
> >> +#define INST_SET_SRC_ADDRESS_BASE          0x10
> >> +#define INST_SET_DST_ADDRESS_BASE          0x11
> >> +#define INST_MOVE_DATA                     0x12
> >
> > I prefer these definitions to come at the top of the file along with
> > other definitions.
> >
> >> +
> >> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
> >> +static void build_serialization_instruction_entry(GArray *table_data,
> >
> > This function and buiild_erst() can come at the end of erst.c. They go
> > together and are doing a common but different operation from the
> > operations of the pci device - building the erst table. Hence, ther
> > code should be separate from pci device code. A new file would be an
> > overkill at this state IMHO but in the future if erst table generation
> > code gains more weight, it can be split into two files.
> >
> >> +    uint8_t serialization_action,
> >> +    uint8_t instruction,
> >> +    uint8_t flags,
> >> +    uint8_t register_bit_width,
> >> +    uint64_t register_address,
> >> +    uint64_t value,
> >> +    uint64_t mask)
> >> +{
> >> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
> >> +    struct AcpiGenericAddress gas;
> >> +
> >> +    /* Serialization Action */
> >> +    build_append_int_noprefix(table_data, serialization_action, 1);
> >> +    /* Instruction */
> >> +    build_append_int_noprefix(table_data, instruction         , 1);
> >> +    /* Flags */
> >> +    build_append_int_noprefix(table_data, flags               , 1);
> >> +    /* Reserved */
> >> +    build_append_int_noprefix(table_data, 0                   , 1);
> >> +    /* Register Region */
> >> +    gas.space_id = AML_SYSTEM_MEMORY;
> >> +    gas.bit_width = register_bit_width;
> >> +    gas.bit_offset = 0;
> >> +    switch (register_bit_width) {
> >> +    case 8:
> >> +        gas.access_width = 1;
> >> +        break;
> >> +    case 16:
> >> +        gas.access_width = 2;
> >> +        break;
> >> +    case 32:
> >> +        gas.access_width = 3;
> >> +        break;
> >> +    case 64:
> >> +        gas.access_width = 4;
> >> +        break;
> >> +    default:
> >> +        gas.access_width = 0;
> >> +        break;
> >> +    }
> >> +    gas.address = register_address;
> >> +    build_append_gas_from_struct(table_data, &gas);
> >> +    /* Value */
> >> +    build_append_int_noprefix(table_data, value  , 8);
> >> +    /* Mask */
> >> +    build_append_int_noprefix(table_data, mask   , 8);
> >> +}
> >> +
> >> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
> >> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
> >> +    const char *oem_id, const char *oem_table_id)
> >> +{
> >> +    GArray *table_instruction_data;
> >> +    unsigned action;
> >> +    pcibus_t bar0, bar1;
> >> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
> >> +                        .oem_table_id = oem_table_id };
> >> +
> >> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
> >> +    trace_acpi_erst_pci_bar_0(bar0);
> >> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
> >> +    trace_acpi_erst_pci_bar_1(bar1);
> >> +
> >> +#define MASK8  0x00000000000000FFUL
> >> +#define MASK16 0x000000000000FFFFUL
> >> +#define MASK32 0x00000000FFFFFFFFUL
> >> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
> >> +
> >> +    /*
> >> +     * Serialization Action Table
> >> +     * The serialization action table must be generated first
> >> +     * so that its size can be known in order to populate the
> >> +     * Instruction Entry Count field.
> >> +     */
> >> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
> >> +
> >> +    /* Serialization Instruction Entries */
> >> +    action = ACTION_BEGIN_WRITE_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_BEGIN_READ_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_BEGIN_CLEAR_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_END_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_SET_RECORD_OFFSET;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER      , 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_EXECUTE_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_CHECK_BUSY_STATUS;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER_VALUE , 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
> >> +
> >> +    action = ACTION_GET_COMMAND_STATUS;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
> >> +
> >> +    action = ACTION_GET_RECORD_IDENTIFIER;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 64,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >> +
> >> +    action = ACTION_SET_RECORD_IDENTIFIER;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER      , 0, 64,
> >> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_GET_RECORD_COUNT;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >> +
> >> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +
> >> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 64,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >> +
> >> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 64,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >> +
> >> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 32,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >> +
> >> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >> +    build_serialization_instruction_entry(table_instruction_data,
> >> +        action, INST_READ_REGISTER       , 0, 64,
> >> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >> +
> >> +    /* Serialization Header */
> >> +    acpi_table_begin(&table, table_data);
> >> +
> >> +    /* Serialization Header Size */
> >> +    build_append_int_noprefix(table_data, 48, 4);
> >> +
> >> +    /* Reserved */
> >> +    build_append_int_noprefix(table_data,  0, 4);
> >> +
> >> +    /*
> >> +     * Instruction Entry Count
> >> +     * Each instruction entry is 32 bytes
> >> +     */
> >> +    build_append_int_noprefix(table_data,
> >> +        (table_instruction_data->len / 32), 4);
> >> +
> >> +    /* Serialization Instruction Entries */
> >> +    g_array_append_vals(table_data, table_instruction_data->data,
> >> +        table_instruction_data->len);
> >> +    g_array_free(table_instruction_data, TRUE);
> >> +
> >> +    acpi_table_end(linker, &table);
> >> +}
> >> +
> >>   /*******************************************************************/
> >>   /*******************************************************************/
> >>   static int erst_post_load(void *opaque, int version_id)
> >> --
> >> 1.8.3.1
> >>
Eric DeVolder Dec. 14, 2021, 6:12 p.m. UTC | #7
Ani, one quick question below.
eric

On 12/13/21 20:58, Ani Sinha wrote:
> On Tue, Dec 14, 2021 at 2:57 AM Eric DeVolder <eric.devolder@oracle.com> wrote:
>>
>> Hi Ani,
>> inline response below.
>> Eric
>>
>> On 12/12/21 07:43, Ani Sinha wrote:
>>> .
>>>
>>> On Thu, Dec 9, 2021 at 11:28 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
>>>>
>>>> This builds the ACPI ERST table to inform OSPM how to communicate
>>>> with the acpi-erst device.
>>>
>>> This patch starts in the middle of pci device code addition, between
>>> erst_reg_ops and erst_post_load. I do not like this :(
>>
>> Below you suggest moving the contents of this patch to the bottom of erst.c.
>> Before I do that, consider moving the contents to the top of the file instead, I believe that would
>> address the concerns cited here, and it would allow for the last line of the file to be the
>> type_init(), like other files.
>>
>> I'll move it, just let me know if top or bottom.
> 
> Moving to the top is fine.
I've moved this to the top. The question is if you prefer this be integrated into the main erst.c 
patch, or still separated out?
thanks!
eric

> 
>> Thanks!
>> eric
>>
>>
>>>
>>>>
>>>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
>>>> ---
>>>>    hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>    1 file changed, 241 insertions(+)
>>>>
>>>> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
>>>> index 81f5435..753425a 100644
>>>> --- a/hw/acpi/erst.c
>>>> +++ b/hw/acpi/erst.c
>>>> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
>>>>        .endianness = DEVICE_NATIVE_ENDIAN,
>>>>    };
>>>>
>>>> +
>>>> +/*******************************************************************/
>>>> +/*******************************************************************/
>>>> +
>>>> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
>>>> +#define INST_READ_REGISTER                 0x00
>>>> +#define INST_READ_REGISTER_VALUE           0x01
>>>> +#define INST_WRITE_REGISTER                0x02
>>>> +#define INST_WRITE_REGISTER_VALUE          0x03
>>>> +#define INST_NOOP                          0x04
>>>> +#define INST_LOAD_VAR1                     0x05
>>>> +#define INST_LOAD_VAR2                     0x06
>>>> +#define INST_STORE_VAR1                    0x07
>>>> +#define INST_ADD                           0x08
>>>> +#define INST_SUBTRACT                      0x09
>>>> +#define INST_ADD_VALUE                     0x0A
>>>> +#define INST_SUBTRACT_VALUE                0x0B
>>>> +#define INST_STALL                         0x0C
>>>> +#define INST_STALL_WHILE_TRUE              0x0D
>>>> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
>>>> +#define INST_GOTO                          0x0F
>>>> +#define INST_SET_SRC_ADDRESS_BASE          0x10
>>>> +#define INST_SET_DST_ADDRESS_BASE          0x11
>>>> +#define INST_MOVE_DATA                     0x12
>>>
>>> I prefer these definitions to come at the top of the file along with
>>> other definitions.
>>>
>>>> +
>>>> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
>>>> +static void build_serialization_instruction_entry(GArray *table_data,
>>>
>>> This function and buiild_erst() can come at the end of erst.c. They go
>>> together and are doing a common but different operation from the
>>> operations of the pci device - building the erst table. Hence, ther
>>> code should be separate from pci device code. A new file would be an
>>> overkill at this state IMHO but in the future if erst table generation
>>> code gains more weight, it can be split into two files.
>>>
>>>> +    uint8_t serialization_action,
>>>> +    uint8_t instruction,
>>>> +    uint8_t flags,
>>>> +    uint8_t register_bit_width,
>>>> +    uint64_t register_address,
>>>> +    uint64_t value,
>>>> +    uint64_t mask)
>>>> +{
>>>> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
>>>> +    struct AcpiGenericAddress gas;
>>>> +
>>>> +    /* Serialization Action */
>>>> +    build_append_int_noprefix(table_data, serialization_action, 1);
>>>> +    /* Instruction */
>>>> +    build_append_int_noprefix(table_data, instruction         , 1);
>>>> +    /* Flags */
>>>> +    build_append_int_noprefix(table_data, flags               , 1);
>>>> +    /* Reserved */
>>>> +    build_append_int_noprefix(table_data, 0                   , 1);
>>>> +    /* Register Region */
>>>> +    gas.space_id = AML_SYSTEM_MEMORY;
>>>> +    gas.bit_width = register_bit_width;
>>>> +    gas.bit_offset = 0;
>>>> +    switch (register_bit_width) {
>>>> +    case 8:
>>>> +        gas.access_width = 1;
>>>> +        break;
>>>> +    case 16:
>>>> +        gas.access_width = 2;
>>>> +        break;
>>>> +    case 32:
>>>> +        gas.access_width = 3;
>>>> +        break;
>>>> +    case 64:
>>>> +        gas.access_width = 4;
>>>> +        break;
>>>> +    default:
>>>> +        gas.access_width = 0;
>>>> +        break;
>>>> +    }
>>>> +    gas.address = register_address;
>>>> +    build_append_gas_from_struct(table_data, &gas);
>>>> +    /* Value */
>>>> +    build_append_int_noprefix(table_data, value  , 8);
>>>> +    /* Mask */
>>>> +    build_append_int_noprefix(table_data, mask   , 8);
>>>> +}
>>>> +
>>>> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
>>>> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
>>>> +    const char *oem_id, const char *oem_table_id)
>>>> +{
>>>> +    GArray *table_instruction_data;
>>>> +    unsigned action;
>>>> +    pcibus_t bar0, bar1;
>>>> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
>>>> +                        .oem_table_id = oem_table_id };
>>>> +
>>>> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
>>>> +    trace_acpi_erst_pci_bar_0(bar0);
>>>> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
>>>> +    trace_acpi_erst_pci_bar_1(bar1);
>>>> +
>>>> +#define MASK8  0x00000000000000FFUL
>>>> +#define MASK16 0x000000000000FFFFUL
>>>> +#define MASK32 0x00000000FFFFFFFFUL
>>>> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
>>>> +
>>>> +    /*
>>>> +     * Serialization Action Table
>>>> +     * The serialization action table must be generated first
>>>> +     * so that its size can be known in order to populate the
>>>> +     * Instruction Entry Count field.
>>>> +     */
>>>> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
>>>> +
>>>> +    /* Serialization Instruction Entries */
>>>> +    action = ACTION_BEGIN_WRITE_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_BEGIN_READ_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_BEGIN_CLEAR_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_END_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_SET_RECORD_OFFSET;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER      , 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_EXECUTE_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_CHECK_BUSY_STATUS;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER_VALUE , 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
>>>> +
>>>> +    action = ACTION_GET_COMMAND_STATUS;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
>>>> +
>>>> +    action = ACTION_GET_RECORD_IDENTIFIER;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 64,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>>>> +
>>>> +    action = ACTION_SET_RECORD_IDENTIFIER;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER      , 0, 64,
>>>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_GET_RECORD_COUNT;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>>>> +
>>>> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +
>>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 64,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>>>> +
>>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 64,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>>>> +
>>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 32,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
>>>> +
>>>> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
>>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
>>>> +    build_serialization_instruction_entry(table_instruction_data,
>>>> +        action, INST_READ_REGISTER       , 0, 64,
>>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
>>>> +
>>>> +    /* Serialization Header */
>>>> +    acpi_table_begin(&table, table_data);
>>>> +
>>>> +    /* Serialization Header Size */
>>>> +    build_append_int_noprefix(table_data, 48, 4);
>>>> +
>>>> +    /* Reserved */
>>>> +    build_append_int_noprefix(table_data,  0, 4);
>>>> +
>>>> +    /*
>>>> +     * Instruction Entry Count
>>>> +     * Each instruction entry is 32 bytes
>>>> +     */
>>>> +    build_append_int_noprefix(table_data,
>>>> +        (table_instruction_data->len / 32), 4);
>>>> +
>>>> +    /* Serialization Instruction Entries */
>>>> +    g_array_append_vals(table_data, table_instruction_data->data,
>>>> +        table_instruction_data->len);
>>>> +    g_array_free(table_instruction_data, TRUE);
>>>> +
>>>> +    acpi_table_end(linker, &table);
>>>> +}
>>>> +
>>>>    /*******************************************************************/
>>>>    /*******************************************************************/
>>>>    static int erst_post_load(void *opaque, int version_id)
>>>> --
>>>> 1.8.3.1
>>>>
Ani Sinha Dec. 15, 2021, 3:22 a.m. UTC | #8
On Tue, Dec 14, 2021 at 11:42 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
>
> Ani, one quick question below.
> eric
>
> On 12/13/21 20:58, Ani Sinha wrote:
> > On Tue, Dec 14, 2021 at 2:57 AM Eric DeVolder <eric.devolder@oracle.com> wrote:
> >>
> >> Hi Ani,
> >> inline response below.
> >> Eric
> >>
> >> On 12/12/21 07:43, Ani Sinha wrote:
> >>> .
> >>>
> >>> On Thu, Dec 9, 2021 at 11:28 PM Eric DeVolder <eric.devolder@oracle.com> wrote:
> >>>>
> >>>> This builds the ACPI ERST table to inform OSPM how to communicate
> >>>> with the acpi-erst device.
> >>>
> >>> This patch starts in the middle of pci device code addition, between
> >>> erst_reg_ops and erst_post_load. I do not like this :(
> >>
> >> Below you suggest moving the contents of this patch to the bottom of erst.c.
> >> Before I do that, consider moving the contents to the top of the file instead, I believe that would
> >> address the concerns cited here, and it would allow for the last line of the file to be the
> >> type_init(), like other files.
> >>
> >> I'll move it, just let me know if top or bottom.
> >
> > Moving to the top is fine.
> I've moved this to the top. The question is if you prefer this be integrated into the main erst.c
> patch, or still separated out?

you can keep this separate no problem. Then you can incorporate mine
and michael's suggestions into it.

> thanks!
> eric
>
> >
> >> Thanks!
> >> eric
> >>
> >>
> >>>
> >>>>
> >>>> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com>
> >>>> ---
> >>>>    hw/acpi/erst.c | 241 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >>>>    1 file changed, 241 insertions(+)
> >>>>
> >>>> diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
> >>>> index 81f5435..753425a 100644
> >>>> --- a/hw/acpi/erst.c
> >>>> +++ b/hw/acpi/erst.c
> >>>> @@ -711,6 +711,247 @@ static const MemoryRegionOps erst_reg_ops = {
> >>>>        .endianness = DEVICE_NATIVE_ENDIAN,
> >>>>    };
> >>>>
> >>>> +
> >>>> +/*******************************************************************/
> >>>> +/*******************************************************************/
> >>>> +
> >>>> +/* ACPI 4.0: Table 17-19 Serialization Instructions */
> >>>> +#define INST_READ_REGISTER                 0x00
> >>>> +#define INST_READ_REGISTER_VALUE           0x01
> >>>> +#define INST_WRITE_REGISTER                0x02
> >>>> +#define INST_WRITE_REGISTER_VALUE          0x03
> >>>> +#define INST_NOOP                          0x04
> >>>> +#define INST_LOAD_VAR1                     0x05
> >>>> +#define INST_LOAD_VAR2                     0x06
> >>>> +#define INST_STORE_VAR1                    0x07
> >>>> +#define INST_ADD                           0x08
> >>>> +#define INST_SUBTRACT                      0x09
> >>>> +#define INST_ADD_VALUE                     0x0A
> >>>> +#define INST_SUBTRACT_VALUE                0x0B
> >>>> +#define INST_STALL                         0x0C
> >>>> +#define INST_STALL_WHILE_TRUE              0x0D
> >>>> +#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
> >>>> +#define INST_GOTO                          0x0F
> >>>> +#define INST_SET_SRC_ADDRESS_BASE          0x10
> >>>> +#define INST_SET_DST_ADDRESS_BASE          0x11
> >>>> +#define INST_MOVE_DATA                     0x12
> >>>
> >>> I prefer these definitions to come at the top of the file along with
> >>> other definitions.
> >>>
> >>>> +
> >>>> +/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
> >>>> +static void build_serialization_instruction_entry(GArray *table_data,
> >>>
> >>> This function and buiild_erst() can come at the end of erst.c. They go
> >>> together and are doing a common but different operation from the
> >>> operations of the pci device - building the erst table. Hence, ther
> >>> code should be separate from pci device code. A new file would be an
> >>> overkill at this state IMHO but in the future if erst table generation
> >>> code gains more weight, it can be split into two files.
> >>>
> >>>> +    uint8_t serialization_action,
> >>>> +    uint8_t instruction,
> >>>> +    uint8_t flags,
> >>>> +    uint8_t register_bit_width,
> >>>> +    uint64_t register_address,
> >>>> +    uint64_t value,
> >>>> +    uint64_t mask)
> >>>> +{
> >>>> +    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
> >>>> +    struct AcpiGenericAddress gas;
> >>>> +
> >>>> +    /* Serialization Action */
> >>>> +    build_append_int_noprefix(table_data, serialization_action, 1);
> >>>> +    /* Instruction */
> >>>> +    build_append_int_noprefix(table_data, instruction         , 1);
> >>>> +    /* Flags */
> >>>> +    build_append_int_noprefix(table_data, flags               , 1);
> >>>> +    /* Reserved */
> >>>> +    build_append_int_noprefix(table_data, 0                   , 1);
> >>>> +    /* Register Region */
> >>>> +    gas.space_id = AML_SYSTEM_MEMORY;
> >>>> +    gas.bit_width = register_bit_width;
> >>>> +    gas.bit_offset = 0;
> >>>> +    switch (register_bit_width) {
> >>>> +    case 8:
> >>>> +        gas.access_width = 1;
> >>>> +        break;
> >>>> +    case 16:
> >>>> +        gas.access_width = 2;
> >>>> +        break;
> >>>> +    case 32:
> >>>> +        gas.access_width = 3;
> >>>> +        break;
> >>>> +    case 64:
> >>>> +        gas.access_width = 4;
> >>>> +        break;
> >>>> +    default:
> >>>> +        gas.access_width = 0;
> >>>> +        break;
> >>>> +    }
> >>>> +    gas.address = register_address;
> >>>> +    build_append_gas_from_struct(table_data, &gas);
> >>>> +    /* Value */
> >>>> +    build_append_int_noprefix(table_data, value  , 8);
> >>>> +    /* Mask */
> >>>> +    build_append_int_noprefix(table_data, mask   , 8);
> >>>> +}
> >>>> +
> >>>> +/* ACPI 4.0: 17.4.1 Serialization Action Table */
> >>>> +void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
> >>>> +    const char *oem_id, const char *oem_table_id)
> >>>> +{
> >>>> +    GArray *table_instruction_data;
> >>>> +    unsigned action;
> >>>> +    pcibus_t bar0, bar1;
> >>>> +    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
> >>>> +                        .oem_table_id = oem_table_id };
> >>>> +
> >>>> +    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
> >>>> +    trace_acpi_erst_pci_bar_0(bar0);
> >>>> +    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
> >>>> +    trace_acpi_erst_pci_bar_1(bar1);
> >>>> +
> >>>> +#define MASK8  0x00000000000000FFUL
> >>>> +#define MASK16 0x000000000000FFFFUL
> >>>> +#define MASK32 0x00000000FFFFFFFFUL
> >>>> +#define MASK64 0xFFFFFFFFFFFFFFFFUL
> >>>> +
> >>>> +    /*
> >>>> +     * Serialization Action Table
> >>>> +     * The serialization action table must be generated first
> >>>> +     * so that its size can be known in order to populate the
> >>>> +     * Instruction Entry Count field.
> >>>> +     */
> >>>> +    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
> >>>> +
> >>>> +    /* Serialization Instruction Entries */
> >>>> +    action = ACTION_BEGIN_WRITE_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_BEGIN_READ_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_BEGIN_CLEAR_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_END_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_SET_RECORD_OFFSET;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER      , 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_EXECUTE_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_CHECK_BUSY_STATUS;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER_VALUE , 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
> >>>> +
> >>>> +    action = ACTION_GET_COMMAND_STATUS;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
> >>>> +
> >>>> +    action = ACTION_GET_RECORD_IDENTIFIER;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 64,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >>>> +
> >>>> +    action = ACTION_SET_RECORD_IDENTIFIER;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER      , 0, 64,
> >>>> +        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_GET_RECORD_COUNT;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >>>> +
> >>>> +    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +
> >>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 64,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >>>> +
> >>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 64,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >>>> +
> >>>> +    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 32,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
> >>>> +
> >>>> +    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_WRITE_REGISTER_VALUE, 0, 32,
> >>>> +        bar0 + ERST_ACTION_OFFSET, action, MASK8);
> >>>> +    build_serialization_instruction_entry(table_instruction_data,
> >>>> +        action, INST_READ_REGISTER       , 0, 64,
> >>>> +        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
> >>>> +
> >>>> +    /* Serialization Header */
> >>>> +    acpi_table_begin(&table, table_data);
> >>>> +
> >>>> +    /* Serialization Header Size */
> >>>> +    build_append_int_noprefix(table_data, 48, 4);
> >>>> +
> >>>> +    /* Reserved */
> >>>> +    build_append_int_noprefix(table_data,  0, 4);
> >>>> +
> >>>> +    /*
> >>>> +     * Instruction Entry Count
> >>>> +     * Each instruction entry is 32 bytes
> >>>> +     */
> >>>> +    build_append_int_noprefix(table_data,
> >>>> +        (table_instruction_data->len / 32), 4);
> >>>> +
> >>>> +    /* Serialization Instruction Entries */
> >>>> +    g_array_append_vals(table_data, table_instruction_data->data,
> >>>> +        table_instruction_data->len);
> >>>> +    g_array_free(table_instruction_data, TRUE);
> >>>> +
> >>>> +    acpi_table_end(linker, &table);
> >>>> +}
> >>>> +
> >>>>    /*******************************************************************/
> >>>>    /*******************************************************************/
> >>>>    static int erst_post_load(void *opaque, int version_id)
> >>>> --
> >>>> 1.8.3.1
> >>>>
diff mbox series

Patch

diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c
index 81f5435..753425a 100644
--- a/hw/acpi/erst.c
+++ b/hw/acpi/erst.c
@@ -711,6 +711,247 @@  static const MemoryRegionOps erst_reg_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
+
+/*******************************************************************/
+/*******************************************************************/
+
+/* ACPI 4.0: Table 17-19 Serialization Instructions */
+#define INST_READ_REGISTER                 0x00
+#define INST_READ_REGISTER_VALUE           0x01
+#define INST_WRITE_REGISTER                0x02
+#define INST_WRITE_REGISTER_VALUE          0x03
+#define INST_NOOP                          0x04
+#define INST_LOAD_VAR1                     0x05
+#define INST_LOAD_VAR2                     0x06
+#define INST_STORE_VAR1                    0x07
+#define INST_ADD                           0x08
+#define INST_SUBTRACT                      0x09
+#define INST_ADD_VALUE                     0x0A
+#define INST_SUBTRACT_VALUE                0x0B
+#define INST_STALL                         0x0C
+#define INST_STALL_WHILE_TRUE              0x0D
+#define INST_SKIP_NEXT_INSTRUCTION_IF_TRUE 0x0E
+#define INST_GOTO                          0x0F
+#define INST_SET_SRC_ADDRESS_BASE          0x10
+#define INST_SET_DST_ADDRESS_BASE          0x11
+#define INST_MOVE_DATA                     0x12
+
+/* ACPI 4.0: 17.4.1.2 Serialization Instruction Entries */
+static void build_serialization_instruction_entry(GArray *table_data,
+    uint8_t serialization_action,
+    uint8_t instruction,
+    uint8_t flags,
+    uint8_t register_bit_width,
+    uint64_t register_address,
+    uint64_t value,
+    uint64_t mask)
+{
+    /* ACPI 4.0: Table 17-18 Serialization Instruction Entry */
+    struct AcpiGenericAddress gas;
+
+    /* Serialization Action */
+    build_append_int_noprefix(table_data, serialization_action, 1);
+    /* Instruction */
+    build_append_int_noprefix(table_data, instruction         , 1);
+    /* Flags */
+    build_append_int_noprefix(table_data, flags               , 1);
+    /* Reserved */
+    build_append_int_noprefix(table_data, 0                   , 1);
+    /* Register Region */
+    gas.space_id = AML_SYSTEM_MEMORY;
+    gas.bit_width = register_bit_width;
+    gas.bit_offset = 0;
+    switch (register_bit_width) {
+    case 8:
+        gas.access_width = 1;
+        break;
+    case 16:
+        gas.access_width = 2;
+        break;
+    case 32:
+        gas.access_width = 3;
+        break;
+    case 64:
+        gas.access_width = 4;
+        break;
+    default:
+        gas.access_width = 0;
+        break;
+    }
+    gas.address = register_address;
+    build_append_gas_from_struct(table_data, &gas);
+    /* Value */
+    build_append_int_noprefix(table_data, value  , 8);
+    /* Mask */
+    build_append_int_noprefix(table_data, mask   , 8);
+}
+
+/* ACPI 4.0: 17.4.1 Serialization Action Table */
+void build_erst(GArray *table_data, BIOSLinker *linker, Object *erst_dev,
+    const char *oem_id, const char *oem_table_id)
+{
+    GArray *table_instruction_data;
+    unsigned action;
+    pcibus_t bar0, bar1;
+    AcpiTable table = { .sig = "ERST", .rev = 1, .oem_id = oem_id,
+                        .oem_table_id = oem_table_id };
+
+    bar0 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 0);
+    trace_acpi_erst_pci_bar_0(bar0);
+    bar1 = (pcibus_t)pci_get_bar_addr(PCI_DEVICE(erst_dev), 1);
+    trace_acpi_erst_pci_bar_1(bar1);
+
+#define MASK8  0x00000000000000FFUL
+#define MASK16 0x000000000000FFFFUL
+#define MASK32 0x00000000FFFFFFFFUL
+#define MASK64 0xFFFFFFFFFFFFFFFFUL
+
+    /*
+     * Serialization Action Table
+     * The serialization action table must be generated first
+     * so that its size can be known in order to populate the
+     * Instruction Entry Count field.
+     */
+    table_instruction_data = g_array_new(FALSE, FALSE, sizeof(char));
+
+    /* Serialization Instruction Entries */
+    action = ACTION_BEGIN_WRITE_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_BEGIN_READ_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_BEGIN_CLEAR_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_END_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_SET_RECORD_OFFSET;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER      , 0, 32,
+        bar0 + ERST_VALUE_OFFSET , 0, MASK32);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_EXECUTE_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_VALUE_OFFSET , ERST_EXECUTE_OPERATION_MAGIC, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_CHECK_BUSY_STATUS;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER_VALUE , 0, 32,
+        bar0 + ERST_VALUE_OFFSET, 0x01, MASK8);
+
+    action = ACTION_GET_COMMAND_STATUS;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 32,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK8);
+
+    action = ACTION_GET_RECORD_IDENTIFIER;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 64,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
+
+    action = ACTION_SET_RECORD_IDENTIFIER;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER      , 0, 64,
+        bar0 + ERST_VALUE_OFFSET , 0, MASK64);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_GET_RECORD_COUNT;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 32,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
+
+    action = ACTION_BEGIN_DUMMY_WRITE_OPERATION;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+
+    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 64,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
+
+    action = ACTION_GET_ERROR_LOG_ADDRESS_LENGTH;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 64,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
+
+    action = ACTION_GET_ERROR_LOG_ADDRESS_RANGE_ATTRIBUTES;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 32,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK32);
+
+    action = ACTION_GET_EXECUTE_OPERATION_TIMINGS;
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_WRITE_REGISTER_VALUE, 0, 32,
+        bar0 + ERST_ACTION_OFFSET, action, MASK8);
+    build_serialization_instruction_entry(table_instruction_data,
+        action, INST_READ_REGISTER       , 0, 64,
+        bar0 + ERST_VALUE_OFFSET, 0, MASK64);
+
+    /* Serialization Header */
+    acpi_table_begin(&table, table_data);
+
+    /* Serialization Header Size */
+    build_append_int_noprefix(table_data, 48, 4);
+
+    /* Reserved */
+    build_append_int_noprefix(table_data,  0, 4);
+
+    /*
+     * Instruction Entry Count
+     * Each instruction entry is 32 bytes
+     */
+    build_append_int_noprefix(table_data,
+        (table_instruction_data->len / 32), 4);
+
+    /* Serialization Instruction Entries */
+    g_array_append_vals(table_data, table_instruction_data->data,
+        table_instruction_data->len);
+    g_array_free(table_instruction_data, TRUE);
+
+    acpi_table_end(linker, &table);
+}
+
 /*******************************************************************/
 /*******************************************************************/
 static int erst_post_load(void *opaque, int version_id)