Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 2 Apr 2018 23:15:32 +0000 (16:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 2 Apr 2018 23:15:32 +0000 (16:15 -0700)
Pull x86 platform updates from Ingo Molnar:
 "The main changes in this cycle were:

   - Add "Jailhouse" hypervisor support (Jan Kiszka)

   - Update DeviceTree support (Ivan Gorinov)

   - Improve DMI date handling (Andy Shevchenko)"

* 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/PCI: Fix a potential regression when using dmi_get_bios_year()
  firmware/dmi_scan: Uninline dmi_get_bios_year() helper
  x86/devicetree: Use CPU description from Device Tree
  of/Documentation: Specify local APIC ID in "reg"
  MAINTAINERS: Add entry for Jailhouse
  x86/jailhouse: Allow to use PCI_MMCONFIG without ACPI
  x86: Consolidate PCI_MMCONFIG configs
  x86: Align x86_64 PCI_MMCONFIG with 32-bit variant
  x86/jailhouse: Enable PCI mmconfig access in inmates
  PCI: Scan all functions when running over Jailhouse
  jailhouse: Provide detection for non-x86 systems
  x86/devicetree: Fix device IRQ settings in DT
  x86/devicetree: Initialize device tree before using it
  pci: Simplify code by using the new dmi_get_bios_year() helper
  ACPI/sleep: Simplify code by using the new dmi_get_bios_year() helper
  x86/pci: Simplify code by using the new dmi_get_bios_year() helper
  dmi: Introduce the dmi_get_bios_year() helper function
  x86/platform/quark: Re-use DEFINE_SHOW_ATTRIBUTE() macro
  x86/platform/atom: Re-use DEFINE_SHOW_ATTRIBUTE() macro

22 files changed:
Documentation/devicetree/bindings/jailhouse.txt [new file with mode: 0644]
Documentation/devicetree/bindings/x86/ce4100.txt
MAINTAINERS
arch/x86/Kconfig
arch/x86/include/asm/jailhouse_para.h
arch/x86/include/asm/pci_x86.h
arch/x86/kernel/Makefile
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/jailhouse.c
arch/x86/pci/acpi.c
arch/x86/pci/direct.c
arch/x86/pci/legacy.c
arch/x86/pci/mmconfig-shared.c
arch/x86/platform/atom/punit_atom_debug.c
arch/x86/platform/intel-quark/imr.c
drivers/acpi/sleep.c
drivers/firmware/dmi_scan.c
drivers/pci/pci.c
drivers/pci/probe.c
include/linux/dmi.h
include/linux/hypervisor.h

diff --git a/Documentation/devicetree/bindings/jailhouse.txt b/Documentation/devicetree/bindings/jailhouse.txt
new file mode 100644 (file)
index 0000000..2901c25
--- /dev/null
@@ -0,0 +1,8 @@
+Jailhouse non-root cell device tree bindings
+--------------------------------------------
+
+When running in a non-root Jailhouse cell (partition), the device tree of this
+platform shall have a top-level "hypervisor" node with the following
+properties:
+
+- compatible = "jailhouse,cell"
index b49ae593a60b1d38020aa0e83526f034e11ed7ff..cd1221bfb53933dec59a2f139d282f96c00d7986 100644 (file)
@@ -7,17 +7,36 @@ Many of the "generic" devices like HPET or IO APIC have the ce4100
 name in their compatible property because they first appeared in this
 SoC.
 
-The CPU node
-------------
-       cpu@0 {
-               device_type = "cpu";
-               compatible = "intel,ce4100";
-               reg = <0>;
-               lapic = <&lapic0>;
+The CPU nodes
+-------------
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       compatible = "intel,ce4100";
+                       reg = <0x00>;
+               };
+
+               cpu@2 {
+                       device_type = "cpu";
+                       compatible = "intel,ce4100";
+                       reg = <0x02>;
+               };
        };
 
-The reg property describes the CPU number. The lapic property points to
-the local APIC timer.
+A "cpu" node describes one logical processor (hardware thread).
+
+Required properties:
+
+- device_type
+       Device type, must be "cpu".
+
+- reg
+       Local APIC ID, the unique number assigned to each processor by
+       system hardware.
 
 The SoC node
 ------------
