Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
authorPeter Maydell <peter.maydell@linaro.org>
Thu, 4 Jun 2015 17:32:44 +0000 (18:32 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Thu, 4 Jun 2015 17:33:24 +0000 (18:33 +0100)
pc, acpi, virtio, tpm

This includes pxb support by Marcel, as well as multiple enhancements all over
the place.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
# gpg: Signature made Thu Jun  4 11:51:02 2015 BST using RSA key ID D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"

* remotes/mst/tags/for_upstream: (28 commits)
  vhost: logs sharing
  hw/acpi: piix4_pm_init(): take fw_cfg object no more
  hw/acpi: move "etc/system-states" fw_cfg file from PIIX4 to core
  hw/acpi: acpi_pm1_cnt_init(): take "disable_s3" and "disable_s4"
  pc-dimm: don't assert if pc-dimm alignment != hotpluggable mem range size
  docs: Add PXB documentation
  apci: fix PXB behaviour if used with unsupported BIOS
  hw/pxb: add numa_node parameter
  hw/pci: add support for NUMA nodes
  hw/pxb: add map_irq func
  hw/pci: inform bios if the system has extra pci root buses
  hw/pci: introduce PCI Expander Bridge (PXB)
  hw/pci: removed 'rootbus nr is 0' assumption from qmp_pci_query
  hw/acpi: remove from root bus 0 the crs resources used by other buses.
  hw/acpi: add _CRS method for extra root busses
  hw/apci: add _PRT method for extra PCI root busses
  hw/acpi: add support for i440fx 'snooping' root busses
  hw/pci: extend PCI config access to support devices behind PXB
  hw/i386: query only for q35/pc when looking for pci host bridge
  hw/pci: made pci_bus_num a PCIBusClass method
  ...

Conflicts:
hw/i386/pc_piix.c

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
1  2 
hw/i386/acpi-build.c
hw/i386/pc.c
hw/i386/pc_piix.c
hw/isa/lpc_ich9.c
hw/pci/pci.c
include/hw/i386/pc.h
include/hw/pci/pci.h
include/sysemu/sysemu.h

@@@ -596,9 -615,292 +615,293 @@@ static void build_append_pci_bus_device
          }
      }
      aml_append(parent_scope, method);
 +    qobject_decref(bsel);
  }
  
+ /*
+  * 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 = aml_package(4);
+     aml_append(pkg, aml_int(0));
+     aml_append(pkg, aml_int(0));
+     aml_append(pkg, aml_name("%s", link_name));
+     aml_append(pkg, aml_int(0));
+     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(void)
+ {
+     Aml *method, *while_ctx, *pin, *res;
+     method = aml_method("_PRT", 0);
+     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)), slot));
+         /* lnk_idx = (slot + pin) & 3 */
+         aml_append(while_ctx,
+                    aml_store(aml_and(aml_add(pin, slot), aml_int(3)), 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));
+         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)),
+                       aml_index(route, aml_int(0))));
+         /* route[1] = pin & 3 */
+         aml_append(while_ctx,
+             aml_store(aml_and(pin, aml_int(3)), 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);
+ }
+ 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_with_free_func(crs_range_free);
+     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, false);
+ }
+ static Aml *build_crs(PCIHostState *host,
+                       GPtrArray *io_ranges, GPtrArray *mem_ranges)
+ {
+     Aml *crs = aml_resource_template();
+     uint8_t max_bus = pci_bus_num(host->bus);
+     uint8_t type;
+     int devfn;
+     for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
+         int i;
+         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) {
+                 aml_append(crs,
+                     aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
+                                 AML_POS_DECODE, AML_ENTIRE_RANGE,
+                                 0,
+                                 range_base,
+                                 range_limit,
+                                 0,
+                                 range_limit - range_base + 1));
+                 crs_range_insert(io_ranges, range_base, range_limit);
+             } else { /* "memory" */
+                 aml_append(crs,
+                     aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
+                                      AML_MAX_FIXED, AML_NON_CACHEABLE,
+                                      AML_READ_WRITE,
+                                      0,
+                                      range_base,
+                                      range_limit,
+                                      0,
+                                      range_limit - range_base + 1));
+                 crs_range_insert(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) {
+                 aml_append(crs,
+                            aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
+                                        AML_POS_DECODE, AML_ENTIRE_RANGE,
+                                        0,
+                                        range_base,
+                                        range_limit,
+                                        0,
+                                        range_limit - range_base + 1));
+                 crs_range_insert(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) {
+                 aml_append(crs,
+                            aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
+                                             AML_MAX_FIXED, AML_NON_CACHEABLE,
+                                             AML_READ_WRITE,
+                                             0,
+                                             range_base,
+                                             range_limit,
+                                             0,
+                                             range_limit - range_base + 1));
+                 crs_range_insert(mem_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) {
+                 aml_append(crs,
+                            aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
+                                             AML_MAX_FIXED, AML_NON_CACHEABLE,
+                                             AML_READ_WRITE,
+                                             0,
+                                             range_base,
+                                             range_limit,
+                                             0,
+                                             range_limit - range_base + 1));
+                 crs_range_insert(mem_ranges, range_base, range_limit);
+             }
+         }
+     }
+     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_ssdt(GArray *table_data, GArray *linker,
             AcpiCpuInfo *cpu, AcpiPmInfo *pm, AcpiMiscInfo *misc,
diff --cc hw/i386/pc.c
Simple merge
@@@ -283,11 -283,11 +282,11 @@@ static void pc_init1(MachineState *mach
          DeviceState *piix4_pm;
          I2CBus *smbus;
  
 -        smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
 +        smi_irq = qemu_allocate_irq(pc_acpi_smi_interrupt, first_cpu, 0);
          /* TODO: Populate SPD eeprom data.  */
          smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
 -                              gsi[9], *smi_irq,
 +                              gsi[9], smi_irq,
-                               kvm_enabled(), fw_cfg, &piix4_pm);
+                               kvm_enabled(), &piix4_pm);
          smbus_eeprom_init(smbus, 8, NULL, 0);
  
          object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP,
Simple merge
diff --cc hw/pci/pci.c
Simple merge
Simple merge
Simple merge
Simple merge