Commit cf1d2b44 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull ACPI updates from Rafael Wysocki:
 "These add support for generic initiator-only proximity domains to the
  ACPI NUMA code and the architectures using it, clean up some
  non-ACPICA code referring to debug facilities from ACPICA, reduce the
  overhead related to accessing GPE registers, add a new DPTF (Dynamic
  Power and Thermal Framework) participant driver, update the ACPICA
  code in the kernel to upstream revision 20200925, add a new ACPI
  backlight whitelist entry, fix a few assorted issues and clean up some
  code.

  Specifics:

   - Add support for generic initiator-only proximity domains to the
     ACPI NUMA code and the architectures using it (Jonathan Cameron)

   - Clean up some non-ACPICA code referring to debug facilities from
     ACPICA that are not actually used in there (Hanjun Guo)

   - Add new DPTF driver for the PCH FIVR participant (Srinivas
     Pandruvada)

   - Reduce overhead related to accessing GPE registers in ACPICA and
     the OS interface layer and make it possible to access GPE registers
     using logical addresses if they are memory-mapped (Rafael Wysocki)

   - Update the ACPICA code in the kernel to upstream revision 20200925
     including changes as follows:
      + Add predefined names from the SMBus sepcification (Bob Moore)
      + Update acpi_help UUID list (Bob Moore)
      + Return exceptions for string-to-integer conversions in iASL (Bob
        Moore)
      + Add a new "ALL <NameSeg>" debugger command (Bob Moore)
      + Add support for 64 bit risc-v compilation (Colin Ian King)
      + Do assorted cleanups (Bob Moore, Colin Ian King, Randy Dunlap)

   - Add new ACPI backlight whitelist entry for HP 635 Notebook (Alex
     Hung)

   - Move TPS68470 OpRegion driver to drivers/acpi/pmic/ and split out
     Kconfig and Makefile specific for ACPI PMIC (Andy Shevchenko)

   - Clean up the ACPI SoC driver for AMD SoCs (Hanjun Guo)

   - Add missing config_item_put() to fix refcount leak (Hanjun Guo)

   - Drop lefrover field from struct acpi_memory_device (Hanjun Guo)

   - Make the ACPI extlog driver check for RDMSR failures (Ben
     Hutchings)

   - Fix handling of lid state changes in the ACPI button driver when
     input device is closed (Dmitry Torokhov)

   - Fix several assorted build issues (Barnabás Pőcze, John Garry,
     Nathan Chancellor, Tian Tao)

   - Drop unused inline functions and reduce code duplication by using
     kobj_to_dev() in the NFIT parsing code (YueHaibing, Wang Qing)

   - Serialize tools/power/acpi Makefile (Thomas Renninger)"

* tag 'acpi-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (64 commits)
  ACPICA: Update version to 20200925 Version 20200925
  ACPICA: Remove unnecessary semicolon
  ACPICA: Debugger: Add a new command: "ALL <NameSeg>"
  ACPICA: iASL: Return exceptions for string-to-integer conversions
  ACPICA: acpi_help: Update UUID list
  ACPICA: Add predefined names found in the SMBus sepcification
  ACPICA: Tree-wide: fix various typos and spelling mistakes
  ACPICA: Drop the repeated word "an" in a comment
  ACPICA: Add support for 64 bit risc-v compilation
  ACPI: button: fix handling lid state changes when input device closed
  tools/power/acpi: Serialize Makefile
  ACPI: scan: Replace ACPI_DEBUG_PRINT() with pr_debug()
  ACPI: memhotplug: Remove 'state' from struct acpi_memory_device
  ACPI / extlog: Check for RDMSR failure
  ACPI: Make acpi_evaluate_dsm() prototype consistent
  docs: mm: numaperf.rst Add brief description for access class 1.
  node: Add access1 class to represent CPU to memory characteristics
  ACPI: HMAT: Fix handling of changes from ACPI 6.2 to ACPI 6.3
  ACPI: Let ACPI know we support Generic Initiator Affinity Structures
  x86: Support Generic Initiator only proximity domains
  ...
parents 0b8417c1 8be2362d
......@@ -92,3 +92,19 @@ Contact: linux-acpi@vger.kernel.org
Description:
(RO) The battery discharge current capability obtained from battery fuel gauge in
milli Amps.
What: /sys/bus/platform/devices/INTC1045:00/pch_fivr_switch_frequency/freq_mhz_low_clock
Date: November, 2020
KernelVersion: v5.10
Contact: linux-acpi@vger.kernel.org
Description:
(RW) The PCH FIVR (Fully Integrated Voltage Regulator) switching frequency in MHz,
when FIVR clock is 19.2MHz or 24MHz.
What: /sys/bus/platform/devices/INTC1045:00/pch_fivr_switch_frequency/freq_mhz_high_clock
Date: November, 2020
KernelVersion: v5.10
Contact: linux-acpi@vger.kernel.org
Description:
(RW) The PCH FIVR (Fully Integrated Voltage Regulator) switching frequency in MHz,
when FIVR clock is 38.4MHz.
......@@ -56,6 +56,11 @@ nodes' access characteristics share the same performance relative to other
linked initiator nodes. Each target within an initiator's access class,
though, do not necessarily perform the same as each other.
The access class "1" is used to allow differentiation between initiators
that are CPUs and hence suitable for generic task scheduling, and
IO initiators such as GPUs and NICs. Unlike access class 0, only
nodes containing CPUs are considered.
================
NUMA Performance
================
......@@ -88,6 +93,9 @@ The latency attributes are provided in nanoseconds.
The values reported here correspond to the rated latency and bandwidth
for the platform.
Access class 1 takes the same form but only includes values for CPU to
memory activity.
==========
NUMA Cache
==========
......
......@@ -405,7 +405,7 @@ F: drivers/platform/x86/i2c-multi-instantiate.c
ACPI PMIC DRIVERS
M: "Rafael J. Wysocki" <rjw@rjwysocki.net>
M: Len Brown <lenb@kernel.org>
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
R: Andy Shevchenko <andy@kernel.org>
R: Mika Westerberg <mika.westerberg@linux.intel.com>
L: linux-acpi@vger.kernel.org
S: Supported
......@@ -8953,7 +8953,7 @@ F: drivers/gpio/gpio-*cove.c
F: drivers/gpio/gpio-msic.c
INTEL PMIC MULTIFUNCTION DEVICE DRIVERS
R: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
M: Andy Shevchenko <andy@kernel.org>
S: Maintained
F: drivers/mfd/intel_msic.c
F: drivers/mfd/intel_soc_pmic*
......
......@@ -63,12 +63,14 @@ extern void numa_clear_node(int cpu);
extern void __init init_cpu_to_node(void);
extern void numa_add_cpu(int cpu);
extern void numa_remove_cpu(int cpu);
extern void init_gi_nodes(void);
#else /* CONFIG_NUMA */
static inline void numa_set_node(int cpu, int node) { }
static inline void numa_clear_node(int cpu) { }
static inline void init_cpu_to_node(void) { }
static inline void numa_add_cpu(int cpu) { }
static inline void numa_remove_cpu(int cpu) { }
static inline void init_gi_nodes(void) { }
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
......
......@@ -1199,6 +1199,7 @@ void __init setup_arch(char **cmdline_p)
prefill_possible_map();
init_cpu_to_node();
init_gi_nodes();
io_apic_init_mappings();
......
......@@ -745,6 +745,27 @@ static void __init init_memory_less_node(int nid)
*/
}
/*
* A node may exist which has one or more Generic Initiators but no CPUs and no
* memory.
*
* This function must be called after init_cpu_to_node(), to ensure that any
* memoryless CPU nodes have already been brought online, and before the
* node_data[nid] is needed for zone list setup in build_all_zonelists().
*
* When this function is called, any nodes containing either memory and/or CPUs
* will already be online and there is no need to do anything extra, even if
* they also contain one or more Generic Initiators.
*/
void __init init_gi_nodes(void)
{
int nid;
for_each_node_state(nid, N_GENERIC_INITIATOR)
if (!node_online(nid))
init_memory_less_node(nid);
}
/*
* Setup early cpu_to_node.
*
......
......@@ -504,55 +504,6 @@ config ACPI_EXTLOG
config ACPI_ADXL
bool
menuconfig PMIC_OPREGION
bool "PMIC (Power Management Integrated Circuit) operation region support"
help
Select this option to enable support for ACPI operation
region of the PMIC chip. The operation region can be used
to control power rails and sensor reading/writing on the
PMIC chip.
if PMIC_OPREGION
config BYTCRC_PMIC_OPREGION
bool "ACPI operation region support for Bay Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for the Bay Trail
version of the Crystal Cove PMIC.
config CHTCRC_PMIC_OPREGION
bool "ACPI operation region support for Cherry Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for the Cherry Trail
version of the Crystal Cove PMIC.
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"
depends on MFD_AXP20X_I2C && IOSF_MBI=y
help
This config adds ACPI operation region support for XPower AXP288 PMIC.
config BXT_WC_PMIC_OPREGION
bool "ACPI operation region support for BXT WhiskeyCove PMIC"
depends on INTEL_SOC_PMIC_BXTWC
help
This config adds ACPI operation region support for BXT WhiskeyCove PMIC.
config CHT_WC_PMIC_OPREGION
bool "ACPI operation region support for CHT Whiskey Cove PMIC"
depends on INTEL_SOC_PMIC_CHTWC
help
This config adds ACPI operation region support for CHT Whiskey Cove PMIC.
config CHT_DC_TI_PMIC_OPREGION
bool "ACPI operation region support for Dollar Cove TI PMIC"
depends on INTEL_SOC_PMIC_CHTDC_TI
help
This config adds ACPI operation region support for Dollar Cove TI PMIC.
endif
config ACPI_CONFIGFS
tristate "ACPI configfs support"
select CONFIGFS_FS
......@@ -568,21 +519,7 @@ config ACPI_PPTT
bool
endif
config TPS68470_PMIC_OPREGION
bool "ACPI operation region support for TPS68470 PMIC"
depends on MFD_TPS68470
help
This config adds ACPI operation region support for TI TPS68470 PMIC.
TPS68470 device is an advanced power management unit that powers
a Compact Camera Module (CCM), generates clocks for image sensors,
drives a dual LED for flash and incorporates two LED drivers for
general purpose indicators.
This driver enables ACPI operation region support control voltage
regulators and clocks.
This option is a bool as it provides an ACPI operation
region, which must be available before any of the devices
using this, are probed.
source "drivers/acpi/pmic/Kconfig"
endif # ACPI
......
......@@ -107,17 +107,9 @@ obj-$(CONFIG_ACPI_APEI) += apei/
obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.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
obj-$(CONFIG_CHT_DC_TI_PMIC_OPREGION) += pmic/intel_pmic_chtdc_ti.o
obj-$(CONFIG_ACPI_CONFIGFS) += acpi_configfs.o
obj-$(CONFIG_TPS68470_PMIC_OPREGION) += pmic/tps68470_pmic.o
obj-y += pmic/
video-objs += acpi_video.o video_detect.o
obj-y += dptf/
......
......@@ -7,39 +7,28 @@
* Wu, Jeff <Jeff.Wu@amd.com>
*/
#include <linux/clk-provider.h>
#include <linux/platform_data/clk-fch.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/clkdev.h>
#include <linux/acpi.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/pm.h>
#include <linux/platform_data/clk-fch.h>
#include <linux/platform_device.h>
#include "internal.h"
ACPI_MODULE_NAME("acpi_apd");
struct apd_private_data;
/**
* ACPI_APD_SYSFS : add device attributes in sysfs
* ACPI_APD_PM : attach power domain to device
*/
#define ACPI_APD_SYSFS BIT(0)
#define ACPI_APD_PM BIT(1)
/**
* struct apd_device_desc - a descriptor for apd device
* @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM
* @fixed_clk_rate: fixed rate input clock source for acpi device;
* 0 means no fixed rate input clock source
* @properties: build-in properties of the device such as UART
* @setup: a hook routine to set device resource during create platform device
*
* Device description defined as acpi_device_id.driver_data
*/
struct apd_device_desc {
unsigned int flags;
unsigned int fixed_clk_rate;
struct property_entry *properties;
int (*setup)(struct apd_private_data *pdata);
......@@ -71,7 +60,6 @@ static int acpi_apd_setup(struct apd_private_data *pdata)
}
#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
static int misc_check_res(struct acpi_resource *ares, void *data)
{
struct resource res;
......@@ -142,7 +130,7 @@ static const struct apd_device_desc cz_uart_desc = {
static const struct apd_device_desc fch_misc_desc = {
.setup = fch_misc_setup,
};
#endif
#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
#ifdef CONFIG_ARM64
static const struct apd_device_desc xgene_i2c_desc = {
......@@ -184,13 +172,9 @@ static const struct apd_device_desc hip08_spi_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 250000000,
};
#endif
#endif /* CONFIG_ARM64 */
#else
#define APD_ADDR(desc) (0UL)
#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
#endif
/**
* Create platform device during acpi scan attach handle.
......
......@@ -15,8 +15,6 @@
#include "internal.h"
ACPI_MODULE_NAME("cmos rtc");
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
{ "PNP0B00" },
{ "PNP0B01" },
......
......@@ -228,6 +228,7 @@ static void acpi_table_drop_item(struct config_group *group,
ACPI_INFO(("Host-directed Dynamic ACPI Table Unload"));
acpi_unload_table(table->index);
config_item_put(cfg);
}
static struct configfs_group_operations acpi_table_group_ops = {
......
......@@ -222,9 +222,9 @@ static int __init extlog_init(void)
u64 cap;
int rc;
rdmsrl(MSR_IA32_MCG_CAP, cap);
if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr())
if (rdmsrl_safe(MSR_IA32_MCG_CAP, &cap) ||
!(cap & MCG_ELOG_P) ||
!extlog_get_l1addr())
return -ENODEV;
rc = -EINVAL;
......
......@@ -26,8 +26,6 @@
#include "internal.h"
ACPI_MODULE_NAME("acpi_lpss");
#ifdef CONFIG_X86_INTEL_LPSS
#include <asm/cpu_device_id.h>
......
......@@ -22,13 +22,6 @@
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
#undef PREFIX
#define PREFIX "ACPI:memory_hp:"
ACPI_MODULE_NAME("acpi_memhotplug");
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
{"", 0},
......@@ -36,11 +29,6 @@ static const struct acpi_device_id memory_device_ids[] = {
#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
#define MEMORY_POWER_OFF_STATE 2
static int acpi_memory_device_add(struct acpi_device *device,
const struct acpi_device_id *not_used);
static void acpi_memory_device_remove(struct acpi_device *device);
......@@ -64,8 +52,7 @@ struct acpi_memory_info {
};
struct acpi_memory_device {
struct acpi_device * device;
unsigned int state; /* State of the memory device */
struct acpi_device *device;
struct list_head res_list;
};
......@@ -233,7 +220,6 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
}
if (!num_enabled) {
dev_err(&mem_device->device->dev, "add_memory failed\n");
mem_device->state = MEMORY_INVALID_STATE;
return -EINVAL;
}
/*
......@@ -304,9 +290,6 @@ static int acpi_memory_device_add(struct acpi_device *device,
return result;
}
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
result = acpi_memory_check_device(mem_device);
if (result) {
acpi_memory_device_free(mem_device);
......
......@@ -19,8 +19,6 @@
#include "internal.h"
ACPI_MODULE_NAME("platform");
static const struct acpi_device_id forbidden_id_list[] = {
{"PNP0000", 0}, /* PIC */
{"PNP0100", 0}, /* Timer */
......
......@@ -37,12 +37,14 @@ struct acpi_db_argument_info {
struct acpi_db_execute_walk {
u32 count;
u32 max_count;
char name_seg[ACPI_NAMESEG_SIZE + 1];
};
#define PARAM_LIST(pl) pl
#define EX_NO_SINGLE_STEP 1
#define EX_SINGLE_STEP 2
#define EX_ALL 4
/*
* dbxface - external debugger interfaces
......@@ -124,6 +126,8 @@ void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op);
void acpi_db_evaluate_predefined_names(void);
void acpi_db_evaluate_all(char *name_seg);
/*
* dbnames - namespace commands
*/
......
......@@ -42,6 +42,12 @@ ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1a_enable);
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_status);
ACPI_GLOBAL(struct acpi_generic_address, acpi_gbl_xpm1b_enable);
#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
ACPI_GLOBAL(unsigned long, acpi_gbl_xgpe0_block_logical_address);
ACPI_GLOBAL(unsigned long, acpi_gbl_xgpe1_block_logical_address);
#endif /* ACPI_GPE_USE_LOGICAL_ADDRESSES */
/*
* Handle both ACPI 1.0 and ACPI 2.0+ Integer widths. The integer width is
* determined by the revision of the DSDT: If the DSDT revision is less than
......
......@@ -73,9 +73,15 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width);
acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width);
acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count);
/*
* hwgpe - GPE support
*/
acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg);
acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg);
u32 acpi_hw_get_gpe_register_bit(struct acpi_gpe_event_info *gpe_event_info);
acpi_status
......
......@@ -454,11 +454,18 @@ struct acpi_gpe_event_info {
u8 disable_for_dispatch; /* Masked during dispatching */
};
/* GPE register address */
struct acpi_gpe_address {
u8 space_id; /* Address space where the register exists */
u64 address; /* 64-bit address of the register */
};
/* Information about a GPE register pair, one per each status/enable pair in an array */
struct acpi_gpe_register_info {
struct acpi_generic_address status_address; /* Address of status reg */
struct acpi_generic_address enable_address; /* Address of enable reg */
struct acpi_gpe_address status_address; /* Address of status reg */
struct acpi_gpe_address enable_address; /* Address of enable reg */
u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */
......
......@@ -101,7 +101,7 @@ enum acpi_return_package_types {
/* Support macros for users of the predefined info table */
#define METHOD_PREDEF_ARGS_MAX 4
#define METHOD_PREDEF_ARGS_MAX 5
#define METHOD_ARG_BIT_WIDTH 3
#define METHOD_ARG_MASK 0x0007
#define ARG_COUNT_IS_MINIMUM 0x8000
......@@ -117,6 +117,7 @@ enum acpi_return_package_types {
#define METHOD_2ARGS(a1,a2) (2 | (a1 << 3) | (a2 << 6))
#define METHOD_3ARGS(a1,a2,a3) (3 | (a1 << 3) | (a2 << 6) | (a3 << 9))
#define METHOD_4ARGS(a1,a2,a3,a4) (4 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12))
#define METHOD_5ARGS(a1,a2,a3,a4,a5) (5 | (a1 << 3) | (a2 << 6) | (a3 << 9) | (a4 << 12) | (a5 << 15))
#define METHOD_RETURNS(type) (type)
#define METHOD_NO_RETURN_VALUE 0
......@@ -902,9 +903,39 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_S4W", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
{{"_SBA", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
{{"_SBI", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Int, 1 Buf) */
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 1,
ACPI_RTYPE_BUFFER, 1, 0),
{{"_SBR",
METHOD_3ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
ACPI_TYPE_INTEGER),
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int) */
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,
ACPI_RTYPE_BUFFER | ACPI_RTYPE_INTEGER, 1, 0),
{{"_SBS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
{{"_SBT",
METHOD_4ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
ACPI_TYPE_ANY),
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (2 Int, 1 Buf | Int) */
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,
ACPI_RTYPE_BUFFER | ACPI_RTYPE_INTEGER, 1, 0),
{{"_SBW",
METHOD_5ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER,
ACPI_TYPE_INTEGER, ACPI_TYPE_ANY),
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}},
PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER | ACPI_RTYPE_INTEGER,
1, 0, 0, 0),
{{"_SCP", METHOD_1ARGS(ACPI_TYPE_INTEGER) | ARG_COUNT_IS_MINIMUM,
METHOD_NO_RETURN_VALUE}}, /* Acpi 1.0 allowed 1 integer arg. Acpi 3.0 expanded to 3 args. Allow both. */
......
......@@ -86,7 +86,8 @@ void acpi_db_delete_objects(u32 count, union acpi_object *objects)
*
* RETURN: Status
*
* DESCRIPTION: Execute a control method.
* DESCRIPTION: Execute a control method. Used to evaluate objects via the
* "EXECUTE" or "EVALUATE" commands.
*
******************************************************************************/
......@@ -314,11 +315,12 @@ acpi_db_execution_walk(acpi_handle obj_handle,
status = acpi_evaluate_object(node, NULL, NULL, &return_obj);
acpi_gbl_method_executing = FALSE;
acpi_os_printf("Evaluation of [%4.4s] returned %s\n",
acpi_ut_get_node_name(node),
acpi_format_exception(status));
acpi_gbl_method_executing = FALSE;
return (AE_OK);
}
......@@ -334,7 +336,8 @@ acpi_db_execution_walk(acpi_handle obj_handle,
* RETURN: None
*
* DESCRIPTION: Execute a control method. Name is relative to the current
* scope.
* scope. Function used for the "EXECUTE", "EVALUATE", and
* "ALL" commands
*
******************************************************************************/
......@@ -372,6 +375,12 @@ acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
return;
}
if ((flags & EX_ALL) && (strlen(name) > 4)) {
acpi_os_printf("Input name (%s) must be a 4-char NameSeg\n",
name);
return;
}
name_string = ACPI_ALLOCATE(strlen(name) + 1);
if (!name_string) {
return;
......@@ -389,13 +398,24 @@ acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
return;
}
acpi_gbl_db_method_info.name = name_string;
acpi_gbl_db_method_info.args = args;
acpi_gbl_db_method_info.types = types;
acpi_gbl_db_method_info.flags = flags;
/* Command (ALL <nameseg>) to execute all methods of a particular name */
return_obj.pointer = NULL;
return_obj.length = ACPI_ALLOCATE_BUFFER;
else if (flags & EX_ALL) {
acpi_gbl_db_method_info.name = name_string;
return_obj.pointer = NULL;
return_obj.length = ACPI_ALLOCATE_BUFFER;
acpi_db_evaluate_all(name_string);
ACPI_FREE(name_string);
return;
} else {
acpi_gbl_db_method_info.name = name_string;
acpi_gbl_db_method_info.args = args;
acpi_gbl_db_method_info.types = types;
acpi_gbl_db_method_info.flags = flags;
return_obj.pointer = NULL;
return_obj.length = ACPI_ALLOCATE_BUFFER;
}
status = acpi_db_execute_setup(&acpi_gbl_db_method_info);
if (ACPI_FAILURE(status)) {
......@@ -450,6 +470,7 @@ acpi_db_execute(char *name, char **args, acpi_object_type *types, u32 flags)
(u32)return_obj.length);
acpi_db_dump_external_object(return_obj.pointer, 1);
acpi_os_printf("\n");
/* Dump a _PLD buffer if present */
......
......@@ -37,6 +37,7 @@ acpi_db_match_command_help(const char *command,
enum acpi_ex_debugger_commands {
CMD_NOT_FOUND = 0,
CMD_NULL,
CMD_ALL,
CMD_ALLOCATIONS,
CMD_ARGS,
CMD_ARGUMENTS,
......@@ -115,6 +116,7 @@ enum acpi_ex_debugger_commands {
static const struct acpi_db_command_info acpi_gbl_db_commands[] = {
{"<NOT FOUND>", 0},
{"<NULL>", 0},
{"ALL", 1},
{"ALLOCATIONS", 0},
{"ARGS", 0},
{"ARGUMENTS", 0},
......@@ -222,6 +224,7 @@ static const struct acpi_db_command_help acpi_gbl_db_command_help[] = {
{1, " Type <Object>", "Display object type\n"},
{0, "\nControl Method Execution:", "\n"},
{1, " All <NameSeg>", "Evaluate all objects named NameSeg\n"},
{1, " Evaluate <Namepath> [Arguments]",
"Evaluate object or control method\n"},
{1, " Execute <Namepath> [Arguments]", "Synonym for Evaluate\n"},
......@@ -436,7 +439,7 @@ static void acpi_db_display_help(char *command)
acpi_os_printf("\n");
} else {
/* Display help for all commands that match the subtring */
/* Display help for all commands that match the substring */
acpi_db_display_command_info(command, TRUE);
}
......@@ -740,6 +743,15 @@ acpi_db_command_dispatch(char *input_buffer,
}
break;
case CMD_ALL:
acpi_os_printf("Executing all objects with NameSeg: %s\n",
acpi_gbl_db_args[1]);
acpi_db_execute(acpi_gbl_db_args[1], &acpi_gbl_db_args[2],
&acpi_gbl_db_arg_types[2],
EX_NO_SINGLE_STEP | EX_ALL);
break;
case CMD_ALLOCATIONS:
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
......
......@@ -21,6 +21,8 @@ static acpi_status
acpi_db_walk_for_execute(acpi_handle obj_handle,
u32 nesting_level, void *context, void **return_value);
static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node);
/*******************************************************************************
*
* FUNCTION: acpi_db_set_method_breakpoint
......@@ -346,42 +348,26 @@ acpi_status acpi_db_disassemble_method(char *name)
/*******************************************************************************
*
* FUNCTION: acpi_db_walk_for_execute
* FUNCTION: acpi_db_evaluate_object
*
* PARAMETERS: Callback from walk_namespace
* PARAMETERS: node - Namespace node for the object
*
* RETURN: Status
*
* DESCRIPTION: Batch execution module. Currently only executes predefined
* ACPI names.
* DESCRIPTION: Main execution function for the Evaluate/Execute/All debugger
* commands.
*
******************************************************************************/
static acpi_status
acpi_db_walk_for_execute(acpi_handle obj_handle,
u32 nesting_level, void *context, void **return_value)
static acpi_status acpi_db_evaluate_object(struct acpi_namespace_node *node)
{
struct acpi_namespace_node *node =
(struct acpi_namespace_node *)obj_handle;
struct acpi_db_execute_walk *info =
(struct acpi_db_execute_walk *)context;
struct acpi_buffer return_obj;
acpi_status status;
char *pathname;
u32 i;
struct acpi_device_info *obj_info;
struct acpi_object_list param_objects;
union acpi_object params[ACPI_METHOD_NUM_ARGS];
const union acpi_predefined_info *predefined;
predefined = acpi_ut_match_predefined_method(node->name.ascii);
if (!predefined) {
return (AE_OK);
}
if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
return (AE_OK);
}
struct acpi_buffer return_obj;
acpi_status status;
pathname = acpi_ns_get_external_pathname(node);
if (!pathname) {
......@@ -390,7 +376,7 @@ acpi_db_walk_for_execute(acpi_handle obj_handle,
/* Get the object info for number of method parameters */
status = acpi_get_object_info(obj_handle, &obj_info);
status = acpi_get_object_info(node, &obj_info);
if (ACPI_FAILURE(status)) {
ACPI_FREE(pathname);
return (status);
......@@ -421,14 +407,67 @@ acpi_db_walk_for_execute(acpi_handle obj_handle,
acpi_gbl_method_executing = TRUE;
status = acpi_evaluate_object(node, NULL, &param_objects, &return_obj);
acpi_gbl_method_executing = FALSE;
acpi_os_printf("%-32s returned %s\n", pathname,
acpi_format_exception(status));
acpi_gbl_method_executing = FALSE;
if (return_obj.length) {
acpi_os_printf("Evaluation of %s returned object %p, "
"external buffer length %X\n",
pathname, return_obj.pointer,
(u32)return_obj.length);
acpi_db_dump_external_object(return_obj.pointer, 1);
acpi_os_printf("\n");
}
ACPI_FREE(pathname);
/* Ignore status from method execution */
return (AE_OK);
/* Update count, check if we have executed enough methods */
}
/*******************************************************************************
*
* FUNCTION: acpi_db_walk_for_execute
*
* PARAMETERS: Callback from walk_namespace
*
* RETURN: Status
*
* DESCRIPTION: Batch execution function. Evaluates all "predefined" objects --
* the nameseg begins with an underscore.
*
******************************************************************************/
static acpi_status
acpi_db_walk_for_execute(acpi_handle obj_handle,
u32 nesting_level, void *context, void **return_value)
{
struct acpi_namespace_node *node =
(struct acpi_namespace_node *)obj_handle;
struct acpi_db_execute_walk *info =
(struct acpi_db_execute_walk *)context;
acpi_status status;
const union acpi_predefined_info *predefined;
predefined = acpi_ut_match_predefined_method(node->name.ascii);
if (!predefined) {
return (AE_OK);
}
if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
return (AE_OK);
}
acpi_db_evaluate_object(node);
/* Ignore status from object evaluation */
status = AE_OK;
/* Update count, check if we have executed enough methods */
......@@ -441,6 +480,52 @@ acpi_db_walk_for_execute(acpi_handle obj_handle,
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_db_walk_for_execute_all
*
* PARAMETERS: Callback from walk_namespace
*
* RETURN: Status
*
* DESCRIPTION: Batch execution function. Evaluates all objects whose path ends
* with the nameseg "Info->NameSeg". Used for the "ALL" command.
*
******************************************************************************/
static acpi_status
acpi_db_walk_for_execute_all(acpi_handle obj_handle,
u32 nesting_level,
void *context, void **return_value)
{
struct acpi_namespace_node *node =
(struct acpi_namespace_node *)obj_handle;
struct acpi_db_execute_walk *info =
(struct acpi_db_execute_walk *)context;
acpi_status status;
if (!ACPI_COMPARE_NAMESEG(node->name.ascii, info->name_seg)) {
return (AE_OK);
}
if (node->type == ACPI_TYPE_LOCAL_SCOPE) {
return (AE_OK);
}
/* Now evaluate the input object (node) */
acpi_db_evaluate_object(node);
/* Ignore status from method execution */
status = AE_OK;
/* Update count of executed methods/objects */
info->count++;
return (status);
}
/*******************************************************************************
*
* FUNCTION: acpi_db_evaluate_predefined_names
......@@ -470,3 +555,35 @@ void acpi_db_evaluate_predefined_names(void)
acpi_os_printf("Evaluated %u predefined names in the namespace\n",
info.count);
}
/*******************************************************************************
*
* FUNCTION: acpi_db_evaluate_all
*
* PARAMETERS: none_acpi_gbl_db_method_info
*
* RETURN: None
*
* DESCRIPTION: Namespace batch execution. Implements the "ALL" command.
* Execute all namepaths whose final nameseg matches the
* input nameseg.
*
******************************************************************************/
void acpi_db_evaluate_all(char *name_seg)
{
struct acpi_db_execute_walk info;
info.count = 0;
info.max_count = ACPI_UINT32_MAX;
ACPI_COPY_NAMESEG(info.name_seg, name_seg);
info.name_seg[ACPI_NAMESEG_SIZE] = 0;
/* Search all nodes in namespace */
(void)acpi_walk_namespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, acpi_db_walk_for_execute_all,
NULL, (void *)&info, NULL);
acpi_os_printf("Evaluated %u names in the namespace\n", info.count);
}
......@@ -656,14 +656,14 @@ acpi_ev_detect_gpe(struct acpi_namespace_node *gpe_device,
/* GPE currently enabled (enable bit == 1)? */
status = acpi_hw_read(&enable_reg, &gpe_register_info->enable_address);
status = acpi_hw_gpe_read(&enable_reg, &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
/* GPE currently active (status bit == 1)? */
status = acpi_hw_read(&status_reg, &gpe_register_info->status_address);
status = acpi_hw_gpe_read(&status_reg, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
......
......@@ -233,12 +233,6 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
this_register->status_address.space_id = gpe_block->space_id;
this_register->enable_address.space_id = gpe_block->space_id;
this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
this_register->enable_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
this_register->status_address.bit_offset = 0;
this_register->enable_address.bit_offset = 0;
/* Init the event_info for each GPE within this register */
......@@ -251,14 +245,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Disable all GPEs within this register */
status = acpi_hw_write(0x00, &this_register->enable_address);
status = acpi_hw_gpe_write(0x00, &this_register->enable_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
/* Clear any pending GPE events within this register */
status = acpi_hw_write(0xFF, &this_register->status_address);
status = acpi_hw_gpe_write(0xFF, &this_register->status_address);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
......@@ -317,6 +311,23 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
return_ACPI_STATUS(AE_OK);
}
/* Validate the space_ID */
if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
(space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
ACPI_ERROR((AE_INFO,
"Unsupported address space: 0x%X", space_id));
return_ACPI_STATUS(AE_SUPPORT);
}
if (space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
status = acpi_hw_validate_io_block(address,
ACPI_GPE_REGISTER_WIDTH,
register_count);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
}
/* Allocate a new GPE block */
gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info));
......
......@@ -32,6 +32,16 @@ ACPI_MODULE_NAME("evgpeinit")
* kernel boot time as well.
*/
#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
#define ACPI_FADT_GPE_BLOCK_ADDRESS(N) \
acpi_gbl_FADT.xgpe##N##_block.space_id == \
ACPI_ADR_SPACE_SYSTEM_MEMORY ? \
(u64)acpi_gbl_xgpe##N##_block_logical_address : \
acpi_gbl_FADT.xgpe##N##_block.address
#else
#define ACPI_FADT_GPE_BLOCK_ADDRESS(N) acpi_gbl_FADT.xgpe##N##_block.address
#endif /* ACPI_GPE_USE_LOGICAL_ADDRESSES */
/*******************************************************************************
*
* FUNCTION: acpi_ev_gpe_initialize
......@@ -49,6 +59,7 @@ acpi_status acpi_ev_gpe_initialize(void)
u32 register_count1 = 0;
u32 gpe_number_max = 0;
acpi_status status;
u64 address;
ACPI_FUNCTION_TRACE(ev_gpe_initialize);
......@@ -85,8 +96,9 @@ acpi_status acpi_ev_gpe_initialize(void)
* If EITHER the register length OR the block address are zero, then that
* particular block is not supported.
*/
if (acpi_gbl_FADT.gpe0_block_length &&
acpi_gbl_FADT.xgpe0_block.address) {
address = ACPI_FADT_GPE_BLOCK_ADDRESS(0);
if (acpi_gbl_FADT.gpe0_block_length && address) {
/* GPE block 0 exists (has both length and address > 0) */
......@@ -97,7 +109,6 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
acpi_gbl_FADT.xgpe0_block.
address,
acpi_gbl_FADT.xgpe0_block.
space_id, register_count0, 0,
......@@ -110,8 +121,9 @@ acpi_status acpi_ev_gpe_initialize(void)
}
}
if (acpi_gbl_FADT.gpe1_block_length &&
acpi_gbl_FADT.xgpe1_block.address) {
address = ACPI_FADT_GPE_BLOCK_ADDRESS(1);
if (acpi_gbl_FADT.gpe1_block_length && address) {
/* GPE block 1 exists (has both length and address > 0) */
......@@ -137,7 +149,6 @@ acpi_status acpi_ev_gpe_initialize(void)
status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
acpi_gbl_FADT.xgpe1_block.
address,
acpi_gbl_FADT.xgpe1_block.
space_id, register_count1,
......
......@@ -24,6 +24,76 @@ static acpi_status
acpi_hw_gpe_enable_write(u8 enable_mask,
struct acpi_gpe_register_info *gpe_register_info);
/******************************************************************************
*
* FUNCTION: acpi_hw_gpe_read
*
* PARAMETERS: value - Where the value is returned
* reg - GPE register structure
*
* RETURN: Status
*
* DESCRIPTION: Read from a GPE register in either memory or IO space.
*
* LIMITATIONS: <These limitations also apply to acpi_hw_gpe_write>
* space_ID must be system_memory or system_IO.
*
******************************************************************************/
acpi_status acpi_hw_gpe_read(u64 *value, struct acpi_gpe_address *reg)
{
acpi_status status;
u32 value32;
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
*value = (u64)ACPI_GET8(reg->address);
return_ACPI_STATUS(AE_OK);
#else
return acpi_os_read_memory((acpi_physical_address)reg->address,
value, ACPI_GPE_REGISTER_WIDTH);
#endif
}
status = acpi_os_read_port((acpi_io_address)reg->address,
&value32, ACPI_GPE_REGISTER_WIDTH);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
*value = (u64)value32;
return_ACPI_STATUS(AE_OK);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_gpe_write
*
* PARAMETERS: value - Value to be written
* reg - GPE register structure
*
* RETURN: Status
*
* DESCRIPTION: Write to a GPE register in either memory or IO space.
*
******************************************************************************/
acpi_status acpi_hw_gpe_write(u64 value, struct acpi_gpe_address *reg)
{
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
#ifdef ACPI_GPE_USE_LOGICAL_ADDRESSES
ACPI_SET8(reg->address, value);
return_ACPI_STATUS(AE_OK);
#else
return acpi_os_write_memory((acpi_physical_address)reg->address,
value, ACPI_GPE_REGISTER_WIDTH);
#endif
}
return acpi_os_write_port((acpi_io_address)reg->address, (u32)value,
ACPI_GPE_REGISTER_WIDTH);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_get_gpe_register_bit
......@@ -79,7 +149,8 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Get current value of the enable register that contains this GPE */
status = acpi_hw_read(&enable_mask, &gpe_register_info->enable_address);
status = acpi_hw_gpe_read(&enable_mask,
&gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
......@@ -118,9 +189,8 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Write the updated enable mask */
status =
acpi_hw_write(enable_mask,
&gpe_register_info->enable_address);
status = acpi_hw_gpe_write(enable_mask,
&gpe_register_info->enable_address);
}
return (status);
}
......@@ -158,8 +228,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info)
*/
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
status =
acpi_hw_write(register_bit, &gpe_register_info->status_address);
status = acpi_hw_gpe_write(register_bit,
&gpe_register_info->status_address);
return (status);
}
......@@ -227,7 +297,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
/* GPE currently enabled (enable bit == 1)? */
status = acpi_hw_read(&in_byte, &gpe_register_info->enable_address);
status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
return (status);
}
......@@ -238,7 +308,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
/* GPE currently active (status bit == 1)? */
status = acpi_hw_read(&in_byte, &gpe_register_info->status_address);
status = acpi_hw_gpe_read(&in_byte, &gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
return (status);
}
......@@ -274,7 +344,8 @@ acpi_hw_gpe_enable_write(u8 enable_mask,
gpe_register_info->enable_mask = enable_mask;
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
status = acpi_hw_gpe_write(enable_mask,
&gpe_register_info->enable_address);
return (status);
}
......@@ -341,9 +412,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Clear status on all GPEs in this register */
status =
acpi_hw_write(0xFF,
&gpe_block->register_info[i].status_address);
status = acpi_hw_gpe_write(0xFF,
&gpe_block->register_info[i].status_address);
if (ACPI_FAILURE(status)) {
return (status);
}
......@@ -481,14 +551,14 @@ acpi_hw_get_gpe_block_status(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
for (i = 0; i < gpe_block->register_count; i++) {
gpe_register_info = &gpe_block->register_info[i];
status = acpi_hw_read(&in_enable,
&gpe_register_info->enable_address);
status = acpi_hw_gpe_read(&in_enable,
&gpe_register_info->enable_address);
if (ACPI_FAILURE(status)) {
continue;
}
status = acpi_hw_read(&in_status,
&gpe_register_info->status_address);
status = acpi_hw_gpe_read(&in_status,
&gpe_register_info->status_address);
if (ACPI_FAILURE(status)) {
continue;
}
......
......@@ -292,3 +292,33 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
return (AE_OK);
}
/******************************************************************************
*
* FUNCTION: acpi_hw_validate_io_block
*
* PARAMETERS: Address Address of I/O port/register blobk
* bit_width Number of bits (8,16,32) in each register
* count Number of registers in the block
*
* RETURN: Status
*
* DESCRIPTION: Validates a block of I/O ports/registers.
*
******************************************************************************/
acpi_status acpi_hw_validate_io_block(u64 address, u32 bit_width, u32 count)
{
acpi_status status;
while (count--) {
status = acpi_hw_validate_io_request((acpi_io_address)address,
bit_width);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
address += ACPI_DIV_8(bit_width);
}
return_ACPI_STATUS(AE_OK);
}
......@@ -294,7 +294,7 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
node_to_delete = next_node;
next_node = next_node->peer;
acpi_ns_delete_node(node_to_delete);
};
}
/* Clear the parent's child pointer */
......
......@@ -55,7 +55,9 @@ void acpi_ns_check_argument_types(struct acpi_evaluate_info *info)
arg_type = METHOD_GET_NEXT_TYPE(arg_type_list);
user_arg_type = info->parameters[i]->common.type;
if (user_arg_type != arg_type) {
/* No typechecking for ACPI_TYPE_ANY */
if ((user_arg_type != arg_type) && (arg_type != ACPI_TYPE_ANY)) {
ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
ACPI_WARN_ALWAYS,
"Argument #%u type mismatch - "
......
......@@ -24,7 +24,8 @@ ACPI_MODULE_NAME("nsxfobj")
*
* RETURN: Status
*
* DESCRIPTION: This routine returns the type associatd with a particular handle
* DESCRIPTION: This routine returns the type associated with a particular
* handle
*
******************************************************************************/
acpi_status acpi_get_type(acpi_handle handle, acpi_object_type *ret_type)
......
......@@ -508,8 +508,8 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
}
/*
* If the transfer to the new method method call worked
*, a new walk state was created -- get it
* If the transfer to the new method method call worked,
* a new walk state was created -- get it
*/
walk_state = acpi_ds_get_current_walk_state(thread);
continue;
......
......@@ -151,7 +151,7 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types);
static const char *ut_external_type_names[] = /* Indexed by ACPI_TYPE_* */
{
", UNSUPPORTED-TYPE",
", Type_ANY",
", Integer",
", String",
", Buffer",
......@@ -311,8 +311,7 @@ static u32 acpi_ut_get_argument_types(char *buffer, u16 argument_types)
for (i = 0; i < arg_count; i++) {
this_argument_type = METHOD_GET_NEXT_TYPE(argument_types);
if (!this_argument_type
|| (this_argument_type > METHOD_MAX_ARG_TYPE)) {
if (this_argument_type > METHOD_MAX_ARG_TYPE) {
printf("**** Invalid argument type (%u) "
"in predefined info structure\n",
this_argument_type);
......
......@@ -45,10 +45,15 @@ acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value_ptr)
/* Convert each ASCII byte in the input string */
while (*string) {
/* Character must be ASCII 0-7, otherwise terminate with no error */
/*
* Character must be ASCII 0-7, otherwise:
* 1) Runtime: terminate with no error, per the ACPI spec
* 2) Compiler: return an error
*/
if (!(ACPI_IS_OCTAL_DIGIT(*string))) {
#ifdef ACPI_ASL_COMPILER
status = AE_BAD_OCTAL_CONSTANT;
#endif
break;
}
......@@ -94,10 +99,15 @@ acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr)
/* Convert each ASCII byte in the input string */
while (*string) {
/* Character must be ASCII 0-9, otherwise terminate with no error */
/*
* Character must be ASCII 0-9, otherwise:
* 1) Runtime: terminate with no error, per the ACPI spec
* 2) Compiler: return an error
*/
if (!isdigit(*string)) {
#ifdef ACPI_ASL_COMPILER
status = AE_BAD_DECIMAL_CONSTANT;
#endif
break;
}
......@@ -143,10 +153,15 @@ acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr)
/* Convert each ASCII byte in the input string */
while (*string) {
/* Must be ASCII A-F, a-f, or 0-9, otherwise terminate with no error */
/*
* Character must be ASCII A-F, a-f, or 0-9, otherwise:
* 1) Runtime: terminate with no error, per the ACPI spec
* 2) Compiler: return an error
*/
if (!isxdigit(*string)) {
#ifdef ACPI_ASL_COMPILER
status = AE_BAD_HEX_CONSTANT;
#endif
break;
}
......
......@@ -632,7 +632,11 @@ int apei_map_generic_address(struct acpi_generic_address *reg)
rc = apei_check_gar(reg, &address, &access_bit_width);
if (rc)
return rc;
return acpi_os_map_generic_address(reg);
if (!acpi_os_map_generic_address(reg))
return -ENXIO;
return 0;
}
EXPORT_SYMBOL_GPL(apei_map_generic_address);
......
......@@ -1329,7 +1329,7 @@ static int __init arm_smmu_v3_set_proximity(struct device *dev,
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
if (smmu->flags & ACPI_IORT_SMMU_V3_PXM_VALID) {
int dev_node = acpi_map_pxm_to_node(smmu->pxm);
int dev_node = pxm_to_node(smmu->pxm);
if (dev_node != NUMA_NO_NODE && !node_online(dev_node))
return -EINVAL;
......
......@@ -303,7 +303,11 @@ static void acpi_bus_osc_support(void)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_HOTPLUG_OST_SUPPORT;
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_PCLPI_SUPPORT;
#ifdef CONFIG_ARM64
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT;
#endif
#ifdef CONFIG_X86
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_GENERIC_INITIATOR_SUPPORT;
if (boot_cpu_has(X86_FEATURE_HWP)) {
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_CPC_SUPPORT;
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_CPCV2_SUPPORT;
......
......@@ -153,6 +153,7 @@ struct acpi_button {
int last_state;
ktime_t last_time;
bool suspended;
bool lid_state_initialized;
};
static struct acpi_device *lid_device;
......@@ -383,6 +384,8 @@ static int acpi_lid_update_state(struct acpi_device *device,
static void acpi_lid_initialize_state(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
(void)acpi_lid_notify_state(device, 1);
......@@ -394,13 +397,14 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
default:
break;
}
button->lid_state_initialized = true;
}
static void acpi_button_notify(struct acpi_device *device, u32 event)
{
struct acpi_button *button = acpi_driver_data(device);
struct input_dev *input;
int users;
switch (event) {
case ACPI_FIXED_HARDWARE_EVENT:
......@@ -409,10 +413,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
case ACPI_BUTTON_NOTIFY_STATUS:
input = button->input;
if (button->type == ACPI_BUTTON_TYPE_LID) {
mutex_lock(&button->input->mutex);
users = button->input->users;
mutex_unlock(&button->input->mutex);
if (users)
if (button->lid_state_initialized)
acpi_lid_update_state(device, true);
} else {
int keycode;
......@@ -457,7 +458,7 @@ static int acpi_button_resume(struct device *dev)
struct acpi_button *button = acpi_driver_data(device);
button->suspended = false;
if (button->type == ACPI_BUTTON_TYPE_LID && button->input->users) {
if (button->type == ACPI_BUTTON_TYPE_LID) {
button->last_state = !!acpi_lid_evaluate_state(device);
button->last_time = ktime_get();
acpi_lid_initialize_state(device);
......
......@@ -14,9 +14,6 @@
#include "internal.h"
#define _COMPONENT ACPI_CONTAINER_COMPONENT
ACPI_MODULE_NAME("container");
static const struct acpi_device_id container_device_ids[] = {
{"ACPI0004", 0},
{"PNP0A05", 0},
......
......@@ -13,8 +13,6 @@
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("custom_method");
MODULE_LICENSE("GPL");
static struct dentry *cm_dentry;
......
......@@ -10,9 +10,6 @@
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("debugfs");
struct dentry *acpi_debugfs_dir;
EXPORT_SYMBOL_GPL(acpi_debugfs_dir);
......
......@@ -20,8 +20,6 @@
#include "internal.h"
ACPI_MODULE_NAME("dock");
static bool immediate_undock = 1;
module_param(immediate_undock, bool, 0644);
MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
......
......@@ -14,3 +14,17 @@ config DPTF_POWER
To compile this driver as a module, choose M here:
the module will be called dptf_power.
config DPTF_PCH_FIVR
tristate "DPTF PCH FIVR Participant"
depends on X86
help
This driver adds support for Dynamic Platform and Thermal Framework
(DPTF) PCH FIVR Participant device support. This driver allows to
switch PCH FIVR (Fully Integrated Voltage Regulator) frequency.
This participant is responsible for exposing:
freq_mhz_low_clock
freq_mhz_high_clock
To compile this driver as a module, choose M here:
the module will be called dptf_pch_fivr.
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ACPI) += int340x_thermal.o
obj-$(CONFIG_DPTF_POWER) += dptf_power.o
obj-$(CONFIG_DPTF_PCH_FIVR) += dptf_pch_fivr.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* dptf_pch_fivr: DPTF PCH FIVR Participant driver
* Copyright (c) 2020, Intel Corporation.
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
/*
* Presentation of attributes which are defined for INT1045
* They are:
* freq_mhz_low_clock : Set PCH FIVR switching freq for
* FIVR clock 19.2MHz and 24MHz
* freq_mhz_high_clock : Set PCH FIVR switching freq for
* FIVR clock 38.4MHz
*/
#define PCH_FIVR_SHOW(name, method) \
static ssize_t name##_show(struct device *dev,\
struct device_attribute *attr,\
char *buf)\
{\
struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
unsigned long long val;\
acpi_status status;\
\
status = acpi_evaluate_integer(acpi_dev->handle, #method,\
NULL, &val);\
if (ACPI_SUCCESS(status))\
return sprintf(buf, "%d\n", (int)val);\
else\
return -EINVAL;\
}
#define PCH_FIVR_STORE(name, method) \
static ssize_t name##_store(struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count)\
{\
struct acpi_device *acpi_dev = dev_get_drvdata(dev);\
acpi_status status;\
u32 val;\
\
if (kstrtouint(buf, 0, &val) < 0)\
return -EINVAL;\
\
status = acpi_execute_simple_method(acpi_dev->handle, #method, val);\
if (ACPI_SUCCESS(status))\
return count;\
\
return -EINVAL;\
}
PCH_FIVR_SHOW(freq_mhz_low_clock, GFC0)
PCH_FIVR_SHOW(freq_mhz_high_clock, GFC1)
PCH_FIVR_STORE(freq_mhz_low_clock, RFC0)
PCH_FIVR_STORE(freq_mhz_high_clock, RFC1)
static DEVICE_ATTR_RW(freq_mhz_low_clock);
static DEVICE_ATTR_RW(freq_mhz_high_clock);
static struct attribute *fivr_attrs[] = {
&dev_attr_freq_mhz_low_clock.attr,
&dev_attr_freq_mhz_high_clock.attr,
NULL
};
static const struct attribute_group pch_fivr_attribute_group = {
.attrs = fivr_attrs,
.name = "pch_fivr_switch_frequency"
};
static int pch_fivr_add(struct platform_device *pdev)
{
struct acpi_device *acpi_dev;
unsigned long long ptype;
acpi_status status;
int result;
acpi_dev = ACPI_COMPANION(&(pdev->dev));
if (!acpi_dev)
return -ENODEV;
status = acpi_evaluate_integer(acpi_dev->handle, "PTYP", NULL, &ptype);
if (ACPI_FAILURE(status) || ptype != 0x05)
return -ENODEV;
result = sysfs_create_group(&pdev->dev.kobj,
&pch_fivr_attribute_group);
if (result)
return result;
platform_set_drvdata(pdev, acpi_dev);
return 0;
}
static int pch_fivr_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &pch_fivr_attribute_group);
return 0;
}
static const struct acpi_device_id pch_fivr_device_ids[] = {
{"INTC1045", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, pch_fivr_device_ids);
static struct platform_driver pch_fivr_driver = {
.probe = pch_fivr_add,
.remove = pch_fivr_remove,
.driver = {
.name = "DPTF PCH FIVR",
.acpi_match_table = pch_fivr_device_ids,
},
};
module_platform_driver(pch_fivr_driver);
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ACPI DPTF PCH FIVR driver");
......@@ -27,6 +27,7 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
{"INTC1040"},
{"INTC1043"},
{"INTC1044"},
{"INTC1045"},
{"INTC1047"},
{""},
};
......
......@@ -19,9 +19,6 @@
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("event");
/* ACPI notifier chain */
static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
......
......@@ -1389,7 +1389,7 @@ static bool ars_supported(struct nvdimm_bus *nvdimm_bus)
static umode_t nfit_visible(struct kobject *kobj, struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct nvdimm_bus *nvdimm_bus = to_nvdimm_bus(dev);
if (a == &dev_attr_scrub.attr)
......@@ -1679,7 +1679,7 @@ static struct attribute *acpi_nfit_dimm_attributes[] = {
static umode_t acpi_nfit_dimm_attr_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct device *dev = kobj_to_dev(kobj);
struct nvdimm *nvdimm = to_nvdimm(dev);
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
......@@ -3006,10 +3006,8 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
ndr_desc->provider_data = nfit_spa;
ndr_desc->attr_groups = acpi_nfit_region_attribute_groups;
if (spa->flags & ACPI_NFIT_PROXIMITY_VALID) {
ndr_desc->numa_node = acpi_map_pxm_to_online_node(
spa->proximity_domain);
ndr_desc->target_node = acpi_map_pxm_to_node(
spa->proximity_domain);
ndr_desc->numa_node = pxm_to_online_node(spa->proximity_domain);
ndr_desc->target_node = pxm_to_node(spa->proximity_domain);
} else {
ndr_desc->numa_node = NUMA_NO_NODE;
ndr_desc->target_node = NUMA_NO_NODE;
......
......@@ -63,7 +63,7 @@ struct memory_target {
unsigned int memory_pxm;
unsigned int processor_pxm;
struct resource memregions;
struct node_hmem_attrs hmem_attrs;
struct node_hmem_attrs hmem_attrs[2];
struct list_head caches;
struct node_cache_attrs cache_attrs;
bool registered;
......@@ -72,6 +72,7 @@ struct memory_target {
struct memory_initiator {
struct list_head node;
unsigned int processor_pxm;
bool has_cpu;
};
struct memory_locality {
......@@ -115,6 +116,7 @@ static __init void alloc_memory_initiator(unsigned int cpu_pxm)
return;
initiator->processor_pxm = cpu_pxm;
initiator->has_cpu = node_state(pxm_to_node(cpu_pxm), N_CPU);
list_add_tail(&initiator->node, &initiators);
}
......@@ -222,28 +224,28 @@ static u32 hmat_normalize(u16 entry, u64 base, u8 type)
}
static void hmat_update_target_access(struct memory_target *target,
u8 type, u32 value)
u8 type, u32 value, int access)
{
switch (type) {
case ACPI_HMAT_ACCESS_LATENCY:
target->hmem_attrs.read_latency = value;
target->hmem_attrs.write_latency = value;
target->hmem_attrs[access].read_latency = value;
target->hmem_attrs[access].write_latency = value;
break;
case ACPI_HMAT_READ_LATENCY:
target->hmem_attrs.read_latency = value;
target->hmem_attrs[access].read_latency = value;
break;
case ACPI_HMAT_WRITE_LATENCY:
target->hmem_attrs.write_latency = value;
target->hmem_attrs[access].write_latency = value;
break;
case ACPI_HMAT_ACCESS_BANDWIDTH:
target->hmem_attrs.read_bandwidth = value;
target->hmem_attrs.write_bandwidth = value;
target->hmem_attrs[access].read_bandwidth = value;
target->hmem_attrs[access].write_bandwidth = value;
break;
case ACPI_HMAT_READ_BANDWIDTH:
target->hmem_attrs.read_bandwidth = value;
target->hmem_attrs[access].read_bandwidth = value;
break;
case ACPI_HMAT_WRITE_BANDWIDTH:
target->hmem_attrs.write_bandwidth = value;
target->hmem_attrs[access].write_bandwidth = value;
break;
default:
break;
......@@ -336,8 +338,12 @@ static __init int hmat_parse_locality(union acpi_subtable_headers *header,
if (mem_hier == ACPI_HMAT_MEMORY) {
target = find_mem_target(targs[targ]);
if (target && target->processor_pxm == inits[init])
hmat_update_target_access(target, type, value);
if (target && target->processor_pxm == inits[init]) {
hmat_update_target_access(target, type, value, 0);
/* If the node has a CPU, update access 1 */
if (node_state(pxm_to_node(inits[init]), N_CPU))
hmat_update_target_access(target, type, value, 1);
}
}
}
}
......@@ -431,7 +437,8 @@ static int __init hmat_parse_proximity_domain(union acpi_subtable_headers *heade
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) {
if ((hmat_revision == 1 && p->flags & ACPI_HMAT_MEMORY_PD_VALID) ||
hmat_revision > 1) {
target = find_mem_target(p->memory_PD);
if (!target) {
pr_debug("HMAT: Memory Domain missing from SRAT\n");
......@@ -573,6 +580,7 @@ static void hmat_register_target_initiators(struct memory_target *target)
unsigned int mem_nid, cpu_nid;
struct memory_locality *loc = NULL;
u32 best = 0;
bool access0done = false;
int i;
mem_nid = pxm_to_node(target->memory_pxm);
......@@ -584,7 +592,11 @@ static void hmat_register_target_initiators(struct memory_target *target)
if (target->processor_pxm != PXM_INVAL) {
cpu_nid = pxm_to_node(target->processor_pxm);
register_memory_node_under_compute_node(mem_nid, cpu_nid, 0);
return;
access0done = true;
if (node_state(cpu_nid, N_CPU)) {
register_memory_node_under_compute_node(mem_nid, cpu_nid, 1);
return;
}
}
if (list_empty(&localities))
......@@ -598,6 +610,41 @@ static void hmat_register_target_initiators(struct memory_target *target)
*/
bitmap_zero(p_nodes, MAX_NUMNODES);
list_sort(p_nodes, &initiators, initiator_cmp);
if (!access0done) {
for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) {
loc = localities_types[i];
if (!loc)
continue;
best = 0;
list_for_each_entry(initiator, &initiators, node) {
u32 value;
if (!test_bit(initiator->processor_pxm, p_nodes))
continue;
value = hmat_initiator_perf(target, initiator,
loc->hmat_loc);
if (hmat_update_best(loc->hmat_loc->data_type, value, &best))
bitmap_clear(p_nodes, 0, initiator->processor_pxm);
if (value != best)
clear_bit(initiator->processor_pxm, p_nodes);
}
if (best)
hmat_update_target_access(target, loc->hmat_loc->data_type,
best, 0);
}
for_each_set_bit(i, p_nodes, MAX_NUMNODES) {
cpu_nid = pxm_to_node(i);
register_memory_node_under_compute_node(mem_nid, cpu_nid, 0);
}
}
/* Access 1 ignores Generic Initiators */
bitmap_zero(p_nodes, MAX_NUMNODES);
list_sort(p_nodes, &initiators, initiator_cmp);
best = 0;
for (i = WRITE_LATENCY; i <= READ_BANDWIDTH; i++) {
loc = localities_types[i];
if (!loc)
......@@ -607,6 +654,10 @@ static void hmat_register_target_initiators(struct memory_target *target)
list_for_each_entry(initiator, &initiators, node) {
u32 value;
if (!initiator->has_cpu) {
clear_bit(initiator->processor_pxm, p_nodes);
continue;
}
if (!test_bit(initiator->processor_pxm, p_nodes))
continue;
......@@ -617,12 +668,11 @@ static void hmat_register_target_initiators(struct memory_target *target)
clear_bit(initiator->processor_pxm, p_nodes);
}
if (best)
hmat_update_target_access(target, loc->hmat_loc->data_type, best);
hmat_update_target_access(target, loc->hmat_loc->data_type, best, 1);
}
for_each_set_bit(i, p_nodes, MAX_NUMNODES) {
cpu_nid = pxm_to_node(i);
register_memory_node_under_compute_node(mem_nid, cpu_nid, 0);
register_memory_node_under_compute_node(mem_nid, cpu_nid, 1);
}
}
......@@ -635,10 +685,10 @@ static void hmat_register_target_cache(struct memory_target *target)
node_add_cache(mem_nid, &tcache->cache_attrs);
}
static void hmat_register_target_perf(struct memory_target *target)
static void hmat_register_target_perf(struct memory_target *target, int access)
{
unsigned mem_nid = pxm_to_node(target->memory_pxm);
node_set_perf_attrs(mem_nid, &target->hmem_attrs, 0);
node_set_perf_attrs(mem_nid, &target->hmem_attrs[access], access);
}
static void hmat_register_target_devices(struct memory_target *target)
......@@ -653,7 +703,7 @@ static void hmat_register_target_devices(struct memory_target *target)
return;
for (res = target->memregions.child; res; res = res->sibling) {
int target_nid = acpi_map_pxm_to_node(target->memory_pxm);
int target_nid = pxm_to_node(target->memory_pxm);
hmem_register_device(target_nid, res);
}
......@@ -683,7 +733,8 @@ static void hmat_register_target(struct memory_target *target)
if (!target->registered) {
hmat_register_target_initiators(target);
hmat_register_target_cache(target);
hmat_register_target_perf(target);
hmat_register_target_perf(target, 0);
hmat_register_target_perf(target, 1);
target->registered = true;
}
mutex_unlock(&target_lock);
......
......@@ -36,7 +36,7 @@ void __init disable_srat(void)
int pxm_to_node(int pxm)
{
if (pxm < 0)
if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
return NUMA_NO_NODE;
return pxm_to_node_map[pxm];
}
......@@ -135,6 +135,36 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header)
}
break;
case ACPI_SRAT_TYPE_GENERIC_AFFINITY:
{
struct acpi_srat_generic_affinity *p =
(struct acpi_srat_generic_affinity *)header;
if (p->device_handle_type == 0) {
/*
* For pci devices this may be the only place they
* are assigned a proximity domain
*/
pr_debug("SRAT Generic Initiator(Seg:%u BDF:%u) in proximity domain %d %s\n",
*(u16 *)(&p->device_handle[0]),
*(u16 *)(&p->device_handle[2]),
p->proximity_domain,
(p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ?
"enabled" : "disabled");
} else {
/*
* In this case we can rely on the device having a
* proximity domain reference
*/
pr_debug("SRAT Generic Initiator(HID=%.8s UID=%.4s) in proximity domain %d %s\n",
(char *)(&p->device_handle[0]),
(char *)(&p->device_handle[8]),
p->proximity_domain,
(p->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED) ?
"enabled" : "disabled");
}
}
break;
default:
pr_warn("Found unsupported SRAT entry (type = 0x%x)\n",
header->type);
......@@ -337,6 +367,41 @@ acpi_parse_gicc_affinity(union acpi_subtable_headers *header,
return 0;
}
#if defined(CONFIG_X86) || defined(CONFIG_ARM64)
static int __init
acpi_parse_gi_affinity(union acpi_subtable_headers *header,
const unsigned long end)
{
struct acpi_srat_generic_affinity *gi_affinity;
int node;
gi_affinity = (struct acpi_srat_generic_affinity *)header;
if (!gi_affinity)
return -EINVAL;
acpi_table_print_srat_entry(&header->common);
if (!(gi_affinity->flags & ACPI_SRAT_GENERIC_AFFINITY_ENABLED))
return -EINVAL;
node = acpi_map_pxm_to_node(gi_affinity->proximity_domain);
if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
pr_err("SRAT: Too many proximity domains.\n");
return -EINVAL;
}
node_set(node, numa_nodes_parsed);
node_set_state(node, N_GENERIC_INITIATOR);
return 0;
}
#else
static int __init
acpi_parse_gi_affinity(union acpi_subtable_headers *header,
const unsigned long end)
{
return 0;
}
#endif /* defined(CONFIG_X86) || defined (CONFIG_ARM64) */
static int __initdata parsed_numa_memblks;
static int __init
......@@ -390,7 +455,7 @@ int __init acpi_numa_init(void)
/* SRAT: System Resource Affinity Table */
if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
struct acpi_subtable_proc srat_proc[3];
struct acpi_subtable_proc srat_proc[4];
memset(srat_proc, 0, sizeof(srat_proc));
srat_proc[0].id = ACPI_SRAT_TYPE_CPU_AFFINITY;
......@@ -399,6 +464,8 @@ int __init acpi_numa_init(void)
srat_proc[1].handler = acpi_parse_x2apic_affinity;
srat_proc[2].id = ACPI_SRAT_TYPE_GICC_AFFINITY;
srat_proc[2].handler = acpi_parse_gicc_affinity;
srat_proc[3].id = ACPI_SRAT_TYPE_GENERIC_AFFINITY;
srat_proc[3].handler = acpi_parse_gi_affinity;
acpi_table_parse_entries_array(ACPI_SIG_SRAT,
sizeof(struct acpi_table_srat),
......@@ -441,6 +508,6 @@ int acpi_get_node(acpi_handle handle)
pxm = acpi_get_pxm(handle);
return acpi_map_pxm_to_node(pxm);
return pxm_to_node(pxm);
}
EXPORT_SYMBOL(acpi_get_node);
......@@ -447,24 +447,19 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
int acpi_os_map_generic_address(struct acpi_generic_address *gas)
void __iomem *acpi_os_map_generic_address(struct acpi_generic_address *gas)
{
u64 addr;
void __iomem *virt;
if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
return 0;
return NULL;
/* Handle possible alignment issues */
memcpy(&addr, &gas->address, sizeof(addr));
if (!addr || !gas->bit_width)
return -EINVAL;
virt = acpi_os_map_iomem(addr, gas->bit_width / 8);
if (!virt)
return -EIO;
return NULL;
return 0;
return acpi_os_map_iomem(addr, gas->bit_width / 8);
}
EXPORT_SYMBOL(acpi_os_map_generic_address);
......@@ -1749,17 +1744,22 @@ acpi_status __init acpi_os_initialize(void)
{
acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
acpi_gbl_xgpe0_block_logical_address =
(unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
acpi_gbl_xgpe1_block_logical_address =
(unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) {
/*
* Use acpi_os_map_generic_address to pre-map the reset
* register if it's in system memory.
*/
int rv;
void *rv;
rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv);
pr_debug(PREFIX "%s: map reset_reg %s\n", __func__,
rv ? "successful" : "failed");
}
acpi_os_initialized = true;
......@@ -1787,8 +1787,12 @@ acpi_status acpi_os_terminate(void)
acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block);
acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);
acpi_gbl_xgpe0_block_logical_address = 0UL;
acpi_gbl_xgpe1_block_logical_address = 0UL;
acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)
acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register);
......
......@@ -24,8 +24,6 @@
#include "internal.h"
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
static int acpi_pci_root_add(struct acpi_device *device,
......@@ -62,7 +60,7 @@ static DEFINE_MUTEX(osc_lock);
/**
* acpi_is_root_bridge - determine whether an ACPI CA node is a PCI root bridge
* @handle - the ACPI CA node in question.
* @handle: the ACPI CA node in question.
*
* Note: we could make this API take a struct acpi_device * instead, but
* for now, it's more convenient to operate on an acpi_handle.
......
......@@ -28,9 +28,6 @@
static int check_sta_before_sun;
#define _COMPONENT ACPI_PCI_COMPONENT
ACPI_MODULE_NAME("pci_slot");
#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
struct acpi_pci_slot {
......
# SPDX-License-Identifier: GPL-2.0
menuconfig PMIC_OPREGION
bool "PMIC (Power Management Integrated Circuit) operation region support"
help
Select this option to enable support for ACPI operation
region of the PMIC chip. The operation region can be used
to control power rails and sensor reading/writing on the
PMIC chip.
if PMIC_OPREGION
config BYTCRC_PMIC_OPREGION
bool "ACPI operation region support for Bay Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for the Bay Trail
version of the Crystal Cove PMIC.
config CHTCRC_PMIC_OPREGION
bool "ACPI operation region support for Cherry Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for the Cherry Trail
version of the Crystal Cove PMIC.
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"
depends on MFD_AXP20X_I2C && IOSF_MBI=y
help
This config adds ACPI operation region support for XPower AXP288 PMIC.
config BXT_WC_PMIC_OPREGION
bool "ACPI operation region support for BXT WhiskeyCove PMIC"
depends on INTEL_SOC_PMIC_BXTWC
help
This config adds ACPI operation region support for BXT WhiskeyCove PMIC.
config CHT_WC_PMIC_OPREGION
bool "ACPI operation region support for CHT Whiskey Cove PMIC"
depends on INTEL_SOC_PMIC_CHTWC
help
This config adds ACPI operation region support for CHT Whiskey Cove PMIC.
config CHT_DC_TI_PMIC_OPREGION
bool "ACPI operation region support for Dollar Cove TI PMIC"
depends on INTEL_SOC_PMIC_CHTDC_TI
help
This config adds ACPI operation region support for Dollar Cove TI PMIC.
endif # PMIC_OPREGION
config TPS68470_PMIC_OPREGION
bool "ACPI operation region support for TPS68470 PMIC"
depends on MFD_TPS68470
help
This config adds ACPI operation region support for TI TPS68470 PMIC.
TPS68470 device is an advanced power management unit that powers
a Compact Camera Module (CCM), generates clocks for image sensors,
drives a dual LED for flash and incorporates two LED drivers for
general purpose indicators.
This driver enables ACPI operation region support control voltage
regulators and clocks.
This option is a bool as it provides an ACPI operation
region, which must be available before any of the devices
using this, are probed.
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PMIC_OPREGION) += intel_pmic.o
obj-$(CONFIG_BYTCRC_PMIC_OPREGION) += intel_pmic_bytcrc.o
obj-$(CONFIG_CHTCRC_PMIC_OPREGION) += intel_pmic_chtcrc.o
obj-$(CONFIG_XPOWER_PMIC_OPREGION) += intel_pmic_xpower.o
obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += intel_pmic_bxtwc.o
obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += intel_pmic_chtwc.o
obj-$(CONFIG_CHT_DC_TI_PMIC_OPREGION) += intel_pmic_chtdc_ti.o
obj-$(CONFIG_TPS68470_PMIC_OPREGION) += tps68470_pmic.o
......@@ -10,15 +10,11 @@
#include "sleep.h"
#include "internal.h"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
/*
* this file provides support for:
* /proc/acpi/wakeup
*/
ACPI_MODULE_NAME("sleep")
static int
acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
{
......
......@@ -14,9 +14,6 @@
#include <linux/acpi.h>
#include <acpi/processor.h>
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
static struct acpi_table_madt *get_madt_table(void)
{
static struct acpi_table_madt *madt;
......
......@@ -20,8 +20,6 @@
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_CLASS "processor"
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_thermal");
#ifdef CONFIG_CPU_FREQ
......
......@@ -898,8 +898,7 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
*/
err = acpi_device_sleep_wake(device, 0, 0, 0);
if (err)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"error in _DSW or _PSW evaluation\n"));
pr_debug("error in _DSW or _PSW evaluation\n");
}
static void acpi_bus_init_power_state(struct acpi_device *device, int state)
......
......@@ -4,7 +4,6 @@
#include <linux/acpi.h>
#include <acpi/button.h>
ACPI_MODULE_NAME("tiny-power-button");
MODULE_AUTHOR("Josh Triplett");
MODULE_DESCRIPTION("ACPI Tiny Power Button Driver");
MODULE_LICENSE("GPL");
......
......@@ -35,9 +35,6 @@
#include <linux/workqueue.h>
#include <acpi/video.h>
ACPI_MODULE_NAME("video");
#define _COMPONENT ACPI_VIDEO_COMPONENT
void acpi_video_unregister_backlight(void);
static bool backlight_notifier_registered;
......@@ -282,6 +279,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "530U4E/540U4E"),
},
},
/* https://bugs.launchpad.net/bugs/1894667 */
{
.callback = video_detect_force_video,
.ident = "HP 635 Notebook",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP 635 Notebook PC"),
},
},
/* Non win8 machines which need native backlight nevertheless */
{
......
......@@ -26,8 +26,6 @@ static DEFINE_MUTEX(acpi_wakeup_handler_mutex);
* suspend/resume and isn't really required as this is called in S-state. At
* that time, there is no device hotplug
**/
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME("wakeup_devices")
/**
* acpi_enable_wakeup_devices - Enable wake-up device GPEs.
......
......@@ -1005,6 +1005,8 @@ static struct node_attr node_state_attr[] = {
#endif
[N_MEMORY] = _NODE_ATTR(has_memory, N_MEMORY),
[N_CPU] = _NODE_ATTR(has_cpu, N_CPU),
[N_GENERIC_INITIATOR] = _NODE_ATTR(has_generic_initiator,
N_GENERIC_INITIATOR),
};
static struct attribute *node_state_attrs[] = {
......@@ -1016,6 +1018,7 @@ static struct attribute *node_state_attrs[] = {
#endif
&node_state_attr[N_MEMORY].attr.attr,
&node_state_attr[N_CPU].attr.attr,
&node_state_attr[N_GENERIC_INITIATOR].attr.attr,
NULL
};
......
......@@ -476,7 +476,7 @@ static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
rhsa = (struct acpi_dmar_rhsa *)header;
for_each_drhd_unit(drhd) {
if (drhd->reg_base_addr == rhsa->base_address) {
int node = acpi_map_pxm_to_node(rhsa->proximity_domain);
int node = pxm_to_node(rhsa->proximity_domain);
if (!node_online(node))
node = NUMA_NO_NODE;
......
......@@ -5269,7 +5269,12 @@ static int __init gic_acpi_parse_srat_its(union acpi_subtable_headers *header,
return -EINVAL;
}
node = acpi_map_pxm_to_node(its_affinity->proximity_domain);
/*
* Note that in theory a new proximity node could be created by this
* entry as it is an SRAT resource allocation structure.
* We do not currently support doing so.
*/
node = pxm_to_node(its_affinity->proximity_domain);
if (node == NUMA_NO_NODE || node >= MAX_NUMNODES) {
pr_err("SRAT: Invalid NUMA node %d in ITS affinity\n", node);
......
......@@ -121,7 +121,7 @@
*
*****************************************************************************/
/* Method info (in WALK_STATE), containing local variables and argumetns */
/* Method info (in WALK_STATE), containing local variables and arguments */
#define ACPI_METHOD_NUM_LOCALS 8
#define ACPI_METHOD_MAX_LOCAL 7
......
......@@ -40,12 +40,12 @@
struct acpi_exception_info {
char *name;
#ifdef ACPI_HELP_APP
#if defined (ACPI_HELP_APP) || defined (ACPI_ASL_COMPILER)
char *description;
#endif
};
#ifdef ACPI_HELP_APP
#if defined (ACPI_HELP_APP) || defined (ACPI_ASL_COMPILER)
#define EXCEP_TXT(name,description) {name, description}
#else
#define EXCEP_TXT(name,description) {name}
......
......@@ -21,7 +21,7 @@ void __iomem __ref
void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size);
void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size);
int acpi_os_map_generic_address(struct acpi_generic_address *addr);
void __iomem *acpi_os_map_generic_address(struct acpi_generic_address *addr);
void acpi_os_unmap_generic_address(struct acpi_generic_address *addr);
#endif
......@@ -26,6 +26,10 @@ extern int srat_disabled(void);
static inline void disable_srat(void)
{
}
static inline int pxm_to_node(int pxm)
{
return 0;
}
#endif /* CONFIG_ACPI_NUMA */
#ifdef CONFIG_ACPI_HMAT
......
......@@ -12,7 +12,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
#define ACPI_CA_VERSION 0x20200717
#define ACPI_CA_VERSION 0x20200925
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
......
......@@ -824,7 +824,7 @@ typedef u8 acpi_adr_space_type;
*
* Note: A Data Table region is a special type of operation region
* that has its own AML opcode. However, internally, the AML
* interpreter simply creates an operation region with an an address
* interpreter simply creates an operation region with an address
* space type of ACPI_ADR_SPACE_DATA_TABLE.
*/
#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 0x7E /* Internal to ACPICA only */
......
......@@ -27,6 +27,10 @@
#define UUID_PCI_HOST_BRIDGE "33db4d5b-1ff7-401c-9657-7441c03dd766"
#define UUID_I2C_DEVICE "3cdff6f7-4267-4555-ad05-b30a3d8938de"
#define UUID_POWER_BUTTON "dfbcf3c5-e7a5-44e6-9c1f-29c76f6e059c"
#define UUID_MEMORY_DEVICE "03b19910-f473-11dd-87af-0800200c9a66"
#define UUID_GENERIC_BUTTONS_DEVICE "fa6bd625-9ce8-470d-a2c7-b3ca36c4282e"
#define UUID_NVDIMM_ROOT_DEVICE "2f10e7a4-9e91-11e4-89d3-123b93f75cba"
#define UUID_CONTROL_METHOD_BATTERY "f18fc78b-0f15-4978-b793-53f833a1d35b"
/* Interfaces */
......@@ -56,5 +60,8 @@
#define UUID_BATTERY_THERMAL_LIMIT "4c2067e3-887d-475c-9720-4af1d3ed602e"
#define UUID_THERMAL_EXTENSIONS "14d399cd-7a27-4b18-8fb4-7cb7b9f4e500"
#define UUID_DEVICE_PROPERTIES "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
#define UUID_DEVICE_GRAPHS "ab02a46b-74c7-45a2-bd68-f7d344ef2153"
#define UUID_HIERARCHICAL_DATA_EXTENSION "dbb8e3e6-5886-4ba6-8795-1319f52a966b"
#define UUID_CORESIGHT_GRAPH "3ecbc8b6-1d0e-4fb3-8107-e627f805c6cd"
#endif /* __ACUUID_H__ */
......@@ -2,6 +2,8 @@
#ifndef __ACPI_BATTERY_H
#define __ACPI_BATTERY_H
#include <linux/power_supply.h>
#define ACPI_BATTERY_CLASS "battery"
#define ACPI_BATTERY_NOTIFY_STATUS 0x80
......
......@@ -118,6 +118,10 @@
#define USE_NATIVE_ALLOCATE_ZEROED
/* Use logical addresses for accessing GPE registers in system memory */
#define ACPI_GPE_USE_LOGICAL_ADDRESSES
/*
* Overrides for in-kernel ACPICA
*/
......@@ -190,7 +194,8 @@
#if defined(__ia64__) || (defined(__x86_64__) && !defined(__ILP32__)) ||\
defined(__aarch64__) || defined(__PPC64__) ||\
defined(__s390x__)
defined(__s390x__) ||\
(defined(__riscv) && (defined(__LP64__) || defined(_LP64)))
#define ACPI_MACHINE_WIDTH 64
#define COMPILER_DEPENDENT_INT64 long
#define COMPILER_DEPENDENT_UINT64 unsigned long
......
......@@ -420,28 +420,27 @@ int acpi_map_pxm_to_node(int pxm);
int acpi_get_node(acpi_handle handle);
/**
* acpi_map_pxm_to_online_node - Map proximity ID to online node
* pxm_to_online_node - Map proximity ID to online node
* @pxm: ACPI proximity ID
*
* This is similar to acpi_map_pxm_to_node(), but always returns an online
* This is similar to pxm_to_node(), but always returns an online
* node. When the mapped node from a given proximity ID is offline, it
* looks up the node distance table and returns the nearest online node.
*
* ACPI device drivers, which are called after the NUMA initialization has
* completed in the kernel, can call this interface to obtain their device
* NUMA topology from ACPI tables. Such drivers do not have to deal with
* offline nodes. A node may be offline when a device proximity ID is
* unique, SRAT memory entry does not exist, or NUMA is disabled, ex.
* "numa=off" on x86.
* offline nodes. A node may be offline when SRAT memory entry does not exist,
* or NUMA is disabled, ex. "numa=off" on x86.
*/
static inline int acpi_map_pxm_to_online_node(int pxm)
static inline int pxm_to_online_node(int pxm)
{
int node = acpi_map_pxm_to_node(pxm);
int node = pxm_to_node(pxm);
return numa_map_to_online_node(node);
}
#else
static inline int acpi_map_pxm_to_online_node(int pxm)
static inline int pxm_to_online_node(int pxm)
{
return 0;
}
......@@ -546,6 +545,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
#define OSC_SB_PCLPI_SUPPORT 0x00000080
#define OSC_SB_OSLPI_SUPPORT 0x00000100
#define OSC_SB_CPC_DIVERSE_HIGH_SUPPORT 0x00001000
#define OSC_SB_GENERIC_INITIATOR_SUPPORT 0x00002000
extern bool osc_sb_apei_support_acked;
extern bool osc_pc_lpi_support_confirmed;
......@@ -867,7 +867,7 @@ static inline bool acpi_driver_match_device(struct device *dev,
static inline union acpi_object *acpi_evaluate_dsm(acpi_handle handle,
const guid_t *guid,
int rev, int func,
u64 rev, u64 func,
union acpi_object *argv4)
{
return NULL;
......@@ -979,8 +979,6 @@ int acpi_subsys_runtime_suspend(struct device *dev);
int acpi_subsys_runtime_resume(struct device *dev);
int acpi_dev_pm_attach(struct device *dev, bool power_on);
#else
static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; }
static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; }
static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
......@@ -1218,13 +1216,6 @@ static inline int acpi_node_prop_get(const struct fwnode_handle *fwnode,
return -ENXIO;
}
static inline int acpi_dev_prop_get(const struct acpi_device *adev,
const char *propname,
void **valptr)
{
return -ENXIO;
}
static inline int acpi_dev_prop_read_single(const struct acpi_device *adev,
const char *propname,
enum dev_prop_type proptype,
......
......@@ -399,6 +399,7 @@ enum node_states {
#endif
N_MEMORY, /* The node has memory(regular, high, movable) */
N_CPU, /* The node has one or more cpus */
N_GENERIC_INITIATOR, /* The node has one or more Generic Initiators */
NR_NODE_STATES
};
......
......@@ -7,6 +7,8 @@
include ../../scripts/Makefile.include
.NOTPARALLEL:
all: acpidbg acpidump ec
clean: acpidbg_clean acpidump_clean ec_clean
install: acpidbg_install acpidump_install ec_install
......
......@@ -110,7 +110,7 @@ u32 gbl_table_count = 0;
*
* RETURN: Status; Converted from errno.
*
* DESCRIPTION: Get last errno and conver it to acpi_status.
* DESCRIPTION: Get last errno and convert it to acpi_status.
*
*****************************************************************************/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment