Merge branches 'pm-sleep', 'pm-cpuidle', 'pm-cpufreq', 'pm-devfreq' and 'pm-avs'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 4 Dec 2019 09:20:17 +0000 (10:20 +0100)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 4 Dec 2019 09:20:17 +0000 (10:20 +0100)
* pm-sleep:
  ACPI: PM: s2idle: Rework ACPI events synchronization
  ACPI: EC: Rework flushing of pending work

* pm-cpuidle:
  cpuidle: minor Kconfig help text fixes
  cpuidle: Drop disabled field from struct cpuidle_state
  cpuidle: Fix Kconfig indentation

* pm-cpufreq:
  cpufreq: Fix Kconfig indentation

* pm-devfreq:
  PM / devfreq: Add missing locking while setting suspend_freq

* pm-avs:
  power: avs: Fix Kconfig indentation

111 files changed:
Documentation/admin-guide/kernel-parameters.txt
Documentation/firmware-guide/acpi/namespace.rst
arch/arm64/mm/mmu.c
arch/sh/kernel/cpu/shmobile/cpuidle.c
arch/x86/boot/compressed/eboot.c
arch/x86/boot/compressed/kaslr.c
arch/x86/include/asm/e820/types.h
arch/x86/include/asm/efi.h
arch/x86/kernel/e820.c
arch/x86/kernel/setup.c
arch/x86/platform/efi/efi.c
arch/x86/platform/efi/quirks.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/acpi_configfs.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_platform.c
drivers/acpi/acpi_video.c
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/acstruct.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dbconvert.c
drivers/acpi/acpica/dbdisply.c
drivers/acpi/acpica/dbfileio.c
drivers/acpi/acpica/dbinput.c
drivers/acpi/acpica/dbmethod.c
drivers/acpi/acpica/dbnames.c
drivers/acpi/acpica/dbobject.c
drivers/acpi/acpica/dscontrol.c
drivers/acpi/acpica/dsfield.c
drivers/acpi/acpica/evgpeblk.c
drivers/acpi/acpica/evgpeinit.c
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evregion.c
drivers/acpi/acpica/evrgnini.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/acpica/nsconvert.c
drivers/acpi/acpica/nsdump.c
drivers/acpi/acpica/nsxfname.c
drivers/acpi/acpica/psobject.c
drivers/acpi/acpica/rscreate.c
drivers/acpi/acpica/tbdata.c
drivers/acpi/acpica/tbxfload.c
drivers/acpi/acpica/utbuffer.c
drivers/acpi/acpica/utids.c
drivers/acpi/acpica/uttrack.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/hmat/Makefile [deleted file]
drivers/acpi/internal.h
drivers/acpi/numa/Kconfig [moved from drivers/acpi/hmat/Kconfig with 75% similarity]
drivers/acpi/numa/Makefile [new file with mode: 0644]
drivers/acpi/numa/hmat.c [moved from drivers/acpi/hmat/hmat.c with 82% similarity]
drivers/acpi/numa/srat.c [moved from drivers/acpi/numa.c with 100% similarity]
drivers/acpi/osi.c
drivers/acpi/pmic/intel_pmic.c
drivers/acpi/pmic/intel_pmic_bytcrc.c [moved from drivers/acpi/pmic/intel_pmic_crc.c with 98% similarity]
drivers/acpi/pmic/intel_pmic_chtcrc.c [new file with mode: 0644]
drivers/acpi/scan.c
drivers/acpi/utils.c
drivers/base/Kconfig
drivers/base/power/Makefile
drivers/base/power/qos-test.c [new file with mode: 0644]
drivers/base/power/qos.c
drivers/cpufreq/Kconfig.powerpc
drivers/cpufreq/Kconfig.x86
drivers/cpuidle/Kconfig
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/cpuidle.c
drivers/cpuidle/poll_state.c
drivers/dax/Kconfig
drivers/dax/Makefile
drivers/dax/bus.c
drivers/dax/bus.h
drivers/dax/dax-private.h
drivers/dax/hmem.c [new file with mode: 0644]
drivers/devfreq/devfreq.c
drivers/firmware/efi/Kconfig
drivers/firmware/efi/Makefile
drivers/firmware/efi/arm-init.c
drivers/firmware/efi/arm-runtime.c
drivers/firmware/efi/efi.c
drivers/firmware/efi/esrt.c
drivers/firmware/efi/fake_mem.c
drivers/firmware/efi/fake_mem.h [new file with mode: 0644]
drivers/firmware/efi/libstub/arm32-stub.c
drivers/firmware/efi/libstub/efi-stub-helper.c
drivers/firmware/efi/libstub/random.c
drivers/firmware/efi/x86_fake_mem.c [new file with mode: 0644]
drivers/idle/intel_idle.c
drivers/iommu/amd_iommu.c
drivers/mfd/intel_soc_pmic_crc.c
drivers/mmc/host/sdhci-acpi.c
drivers/nvdimm/Kconfig
drivers/nvdimm/core.c
drivers/nvdimm/nd-core.h
drivers/nvdimm/region_devs.c
drivers/power/avs/Kconfig
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/acpi/button.h
include/linux/acpi.h
include/linux/cpuidle.h
include/linux/efi.h
include/linux/ioport.h
include/linux/memregion.h [new file with mode: 0644]
include/linux/pm_qos.h
kernel/power/qos.c
lib/Kconfig
lib/Makefile
lib/memregion.c [new file with mode: 0644]

index a0a4732..122f2d2 100644 (file)
                        Format: {"off" | "on" | "skip[mbr]"}
 
        efi=            [EFI]
-                       Format: { "old_map", "nochunk", "noruntime", "debug" }
+                       Format: { "old_map", "nochunk", "noruntime", "debug",
+                                 "nosoftreserve" }
                        old_map [X86-64]: switch to the old ioremap-based EFI
                        runtime services mapping. 32-bit still uses this one by
                        default.
                        firmware implementations.
                        noruntime : disable EFI runtime services support
                        debug: enable misc debug output
+                       nosoftreserve: The EFI_MEMORY_SP (Specific Purpose)
+                       attribute may cause the kernel to reserve the
+                       memory range for a memory mapping driver to
+                       claim. Specify efi=nosoftreserve to disable this
+                       reservation and treat the memory by its base type
+                       (i.e. EFI_CONVENTIONAL_MEMORY / "System RAM").
 
        efi_no_storage_paranoia [EFI; X86]
                        Using this parameter you can use more than 50% of
                        updating original EFI memory map.
                        Region of memory which aa attribute is added to is
                        from ss to ss+nn.
+
                        If efi_fake_mem=2G@4G:0x10000,2G@0x10a0000000:0x10000
                        is specified, EFI_MEMORY_MORE_RELIABLE(0x10000)
                        attribute is added to range 0x100000000-0x180000000 and
                        0x10a0000000-0x1120000000.
 
+                       If efi_fake_mem=8G@9G:0x40000 is specified, the
+                       EFI_MEMORY_SP(0x40000) attribute is added to
+                       range 0x240000000-0x43fffffff.
+
                        Using this parameter you can do debugging of EFI memmap
-                       related feature. For example, you can do debugging of
+                       related features. For example, you can do debugging of
                        Address Range Mirroring feature even if your box
-                       doesn't support it.
+                       doesn't support it, or mark specific memory as
+                       "soft reserved".
 
        efivar_ssdt=    [EFI; X86] Name of an EFI variable that contains an SSDT
                        that is to be dynamically loaded by Linux. If there are
index 835521b..3eb763d 100644 (file)
@@ -261,7 +261,7 @@ Description Tables contain information used for the creation of the
 struct acpi_device objects represented by the given row (xSDT means DSDT
 or SSDT).
 
-The forth column of the above table indicates the 'bus_id' generation
+The fourth column of the above table indicates the 'bus_id' generation
 rule of the struct acpi_device object:
 
    _HID:
index a9f5419..5a3b15a 100644 (file)
@@ -1060,6 +1060,8 @@ int arch_add_memory(int nid, u64 start, u64 size,
        __create_pgd_mapping(swapper_pg_dir, start, __phys_to_virt(start),
                             size, PAGE_KERNEL, __pgd_pgtable_alloc, flags);
 
+       memblock_clear_nomap(start, size);
+
        return __add_pages(nid, start >> PAGE_SHIFT, size >> PAGE_SHIFT,
                           restrictions);
 }
index dbd2cde..b0f9c8f 100644 (file)
@@ -67,7 +67,7 @@ static struct cpuidle_driver cpuidle_driver = {
                        .enter = cpuidle_sleep_enter,
                        .name = "C2",
                        .desc = "SuperH Sleep Mode [SF]",
-                       .disabled = true,
+                       .flags = CPUIDLE_FLAG_UNUSABLE,
                },
                {
                        .exit_latency = 2300,
@@ -76,7 +76,7 @@ static struct cpuidle_driver cpuidle_driver = {
                        .enter = cpuidle_sleep_enter,
                        .name = "C3",
                        .desc = "SuperH Mobile Standby Mode [SF]",
-                       .disabled = true,
+                       .flags = CPUIDLE_FLAG_UNUSABLE,
                },
        },
        .safe_state_index = 0,
@@ -86,10 +86,10 @@ static struct cpuidle_driver cpuidle_driver = {
 int __init sh_mobile_setup_cpuidle(void)
 {
        if (sh_mobile_sleep_supported & SUSP_SH_SF)
-               cpuidle_driver.states[1].disabled = false;
+               cpuidle_driver.states[1].flags = CPUIDLE_FLAG_NONE;
 
        if (sh_mobile_sleep_supported & SUSP_SH_STANDBY)
-               cpuidle_driver.states[2].disabled = false;
+               cpuidle_driver.states[2].flags = CPUIDLE_FLAG_NONE;
 
        return cpuidle_register(&cpuidle_driver, NULL);
 }
index 68945c5..72b08fd 100644 (file)
@@ -554,7 +554,11 @@ setup_e820(struct boot_params *params, struct setup_data *e820ext, u32 e820ext_s
                case EFI_BOOT_SERVICES_CODE:
                case EFI_BOOT_SERVICES_DATA:
                case EFI_CONVENTIONAL_MEMORY:
-                       e820_type = E820_TYPE_RAM;
+                       if (efi_soft_reserve_enabled() &&
+                           (d->attribute & EFI_MEMORY_SP))
+                               e820_type = E820_TYPE_SOFT_RESERVED;
+                       else
+                               e820_type = E820_TYPE_RAM;
                        break;
 
                case EFI_ACPI_MEMORY_NVS:
index bb9bfef..d7408af 100644 (file)
@@ -132,8 +132,14 @@ char *skip_spaces(const char *str)
 #include "../../../../lib/ctype.c"
 #include "../../../../lib/cmdline.c"
 
+enum parse_mode {
+       PARSE_MEMMAP,
+       PARSE_EFI,
+};
+
 static int
-parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
+parse_memmap(char *p, unsigned long long *start, unsigned long long *size,
+               enum parse_mode mode)
 {
        char *oldp;
 
@@ -156,8 +162,29 @@ parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
                *start = memparse(p + 1, &p);
                return 0;
        case '@':
-               /* memmap=nn@ss specifies usable region, should be skipped */
-               *size = 0;
+               if (mode == PARSE_MEMMAP) {
+                       /*
+                        * memmap=nn@ss specifies usable region, should
+                        * be skipped
+                        */
+                       *size = 0;
+               } else {
+                       unsigned long long flags;
+
+                       /*
+                        * efi_fake_mem=nn@ss:attr the attr specifies
+                        * flags that might imply a soft-reservation.
+                        */
+                       *start = memparse(p + 1, &p);
+                       if (p && *p == ':') {
+                               p++;
+                               if (kstrtoull(p, 0, &flags) < 0)
+                                       *size = 0;
+                               else if (flags & EFI_MEMORY_SP)
+                                       return 0;
+                       }
+                       *size = 0;
+               }
                /* Fall through */
        default:
                /*
@@ -172,7 +199,7 @@ parse_memmap(char *p, unsigned long long *start, unsigned long long *size)
        return -EINVAL;
 }
 
-static void mem_avoid_memmap(char *str)
+static void mem_avoid_memmap(enum parse_mode mode, char *str)
 {
        static int i;
 
@@ -187,7 +214,7 @@ static void mem_avoid_memmap(char *str)
                if (k)
                        *k++ = 0;
 
-               rc = parse_memmap(str, &start, &size);
+               rc = parse_memmap(str, &start, &size, mode);
                if (rc < 0)
                        break;
                str = k;
@@ -238,7 +265,6 @@ static void parse_gb_huge_pages(char *param, char *val)
        }
 }
 
-
 static void handle_mem_options(void)
 {
        char *args = (char *)get_cmd_line_ptr();
@@ -271,7 +297,7 @@ static void handle_mem_options(void)
                }
 
                if (!strcmp(param, "memmap")) {
-                       mem_avoid_memmap(val);
+                       mem_avoid_memmap(PARSE_MEMMAP, val);
                } else if (strstr(param, "hugepages")) {
                        parse_gb_huge_pages(param, val);
                } else if (!strcmp(param, "mem")) {
@@ -284,6 +310,8 @@ static void handle_mem_options(void)
                                goto out;
 
                        mem_limit = mem_size;
+               } else if (!strcmp(param, "efi_fake_mem")) {
+                       mem_avoid_memmap(PARSE_EFI, val);
                }
        }
 
@@ -772,6 +800,10 @@ process_efi_entries(unsigned long minimum, unsigned long image_size)
                if (md->type != EFI_CONVENTIONAL_MEMORY)
                        continue;
 
+               if (efi_soft_reserve_enabled() &&
+                   (md->attribute & EFI_MEMORY_SP))
+                       continue;
+
                if (efi_mirror_found &&
                    !(md->attribute & EFI_MEMORY_MORE_RELIABLE))
                        continue;
index c3aa4b5..314f75d 100644 (file)
@@ -29,6 +29,14 @@ enum e820_type {
        E820_TYPE_PRAM          = 12,
 
        /*
+        * Special-purpose memory is indicated to the system via the
+        * EFI_MEMORY_SP attribute. Define an e820 translation of this
+        * memory type for the purpose of reserving this range and
+        * marking it with the IORES_DESC_SOFT_RESERVED designation.
+        */
+       E820_TYPE_SOFT_RESERVED = 0xefffffff,
+
+       /*
         * Reserved RAM used by the kernel itself if
         * CONFIG_INTEL_TXT=y is enabled, memory of this type
         * will be included in the S3 integrity calculation
index 43a82e5..d028e9a 100644 (file)
@@ -140,7 +140,6 @@ extern void efi_delete_dummy_variable(void);
 extern void efi_switch_mm(struct mm_struct *mm);
 extern void efi_recover_from_page_fault(unsigned long phys_addr);
 extern void efi_free_boot_services(void);
-extern void efi_reserve_boot_services(void);
 
 struct efi_setup_data {
        u64 fw_vendor;
@@ -244,6 +243,8 @@ static inline bool efi_is_64bit(void)
 extern bool efi_reboot_required(void);
 extern bool efi_is_table_address(unsigned long phys_addr);
 
+extern void efi_find_mirror(void);
+extern void efi_reserve_boot_services(void);
 #else
 static inline void parse_efi_setup(u64 phys_addr, u32 data_len) {}
 static inline bool efi_reboot_required(void)
@@ -254,6 +255,20 @@ static inline  bool efi_is_table_address(unsigned long phys_addr)
 {
        return false;
 }
+static inline void efi_find_mirror(void)
+{
+}
+static inline void efi_reserve_boot_services(void)
+{
+}
 #endif /* CONFIG_EFI */
 
+#ifdef CONFIG_EFI_FAKE_MEMMAP
+extern void __init efi_fake_memmap_early(void);
+#else
+static inline void efi_fake_memmap_early(void)
+{
+}
+#endif
+
 #endif /* _ASM_X86_EFI_H */
index 0bfe9a6..c5399e8 100644 (file)
@@ -190,6 +190,7 @@ static void __init e820_print_type(enum e820_type type)
        case E820_TYPE_RAM:             /* Fall through: */
        case E820_TYPE_RESERVED_KERN:   pr_cont("usable");                      break;
        case E820_TYPE_RESERVED:        pr_cont("reserved");                    break;
+       case E820_TYPE_SOFT_RESERVED:   pr_cont("soft reserved");               break;
        case E820_TYPE_ACPI:            pr_cont("ACPI data");                   break;
        case E820_TYPE_NVS:             pr_cont("ACPI NVS");                    break;
        case E820_TYPE_UNUSABLE:        pr_cont("unusable");                    break;
@@ -1048,6 +1049,7 @@ static const char *__init e820_type_to_string(struct e820_entry *entry)
        case E820_TYPE_PRAM:            return "Persistent Memory (legacy)";
        case E820_TYPE_PMEM:            return "Persistent Memory";
        case E820_TYPE_RESERVED:        return "Reserved";
+       case E820_TYPE_SOFT_RESERVED:   return "Soft Reserved";
        default:                        return "Unknown E820 type";
        }
 }
@@ -1063,6 +1065,7 @@ static unsigned long __init e820_type_to_iomem_type(struct e820_entry *entry)
        case E820_TYPE_PRAM:            /* Fall-through: */
        case E820_TYPE_PMEM:            /* Fall-through: */
        case E820_TYPE_RESERVED:        /* Fall-through: */
+       case E820_TYPE_SOFT_RESERVED:   /* Fall-through: */
        default:                        return IORESOURCE_MEM;
        }
 }
@@ -1075,6 +1078,7 @@ static unsigned long __init e820_type_to_iores_desc(struct e820_entry *entry)
        case E820_TYPE_PMEM:            return IORES_DESC_PERSISTENT_MEMORY;
        case E820_TYPE_PRAM:            return IORES_DESC_PERSISTENT_MEMORY_LEGACY;
        case E820_TYPE_RESERVED:        return IORES_DESC_RESERVED;
+       case E820_TYPE_SOFT_RESERVED:   return IORES_DESC_SOFT_RESERVED;
        case E820_TYPE_RESERVED_KERN:   /* Fall-through: */
        case E820_TYPE_RAM:             /* Fall-through: */
        case E820_TYPE_UNUSABLE:        /* Fall-through: */
@@ -1089,11 +1093,12 @@ static bool __init do_mark_busy(enum e820_type type, struct resource *res)
                return true;
 
        /*
-        * Treat persistent memory like device memory, i.e. reserve it
-        * for exclusive use of a driver
+        * Treat persistent memory and other special memory ranges like
+        * device memory, i.e. reserve it for exclusive use of a driver
         */
        switch (type) {
        case E820_TYPE_RESERVED:
+       case E820_TYPE_SOFT_RESERVED:
        case E820_TYPE_PRAM:
        case E820_TYPE_PMEM:
                return false;
@@ -1296,6 +1301,9 @@ void __init e820__memblock_setup(void)
                if (end != (resource_size_t)end)
                        continue;
 
+               if (entry->type == E820_TYPE_SOFT_RESERVED)
+                       memblock_reserve(entry->addr, entry->size);
+
                if (entry->type != E820_TYPE_RAM && entry->type != E820_TYPE_RESERVED_KERN)
                        continue;
 
index d398afd..cedfe20 100644 (file)
@@ -1138,17 +1138,15 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_bios_regions();
 
-       if (efi_enabled(EFI_MEMMAP)) {
-               efi_fake_memmap();
-               efi_find_mirror();
-               efi_esrt_init();
+       efi_fake_memmap();
+       efi_find_mirror();
+       efi_esrt_init();
 
-               /*
-                * The EFI specification says that boot service code won't be
-                * called after ExitBootServices(). This is, in fact, a lie.
-                */
-               efi_reserve_boot_services();
-       }
+       /*
+        * The EFI specification says that boot service code won't be
+        * called after ExitBootServices(). This is, in fact, a lie.
+        */
+       efi_reserve_boot_services();
 
        /* preallocate 4k for mptable mpc */
        e820__memblock_alloc_reserved_mpc_new();
index 425e025..38d44f3 100644 (file)
@@ -128,6 +128,9 @@ void __init efi_find_mirror(void)
        efi_memory_desc_t *md;
        u64 mirror_size = 0, total_size = 0;
 
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
        for_each_efi_memory_desc(md) {
                unsigned long long start = md->phys_addr;
                unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -145,14 +148,18 @@ void __init efi_find_mirror(void)
 
 /*
  * Tell the kernel about the EFI memory map.  This might include
- * more than the max 128 entries that can fit in the e820 legacy
- * (zeropage) memory map.
+ * more than the max 128 entries that can fit in the passed in e820
+ * legacy (zeropage) memory map, but the kernel's e820 table can hold
+ * E820_MAX_ENTRIES.
  */
 
 static void __init do_add_efi_memmap(void)
 {
        efi_memory_desc_t *md;
 
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
        for_each_efi_memory_desc(md) {
                unsigned long long start = md->phys_addr;
                unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -164,7 +171,10 @@ static void __init do_add_efi_memmap(void)
                case EFI_BOOT_SERVICES_CODE:
                case EFI_BOOT_SERVICES_DATA:
                case EFI_CONVENTIONAL_MEMORY:
-                       if (md->attribute & EFI_MEMORY_WB)
+                       if (efi_soft_reserve_enabled()
+                           && (md->attribute & EFI_MEMORY_SP))
+                               e820_type = E820_TYPE_SOFT_RESERVED;
+                       else if (md->attribute & EFI_MEMORY_WB)
                                e820_type = E820_TYPE_RAM;
                        else
                                e820_type = E820_TYPE_RESERVED;
@@ -190,11 +200,36 @@ static void __init do_add_efi_memmap(void)
                        e820_type = E820_TYPE_RESERVED;
                        break;
                }
+
                e820__range_add(start, size, e820_type);
        }
        e820__update_table(e820_table);
 }
 
+/*
+ * Given add_efi_memmap defaults to 0 and there there is no alternative
+ * e820 mechanism for soft-reserved memory, import the full EFI memory
+ * map if soft reservations are present and enabled. Otherwise, the
+ * mechanism to disable the kernel's consideration of EFI_MEMORY_SP is
+ * the efi=nosoftreserve option.
+ */
+static bool do_efi_soft_reserve(void)
+{
+       efi_memory_desc_t *md;
+
+       if (!efi_enabled(EFI_MEMMAP))
+               return false;
+
+       if (!efi_soft_reserve_enabled())
+               return false;
+
+       for_each_efi_memory_desc(md)
+               if (md->type == EFI_CONVENTIONAL_MEMORY &&
+                   (md->attribute & EFI_MEMORY_SP))
+                       return true;
+       return false;
+}
+
 int __init efi_memblock_x86_reserve_range(void)
 {
        struct efi_info *e = &boot_params.efi_info;
@@ -224,9 +259,11 @@ int __init efi_memblock_x86_reserve_range(void)
        if (rv)
                return rv;
 
-       if (add_efi_memmap)
+       if (add_efi_memmap || do_efi_soft_reserve())
                do_add_efi_memmap();
 
+       efi_fake_memmap_early();
+
        WARN(efi.memmap.desc_version != 1,
             "Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
             efi.memmap.desc_version);
@@ -779,6 +816,15 @@ static bool should_map_region(efi_memory_desc_t *md)
                return false;
 
        /*
+        * EFI specific purpose memory may be reserved by default
+        * depending on kernel config and boot options.
+        */
+       if (md->type == EFI_CONVENTIONAL_MEMORY &&
+           efi_soft_reserve_enabled() &&
+           (md->attribute & EFI_MEMORY_SP))
+               return false;
+
+       /*
         * Map all of RAM so that we can access arguments in the 1:1
         * mapping when making EFI runtime calls.
         */
index 3b9fd67..7675cf7 100644 (file)
@@ -320,6 +320,9 @@ void __init efi_reserve_boot_services(void)
 {
        efi_memory_desc_t *md;
 
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
        for_each_efi_memory_desc(md) {
                u64 start = md->phys_addr;
                u64 size = md->num_pages << EFI_PAGE_SHIFT;
index ebe1e9e..4fb9751 100644 (file)
@@ -319,12 +319,6 @@ config ACPI_THERMAL
          To compile this driver as a module, choose M here:
          the module will be called thermal.
 
-config ACPI_NUMA
-       bool "NUMA support"
-       depends on NUMA
-       depends on (X86 || IA64 || ARM64)
-       default y if IA64 || ARM64
-
 config ACPI_CUSTOM_DSDT_FILE
        string "Custom DSDT Table file to include"
        default ""
@@ -473,8 +467,7 @@ config ACPI_REDUCED_HARDWARE_ONLY
          If you are unsure what to do, do not enable this option.
 
 source "drivers/acpi/nfit/Kconfig"
-source "drivers/acpi/hmat/Kconfig"
-
+source "drivers/acpi/numa/Kconfig"
 source "drivers/acpi/apei/Kconfig"
 source "drivers/acpi/dptf/Kconfig"
 
@@ -513,11 +506,19 @@ menuconfig PMIC_OPREGION
          PMIC chip.
 
 if PMIC_OPREGION
-config CRC_PMIC_OPREGION
-       bool "ACPI operation region support for CrystalCove PMIC"
+config BYTCRC_PMIC_OPREGION
+       bool "ACPI operation region support for Bay Trail Crystal Cove PMIC"
+       depends on INTEL_SOC_PMIC
+       help
+         This config adds ACPI operation region support for the Bay Trail
+         version of the Crystal Cove PMIC.
+
+config CHTCRC_PMIC_OPREGION
+       bool "ACPI operation region support for Cherry Trail Crystal Cove PMIC"
        depends on INTEL_SOC_PMIC
        help
-         This config adds ACPI operation region support for CrystalCove PMIC.
+         This config adds ACPI operation region support for the Cherry Trail
+         version of the Crystal Cove PMIC.
 
 config XPOWER_PMIC_OPREGION
        bool "ACPI operation region support for XPower AXP288 PMIC"
index 5d361e4..33fdaf6 100644 (file)
@@ -48,14 +48,13 @@ acpi-y                              += acpi_pnp.o
 acpi-$(CONFIG_ARM_AMBA)        += acpi_amba.o
 acpi-y                         += power.o
 acpi-y                         += event.o
-acpi-$(CONFIG_ACPI_REDUCED_HARDWARE_ONLY) += evged.o
+acpi-y                         += evged.o
 acpi-y                         += sysfs.o
 acpi-y                         += property.o
 acpi-$(CONFIG_X86)             += acpi_cmos_rtc.o
 acpi-$(CONFIG_X86)             += x86/apple.o
 acpi-$(CONFIG_X86)             += x86/utils.o
 acpi-$(CONFIG_DEBUG_FS)                += debugfs.o
-acpi-$(CONFIG_ACPI_NUMA)       += numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
 acpi-y                         += acpi_lpat.o
 acpi-$(CONFIG_ACPI_LPIT)       += acpi_lpit.o
@@ -80,7 +79,7 @@ obj-$(CONFIG_ACPI_PROCESSOR)  += processor.o
 obj-$(CONFIG_ACPI)             += container.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
 obj-$(CONFIG_ACPI_NFIT)                += nfit/
-obj-$(CONFIG_ACPI_HMAT)                += hmat/
+obj-$(CONFIG_ACPI_NUMA)                += numa/
 obj-$(CONFIG_ACPI)             += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
@@ -109,7 +108,8 @@ obj-$(CONFIG_ACPI_APEI)             += apei/
 obj-$(CONFIG_ACPI_EXTLOG)      += acpi_extlog.o
 
 obj-$(CONFIG_PMIC_OPREGION)    += pmic/intel_pmic.o
-obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
+obj-$(CONFIG_BYTCRC_PMIC_OPREGION) += pmic/intel_pmic_bytcrc.o
+obj-$(CONFIG_CHTCRC_PMIC_OPREGION) += pmic/intel_pmic_chtcrc.o
 obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
 obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o
 obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o
index 57d9d57..ece8c1a 100644 (file)
@@ -53,7 +53,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg,
        if (!table->header)
                return -ENOMEM;
 
-       ret = acpi_load_table(table->header);
+       ret = acpi_load_table(table->header, &table->index);
        if (ret) {
                kfree(table->header);
                table->header = NULL;
@@ -223,7 +223,7 @@ static void acpi_table_drop_item(struct config_group *group,
        struct acpi_table *table = container_of(cfg, struct acpi_table, cfg);
 
        ACPI_INFO(("Host-directed Dynamic ACPI Table Unload"));
-       acpi_tb_unload_table(table->index);
+       acpi_unload_table(table->index);
 }
 
 static struct configfs_group_operations acpi_table_group_ops = {
index 60bbc50..70f740b 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/acpi.h>
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
+#include <linux/dmi.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/mutex.h>
@@ -463,6 +464,18 @@ struct lpss_device_links {
        const char *consumer_hid;
        const char *consumer_uid;
        u32 flags;
+       const struct dmi_system_id *dep_missing_ids;
+};
+
+/* Please keep this list sorted alphabetically by vendor and model */
+static const struct dmi_system_id i2c1_dep_missing_dmi_ids[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
+               },
+       },
+       {}
 };
 
 /*
@@ -473,36 +486,29 @@ struct lpss_device_links {
  * the supplier is not enumerated until after the consumer is probed.
  */
 static const struct lpss_device_links lpss_device_links[] = {
+       /* CHT External sdcard slot controller depends on PMIC I2C ctrl */
        {"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
+       /* CHT iGPU depends on PMIC I2C controller */
        {"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+       /* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */
+       {"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME,
+        i2c1_dep_missing_dmi_ids},
+       /* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */
        {"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
+       /* BYT iGPU depends on PMIC I2C controller (UID 7 on non CR) */
+       {"80860F41", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
 };
 
-static bool hid_uid_match(struct acpi_device *adev,
-                         const char *hid2, const char *uid2)
-{
-       const char *hid1 = acpi_device_hid(adev);
-       const char *uid1 = acpi_device_uid(adev);
-
-       if (strcmp(hid1, hid2))
-               return false;
-
-       if (!uid2)
-               return true;
-
-       return uid1 && !strcmp(uid1, uid2);
-}
-
 static bool acpi_lpss_is_supplier(struct acpi_device *adev,
                                  const struct lpss_device_links *link)
 {
-       return hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
+       return acpi_dev_hid_uid_match(adev, link->supplier_hid, link->supplier_uid);
 }
 
 static bool acpi_lpss_is_consumer(struct acpi_device *adev,
                                  const struct lpss_device_links *link)
 {
-       return hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
+       return acpi_dev_hid_uid_match(adev, link->consumer_hid, link->consumer_uid);
 }
 
 struct hid_uid {
@@ -518,7 +524,7 @@ static int match_hid_uid(struct device *dev, const void *data)
        if (!adev)
                return 0;
 
-       return hid_uid_match(adev, id->hid, id->uid);
+       return acpi_dev_hid_uid_match(adev, id->hid, id->uid);
 }
 
 static struct device *acpi_lpss_find_device(const char *hid, const char *uid)
@@ -570,7 +576,8 @@ static void acpi_lpss_link_consumer(struct device *dev1,
        if (!dev2)
                return;
 
-       if (acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
+       if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
+           || acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
                device_link_add(dev2, dev1, link->flags);
 
        put_device(dev2);
@@ -585,7 +592,8 @@ static void acpi_lpss_link_supplier(struct device *dev1,
        if (!dev2)
                return;
 
-       if (acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
+       if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
+           || acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
                device_link_add(dev1, dev2, link->flags);
 
        put_device(dev2);
index 00ec4f2..c05050f 100644 (file)
@@ -31,6 +31,44 @@ static const struct acpi_device_id forbidden_id_list[] = {
        {"", 0},
 };
 
+static struct platform_device *acpi_platform_device_find_by_companion(struct acpi_device *adev)
+{
+       struct device *dev;
+
+       dev = bus_find_device_by_acpi_dev(&platform_bus_type, adev);
+       return dev ? to_platform_device(dev) : NULL;
+}
+
+static int acpi_platform_device_remove_notify(struct notifier_block *nb,
+                                             unsigned long value, void *arg)
+{
+       struct acpi_device *adev = arg;
+       struct platform_device *pdev;
+
+       switch (value) {
+       case ACPI_RECONFIG_DEVICE_ADD:
+               /* Nothing to do here */
+               break;
+       case ACPI_RECONFIG_DEVICE_REMOVE:
+               if (!acpi_device_enumerated(adev))
+                       break;
+
+               pdev = acpi_platform_device_find_by_companion(adev);
+               if (!pdev)
+                       break;
+
+               platform_device_unregister(pdev);
+               put_device(&pdev->dev);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_platform_notifier = {
+       .notifier_call = acpi_platform_device_remove_notify,
+};
+
 static void acpi_platform_fill_resource(struct acpi_device *adev,
        const struct resource *src, struct resource *dest)
 {
@@ -130,3 +168,8 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
        return pdev;
 }
 EXPORT_SYMBOL_GPL(acpi_create_platform_device);
+
+void __init acpi_platform_init(void)
+{
+       acpi_reconfig_notifier_register(&acpi_platform_notifier);
+}
index 4f325e4..2f380e7 100644 (file)
@@ -699,9 +699,13 @@ acpi_video_device_EDID(struct acpi_video_device *device,
  *                     event notify code.
  *     lcd_flag        :
  *             0.      The system BIOS should automatically control the brightness level
- *                     of the LCD when the power changes from AC to DC
+ *                     of the LCD when:
+ *                     - the power changes from AC to DC (ACPI appendix B)
+ *                     - a brightness hotkey gets pressed (implied by Win7/8 backlight docs)
  *             1.      The system BIOS should NOT automatically control the brightness
- *                     level of the LCD when the power changes from AC to DC.
+ *                     level of the LCD when:
+ *                     - the power changes from AC to DC (ACPI appendix B)
+ *                     - a brightness hotkey gets pressed (implied by Win7/8 backlight docs)
  *  Return Value:
  *             -EINVAL wrong arg.
  */
index 32f2e38..694cf20 100644 (file)
@@ -148,6 +148,8 @@ void acpi_db_find_references(char *object_arg);
 
 void acpi_db_get_bus_info(void);
 
+acpi_status acpi_db_display_fields(u32 address_space_id);
+
 /*
  * dbdisply - debug display commands
  */
index 218ff4c..2043dff 100644 (file)
@@ -192,6 +192,16 @@ struct acpi_device_walk_info {
        u32 num_INI;
 };
 
+/* Info used by Acpi  acpi_db_display_fields */
+
+struct acpi_region_walk_info {
+       u32 debug_level;
+       u32 count;
+       acpi_owner_id owner_id;
+       u8 display_type;
+       u32 address_space_id;
+};
+
 /* TBD: [Restructure] Merge with struct above */
 
 struct acpi_walk_info {
index 601808b..5fb5063 100644 (file)
@@ -142,10 +142,11 @@ struct acpi_pkg_info {
 
 /* acpi_ut_dump_buffer */
 
-#define DB_BYTE_DISPLAY     1
-#define DB_WORD_DISPLAY     2
-#define DB_DWORD_DISPLAY    4
-#define DB_QWORD_DISPLAY    8
+#define DB_BYTE_DISPLAY      0x01
+#define DB_WORD_DISPLAY      0x02
+#define DB_DWORD_DISPLAY     0x04
+#define DB_QWORD_DISPLAY     0x08
+#define DB_DISPLAY_DATA_ONLY 0x10
 
 /*
  * utascii - ASCII utilities
index 9fd9a98..2b84ac0 100644 (file)
@@ -106,6 +106,10 @@ acpi_db_convert_to_buffer(char *string, union acpi_object *object)
        u8 *buffer;
        acpi_status status;
 
+       /* Skip all preceding white space */
+
+       acpi_ut_remove_whitespace(&string);
+
        /* Generate the final buffer length */
 
        for (i = 0, length = 0; string[i];) {
index 30ab62b..f2df416 100644 (file)
@@ -513,7 +513,6 @@ void acpi_db_display_results(void)
                return;
        }
 
-       obj_desc = walk_state->method_desc;
        node = walk_state->method_node;
 
        if (walk_state->results) {
@@ -565,7 +564,6 @@ void acpi_db_display_calling_tree(void)
                return;
        }
 
-       node = walk_state->method_node;
        acpi_os_printf("Current Control Method Call Tree\n");
 
        while (walk_state) {
index c6e2573..e1b6e54 100644 (file)
@@ -93,7 +93,7 @@ acpi_status acpi_db_load_tables(struct acpi_new_table_desc *list_head)
        while (table_list_head) {
                table = table_list_head->table;
 
-               status = acpi_load_table(table);
+               status = acpi_load_table(table, NULL);
                if (ACPI_FAILURE(status)) {
                        if (status == AE_ALREADY_EXISTS) {
                                acpi_os_printf
index 55a7e10..e1632b3 100644 (file)
@@ -50,6 +50,7 @@ enum acpi_ex_debugger_commands {
        CMD_EVALUATE,
        CMD_EXECUTE,
        CMD_EXIT,
+       CMD_FIELDS,
        CMD_FIND,
        CMD_GO,
        CMD_HANDLERS,
@@ -127,6 +128,7 @@ static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
        {"EVALUATE", 1},
        {"EXECUTE", 1},
        {"EXIT", 0},
+       {"FIELDS", 1},
        {"FIND", 1},
        {"GO", 0},
        {"HANDLERS", 0},
@@ -200,6 +202,8 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
         "Find ACPI name(s) with wildcards\n"},
        {1, "  Integrity", "Validate namespace integrity\n"},
        {1, "  Methods", "Display list of loaded control methods\n"},
+       {1, "  Fields <AddressSpaceId>",
+        "Display list of loaded field units by space ID\n"},
        {1, "  Namespace [Object] [Depth]",
         "Display loaded namespace tree/subtree\n"},
        {1, "  Notify <Object> <Value>", "Send a notification on Object\n"},
@@ -507,6 +511,21 @@ char *acpi_db_get_next_token(char *string,
                }
                break;
 
+       case '{':
+
+               /* This is the start of a field unit, scan until closing brace */
+
+               string++;
+               start = string;
+               type = ACPI_TYPE_FIELD_UNIT;
+
+               /* Find end of buffer */
+
+               while (*string && (*string != '}')) {
+                       string++;
+               }
+               break;
+
        case '[':
 
                /* This is the start of a package, scan until closing bracket */
@@ -674,6 +693,7 @@ acpi_db_command_dispatch(char *input_buffer,
                         union acpi_parse_object *op)
 {
        u32 temp;
+       u64 temp64;
        u32 command_index;
        u32 param_count;
        char *command_line;
@@ -689,7 +709,6 @@ acpi_db_command_dispatch(char *input_buffer,
 
        param_count = acpi_db_get_line(input_buffer);
        command_index = acpi_db_match_command(acpi_gbl_db_args[0]);
-       temp = 0;
 
        /*
         * We don't want to add the !! command to the history buffer. It
@@ -790,6 +809,21 @@ acpi_db_command_dispatch(char *input_buffer,
                status = acpi_db_find_name_in_namespace(acpi_gbl_db_args[1]);
                break;
 
+       case CMD_FIELDS:
+
+               status = acpi_ut_strtoul64(acpi_gbl_db_args[1], &temp64);
+
+               if (ACPI_FAILURE(status)
+                   || temp64 >= ACPI_NUM_PREDEFINED_REGIONS) {
+                       acpi_os_printf
+                           ("Invalid adress space ID: must be between 0 and %u inclusive\n",
+                            ACPI_NUM_PREDEFINED_REGIONS - 1);
+                       return (AE_OK);
+               }
+
+               status = acpi_db_display_fields((u32)temp64);
+               break;
+
        case CMD_GO:
 
                acpi_gbl_cm_single_step = FALSE;
index 76a15b6..4e48a7d 100644 (file)
@@ -321,6 +321,10 @@ acpi_status acpi_db_disassemble_method(char *name)
        walk_state->parse_flags |= ACPI_PARSE_DISASSEMBLE;
 
        status = acpi_ps_parse_aml(walk_state);
+       if (ACPI_FAILURE(status)) {
+               return (status);
+       }
+
        (void)acpi_dm_parse_deferred_ops(op);
 
        /* Now we can disassemble the method */
index 63fe30e..3615e1a 100644 (file)
@@ -10,6 +10,7 @@
 #include "acnamesp.h"
 #include "acdebug.h"
 #include "acpredef.h"
+#include "acinterp.h"
 
 #define _COMPONENT          ACPI_CA_DEBUGGER
 ACPI_MODULE_NAME("dbnames")
@@ -504,6 +505,86 @@ acpi_db_walk_for_object_counts(acpi_handle obj_handle,
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_db_walk_for_fields
+ *
+ * PARAMETERS:  Callback from walk_namespace
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Display short info about objects in the namespace
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_db_walk_for_fields(acpi_handle obj_handle,
+                       u32 nesting_level, void *context, void **return_value)
+{
+       union acpi_object *ret_value;
+       struct acpi_region_walk_info *info =
+           (struct acpi_region_walk_info *)context;
+       struct acpi_buffer buffer;
+       acpi_status status;
+       struct acpi_namespace_node *node = acpi_ns_validate_handle(obj_handle);
+
+       if (!node) {
+               return (AE_OK);
+       }
+       if (node->object->field.region_obj->region.space_id !=
+           info->address_space_id) {
+               return (AE_OK);
+       }
+
+       info->count++;
+
+       /* Get and display the full pathname to this object */
+
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_printf("Could Not get pathname for object %p\n",
+                              obj_handle);
+               return (AE_OK);
+       }
+
+       acpi_os_printf("%s ", (char *)buffer.pointer);
+       ACPI_FREE(buffer.pointer);
+
+       buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+       acpi_evaluate_object(obj_handle, NULL, NULL, &buffer);
+
+       /*
+        * Since this is a field unit, surround the output in braces
+        */
+       acpi_os_printf("{");
+
+       ret_value = (union acpi_object *)buffer.pointer;
+       switch (ret_value->type) {
+       case ACPI_TYPE_INTEGER:
+
+               acpi_os_printf("%8.8X%8.8X",
+                              ACPI_FORMAT_UINT64(ret_value->integer.value));
+               break;
+
+       case ACPI_TYPE_BUFFER:
+
+               acpi_ut_dump_buffer(ret_value->buffer.pointer,
+                                   ret_value->buffer.length,
+                                   DB_DISPLAY_DATA_ONLY | DB_BYTE_DISPLAY, 0);
+               break;
+
+       default:
+
+               break;
+       }
+       acpi_os_printf("}\n");
+
+       ACPI_FREE(buffer.pointer);
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_db_walk_for_specific_objects
  *
  * PARAMETERS:  Callback from walk_namespace
@@ -630,6 +711,39 @@ acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg)
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_db_display_fields
+ *
+ * PARAMETERS:  obj_type_arg        - Type of object to display
+ *              display_count_arg   - Max depth to display
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Display objects in the namespace of the requested type
+ *
+ ******************************************************************************/
+
+acpi_status acpi_db_display_fields(u32 address_space_id)
+{
+       struct acpi_region_walk_info info;
+
+       info.count = 0;
+       info.owner_id = ACPI_OWNER_ID_MAX;
+       info.debug_level = ACPI_UINT32_MAX;
+       info.display_type = ACPI_DISPLAY_SUMMARY | ACPI_DISPLAY_SHORT;
+       info.address_space_id = address_space_id;
+
+       /* Walk the namespace from the root */
+
+       (void)acpi_walk_namespace(ACPI_TYPE_LOCAL_REGION_FIELD,
+                                 ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+                                 acpi_db_walk_for_fields, NULL, (void *)&info,
+                                 NULL);
+
+       return (AE_OK);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_db_integrity_walk
  *
  * PARAMETERS:  Callback from walk_namespace
index f9fc84b..4b4c530 100644 (file)
@@ -464,7 +464,6 @@ void acpi_db_decode_arguments(struct acpi_walk_state *walk_state)
        u8 display_args = FALSE;
 
        node = walk_state->method_node;
-       obj_desc = walk_state->method_desc;
 
        /* There are no arguments for the module-level code case */
 
index 4847f89..5034fab 100644 (file)
@@ -85,7 +85,7 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
                    walk_state->parser_state.pkg_end;
                control_state->control.opcode = op->common.aml_opcode;
                control_state->control.loop_timeout = acpi_os_get_timer() +
-                   (u64)(acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);
+                   ((u64)acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);
 
                /* Push the control state on this walk's control stack */
 
index cf4e061..faa38a2 100644 (file)
@@ -149,7 +149,6 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
 
        if (walk_state->deferred_node) {
                node = walk_state->deferred_node;
-               status = AE_OK;
        } else {
                /* Execute flag should always be set when this function is entered */
 
@@ -264,7 +263,6 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
        union acpi_parse_object *child;
 
 #ifdef ACPI_EXEC_APP
-       u64 value = 0;
        union acpi_operand_object *result_desc;
        union acpi_operand_object *obj_desc;
        char *name_path;
@@ -406,19 +404,17 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
                                        name_path =
                                            acpi_ns_get_external_pathname(info->
                                                                          field_node);
-                                       obj_desc =
-                                           acpi_ut_create_integer_object
-                                           (value);
                                        if (ACPI_SUCCESS
                                            (ae_lookup_init_file_entry
-                                            (name_path, &value))) {
+                                            (name_path, &obj_desc))) {
                                                acpi_ex_write_data_to_field
                                                    (obj_desc,
                                                     acpi_ns_get_attached_object
                                                     (info->field_node),
                                                     &result_desc);
+                                               acpi_ut_remove_reference
+                                                   (obj_desc);
                                        }
-                                       acpi_ut_remove_reference(obj_desc);
                                        ACPI_FREE(name_path);
 #endif
                                }
@@ -636,8 +632,6 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
                                }
 
                                /* Name already exists, just ignore this error */
-
-                               status = AE_OK;
                        }
 
                        arg->common.node = node;
index fb15e9e..9c7adaa 100644 (file)
@@ -110,6 +110,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block)
 
        status =
            acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
        if (!gpe_block->previous && !gpe_block->next) {
 
@@ -359,10 +362,10 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
        walk_info.gpe_device = gpe_device;
        walk_info.execute_by_owner_id = FALSE;
 
-       status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
-                                       ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
-                                       acpi_ev_match_gpe_method, NULL,
-                                       &walk_info, NULL);
+       (void)acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device,
+                                    ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
+                                    acpi_ev_match_gpe_method, NULL, &walk_info,
+                                    NULL);
 
        /* Return the new block */
 
index b04f982..70d21d5 100644 (file)
@@ -156,8 +156,6 @@ acpi_status acpi_ev_gpe_initialize(void)
                         * GPE0 and GPE1 do not have to be contiguous in the GPE number
                         * space. However, GPE0 always starts at GPE number zero.
                         */
-                       gpe_number_max = acpi_gbl_FADT.gpe1_base +
-                           ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
                }
        }
 
@@ -169,7 +167,6 @@ acpi_status acpi_ev_gpe_initialize(void)
 
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "There are no GPE blocks defined in the FADT\n"));
-               status = AE_OK;
                goto cleanup;
        }
 
index d45f763..aa98fe0 100644 (file)
@@ -230,11 +230,15 @@ void acpi_ev_terminate(void)
                /* Disable all GPEs in all GPE blocks */
 
                status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL);
+               if (ACPI_FAILURE(status)) {
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "Could not disable GPEs in GPE block"));
+               }
 
                status = acpi_ev_remove_global_lock_handler();
                if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not remove Global Lock handler"));
+                       ACPI_EXCEPTION((AE_INFO, status,
+                                       "Could not remove Global Lock handler"));
                }
 
                acpi_gbl_events_initialized = FALSE;
@@ -250,6 +254,10 @@ void acpi_ev_terminate(void)
        /* Deallocate all handler objects installed within GPE info structs */
 
        status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "Could not delete GPE handlers"));
+       }
 
        /* Return to original mode if necessary */
 
index 45dc797..1ff1264 100644 (file)
@@ -836,11 +836,11 @@ acpi_ev_orphan_ec_reg_method(struct acpi_namespace_node *ec_device_node)
        objects[1].type = ACPI_TYPE_INTEGER;
        objects[1].integer.value = ACPI_REG_CONNECT;
 
-       status = acpi_evaluate_object(reg_method, NULL, &args, NULL);
+       (void)acpi_evaluate_object(reg_method, NULL, &args, NULL);
 
 exit:
        /* We ignore all errors from above, don't care */
 
-       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
        return_VOID;
 }
index 0b47bbc..aee0964 100644 (file)
@@ -198,7 +198,6 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
                                                 * root bridge. Still need to return a context object
                                                 * for the new PCI_Config operation region, however.
                                                 */
-                                               status = AE_OK;
                                        } else {
                                                ACPI_EXCEPTION((AE_INFO, status,
                                                                "Could not install PciConfig handler "
index abbf970..2919746 100644 (file)
@@ -166,6 +166,9 @@ acpi_status acpi_enter_sleep_state_s4bios(void)
 
        status = acpi_hw_write_port(acpi_gbl_FADT.smi_command,
                                    (u32)acpi_gbl_FADT.s4_bios_request, 8);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
        do {
                acpi_os_stall(ACPI_USEC_PER_MSEC);
index 14cbf63..c86d077 100644 (file)
@@ -486,5 +486,5 @@ acpi_ns_convert_to_reference(struct acpi_namespace_node *scope,
 error_exit:
        ACPI_FREE(name);
        *return_object = new_object;
-       return (AE_OK);
+       return (status);
 }
index 9731d7c..9ad340f 100644 (file)
@@ -291,7 +291,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
                                        for (i = 0;
                                             (i < obj_desc->buffer.length
                                              && i < 12); i++) {
-                                               acpi_os_printf(" %.2hX",
+                                               acpi_os_printf(" %2.2X",
                                                               obj_desc->buffer.
                                                               pointer[i]);
                                        }
@@ -404,7 +404,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
                case ACPI_TYPE_LOCAL_BANK_FIELD:
                case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
-                       acpi_os_printf(" Off %.3X Len %.2X Acc %.2hd\n",
+                       acpi_os_printf(" Off %.3X Len %.2X Acc %.2X\n",
                                       (obj_desc->common_field.
                                        base_byte_offset * 8)
                                       +
@@ -589,8 +589,6 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
 
                        goto cleanup;
                }
-
-               obj_type = ACPI_TYPE_INVALID;   /* Terminate loop after next pass */
        }
 
 cleanup:
index 55b4a5b..161e60d 100644 (file)
@@ -425,8 +425,8 @@ acpi_get_object_info(acpi_handle handle,
        }
 
        if (cls) {
-               next_id_string = acpi_ns_copy_device_id(&info->class_code,
-                                                       cls, next_id_string);
+               (void)acpi_ns_copy_device_id(&info->class_code,
+                                            cls, next_id_string);
        }
 
        /* Copy the fixed-length data */
index 98e5c74..ded2779 100644 (file)
@@ -481,8 +481,7 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
                        walk_state->opcode = (*op)->common.aml_opcode;
 
                        status = walk_state->ascending_callback(walk_state);
-                       status =
-                           acpi_ps_next_parse_state(walk_state, *op, status);
+                       (void)acpi_ps_next_parse_state(walk_state, *op, status);
 
                        status2 = acpi_ps_complete_this_op(walk_state, *op);
                        if (ACPI_FAILURE(status2)) {
@@ -490,7 +489,6 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
                        }
                }
 
-               status = AE_OK;
                break;
 
        case AE_CTRL_BREAK:
@@ -512,14 +510,13 @@ acpi_ps_complete_op(struct acpi_walk_state *walk_state,
                walk_state->opcode = (*op)->common.aml_opcode;
 
                status = walk_state->ascending_callback(walk_state);
-               status = acpi_ps_next_parse_state(walk_state, *op, status);
+               (void)acpi_ps_next_parse_state(walk_state, *op, status);
 
                status2 = acpi_ps_complete_this_op(walk_state, *op);
                if (ACPI_FAILURE(status2)) {
                        return_ACPI_STATUS(status2);
                }
 
-               status = AE_OK;
                break;
 
        case AE_CTRL_TERMINATE:
index 570ea0d..c659b54 100644 (file)
@@ -312,6 +312,9 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object,
                                path_buffer.pointer = user_prt->source;
 
                                status = acpi_ns_handle_to_pathname((acpi_handle)node, &path_buffer, FALSE);
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
 
                                /* +1 to include null terminator */
 
index 3094400..2cf3645 100644 (file)
@@ -933,6 +933,9 @@ acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node)
        }
 
        status = acpi_ns_load_table(table_index, parent_node);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
 
        /*
         * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
index 86f1693..0782acf 100644 (file)
@@ -268,6 +268,8 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)
  *
  * PARAMETERS:  table               - Pointer to a buffer containing the ACPI
  *                                    table to be loaded.
+ *              table_idx           - Pointer to a u32 for storing the table
+ *                                    index, might be NULL
  *
  * RETURN:      Status
  *
@@ -278,7 +280,7 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)
  *              to ensure that the table is not deleted or unmapped.
  *
  ******************************************************************************/
-acpi_status acpi_load_table(struct acpi_table_header *table)
+acpi_status acpi_load_table(struct acpi_table_header *table, u32 *table_idx)
 {
        acpi_status status;
        u32 table_index;
@@ -297,6 +299,10 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
        status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),
                                                ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
                                                FALSE, &table_index);
+       if (table_idx) {
+               *table_idx = table_index;
+       }
+
        if (ACPI_SUCCESS(status)) {
 
                /* Complete the initialization/resolution of new objects */
@@ -390,3 +396,35 @@ acpi_status acpi_unload_parent_table(acpi_handle object)
 }
 
 ACPI_EXPORT_SYMBOL(acpi_unload_parent_table)
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_unload_table
+ *
+ * PARAMETERS:  table_index         - Index as returned by acpi_load_table
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Via the table_index representing an SSDT or OEMx table, unloads
+ *              the table and deletes all namespace objects associated with
+ *              that table. Unloading of the DSDT is not allowed.
+ *              Note: Mainly intended to support hotplug removal of SSDTs.
+ *
+ ******************************************************************************/
+acpi_status acpi_unload_table(u32 table_index)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(acpi_unload_table);
+
+       if (table_index == 1) {
+
+               /* table_index==1 means DSDT is the owner. DSDT cannot be unloaded */
+
+               return_ACPI_STATUS(AE_TYPE);
+       }
+
+       status = acpi_tb_unload_table(table_index);
+       return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_unload_table)
index 61db996..db897af 100644 (file)
@@ -37,7 +37,9 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
        u32 j;
        u32 temp32;
        u8 buf_char;
+       u32 display_data_only = display & DB_DISPLAY_DATA_ONLY;
 
+       display &= ~DB_DISPLAY_DATA_ONLY;
        if (!buffer) {
                acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
                return;
@@ -53,7 +55,9 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
 
                /* Print current offset */
 
-               acpi_os_printf("%8.4X: ", (base_offset + i));
+               if (!display_data_only) {
+                       acpi_os_printf("%8.4X: ", (base_offset + i));
+               }
 
                /* Print 16 hex chars */
 
@@ -109,32 +113,34 @@ void acpi_ut_dump_buffer(u8 *buffer, u32 count, u32 display, u32 base_offset)
                 * Print the ASCII equivalent characters but watch out for the bad
                 * unprintable ones (printable chars are 0x20 through 0x7E)
                 */
-               acpi_os_printf(" ");
-               for (j = 0; j < 16; j++) {
-                       if (i + j >= count) {
-                               acpi_os_printf("\n");
-                               return;
+               if (!display_data_only) {
+                       acpi_os_printf(" ");
+                       for (j = 0; j < 16; j++) {
+                               if (i + j >= count) {
+                                       acpi_os_printf("\n");
+                                       return;
+                               }
+
+                               /*
+                                * Add comment characters so rest of line is ignored when
+                                * compiled
+                                */
+                               if (j == 0) {
+                                       acpi_os_printf("// ");
+                               }
+
+                               buf_char = buffer[(acpi_size)i + j];
+                               if (isprint(buf_char)) {
+                                       acpi_os_printf("%c", buf_char);
+                               } else {
+                                       acpi_os_printf(".");
+                               }
                        }
 
-                       /*
-                        * Add comment characters so rest of line is ignored when
-                        * compiled
-                        */
-                       if (j == 0) {
-                               acpi_os_printf("// ");
-                       }
+                       /* Done with that line. */
 
-                       buf_char = buffer[(acpi_size)i + j];
-                       if (isprint(buf_char)) {
-                               acpi_os_printf("%c", buf_char);
-                       } else {
-                               acpi_os_printf(".");
-                       }
+                       acpi_os_printf("\n");
                }
-
-               /* Done with that line. */
-
-               acpi_os_printf("\n");
                i += 16;
        }
 
index e805abd..30198c8 100644 (file)
@@ -289,9 +289,7 @@ acpi_ut_execute_CID(struct acpi_namespace_node *device_node,
                                                  value);
                        length = ACPI_EISAID_STRING_SIZE;
                } else {        /* ACPI_TYPE_STRING */
-
                        /* Copy the String CID from the returned object */
-
                        strcpy(next_id_string, cid_objects[i]->string.pointer);
                        length = cid_objects[i]->string.length + 1;
                }
index 8052f7e..14de4d1 100644 (file)
@@ -660,7 +660,7 @@ void acpi_ut_dump_allocations(u32 component, const char *module)
                                        case ACPI_DESC_TYPE_PARSER:
 
                                                acpi_os_printf
-                                                   ("AmlOpcode 0x%04hX\n",
+                                                   ("AmlOpcode 0x%04X\n",
                                                     descriptor->op.asl.
                                                     aml_opcode);
                                                break;
index 4a2cde2..d27b01c 100644 (file)
 #define ACPI_BUTTON_DEVICE_NAME_LID    "Lid Switch"
 #define ACPI_BUTTON_TYPE_LID           0x05
 
-#define ACPI_BUTTON_LID_INIT_IGNORE    0x00
-#define ACPI_BUTTON_LID_INIT_OPEN      0x01
-#define ACPI_BUTTON_LID_INIT_METHOD    0x02
+enum {
+       ACPI_BUTTON_LID_INIT_IGNORE,
+       ACPI_BUTTON_LID_INIT_OPEN,
+       ACPI_BUTTON_LID_INIT_METHOD,
+       ACPI_BUTTON_LID_INIT_DISABLED,
+};
+
+static const char * const lid_init_state_str[] = {
+       [ACPI_BUTTON_LID_INIT_IGNORE]           = "ignore",
+       [ACPI_BUTTON_LID_INIT_OPEN]             = "open",
+       [ACPI_BUTTON_LID_INIT_METHOD]           = "method",
+       [ACPI_BUTTON_LID_INIT_DISABLED]         = "disabled",
+};
 
 #define _COMPONENT             ACPI_BUTTON_COMPONENT
 ACPI_MODULE_NAME("button");
@@ -65,18 +75,39 @@ static const struct acpi_device_id button_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, button_device_ids);
 
-/*
- * Some devices which don't even have a lid in anyway have a broken _LID
- * method (e.g. pointing to a floating gpio pin) causing spurious LID events.
- */
-static const struct dmi_system_id lid_blacklst[] = {
+/* Please keep this list sorted alphabetically by vendor and model */
+static const struct dmi_system_id dmi_lid_quirks[] = {
+       {
+               /*
+                * Asus T200TA, _LID keeps reporting closed after every second
+                * openening of the lid. Causing immediate re-suspend after
+                * opening every other open. Using LID_INIT_OPEN fixes this.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
+               },
+               .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
+       },
        {
-               /* GP-electronic T701 */
+               /* GP-electronic T701, _LID method points to a floating GPIO */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
                        DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
                },
+               .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
+       },
+       {
+               /*
+                * Medion Akoya E2215T, notification of the LID device only
+                * happens on close, not on open and _LID always returns closed.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "E2215T MD60198"),
+               },
+               .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
        },
        {}
 };
@@ -116,9 +147,8 @@ struct acpi_button {
        bool suspended;
 };
 
-static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
 static struct acpi_device *lid_device;
-static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
+static long lid_init_state = -1;
 
 static unsigned long lid_report_interval __read_mostly = 500;
 module_param(lid_report_interval, ulong, 0644);
@@ -146,7 +176,6 @@ static int acpi_lid_evaluate_state(struct acpi_device *device)
 static int acpi_lid_notify_state(struct acpi_device *device, int state)
 {
        struct acpi_button *button = acpi_driver_data(device);
-       int ret;
        ktime_t next_report;
        bool do_update;
 
@@ -223,18 +252,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
                button->last_time = ktime_get();
        }
 
-       ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
-       if (ret == NOTIFY_DONE)
-               ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
-                                                  device);
-       if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
-               /*
-                * It is also regarded as success if the notifier_chain
-                * returns NOTIFY_OK or NOTIFY_DONE.
-                */
-               ret = 0;
-       }
-       return ret;
+       return 0;
 }
 
 static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq,
@@ -331,18 +349,6 @@ static int acpi_button_remove_fs(struct acpi_device *device)
 /* --------------------------------------------------------------------------
                                 Driver Interface
    -------------------------------------------------------------------------- */
-int acpi_lid_notifier_register(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
-}
-EXPORT_SYMBOL(acpi_lid_notifier_register);
-
-int acpi_lid_notifier_unregister(struct notifier_block *nb)
-{
-       return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
-}
-EXPORT_SYMBOL(acpi_lid_notifier_unregister);
-
 int acpi_lid_open(void)
 {
        if (!lid_device)
@@ -472,7 +478,8 @@ static int acpi_button_add(struct acpi_device *device)
        char *name, *class;
        int error;
 
-       if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst))
+       if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
+            lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
                return -ENODEV;
 
        button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
@@ -578,36 +585,30 @@ static int acpi_button_remove(struct acpi_device *device)
 static int param_set_lid_init_state(const char *val,
                                    const struct kernel_param *kp)
 {
-       int result = 0;
-
-       if (!strncmp(val, "open", sizeof("open") - 1)) {
-               lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
-               pr_info("Notify initial lid state as open\n");
-       } else if (!strncmp(val, "method", sizeof("method") - 1)) {
-               lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
-               pr_info("Notify initial lid state with _LID return value\n");
-       } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
-               lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
-               pr_info("Do not notify initial lid state\n");
-       } else
-               result = -EINVAL;
-       return result;
+       int i;
+
+       i = sysfs_match_string(lid_init_state_str, val);
+       if (i < 0)
+               return i;
+
+       lid_init_state = i;
+       pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]);
+       return 0;
 }
 
-static int param_get_lid_init_state(char *buffer,
-                                   const struct kernel_param *kp)
+static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
 {
-       switch (lid_init_state) {
-       case ACPI_BUTTON_LID_INIT_OPEN:
-               return sprintf(buffer, "open");
-       case ACPI_BUTTON_LID_INIT_METHOD:
-               return sprintf(buffer, "method");
-       case ACPI_BUTTON_LID_INIT_IGNORE:
-               return sprintf(buffer, "ignore");
-       default:
-               return sprintf(buffer, "invalid");
-       }
-       return 0;
+       int i, c = 0;
+
+       for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
+               if (i == lid_init_state)
+                       c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
+               else
+                       c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
+
+       buf[c - 1] = '\n'; /* Replace the final space with a newline */
+
+       return c;
 }
 
 module_param_call(lid_init_state,
@@ -617,6 +618,16 @@ MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
 
 static int acpi_button_register_driver(struct acpi_driver *driver)
 {
+       const struct dmi_system_id *dmi_id;
+
+       if (lid_init_state == -1) {
+               dmi_id = dmi_first_match(dmi_lid_quirks);
+               if (dmi_id)
+                       lid_init_state = (long)dmi_id->driver_data;
+               else
+                       lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
+       }
+
        /*
         * Modules such as nouveau.ko and i915.ko have a link time dependency
         * on acpi_lid_open(), and would therefore not be loadable on ACPI
index bd75caf..d05be13 100644 (file)
@@ -95,12 +95,12 @@ enum {
        EC_FLAGS_QUERY_ENABLED,         /* Query is enabled */
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
        EC_FLAGS_QUERY_GUARDING,        /* Guard for SCI_EVT check */
-       EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */
+       EC_FLAGS_EVENT_HANDLER_INSTALLED,       /* Event handler installed */
        EC_FLAGS_EC_HANDLER_INSTALLED,  /* OpReg handler installed */
-       EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
+       EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
        EC_FLAGS_STARTED,               /* Driver is started */
        EC_FLAGS_STOPPED,               /* Driver is stopped */
-       EC_FLAGS_GPE_MASKED,            /* GPE masked */
+       EC_FLAGS_EVENTS_MASKED,         /* Events masked */
 };
 
 #define ACPI_EC_COMMAND_POLL           0x01 /* Available for command byte */
@@ -397,8 +397,8 @@ static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
 static void acpi_ec_submit_request(struct acpi_ec *ec)
 {
        ec->reference_count++;
-       if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
-           ec->reference_count == 1)
+       if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+           ec->gpe >= 0 && ec->reference_count == 1)
                acpi_ec_enable_gpe(ec, true);
 }
 
@@ -407,28 +407,36 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
        bool flushed = false;
 
        ec->reference_count--;
-       if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
-           ec->reference_count == 0)
+       if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
+           ec->gpe >= 0 && ec->reference_count == 0)
                acpi_ec_disable_gpe(ec, true);
        flushed = acpi_ec_flushed(ec);
        if (flushed)
                wake_up(&ec->wait);
 }
 
-static void acpi_ec_mask_gpe(struct acpi_ec *ec)
+static void acpi_ec_mask_events(struct acpi_ec *ec)
 {
-       if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
-               acpi_ec_disable_gpe(ec, false);
+       if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+               if (ec->gpe >= 0)
+                       acpi_ec_disable_gpe(ec, false);
+               else
+                       disable_irq_nosync(ec->irq);
+
                ec_dbg_drv("Polling enabled");
-               set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
+               set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
        }
 }
 
-static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
+static void acpi_ec_unmask_events(struct acpi_ec *ec)
 {
-       if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
-               clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
-               acpi_ec_enable_gpe(ec, false);
+       if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
+               clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
+               if (ec->gpe >= 0)
+                       acpi_ec_enable_gpe(ec, false);
+               else
+                       enable_irq(ec->irq);
+
                ec_dbg_drv("Polling disabled");
        }
 }
@@ -454,7 +462,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
 
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
-       acpi_ec_mask_gpe(ec);
+       acpi_ec_mask_events(ec);
        if (!acpi_ec_event_enabled(ec))
                return;
        if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@@ -470,7 +478,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
        if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
                ec_dbg_evt("Command(%s) unblocked",
                           acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
-       acpi_ec_unmask_gpe(ec);
+       acpi_ec_unmask_events(ec);
 }
 
 static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@@ -638,7 +646,9 @@ static void advance_transaction(struct acpi_ec *ec)
         * ensure a hardware STS 0->1 change after this clearing can always
         * trigger a GPE interrupt.
         */
-       acpi_ec_clear_gpe(ec);
+       if (ec->gpe >= 0)
+               acpi_ec_clear_gpe(ec);
+
        status = acpi_ec_read_status(ec);
        t = ec->curr;
        /*
@@ -707,7 +717,7 @@ err:
                                ++t->irq_count;
                        /* Allow triggering on 0 threshold */
                        if (t->irq_count == ec_storm_threshold)
-                               acpi_ec_mask_gpe(ec);
+                               acpi_ec_mask_events(ec);
                }
        }
 out:
@@ -805,7 +815,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
 
        spin_lock_irqsave(&ec->lock, tmp);
        if (t->irq_count == ec_storm_threshold)
-               acpi_ec_unmask_gpe(ec);
+               acpi_ec_unmask_events(ec);
        ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
        ec->curr = NULL;
        /* Disable GPE for command processing (IBF=0/OBF=1) */
@@ -1265,18 +1275,28 @@ static void acpi_ec_event_handler(struct work_struct *work)
        acpi_ec_check_event(ec);
 }
 
-static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
-       u32 gpe_number, void *data)
+static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
 {
        unsigned long flags;
-       struct acpi_ec *ec = data;
 
        spin_lock_irqsave(&ec->lock, flags);
        advance_transaction(ec);
        spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
+                              u32 gpe_number, void *data)
+{
+       acpi_ec_handle_interrupt(data);
        return ACPI_INTERRUPT_HANDLED;
 }
 
+static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
+{
+       acpi_ec_handle_interrupt(data);
+       return IRQ_HANDLED;
+}
+
 /* --------------------------------------------------------------------------
  *                           Address Space Management
  * -------------------------------------------------------------------------- */
@@ -1349,6 +1369,8 @@ static struct acpi_ec *acpi_ec_alloc(void)
        ec->timestamp = jiffies;
        ec->busy_polling = true;
        ec->polling_guard = 0;
+       ec->gpe = -1;
+       ec->irq = -1;
        return ec;
 }
 
@@ -1396,9 +1418,13 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
                /* Get GPE bit assignment (EC events). */
                /* TODO: Add support for _GPE returning a package */
                status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
-               if (ACPI_FAILURE(status))
-                       return status;
-               ec->gpe = tmp;
+               if (ACPI_SUCCESS(status))
+                       ec->gpe = tmp;
+
+               /*
+                * Errors are non-fatal, allowing for ACPI Reduced Hardware
+                * platforms which use GpioInt instead of GPE.
+                */
        }
        /* Use the global lock for all EC transactions? */
        tmp = 0;
@@ -1408,12 +1434,57 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
        return AE_CTRL_TERMINATE;
 }
 
+static void install_gpe_event_handler(struct acpi_ec *ec)
+{
+       acpi_status status =
+               acpi_install_gpe_raw_handler(NULL, ec->gpe,
+                                            ACPI_GPE_EDGE_TRIGGERED,
+                                            &acpi_ec_gpe_handler,
+                                            ec);
+       if (ACPI_SUCCESS(status)) {
+               /* This is not fatal as we can poll EC events */
+               set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+               acpi_ec_leave_noirq(ec);
+               if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+                   ec->reference_count >= 1)
+                       acpi_ec_enable_gpe(ec, true);
+       }
+}
+
+/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
+static int install_gpio_irq_event_handler(struct acpi_ec *ec,
+                                         struct acpi_device *device)
+{
+       int irq = acpi_dev_gpio_irq_get(device, 0);
+       int ret;
+
+       if (irq < 0)
+               return irq;
+
+       ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
+                         "ACPI EC", ec);
+
+       /*
+        * Unlike the GPE case, we treat errors here as fatal, we'll only
+        * implement GPIO polling if we find a case that needs it.
+        */
+       if (ret < 0)
+               return ret;
+
+       ec->irq = irq;
+       set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
+       acpi_ec_leave_noirq(ec);
+
+       return 0;
+}
+
 /*
  * Note: This function returns an error code only when the address space
  *       handler is not installed, which means "not able to handle
  *       transactions".
  */
-static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
+static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
+                              bool handle_events)
 {
        acpi_status status;
 
@@ -1446,24 +1517,23 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
        if (!handle_events)
                return 0;
 
-       if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+       if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
                /* Find and register all query methods */
                acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
                                    acpi_ec_register_query_methods,
                                    NULL, ec, NULL);
-               set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+               set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
        }
-       if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
-               status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
-                                         ACPI_GPE_EDGE_TRIGGERED,
-                                         &acpi_ec_gpe_handler, ec);
-               /* This is not fatal as we can poll EC events */
-               if (ACPI_SUCCESS(status)) {
-                       set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
-                       acpi_ec_leave_noirq(ec);
-                       if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-                           ec->reference_count >= 1)
-                               acpi_ec_enable_gpe(ec, true);
+       if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+               if (ec->gpe >= 0) {
+                       install_gpe_event_handler(ec);
+               } else if (device) {
+                       int ret = install_gpio_irq_event_handler(ec, device);
+
+                       if (ret)
+                               return ret;
+               } else { /* No GPE and no GpioInt? */
+                       return -ENODEV;
                }
        }
        /* EC is fully operational, allow queries */
@@ -1494,23 +1564,29 @@ static void ec_remove_handlers(struct acpi_ec *ec)
         */
        acpi_ec_stop(ec, false);
 
-       if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
-               if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
-                                       &acpi_ec_gpe_handler)))
+       if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
+               if (ec->gpe >= 0 &&
+                   ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
+                                &acpi_ec_gpe_handler)))
                        pr_err("failed to remove gpe handler\n");
-               clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
+
+               if (ec->irq >= 0)
+                       free_irq(ec->irq, ec);
+
+               clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
        }
-       if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
+       if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
                acpi_ec_remove_query_handlers(ec, true, 0);
-               clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
+               clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
        }
 }
 
-static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
+static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device,
+                        bool handle_events)
 {
        int ret;
 
-       ret = ec_install_handlers(ec, handle_events);
+       ret = ec_install_handlers(ec, device, handle_events);
        if (ret)
                return ret;
 
@@ -1521,8 +1597,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
        }
 
        acpi_handle_info(ec->handle,
-                        "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
-                        ec->gpe, ec->command_addr, ec->data_addr);
+                        "GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
+                        ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
        return ret;
 }
 
@@ -1586,7 +1662,7 @@ static int acpi_ec_add(struct acpi_device *device)
                }
        }
 
-       ret = acpi_ec_setup(ec, true);
+       ret = acpi_ec_setup(ec, device, true);
        if (ret)
                goto err_query;
 
@@ -1706,7 +1782,7 @@ void __init acpi_ec_dsdt_probe(void)
         * At this point, the GPE is not fully initialized, so do not to
         * handle the events.
         */
-       ret = acpi_ec_setup(ec, false);
+       ret = acpi_ec_setup(ec, NULL, false);
        if (ret) {
                acpi_ec_free(ec);
                return;
@@ -1879,14 +1955,21 @@ void __init acpi_ec_ecdt_probe(void)
                ec->command_addr = ecdt_ptr->control.address;
                ec->data_addr = ecdt_ptr->data.address;
        }
-       ec->gpe = ecdt_ptr->gpe;
+
+       /*
+        * Ignore the GPE value on Reduced Hardware platforms.
+        * Some products have this set to an erroneous value.
+        */
+       if (!acpi_gbl_reduced_hardware)
+               ec->gpe = ecdt_ptr->gpe;
+
        ec->handle = ACPI_ROOT_OBJECT;
 
        /*
         * At this point, the namespace is not initialized, so do not find
         * the namespace objects, or handle the events.
         */
-       ret = acpi_ec_setup(ec, false);
+       ret = acpi_ec_setup(ec, NULL, false);
        if (ret) {
                acpi_ec_free(ec);
                return;
@@ -1918,7 +2001,7 @@ static int acpi_ec_suspend_noirq(struct device *dev)
         * masked at the low level without side effects.
         */
        if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-           ec->reference_count >= 1)
+           ec->gpe >= 0 && ec->reference_count >= 1)
                acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
 
        acpi_ec_enter_noirq(ec);
@@ -1933,7 +2016,7 @@ static int acpi_ec_resume_noirq(struct device *dev)
        acpi_ec_leave_noirq(ec);
 
        if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
-           ec->reference_count >= 1)
+           ec->gpe >= 0 && ec->reference_count >= 1)
                acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
 
        return 0;
diff --git a/drivers/acpi/hmat/Makefile b/drivers/acpi/hmat/Makefile
deleted file mode 100644 (file)
index 1c20ef3..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-obj-$(CONFIG_ACPI_HMAT) := hmat.o
index afe6636..3616dae 100644 (file)
@@ -165,7 +165,8 @@ static inline void acpi_early_processor_osc(void) {}
    -------------------------------------------------------------------------- */
 struct acpi_ec {
        acpi_handle handle;
-       u32 gpe;
+       int gpe;
+       int irq;
        unsigned long command_addr;
        unsigned long data_addr;
        bool global_lock;
similarity index 75%
rename from drivers/acpi/hmat/Kconfig
rename to drivers/acpi/numa/Kconfig
index 95a2996..fcf2e55 100644 (file)
@@ -1,8 +1,15 @@
 # SPDX-License-Identifier: GPL-2.0
+config ACPI_NUMA
+       bool "NUMA support"
+       depends on NUMA
+       depends on (X86 || IA64 || ARM64)
+       default y if IA64 || ARM64
+
 config ACPI_HMAT
        bool "ACPI Heterogeneous Memory Attribute Table Support"
        depends on ACPI_NUMA
        select HMEM_REPORTING
+       select MEMREGION
        help
         If set, this option has the kernel parse and report the
         platform's ACPI HMAT (Heterogeneous Memory Attributes Table),
diff --git a/drivers/acpi/numa/Makefile b/drivers/acpi/numa/Makefile
new file mode 100644 (file)
index 0000000..517a6c6
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_ACPI_NUMA) += srat.o
+obj-$(CONFIG_ACPI_HMAT) += hmat.o
similarity index 82%
rename from drivers/acpi/hmat/hmat.c
rename to drivers/acpi/numa/hmat.c
index 8b0de8a..2c32cfb 100644 (file)
@@ -8,12 +8,18 @@
  * the applicable attributes with the node's interfaces.
  */
 
+#define pr_fmt(fmt) "acpi/hmat: " fmt
+#define dev_fmt(fmt) "acpi/hmat: " fmt
+
 #include <linux/acpi.h>
 #include <linux/bitops.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
 #include <linux/list_sort.h>
