[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 07/24] hw: acpi: Generalize AML build routines
On Mon, 5 Nov 2018 02:40:30 +0100 Samuel Ortiz <sameo@xxxxxxxxxxxxxxx> wrote: > From: Yang Zhong <yang.zhong@xxxxxxxxx> > > Most of the AML build routines under acpi-build are not even > architecture specific. They can be moved to the more generic hw/acpi > folder where they could be shared across machine types and > architectures. I'd prefer if won't pull into aml-build PCI specific headers, Suggest to create hw/acpi/pci.c and move generic PCI related code there, with corresponding header the would export API (preferably without PCI dependencies in it) Also patch is too big and does too much at a time. Here I'd suggest to split it in smaller parts to make it more digestible 1. split it in 3 parts * MCFG * CRS * PTR 2. mcfg between x86 and ARM look pretty much the same with ARM open codding bus number calculation and missing migration hack * a patch to make bus number calculation in ARM the same as x86 * a patch to bring migration hack (dummy MCFG table in case it's disabled) it's questionable if we actually need it in generic, we most likely need it for legacy machines that predate resizable MemeoryRegion, but we probably don't need it for later machines as problem doesn't exists there. So it might be better to push hack out from generic code to a legacy caller and keep generic MCFG clean. (this patch might be better at the beginning of the series as it might affect acpi test results, and might need an update to reference tables I don't really sure) * at this point arm and x86 impl. would be the same so a patch to move mcfg build routine to a generic place and replace x86/arm with a single impl. * a patch to convert mcfg build routine to build_append_int_noprefix() API and drop AcpiTableMcfg structure > Reviewed-by: Philippe Mathieu-Daudé <philmd@xxxxxxxxxx> > Tested-by: Philippe Mathieu-Daudé <philmd@xxxxxxxxxx> > Signed-off-by: Yang Zhong <yang.zhong@xxxxxxxxx> > --- > include/hw/acpi/aml-build.h | 25 ++ > hw/acpi/aml-build.c | 498 ++++++++++++++++++++++++++++++++++ > hw/arm/virt-acpi-build.c | 4 +- > hw/i386/acpi-build.c | 518 +----------------------------------- > 4 files changed, 528 insertions(+), 517 deletions(-) > > diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h > index a2ef8b6f31..4f678c45a5 100644 > --- a/include/hw/acpi/aml-build.h > +++ b/include/hw/acpi/aml-build.h > @@ -3,6 +3,7 @@ > > #include "hw/acpi/acpi-defs.h" > #include "hw/acpi/bios-linker-loader.h" > +#include "hw/pci/pcie_host.h" > > /* Reserve RAM space for tables: add another order of magnitude. */ > #define ACPI_BUILD_TABLE_MAX_SIZE 0x200000 > @@ -223,6 +224,21 @@ struct AcpiBuildTables { > BIOSLinker *linker; > } AcpiBuildTables; > > +typedef struct AcpiMcfgInfo { > + uint64_t mcfg_base; > + uint32_t mcfg_size; > +} AcpiMcfgInfo; > + > +typedef struct CrsRangeEntry { > + uint64_t base; > + uint64_t limit; > +} CrsRangeEntry; > + > +typedef struct CrsRangeSet { > + GPtrArray *io_ranges; > + GPtrArray *mem_ranges; > + GPtrArray *mem_64bit_ranges; > +} CrsRangeSet; > /** I'd prefer not to put these into aml-build.h, it's supposed to host ACPI spec primitives mostly so I'd suggest to move these to acpi-defs.h or PCI specific acpi header > * init_aml_allocator: > * > @@ -389,6 +405,15 @@ void acpi_align_size(GArray *blob, unsigned align); > void acpi_add_table(GArray *table_offsets, GArray *table_data); > void acpi_build_tables_init(AcpiBuildTables *tables); > void acpi_build_tables_cleanup(AcpiBuildTables *tables, bool mfre); > +Aml *build_osc_method(void); > +void build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info); > +Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi); > +Aml *build_prt(bool is_pci0_prt); > +void crs_range_set_init(CrsRangeSet *range_set); > +Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set); > +void crs_replace_with_free_ranges(GPtrArray *ranges, > + uint64_t start, uint64_t end); > +void crs_range_set_free(CrsRangeSet *range_set); > void > build_rsdp_rsdt(GArray *table_data, > BIOSLinker *linker, unsigned rsdt_tbl_offset); > diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c > index 8c2388274c..d3242c6b31 100644 > --- a/hw/acpi/aml-build.c > +++ b/hw/acpi/aml-build.c > @@ -25,6 +25,10 @@ > #include "qemu/bswap.h" > #include "qemu/bitops.h" > #include "sysemu/numa.h" > +#include "hw/pci/pci.h" > +#include "hw/pci/pci_bus.h" > +#include "qemu/range.h" > +#include "hw/pci/pci_bridge.h" > > static GArray *build_alloc_array(void) > { > @@ -1597,6 +1601,500 @@ void acpi_build_tables_cleanup(AcpiBuildTables > *tables, bool mfre) > g_array_free(tables->vmgenid, mfre); > } > > +static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t > limit) > +{ > + CrsRangeEntry *entry; > + > + entry = g_malloc(sizeof(*entry)); > + entry->base = base; > + entry->limit = limit; > + > + g_ptr_array_add(ranges, entry); > +} > + > +static void crs_range_free(gpointer data) > +{ > + CrsRangeEntry *entry = (CrsRangeEntry *)data; > + g_free(entry); > +} > + > +void crs_range_set_init(CrsRangeSet *range_set) > +{ > + range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free); > + range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); > + range_set->mem_64bit_ranges = > + g_ptr_array_new_with_free_func(crs_range_free); > +} > + > +void crs_range_set_free(CrsRangeSet *range_set) > +{ > + g_ptr_array_free(range_set->io_ranges, true); > + g_ptr_array_free(range_set->mem_ranges, true); > + g_ptr_array_free(range_set->mem_64bit_ranges, true); > +} > + > +static gint crs_range_compare(gconstpointer a, gconstpointer b) > +{ > + CrsRangeEntry *entry_a = *(CrsRangeEntry **)a; > + CrsRangeEntry *entry_b = *(CrsRangeEntry **)b; > + > + return (int64_t)entry_a->base - (int64_t)entry_b->base; > +} > + > +/* > + * crs_replace_with_free_ranges - given the 'used' ranges within [start - > end] > + * interval, computes the 'free' ranges from the same interval. > + * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function > + * will return { [base - a1], [a2 - b1], [b2 - limit] }. > + */ > +void crs_replace_with_free_ranges(GPtrArray *ranges, > + uint64_t start, uint64_t end) > +{ > + GPtrArray *free_ranges = g_ptr_array_new(); > + uint64_t free_base = start; > + int i; > + > + g_ptr_array_sort(ranges, crs_range_compare); > + for (i = 0; i < ranges->len; i++) { > + CrsRangeEntry *used = g_ptr_array_index(ranges, i); > + > + if (free_base < used->base) { > + crs_range_insert(free_ranges, free_base, used->base - 1); > + } > + > + free_base = used->limit + 1; > + } > + > + if (free_base < end) { > + crs_range_insert(free_ranges, free_base, end); > + } > + > + g_ptr_array_set_size(ranges, 0); > + for (i = 0; i < free_ranges->len; i++) { > + g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i)); > + } > + > + g_ptr_array_free(free_ranges, true); > +} > + > +/* > + * crs_range_merge - merges adjacent ranges in the given array. > + * Array elements are deleted and replaced with the merged ranges. > + */ > +static void crs_range_merge(GPtrArray *range) > +{ > + GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free); > + CrsRangeEntry *entry; > + uint64_t range_base, range_limit; > + int i; > + > + if (!range->len) { > + return; > + } > + > + g_ptr_array_sort(range, crs_range_compare); > + > + entry = g_ptr_array_index(range, 0); > + range_base = entry->base; > + range_limit = entry->limit; > + for (i = 1; i < range->len; i++) { > + entry = g_ptr_array_index(range, i); > + if (entry->base - 1 == range_limit) { > + range_limit = entry->limit; > + } else { > + crs_range_insert(tmp, range_base, range_limit); > + range_base = entry->base; > + range_limit = entry->limit; > + } > + } > + crs_range_insert(tmp, range_base, range_limit); > + > + g_ptr_array_set_size(range, 0); > + for (i = 0; i < tmp->len; i++) { > + entry = g_ptr_array_index(tmp, i); > + crs_range_insert(range, entry->base, entry->limit); > + } > + g_ptr_array_free(tmp, true); > +} > + > +Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) > +{ > + Aml *crs = aml_resource_template(); > + CrsRangeSet temp_range_set; > + CrsRangeEntry *entry; > + uint8_t max_bus = pci_bus_num(host->bus); > + uint8_t type; > + int devfn; > + int i; > + > + crs_range_set_init(&temp_range_set); > + for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) { > + uint64_t range_base, range_limit; > + PCIDevice *dev = host->bus->devices[devfn]; > + > + if (!dev) { > + continue; > + } > + > + for (i = 0; i < PCI_NUM_REGIONS; i++) { > + PCIIORegion *r = &dev->io_regions[i]; > + > + range_base = r->addr; > + range_limit = r->addr + r->size - 1; > + > + /* > + * Work-around for old bioses > + * that do not support multiple root buses > + */ > + if (!range_base || range_base > range_limit) { > + continue; > + } > + > + if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > + crs_range_insert(temp_range_set.io_ranges, > + range_base, range_limit); > + } else { /* "memory" */ > + crs_range_insert(temp_range_set.mem_ranges, > + range_base, range_limit); > + } > + } > + > + type = dev->config[PCI_HEADER_TYPE] & > ~PCI_HEADER_TYPE_MULTI_FUNCTION; > + if (type == PCI_HEADER_TYPE_BRIDGE) { > + uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS]; > + if (subordinate > max_bus) { > + max_bus = subordinate; > + } > + > + range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > + range_limit = pci_bridge_get_limit(dev, > PCI_BASE_ADDRESS_SPACE_IO); > + > + /* > + * Work-around for old bioses > + * that do not support multiple root buses > + */ > + if (range_base && range_base <= range_limit) { > + crs_range_insert(temp_range_set.io_ranges, > + range_base, range_limit); > + } > + > + range_base = > + pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > + range_limit = > + pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > + > + /* > + * Work-around for old bioses > + * that do not support multiple root buses > + */ > + if (range_base && range_base <= range_limit) { > + uint64_t length = range_limit - range_base + 1; > + if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { > + crs_range_insert(temp_range_set.mem_ranges, > + range_base, range_limit); > + } else { > + crs_range_insert(temp_range_set.mem_64bit_ranges, > + range_base, range_limit); > + } > + } > + > + range_base = > + pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > + range_limit = > + pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > + > + /* > + * Work-around for old bioses > + * that do not support multiple root buses > + */ > + if (range_base && range_base <= range_limit) { > + uint64_t length = range_limit - range_base + 1; > + if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { > + crs_range_insert(temp_range_set.mem_ranges, > + range_base, range_limit); > + } else { > + crs_range_insert(temp_range_set.mem_64bit_ranges, > + range_base, range_limit); > + } > + } > + } > + } > + > + crs_range_merge(temp_range_set.io_ranges); > + for (i = 0; i < temp_range_set.io_ranges->len; i++) { > + entry = g_ptr_array_index(temp_range_set.io_ranges, i); > + aml_append(crs, > + aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, > + AML_POS_DECODE, AML_ENTIRE_RANGE, > + 0, entry->base, entry->limit, 0, > + entry->limit - entry->base + 1)); > + crs_range_insert(range_set->io_ranges, entry->base, entry->limit); > + } > + > + crs_range_merge(temp_range_set.mem_ranges); > + for (i = 0; i < temp_range_set.mem_ranges->len; i++) { > + entry = g_ptr_array_index(temp_range_set.mem_ranges, i); > + aml_append(crs, > + aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, > + AML_MAX_FIXED, AML_NON_CACHEABLE, > + AML_READ_WRITE, > + 0, entry->base, entry->limit, 0, > + entry->limit - entry->base + 1)); > + crs_range_insert(range_set->mem_ranges, entry->base, entry->limit); > + } > + > + crs_range_merge(temp_range_set.mem_64bit_ranges); > + for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) { > + entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i); > + aml_append(crs, > + aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, > + AML_MAX_FIXED, AML_NON_CACHEABLE, > + AML_READ_WRITE, > + 0, entry->base, entry->limit, 0, > + entry->limit - entry->base + 1)); > + crs_range_insert(range_set->mem_64bit_ranges, > + entry->base, entry->limit); > + } > + > + crs_range_set_free(&temp_range_set); > + > + aml_append(crs, > + aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, > + 0, > + pci_bus_num(host->bus), > + max_bus, > + 0, > + max_bus - pci_bus_num(host->bus) + 1)); > + > + return crs; > +} > + > +Aml *build_osc_method(void) > +{ > + Aml *if_ctx; > + Aml *if_ctx2; > + Aml *else_ctx; > + Aml *method; > + Aml *a_cwd1 = aml_name("CDW1"); > + Aml *a_ctrl = aml_local(0); > + > + method = aml_method("_OSC", 4, AML_NOTSERIALIZED); > + aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), > "CDW1")); > + > + if_ctx = aml_if(aml_equal( > + aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); > + aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), > "CDW2")); > + aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), > "CDW3")); > + > + aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); > + > + /* > + * Always allow native PME, AER (no dependencies) > + * Allow SHPC (PCI bridges can have SHPC controller) > + */ > + aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); > + > + if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); > + /* Unknown revision */ > + aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); > + aml_append(if_ctx, if_ctx2); > + > + if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); > + /* Capabilities bits were masked */ > + aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); > + aml_append(if_ctx, if_ctx2); > + > + /* Update DWORD3 in the buffer */ > + aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); > + aml_append(method, if_ctx); > + > + else_ctx = aml_else(); > + /* Unrecognized UUID */ > + aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); > + aml_append(method, else_ctx); > + > + aml_append(method, aml_return(aml_arg(3))); > + return method; > +} > + > +void > +build_mcfg(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info) > +{ > + AcpiTableMcfg *mcfg; > + const char *sig; > + int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]); > + > + mcfg = acpi_data_push(table_data, len); > + mcfg->allocation[0].address = cpu_to_le64(info->mcfg_base); > + /* Only a single allocation so no need to play with segments */ > + mcfg->allocation[0].pci_segment = cpu_to_le16(0); > + mcfg->allocation[0].start_bus_number = 0; > + mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->mcfg_size - 1); > + > + /* MCFG is used for ECAM which can be enabled or disabled by guest. > + * To avoid table size changes (which create migration issues), > + * always create the table even if there are no allocations, > + * but set the signature to a reserved value in this case. > + * ACPI spec requires OSPMs to ignore such tables. > + */ > + if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) { > + /* Reserved signature: ignored by OSPM */ > + sig = "QEMU"; > + } else { > + sig = "MCFG"; > + } > + build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL); > +} > + > +Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi) > +{ > + Aml *dev; > + Aml *crs; > + Aml *method; > + uint32_t irqs; > + > + dev = aml_device("%s", name); > + aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F"))); > + aml_append(dev, aml_name_decl("_UID", aml_int(uid))); > + > + crs = aml_resource_template(); > + irqs = gsi; > + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, > + AML_SHARED, &irqs, 1)); > + aml_append(dev, aml_name_decl("_PRS", crs)); > + > + aml_append(dev, aml_name_decl("_CRS", crs)); > + > + /* > + * _DIS can be no-op because the interrupt cannot be disabled. > + */ > + method = aml_method("_DIS", 0, AML_NOTSERIALIZED); > + aml_append(dev, method); > + > + method = aml_method("_SRS", 1, AML_NOTSERIALIZED); > + aml_append(dev, method); > + > + return dev; > +} > + > +/** > + * build_prt_entry: > + * @link_name: link name for PCI route entry > + * > + * build AML package containing a PCI route entry for @link_name > + */ > +static Aml *build_prt_entry(const char *link_name) > +{ > + Aml *a_zero = aml_int(0); > + Aml *pkg = aml_package(4); > + aml_append(pkg, a_zero); > + aml_append(pkg, a_zero); > + aml_append(pkg, aml_name("%s", link_name)); > + aml_append(pkg, a_zero); > + return pkg; > +} > + > +/* > + * initialize_route - Initialize the interrupt routing rule > + * through a specific LINK: > + * if (lnk_idx == idx) > + * route using link 'link_name' > + */ > +static Aml *initialize_route(Aml *route, const char *link_name, > + Aml *lnk_idx, int idx) > +{ > + Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx))); > + Aml *pkg = build_prt_entry(link_name); > + > + aml_append(if_ctx, aml_store(pkg, route)); > + > + return if_ctx; > +} > + > +/* > + * build_prt - Define interrupt rounting rules > + * > + * Returns an array of 128 routes, one for each device, > + * based on device location. > + * The main goal is to equaly distribute the interrupts > + * over the 4 existing ACPI links (works only for i440fx). > + * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]". > + * > + */ > +Aml *build_prt(bool is_pci0_prt) > +{ > + Aml *method, *while_ctx, *pin, *res; > + > + method = aml_method("_PRT", 0, AML_NOTSERIALIZED); > + res = aml_local(0); > + pin = aml_local(1); > + aml_append(method, aml_store(aml_package(128), res)); > + aml_append(method, aml_store(aml_int(0), pin)); > + > + /* while (pin < 128) */ > + while_ctx = aml_while(aml_lless(pin, aml_int(128))); > + { > + Aml *slot = aml_local(2); > + Aml *lnk_idx = aml_local(3); > + Aml *route = aml_local(4); > + > + /* slot = pin >> 2 */ > + aml_append(while_ctx, > + aml_store(aml_shiftright(pin, aml_int(2), NULL), slot)); > + /* lnk_idx = (slot + pin) & 3 */ > + aml_append(while_ctx, > + aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL), > + lnk_idx)); > + > + /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */ > + aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0)); > + if (is_pci0_prt) { > + Aml *if_device_1, *if_pin_4, *else_pin_4; > + > + /* device 1 is the power-management device, needs SCI */ > + if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1))); > + { > + if_pin_4 = aml_if(aml_equal(pin, aml_int(4))); > + { > + aml_append(if_pin_4, > + aml_store(build_prt_entry("LNKS"), route)); > + } > + aml_append(if_device_1, if_pin_4); > + else_pin_4 = aml_else(); > + { > + aml_append(else_pin_4, > + aml_store(build_prt_entry("LNKA"), route)); > + } > + aml_append(if_device_1, else_pin_4); > + } > + aml_append(while_ctx, if_device_1); > + } else { > + aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, > 1)); > + } > + aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2)); > + aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3)); > + > + /* route[0] = 0x[slot]FFFF */ > + aml_append(while_ctx, > + aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), > aml_int(0xFFFF), > + NULL), > + aml_index(route, aml_int(0)))); > + /* route[1] = pin & 3 */ > + aml_append(while_ctx, > + aml_store(aml_and(pin, aml_int(3), NULL), > + aml_index(route, aml_int(1)))); > + /* res[pin] = route */ > + aml_append(while_ctx, aml_store(route, aml_index(res, pin))); > + /* pin++ */ > + aml_append(while_ctx, aml_increment(pin)); > + } > + aml_append(method, while_ctx); > + /* return res*/ > + aml_append(method, aml_return(res)); > + > + return method; > +} > + > /* Build rsdt table */ > void > build_rsdt(GArray *table_data, BIOSLinker *linker, GArray *table_offsets, > diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c > index 261363e20c..c9b4916ba7 100644 > --- a/hw/arm/virt-acpi-build.c > +++ b/hw/arm/virt-acpi-build.c > @@ -545,7 +545,7 @@ build_srat(GArray *table_data, BIOSLinker *linker, > VirtMachineState *vms) > } > > static void > -build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) > +virt_build_mcfg(GArray *table_data, BIOSLinker *linker, VirtMachineState > *vms) > { > AcpiTableMcfg *mcfg; > const MemMapEntry *memmap = vms->memmap; > @@ -790,7 +790,7 @@ void virt_acpi_build(VirtMachineState *vms, > AcpiBuildTables *tables) > build_gtdt(tables_blob, tables->linker, vms); > > acpi_add_table(table_offsets, tables_blob); > - build_mcfg(tables_blob, tables->linker, vms); > + virt_build_mcfg(tables_blob, tables->linker, vms); > > acpi_add_table(table_offsets, tables_blob); > build_spcr(tables_blob, tables->linker, vms); > diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c > index cfc2444d0d..996d8a11dc 100644 > --- a/hw/i386/acpi-build.c > +++ b/hw/i386/acpi-build.c > @@ -27,7 +27,6 @@ > #include "qemu-common.h" > #include "qemu/bitmap.h" > #include "qemu/error-report.h" > -#include "hw/pci/pci.h" > #include "qom/cpu.h" > #include "target/i386/cpu.h" > #include "hw/misc/pvpanic.h" > @@ -53,7 +52,6 @@ > #include "hw/acpi/piix4.h" > #include "hw/acpi/pcihp.h" > #include "hw/i386/ich9.h" > -#include "hw/pci/pci_bus.h" > #include "hw/pci-host/q35.h" > #include "hw/i386/x86-iommu.h" > > @@ -86,11 +84,6 @@ > /* Default IOAPIC ID */ > #define ACPI_BUILD_IOAPIC_ID 0x0 > > -typedef struct AcpiMcfgInfo { > - uint64_t mcfg_base; > - uint32_t mcfg_size; > -} AcpiMcfgInfo; > - > typedef struct AcpiPmInfo { > bool s3_disabled; > bool s4_disabled; > @@ -567,403 +560,6 @@ static void build_append_pci_bus_devices(Aml > *parent_scope, PCIBus *bus, > qobject_unref(bsel); > } > > -/** > - * build_prt_entry: > - * @link_name: link name for PCI route entry > - * > - * build AML package containing a PCI route entry for @link_name > - */ > -static Aml *build_prt_entry(const char *link_name) > -{ > - Aml *a_zero = aml_int(0); > - Aml *pkg = aml_package(4); > - aml_append(pkg, a_zero); > - aml_append(pkg, a_zero); > - aml_append(pkg, aml_name("%s", link_name)); > - aml_append(pkg, a_zero); > - return pkg; > -} > - > -/* > - * initialize_route - Initialize the interrupt routing rule > - * through a specific LINK: > - * if (lnk_idx == idx) > - * route using link 'link_name' > - */ > -static Aml *initialize_route(Aml *route, const char *link_name, > - Aml *lnk_idx, int idx) > -{ > - Aml *if_ctx = aml_if(aml_equal(lnk_idx, aml_int(idx))); > - Aml *pkg = build_prt_entry(link_name); > - > - aml_append(if_ctx, aml_store(pkg, route)); > - > - return if_ctx; > -} > - > -/* > - * build_prt - Define interrupt rounting rules > - * > - * Returns an array of 128 routes, one for each device, > - * based on device location. > - * The main goal is to equaly distribute the interrupts > - * over the 4 existing ACPI links (works only for i440fx). > - * The hash function is (slot + pin) & 3 -> "LNK[D|A|B|C]". > - * > - */ > -static Aml *build_prt(bool is_pci0_prt) > -{ > - Aml *method, *while_ctx, *pin, *res; > - > - method = aml_method("_PRT", 0, AML_NOTSERIALIZED); > - res = aml_local(0); > - pin = aml_local(1); > - aml_append(method, aml_store(aml_package(128), res)); > - aml_append(method, aml_store(aml_int(0), pin)); > - > - /* while (pin < 128) */ > - while_ctx = aml_while(aml_lless(pin, aml_int(128))); > - { > - Aml *slot = aml_local(2); > - Aml *lnk_idx = aml_local(3); > - Aml *route = aml_local(4); > - > - /* slot = pin >> 2 */ > - aml_append(while_ctx, > - aml_store(aml_shiftright(pin, aml_int(2), NULL), slot)); > - /* lnk_idx = (slot + pin) & 3 */ > - aml_append(while_ctx, > - aml_store(aml_and(aml_add(pin, slot, NULL), aml_int(3), NULL), > - lnk_idx)); > - > - /* route[2] = "LNK[D|A|B|C]", selection based on pin % 3 */ > - aml_append(while_ctx, initialize_route(route, "LNKD", lnk_idx, 0)); > - if (is_pci0_prt) { > - Aml *if_device_1, *if_pin_4, *else_pin_4; > - > - /* device 1 is the power-management device, needs SCI */ > - if_device_1 = aml_if(aml_equal(lnk_idx, aml_int(1))); > - { > - if_pin_4 = aml_if(aml_equal(pin, aml_int(4))); > - { > - aml_append(if_pin_4, > - aml_store(build_prt_entry("LNKS"), route)); > - } > - aml_append(if_device_1, if_pin_4); > - else_pin_4 = aml_else(); > - { > - aml_append(else_pin_4, > - aml_store(build_prt_entry("LNKA"), route)); > - } > - aml_append(if_device_1, else_pin_4); > - } > - aml_append(while_ctx, if_device_1); > - } else { > - aml_append(while_ctx, initialize_route(route, "LNKA", lnk_idx, > 1)); > - } > - aml_append(while_ctx, initialize_route(route, "LNKB", lnk_idx, 2)); > - aml_append(while_ctx, initialize_route(route, "LNKC", lnk_idx, 3)); > - > - /* route[0] = 0x[slot]FFFF */ > - aml_append(while_ctx, > - aml_store(aml_or(aml_shiftleft(slot, aml_int(16)), > aml_int(0xFFFF), > - NULL), > - aml_index(route, aml_int(0)))); > - /* route[1] = pin & 3 */ > - aml_append(while_ctx, > - aml_store(aml_and(pin, aml_int(3), NULL), > - aml_index(route, aml_int(1)))); > - /* res[pin] = route */ > - aml_append(while_ctx, aml_store(route, aml_index(res, pin))); > - /* pin++ */ > - aml_append(while_ctx, aml_increment(pin)); > - } > - aml_append(method, while_ctx); > - /* return res*/ > - aml_append(method, aml_return(res)); > - > - return method; > -} > - > -typedef struct CrsRangeEntry { > - uint64_t base; > - uint64_t limit; > -} CrsRangeEntry; > - > -static void crs_range_insert(GPtrArray *ranges, uint64_t base, uint64_t > limit) > -{ > - CrsRangeEntry *entry; > - > - entry = g_malloc(sizeof(*entry)); > - entry->base = base; > - entry->limit = limit; > - > - g_ptr_array_add(ranges, entry); > -} > - > -static void crs_range_free(gpointer data) > -{ > - CrsRangeEntry *entry = (CrsRangeEntry *)data; > - g_free(entry); > -} > - > -typedef struct CrsRangeSet { > - GPtrArray *io_ranges; > - GPtrArray *mem_ranges; > - GPtrArray *mem_64bit_ranges; > - } CrsRangeSet; > - > -static void crs_range_set_init(CrsRangeSet *range_set) > -{ > - range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free); > - range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free); > - range_set->mem_64bit_ranges = > - g_ptr_array_new_with_free_func(crs_range_free); > -} > - > -static void crs_range_set_free(CrsRangeSet *range_set) > -{ > - g_ptr_array_free(range_set->io_ranges, true); > - g_ptr_array_free(range_set->mem_ranges, true); > - g_ptr_array_free(range_set->mem_64bit_ranges, true); > -} > - > -static gint crs_range_compare(gconstpointer a, gconstpointer b) > -{ > - CrsRangeEntry *entry_a = *(CrsRangeEntry **)a; > - CrsRangeEntry *entry_b = *(CrsRangeEntry **)b; > - > - return (int64_t)entry_a->base - (int64_t)entry_b->base; > -} > - > -/* > - * crs_replace_with_free_ranges - given the 'used' ranges within [start - > end] > - * interval, computes the 'free' ranges from the same interval. > - * Example: If the input array is { [a1 - a2],[b1 - b2] }, the function > - * will return { [base - a1], [a2 - b1], [b2 - limit] }. > - */ > -static void crs_replace_with_free_ranges(GPtrArray *ranges, > - uint64_t start, uint64_t end) > -{ > - GPtrArray *free_ranges = g_ptr_array_new(); > - uint64_t free_base = start; > - int i; > - > - g_ptr_array_sort(ranges, crs_range_compare); > - for (i = 0; i < ranges->len; i++) { > - CrsRangeEntry *used = g_ptr_array_index(ranges, i); > - > - if (free_base < used->base) { > - crs_range_insert(free_ranges, free_base, used->base - 1); > - } > - > - free_base = used->limit + 1; > - } > - > - if (free_base < end) { > - crs_range_insert(free_ranges, free_base, end); > - } > - > - g_ptr_array_set_size(ranges, 0); > - for (i = 0; i < free_ranges->len; i++) { > - g_ptr_array_add(ranges, g_ptr_array_index(free_ranges, i)); > - } > - > - g_ptr_array_free(free_ranges, true); > -} > - > -/* > - * crs_range_merge - merges adjacent ranges in the given array. > - * Array elements are deleted and replaced with the merged ranges. > - */ > -static void crs_range_merge(GPtrArray *range) > -{ > - GPtrArray *tmp = g_ptr_array_new_with_free_func(crs_range_free); > - CrsRangeEntry *entry; > - uint64_t range_base, range_limit; > - int i; > - > - if (!range->len) { > - return; > - } > - > - g_ptr_array_sort(range, crs_range_compare); > - > - entry = g_ptr_array_index(range, 0); > - range_base = entry->base; > - range_limit = entry->limit; > - for (i = 1; i < range->len; i++) { > - entry = g_ptr_array_index(range, i); > - if (entry->base - 1 == range_limit) { > - range_limit = entry->limit; > - } else { > - crs_range_insert(tmp, range_base, range_limit); > - range_base = entry->base; > - range_limit = entry->limit; > - } > - } > - crs_range_insert(tmp, range_base, range_limit); > - > - g_ptr_array_set_size(range, 0); > - for (i = 0; i < tmp->len; i++) { > - entry = g_ptr_array_index(tmp, i); > - crs_range_insert(range, entry->base, entry->limit); > - } > - g_ptr_array_free(tmp, true); > -} > - > -static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set) > -{ > - Aml *crs = aml_resource_template(); > - CrsRangeSet temp_range_set; > - CrsRangeEntry *entry; > - uint8_t max_bus = pci_bus_num(host->bus); > - uint8_t type; > - int devfn; > - int i; > - > - crs_range_set_init(&temp_range_set); > - for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) { > - uint64_t range_base, range_limit; > - PCIDevice *dev = host->bus->devices[devfn]; > - > - if (!dev) { > - continue; > - } > - > - for (i = 0; i < PCI_NUM_REGIONS; i++) { > - PCIIORegion *r = &dev->io_regions[i]; > - > - range_base = r->addr; > - range_limit = r->addr + r->size - 1; > - > - /* > - * Work-around for old bioses > - * that do not support multiple root buses > - */ > - if (!range_base || range_base > range_limit) { > - continue; > - } > - > - if (r->type & PCI_BASE_ADDRESS_SPACE_IO) { > - crs_range_insert(temp_range_set.io_ranges, > - range_base, range_limit); > - } else { /* "memory" */ > - crs_range_insert(temp_range_set.mem_ranges, > - range_base, range_limit); > - } > - } > - > - type = dev->config[PCI_HEADER_TYPE] & > ~PCI_HEADER_TYPE_MULTI_FUNCTION; > - if (type == PCI_HEADER_TYPE_BRIDGE) { > - uint8_t subordinate = dev->config[PCI_SUBORDINATE_BUS]; > - if (subordinate > max_bus) { > - max_bus = subordinate; > - } > - > - range_base = pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_IO); > - range_limit = pci_bridge_get_limit(dev, > PCI_BASE_ADDRESS_SPACE_IO); > - > - /* > - * Work-around for old bioses > - * that do not support multiple root buses > - */ > - if (range_base && range_base <= range_limit) { > - crs_range_insert(temp_range_set.io_ranges, > - range_base, range_limit); > - } > - > - range_base = > - pci_bridge_get_base(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > - range_limit = > - pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_SPACE_MEMORY); > - > - /* > - * Work-around for old bioses > - * that do not support multiple root buses > - */ > - if (range_base && range_base <= range_limit) { > - uint64_t length = range_limit - range_base + 1; > - if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { > - crs_range_insert(temp_range_set.mem_ranges, > - range_base, range_limit); > - } else { > - crs_range_insert(temp_range_set.mem_64bit_ranges, > - range_base, range_limit); > - } > - } > - > - range_base = > - pci_bridge_get_base(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > - range_limit = > - pci_bridge_get_limit(dev, PCI_BASE_ADDRESS_MEM_PREFETCH); > - > - /* > - * Work-around for old bioses > - * that do not support multiple root buses > - */ > - if (range_base && range_base <= range_limit) { > - uint64_t length = range_limit - range_base + 1; > - if (range_limit <= UINT32_MAX && length <= UINT32_MAX) { > - crs_range_insert(temp_range_set.mem_ranges, > - range_base, range_limit); > - } else { > - crs_range_insert(temp_range_set.mem_64bit_ranges, > - range_base, range_limit); > - } > - } > - } > - } > - > - crs_range_merge(temp_range_set.io_ranges); > - for (i = 0; i < temp_range_set.io_ranges->len; i++) { > - entry = g_ptr_array_index(temp_range_set.io_ranges, i); > - aml_append(crs, > - aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED, > - AML_POS_DECODE, AML_ENTIRE_RANGE, > - 0, entry->base, entry->limit, 0, > - entry->limit - entry->base + 1)); > - crs_range_insert(range_set->io_ranges, entry->base, entry->limit); > - } > - > - crs_range_merge(temp_range_set.mem_ranges); > - for (i = 0; i < temp_range_set.mem_ranges->len; i++) { > - entry = g_ptr_array_index(temp_range_set.mem_ranges, i); > - aml_append(crs, > - aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, > - AML_MAX_FIXED, AML_NON_CACHEABLE, > - AML_READ_WRITE, > - 0, entry->base, entry->limit, 0, > - entry->limit - entry->base + 1)); > - crs_range_insert(range_set->mem_ranges, entry->base, entry->limit); > - } > - > - crs_range_merge(temp_range_set.mem_64bit_ranges); > - for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) { > - entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i); > - aml_append(crs, > - aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, > - AML_MAX_FIXED, AML_NON_CACHEABLE, > - AML_READ_WRITE, > - 0, entry->base, entry->limit, 0, > - entry->limit - entry->base + 1)); > - crs_range_insert(range_set->mem_64bit_ranges, > - entry->base, entry->limit); > - } > - > - crs_range_set_free(&temp_range_set); > - > - aml_append(crs, > - aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, > - 0, > - pci_bus_num(host->bus), > - max_bus, > - 0, > - max_bus - pci_bus_num(host->bus) + 1)); > - > - return crs; > -} > - > static void build_hpet_aml(Aml *table) > { > Aml *crs; > @@ -1334,37 +930,6 @@ static Aml *build_link_dev(const char *name, uint8_t > uid, Aml *reg) > return dev; > } > > -static Aml *build_gsi_link_dev(const char *name, uint8_t uid, uint8_t gsi) > -{ > - Aml *dev; > - Aml *crs; > - Aml *method; > - uint32_t irqs; > - > - dev = aml_device("%s", name); > - aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C0F"))); > - aml_append(dev, aml_name_decl("_UID", aml_int(uid))); > - > - crs = aml_resource_template(); > - irqs = gsi; > - aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, > - AML_SHARED, &irqs, 1)); > - aml_append(dev, aml_name_decl("_PRS", crs)); > - > - aml_append(dev, aml_name_decl("_CRS", crs)); > - > - /* > - * _DIS can be no-op because the interrupt cannot be disabled. > - */ > - method = aml_method("_DIS", 0, AML_NOTSERIALIZED); > - aml_append(dev, method); > - > - method = aml_method("_SRS", 1, AML_NOTSERIALIZED); > - aml_append(dev, method); > - > - return dev; > -} > - > /* _CRS method - get current settings */ > static Aml *build_iqcr_method(bool is_piix4) > { > @@ -1728,54 +1293,6 @@ static void build_piix4_pci_hotplug(Aml *table) > aml_append(table, scope); > } > > -static Aml *build_q35_osc_method(void) > -{ > - Aml *if_ctx; > - Aml *if_ctx2; > - Aml *else_ctx; > - Aml *method; > - Aml *a_cwd1 = aml_name("CDW1"); > - Aml *a_ctrl = aml_local(0); > - > - method = aml_method("_OSC", 4, AML_NOTSERIALIZED); > - aml_append(method, aml_create_dword_field(aml_arg(3), aml_int(0), > "CDW1")); > - > - if_ctx = aml_if(aml_equal( > - aml_arg(0), aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"))); > - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(4), > "CDW2")); > - aml_append(if_ctx, aml_create_dword_field(aml_arg(3), aml_int(8), > "CDW3")); > - > - aml_append(if_ctx, aml_store(aml_name("CDW3"), a_ctrl)); > - > - /* > - * Always allow native PME, AER (no dependencies) > - * Allow SHPC (PCI bridges can have SHPC controller) > - */ > - aml_append(if_ctx, aml_and(a_ctrl, aml_int(0x1F), a_ctrl)); > - > - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(1)))); > - /* Unknown revision */ > - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x08), a_cwd1)); > - aml_append(if_ctx, if_ctx2); > - > - if_ctx2 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), a_ctrl))); > - /* Capabilities bits were masked */ > - aml_append(if_ctx2, aml_or(a_cwd1, aml_int(0x10), a_cwd1)); > - aml_append(if_ctx, if_ctx2); > - > - /* Update DWORD3 in the buffer */ > - aml_append(if_ctx, aml_store(a_ctrl, aml_name("CDW3"))); > - aml_append(method, if_ctx); > - > - else_ctx = aml_else(); > - /* Unrecognized UUID */ > - aml_append(else_ctx, aml_or(a_cwd1, aml_int(4), a_cwd1)); > - aml_append(method, else_ctx); > - > - aml_append(method, aml_return(aml_arg(3))); > - return method; > -} > - > static void > build_dsdt(GArray *table_data, BIOSLinker *linker, > AcpiPmInfo *pm, AcpiMiscInfo *misc, > @@ -1818,7 +1335,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, > aml_append(dev, aml_name_decl("_CID", aml_eisaid("PNP0A03"))); > aml_append(dev, aml_name_decl("_ADR", aml_int(0))); > aml_append(dev, aml_name_decl("_UID", aml_int(1))); > - aml_append(dev, build_q35_osc_method()); > + aml_append(dev, build_osc_method()); > aml_append(sb_scope, dev); > aml_append(dsdt, sb_scope); > > @@ -1883,7 +1400,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, > aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0A03"))); > aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); > if (pci_bus_is_express(bus)) { > - aml_append(dev, build_q35_osc_method()); > + aml_append(dev, build_osc_method()); > } > > if (numa_node != NUMA_NODE_UNASSIGNED) { > @@ -2370,35 +1887,6 @@ build_srat(GArray *table_data, BIOSLinker *linker, > table_data->len - srat_start, 1, NULL, NULL); > } > > -static void > -build_mcfg_q35(GArray *table_data, BIOSLinker *linker, AcpiMcfgInfo *info) > -{ > - AcpiTableMcfg *mcfg; > - const char *sig; > - int len = sizeof(*mcfg) + 1 * sizeof(mcfg->allocation[0]); > - > - mcfg = acpi_data_push(table_data, len); > - mcfg->allocation[0].address = cpu_to_le64(info->mcfg_base); > - /* Only a single allocation so no need to play with segments */ > - mcfg->allocation[0].pci_segment = cpu_to_le16(0); > - mcfg->allocation[0].start_bus_number = 0; > - mcfg->allocation[0].end_bus_number = PCIE_MMCFG_BUS(info->mcfg_size - 1); > - > - /* MCFG is used for ECAM which can be enabled or disabled by guest. > - * To avoid table size changes (which create migration issues), > - * always create the table even if there are no allocations, > - * but set the signature to a reserved value in this case. > - * ACPI spec requires OSPMs to ignore such tables. > - */ > - if (info->mcfg_base == PCIE_BASE_ADDR_UNMAPPED) { > - /* Reserved signature: ignored by OSPM */ > - sig = "QEMU"; > - } else { > - sig = "MCFG"; > - } > - build_header(linker, table_data, (void *)mcfg, sig, len, 1, NULL, NULL); > -} > - > /* > * VT-d spec 8.1 DMA Remapping Reporting Structure > * (version Oct. 2014 or later) > @@ -2626,7 +2114,7 @@ void acpi_build(AcpiBuildTables *tables, > } > if (acpi_get_mcfg(&mcfg)) { > acpi_add_table(table_offsets, tables_blob); > - build_mcfg_q35(tables_blob, tables->linker, &mcfg); > + build_mcfg(tables_blob, tables->linker, &mcfg); > } > if (x86_iommu_get_default()) { > IommuType IOMMUType = x86_iommu_get_type(); _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |