ACPI updates for 5.5-rc1

- Update the ACPICA code in the kernel to upstream revision 20191018
    including:
 
    * Fixes for Clang warnings (Bob Moore).
 
    * Fix for possible overflow in get_tick_count() (Bob Moore).
 
    * Introduction of acpi_unload_table() (Bob Moore).
 
    * Debugger and utilities updates (Erik Schmauss).
 
    * Fix for unloading tables loaded via configfs (Nikolaus Voss).
 
  - Add support for EFI specific purpose memory to optionally allow
    either application-exclusive or core-kernel-mm managed access to
    differentiated memory (Dan Williams).
 
  - Fix and clean up processing of the HMAT table (Brice Goglin,
    Qian Cai, Tao Xu).
 
  - Update the ACPI EC driver to make it work on systems with
    hardware-reduced ACPI (Daniel Drake).
 
  - Always build in support for the Generic Event Device (GED) to
    allow one kernel binary to work both on systems with full
    hardware ACPI and hardware-reduced ACPI (Arjan van de Ven).
 
  - Fix the table unload mechanism to unregister platform devices
    created when the given table was loaded (Andy Shevchenko).
 
  - Rework the lid blacklist handling in the button driver and add
    more lid quirks to it (Hans de Goede).
 
  - Improve ACPI-based device enumeration for some platforms based
    on Intel BayTrail SoCs (Hans de Goede).
 
  - Add an OpRegion driver for the Cherry Trail Crystal Cove PMIC
    and prevent handlers from being registered for unhandled PMIC
    OpRegions (Hans de Goede).
 
  - Unify ACPI _HID/_UID matching (Andy Shevchenko).
 
  - Clean up documentation and comments (Cao jin, James Pack, Kacper
    Piwiński).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAl3dHNkSHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRx/NkP/2y6DWjslA6UW4gjZwaRBcjYoyWExMtQ
 Z86goiRJtP+/NqOwm09wHFcV6FdZ4kitUno3UgMCDZJjrURapg1D0rxb1lSYtMzs
 mGr2FBZlVsJ9erOVSzKj1x2afVhdgl0Rl0fxPzoKgCFt8tCJar6cXy4CVEQKdeLs
 eUui2ksXMIEODGhpN/tr/fJqY4O4jlLmPY6gKWfFpSTsv6lnZmzcCxLf5EvUU7JW
 O91/jXdWz4Vl6IdP32sce6dGDjkvwnY105c7HeBf5EQWUe9RHFuSex982qhCD8U+
 iE+JzlhoYpUb03EktJSXbL++IKUHvoUpTanbhka6unMhazC86x0hDf7ruUtYo2Bk
 V8347CFeQ1x2O5IabfJNnUfKaMYhYmOXIoFHJTLKFO5mcCJmP8KOOyDAYilC1psb
 RJpl1fDoAhk7NqhMttyBqfxiotP0kMoKuqtAAl8Y0hTF0DwR9IfKntuTtp1yTGds
 R4dpJrizUDzw1/o4fCWbc3dFZQR3NFGpL/EAyfPzqjGaeaBBkLoNYstqkal5XHwT
 CILmQg2WHoNuQLXZ4NFFDrM2k2G+VUAjQdkYcb/MCOFbw+aTVPu1wyQq37RLtbMo
 9UwGeeT6SXW3iA1nyMoM+YvitjmxS7gHPPPl+b9G6kBubAzBPp91Ra0Mj9dPIGRB
 Evv5nzOIh8Hi
 =7Cqr
 -----END PGP SIGNATURE-----

Merge tag 'acpi-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI updates from Rafael Wysocki:
 "These update the ACPICA code in the kernel to upstream revision
  20191018, add support for EFI specific purpose memory, update the ACPI
  EC driver to make it work on systems with hardware-reduced ACPI,
  improve ACPI-based device enumeration for some platforms, rework the
  lid blacklist handling in the button driver and add more lid quirks to
  it, unify ACPI _HID/_UID matching, fix assorted issues and clean up
  the code and documentation.

  Specifics:

   - Update the ACPICA code in the kernel to upstream revision 20191018
     including:
      * Fixes for Clang warnings (Bob Moore)
      * Fix for possible overflow in get_tick_count() (Bob Moore)
      * Introduction of acpi_unload_table() (Bob Moore)
      * Debugger and utilities updates (Erik Schmauss)
      * Fix for unloading tables loaded via configfs (Nikolaus Voss)

   - Add support for EFI specific purpose memory to optionally allow
     either application-exclusive or core-kernel-mm managed access to
     differentiated memory (Dan Williams)

   - Fix and clean up processing of the HMAT table (Brice Goglin, Qian
     Cai, Tao Xu)

   - Update the ACPI EC driver to make it work on systems with
     hardware-reduced ACPI (Daniel Drake)

   - Always build in support for the Generic Event Device (GED) to allow
     one kernel binary to work both on systems with full hardware ACPI
     and hardware-reduced ACPI (Arjan van de Ven)

   - Fix the table unload mechanism to unregister platform devices
     created when the given table was loaded (Andy Shevchenko)

   - Rework the lid blacklist handling in the button driver and add more
     lid quirks to it (Hans de Goede)

   - Improve ACPI-based device enumeration for some platforms based on
     Intel BayTrail SoCs (Hans de Goede)

   - Add an OpRegion driver for the Cherry Trail Crystal Cove PMIC and
     prevent handlers from being registered for unhandled PMIC OpRegions
     (Hans de Goede)

   - Unify ACPI _HID/_UID matching (Andy Shevchenko)

   - Clean up documentation and comments (Cao jin, James Pack, Kacper
     Piwiński)"

* tag 'acpi-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (52 commits)
  ACPI: OSI: Shoot duplicate word
  ACPI: HMAT: use %u instead of %d to print u32 values
  ACPI: NUMA: HMAT: fix a section mismatch
  ACPI: HMAT: don't mix pxm and nid when setting memory target processor_pxm
  ACPI: NUMA: HMAT: Register "soft reserved" memory as an "hmem" device
  ACPI: NUMA: HMAT: Register HMAT at device_initcall level
  device-dax: Add a driver for "hmem" devices
  dax: Fix alloc_dax_region() compile warning
  lib: Uplevel the pmem "region" ida to a global allocator
  x86/efi: Add efi_fake_mem support for EFI_MEMORY_SP
  arm/efi: EFI soft reservation to memblock
  x86/efi: EFI soft reservation to E820 enumeration
  efi: Common enable/disable infrastructure for EFI soft reservation
  x86/efi: Push EFI_MEMMAP check into leaf routines
  efi: Enumerate EFI_MEMORY_SP
  ACPI: NUMA: Establish a new drivers/acpi/numa/ directory
  ACPICA: Update version to 20191018
  ACPICA: debugger: remove leading whitespaces when converting a string to a buffer
  ACPICA: acpiexec: initialize all simple types and field units from user input
  ACPICA: debugger: add field unit support for acpi_db_get_next_token
  ...
This commit is contained in:
Linus Torvalds 2019-11-26 19:25:25 -08:00
commit 6e9f879684
94 changed files with 1373 additions and 409 deletions

View File

@ -1168,7 +1168,8 @@
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.
@ -1177,6 +1178,12 @@
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
@ -1189,15 +1196,21 @@
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

View 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:

View 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);
}

View 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:

View 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;

View File

@ -28,6 +28,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

View 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 */

View 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;

View 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();

View 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);
@ -778,6 +815,15 @@ static bool should_map_region(efi_memory_desc_t *md)
if (IS_ENABLED(CONFIG_X86_32))
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.

View 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;

View 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 CrystalCove PMIC.
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 the Cherry Trail
version of the Crystal Cove PMIC.
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"

View 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

View 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 = {

View 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);

View 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);
}

View 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.
*/

View 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
*/

View 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 {

View 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

View 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];) {

View 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) {

View 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

View 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;

View 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 */

View 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")
@ -502,6 +503,86 @@ acpi_db_walk_for_object_counts(acpi_handle obj_handle,
return (AE_OK);
}
/*******************************************************************************
*
* 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
@ -628,6 +709,39 @@ acpi_status acpi_db_display_objects(char *obj_type_arg, char *display_count_arg)
return (AE_OK);
}
/*******************************************************************************
*
* 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

View 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 */

View 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 */

View 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;

View 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 */

View 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;
}

View 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 */

View 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;
}

View 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 "

View 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);

View 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);
}

View 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:

View 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 */

View 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:

View 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 */

View 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

View 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)

View 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;
}

View 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;
}

View 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;

View File

@ -44,9 +44,19 @@
#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[] = {
{
/* GP-electronic T701 */
/*
* 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, _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;
int i;
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;
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

View 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)
@ -648,7 +656,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;
/*
@ -717,7 +727,7 @@ static void advance_transaction(struct acpi_ec *ec)
++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:
@ -815,7 +825,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) */
@ -1275,18 +1285,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
* -------------------------------------------------------------------------- */
@ -1359,6 +1379,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;
}
@ -1406,9 +1428,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;
@ -1418,12 +1444,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;
@ -1456,24 +1527,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 */
@ -1504,23 +1574,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;
@ -1531,8 +1607,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;
}
@ -1596,7 +1672,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;
@ -1716,7 +1792,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;
@ -1889,14 +1965,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;
@ -1928,7 +2011,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);
@ -1943,7 +2026,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;

View File

@ -1,2 +0,0 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ACPI_HMAT) := hmat.o

View 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;

View 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),

View File

@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ACPI_NUMA) += srat.o
obj-$(CONFIG_ACPI_HMAT) += hmat.o

View 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;
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 = kzalloc(sizeof(*target), GFP_KERNEL);
if (!target)
return;
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,10 +634,91 @@ 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
@ -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 @@ static __init int hmat_init(void)
acpi_put_table(tbl);
return 0;
}
subsys_initcall(hmat_init);
device_initcall(hmat_init);

View 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,

View 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);

View 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);

View File

@ -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);

View 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();

View 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
@ -694,6 +701,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.

View 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.

View 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/

View 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;

View 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,

View 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;
};
/**

56
drivers/dax/hmem.c Normal file
View File

@ -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");

View 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

View 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)

View File

@ -163,6 +163,15 @@ static __init int is_usable_memory(efi_memory_desc_t *md)
case EFI_BOOT_SERVICES_DATA:
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

View 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;

View 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" : "",

View 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;

View File

@ -17,12 +17,10 @@
#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;
}

View File

@ -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__ */

View 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.

View 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 @@ efi_status_t efi_high_alloc(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;
@ -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++;

View 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);

View File

@ -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);
}
}
}

View 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;

View 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",

View 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 @@ static int bxt_get_cd(struct mmc_host *mmc)
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;
}

View 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

View 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();
}

View 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);

View 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);
}

View 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);

View 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))

View 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;

View 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)
{

View 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);

View 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,
};
/*

23
include/linux/memregion.h Normal file
View File

@ -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_ */

View 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

View 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

18
lib/memregion.c Normal file
View File

@ -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);