+#include <linux/memregion.h>
 #include <linux/memory.h>
 #include <linux/mutex.h>
 #include <linux/node.h>
@@ -49,6 +55,7 @@ struct memory_target {
        struct list_head node;
        unsigned int memory_pxm;
        unsigned int processor_pxm;
+       struct resource memregions;
        struct node_hmem_attrs hmem_attrs;
        struct list_head caches;
        struct node_cache_attrs cache_attrs;
@@ -104,22 +111,36 @@ static __init void alloc_memory_initiator(unsigned int cpu_pxm)
        list_add_tail(&initiator->node, &initiators);
 }
 
-static __init void alloc_memory_target(unsigned int mem_pxm)
+static __init void alloc_memory_target(unsigned int mem_pxm,
+               resource_size_t start, resource_size_t len)
 {
        struct memory_target *target;
 
        target = find_mem_target(mem_pxm);
-       if (target)
-               return;
-
-       target = kzalloc(sizeof(*target), GFP_KERNEL);
-       if (!target)
-               return;
+       if (!target) {
+               target = kzalloc(sizeof(*target), GFP_KERNEL);
+               if (!target)
+                       return;
+               target->memory_pxm = mem_pxm;
+               target->processor_pxm = PXM_INVAL;
+               target->memregions = (struct resource) {
+                       .name   = "ACPI mem",
+                       .start  = 0,
+                       .end    = -1,
+                       .flags  = IORESOURCE_MEM,
+               };
+               list_add_tail(&target->node, &targets);
+               INIT_LIST_HEAD(&target->caches);
+       }
 
-       target->memory_pxm = mem_pxm;
-       target->processor_pxm = PXM_INVAL;
-       list_add_tail(&target->node, &targets);
-       INIT_LIST_HEAD(&target->caches);
+       /*
+        * There are potentially multiple ranges per PXM, so record each
+        * in the per-target memregions resource tree.
+        */
+       if (!__request_region(&target->memregions, start, len, "memory target",
+                               IORESOURCE_MEM))
+               pr_warn("failed to reserve %#llx - %#llx in pxm: %d\n",
+                               start, start + len, mem_pxm);
 }
 
 static __init const char *hmat_data_type(u8 type)