index e7f482fd73bd848374ddeb249b1d407ad49d980b..689f875b47fa17c414c579889cec55d6817fe18c 100644 (file)
@@ -7534,6 +7534,13 @@ Q:       http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/ix2505v*
 
+JAILHOUSE HYPERVISOR INTERFACE
+M:     Jan Kiszka <jan.kiszka@siemens.com>
+L:     jailhouse-dev@googlegroups.com
+S:     Maintained
+F:     arch/x86/kernel/jailhouse.c
+F:     arch/x86/include/asm/jailhouse_para.h
+
 JC42.4 TEMPERATURE SENSOR DRIVER
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     linux-hwmon@vger.kernel.org
index 518b41b097dc6b7b52ca2120a15bf96030849a71..a0fb8bc346d57ddcc3c6f7a8f757482e8ff10f97 100644 (file)
@@ -2626,8 +2626,10 @@ config PCI_DIRECT
        depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC || PCI_GOMMCONFIG))
 
 config PCI_MMCONFIG
-       def_bool y
-       depends on X86_32 && PCI && (ACPI || SFI) && (PCI_GOMMCONFIG || PCI_GOANY)
+       bool "Support mmconfig PCI config space access" if X86_64
+       default y
+       depends on PCI && (ACPI || SFI || JAILHOUSE_GUEST)
+       depends on X86_64 || (PCI_GOANY || PCI_GOMMCONFIG)
 
 config PCI_OLPC
        def_bool y
@@ -2642,9 +2644,9 @@ config PCI_DOMAINS
        def_bool y
        depends on PCI
 
-config PCI_MMCONFIG
-       bool "Support mmconfig PCI config space access"
-       depends on X86_64 && PCI && ACPI
+config MMCONF_FAM10H
+       def_bool y
+       depends on X86_64 && PCI_MMCONFIG && ACPI
 
 config PCI_CNB20LE_QUIRK
        bool "Read CNB20LE Host Bridge Windows" if EXPERT
index 875b543766892e7686512e864a6ee4e95e04dea3..b885a961a150f079e38d4e5dbb8670ef9fde0b57 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL2.0 */
 
 /*
- * Jailhouse paravirt_ops implementation
+ * Jailhouse paravirt detection
  *
  * Copyright (c) Siemens AG, 2015-2017
  *
index eb66fa9cd0fc6187d55dc0c1a8fb30e5e32687a8..959d618dbb1707fcdda5bd8c17c6082c498a9046 100644 (file)
@@ -151,6 +151,8 @@ extern int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
                               phys_addr_t addr);
 extern int pci_mmconfig_delete(u16 seg, u8 start, u8 end);
 extern struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus);
+extern struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
+                                                       int end, u64 addr);
 
 extern struct list_head pci_mmcfg_list;
 
index 29786c87e864524cc020798a10198a9cc0f3ca0a..73ccf80c09a2da6e4d0f1ee9a0bd84334e764424 100644 (file)
@@ -146,6 +146,6 @@ ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_GART_IOMMU)        += amd_gart_64.o aperture_64.o
        obj-$(CONFIG_CALGARY_IOMMU)     += pci-calgary_64.o tce_64.o
 
-       obj-$(CONFIG_PCI_MMCONFIG)      += mmconf-fam10h_64.o
+       obj-$(CONFIG_MMCONF_FAM10H)     += mmconf-fam10h_64.o
        obj-y                           += vsmp_64.o
 endif
index f0e6456ca7d3cd482893a7d1953aec5d79c4caad..12bc0a1139dac57fefe8b299d1ef9685fa0e3147 100644 (file)
@@ -716,7 +716,7 @@ static void init_amd_k8(struct cpuinfo_x86 *c)
 
 static void init_amd_gh(struct cpuinfo_x86 *c)
 {
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_MMCONF_FAM10H
        /* do this for boot cpu */
        if (c == &boot_cpu_data)
                check_enable_amd_mmconf_dmi();
index 45416826f6eef0ed875b7ed2b74c00232b5b629a..f39f3a06c26fa2c49fb94c59f032013ee122ed1d 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/of_irq.h>
+#include <linux/libfdt.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/of_pci.h>
@@ -130,34 +131,52 @@ static void __init dtb_setup_hpet(void)
 #endif
 }
 
+#ifdef CONFIG_X86_LOCAL_APIC
+
+static void __init dtb_cpu_setup(void)
+{
+       struct device_node *dn;
+       u32 apic_id, version;
+       int ret;
+
+       version = GET_APIC_VERSION(apic_read(APIC_LVR));
+       for_each_node_by_type(dn, "cpu") {
+               ret = of_property_read_u32(dn, "reg", &apic_id);
+               if (ret < 0) {
+                       pr_warn("%pOF: missing local APIC ID\n", dn);
+                       continue;
+               }
+               generic_processor_info(apic_id, version);
+       }
+}
+
 static void __init dtb_lapic_setup(void)
 {
-#ifdef CONFIG_X86_LOCAL_APIC
        struct device_node *dn;
        struct resource r;
+       unsigned long lapic_addr = APIC_DEFAULT_PHYS_BASE;
        int ret;
 
        dn = of_find_compatible_node(NULL, NULL, "intel,ce4100-lapic");
-       if (!dn)
-               return;
-
-       ret = of_address_to_resource(dn, 0, &r);
-       if (WARN_ON(ret))
-               return;
+       if (dn) {
+               ret = of_address_to_resource(dn, 0, &r);
+               if (WARN_ON(ret))
+                       return;
+               lapic_addr = r.start;
+       }
 
        /* Did the boot loader setup the local APIC ? */
        if (!boot_cpu_has(X86_FEATURE_APIC)) {
-               if (apic_force_enable(r.start))
+               if (apic_force_enable(lapic_addr))
                        return;
        }
        smp_found_config = 1;
        pic_mode = 1;
-       register_lapic_address(r.start);
-       generic_processor_info(boot_cpu_physical_apicid,
-                              GET_APIC_VERSION(apic_read(APIC_LVR)));
-#endif
+       register_lapic_address(lapic_addr);
 }
 
+#endif /* CONFIG_X86_LOCAL_APIC */
+
 #ifdef CONFIG_X86_IO_APIC
 static unsigned int ioapic_id;
 
@@ -194,19 +213,22 @@ static struct of_ioapic_type of_ioapic_type[] =
 static int dt_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
                              unsigned int nr_irqs, void *arg)
 {
-       struct of_phandle_args *irq_data = (void *)arg;
+       struct irq_fwspec *fwspec = (struct irq_fwspec *)arg;
        struct of_ioapic_type *it;
        struct irq_alloc_info tmp;
+       int type_index;
 
-       if (WARN_ON(irq_data->args_count < 2))
+       if (WARN_ON(fwspec->param_count < 2))
                return -EINVAL;
-       if (irq_data->args[1] >= ARRAY_SIZE(of_ioapic_type))
+
+       type_index = fwspec->param[1];
+       if (type_index >= ARRAY_SIZE(of_ioapic_type))
                return -EINVAL;
 
-       it = &of_ioapic_type[irq_data->args[1]];
+       it = &of_ioapic_type[type_index];
        ioapic_set_alloc_attr(&tmp, NUMA_NO_NODE, it->trigger, it->polarity);
        tmp.ioapic_id = mpc_ioapic_id(mp_irqdomain_ioapic_idx(domain));
-       tmp.ioapic_pin = irq_data->args[0];
+       tmp.ioapic_pin = fwspec->param[0];
 
        return mp_irqdomain_alloc(domain, virq, nr_irqs, &tmp);
 }
@@ -255,7 +277,10 @@ static void __init dtb_ioapic_setup(void) {}
 
 static void __init dtb_apic_setup(void)
 {
+#ifdef CONFIG_X86_LOCAL_APIC
        dtb_lapic_setup();
+       dtb_cpu_setup();
+#endif
        dtb_ioapic_setup();
 }
 
@@ -270,14 +295,15 @@ static void __init x86_flattree_get_config(void)
 
        map_len = max(PAGE_SIZE - (initial_dtb & ~PAGE_MASK), (u64)128);
 
-       initial_boot_params = dt = early_memremap(initial_dtb, map_len);
-       size = of_get_flat_dt_size();
+       dt = early_memremap(initial_dtb, map_len);
+       size = fdt_totalsize(dt);
        if (map_len < size) {
                early_memunmap(dt, map_len);
-               initial_boot_params = dt = early_memremap(initial_dtb, size);
+               dt = early_memremap(initial_dtb, size);
                map_len = size;
        }
 
+       early_init_dt_verify(dt);
        unflatten_and_copy_device_tree();
        early_memunmap(dt, map_len);
 }
index b68fd895235ace042d11210bc0d8147e3a9842c2..fa183a131edc7b493dd86f47cf637ba42f15d274 100644 (file)
@@ -124,6 +124,14 @@ static int __init jailhouse_pci_arch_init(void)
        if (pcibios_last_bus < 0)
                pcibios_last_bus = 0xff;
 
+#ifdef CONFIG_PCI_MMCONFIG
+       if (setup_data.pci_mmconfig_base) {
+               pci_mmconfig_add(0, 0, pcibios_last_bus,
+                                setup_data.pci_mmconfig_base);
+               pci_mmcfg_arch_init();
+       }
+#endif
+
        return 0;
 }
 
index 7df49c40665ed13315e713621984a10f69dae4c2..5559dcaddd5e0345f50fdc81299a7d9452a79254 100644 (file)
@@ -140,12 +140,10 @@ static const struct dmi_system_id pci_crs_quirks[] __initconst = {
 
 void __init pci_acpi_crs_quirks(void)
 {
-       int year;
+       int year = dmi_get_bios_year();
 
-       if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) {
-               if (iomem_resource.end <= 0xffffffff)
-                       pci_use_crs = false;
-       }
+       if (year >= 0 && year < 2008 && iomem_resource.end <= 0xffffffff)
+               pci_use_crs = false;
 
        dmi_check_system(pci_crs_quirks);
 
index 2d9503323d104f65bca6798badd6e7cdd0a41890..a51074c559824320fffbfefa07c82f55dbc178c6 100644 (file)
@@ -195,14 +195,13 @@ static const struct pci_raw_ops pci_direct_conf2 = {
 static int __init pci_sanity_check(const struct pci_raw_ops *o)
 {
        u32 x = 0;
-       int year, devfn;
+       int devfn;
 
        if (pci_probe & PCI_NO_CHECKS)
                return 1;
        /* Assume Type 1 works for newer systems.
           This handles machines that don't have anything on PCI Bus 0. */
-       dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL);
-       if (year >= 2001)
+       if (dmi_get_bios_year() >= 2001)
                return 1;
 
        for (devfn = 0; devfn < 0x100; devfn++) {
index 1cb01abcb1bee88befdb2fbce8c989104cfa737f..dfbe6ac38830543be4979c9ff0b7dc6eb99346ec 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/init.h>
 #include <linux/export.h>
 #include <linux/pci.h>
+#include <asm/jailhouse_para.h>
 #include <asm/pci_x86.h>
 
 /*
@@ -34,13 +35,14 @@ int __init pci_legacy_init(void)
 
 void pcibios_scan_specific_bus(int busn)
 {
+       int stride = jailhouse_paravirt() ? 1 : 8;
        int devfn;
        u32 l;
 
        if (pci_find_bus(0, busn))
                return;
 
-       for (devfn = 0; devfn < 256; devfn += 8) {
+       for (devfn = 0; devfn < 256; devfn += stride) {
                if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
                    l != 0x0000 && l != 0xffff) {
                        DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
index 96684d0adcf944abbd1d9688d0c1cd90fb2fdf2c..7389db538c304d86611a1da10f1938c40e3a346d 100644 (file)
@@ -94,8 +94,8 @@ static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
        return new;
 }
 
-static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
-                                                       int end, u64 addr)
+struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
+                                                int end, u64 addr)
 {
        struct pci_mmcfg_region *new;
 
@@ -547,19 +547,14 @@ static void __init pci_mmcfg_reject_broken(int early)
 static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
                                        struct acpi_mcfg_allocation *cfg)
 {
-       int year;
-
        if (cfg->address < 0xFFFFFFFF)
                return 0;
 
        if (!strncmp(mcfg->header.oem_id, "SGI", 3))
                return 0;
 
-       if (mcfg->header.revision >= 1) {
-               if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-                   year >= 2010)
-                       return 0;
-       }
+       if ((mcfg->header.revision >= 1) && (dmi_get_bios_year() >= 2010))
+               return 0;
 
        pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
               "is above 4GB, ignored\n", cfg->pci_segment,
index d49d3be8195324a42de6c85657af187e6a5a2d41..034813d4ab1e1a2ff3c1d2c1969a61cfd198a3e6 100644 (file)
@@ -109,18 +109,7 @@ static int punit_dev_state_show(struct seq_file *seq_file, void *unused)
 
        return 0;
 }
-
-static int punit_dev_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, punit_dev_state_show, inode->i_private);
-}
-
-static const struct file_operations punit_dev_state_ops = {
-       .open           = punit_dev_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
 
 static struct dentry *punit_dbg_file;
 
@@ -132,9 +121,9 @@ static int punit_dbgfs_register(struct punit_device *punit_device)
        if (!punit_dbg_file)
                return -ENXIO;
 
-       dev_state = debugfs_create_file("dev_power_state", S_IFREG | S_IRUGO,
+       dev_state = debugfs_create_file("dev_power_state", 0444,
                                        punit_dbg_file, punit_device,
-                                       &punit_dev_state_ops);
+                                       &punit_dev_state_fops);
        if (!dev_state) {
                pr_err("punit_dev_state register failed\n");
                debugfs_remove(punit_dbg_file);
index 17d6d2296e4d8d0b51745b57a10b9256358a7cff..49828c2707ac184f85c14b38138ebc1794b08184 100644 (file)
@@ -224,25 +224,7 @@ static int imr_dbgfs_state_show(struct seq_file *s, void *unused)
        mutex_unlock(&idev->lock);
        return ret;
 }
-
-/**
- * imr_state_open - debugfs open callback.
- *
- * @inode:     pointer to struct inode.
- * @file:      pointer to struct file.
- * @return:    result of single open.
- */
-static int imr_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, imr_dbgfs_state_show, inode->i_private);
-}
-
-static const struct file_operations imr_state_ops = {
-       .open           = imr_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(imr_dbgfs_state);
 
 /**
  * imr_debugfs_register - register debugfs hooks.
@@ -252,8 +234,8 @@ static const struct file_operations imr_state_ops = {
  */
 static int imr_debugfs_register(struct imr_device *idev)
 {
-       idev->file = debugfs_create_file("imr_state", S_IFREG | S_IRUGO, NULL,
-                                        idev, &imr_state_ops);
+       idev->file = debugfs_create_file("imr_state", 0444, NULL, idev,
+                                        &imr_dbgfs_state_fops);
        return PTR_ERR_OR_ZERO(idev->file);
 }
 
index 46cde0912762e5d8d68aaa5611a7eebb9d4caedd..b35923e3a926a4f23a073c37ab6892ecf4a37fee 100644 (file)
@@ -376,12 +376,10 @@ void __init acpi_sleep_no_blacklist(void)
 
 static void __init acpi_sleep_dmi_check(void)
 {
-       int year;
-
        if (ignore_blacklist)
                return;
 
-       if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2012)
+       if (dmi_get_bios_year() >= 2012)
                acpi_nvs_nosave_s3();
 
        dmi_check_system(acpisleep_dmi_table);
index e763e148433115328930debe838a8c2c20da430e..e35c5e04c46adcbdf1a20b3fe5f090b4651a0ee4 100644 (file)
@@ -1004,6 +1004,26 @@ out:
 }
 EXPORT_SYMBOL(dmi_get_date);
 
+/**
+ *     dmi_get_bios_year - get a year out of DMI_BIOS_DATE field
+ *
+ *     Returns year on success, -ENXIO if DMI is not selected,
+ *     or a different negative error code if DMI field is not present
+ *     or not parseable.
+ */
+int dmi_get_bios_year(void)
+{
+       bool exists;
+       int year;
+
+       exists = dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL);
+       if (!exists)
+               return -ENODATA;
+
+       return year ? year : -ERANGE;
+}
+EXPORT_SYMBOL(dmi_get_bios_year);
+
 /**
  *     dmi_walk - Walk the DMI table and get called back for every record
  *     @decode: Callback function
index bd6f156dc3cfa9abc54a8aa0973fe6ffdcdd81fc..99ec0ef5ba8265abc91f402a904690b9bbbf5df6 100644 (file)
@@ -2258,8 +2258,6 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev)
  */
 bool pci_bridge_d3_possible(struct pci_dev *bridge)
 {
-       unsigned int year;
-
        if (!pci_is_pcie(bridge))
                return false;
 
@@ -2287,10 +2285,8 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge)
                 * It should be safe to put PCIe ports from 2015 or newer
                 * to D3.
                 */
-               if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) &&
-                   year >= 2015) {
+               if (dmi_get_bios_year() >= 2015)
                        return true;
-               }
                break;
        }
 
index ef5377438a1e65df31790a61472e34e708a835ab..3c365dc996e71e103bf5891749d52bee1af01f26 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pci-aspm.h>
 #include <linux/aer.h>
 #include <linux/acpi.h>
+#include <linux/hypervisor.h>
 #include <linux/irqdomain.h>
 #include <linux/pm_runtime.h>
 #include "pci.h"
@@ -2518,14 +2519,29 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
 {
        unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
        unsigned int start = bus->busn_res.start;
-       unsigned int devfn, cmax, max = start;
+       unsigned int devfn, fn, cmax, max = start;
        struct pci_dev *dev;
+       int nr_devs;
 
        dev_dbg(&bus->dev, "scanning bus\n");
 
        /* Go find them, Rover! */
-       for (devfn = 0; devfn < 0x100; devfn += 8)
-               pci_scan_slot(bus, devfn);
+       for (devfn = 0; devfn < 256; devfn += 8) {
+               nr_devs = pci_scan_slot(bus, devfn);
+
+               /*
+                * The Jailhouse hypervisor may pass individual functions of a
+                * multi-function device to a guest without passing function 0.
+                * Look for them as well.
+                */
+               if (jailhouse_paravirt() && nr_devs == 0) {
+                       for (fn = 1; fn < 8; fn++) {
+                               dev = pci_scan_single_device(bus, devfn + fn);
+                               if (dev)
+                                       dev->multifunction = 1;
+                       }
+               }
+       }
 
        /* Reserve buses for SR-IOV capability */
        used_buses = pci_iov_bus_range(bus);
index 46e151172d95429f72ff5d6b4252ea8d2d430305..6a86d8db16d9274e3e82ed0522bc47170d4e23cc 100644 (file)
@@ -106,6 +106,7 @@ extern void dmi_scan_machine(void);
 extern void dmi_memdev_walk(void);
 extern void dmi_set_dump_stack_arch_desc(void);
 extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
+extern int dmi_get_bios_year(void);
 extern int dmi_name_in_vendors(const char *str);
 extern int dmi_name_in_serial(const char *str);
 extern int dmi_available;
@@ -133,6 +134,7 @@ static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp)
                *dayp = 0;
        return false;
 }
+static inline int dmi_get_bios_year(void) { return -ENXIO; }
 static inline int dmi_name_in_vendors(const char *s) { return 0; }
 static inline int dmi_name_in_serial(const char *s) { return 0; }
 #define dmi_available 0
index b19563f9a8ebb9c58e115b79fecde5a0167ba0e0..fc08b433c856d38cb374398da7078e305fc85564 100644 (file)
@@ -8,15 +8,28 @@
  */
 
 #ifdef CONFIG_X86
+
+#include <asm/jailhouse_para.h>
 #include <asm/x86_init.h>
+
 static inline void hypervisor_pin_vcpu(int cpu)
 {
        x86_platform.hyper.pin_vcpu(cpu);
 }
-#else
+
+#else /* !CONFIG_X86 */
+
+#include <linux/of.h>
+
 static inline void hypervisor_pin_vcpu(int cpu)
 {
 }
-#endif
+
+static inline bool jailhouse_paravirt(void)
+{
+       return of_find_compatible_node(NULL, NULL, "jailhouse,cell");
+}
+
+#endif /* !CONFIG_X86 */
 
 #endif /* __LINUX_HYPEVISOR_H */