@@ -272,7 +293,7 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header,
        u8 type, mem_hier;
 
        if (hmat_loc->header.length < sizeof(*hmat_loc)) {
-               pr_notice("HMAT: Unexpected locality header length: %d\n",
+               pr_notice("HMAT: Unexpected locality header length: %u\n",
                         hmat_loc->header.length);
                return -EINVAL;
        }
@@ -284,12 +305,12 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header,
        total_size = sizeof(*hmat_loc) + sizeof(*entries) * ipds * tpds +
                     sizeof(*inits) * ipds + sizeof(*targs) * tpds;
        if (hmat_loc->header.length < total_size) {
-               pr_notice("HMAT: Unexpected locality header length:%d, minimum required:%d\n",
+               pr_notice("HMAT: Unexpected locality header length:%u, minimum required:%u\n",
                         hmat_loc->header.length, total_size);
                return -EINVAL;
        }
 
-       pr_info("HMAT: Locality: Flags:%02x Type:%s Initiator Domains:%d Target Domains:%d Base:%lld\n",
+       pr_info("HMAT: Locality: Flags:%02x Type:%s Initiator Domains:%u Target Domains:%u Base:%lld\n",
                hmat_loc->flags, hmat_data_type(type), ipds, tpds,
                hmat_loc->entry_base_unit);
 
@@ -302,7 +323,7 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header,
                        value = hmat_normalize(entries[init * tpds + targ],
                                               hmat_loc->entry_base_unit,
                                               type);
-                       pr_info("  Initiator-Target[%d-%d]:%d%s\n",
+                       pr_info("  Initiator-Target[%u-%u]:%u%s\n",
                                inits[init], targs[targ], value,
                                hmat_data_type_suffix(type));
 
@@ -329,13 +350,13 @@ static __init int hmat_parse_cache(union acpi_subtable_headers *header,
        u32 attrs;
 
        if (cache->header.length < sizeof(*cache)) {
-               pr_notice("HMAT: Unexpected cache header length: %d\n",
+               pr_notice("HMAT: Unexpected cache header length: %u\n",
                         cache->header.length);
                return -EINVAL;
        }
 
        attrs = cache->cache_attributes;
-       pr_info("HMAT: Cache: Domain:%d Size:%llu Attrs:%08x SMBIOS Handles:%d\n",
+       pr_info("HMAT: Cache: Domain:%u Size:%llu Attrs:%08x SMBIOS Handles:%d\n",
                cache->memory_PD, cache->cache_size, attrs,
                cache->number_of_SMBIOShandles);
 
@@ -390,17 +411,17 @@ static int __init hmat_parse_proximity_domain(union acpi_subtable_headers *heade
        struct memory_target *target = NULL;
 
        if (p->header.length != sizeof(*p)) {
-               pr_notice("HMAT: Unexpected address range header length: %d\n",
+               pr_notice("HMAT: Unexpected address range header length: %u\n",
                         p->header.length);
                return -EINVAL;
        }
 
        if (hmat_revision == 1)
-               pr_info("HMAT: Memory (%#llx length %#llx) Flags:%04x Processor Domain:%d Memory Domain:%d\n",
+               pr_info("HMAT: Memory (%#llx length %#llx) Flags:%04x Processor Domain:%u Memory Domain:%u\n",
                        p->reserved3, p->reserved4, p->flags, p->processor_PD,
                        p->memory_PD);
        else
-               pr_info("HMAT: Memory Flags:%04x Processor Domain:%d Memory Domain:%d\n",
+               pr_info("HMAT: Memory Flags:%04x Processor Domain:%u Memory Domain:%u\n",
                        p->flags, p->processor_PD, p->memory_PD);
 
        if (p->flags & ACPI_HMAT_MEMORY_PD_VALID && hmat_revision == 1) {
@@ -417,7 +438,7 @@ static int __init hmat_parse_proximity_domain(union acpi_subtable_headers *heade
                        pr_debug("HMAT: Invalid Processor Domain\n");
                        return -EINVAL;
                }
-               target->processor_pxm = p_node;
+               target->processor_pxm = p->processor_PD;
        }
 
        return 0;
@@ -452,7 +473,7 @@ static __init int srat_parse_mem_affinity(union acpi_subtable_headers *header,
                return -EINVAL;
        if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
                return 0;
-       alloc_memory_target(ma->proximity_domain);
+       alloc_memory_target(ma->proximity_domain, ma->base_address, ma->length);
        return 0;
 }
 
@@ -613,11 +634,92 @@ static void hmat_register_target_perf(struct memory_target *target)
        node_set_perf_attrs(mem_nid, &target->hmem_attrs, 0);
 }
 
+static void hmat_register_target_device(struct memory_target *target,
+               struct resource *r)
+{
+       /* define a clean / non-busy resource for the platform device */
+       struct resource res = {
+               .start = r->start,
+               .end = r->end,
+               .flags = IORESOURCE_MEM,
+       };
+       struct platform_device *pdev;
+       struct memregion_info info;
+       int rc, id;
+
+       rc = region_intersects(res.start, resource_size(&res), IORESOURCE_MEM,
+                       IORES_DESC_SOFT_RESERVED);
+       if (rc != REGION_INTERSECTS)
+               return;
+
+       id = memregion_alloc(GFP_KERNEL);
+       if (id < 0) {
+               pr_err("memregion allocation failure for %pr\n", &res);
+               return;
+       }
+
+       pdev = platform_device_alloc("hmem", id);
+       if (!pdev) {
+               pr_err("hmem device allocation failure for %pr\n", &res);
+               goto out_pdev;
+       }
+
+       pdev->dev.numa_node = acpi_map_pxm_to_online_node(target->memory_pxm);
+       info = (struct memregion_info) {
+               .target_node = acpi_map_pxm_to_node(target->memory_pxm),
+       };
+       rc = platform_device_add_data(pdev, &info, sizeof(info));
+       if (rc < 0) {
+               pr_err("hmem memregion_info allocation failure for %pr\n", &res);
+               goto out_pdev;
+       }
+
+       rc = platform_device_add_resources(pdev, &res, 1);
+       if (rc < 0) {
+               pr_err("hmem resource allocation failure for %pr\n", &res);
+               goto out_resource;
+       }
+
+       rc = platform_device_add(pdev);
+       if (rc < 0) {
+               dev_err(&pdev->dev, "device add failed for %pr\n", &res);
+               goto out_resource;
+       }
+
+       return;
+
+out_resource:
+       put_device(&pdev->dev);
+out_pdev:
+       memregion_free(id);
+}
+
+static void hmat_register_target_devices(struct memory_target *target)
+{
+       struct resource *res;
+
+       /*
+        * Do not bother creating devices if no driver is available to
+        * consume them.
+        */
+       if (!IS_ENABLED(CONFIG_DEV_DAX_HMEM))
+               return;
+
+       for (res = target->memregions.child; res; res = res->sibling)
+               hmat_register_target_device(target, res);
+}
+
 static void hmat_register_target(struct memory_target *target)
 {
        int nid = pxm_to_node(target->memory_pxm);
 
        /*
+        * Devices may belong to either an offline or online
+        * node, so unconditionally add them.
+        */
+       hmat_register_target_devices(target);
+
+       /*
         * Skip offline nodes. This can happen when memory
         * marked EFI_MEMORY_SP, "specific purpose", is applied
         * to all the memory in a promixity domain leading to
@@ -677,11 +779,21 @@ static __init void hmat_free_structures(void)
        struct target_cache *tcache, *cnext;
 
        list_for_each_entry_safe(target, tnext, &targets, node) {
+               struct resource *res, *res_next;
+
                list_for_each_entry_safe(tcache, cnext, &target->caches, node) {
                        list_del(&tcache->node);
                        kfree(tcache);
                }
+
                list_del(&target->node);
+               res = target->memregions.child;
+               while (res) {
+                       res_next = res->sibling;
+                       __release_region(&target->memregions, res->start,
+                                       resource_size(res));
+                       res = res_next;
+               }
                kfree(target);
        }
 
@@ -748,4 +860,4 @@ out_put:
        acpi_put_table(tbl);
        return 0;
 }
-subsys_initcall(hmat_init);
+device_initcall(hmat_init);
similarity index 100%
rename from drivers/acpi/numa.c
rename to drivers/acpi/numa/srat.c
index bec0beb..9f68538 100644 (file)
@@ -473,9 +473,9 @@ static const struct dmi_system_id acpi_osi_dmi_table[] __initconst = {
         */
 
        /*
-        * Without this this EEEpc exports a non working WMI interface, with
-        * this it exports a working "good old" eeepc_laptop interface, fixing
-        * both brightness control, and rfkill not working.
+        * Without this EEEpc exports a non working WMI interface, with
+        * this it exports a working "good old" eeepc_laptop interface,
+        * fixing both brightness control, and rfkill not working.
         */
        {
        .callback = dmi_enable_osi_linux,
index 4520413..a371f27 100644 (file)
@@ -252,7 +252,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
                                        struct regmap *regmap,
                                        struct intel_pmic_opregion_data *d)
 {
-       acpi_status status;
+       acpi_status status = AE_OK;
        struct intel_pmic_opregion *opregion;
        int ret;
 
@@ -270,7 +270,8 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
        opregion->regmap = regmap;
        opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
 
-       status = acpi_install_address_space_handler(handle,
+       if (d->power_table_count)
+               status = acpi_install_address_space_handler(handle,
                                                    PMIC_POWER_OPREGION_ID,
                                                    intel_pmic_power_handler,
                                                    NULL, opregion);
@@ -279,7 +280,8 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
                goto out_error;
        }
 
-       status = acpi_install_address_space_handler(handle,
+       if (d->thermal_table_count)
+               status = acpi_install_address_space_handler(handle,
                                                    PMIC_THERMAL_OPREGION_ID,
                                                    intel_pmic_thermal_handler,
                                                    NULL, opregion);
@@ -301,12 +303,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
        return 0;
 
 out_remove_thermal_handler:
-       acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID,
-                                         intel_pmic_thermal_handler);
+       if (d->thermal_table_count)
+               acpi_remove_address_space_handler(handle,
+                                                 PMIC_THERMAL_OPREGION_ID,
+                                                 intel_pmic_thermal_handler);
 
 out_remove_power_handler:
-       acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
-                                         intel_pmic_power_handler);
+       if (d->power_table_count)
+               acpi_remove_address_space_handler(handle,
+                                                 PMIC_POWER_OPREGION_ID,
+                                                 intel_pmic_power_handler);
 
 out_error:
        acpi_lpat_free_conversion_table(opregion->lpat_table);
similarity index 98%
rename from drivers/acpi/pmic/intel_pmic_crc.c
rename to drivers/acpi/pmic/intel_pmic_bytcrc.c
index a0f411a..2a692cc 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Intel CrystalCove PMIC operation region driver
+ * Intel Bay Trail Crystal Cove PMIC operation region driver
  *
  * Copyright (C) 2014 Intel Corporation. All rights reserved.
  */
@@ -295,7 +295,7 @@ static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
 static struct platform_driver intel_crc_pmic_opregion_driver = {
        .probe = intel_crc_pmic_opregion_probe,
        .driver = {
-               .name = "crystal_cove_pmic",
+               .name = "byt_crystal_cove_pmic",
        },
 };
 builtin_platform_driver(intel_crc_pmic_opregion_driver);
diff --git a/drivers/acpi/pmic/intel_pmic_chtcrc.c b/drivers/acpi/pmic/intel_pmic_chtcrc.c
new file mode 100644 (file)
index 0000000..ebf8d31
--- /dev/null
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Intel Cherry Trail Crystal Cove PMIC operation region driver
+ *
+ * Copyright (C) 2019 Hans de Goede <hdegoede@redhat.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/init.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+/*
+ * We have no docs for the CHT Crystal Cove PMIC. The Asus Zenfone-2 kernel
+ * code has 2 Crystal Cove regulator drivers, one calls the PMIC a "Crystal
+ * Cove Plus" PMIC and talks about Cherry Trail, so presuambly that one
+ * could be used to get register info for the regulators if we need to
+ * implement regulator support in the future.
+ *
+ * For now the sole purpose of this driver is to make
+ * intel_soc_pmic_exec_mipi_pmic_seq_element work on devices with a
+ * CHT Crystal Cove PMIC.
+ */
+static struct intel_pmic_opregion_data intel_chtcrc_pmic_opregion_data = {
+       .pmic_i2c_address = 0x6e,
+};
+
+static int intel_chtcrc_pmic_opregion_probe(struct platform_device *pdev)
+{
+       struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+       return intel_pmic_install_opregion_handler(&pdev->dev,
+                       ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
+                       &intel_chtcrc_pmic_opregion_data);
+}
+
+static struct platform_driver intel_chtcrc_pmic_opregion_driver = {
+       .probe = intel_chtcrc_pmic_opregion_probe,
+       .driver = {
+               .name = "cht_crystal_cove_pmic",
+       },
+};
+builtin_platform_driver(intel_chtcrc_pmic_opregion_driver);
index aad6be5..915650b 100644 (file)
@@ -2174,6 +2174,7 @@ int __init acpi_scan_init(void)
        acpi_pci_root_init();
        acpi_pci_link_init();
        acpi_processor_init();
+       acpi_platform_init();
        acpi_lpss_init();
        acpi_apd_init();
        acpi_cmos_rtc_init();
index e3974a8..804ac0d 100644 (file)
@@ -455,6 +455,7 @@ EXPORT_SYMBOL(acpi_evaluate_ost);
 
 /**
  * acpi_handle_path: Return the object path of handle
+ * @handle: ACPI device handle
  *
  * Caller must free the returned buffer
  */
@@ -473,6 +474,9 @@ static char *acpi_handle_path(acpi_handle handle)
 
 /**
  * acpi_handle_printk: Print message with ACPI prefix and object path
+ * @level: log level
+ * @handle: ACPI device handle
+ * @fmt: format string
  *
  * This function is called through acpi_handle_<level> macros and prints
  * a message with ACPI prefix and object path.  This function acquires
@@ -501,6 +505,9 @@ EXPORT_SYMBOL(acpi_handle_printk);
 #if defined(CONFIG_DYNAMIC_DEBUG)
 /**
  * __acpi_handle_debug: pr_debug with ACPI prefix and object path
+ * @descriptor: Dynamic Debug descriptor
+ * @handle: ACPI device handle
+ * @fmt: format string
  *
  * This function is called through acpi_handle_debug macro and debug
  * prints a message with ACPI prefix and object path. This function
@@ -695,6 +702,31 @@ bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs)
 EXPORT_SYMBOL(acpi_check_dsm);
 
 /**
+ * acpi_dev_hid_uid_match - Match device by supplied HID and UID
+ * @adev: ACPI device to match.
+ * @hid2: Hardware ID of the device.
+ * @uid2: Unique ID of the device, pass NULL to not check _UID.
+ *
+ * Matches HID and UID in @adev with given @hid2 and @uid2.
+ * Returns true if matches.
+ */
+bool acpi_dev_hid_uid_match(struct acpi_device *adev,
+                           const char *hid2, const char *uid2)
+{
+       const char *hid1 = acpi_device_hid(adev);
+       const char *uid1 = acpi_device_uid(adev);
+
+       if (strcmp(hid1, hid2))
+               return false;
+
+       if (!uid2)
+               return true;
+
+       return uid1 && !strcmp(uid1, uid2);
+}
+EXPORT_SYMBOL(acpi_dev_hid_uid_match);
+
+/**
  * acpi_dev_found - Detect presence of a given ACPI device in the namespace.
  * @hid: Hardware ID of the device.
  *
index 28b92e3..c3b3b5c 100644 (file)
@@ -148,6 +148,10 @@ config DEBUG_TEST_DRIVER_REMOVE
          unusable. You should say N here unless you are explicitly looking to
          test this functionality.
 
+config PM_QOS_KUNIT_TEST
+       bool "KUnit Test for PM QoS features"
+       depends on KUNIT
+
 config HMEM_REPORTING
        bool
        default n
index ec5bb19..8fdd007 100644 (file)
@@ -4,5 +4,6 @@ obj-$(CONFIG_PM_SLEEP)  += main.o wakeup.o wakeup_stats.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
 obj-$(CONFIG_PM_GENERIC_DOMAINS)       +=  domain.o domain_governor.o
 obj-$(CONFIG_HAVE_CLK) += clock_ops.o
+obj-$(CONFIG_PM_QOS_KUNIT_TEST) += qos-test.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
diff --git a/drivers/base/power/qos-test.c b/drivers/base/power/qos-test.c
new file mode 100644 (file)
index 0000000..3115db0
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP
+ */
+#include <kunit/test.h>
+#include <linux/pm_qos.h>
+
+/* Basic test for aggregating two "min" requests */
+static void freq_qos_test_min(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req1, req2;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req1, 0, sizeof(req1));
+       memset(&req2, 0, sizeof(req2));
+
+       ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MIN, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MIN, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
+
+       ret = freq_qos_remove_request(&req2);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
+
+       ret = freq_qos_remove_request(&req1);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+}
+
+/* Test that requests for MAX_DEFAULT_VALUE have no effect */
+static void freq_qos_test_maxdef(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req1, req2;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req1, 0, sizeof(req1));
+       memset(&req2, 0, sizeof(req2));
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX),
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+
+       ret = freq_qos_add_request(&qos, &req1, FREQ_QOS_MAX,
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+       ret = freq_qos_add_request(&qos, &req2, FREQ_QOS_MAX,
+                       FREQ_QOS_MAX_DEFAULT_VALUE);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+
+       /* Add max 1000 */
+       ret = freq_qos_update_request(&req1, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
+
+       /* Add max 2000, no impact */
+       ret = freq_qos_update_request(&req2, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 0);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 1000);
+
+       /* Remove max 1000, new max 2000 */
+       ret = freq_qos_remove_request(&req1);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MAX), 2000);
+}
+
+/*
+ * Test that a freq_qos_request can be added again after removal
+ *
+ * This issue was solved by commit 05ff1ba412fd ("PM: QoS: Invalidate frequency
+ * QoS requests after removal")
+ */
+static void freq_qos_test_readd(struct kunit *test)
+{
+       struct freq_constraints qos;
+       struct freq_qos_request req;
+       int ret;
+
+       freq_constraints_init(&qos);
+       memset(&req, 0, sizeof(req));
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+
+       /* Add */
+       ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 1000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 1000);
+
+       /* Remove */
+       ret = freq_qos_remove_request(&req);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN),
+                       FREQ_QOS_MIN_DEFAULT_VALUE);
+
+       /* Add again */
+       ret = freq_qos_add_request(&qos, &req, FREQ_QOS_MIN, 2000);
+       KUNIT_EXPECT_EQ(test, ret, 1);
+       KUNIT_EXPECT_EQ(test, freq_qos_read_value(&qos, FREQ_QOS_MIN), 2000);
+}
+
+static struct kunit_case pm_qos_test_cases[] = {
+       KUNIT_CASE(freq_qos_test_min),
+       KUNIT_CASE(freq_qos_test_maxdef),
+       KUNIT_CASE(freq_qos_test_readd),
+       {},
+};
+
+static struct kunit_suite pm_qos_test_module = {
+       .name = "qos-kunit-test",
+       .test_cases = pm_qos_test_cases,
+};
+kunit_test_suite(pm_qos_test_module);
index 350dcaf..8e93167 100644 (file)
@@ -115,10 +115,20 @@ s32 dev_pm_qos_read_value(struct device *dev, enum dev_pm_qos_req_type type)
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
-       if (type == DEV_PM_QOS_RESUME_LATENCY) {
+       switch (type) {
+       case DEV_PM_QOS_RESUME_LATENCY:
                ret = IS_ERR_OR_NULL(qos) ? PM_QOS_RESUME_LATENCY_NO_CONSTRAINT
                        : pm_qos_read_value(&qos->resume_latency);
-       } else {
+               break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MIN);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = IS_ERR_OR_NULL(qos) ? PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE
+                       : freq_qos_read_value(&qos->freq, FREQ_QOS_MAX);
+               break;
+       default:
                WARN_ON(1);
                ret = 0;
        }
@@ -159,6 +169,10 @@ static int apply_constraint(struct dev_pm_qos_request *req,
                        req->dev->power.set_latency_tolerance(req->dev, value);
                }
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_apply(&req->data.freq, action, value);
+               break;
        case DEV_PM_QOS_FLAGS:
                ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                          action, value);
@@ -209,6 +223,8 @@ static int dev_pm_qos_constraints_allocate(struct device *dev)
        c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
        c->type = PM_QOS_MIN;
 
+       freq_constraints_init(&qos->freq);
+
        INIT_LIST_HEAD(&qos->flags.list);
 
        spin_lock_irq(&dev->power.lock);
@@ -269,6 +285,20 @@ void dev_pm_qos_constraints_destroy(struct device *dev)
                memset(req, 0, sizeof(*req));
        }
 
+       c = &qos->freq.min_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
+       c = &qos->freq.max_freq;
+       plist_for_each_entry_safe(req, tmp, &c->list, data.freq.pnode) {
+               apply_constraint(req, PM_QOS_REMOVE_REQ,
+                                PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
+               memset(req, 0, sizeof(*req));
+       }
+
        f = &qos->flags;
        list_for_each_entry_safe(req, tmp, &f->list, data.flr.node) {
                apply_constraint(req, PM_QOS_REMOVE_REQ, PM_QOS_DEFAULT_VALUE);
@@ -314,11 +344,22 @@ static int __dev_pm_qos_add_request(struct device *dev,
                ret = dev_pm_qos_constraints_allocate(dev);
 
        trace_dev_pm_qos_add_request(dev_name(dev), type, value);
-       if (!ret) {
-               req->dev = dev;
-               req->type = type;
+       if (ret)
+               return ret;
+
+       req->dev = dev;
+       req->type = type;
+       if (req->type == DEV_PM_QOS_MIN_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MIN, value);
+       else if (req->type == DEV_PM_QOS_MAX_FREQUENCY)
+               ret = freq_qos_add_request(&dev->power.qos->freq,
+                                          &req->data.freq,
+                                          FREQ_QOS_MAX, value);
+       else
                ret = apply_constraint(req, PM_QOS_ADD_REQ, value);
-       }
+
        return ret;
 }
 
@@ -382,6 +423,10 @@ static int __dev_pm_qos_update_request(struct dev_pm_qos_request *req,
        case DEV_PM_QOS_LATENCY_TOLERANCE:
                curr_value = req->data.pnode.prio;
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               curr_value = req->data.freq.pnode.prio;
+               break;
        case DEV_PM_QOS_FLAGS:
                curr_value = req->data.flr.flags;
                break;
@@ -507,6 +552,14 @@ int dev_pm_qos_add_notifier(struct device *dev, struct notifier_block *notifier,
                ret = blocking_notifier_chain_register(dev->power.qos->resume_latency.notifiers,
                                                       notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_add_notifier(&dev->power.qos->freq,
+                                           FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
@@ -546,6 +599,14 @@ int dev_pm_qos_remove_notifier(struct device *dev,
                ret = blocking_notifier_chain_unregister(dev->power.qos->resume_latency.notifiers,
                                                         notifier);
                break;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MIN, notifier);
+               break;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               ret = freq_qos_remove_notifier(&dev->power.qos->freq,
+                                              FREQ_QOS_MAX, notifier);
+               break;
        default:
                WARN_ON(1);
                ret = -EINVAL;
index 35b4f70..58151ca 100644 (file)
@@ -48,9 +48,9 @@ config PPC_PASEMI_CPUFREQ
          PWRficient processors.
 
 config POWERNV_CPUFREQ
-       tristate "CPU frequency scaling for IBM POWERNV platform"
-       depends on PPC_POWERNV
-       default y
-       help
+       tristate "CPU frequency scaling for IBM POWERNV platform"
+       depends on PPC_POWERNV
+       default y
+       help
         This adds support for CPU frequency switching on IBM POWERNV
         platform
index dfa6457..a652838 100644 (file)
@@ -4,17 +4,17 @@
 #
 
 config X86_INTEL_PSTATE
-       bool "Intel P state control"
-       depends on X86
-       select ACPI_PROCESSOR if ACPI
-       select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
-       help
-          This driver provides a P state for Intel core processors.
+       bool "Intel P state control"
+       depends on X86
+       select ACPI_PROCESSOR if ACPI
+       select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
+       help
+         This driver provides a P state for Intel core processors.
          The driver implements an internal governor and will become
-          the scaling driver and governor for Sandy bridge processors.
+         the scaling driver and governor for Sandy bridge processors.
 
          When this driver is enabled it will become the preferred
-          scaling driver for Sandy bridge processors.
+         scaling driver for Sandy bridge processors.
 
          If in doubt, say N.
 
index 88727b7..c0aeedd 100644 (file)
@@ -16,7 +16,7 @@ config CPU_IDLE
 if CPU_IDLE
 
 config CPU_IDLE_MULTIPLE_DRIVERS
-        bool
+       bool
 
 config CPU_IDLE_GOV_LADDER
        bool "Ladder governor (for periodic timer tick)"
@@ -63,13 +63,13 @@ source "drivers/cpuidle/Kconfig.powerpc"
 endmenu
 
 config HALTPOLL_CPUIDLE
-       tristate "Halt poll cpuidle driver"
-       depends on X86 && KVM_GUEST
-       default y
-       help
-         This option enables halt poll cpuidle driver, which allows to poll
-         before halting in the guest (more efficient than polling in the
-         host via halt_poll_ns for some scenarios).
+       tristate "Halt poll cpuidle driver"
+       depends on X86 && KVM_GUEST
+       default y
+       help
+        This option enables halt poll cpuidle driver, which allows to poll
+        before halting in the guest (more efficient than polling in the
+        host via halt_poll_ns for some scenarios).
 
 endif
 
index d853047..a224d33 100644 (file)
@@ -3,15 +3,15 @@
 # ARM CPU Idle drivers
 #
 config ARM_CPUIDLE
-        bool "Generic ARM/ARM64 CPU idle Driver"
-        select DT_IDLE_STATES
+       bool "Generic ARM/ARM64 CPU idle Driver"
+       select DT_IDLE_STATES
        select CPU_IDLE_MULTIPLE_DRIVERS
-        help
-          Select this to enable generic cpuidle driver for ARM.
-          It provides a generic idle driver whose idle states are configured
-          at run-time through DT nodes. The CPUidle suspend backend is
-          initialized by calling the CPU operations init idle hook
-          provided by architecture code.
+       help
+         Select this to enable generic cpuidle driver for ARM.
+         It provides a generic idle driver whose idle states are configured
+         at run-time through DT nodes. The CPUidle suspend backend is
+         initialized by calling the CPU operations init idle hook
+         provided by architecture code.
 
 config ARM_PSCI_CPUIDLE
        bool "PSCI CPU idle Driver"
@@ -65,21 +65,21 @@ config ARM_U8500_CPUIDLE
        bool "Cpu Idle Driver for the ST-E u8500 processors"
        depends on ARCH_U8500 && !ARM64
        help
-         Select this to enable cpuidle for ST-E u8500 processors
+         Select this to enable cpuidle for ST-E u8500 processors.
 
 config ARM_AT91_CPUIDLE
        bool "Cpu Idle Driver for the AT91 processors"
        default y
        depends on ARCH_AT91 && !ARM64
        help
-         Select this to enable cpuidle for AT91 processors
+         Select this to enable cpuidle for AT91 processors.
 
 config ARM_EXYNOS_CPUIDLE
        bool "Cpu Idle Driver for the Exynos processors"
        depends on ARCH_EXYNOS && !ARM64
        select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
        help
-         Select this to enable cpuidle for Exynos processors
+         Select this to enable cpuidle for Exynos processors.
 
 config ARM_MVEBU_V7_CPUIDLE
        bool "CPU Idle Driver for mvebu v7 family processors"
index 569dbac..0005be5 100644 (file)
@@ -572,7 +572,7 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
                return -EINVAL;
 
        for (i = 0; i < drv->state_count; i++)
-               if (drv->states[i].disabled)
+               if (drv->states[i].flags & CPUIDLE_FLAG_UNUSABLE)
                        dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
 
        per_cpu(cpuidle_devices, dev->cpu) = dev;
index 9f1ace9..f7e8361 100644 (file)
@@ -53,7 +53,6 @@ void cpuidle_poll_state_init(struct cpuidle_driver *drv)
        state->target_residency_ns = 0;
        state->power_usage = -1;
        state->enter = poll_idle;
-       state->disabled = false;
        state->flags = CPUIDLE_FLAG_POLLING;
 }
 EXPORT_SYMBOL_GPL(cpuidle_poll_state_init);
index f33c73e..3b6c06f 100644 (file)
@@ -32,19 +32,36 @@ config DEV_DAX_PMEM
 
          Say M if unsure
 
+config DEV_DAX_HMEM
+       tristate "HMEM DAX: direct access to 'specific purpose' memory"
+       depends on EFI_SOFT_RESERVE
+       default DEV_DAX
+       help
+         EFI 2.8 platforms, and others, may advertise 'specific purpose'
+         memory. For example, a high bandwidth memory pool. The
+         indication from platform firmware is meant to reserve the
+         memory from typical usage by default. This driver creates
+         device-dax instances for these memory ranges, and that also
+         enables the possibility to assign them to the DEV_DAX_KMEM
+         driver to override the reservation and add them to kernel
+         "System RAM" pool.
+
+         Say M if unsure.
+
 config DEV_DAX_KMEM
        tristate "KMEM DAX: volatile-use of persistent memory"
        default DEV_DAX
        depends on DEV_DAX
        depends on MEMORY_HOTPLUG # for add_memory() and friends
        help
-         Support access to persistent memory as if it were RAM.  This
-         allows easier use of persistent memory by unmodified
-         applications.
+         Support access to persistent, or other performance
+         differentiated memory as if it were System RAM. This allows
+         easier use of persistent memory by unmodified applications, or
+         adds core kernel memory services to heterogeneous memory types
+         (HMEM) marked "reserved" by platform firmware.
 
          To use this feature, a DAX device must be unbound from the
-         device_dax driver (PMEM DAX) and bound to this kmem driver
-         on each boot.
+         device_dax driver and bound to this kmem driver on each boot.
 
          Say N if unsure.
 
index 81f7d54..80065b3 100644 (file)
@@ -2,9 +2,11 @@
 obj-$(CONFIG_DAX) += dax.o
 obj-$(CONFIG_DEV_DAX) += device_dax.o
 obj-$(CONFIG_DEV_DAX_KMEM) += kmem.o
+obj-$(CONFIG_DEV_DAX_HMEM) += dax_hmem.o
 
 dax-y := super.o
 dax-y += bus.o
 device_dax-y := device.o
+dax_hmem-y := hmem.o
 
 obj-y += pmem/
index 8fafbea..eccdda1 100644 (file)
@@ -227,7 +227,7 @@ static void dax_region_unregister(void *region)
 
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
                struct resource *res, int target_node, unsigned int align,
-               unsigned long pfn_flags)
+               unsigned long long pfn_flags)
 {
        struct dax_region *dax_region;
 
index 8619e32..9e4eba6 100644 (file)
@@ -11,7 +11,7 @@ struct dax_region;
 void dax_region_put(struct dax_region *dax_region);
 struct dax_region *alloc_dax_region(struct device *parent, int region_id,
                struct resource *res, int target_node, unsigned int align,
-               unsigned long flags);
+               unsigned long long flags);
 
 enum dev_dax_subsys {
        DEV_DAX_BUS,
index 6ccca3b..3107ce8 100644 (file)
@@ -32,7 +32,7 @@ struct dax_region {
        struct device *dev;
        unsigned int align;
        struct resource res;
-       unsigned long pfn_flags;
+       unsigned long long pfn_flags;
 };
 
 /**
diff --git a/drivers/dax/hmem.c b/drivers/dax/hmem.c
new file mode 100644 (file)
index 0000000..fe7214d
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/platform_device.h>
+#include <linux/memregion.h>
+#include <linux/module.h>
+#include <linux/pfn_t.h>
+#include "bus.h"
+
+static int dax_hmem_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dev_pagemap pgmap = { };
+       struct dax_region *dax_region;
+       struct memregion_info *mri;
+       struct dev_dax *dev_dax;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENOMEM;
+
+       mri = dev->platform_data;
+       memcpy(&pgmap.res, res, sizeof(*res));
+
+       dax_region = alloc_dax_region(dev, pdev->id, res, mri->target_node,
+                       PMD_SIZE, PFN_DEV|PFN_MAP);
+       if (!dax_region)
+               return -ENOMEM;
+
+       dev_dax = devm_create_dev_dax(dax_region, 0, &pgmap);
+       if (IS_ERR(dev_dax))
+               return PTR_ERR(dev_dax);
+
+       /* child dev_dax instances now own the lifetime of the dax_region */
+       dax_region_put(dax_region);
+       return 0;
+}
+
+static int dax_hmem_remove(struct platform_device *pdev)
+{
+       /* devm handles teardown */
+       return 0;
+}
+
+static struct platform_driver dax_hmem_driver = {
+       .probe = dax_hmem_probe,
+       .remove = dax_hmem_remove,
+       .driver = {
+               .name = "hmem",
+       },
+};
+
+module_platform_driver(dax_hmem_driver);
+
+MODULE_ALIAS("platform:hmem*");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Intel Corporation");
index f840e61..425149e 100644 (file)
@@ -921,7 +921,9 @@ int devfreq_suspend_device(struct devfreq *devfreq)
        }
 
        if (devfreq->suspend_freq) {
+               mutex_lock(&devfreq->lock);
                ret = devfreq_set_target(devfreq, devfreq->suspend_freq, 0);
+               mutex_unlock(&devfreq->lock);
                if (ret)
                        return ret;
        }
@@ -949,7 +951,9 @@ int devfreq_resume_device(struct devfreq *devfreq)
                return 0;
 
        if (devfreq->resume_freq) {
+               mutex_lock(&devfreq->lock);
                ret = devfreq_set_target(devfreq, devfreq->resume_freq, 0);
+               mutex_unlock(&devfreq->lock);
                if (ret)
                        return ret;
        }
index b248870..bcc378c 100644 (file)
@@ -75,6 +75,27 @@ config EFI_MAX_FAKE_MEM
          Ranges can be set up to this value using comma-separated list.
          The default value is 8.
 
+config EFI_SOFT_RESERVE
+       bool "Reserve EFI Specific Purpose Memory"
+       depends on EFI && EFI_STUB && ACPI_HMAT
+       default ACPI_HMAT
+       help
+         On systems that have mixed performance classes of memory EFI
+         may indicate specific purpose memory with an attribute (See
+         EFI_MEMORY_SP in UEFI 2.8). A memory range tagged with this
+         attribute may have unique performance characteristics compared
+         to the system's general purpose "System RAM" pool. On the
+         expectation that such memory has application specific usage,
+         and its base EFI memory type is "conventional" answer Y to
+         arrange for the kernel to reserve it as a "Soft Reserved"
+         resource, and set aside for direct-access (device-dax) by
+         default. The memory range can later be optionally assigned to
+         the page allocator by system administrator policy via the
+         device-dax kmem facility. Say N to have the kernel treat this
+         memory as "System RAM" by default.
+
+         If unsure, say Y.
+
 config EFI_PARAMS_FROM_FDT
        bool
        help
index 4ac2de4..554d795 100644 (file)
@@ -20,13 +20,16 @@ obj-$(CONFIG_UEFI_CPER)                     += cper.o
 obj-$(CONFIG_EFI_RUNTIME_MAP)          += runtime-map.o
 obj-$(CONFIG_EFI_RUNTIME_WRAPPERS)     += runtime-wrappers.o
 obj-$(CONFIG_EFI_STUB)                 += libstub/
-obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_mem.o
+obj-$(CONFIG_EFI_FAKE_MEMMAP)          += fake_map.o
 obj-$(CONFIG_EFI_BOOTLOADER_CONTROL)   += efibc.o
 obj-$(CONFIG_EFI_TEST)                 += test/
 obj-$(CONFIG_EFI_DEV_PATH_PARSER)      += dev-path-parser.o
 obj-$(CONFIG_APPLE_PROPERTIES)         += apple-properties.o
 obj-$(CONFIG_EFI_RCI2_TABLE)           += rci2-table.o
 
+fake_map-y                             += fake_mem.o
+fake_map-$(CONFIG_X86)                 += x86_fake_mem.o
+
 arm-obj-$(CONFIG_EFI)                  := arm-init.o arm-runtime.o
 obj-$(CONFIG_ARM)                      += $(arm-obj-y)
 obj-$(CONFIG_ARM64)                    += $(arm-obj-y)
index 311cd34..904fa09 100644 (file)
@@ -164,6 +164,15 @@ static __init int is_usable_memory(efi_memory_desc_t *md)
        case EFI_CONVENTIONAL_MEMORY:
        case EFI_PERSISTENT_MEMORY:
                /*
+                * Special purpose memory is 'soft reserved', which means it
+                * is set aside initially, but can be hotplugged back in or
+                * be assigned to the dax driver after boot.
+                */
+               if (efi_soft_reserve_enabled() &&
+                   (md->attribute & EFI_MEMORY_SP))
+                       return false;
+
+               /*
                 * According to the spec, these regions are no longer reserved
                 * after calling ExitBootServices(). However, we can only use
                 * them as System RAM if they can be mapped writeback cacheable.
index e2ac5fa..899b803 100644 (file)
@@ -121,6 +121,30 @@ static int __init arm_enable_runtime_services(void)
                return 0;
        }
 
+       if (efi_soft_reserve_enabled()) {
+               efi_memory_desc_t *md;
+
+               for_each_efi_memory_desc(md) {
+                       int md_size = md->num_pages << EFI_PAGE_SHIFT;
+                       struct resource *res;
+
+                       if (!(md->attribute & EFI_MEMORY_SP))
+                               continue;
+
+                       res = kzalloc(sizeof(*res), GFP_KERNEL);
+                       if (WARN_ON(!res))
+                               break;
+
+                       res->start      = md->phys_addr;
+                       res->end        = md->phys_addr + md_size - 1;
+                       res->name       = "Soft Reserved";
+                       res->flags      = IORESOURCE_MEM;
+                       res->desc       = IORES_DESC_SOFT_RESERVED;
+
+                       insert_resource(&iomem_resource, res);
+               }
+       }
+
        if (efi_runtime_disabled()) {
                pr_info("EFI runtime services will be disabled.\n");
                return 0;
index e98bbf8..d101f07 100644 (file)
@@ -81,6 +81,11 @@ bool efi_runtime_disabled(void)
        return disable_runtime;
 }
 
+bool __pure __efi_soft_reserve_enabled(void)
+{
+       return !efi_enabled(EFI_MEM_NO_SOFT_RESERVE);
+}
+
 static int __init parse_efi_cmdline(char *str)
 {
        if (!str) {
@@ -94,6 +99,9 @@ static int __init parse_efi_cmdline(char *str)
        if (parse_option_str(str, "noruntime"))
                disable_runtime = true;
 
+       if (parse_option_str(str, "nosoftreserve"))
+               set_bit(EFI_MEM_NO_SOFT_RESERVE, &efi.flags);
+
        return 0;
 }
 early_param("efi", parse_efi_cmdline);
@@ -296,7 +304,7 @@ static __init int efivar_ssdt_load(void)
                        goto free_data;
                }
 
-               ret = acpi_load_table(data);
+               ret = acpi_load_table(data, NULL);
                if (ret) {
                        pr_err("failed to load table: %d\n", ret);
                        goto free_data;
@@ -842,15 +850,16 @@ char * __init efi_md_typeattr_format(char *buf, size_t size,
        if (attr & ~(EFI_MEMORY_UC | EFI_MEMORY_WC | EFI_MEMORY_WT |
                     EFI_MEMORY_WB | EFI_MEMORY_UCE | EFI_MEMORY_RO |
                     EFI_MEMORY_WP | EFI_MEMORY_RP | EFI_MEMORY_XP |
-                    EFI_MEMORY_NV |
+                    EFI_MEMORY_NV | EFI_MEMORY_SP |
                     EFI_MEMORY_RUNTIME | EFI_MEMORY_MORE_RELIABLE))
                snprintf(pos, size, "|attr=0x%016llx]",
                         (unsigned long long)attr);
        else
                snprintf(pos, size,
-                        "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
+                        "|%3s|%2s|%2s|%2s|%2s|%2s|%2s|%2s|%3s|%2s|%2s|%2s|%2s]",
                         attr & EFI_MEMORY_RUNTIME ? "RUN" : "",
                         attr & EFI_MEMORY_MORE_RELIABLE ? "MR" : "",
+                        attr & EFI_MEMORY_SP      ? "SP"  : "",
                         attr & EFI_MEMORY_NV      ? "NV"  : "",
                         attr & EFI_MEMORY_XP      ? "XP"  : "",
                         attr & EFI_MEMORY_RP      ? "RP"  : "",
index d6dd5f5..2762e06 100644 (file)
@@ -246,6 +246,9 @@ void __init efi_esrt_init(void)
        int rc;
        phys_addr_t end;
 
+       if (!efi_enabled(EFI_MEMMAP))
+               return;
+
        pr_debug("esrt-init: loading.\n");
        if (!esrt_table_exists())
                return;
index 9501edc..bb9fc70 100644 (file)
 #include <linux/memblock.h>
 #include <linux/types.h>
 #include <linux/sort.h>
-#include <asm/efi.h>
+#include "fake_mem.h"
 
-#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
-
-static struct efi_mem_range fake_mems[EFI_MAX_FAKEMEM];
-static int nr_fake_mem;
+struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
+int nr_fake_mem;
 
 static int __init cmp_fake_mem(const void *x1, const void *x2)
 {
@@ -44,13 +42,13 @@ void __init efi_fake_memmap(void)
        void *new_memmap;
        int i;
 
-       if (!nr_fake_mem)
+       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
                return;
 
        /* count up the number of EFI memory descriptor */
        for (i = 0; i < nr_fake_mem; i++) {
                for_each_efi_memory_desc(md) {
-                       struct range *r = &fake_mems[i].range;
+                       struct range *r = &efi_fake_mems[i].range;
 
                        new_nr_map += efi_memmap_split_count(md, r);
                }
@@ -70,7 +68,7 @@ void __init efi_fake_memmap(void)
        }
 
        for (i = 0; i < nr_fake_mem; i++)
-               efi_memmap_insert(&efi.memmap, new_memmap, &fake_mems[i]);
+               efi_memmap_insert(&efi.memmap, new_memmap, &efi_fake_mems[i]);
 
        /* swap into new EFI memmap */
        early_memunmap(new_memmap, efi.memmap.desc_size * new_nr_map);
@@ -104,22 +102,22 @@ static int __init setup_fake_mem(char *p)
                if (nr_fake_mem >= EFI_MAX_FAKEMEM)
                        break;
 
-               fake_mems[nr_fake_mem].range.start = start;
-               fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
-               fake_mems[nr_fake_mem].attribute = attribute;
+               efi_fake_mems[nr_fake_mem].range.start = start;
+               efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
+               efi_fake_mems[nr_fake_mem].attribute = attribute;
                nr_fake_mem++;
 
                if (*p == ',')
                        p++;
        }
 
-       sort(fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
+       sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
             cmp_fake_mem, NULL);
 
        for (i = 0; i < nr_fake_mem; i++)
                pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
-                       fake_mems[i].attribute, fake_mems[i].range.start,
-                       fake_mems[i].range.end);
+                       efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
+                       efi_fake_mems[i].range.end);
 
        return *p == '\0' ? 0 : -EINVAL;
 }
diff --git a/drivers/firmware/efi/fake_mem.h b/drivers/firmware/efi/fake_mem.h
new file mode 100644 (file)
index 0000000..d52791a
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __EFI_FAKE_MEM_H__
+#define __EFI_FAKE_MEM_H__
+#include <asm/efi.h>
+
+#define EFI_MAX_FAKEMEM CONFIG_EFI_MAX_FAKE_MEM
+
+extern struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
+extern int nr_fake_mem;
+#endif /* __EFI_FAKE_MEM_H__ */
index 41213bf..4566640 100644 (file)
@@ -146,6 +146,11 @@ static efi_status_t reserve_kernel_base(efi_system_table_t *sys_table_arg,
                        continue;
 
                case EFI_CONVENTIONAL_MEMORY:
+                       /* Skip soft reserved conventional memory */
+                       if (efi_soft_reserve_enabled() &&
+                           (desc->attribute & EFI_MEMORY_SP))
+                               continue;
+
                        /*
                         * Reserve the intersection between this entry and the
                         * region.
index 35dbc27..e025799 100644 (file)
@@ -32,6 +32,7 @@ static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
 static int __section(.data) __nokaslr;
 static int __section(.data) __quiet;
 static int __section(.data) __novamap;
+static bool __section(.data) efi_nosoftreserve;
 
 int __pure nokaslr(void)
 {
@@ -45,6 +46,10 @@ int __pure novamap(void)
 {
        return __novamap;
 }
+bool __pure __efi_soft_reserve_enabled(void)
+{
+       return !efi_nosoftreserve;
+}
 
 #define EFI_MMAP_NR_SLACK_SLOTS        8
 
@@ -211,6 +216,10 @@ again:
                if (desc->type != EFI_CONVENTIONAL_MEMORY)
                        continue;
 
+               if (efi_soft_reserve_enabled() &&
+                   (desc->attribute & EFI_MEMORY_SP))
+                       continue;
+
                if (desc->num_pages < nr_pages)
                        continue;
 
@@ -305,6 +314,10 @@ efi_status_t efi_low_alloc_above(efi_system_table_t *sys_table_arg,
                if (desc->type != EFI_CONVENTIONAL_MEMORY)
                        continue;
 
+               if (efi_soft_reserve_enabled() &&
+                   (desc->attribute & EFI_MEMORY_SP))
+                       continue;
+
                if (desc->num_pages < nr_pages)
                        continue;
 
@@ -484,6 +497,12 @@ efi_status_t efi_parse_options(char const *cmdline)
                        __novamap = 1;
                }
 
+               if (IS_ENABLED(CONFIG_EFI_SOFT_RESERVE) &&
+                   !strncmp(str, "nosoftreserve", 7)) {
+                       str += strlen("nosoftreserve");
+                       efi_nosoftreserve = 1;
+               }
+
                /* Group words together, delimited by "," */
                while (*str && *str != ' ' && *str != ',')
                        str++;
index 53f1466..35edd7c 100644 (file)
@@ -58,6 +58,10 @@ static unsigned long get_entry_num_slots(efi_memory_desc_t *md,
        if (md->type != EFI_CONVENTIONAL_MEMORY)
                return 0;
 
+       if (efi_soft_reserve_enabled() &&
+           (md->attribute & EFI_MEMORY_SP))
+               return 0;
+
        region_end = min((u64)ULONG_MAX, md->phys_addr + md->num_pages*EFI_PAGE_SIZE - 1);
 
        first_slot = round_up(md->phys_addr, align);
diff --git a/drivers/firmware/efi/x86_fake_mem.c b/drivers/firmware/efi/x86_fake_mem.c
new file mode 100644 (file)
index 0000000..e5d6d5a
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) 2019 Intel Corporation. All rights reserved. */
+#include <linux/efi.h>
+#include <asm/e820/api.h>
+#include "fake_mem.h"
+
+void __init efi_fake_memmap_early(void)
+{
+       int i;
+
+       /*
+        * The late efi_fake_mem() call can handle all requests if
+        * EFI_MEMORY_SP support is disabled.
+        */
+       if (!efi_soft_reserve_enabled())
+               return;
+
+       if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
+               return;
+
+       /*
+        * Given that efi_fake_memmap() needs to perform memblock
+        * allocations it needs to run after e820__memblock_setup().
+        * However, if efi_fake_mem specifies EFI_MEMORY_SP for a given
+        * address range that potentially needs to mark the memory as
+        * reserved prior to e820__memblock_setup(). Update e820
+        * directly if EFI_MEMORY_SP is specified for an
+        * EFI_CONVENTIONAL_MEMORY descriptor.
+        */
+       for (i = 0; i < nr_fake_mem; i++) {
+               struct efi_mem_range *mem = &efi_fake_mems[i];
+               efi_memory_desc_t *md;
+               u64 m_start, m_end;
+
+               if ((mem->attribute & EFI_MEMORY_SP) == 0)
+                       continue;
+
+               m_start = mem->range.start;
+               m_end = mem->range.end;
+               for_each_efi_memory_desc(md) {
+                       u64 start, end;
+
+                       if (md->type != EFI_CONVENTIONAL_MEMORY)
+                               continue;
+
+                       start = md->phys_addr;
+                       end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT) - 1;
+
+                       if (m_start <= end && m_end >= start)
+                               /* fake range overlaps descriptor */;
+                       else
+                               continue;
+
+                       /*
+                        * Trim the boundary of the e820 update to the
+                        * descriptor in case the fake range overlaps
+                        * !EFI_CONVENTIONAL_MEMORY
+                        */
+                       start = max(start, m_start);
+                       end = min(end, m_end);
+
+                       if (end <= start)
+                               continue;
+                       e820__range_update(start, end - start + 1, E820_TYPE_RAM,
+                                       E820_TYPE_SOFT_RESERVED);
+                       e820__update_table(e820_table);
+               }
+       }
+}
index 347b08b..75fd2a7 100644 (file)
@@ -1291,8 +1291,8 @@ static void sklh_idle_state_table_update(void)
                        return;
        }
 
-       skl_cstates[5].disabled = 1;    /* C8-SKL */
-       skl_cstates[6].disabled = 1;    /* C9-SKL */
+       skl_cstates[5].flags |= CPUIDLE_FLAG_UNUSABLE;  /* C8-SKL */
+       skl_cstates[6].flags |= CPUIDLE_FLAG_UNUSABLE;  /* C9-SKL */
 }
 /*
  * intel_idle_state_table_update()
@@ -1355,7 +1355,7 @@ static void __init intel_idle_cpuidle_driver_init(void)
                        continue;
 
                /* if state marked as disabled, skip it */
-               if (cpuidle_state_table[cstate].disabled != 0) {
+               if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_UNUSABLE) {
                        pr_debug("state %s is disabled\n",
                                 cpuidle_state_table[cstate].name);
                        continue;
index dd55507..12e5039 100644 (file)
@@ -124,30 +124,6 @@ static struct lock_class_key reserved_rbtree_key;
  *
  ****************************************************************************/
 
-static inline int match_hid_uid(struct device *dev,
-                               struct acpihid_map_entry *entry)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       const char *hid, *uid;
-
-       if (!adev)
-               return -ENODEV;
-
-       hid = acpi_device_hid(adev);
-       uid = acpi_device_uid(adev);
-
-       if (!hid || !(*hid))
-               return -ENODEV;
-
-       if (!uid || !(*uid))
-               return strcmp(hid, entry->hid);
-
-       if (!(*entry->uid))
-               return strcmp(hid, entry->hid);
-
-       return (strcmp(hid, entry->hid) || strcmp(uid, entry->uid));
-}
-
 static inline u16 get_pci_device_id(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -158,10 +134,14 @@ static inline u16 get_pci_device_id(struct device *dev)
 static inline int get_acpihid_device_id(struct device *dev,
                                        struct acpihid_map_entry **entry)
 {
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        struct acpihid_map_entry *p;
 
+       if (!adev)
+               return -ENODEV;
+
        list_for_each_entry(p, &acpihid_map, list) {
-               if (!match_hid_uid(dev, p)) {
+               if (acpi_dev_hid_uid_match(adev, p->hid, p->uid)) {
                        if (entry)
                                *entry = p;
                        return p->devid;
index b6ab72f..ab09b82 100644 (file)
@@ -75,7 +75,7 @@ static struct mfd_cell crystal_cove_byt_dev[] = {
                .resources = gpio_resources,
        },
        {
-               .name = "crystal_cove_pmic",
+               .name = "byt_crystal_cove_pmic",
        },
        {
                .name = "crystal_cove_pwm",
index 1604f51..105e73d 100644 (file)
@@ -61,7 +61,7 @@ struct sdhci_acpi_slot {
        mmc_pm_flag_t   pm_caps;
        unsigned int    flags;
        size_t          priv_size;
-       int (*probe_slot)(struct platform_device *, const char *, const char *);
+       int (*probe_slot)(struct platform_device *, struct acpi_device *);
        int (*remove_slot)(struct platform_device *);
        int (*free_slot)(struct platform_device *pdev);
        int (*setup_host)(struct platform_device *pdev);
@@ -325,12 +325,10 @@ static bool sdhci_acpi_cht_pci_wifi(unsigned int vendor, unsigned int device,
  * wifi card in the expected slot with an ACPI companion node, is used to
  * indicate that acpi_device_fix_up_power() should be avoided.
  */
-static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
-                                                  const char *uid)
+static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev)
 {
        return sdhci_acpi_cht() &&
-              !strcmp(hid, "80860F14") &&
-              !strcmp(uid, "2") &&
+              acpi_dev_hid_uid_match(adev, "80860F14", "2") &&
               sdhci_acpi_cht_pci_wifi(0x14e4, 0x43ec, 0, 28);
 }
 
@@ -345,8 +343,7 @@ static inline bool sdhci_acpi_byt_defer(struct device *dev)
        return false;
 }
 
-static inline bool sdhci_acpi_no_fixup_child_power(const char *hid,
-                                                  const char *uid)
+static inline bool sdhci_acpi_no_fixup_child_power(struct acpi_device *adev)
 {
        return false;
 }
@@ -375,19 +372,18 @@ out:
        return ret;
 }
 
-static int intel_probe_slot(struct platform_device *pdev, const char *hid,
-                           const char *uid)
+static int intel_probe_slot(struct platform_device *pdev, struct acpi_device *adev)
 {
        struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
        struct intel_host *intel_host = sdhci_acpi_priv(c);
        struct sdhci_host *host = c->host;
 
-       if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") &&
+       if (acpi_dev_hid_uid_match(adev, "80860F14", "1") &&
            sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
            sdhci_readl(host, SDHCI_CAPABILITIES_1) == 0x00000807)
                host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
 
-       if (hid && !strcmp(hid, "80865ACA"))
+       if (acpi_dev_hid_uid_match(adev, "80865ACA", NULL))
                host->mmc_host_ops.get_cd = bxt_get_cd;
 
        intel_dsm_init(intel_host, &pdev->dev, host->mmc);
@@ -473,8 +469,7 @@ static irqreturn_t sdhci_acpi_qcom_handler(int irq, void *ptr)
        return IRQ_HANDLED;
 }
 
-static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
-                          const char *uid)
+static int qcom_probe_slot(struct platform_device *pdev, struct acpi_device *adev)
 {
        struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
        struct sdhci_host *host = c->host;
@@ -482,7 +477,7 @@ static int qcom_probe_slot(struct platform_device *pdev, const char *hid,
 
        *irq = -EINVAL;
 
-       if (strcmp(hid, "QCOM8051"))
+       if (!acpi_dev_hid_uid_match(adev, "QCOM8051", NULL))
                return 0;
 
        *irq = platform_get_irq(pdev, 1);
@@ -501,14 +496,12 @@ static int qcom_free_slot(struct platform_device *pdev)
        struct sdhci_host *host = c->host;
        struct acpi_device *adev;
        int *irq = sdhci_acpi_priv(c);
-       const char *hid;
 
        adev = ACPI_COMPANION(dev);
        if (!adev)
                return -ENODEV;
 
-       hid = acpi_device_hid(adev);
-       if (strcmp(hid, "QCOM8051"))
+       if (!acpi_dev_hid_uid_match(adev, "QCOM8051", NULL))
                return 0;
 
        if (*irq < 0)
@@ -583,7 +576,7 @@ static const struct sdhci_acpi_chip sdhci_acpi_chip_amd = {
 };
 
 static int sdhci_acpi_emmc_amd_probe_slot(struct platform_device *pdev,
-                                         const char *hid, const char *uid)
+                                         struct acpi_device *adev)
 {
        struct sdhci_acpi_host *c = platform_get_drvdata(pdev);
        struct sdhci_host *host   = c->host;
@@ -654,17 +647,12 @@ static const struct acpi_device_id sdhci_acpi_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids);
 
-static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid,
-                                                        const char *uid)
+static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(struct acpi_device *adev)
 {
        const struct sdhci_acpi_uid_slot *u;
 
        for (u = sdhci_acpi_uids; u->hid; u++) {
-               if (strcmp(u->hid, hid))
-                       continue;
-               if (!u->uid)
-                       return u->slot;
-               if (uid && !strcmp(u->uid, uid))
+               if (acpi_dev_hid_uid_match(adev, u->hid, u->uid))
                        return u->slot;
        }
        return NULL;
@@ -680,22 +668,17 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct resource *iomem;
        resource_size_t len;
        size_t priv_size;
-       const char *hid;
-       const char *uid;
        int err;
 
        device = ACPI_COMPANION(dev);
        if (!device)
                return -ENODEV;
 
-       hid = acpi_device_hid(device);
-       uid = acpi_device_uid(device);
-
-       slot = sdhci_acpi_get_slot(hid, uid);
+       slot = sdhci_acpi_get_slot(device);
 
        /* Power on the SDHCI controller and its children */
        acpi_device_fix_up_power(device);
-       if (!sdhci_acpi_no_fixup_child_power(hid, uid)) {
+       if (!sdhci_acpi_no_fixup_child_power(device)) {
                list_for_each_entry(child, &device->children, node)
                        if (child->status.present && child->status.enabled)
                                acpi_device_fix_up_power(child);
@@ -745,7 +728,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 
        if (c->slot) {
                if (c->slot->probe_slot) {
-                       err = c->slot->probe_slot(pdev, hid, uid);
+                       err = c->slot->probe_slot(pdev, device);
                        if (err)
                                goto err_free;
                }
index 36af7af..b7d1eb3 100644 (file)
@@ -4,6 +4,7 @@ menuconfig LIBNVDIMM
        depends on PHYS_ADDR_T_64BIT
        depends on HAS_IOMEM
        depends on BLK_DEV
+       select MEMREGION
        help
          Generic support for non-volatile memory devices including
          ACPI-6-NFIT defined resources.  On platforms that define an
index 9204f1e..e592c49 100644 (file)
@@ -455,7 +455,6 @@ static __exit void libnvdimm_exit(void)
        nd_region_exit();
        nvdimm_exit();
        nvdimm_bus_exit();
-       nd_region_devs_exit();
        nvdimm_devs_exit();
 }
 
index 25fa121..aa05943 100644 (file)
@@ -114,7 +114,6 @@ struct nvdimm_bus *walk_to_nvdimm_bus(struct device *nd_dev);
 int __init nvdimm_bus_init(void);
 void nvdimm_bus_exit(void);
 void nvdimm_devs_exit(void);
-void nd_region_devs_exit(void);
 struct nd_region;
 void nd_region_advance_seeds(struct nd_region *nd_region, struct device *dev);
 void nd_region_create_ns_seed(struct nd_region *nd_region);
index ef423ba..fbf34cf 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright(c) 2013-2015 Intel Corporation. All rights reserved.
  */
 #include <linux/scatterlist.h>
+#include <linux/memregion.h>
 #include <linux/highmem.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -19,7 +20,6 @@
  */
 #include <linux/io-64-nonatomic-hi-lo.h>
 
-static DEFINE_IDA(region_ida);
 static DEFINE_PER_CPU(int, flush_idx);
 
 static int nvdimm_map_flush(struct device *dev, struct nvdimm *nvdimm, int dimm,
@@ -133,7 +133,7 @@ static void nd_region_release(struct device *dev)
                put_device(&nvdimm->dev);
        }
        free_percpu(nd_region->lane);
-       ida_simple_remove(&region_ida, nd_region->id);
+       memregion_free(nd_region->id);
        if (is_nd_blk(dev))
                kfree(to_nd_blk_region(dev));
        else
@@ -985,7 +985,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
 
        if (!region_buf)
                return NULL;
-       nd_region->id = ida_simple_get(&region_ida, 0, 0, GFP_KERNEL);
+       nd_region->id = memregion_alloc(GFP_KERNEL);
        if (nd_region->id < 0)
                goto err_id;
 
@@ -1044,7 +1044,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus,
        return nd_region;
 
  err_percpu:
-       ida_simple_remove(&region_ida, nd_region->id);
+       memregion_free(nd_region->id);
  err_id:
        kfree(region_buf);
        return NULL;
@@ -1216,8 +1216,3 @@ int nd_region_conflict(struct nd_region *nd_region, resource_size_t start,
 
        return device_for_each_child(&nvdimm_bus->dev, &ctx, region_conflict);
 }
-
-void __exit nd_region_devs_exit(void)
-{
-       ida_destroy(&region_ida);
-}
index b5a217b..089b624 100644 (file)
@@ -13,9 +13,9 @@ menuconfig POWER_AVS
          Say Y here to enable Adaptive Voltage Scaling class support.
 
 config ROCKCHIP_IODOMAIN
-        tristate "Rockchip IO domain support"
-        depends on POWER_AVS && ARCH_ROCKCHIP && OF
-        help
-          Say y here to enable support io domains on Rockchip SoCs. It is
-          necessary for the io domain setting of the SoC to match the
-          voltage supplied by the regulators.
+       tristate "Rockchip IO domain support"
+       depends on POWER_AVS && ARCH_ROCKCHIP && OF
+       help
+         Say y here to enable support io domains on Rockchip SoCs. It is
+         necessary for the io domain setting of the SoC to match the
+         voltage supplied by the regulators.
index 175f7b4..0c23fd0 100644 (file)
@@ -78,9 +78,6 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev,
 bool acpi_dev_found(const char *hid);
 bool acpi_dev_present(const char *hid, const char *uid, s64 hrv);
 
-struct acpi_device *
-acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv);
-
 #ifdef CONFIG_ACPI
 
 #include <linux/proc_fs.h>
@@ -683,6 +680,11 @@ static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
                adev->power.states[ACPI_STATE_D3_HOT].flags.explicit_set);
 }
 
+bool acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2);
+
+struct acpi_device *
+acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv);
+
 static inline void acpi_dev_put(struct acpi_device *adev)
 {
        put_device(&adev->dev);
index e5e0414..18790b9 100644 (file)
@@ -12,7 +12,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20190816
+#define ACPI_CA_VERSION                 0x20191018
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
@@ -458,7 +458,11 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION
                                               u8 physical))
 
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
-                           acpi_load_table(struct acpi_table_header *table))
+                           acpi_load_table(struct acpi_table_header *table,
+                                           u32 *table_idx))
+
+ACPI_EXTERNAL_RETURN_STATUS(acpi_status
+                           acpi_unload_table(u32 table_index))
 
 ACPI_EXTERNAL_RETURN_STATUS(acpi_status
                            acpi_unload_parent_table(acpi_handle object))
index 3a2b853..340da77 100644 (file)
@@ -2,21 +2,9 @@
 #ifndef ACPI_BUTTON_H
 #define ACPI_BUTTON_H
 
-#include <linux/notifier.h>
-
 #if IS_ENABLED(CONFIG_ACPI_BUTTON)
-extern int acpi_lid_notifier_register(struct notifier_block *nb);
-extern int acpi_lid_notifier_unregister(struct notifier_block *nb);
 extern int acpi_lid_open(void);
 #else
-static inline int acpi_lid_notifier_register(struct notifier_block *nb)
-{
-       return 0;
-}
-static inline int acpi_lid_notifier_unregister(struct notifier_block *nb)
-{
-       return 0;
-}
 static inline int acpi_lid_open(void)
 {
        return 1;
index 8b4e516..0f37a7d 100644 (file)
@@ -678,6 +678,14 @@ static inline bool acpi_dev_present(const char *hid, const char *uid, s64 hrv)
        return false;
 }
 
+struct acpi_device;
+
+static inline bool
+acpi_dev_hid_uid_match(struct acpi_device *adev, const char *hid2, const char *uid2)
+{
+       return false;
+}
+
 static inline struct acpi_device *
 acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
 {
index 2dbe46b..1dabe36 100644 (file)
@@ -54,7 +54,6 @@ struct cpuidle_state {
        unsigned int    exit_latency; /* in US */
        int             power_usage; /* in mW */
        unsigned int    target_residency; /* in US */
-       bool            disabled; /* disabled on all CPUs */
 
        int (*enter)    (struct cpuidle_device *dev,
                        struct cpuidle_driver *drv,
@@ -77,6 +76,7 @@ struct cpuidle_state {
 #define CPUIDLE_FLAG_POLLING   BIT(0) /* polling state */
 #define CPUIDLE_FLAG_COUPLED   BIT(1) /* state applies to multiple cpus */
 #define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
+#define CPUIDLE_FLAG_UNUSABLE  BIT(3) /* avoid using this state */
 
 struct cpuidle_device_kobj;
 struct cpuidle_state_kobj;
index 028efa7..99dfea5 100644 (file)
@@ -112,6 +112,7 @@ typedef     struct {
 #define EFI_MEMORY_MORE_RELIABLE \
                                ((u64)0x0000000000010000ULL)    /* higher reliability */
 #define EFI_MEMORY_RO          ((u64)0x0000000000020000ULL)    /* read-only */
+#define EFI_MEMORY_SP          ((u64)0x0000000000040000ULL)    /* soft reserved */
 #define EFI_MEMORY_RUNTIME     ((u64)0x8000000000000000ULL)    /* range requires runtime mapping */
 #define EFI_MEMORY_DESCRIPTOR_VERSION  1
 
@@ -1044,7 +1045,6 @@ extern void efi_enter_virtual_mode (void);        /* switch EFI to virtual mode, if pos
 extern efi_status_t efi_query_variable_store(u32 attributes,
                                             unsigned long size,
                                             bool nonblocking);
-extern void efi_find_mirror(void);
 #else
 
 static inline efi_status_t efi_query_variable_store(u32 attributes,
@@ -1202,6 +1202,7 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_DBG                        8       /* Print additional debug info at runtime */
 #define EFI_NX_PE_DATA         9       /* Can runtime data regions be mapped non-executable? */
 #define EFI_MEM_ATTR           10      /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */
+#define EFI_MEM_NO_SOFT_RESERVE        11      /* Is the kernel configured to ignore soft reservations? */
 
 #ifdef CONFIG_EFI
 /*
@@ -1212,6 +1213,14 @@ static inline bool efi_enabled(int feature)
        return test_bit(feature, &efi.flags) != 0;
 }
 extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused);
+
+bool __pure __efi_soft_reserve_enabled(void);
+
+static inline bool __pure efi_soft_reserve_enabled(void)
+{
+       return IS_ENABLED(CONFIG_EFI_SOFT_RESERVE)
+               && __efi_soft_reserve_enabled();
+}
 #else
 static inline bool efi_enabled(int feature)
 {
@@ -1225,6 +1234,11 @@ efi_capsule_pending(int *reset_type)
 {
        return false;
 }
+
+static inline bool efi_soft_reserve_enabled(void)
+{
+       return false;
+}
 #endif
 
 extern int efi_status_to_err(efi_status_t status);
index 7bddddf..a9b9170 100644 (file)
@@ -134,6 +134,7 @@ enum {
        IORES_DESC_PERSISTENT_MEMORY_LEGACY     = 5,
        IORES_DESC_DEVICE_PRIVATE_MEMORY        = 6,
        IORES_DESC_RESERVED                     = 7,
+       IORES_DESC_SOFT_RESERVED                = 8,
 };
 
 /*
diff --git a/include/linux/memregion.h b/include/linux/memregion.h
new file mode 100644 (file)
index 0000000..e115952
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _MEMREGION_H_
+#define _MEMREGION_H_
+#include <linux/types.h>
+#include <linux/errno.h>
+
+struct memregion_info {
+       int target_node;
+};
+
+#ifdef CONFIG_MEMREGION
+int memregion_alloc(gfp_t gfp);
+void memregion_free(int id);
+#else
+static inline int memregion_alloc(gfp_t gfp)
+{
+       return -ENOMEM;
+}
+void memregion_free(int id)
+{
+}
+#endif
+#endif /* _MEMREGION_H_ */
index ebf5ef1..19eafca 100644 (file)
@@ -34,6 +34,8 @@ enum pm_qos_flags_status {
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT    PM_QOS_LATENCY_ANY
 #define PM_QOS_RESUME_LATENCY_NO_CONSTRAINT_NS PM_QOS_LATENCY_ANY_NS
 #define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0
+#define PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE     0
+#define PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE     FREQ_QOS_MAX_DEFAULT_VALUE
 #define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1)
 
 #define PM_QOS_FLAG_NO_POWER_OFF       (1 << 0)
@@ -49,21 +51,6 @@ struct pm_qos_flags_request {
        s32 flags;      /* Do not change to 64 bit */
 };
 
-enum dev_pm_qos_req_type {
-       DEV_PM_QOS_RESUME_LATENCY = 1,
-       DEV_PM_QOS_LATENCY_TOLERANCE,
-       DEV_PM_QOS_FLAGS,
-};
-
-struct dev_pm_qos_request {
-       enum dev_pm_qos_req_type type;
-       union {
-               struct plist_node pnode;
-               struct pm_qos_flags_request flr;
-       } data;
-       struct device *dev;
-};
-
 enum pm_qos_type {
        PM_QOS_UNITIALIZED,
        PM_QOS_MAX,             /* return the largest value */
@@ -90,9 +77,51 @@ struct pm_qos_flags {
        s32 effective_flags;    /* Do not change to 64 bit */
 };
 
+
+#define FREQ_QOS_MIN_DEFAULT_VALUE     0
+#define FREQ_QOS_MAX_DEFAULT_VALUE     S32_MAX
+
+enum freq_qos_req_type {
+       FREQ_QOS_MIN = 1,
+       FREQ_QOS_MAX,
+};
+
+struct freq_constraints {
+       struct pm_qos_constraints min_freq;
+       struct blocking_notifier_head min_freq_notifiers;
+       struct pm_qos_constraints max_freq;
+       struct blocking_notifier_head max_freq_notifiers;
+};
+
+struct freq_qos_request {
+       enum freq_qos_req_type type;
+       struct plist_node pnode;
+       struct freq_constraints *qos;
+};
+
+
+enum dev_pm_qos_req_type {
+       DEV_PM_QOS_RESUME_LATENCY = 1,
+       DEV_PM_QOS_LATENCY_TOLERANCE,
+       DEV_PM_QOS_MIN_FREQUENCY,
+       DEV_PM_QOS_MAX_FREQUENCY,
+       DEV_PM_QOS_FLAGS,
+};
+
+struct dev_pm_qos_request {
+       enum dev_pm_qos_req_type type;
+       union {
+               struct plist_node pnode;
+               struct pm_qos_flags_request flr;
+               struct freq_qos_request freq;
+       } data;
+       struct device *dev;
+};
+
 struct dev_pm_qos {
        struct pm_qos_constraints resume_latency;
        struct pm_qos_constraints latency_tolerance;
+       struct freq_constraints freq;
        struct pm_qos_flags flags;
        struct dev_pm_qos_request *resume_latency_req;
        struct dev_pm_qos_request *latency_tolerance_req;
@@ -191,6 +220,10 @@ static inline s32 dev_pm_qos_read_value(struct device *dev,
        switch (type) {
        case DEV_PM_QOS_RESUME_LATENCY:
                return PM_QOS_RESUME_LATENCY_NO_CONSTRAINT;
+       case DEV_PM_QOS_MIN_FREQUENCY:
+               return PM_QOS_MIN_FREQUENCY_DEFAULT_VALUE;
+       case DEV_PM_QOS_MAX_FREQUENCY:
+               return PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE;
        default:
                WARN_ON(1);
                return 0;
@@ -255,27 +288,6 @@ static inline s32 dev_pm_qos_raw_resume_latency(struct device *dev)
 }
 #endif
 
-#define FREQ_QOS_MIN_DEFAULT_VALUE     0
-#define FREQ_QOS_MAX_DEFAULT_VALUE     (-1)
-
-enum freq_qos_req_type {
-       FREQ_QOS_MIN = 1,
-       FREQ_QOS_MAX,
-};
-
-struct freq_constraints {
-       struct pm_qos_constraints min_freq;
-       struct blocking_notifier_head min_freq_notifiers;
-       struct pm_qos_constraints max_freq;
-       struct blocking_notifier_head max_freq_notifiers;
-};
-
-struct freq_qos_request {
-       enum freq_qos_req_type type;
-       struct plist_node pnode;
-       struct freq_constraints *qos;
-};
-
 static inline int freq_qos_request_active(struct freq_qos_request *req)
 {
        return !IS_ERR_OR_NULL(req->qos);
@@ -291,6 +303,8 @@ int freq_qos_add_request(struct freq_constraints *qos,
                         enum freq_qos_req_type type, s32 value);
 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value);
 int freq_qos_remove_request(struct freq_qos_request *req);
+int freq_qos_apply(struct freq_qos_request *req,
+                  enum pm_qos_req_action action, s32 value);
 
 int freq_qos_add_notifier(struct freq_constraints *qos,
                          enum freq_qos_req_type type,
index a45cba7..83edf86 100644 (file)
@@ -714,8 +714,10 @@ s32 freq_qos_read_value(struct freq_constraints *qos,
  * @req: Constraint request to apply.
  * @action: Action to perform (add/update/remove).
  * @value: Value to assign to the QoS request.
+ *
+ * This is only meant to be called from inside pm_qos, not drivers.
  */
-static int freq_qos_apply(struct freq_qos_request *req,
+int freq_qos_apply(struct freq_qos_request *req,
                          enum pm_qos_req_action action, s32 value)
 {
        int ret;
index 3321d04..681b7e5 100644 (file)
@@ -605,6 +605,9 @@ config ARCH_NO_SG_CHAIN
 config ARCH_HAS_PMEM_API
        bool
 
+config MEMREGION
+       bool
+
 # use memcpy to implement user copies for nommu architectures
 config UACCESS_MEMCPY
        bool
index b7f0ea9..c2f0e2a 100644 (file)
@@ -214,6 +214,7 @@ obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o
 
 obj-$(CONFIG_SG_SPLIT) += sg_split.o
 obj-$(CONFIG_SG_POOL) += sg_pool.o
+obj-$(CONFIG_MEMREGION) += memregion.o
 obj-$(CONFIG_STMP_DEVICE) += stmp_device.o
 obj-$(CONFIG_IRQ_POLL) += irq_poll.o
 
diff --git a/lib/memregion.c b/lib/memregion.c
new file mode 100644 (file)
index 0000000..77c85b5
--- /dev/null
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/* identifiers for device / performance-differentiated memory regions */
+#include <linux/idr.h>
+#include <linux/types.h>
+
+static DEFINE_IDA(memregion_ids);
+
+int memregion_alloc(gfp_t gfp)
+{
+       return ida_alloc(&memregion_ids, gfp);
+}
+EXPORT_SYMBOL(memregion_alloc);
+
+void memregion_free(int id)
+{
+       ida_free(&memregion_ids, id);
+}
+EXPORT_SYMBOL(memregion_free);