Merge back earlier ACPICA changes for v4.11.

This commit is contained in:
Rafael J. Wysocki 2017-01-30 08:57:22 +01:00
commit 1b62d134d3
11659 changed files with 740674 additions and 247265 deletions

View file

@ -104,7 +104,7 @@ config ACPI_PROCFS_POWER
Say N to delete power /proc/acpi/ directories that have moved to /sys/
config ACPI_REV_OVERRIDE_POSSIBLE
bool "Allow supported ACPI revision to be overriden"
bool "Allow supported ACPI revision to be overridden"
depends on X86
default y
help
@ -342,7 +342,7 @@ config ACPI_DEBUG
Use the acpi.debug_layer and acpi.debug_level kernel command-line
parameters documented in Documentation/acpi/debug.txt and
Documentation/kernel-parameters.txt to control the type and
Documentation/admin-guide/kernel-parameters.rst to control the type and
amount of debug output.
config ACPI_PCI_SLOT

View file

@ -77,6 +77,11 @@ static const struct apd_device_desc cz_i2c_desc = {
.fixed_clk_rate = 133000000,
};
static const struct apd_device_desc wt_i2c_desc = {
.setup = acpi_apd_setup,
.fixed_clk_rate = 150000000,
};
static struct property_entry uart_properties[] = {
PROPERTY_ENTRY_U32("reg-io-width", 4),
PROPERTY_ENTRY_U32("reg-shift", 2),
@ -156,7 +161,7 @@ static const struct acpi_device_id acpi_apd_device_ids[] = {
/* Generic apd devices */
#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
{ "AMD0010", APD_ADDR(cz_i2c_desc) },
{ "AMDI0010", APD_ADDR(cz_i2c_desc) },
{ "AMDI0010", APD_ADDR(wt_i2c_desc) },
{ "AMD0020", APD_ADDR(cz_uart_desc) },
{ "AMDI0020", APD_ADDR(cz_uart_desc) },
{ "AMD0030", },

View file

@ -718,13 +718,14 @@ static int acpi_lpss_resume_early(struct device *dev)
#define LPSS_GPIODEF0_DMA1_D3 BIT(2)
#define LPSS_GPIODEF0_DMA2_D3 BIT(3)
#define LPSS_GPIODEF0_DMA_D3_MASK GENMASK(3, 2)
#define LPSS_GPIODEF0_DMA_LLP BIT(13)
static DEFINE_MUTEX(lpss_iosf_mutex);
static void lpss_iosf_enter_d3_state(void)
{
u32 value1 = 0;
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK;
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP;
u32 value2 = LPSS_PMCSR_D3hot;
u32 mask2 = LPSS_PMCSR_Dx_MASK;
/*
@ -768,8 +769,9 @@ exit:
static void lpss_iosf_exit_d3_state(void)
{
u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3;
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK;
u32 value1 = LPSS_GPIODEF0_DMA1_D3 | LPSS_GPIODEF0_DMA2_D3 |
LPSS_GPIODEF0_DMA_LLP;
u32 mask1 = LPSS_GPIODEF0_DMA_D3_MASK | LPSS_GPIODEF0_DMA_LLP;
u32 value2 = LPSS_PMCSR_D0;
u32 mask2 = LPSS_PMCSR_Dx_MASK;

View file

@ -37,23 +37,12 @@
#include <linux/suspend.h>
#include <linux/acpi.h>
#include <acpi/video.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#define PREFIX "ACPI: "
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
#define ACPI_VIDEO_NOTIFY_PROBE 0x81
#define ACPI_VIDEO_NOTIFY_CYCLE 0x82
#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x85
#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
#define MAX_NAME_LEN 20

View file

@ -770,7 +770,7 @@ union acpi_parse_value {
char *operator_symbol;/* Used for C-style operator name strings */\
char aml_op_name[16]) /* Op name (debug only) */
/* Flags for disasm_flags field above */
/* Internal opcodes for disasm_opcode field above */
#define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */
#define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */
@ -783,7 +783,10 @@ union acpi_parse_value {
#define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a Lnot_equal (etc.) pair of opcodes */
#define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a Lnot_equal (etc.) pair of opcodes */
#define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */
#define ACPI_DASM_IGNORE 0x0B /* Not used at this time */
#define ACPI_DASM_IGNORE_SINGLE 0x0B /* Ignore the opcode but not it's children */
#define ACPI_DASM_SWITCH_PREDICATE 0x0C /* Object is a predicate for a Switch or Case block */
#define ACPI_DASM_CASE 0x0D /* If/Else is a Case in a Switch/Case block */
#define ACPI_DASM_DEFAULT 0x0E /* Else is a Default in a Switch/Case block */
/*
* Generic operation (for example: If, While, Store)

View file

@ -46,7 +46,7 @@
/*
* Extract data using a pointer. Any more than a byte and we
* get into potential aligment issues -- see the STORE macros below.
* get into potential alignment issues -- see the STORE macros below.
* Use with care.
*/
#define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr))
@ -63,7 +63,7 @@
#define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val))
/*
* printf() format helper. This macros is a workaround for the difficulties
* printf() format helper. This macro is a workaround for the difficulties
* with emitting 64-bit integers and 64-bit pointers with the same code
* for both 32-bit and 64-bit hosts.
*/
@ -260,8 +260,70 @@
#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1))
/* Generic bit manipulation */
#ifndef ACPI_USE_NATIVE_BIT_FINDER
#define __ACPI_FIND_LAST_BIT_2(a, r) ((((u8) (a)) & 0x02) ? (r)+1 : (r))
#define __ACPI_FIND_LAST_BIT_4(a, r) ((((u8) (a)) & 0x0C) ? \
__ACPI_FIND_LAST_BIT_2 ((a)>>2, (r)+2) : \
__ACPI_FIND_LAST_BIT_2 ((a), (r)))
#define __ACPI_FIND_LAST_BIT_8(a, r) ((((u8) (a)) & 0xF0) ? \
__ACPI_FIND_LAST_BIT_4 ((a)>>4, (r)+4) : \
__ACPI_FIND_LAST_BIT_4 ((a), (r)))
#define __ACPI_FIND_LAST_BIT_16(a, r) ((((u16) (a)) & 0xFF00) ? \
__ACPI_FIND_LAST_BIT_8 ((a)>>8, (r)+8) : \
__ACPI_FIND_LAST_BIT_8 ((a), (r)))
#define __ACPI_FIND_LAST_BIT_32(a, r) ((((u32) (a)) & 0xFFFF0000) ? \
__ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \
__ACPI_FIND_LAST_BIT_16 ((a), (r)))
#define __ACPI_FIND_LAST_BIT_64(a, r) ((((u64) (a)) & 0xFFFFFFFF00000000) ? \
__ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \
__ACPI_FIND_LAST_BIT_32 ((a), (r)))
#define ACPI_FIND_LAST_BIT_8(a) ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 1) : 0)
#define ACPI_FIND_LAST_BIT_16(a) ((a) ? __ACPI_FIND_LAST_BIT_16 (a, 1) : 0)
#define ACPI_FIND_LAST_BIT_32(a) ((a) ? __ACPI_FIND_LAST_BIT_32 (a, 1) : 0)
#define ACPI_FIND_LAST_BIT_64(a) ((a) ? __ACPI_FIND_LAST_BIT_64 (a, 1) : 0)
#define __ACPI_FIND_FIRST_BIT_2(a, r) ((((u8) (a)) & 0x01) ? (r) : (r)+1)
#define __ACPI_FIND_FIRST_BIT_4(a, r) ((((u8) (a)) & 0x03) ? \
__ACPI_FIND_FIRST_BIT_2 ((a), (r)) : \
__ACPI_FIND_FIRST_BIT_2 ((a)>>2, (r)+2))
#define __ACPI_FIND_FIRST_BIT_8(a, r) ((((u8) (a)) & 0x0F) ? \
__ACPI_FIND_FIRST_BIT_4 ((a), (r)) : \
__ACPI_FIND_FIRST_BIT_4 ((a)>>4, (r)+4))
#define __ACPI_FIND_FIRST_BIT_16(a, r) ((((u16) (a)) & 0x00FF) ? \
__ACPI_FIND_FIRST_BIT_8 ((a), (r)) : \
__ACPI_FIND_FIRST_BIT_8 ((a)>>8, (r)+8))
#define __ACPI_FIND_FIRST_BIT_32(a, r) ((((u32) (a)) & 0x0000FFFF) ? \
__ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \
__ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16))
#define __ACPI_FIND_FIRST_BIT_64(a, r) ((((u64) (a)) & 0x00000000FFFFFFFF) ? \
__ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \
__ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32))
#define ACPI_FIND_FIRST_BIT_8(a) ((a) ? __ACPI_FIND_FIRST_BIT_8 (a, 1) : 0)
#define ACPI_FIND_FIRST_BIT_16(a) ((a) ? __ACPI_FIND_FIRST_BIT_16 (a, 1) : 0)
#define ACPI_FIND_FIRST_BIT_32(a) ((a) ? __ACPI_FIND_FIRST_BIT_32 (a, 1) : 0)
#define ACPI_FIND_FIRST_BIT_64(a) ((a) ? __ACPI_FIND_FIRST_BIT_64 (a, 1) : 0)
#endif /* ACPI_USE_NATIVE_BIT_FINDER */
/* Generic (power-of-two) rounding */
#define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((u8) \
(((u16) 1) << ACPI_FIND_LAST_BIT_8 ((a) - 1)))
#define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a) ((u8) \
(((u16) 1) << (ACPI_FIND_LAST_BIT_8 ((a)) - 1)))
#define ACPI_ROUND_UP_POWER_OF_TWO_16(a) ((u16) \
(((u32) 1) << ACPI_FIND_LAST_BIT_16 ((a) - 1)))
#define ACPI_ROUND_DOWN_POWER_OF_TWO_16(a) ((u16) \
(((u32) 1) << (ACPI_FIND_LAST_BIT_16 ((a)) - 1)))
#define ACPI_ROUND_UP_POWER_OF_TWO_32(a) ((u32) \
(((u64) 1) << ACPI_FIND_LAST_BIT_32 ((a) - 1)))
#define ACPI_ROUND_DOWN_POWER_OF_TWO_32(a) ((u32) \
(((u64) 1) << (ACPI_FIND_LAST_BIT_32 ((a)) - 1)))
#define ACPI_IS_ALIGNED(a, s) (((a) & ((s) - 1)) == 0)
#define ACPI_IS_POWER_OF_TWO(a) ACPI_IS_ALIGNED(a, a)
@ -270,8 +332,8 @@
* Bit positions start at zero.
* MASK_BITS_ABOVE creates a mask starting AT the position and above
* MASK_BITS_BELOW creates a mask starting one bit BELOW the position
* MASK_BITS_ABOVE/BELOW accpets a bit offset to create a mask
* MASK_BITS_ABOVE/BELOW_32/64 accpets a bit width to create a mask
* MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask
* MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask
* Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler
* differences with the shift operator
*/
@ -389,7 +451,7 @@
*/
#ifndef ACPI_NO_ERROR_MESSAGES
/*
* Error reporting. Callers module and line number are inserted by AE_INFO,
* Error reporting. The callers module and line number are inserted by AE_INFO,
* the plist contains a set of parens to allow variable-length lists.
* These macros are used for both the debug and non-debug versions of the code.
*/

View file

@ -92,7 +92,7 @@
#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET)
#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET)
#define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
#define ARGP_CONTINUE_OP ARG_NONE
#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME)
@ -105,7 +105,7 @@
#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
#define ARGP_DEBUG_OP ARG_NONE
#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
@ -152,14 +152,14 @@
#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
#define ARGP_NOOP_OP ARG_NONE
#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF)
#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_SIMPLENAME)
#define ARGP_ONE_OP ARG_NONE
#define ARGP_ONES_OP ARG_NONE
#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA)
#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_NAME_OR_REF)
#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SIMPLENAME)
#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
@ -249,7 +249,7 @@
#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_IF_OP ARGI_INVALID_OPCODE
#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
@ -313,12 +313,12 @@
#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
#define ARGI_TIMER_OP ARG_NONE
#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET)
#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF)
#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER)

View file

@ -277,9 +277,23 @@
#define ARGI_DEVICE_REF 0x0D
#define ARGI_REFERENCE 0x0E
#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */
#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */
#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */
#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */
#define ARGI_SIMPLE_TARGET 0x10 /* Name, Local, Arg -- no implicit conversion */
#define ARGI_STORE_TARGET 0x11 /* Target for store is TARGETREF + package objects */
/*
* #define ARGI_FIXED_TARGET 0x10 Target, no implicit conversion
*
* Removed 10/2016. ARGI_FIXED_TARGET was used for these operators:
* from_BCD
* to_BCD
* to_decimal_string
* to_hex_string
* to_integer
* to_buffer
* The purpose of this type was to disable "implicit result conversion",
* but this was incorrect per the ACPI spec and other ACPI implementations.
* These operators now have the target operand defined as a normal
* ARGI_TARGETREF.
*/
/* Multiple/complex types */

View file

@ -430,7 +430,7 @@ acpi_status acpi_initialize_debugger(void)
/* These were created with one unit, grab it */
status = acpi_os_initialize_command_signals();
status = acpi_os_initialize_debugger();
if (ACPI_FAILURE(status)) {
acpi_os_printf("Could not get debugger mutex\n");
return_ACPI_STATUS(status);
@ -482,7 +482,7 @@ void acpi_terminate_debugger(void)
acpi_os_sleep(100);
}
acpi_os_terminate_command_signals();
acpi_os_terminate_debugger();
}
if (acpi_gbl_db_buffer) {

View file

@ -592,7 +592,6 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type,
*/
switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) {
case ARGI_SIMPLE_TARGET:
case ARGI_FIXED_TARGET:
case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */
switch (destination_type) {

View file

@ -305,7 +305,6 @@ acpi_ex_resolve_operands(u16 opcode,
case ARGI_OBJECT_REF:
case ARGI_DEVICE_REF:
case ARGI_TARGETREF: /* Allows implicit conversion rules before store */
case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
case ARGI_SIMPLE_TARGET: /* Name, Local, or arg - no implicit conversion */
case ARGI_STORE_TARGET:

View file

@ -43,7 +43,6 @@
*/
#include <acpi/acpi.h>
#include <linux/acpi.h>
#include "accommon.h"
#define _COMPONENT ACPI_HARDWARE
@ -103,7 +102,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
acpi_status acpi_hw_extended_sleep(u8 sleep_state)
{
acpi_status status;
u8 sleep_type_value;
u8 sleep_control;
u64 sleep_status;
ACPI_FUNCTION_TRACE(hw_extended_sleep);
@ -125,18 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
acpi_gbl_system_awake_and_running = FALSE;
/* Flush caches, as per ACPI specification */
ACPI_FLUSH_CPU_CACHE();
status = acpi_os_prepare_extended_sleep(sleep_state,
acpi_gbl_sleep_type_a,
acpi_gbl_sleep_type_b);
if (ACPI_SKIP(status))
return_ACPI_STATUS(AE_OK);
if (ACPI_FAILURE(status))
return_ACPI_STATUS(status);
/*
* Set the SLP_TYP and SLP_EN bits.
*
@ -146,12 +133,22 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state)
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
"Entering sleep state [S%u]\n", sleep_state));
sleep_type_value =
((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
ACPI_X_SLEEP_TYPE_MASK);
sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) &
ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE;
status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE),
&acpi_gbl_FADT.sleep_control);
/* Flush caches, as per ACPI specification */
ACPI_FLUSH_CPU_CACHE();
status = acpi_os_enter_sleep(sleep_state, sleep_control, 0);
if (status == AE_CTRL_TERMINATE) {
return_ACPI_STATUS(AE_OK);
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}

View file

@ -52,7 +52,8 @@ ACPI_MODULE_NAME("hwregs")
#if (!ACPI_REDUCED_HARDWARE)
/* Local Prototypes */
static u8
acpi_hw_get_access_bit_width(struct acpi_generic_address *reg,
acpi_hw_get_access_bit_width(u64 address,
struct acpi_generic_address *reg,
u8 max_bit_width);
static acpi_status
@ -71,7 +72,8 @@ acpi_hw_write_multiple(u32 value,
*
* FUNCTION: acpi_hw_get_access_bit_width
*
* PARAMETERS: reg - GAS register structure
* PARAMETERS: address - GAS register address
* reg - GAS register structure
* max_bit_width - Max bit_width supported (32 or 64)
*
* RETURN: Status
@ -81,27 +83,59 @@ acpi_hw_write_multiple(u32 value,
******************************************************************************/
static u8
acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, u8 max_bit_width)
acpi_hw_get_access_bit_width(u64 address,
struct acpi_generic_address *reg, u8 max_bit_width)
{
if (!reg->access_width) {
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
max_bit_width = 32;
}
u8 access_bit_width;
/*
* Detect old register descriptors where only the bit_width field
* makes senses.
*/
if (reg->bit_width < max_bit_width &&
!reg->bit_offset && reg->bit_width &&
ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
ACPI_IS_ALIGNED(reg->bit_width, 8)) {
return (reg->bit_width);
}
return (max_bit_width);
/*
* GAS format "register", used by FADT:
* 1. Detected if bit_offset is 0 and bit_width is 8/16/32/64;
* 2. access_size field is ignored and bit_width field is used for
* determining the boundary of the IO accesses.
* GAS format "region", used by APEI registers:
* 1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64;
* 2. access_size field is used for determining the boundary of the
* IO accesses;
* 3. bit_offset/bit_width fields are used to describe the "region".
*
* Note: This algorithm assumes that the "Address" fields should always
* contain aligned values.
*/
if (!reg->bit_offset && reg->bit_width &&
ACPI_IS_POWER_OF_TWO(reg->bit_width) &&
ACPI_IS_ALIGNED(reg->bit_width, 8)) {
access_bit_width = reg->bit_width;
} else if (reg->access_width) {
access_bit_width = (1 << (reg->access_width + 2));
} else {
return (1 << (reg->access_width + 2));
access_bit_width =
ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset +
reg->bit_width);
if (access_bit_width <= 8) {
access_bit_width = 8;
} else {
while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) {
access_bit_width >>= 1;
}
}
}
/* Maximum IO port access bit width is 32 */
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
max_bit_width = 32;
}
/*
* Return access width according to the requested maximum access bit width,
* as the caller should know the format of the register and may enforce
* a 32-bit accesses.
*/
if (access_bit_width < max_bit_width) {
return (access_bit_width);
}
return (max_bit_width);
}
/******************************************************************************
@ -163,7 +197,8 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
/* Validate the bit_width, convert access_width into number of bits */
access_width = acpi_hw_get_access_bit_width(reg, max_bit_width);
access_width =
acpi_hw_get_access_bit_width(*address, reg, max_bit_width);
bit_width =
ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width);
if (max_bit_width < bit_width) {
@ -219,7 +254,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
* into number of bits based
*/
*value = 0;
access_width = acpi_hw_get_access_bit_width(reg, 32);
access_width = acpi_hw_get_access_bit_width(address, reg, 32);
bit_width = reg->bit_offset + reg->bit_width;
bit_offset = reg->bit_offset;
@ -252,20 +287,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
&value32,
access_width);
}
/*
* Use offset style bit masks because:
* bit_offset < access_width/bit_width < access_width, and
* access_width is ensured to be less than 32-bits by
* acpi_hw_validate_register().
*/
if (bit_offset) {
value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
bit_offset = 0;
}
if (bit_width < access_width) {
value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
}
}
/*
@ -306,6 +327,12 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
{
u64 address;
u8 access_width;
u32 bit_width;
u8 bit_offset;
u64 value64;
u32 value32;
u8 index;
acpi_status status;
ACPI_FUNCTION_NAME(hw_write);
@ -317,23 +344,61 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
return (status);
}
/* Convert access_width into number of bits based */
access_width = acpi_hw_get_access_bit_width(address, reg, 32);
bit_width = reg->bit_offset + reg->bit_width;
bit_offset = reg->bit_offset;
/*
* Two address spaces supported: Memory or IO. PCI_Config is
* not supported here because the GAS structure is insufficient
*/
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
status = acpi_os_write_memory((acpi_physical_address)
address, (u64)value,
reg->bit_width);
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
index = 0;
while (bit_width) {
/*
* Use offset style bit reads because "Index * AccessWidth" is
* ensured to be less than 32-bits by acpi_hw_validate_register().
*/
value32 = ACPI_GET_BITS(&value, index * access_width,
ACPI_MASK_BITS_ABOVE_32(access_width));
status = acpi_hw_write_port((acpi_io_address)
address, value, reg->bit_width);
if (bit_offset >= access_width) {
bit_offset -= access_width;
} else {
if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
value64 = (u64)value32;
status =
acpi_os_write_memory((acpi_physical_address)
address +
index *
ACPI_DIV_8
(access_width),
value64, access_width);
} else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
status = acpi_hw_write_port((acpi_io_address)
address +
index *
ACPI_DIV_8
(access_width),
value32,
access_width);
}
}
/*
* Index * access_width is ensured to be less than 32-bits by
* acpi_hw_validate_register().
*/
bit_width -=
bit_width > access_width ? access_width : bit_width;
index++;
}
ACPI_DEBUG_PRINT((ACPI_DB_IO,
"Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
value, reg->bit_width, ACPI_FORMAT_UINT64(address),
value, access_width, ACPI_FORMAT_UINT64(address),
acpi_ut_get_region_name(reg->space_id)));
return (status);

View file

@ -43,7 +43,6 @@
*/
#include <acpi/acpi.h>
#include <linux/acpi.h>
#include "accommon.h"
#define _COMPONENT ACPI_HARDWARE
@ -152,12 +151,14 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
ACPI_FLUSH_CPU_CACHE();
status = acpi_os_prepare_sleep(sleep_state, pm1a_control,
pm1b_control);
if (ACPI_SKIP(status))
status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control);
if (status == AE_CTRL_TERMINATE) {
return_ACPI_STATUS(AE_OK);
if (ACPI_FAILURE(status))
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Write #2: Write both SLP_TYP + SLP_EN */
status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control);

View file

@ -269,23 +269,27 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state,
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
if (walk_state->opcode == AML_UNLOAD_OP) {
if ((GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
ARGP_SUPERNAME)
|| (GET_CURRENT_ARG_TYPE(walk_state->arg_types) ==
ARGP_TARGET)) {
/*
* acpi_ps_get_next_namestring has increased the AML pointer,
* so we need to restore the saved AML pointer for method call.
* acpi_ps_get_next_namestring has increased the AML pointer past
* the method invocation namestring, so we need to restore the
* saved AML pointer back to the original method invocation
* namestring.
*/
walk_state->parser_state.aml = start;
walk_state->arg_count = 1;
acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
return_ACPI_STATUS(AE_OK);
}
/* This name is actually a control method invocation */
method_desc = acpi_ns_get_attached_object(node);
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"Control Method - %p Desc %p Path=%p\n", node,
method_desc, path));
"Control Method invocation %4.4s - %p Desc %p Path=%p\n",
node->name.ascii, node, method_desc, path));
name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start);
if (!name_op) {
@ -719,6 +723,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state);
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"Expected argument type ARGP: %s (%2.2X)\n",
acpi_ut_get_argument_type_name(arg_type), arg_type));
switch (arg_type) {
case ARGP_BYTEDATA:
case ARGP_WORDDATA:
@ -796,11 +804,14 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
}
break;
case ARGP_TARGET:
case ARGP_SUPERNAME:
case ARGP_SIMPLENAME:
case ARGP_NAME_OR_REF:
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** SimpleName/NameOrRef: %s (%2.2X)\n",
acpi_ut_get_argument_type_name(arg_type),
arg_type));
subop = acpi_ps_peek_opcode(parser_state);
if (subop == 0 ||
acpi_ps_is_leading_char(subop) ||
@ -816,28 +827,49 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* To support super_name arg of Unload */
status =
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_NOT_METHOD_CALL);
} else {
/* Single complex argument, nothing returned */
if (walk_state->opcode == AML_UNLOAD_OP) {
status =
acpi_ps_get_next_namepath(walk_state,
parser_state, arg,
ACPI_POSSIBLE_METHOD_CALL);
walk_state->arg_count = 1;
}
break;
/*
* If the super_name argument is a method call, we have
* already restored the AML pointer, just free this Arg
*/
if (arg->common.aml_opcode ==
AML_INT_METHODCALL_OP) {
acpi_ps_free_op(arg);
arg = NULL;
}
} else {
status =
acpi_ps_get_next_namepath(walk_state,
parser_state, arg,
ACPI_NOT_METHOD_CALL);
case ARGP_TARGET:
case ARGP_SUPERNAME:
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** Target/Supername: %s (%2.2X)\n",
acpi_ut_get_argument_type_name(arg_type),
arg_type));
subop = acpi_ps_peek_opcode(parser_state);
if (subop == 0 ||
acpi_ps_is_leading_char(subop) ||
ACPI_IS_ROOT_PREFIX(subop) ||
ACPI_IS_PARENT_PREFIX(subop)) {
/* NULL target (zero). Convert to a NULL namepath */
arg =
acpi_ps_alloc_op(AML_INT_NAMEPATH_OP,
parser_state->aml);
if (!arg) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
status =
acpi_ps_get_next_namepath(walk_state, parser_state,
arg,
ACPI_POSSIBLE_METHOD_CALL);
if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) {
acpi_ps_free_op(arg);
arg = NULL;
walk_state->arg_count = 1;
}
} else {
/* Single complex argument, nothing returned */
@ -849,6 +881,11 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state,
case ARGP_DATAOBJ:
case ARGP_TERMARG:
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"**** TermArg/DataObj: %s (%2.2X)\n",
acpi_ut_get_argument_type_name(arg_type),
arg_type));
/* Single complex argument, nothing returned */
walk_state->arg_count = 1;

View file

@ -92,6 +92,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
"Get arguments for opcode [%s]\n",
op->common.aml_op_name));
switch (op->common.aml_opcode) {
case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
case AML_WORD_OP: /* AML_WORDDATA_ARG */

View file

@ -348,7 +348,15 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state,
argument_count) {
op->common.flags |= ACPI_PARSEOP_TARGET;
}
} else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
}
/*
* Special case for both Increment() and Decrement(), where
* the lone argument is both a source and a target.
*/
else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP)
|| (parent_scope->common.aml_opcode ==
AML_DECREMENT_OP)) {
op->common.flags |= ACPI_PARSEOP_TARGET;
}
}

View file

@ -129,10 +129,10 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
union acpi_parse_object *prev_arg;
const struct acpi_opcode_info *op_info;
ACPI_FUNCTION_ENTRY();
ACPI_FUNCTION_TRACE(ps_append_arg);
if (!op) {
return;
return_VOID;
}
/* Get the info structure for this opcode */
@ -144,7 +144,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X",
op->common.aml_opcode));
return;
return_VOID;
}
/* Check if this opcode requires argument sub-objects */
@ -153,7 +153,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
/* Has no linked argument objects */
return;
return_VOID;
}
/* Append the argument to the linked argument list */
@ -181,6 +181,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg)
op->common.arg_list_length++;
}
return_VOID;
}
/*******************************************************************************

View file

@ -238,7 +238,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
if (!obj_desc) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n"));
return_PTR("[NULL Object Descriptor]");
return_STR("[NULL Object Descriptor]");
}
/* These descriptor types share a common area */
@ -251,7 +251,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc)
acpi_ut_get_descriptor_name(obj_desc),
obj_desc));
return_PTR("Invalid object");
return_STR("Invalid object");
}
return_STR(acpi_ut_get_type_name(obj_desc->common.type));

View file

@ -421,8 +421,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
}
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"Obj %p Type %.2X Refs %.2X [Incremented]\n",
object, object->common.type, new_count));
"Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n",
object, object->common.type,
acpi_ut_get_object_type_name(object),
new_count));
break;
case REF_DECREMENT:

View file

@ -421,8 +421,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
/* The absolute minimum resource template is one end_tag descriptor */
/*
* The absolute minimum resource template is one end_tag descriptor.
* However, we will treat a lone end_tag as just a simple buffer.
*/
if (aml_length < sizeof(struct aml_resource_end_tag)) {
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
}
@ -454,9 +456,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
/* Invoke the user function */
if (user_function) {
status =
user_function(aml, length, offset, resource_index,
context);
status = user_function(aml, length, offset,
resource_index, context);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@ -480,6 +481,12 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
*context = aml;
}
/* Check if buffer is defined to be longer than the resource length */
if (aml_length > (offset + length)) {
return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
}
/* Normal exit */
return_ACPI_STATUS(AE_OK);

View file

@ -852,6 +852,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
if (ghes_read_estatus(ghes, 1)) {
ghes_clear_estatus(ghes);
continue;
} else {
ret = NMI_HANDLED;
}
sev = ghes_severity(ghes->estatus->error_severity);
@ -863,12 +865,11 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
__process_error(ghes);
ghes_clear_estatus(ghes);
ret = NMI_HANDLED;
}
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
irq_work_queue(&ghes_proc_irq_work);
if (ret == NMI_HANDLED)
irq_work_queue(&ghes_proc_irq_work);
#endif
atomic_dec(&ghes_in_nmi);
return ret;

View file

@ -123,7 +123,13 @@ EXPORT_SYMBOL_GPL(apei_hest_parse);
*/
static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data)
{
return arch_apei_enable_cmcff(hest_hdr, data);
if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
return 0;
if (!acpi_disable_cmcff)
return !arch_apei_enable_cmcff(hest_hdr, data);
return 0;
}
struct ghes_arr {
@ -232,8 +238,9 @@ void __init acpi_hest_init(void)
goto err;
}
if (!acpi_disable_cmcff)
apei_hest_parse(hest_parse_cmc, NULL);
rc = apei_hest_parse(hest_parse_cmc, NULL);
if (rc)
goto err;
if (!ghes_disable) {
rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count);

View file

@ -19,8 +19,17 @@
#define pr_fmt(fmt) "ACPI: IORT: " fmt
#include <linux/acpi_iort.h>
#include <linux/iommu.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define IORT_TYPE_MASK(type) (1 << (type))
#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP)
#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \
(1 << ACPI_IORT_NODE_SMMU_V3))
struct iort_its_msi_chip {
struct list_head list;
@ -28,6 +37,90 @@ struct iort_its_msi_chip {
u32 translation_id;
};
struct iort_fwnode {
struct list_head list;
struct acpi_iort_node *iort_node;
struct fwnode_handle *fwnode;
};
static LIST_HEAD(iort_fwnode_list);
static DEFINE_SPINLOCK(iort_fwnode_lock);
/**
* iort_set_fwnode() - Create iort_fwnode and use it to register
* iommu data in the iort_fwnode_list
*
* @node: IORT table node associated with the IOMMU
* @fwnode: fwnode associated with the IORT node
*
* Returns: 0 on success
* <0 on failure
*/
static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode)
{
struct iort_fwnode *np;
np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
if (WARN_ON(!np))
return -ENOMEM;
INIT_LIST_HEAD(&np->list);
np->iort_node = iort_node;
np->fwnode = fwnode;
spin_lock(&iort_fwnode_lock);
list_add_tail(&np->list, &iort_fwnode_list);
spin_unlock(&iort_fwnode_lock);
return 0;
}
/**
* iort_get_fwnode() - Retrieve fwnode associated with an IORT node
*
* @node: IORT table node to be looked-up
*
* Returns: fwnode_handle pointer on success, NULL on failure
*/
static inline
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
{
struct iort_fwnode *curr;
struct fwnode_handle *fwnode = NULL;
spin_lock(&iort_fwnode_lock);
list_for_each_entry(curr, &iort_fwnode_list, list) {
if (curr->iort_node == node) {
fwnode = curr->fwnode;
break;
}
}
spin_unlock(&iort_fwnode_lock);
return fwnode;
}
/**
* iort_delete_fwnode() - Delete fwnode associated with an IORT node
*
* @node: IORT table node associated with fwnode to delete
*/
static inline void iort_delete_fwnode(struct acpi_iort_node *node)
{
struct iort_fwnode *curr, *tmp;
spin_lock(&iort_fwnode_lock);
list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) {
if (curr->iort_node == node) {
list_del(&curr->list);
kfree(curr);
break;
}
}
spin_unlock(&iort_fwnode_lock);
}
typedef acpi_status (*iort_find_node_callback)
(struct acpi_iort_node *node, void *context);
@ -141,6 +234,21 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type,
return NULL;
}
static acpi_status
iort_match_type_callback(struct acpi_iort_node *node, void *context)
{
return AE_OK;
}
bool iort_node_match(u8 type)
{
struct acpi_iort_node *node;
node = iort_scan_node(type, iort_match_type_callback, NULL);
return node != NULL;
}
static acpi_status iort_match_node_callback(struct acpi_iort_node *node,
void *context)
{
@ -212,9 +320,48 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in,
return 0;
}
static
struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node,
u32 *id_out, u8 type_mask,
int index)
{
struct acpi_iort_node *parent;
struct acpi_iort_id_mapping *map;
if (!node->mapping_offset || !node->mapping_count ||
index >= node->mapping_count)
return NULL;
map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node,
node->mapping_offset);
/* Firmware bug! */
if (!map->output_reference) {
pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n",
node, node->type);
return NULL;
}
parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table,
map->output_reference);
if (!(IORT_TYPE_MASK(parent->type) & type_mask))
return NULL;
if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) {
if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT ||
node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) {
*id_out = map[index].output_base;
return parent;
}
}
return NULL;
}
static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
u32 rid_in, u32 *rid_out,
u8 type)
u8 type_mask)
{
u32 rid = rid_in;
@ -223,7 +370,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node,
struct acpi_iort_id_mapping *map;
int i;
if (node->type == type) {
if (IORT_TYPE_MASK(node->type) & type_mask) {
if (rid_out)
*rid_out = rid;
return node;
@ -296,7 +443,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id)
if (!node)
return req_id;
iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP);
iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE);
return dev_id;
}
@ -318,7 +465,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id,
if (!node)
return -ENXIO;
node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP);
node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE);
if (!node)
return -ENXIO;
@ -356,13 +503,459 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id)
return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI);
}
static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
{
u32 *rid = data;
*rid = alias;
return 0;
}
static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
struct fwnode_handle *fwnode,
const struct iommu_ops *ops)
{
int ret = iommu_fwspec_init(dev, fwnode, ops);
if (!ret)
ret = iommu_fwspec_add_ids(dev, &streamid, 1);
return ret;
}
static const struct iommu_ops *iort_iommu_xlate(struct device *dev,
struct acpi_iort_node *node,
u32 streamid)
{
const struct iommu_ops *ops = NULL;
int ret = -ENODEV;
struct fwnode_handle *iort_fwnode;
if (node) {
iort_fwnode = iort_get_fwnode(node);
if (!iort_fwnode)
return NULL;
ops = iommu_get_instance(iort_fwnode);
if (!ops)
return NULL;
ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops);
}
return ret ? NULL : ops;
}
/**
* iort_set_dma_mask - Set-up dma mask for a device.
*
* @dev: device to configure
*/
void iort_set_dma_mask(struct device *dev)
{
/*
* Set default coherent_dma_mask to 32 bit. Drivers are expected to
* setup the correct supported mask.
*/
if (!dev->coherent_dma_mask)
dev->coherent_dma_mask = DMA_BIT_MASK(32);
/*
* Set it to coherent_dma_mask by default if the architecture
* code has not set it.
*/
if (!dev->dma_mask)
dev->dma_mask = &dev->coherent_dma_mask;
}
/**
* iort_iommu_configure - Set-up IOMMU configuration for a device.
*
* @dev: device to configure
*
* Returns: iommu_ops pointer on configuration success
* NULL on configuration failure
*/
const struct iommu_ops *iort_iommu_configure(struct device *dev)
{
struct acpi_iort_node *node, *parent;
const struct iommu_ops *ops = NULL;
u32 streamid = 0;
if (dev_is_pci(dev)) {
struct pci_bus *bus = to_pci_dev(dev)->bus;
u32 rid;
pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid,
&rid);
node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX,
iort_match_node_callback, &bus->dev);
if (!node)
return NULL;
parent = iort_node_map_rid(node, rid, &streamid,
IORT_IOMMU_TYPE);
ops = iort_iommu_xlate(dev, parent, streamid);
} else {
int i = 0;
node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT,
iort_match_node_callback, dev);
if (!node)
return NULL;
parent = iort_node_get_id(node, &streamid,
IORT_IOMMU_TYPE, i++);
while (parent) {
ops = iort_iommu_xlate(dev, parent, streamid);
parent = iort_node_get_id(node, &streamid,
IORT_IOMMU_TYPE, i++);
}
}
return ops;
}
static void __init acpi_iort_register_irq(int hwirq, const char *name,
int trigger,
struct resource *res)
{
int irq = acpi_register_gsi(NULL, hwirq, trigger,
ACPI_ACTIVE_HIGH);
if (irq <= 0) {
pr_err("could not register gsi hwirq %d name [%s]\n", hwirq,
name);
return;
}
res->start = irq;
res->end = irq;
res->flags = IORESOURCE_IRQ;
res->name = name;
}
static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node)
{
struct acpi_iort_smmu_v3 *smmu;
/* Always present mem resource */
int num_res = 1;
/* Retrieve SMMUv3 specific data */
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
if (smmu->event_gsiv)
num_res++;
if (smmu->pri_gsiv)
num_res++;
if (smmu->gerr_gsiv)
num_res++;
if (smmu->sync_gsiv)
num_res++;
return num_res;
}
static void __init arm_smmu_v3_init_resources(struct resource *res,
struct acpi_iort_node *node)
{
struct acpi_iort_smmu_v3 *smmu;
int num_res = 0;
/* Retrieve SMMUv3 specific data */
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
res[num_res].start = smmu->base_address;
res[num_res].end = smmu->base_address + SZ_128K - 1;
res[num_res].flags = IORESOURCE_MEM;
num_res++;
if (smmu->event_gsiv)
acpi_iort_register_irq(smmu->event_gsiv, "eventq",
ACPI_EDGE_SENSITIVE,
&res[num_res++]);
if (smmu->pri_gsiv)
acpi_iort_register_irq(smmu->pri_gsiv, "priq",
ACPI_EDGE_SENSITIVE,
&res[num_res++]);
if (smmu->gerr_gsiv)
acpi_iort_register_irq(smmu->gerr_gsiv, "gerror",
ACPI_EDGE_SENSITIVE,
&res[num_res++]);
if (smmu->sync_gsiv)
acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync",
ACPI_EDGE_SENSITIVE,
&res[num_res++]);
}
static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node)
{
struct acpi_iort_smmu_v3 *smmu;
/* Retrieve SMMUv3 specific data */
smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE;
}
static int __init arm_smmu_count_resources(struct acpi_iort_node *node)
{
struct acpi_iort_smmu *smmu;
/* Retrieve SMMU specific data */
smmu = (struct acpi_iort_smmu *)node->node_data;
/*
* Only consider the global fault interrupt and ignore the
* configuration access interrupt.
*
* MMIO address and global fault interrupt resources are always
* present so add them to the context interrupt count as a static
* value.
*/
return smmu->context_interrupt_count + 2;
}
static void __init arm_smmu_init_resources(struct resource *res,
struct acpi_iort_node *node)
{
struct acpi_iort_smmu *smmu;
int i, hw_irq, trigger, num_res = 0;
u64 *ctx_irq, *glb_irq;
/* Retrieve SMMU specific data */
smmu = (struct acpi_iort_smmu *)node->node_data;
res[num_res].start = smmu->base_address;
res[num_res].end = smmu->base_address + smmu->span - 1;
res[num_res].flags = IORESOURCE_MEM;
num_res++;
glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset);
/* Global IRQs */
hw_irq = IORT_IRQ_MASK(glb_irq[0]);
trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]);
acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger,
&res[num_res++]);
/* Context IRQs */
ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset);
for (i = 0; i < smmu->context_interrupt_count; i++) {
hw_irq = IORT_IRQ_MASK(ctx_irq[i]);
trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]);
acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger,
&res[num_res++]);
}
}
static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node)
{
struct acpi_iort_smmu *smmu;
/* Retrieve SMMU specific data */
smmu = (struct acpi_iort_smmu *)node->node_data;
return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK;
}
struct iort_iommu_config {
const char *name;
int (*iommu_init)(struct acpi_iort_node *node);
bool (*iommu_is_coherent)(struct acpi_iort_node *node);
int (*iommu_count_resources)(struct acpi_iort_node *node);
void (*iommu_init_resources)(struct resource *res,
struct acpi_iort_node *node);
};
static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = {
.name = "arm-smmu-v3",
.iommu_is_coherent = arm_smmu_v3_is_coherent,
.iommu_count_resources = arm_smmu_v3_count_resources,
.iommu_init_resources = arm_smmu_v3_init_resources
};
static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = {
.name = "arm-smmu",
.iommu_is_coherent = arm_smmu_is_coherent,
.iommu_count_resources = arm_smmu_count_resources,
.iommu_init_resources = arm_smmu_init_resources
};
static __init
const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node)
{
switch (node->type) {
case ACPI_IORT_NODE_SMMU_V3:
return &iort_arm_smmu_v3_cfg;
case ACPI_IORT_NODE_SMMU:
return &iort_arm_smmu_cfg;
default:
return NULL;
}
}
/**
* iort_add_smmu_platform_device() - Allocate a platform device for SMMU
* @node: Pointer to SMMU ACPI IORT node
*
* Returns: 0 on success, <0 failure
*/
static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node)
{
struct fwnode_handle *fwnode;
struct platform_device *pdev;
struct resource *r;
enum dev_dma_attr attr;
int ret, count;
const struct iort_iommu_config *ops = iort_get_iommu_cfg(node);
if (!ops)
return -ENODEV;
pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO);
if (!pdev)
return PTR_ERR(pdev);
count = ops->iommu_count_resources(node);
r = kcalloc(count, sizeof(*r), GFP_KERNEL);
if (!r) {
ret = -ENOMEM;
goto dev_put;
}
ops->iommu_init_resources(r, node);
ret = platform_device_add_resources(pdev, r, count);
/*
* Resources are duplicated in platform_device_add_resources,
* free their allocated memory
*/
kfree(r);
if (ret)
goto dev_put;
/*
* Add a copy of IORT node pointer to platform_data to
* be used to retrieve IORT data information.
*/
ret = platform_device_add_data(pdev, &node, sizeof(node));
if (ret)
goto dev_put;
/*
* We expect the dma masks to be equivalent for
* all SMMUs set-ups
*/
pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
fwnode = iort_get_fwnode(node);
if (!fwnode) {
ret = -ENODEV;
goto dev_put;
}
pdev->dev.fwnode = fwnode;
attr = ops->iommu_is_coherent(node) ?
DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT;
/* Configure DMA for the page table walker */
acpi_dma_configure(&pdev->dev, attr);
ret = platform_device_add(pdev);
if (ret)
goto dma_deconfigure;
return 0;
dma_deconfigure:
acpi_dma_deconfigure(&pdev->dev);
dev_put:
platform_device_put(pdev);
return ret;
}
static void __init iort_init_platform_devices(void)
{
struct acpi_iort_node *iort_node, *iort_end;
struct acpi_table_iort *iort;
struct fwnode_handle *fwnode;
int i, ret;
/*
* iort_table and iort both point to the start of IORT table, but
* have different struct types
*/
iort = (struct acpi_table_iort *)iort_table;
/* Get the first IORT node */
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort,
iort->node_offset);
iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort,
iort_table->length);
for (i = 0; i < iort->node_count; i++) {
if (iort_node >= iort_end) {
pr_err("iort node pointer overflows, bad table\n");
return;
}
if ((iort_node->type == ACPI_IORT_NODE_SMMU) ||
(iort_node->type == ACPI_IORT_NODE_SMMU_V3)) {
fwnode = acpi_alloc_fwnode_static();
if (!fwnode)
return;
iort_set_fwnode(iort_node, fwnode);
ret = iort_add_smmu_platform_device(iort_node);
if (ret) {
iort_delete_fwnode(iort_node);
acpi_free_fwnode_static(fwnode);
return;
}
}
iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node,
iort_node->length);
}
}
void __init acpi_iort_init(void)
{
acpi_status status;
status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
const char *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) {
const char *msg = acpi_format_exception(status);
pr_err("Failed to get table, %s\n", msg);
}
return;
}
iort_init_platform_devices();
acpi_probe_device_table(iort);
}

View file

@ -36,7 +36,7 @@
#ifdef CONFIG_ACPI_PROCFS_POWER
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#endif
#include <linux/acpi.h>
@ -430,39 +430,24 @@ static int acpi_battery_get_status(struct acpi_battery *battery)
return 0;
}
static int acpi_battery_get_info(struct acpi_battery *battery)
static int extract_battery_info(const int use_bix,
struct acpi_battery *battery,
const struct acpi_buffer *buffer)
{
int result = -EFAULT;
acpi_status status = 0;
char *name = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags) ?
"_BIX" : "_BIF";
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
if (!acpi_battery_present(battery))
return 0;
mutex_lock(&battery->lock);
status = acpi_evaluate_object(battery->device->handle, name,
NULL, &buffer);
mutex_unlock(&battery->lock);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name));
return -ENODEV;
}
if (battery_bix_broken_package)
result = extract_package(battery, buffer.pointer,
if (use_bix && battery_bix_broken_package)
result = extract_package(battery, buffer->pointer,
extended_info_offsets + 1,
ARRAY_SIZE(extended_info_offsets) - 1);
else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags))
result = extract_package(battery, buffer.pointer,
else if (use_bix)
result = extract_package(battery, buffer->pointer,
extended_info_offsets,
ARRAY_SIZE(extended_info_offsets));
else
result = extract_package(battery, buffer.pointer,
result = extract_package(battery, buffer->pointer,
info_offsets, ARRAY_SIZE(info_offsets));
kfree(buffer.pointer);
if (test_bit(ACPI_BATTERY_QUIRK_PERCENTAGE_CAPACITY, &battery->flags))
battery->full_charge_capacity = battery->design_capacity;
if (test_bit(ACPI_BATTERY_QUIRK_THINKPAD_MAH, &battery->flags) &&
@ -483,6 +468,45 @@ static int acpi_battery_get_info(struct acpi_battery *battery)
return result;
}
static int acpi_battery_get_info(struct acpi_battery *battery)
{
const int xinfo = test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
int use_bix;
int result = -ENODEV;
if (!acpi_battery_present(battery))
return 0;
for (use_bix = xinfo ? 1 : 0; use_bix >= 0; use_bix--) {
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
acpi_status status = AE_ERROR;
mutex_lock(&battery->lock);
status = acpi_evaluate_object(battery->device->handle,
use_bix ? "_BIX":"_BIF",
NULL, &buffer);
mutex_unlock(&battery->lock);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s",
use_bix ? "_BIX":"_BIF"));
} else {
result = extract_battery_info(use_bix,
battery,
&buffer);
kfree(buffer.pointer);
break;
}
}
if (!result && !use_bix && xinfo)
pr_warn(FW_BUG "The _BIX method is broken, using _BIF.\n");
return result;
}
static int acpi_battery_get_state(struct acpi_battery *battery)
{
int result = 0;

View file

@ -160,6 +160,34 @@ static struct dmi_system_id acpi_rev_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "XPS 13 9343"),
},
},
{
.callback = dmi_enable_rev_override,
.ident = "DELL Precision 5520",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Precision 5520"),
},
},
{
.callback = dmi_enable_rev_override,
.ident = "DELL Precision 3520",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3520"),
},
},
/*
* Resolves a quirk with the Dell Latitude 3350 that
* causes the ethernet adapter to not function.
*/
{
.callback = dmi_enable_rev_override,
.ident = "DELL Latitude 3350",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude 3350"),
},
},
#endif
{}
};

View file

@ -331,6 +331,16 @@ 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_X86
if (boot_cpu_has(X86_FEATURE_HWP)) {
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_CPC_SUPPORT;
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_CPCV2_SUPPORT;
}
#endif
if (IS_ENABLED(CONFIG_SCHED_MC_PRIO))
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_CPC_DIVERSE_HIGH_SUPPORT;
if (!ghes_disable)
capbuf[OSC_SUPPORT_DWORD] |= OSC_SB_APEI_SUPPORT;
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))

View file

@ -776,21 +776,25 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
init_waitqueue_head(&pcc_data.pcc_write_wait_q);
}
/* Plug PSD data into this CPUs CPC descriptor. */
per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
/* Everything looks okay */
pr_debug("Parsed CPC struct for CPU: %d\n", pr->id);
/* Add per logical CPU nodes for reading its feedback counters. */
cpu_dev = get_cpu_device(pr->id);
if (!cpu_dev)
if (!cpu_dev) {
ret = -EINVAL;
goto out_free;
}
/* Plug PSD data into this CPUs CPC descriptor. */
per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj,
"acpi_cppc");
if (ret)
if (ret) {
per_cpu(cpc_desc_ptr, pr->id) = NULL;
goto out_free;
}
kfree(output.pointer);
return 0;
@ -824,6 +828,8 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
void __iomem *addr;
cpc_ptr = per_cpu(cpc_desc_ptr, pr->id);
if (!cpc_ptr)
return;
/* Free all the mapped sys mem areas for this CPU */
for (i = 2; i < cpc_ptr->num_entries; i++) {

View file

@ -52,7 +52,7 @@ struct acpi_data_node_attr {
static ssize_t data_node_show_path(struct acpi_data_node *dn, char *buf)
{
return acpi_object_path(dn->handle, buf);
return dn->handle ? acpi_object_path(dn->handle, buf) : 0;
}
DATA_NODE_ATTR(path);
@ -105,10 +105,10 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
init_completion(&dn->kobj_done);
ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
kobj, "%s", dn->name);
if (ret)
acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
else
if (!ret)
acpi_expose_nondev_subnodes(&dn->kobj, &dn->data);
else if (dn->handle)
acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
}
}

View file

@ -82,8 +82,8 @@ static const struct genl_multicast_group acpi_event_mcgrps[] = {
{ .name = ACPI_GENL_MCAST_GROUP_NAME, },
};
static struct genl_family acpi_event_genl_family = {
.id = GENL_ID_GENERATE,
static struct genl_family acpi_event_genl_family __ro_after_init = {
.module = THIS_MODULE,
.name = ACPI_GENL_FAMILY_NAME,
.version = ACPI_GENL_VERSION,
.maxattr = ACPI_GENL_ATTR_MAX,
@ -144,7 +144,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
static int acpi_event_genetlink_init(void)
static int __init acpi_event_genetlink_init(void)
{
return genl_register_family(&acpi_event_genl_family);
}

View file

@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
attr = acpi_get_dma_attr(acpi_dev);
if (attr != DEV_DMA_NOT_SUPPORTED)
arch_setup_dma_ops(dev, 0, 0, NULL,
attr == DEV_DMA_COHERENT);
acpi_dma_configure(dev, attr);
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
return 0;
err:
acpi_dma_deconfigure(dev);
ACPI_COMPANION_SET(dev, NULL);
put_device(dev);
put_device(&acpi_dev->dev);

View file

@ -94,7 +94,7 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
return to_acpi_device(acpi_desc->dev);
}
static int xlat_status(void *buf, unsigned int cmd, u32 status)
static int xlat_bus_status(void *buf, unsigned int cmd, u32 status)
{
struct nd_cmd_clear_error *clear_err;
struct nd_cmd_ars_status *ars_status;
@ -113,7 +113,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
if ((status >> 16 & flags) == 0)
return -ENOTTY;
break;
return 0;
case ND_CMD_ARS_START:
/* ARS is in progress */
if ((status & 0xffff) == NFIT_ARS_START_BUSY)
@ -122,7 +122,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
/* Command failed */
if (status & 0xffff)
return -EIO;
break;
return 0;
case ND_CMD_ARS_STATUS:
ars_status = buf;
/* Command failed */
@ -146,7 +146,8 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
* then just continue with the returned results.
*/
if (status == NFIT_ARS_STATUS_INTR) {
if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
if (ars_status->out_length >= 40 && (ars_status->flags
& NFIT_ARS_F_OVERFLOW))
return -ENOSPC;
return 0;
}
@ -154,7 +155,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
/* Unknown status */
if (status >> 16)
return -EIO;
break;
return 0;
case ND_CMD_CLEAR_ERROR:
clear_err = buf;
if (status & 0xffff)
@ -163,7 +164,7 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
return -EIO;
if (clear_err->length > clear_err->cleared)
return clear_err->cleared;
break;
return 0;
default:
break;
}
@ -174,9 +175,18 @@ static int xlat_status(void *buf, unsigned int cmd, u32 status)
return 0;
}
static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
unsigned int buf_len, int *cmd_rc)
static int xlat_status(struct nvdimm *nvdimm, void *buf, unsigned int cmd,
u32 status)
{
if (!nvdimm)
return xlat_bus_status(buf, cmd, status);
if (status)
return -EIO;
return 0;
}
int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc)
{
struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc);
union acpi_object in_obj, in_buf, *out_obj;
@ -298,7 +308,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
for (i = 0, offset = 0; i < desc->out_num; i++) {
u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
(u32 *) out_obj->buffer.pointer);
(u32 *) out_obj->buffer.pointer,
out_obj->buffer.length - offset);
if (offset + out_size > out_obj->buffer.length) {
dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
@ -333,7 +344,8 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
*/
rc = buf_len - offset - in_buf.buffer.length;
if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd, fw_status);
*cmd_rc = xlat_status(nvdimm, buf, cmd,
fw_status);
} else {
dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
__func__, dimm_name, cmd_name, buf_len,
@ -343,7 +355,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
} else {
rc = 0;
if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd, fw_status);
*cmd_rc = xlat_status(nvdimm, buf, cmd, fw_status);
}
out:
@ -351,6 +363,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
return rc;
}
EXPORT_SYMBOL_GPL(acpi_nfit_ctl);
static const char *spa_type_name(u16 type)
{
@ -2001,19 +2014,32 @@ static int ars_get_status(struct acpi_nfit_desc *acpi_desc)
return cmd_rc;
}
static int ars_status_process_records(struct nvdimm_bus *nvdimm_bus,
static int ars_status_process_records(struct acpi_nfit_desc *acpi_desc,
struct nd_cmd_ars_status *ars_status)
{
struct nvdimm_bus *nvdimm_bus = acpi_desc->nvdimm_bus;
int rc;
u32 i;
/*
* First record starts at 44 byte offset from the start of the
* payload.
*/
if (ars_status->out_length < 44)
return 0;
for (i = 0; i < ars_status->num_records; i++) {
/* only process full records */
if (ars_status->out_length
< 44 + sizeof(struct nd_ars_record) * (i + 1))
break;
rc = nvdimm_bus_add_poison(nvdimm_bus,
ars_status->records[i].err_address,
ars_status->records[i].length);
if (rc)
return rc;
}
if (i < ars_status->num_records)
dev_warn(acpi_desc->dev, "detected truncated ars results\n");
return 0;
}
@ -2266,8 +2292,7 @@ static int acpi_nfit_query_poison(struct acpi_nfit_desc *acpi_desc,
if (rc < 0 && rc != -ENOSPC)
return rc;
if (ars_status_process_records(acpi_desc->nvdimm_bus,
acpi_desc->ars_status))
if (ars_status_process_records(acpi_desc, acpi_desc->ars_status))
return -ENOMEM;
return 0;

View file

@ -240,5 +240,7 @@ const u8 *to_nfit_uuid(enum nfit_uuids id);
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, void *nfit, acpi_size sz);
void __acpi_nfit_notify(struct device *dev, acpi_handle handle, u32 event);
void __acpi_nvdimm_notify(struct device *dev, u32 event);
int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
unsigned int cmd, void *buf, unsigned int buf_len, int *cmd_rc);
void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
#endif /* __NFIT_H__ */

View file

@ -70,7 +70,7 @@ int acpi_map_pxm_to_node(int pxm)
{
int node;
if (pxm < 0 || pxm >= MAX_PXM_DOMAINS)
if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off)
return NUMA_NO_NODE;
node = pxm_to_node_map[pxm];

View file

@ -42,7 +42,7 @@
#include <linux/semaphore.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include "internal.h"
@ -182,15 +182,15 @@ void acpi_os_vprintf(const char *fmt, va_list args)
static unsigned long acpi_rsdp;
static int __init setup_acpi_rsdp(char *arg)
{
if (kstrtoul(arg, 16, &acpi_rsdp))
return -EINVAL;
return 0;
return kstrtoul(arg, 16, &acpi_rsdp);
}
early_param("acpi_rsdp", setup_acpi_rsdp);
#endif
acpi_physical_address __init acpi_os_get_root_pointer(void)
{
acpi_physical_address pa = 0;
#ifdef CONFIG_KEXEC
if (acpi_rsdp)
return acpi_rsdp;
@ -199,21 +199,14 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
if (efi_enabled(EFI_CONFIG_TABLES)) {
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
if (efi.acpi != EFI_INVALID_TABLE_ADDR)
return efi.acpi;
else {
printk(KERN_ERR PREFIX
"System description tables not found\n");
return 0;
}
pr_err(PREFIX "System description tables not found\n");
} else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) {
acpi_physical_address pa = 0;
acpi_find_root_pointer(&pa);
return pa;
}
return 0;
return pa;
}
/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
@ -1693,7 +1686,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control,
if (rc < 0)
return AE_ERROR;
else if (rc > 0)
return AE_CTRL_SKIP;
return AE_CTRL_TERMINATE;
return AE_OK;
}
@ -1704,6 +1697,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
__acpi_os_prepare_sleep = func;
}
#if (ACPI_REDUCED_HARDWARE)
acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
u32 val_b)
{
@ -1714,13 +1708,35 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
if (rc < 0)
return AE_ERROR;
else if (rc > 0)
return AE_CTRL_SKIP;
return AE_CTRL_TERMINATE;
return AE_OK;
}
#else
acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
u32 val_b)
{
return AE_OK;
}
#endif
void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
u32 val_a, u32 val_b))
{
__acpi_os_prepare_extended_sleep = func;
}
acpi_status acpi_os_enter_sleep(u8 sleep_state,
u32 reg_a_value, u32 reg_b_value)
{
acpi_status status;
if (acpi_gbl_reduced_hardware)
status = acpi_os_prepare_extended_sleep(sleep_state,
reg_a_value,
reg_b_value);
else
status = acpi_os_prepare_sleep(sleep_state,
reg_a_value, reg_b_value);
return status;
}

View file

@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
/* Structure to hold entries from the MCFG table */
struct mcfg_entry {
@ -32,12 +33,166 @@ struct mcfg_entry {
u8 bus_end;
};
#ifdef CONFIG_PCI_QUIRKS
struct mcfg_fixup {
char oem_id[ACPI_OEM_ID_SIZE + 1];
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
u32 oem_revision;
u16 segment;
struct resource bus_range;
struct pci_ecam_ops *ops;
struct resource cfgres;
};
#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \
((end) - (start) + 1), \
NULL, IORESOURCE_BUS)
#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff)
static struct mcfg_fixup mcfg_quirks[] = {
/* { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */
#define QCOM_ECAM32(seg) \
{ "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops }
QCOM_ECAM32(0),
QCOM_ECAM32(1),
QCOM_ECAM32(2),
QCOM_ECAM32(3),
QCOM_ECAM32(4),
QCOM_ECAM32(5),
QCOM_ECAM32(6),
QCOM_ECAM32(7),
#define HISI_QUAD_DOM(table_id, seg, ops) \
{ "HISI ", table_id, 0, (seg) + 0, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops }
HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops),
#define THUNDER_PEM_RES(addr, node) \
DEFINE_RES_MEM((addr) + ((u64) (node) << 44), 0x39 * SZ_16M)
#define THUNDER_PEM_QUIRK(rev, node) \
{ "CAVIUM", "THUNDERX", rev, 4 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88001f000000UL, node) }, \
{ "CAVIUM", "THUNDERX", rev, 5 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x884057000000UL, node) }, \
{ "CAVIUM", "THUNDERX", rev, 6 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88808f000000UL, node) }, \
{ "CAVIUM", "THUNDERX", rev, 7 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89001f000000UL, node) }, \
{ "CAVIUM", "THUNDERX", rev, 8 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x894057000000UL, node) }, \
{ "CAVIUM", "THUNDERX", rev, 9 + (10 * (node)), MCFG_BUS_ANY, \
&thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89808f000000UL, node) }
/* SoC pass2.x */
THUNDER_PEM_QUIRK(1, 0),
THUNDER_PEM_QUIRK(1, 1),
#define THUNDER_ECAM_QUIRK(rev, seg) \
{ "CAVIUM", "THUNDERX", rev, seg, MCFG_BUS_ANY, \
&pci_thunder_ecam_ops }
/* SoC pass1.x */
THUNDER_PEM_QUIRK(2, 0), /* off-chip devices */
THUNDER_PEM_QUIRK(2, 1), /* off-chip devices */
THUNDER_ECAM_QUIRK(2, 0),
THUNDER_ECAM_QUIRK(2, 1),
THUNDER_ECAM_QUIRK(2, 2),
THUNDER_ECAM_QUIRK(2, 3),
THUNDER_ECAM_QUIRK(2, 10),
THUNDER_ECAM_QUIRK(2, 11),
THUNDER_ECAM_QUIRK(2, 12),
THUNDER_ECAM_QUIRK(2, 13),
#define XGENE_V1_ECAM_MCFG(rev, seg) \
{"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
&xgene_v1_pcie_ecam_ops }
#define XGENE_V2_ECAM_MCFG(rev, seg) \
{"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \
&xgene_v2_pcie_ecam_ops }
/* X-Gene SoC with v1 PCIe controller */
XGENE_V1_ECAM_MCFG(1, 0),
XGENE_V1_ECAM_MCFG(1, 1),
XGENE_V1_ECAM_MCFG(1, 2),
XGENE_V1_ECAM_MCFG(1, 3),
XGENE_V1_ECAM_MCFG(1, 4),
XGENE_V1_ECAM_MCFG(2, 0),
XGENE_V1_ECAM_MCFG(2, 1),
XGENE_V1_ECAM_MCFG(2, 2),
XGENE_V1_ECAM_MCFG(2, 3),
XGENE_V1_ECAM_MCFG(2, 4),
/* X-Gene SoC with v2.1 PCIe controller */
XGENE_V2_ECAM_MCFG(3, 0),
XGENE_V2_ECAM_MCFG(3, 1),
/* X-Gene SoC with v2.2 PCIe controller */
XGENE_V2_ECAM_MCFG(4, 0),
XGENE_V2_ECAM_MCFG(4, 1),
XGENE_V2_ECAM_MCFG(4, 2),
};
static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
static char mcfg_oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
static u32 mcfg_oem_revision;
static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment,
struct resource *bus_range)
{
if (!memcmp(f->oem_id, mcfg_oem_id, ACPI_OEM_ID_SIZE) &&
!memcmp(f->oem_table_id, mcfg_oem_table_id,
ACPI_OEM_TABLE_ID_SIZE) &&
f->oem_revision == mcfg_oem_revision &&
f->segment == segment &&
resource_contains(&f->bus_range, bus_range))
return 1;
return 0;
}
#endif
static void pci_mcfg_apply_quirks(struct acpi_pci_root *root,
struct resource *cfgres,
struct pci_ecam_ops **ecam_ops)
{
#ifdef CONFIG_PCI_QUIRKS
u16 segment = root->segment;
struct resource *bus_range = &root->secondary;
struct mcfg_fixup *f;
int i;
for (i = 0, f = mcfg_quirks; i < ARRAY_SIZE(mcfg_quirks); i++, f++) {
if (pci_mcfg_quirk_matches(f, segment, bus_range)) {
if (f->cfgres.start)
*cfgres = f->cfgres;
if (f->ops)
*ecam_ops = f->ops;
dev_info(&root->device->dev, "MCFG quirk: ECAM at %pR for %pR with %ps\n",
cfgres, bus_range, *ecam_ops);
return;
}
}
#endif
}
/* List to save MCFG entries */
static LIST_HEAD(pci_mcfg_list);
phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres,
struct pci_ecam_ops **ecam_ops)
{
struct pci_ecam_ops *ops = &pci_generic_ecam_ops;
struct resource *bus_res = &root->secondary;
u16 seg = root->segment;
struct mcfg_entry *e;
struct resource res;
/* Use address from _CBA if present, otherwise lookup MCFG */
if (root->mcfg_addr)
goto skip_lookup;
/*
* We expect exact match, unless MCFG entry end bus covers more than
@ -45,10 +200,32 @@ phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res)
*/
list_for_each_entry(e, &pci_mcfg_list, list) {
if (e->segment == seg && e->bus_start == bus_res->start &&
e->bus_end >= bus_res->end)
return e->addr;
e->bus_end >= bus_res->end) {
root->mcfg_addr = e->addr;
}
}
skip_lookup:
memset(&res, 0, sizeof(res));
if (root->mcfg_addr) {
res.start = root->mcfg_addr + (bus_res->start << 20);
res.end = res.start + (resource_size(bus_res) << 20) - 1;
res.flags = IORESOURCE_MEM;
}
/*
* Allow quirks to override default ECAM ops and CFG resource
* range. This may even fabricate a CFG resource range in case
* MCFG does not have it. Invalid CFG start address means MCFG
* firmware bug or we need another quirk in array.
*/
pci_mcfg_apply_quirks(root, &res, &ops);
if (!res.start)
return -ENXIO;
*cfgres = res;
*ecam_ops = ops;
return 0;
}
@ -79,6 +256,13 @@ static __init int pci_mcfg_parse(struct acpi_table_header *header)
list_add(&e->list, &pci_mcfg_list);
}
#ifdef CONFIG_PCI_QUIRKS
/* Save MCFG IDs and revision for quirks matching */
memcpy(mcfg_oem_id, header->oem_id, ACPI_OEM_ID_SIZE);
memcpy(mcfg_oem_table_id, header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
mcfg_oem_revision = header->oem_revision;
#endif
pr_info("MCFG table detected, %d entries\n", n);
return 0;
}

View file

@ -4,7 +4,7 @@
#include <linux/suspend.h>
#include <linux/bcd.h>
#include <linux/acpi.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#include "sleep.h"
#include "internal.h"

View file

@ -141,7 +141,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr,
if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
return;
if (amd_e400_c1e_detected)
if (boot_cpu_has_bug(X86_BUG_AMD_APIC_C1E))
type = ACPI_STATE_C1;
/*

View file

@ -157,7 +157,7 @@ static void acpi_processor_ppc_ost(acpi_handle handle, int status)
status, NULL);
}
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
void acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
{
int ret;
@ -168,7 +168,7 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
*/
if (event_flag)
acpi_processor_ppc_ost(pr->handle, 1);
return 0;
return;
}
ret = acpi_processor_get_platform_limit(pr);
@ -182,10 +182,8 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
else
acpi_processor_ppc_ost(pr->handle, 0);
}
if (ret < 0)
return (ret);
else
return cpufreq_update_policy(pr->id);
if (ret >= 0)
cpufreq_update_policy(pr->id);
}
int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
@ -465,11 +463,33 @@ int acpi_processor_get_performance_info(struct acpi_processor *pr)
return result;
}
EXPORT_SYMBOL_GPL(acpi_processor_get_performance_info);
int acpi_processor_notify_smm(struct module *calling_module)
int acpi_processor_pstate_control(void)
{
acpi_status status;
static int is_done = 0;
if (!acpi_gbl_FADT.smi_command || !acpi_gbl_FADT.pstate_control)
return 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Writing pstate_control [0x%x] to smi_command [0x%x]\n",
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
(u32)acpi_gbl_FADT.pstate_control, 8);
if (ACPI_SUCCESS(status))
return 1;
ACPI_EXCEPTION((AE_INFO, status,
"Failed to write pstate_control [0x%x] to smi_command [0x%x]",
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
return -EIO;
}
int acpi_processor_notify_smm(struct module *calling_module)
{
static int is_done = 0;
int result;
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
return -EBUSY;
@ -492,26 +512,15 @@ int acpi_processor_notify_smm(struct module *calling_module)
is_done = -EIO;
/* Can't write pstate_control to smi_command if either value is zero */
if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
result = acpi_processor_pstate_control();
if (!result) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
module_put(calling_module);
return 0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Writing pstate_control [0x%x] to smi_command [0x%x]\n",
acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
(u32) acpi_gbl_FADT.pstate_control, 8);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"Failed to write pstate_control [0x%x] to "
"smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
acpi_gbl_FADT.smi_command));
if (result < 0) {
module_put(calling_module);
return status;
return result;
}
/* Success. If there's no _PPC, we need to fear nothing, so

View file

@ -28,7 +28,7 @@
#include <linux/cpufreq.h>
#include <linux/acpi.h>
#include <acpi/processor.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#define PREFIX "ACPI: "

View file

@ -31,7 +31,7 @@
#include <linux/acpi.h>
#include <acpi/processor.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#define PREFIX "ACPI: "

View file

@ -41,14 +41,13 @@ static bool acpi_enumerate_nondev_subnodes(acpi_handle scope,
static bool acpi_extract_properties(const union acpi_object *desc,
struct acpi_device_data *data);
static bool acpi_nondev_subnode_ok(acpi_handle scope,
const union acpi_object *link,
struct list_head *list)
static bool acpi_nondev_subnode_extract(const union acpi_object *desc,
acpi_handle handle,
const union acpi_object *link,
struct list_head *list)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
struct acpi_data_node *dn;
acpi_handle handle;
acpi_status status;
bool result;
dn = kzalloc(sizeof(*dn), GFP_KERNEL);
if (!dn)
@ -58,43 +57,75 @@ static bool acpi_nondev_subnode_ok(acpi_handle scope,
dn->fwnode.type = FWNODE_ACPI_DATA;
INIT_LIST_HEAD(&dn->data.subnodes);
status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
&handle);
if (ACPI_FAILURE(status))
goto fail;
result = acpi_extract_properties(desc, &dn->data);
status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
ACPI_TYPE_PACKAGE);
if (ACPI_FAILURE(status))
goto fail;
if (handle) {
acpi_handle scope;
acpi_status status;
if (acpi_extract_properties(buf.pointer, &dn->data))
/*
* The scope for the subnode object lookup is the one of the
* namespace node (device) containing the object that has
* returned the package. That is, it's the scope of that
* object's parent.
*/
status = acpi_get_parent(handle, &scope);
if (ACPI_SUCCESS(status)
&& acpi_enumerate_nondev_subnodes(scope, desc, &dn->data))
result = true;
} else if (acpi_enumerate_nondev_subnodes(NULL, desc, &dn->data)) {
result = true;
}
if (result) {
dn->handle = handle;
/*
* The scope for the subnode object lookup is the one of the namespace
* node (device) containing the object that has returned the package.
* That is, it's the scope of that object's parent.
*/
status = acpi_get_parent(handle, &scope);
if (ACPI_SUCCESS(status)
&& acpi_enumerate_nondev_subnodes(scope, buf.pointer, &dn->data))
dn->handle = handle;
if (dn->handle) {
dn->data.pointer = buf.pointer;
dn->data.pointer = desc;
list_add_tail(&dn->sibling, list);
return true;
}
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
fail:
ACPI_FREE(buf.pointer);
kfree(dn);
acpi_handle_debug(handle, "Invalid properties/subnodes data, skipping\n");
return false;
}
static bool acpi_nondev_subnode_data_ok(acpi_handle handle,
const union acpi_object *link,
struct list_head *list)
{
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
acpi_status status;
status = acpi_evaluate_object_typed(handle, NULL, NULL, &buf,
ACPI_TYPE_PACKAGE);
if (ACPI_FAILURE(status))
return false;
if (acpi_nondev_subnode_extract(buf.pointer, handle, link, list))
return true;
ACPI_FREE(buf.pointer);
return false;
}
static bool acpi_nondev_subnode_ok(acpi_handle scope,
const union acpi_object *link,
struct list_head *list)
{
acpi_handle handle;
acpi_status status;
if (!scope)
return false;
status = acpi_get_handle(scope, link->package.elements[1].string.pointer,
&handle);
if (ACPI_FAILURE(status))
return false;
return acpi_nondev_subnode_data_ok(handle, link, list);
}
static int acpi_add_nondev_subnodes(acpi_handle scope,
const union acpi_object *links,
struct list_head *list)
@ -103,15 +134,37 @@ static int acpi_add_nondev_subnodes(acpi_handle scope,
int i;
for (i = 0; i < links->package.count; i++) {
const union acpi_object *link;
const union acpi_object *link, *desc;
acpi_handle handle;
bool result;
link = &links->package.elements[i];
/* Only two elements allowed, both must be strings. */
if (link->package.count == 2
&& link->package.elements[0].type == ACPI_TYPE_STRING
&& link->package.elements[1].type == ACPI_TYPE_STRING
&& acpi_nondev_subnode_ok(scope, link, list))
ret = true;
/* Only two elements allowed. */
if (link->package.count != 2)
continue;
/* The first one must be a string. */
if (link->package.elements[0].type != ACPI_TYPE_STRING)
continue;
/* The second one may be a string, a reference or a package. */
switch (link->package.elements[1].type) {
case ACPI_TYPE_STRING:
result = acpi_nondev_subnode_ok(scope, link, list);
break;
case ACPI_TYPE_LOCAL_REFERENCE:
handle = link->package.elements[1].reference.handle;
result = acpi_nondev_subnode_data_ok(handle, link, list);
break;
case ACPI_TYPE_PACKAGE:
desc = &link->package.elements[1];
result = acpi_nondev_subnode_extract(desc, NULL, link, list);
break;
default:
result = false;
break;
}
ret = ret || result;
}
return ret;

View file

@ -664,3 +664,60 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
return (type & types) ? 0 : 1;
}
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
static int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res)
{
struct list_head resource_list;
struct resource_entry *rentry;
int ret, found = 0;
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (ret < 0)
return 0;
list_for_each_entry(rentry, &resource_list, node) {
if (resource_contains(rentry->res, res)) {
found = 1;
break;
}
}
acpi_dev_free_resource_list(&resource_list);
return found;
}
static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth,
void *context, void **ret)
{
struct resource *res = context;
struct acpi_device **consumer = (struct acpi_device **) ret;
struct acpi_device *adev;
if (acpi_bus_get_device(handle, &adev))
return AE_OK;
if (acpi_dev_consumes_res(adev, res)) {
*consumer = adev;
return AE_CTRL_TERMINATE;
}
return AE_OK;
}
/**
* acpi_resource_consumer - Find the ACPI device that consumes @res.
* @res: Resource to search for.
*
* Search the current resource settings (_CRS) of every ACPI device node
* for @res. If we find an ACPI device whose _CRS includes @res, return
* it. Otherwise, return NULL.
*/
struct acpi_device *acpi_resource_consumer(struct resource *res)
{
struct acpi_device *consumer = NULL;
acpi_get_devices(NULL, acpi_res_consumer_cb, res, (void **) &consumer);
return consumer;
}

View file

@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/acpi_iort.h>
#include <linux/signal.h>
#include <linux/kthread.h>
#include <linux/dmi.h>
@ -1119,9 +1120,6 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
"support\n"));
*cap |= ACPI_VIDEO_BACKLIGHT;
if (!acpi_has_method(handle, "_BQC"))
printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
"cannot determine initial brightness\n");
/* We have backlight support, no need to scan further */
return AE_CTRL_TERMINATE;
}
@ -1370,6 +1368,38 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
return DEV_DMA_NON_COHERENT;
}
/**
* acpi_dma_configure - Set-up DMA configuration for the device.
* @dev: The pointer to the device
* @attr: device dma attributes
*/
void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
{
const struct iommu_ops *iommu;
iort_set_dma_mask(dev);
iommu = iort_iommu_configure(dev);
/*
* Assume dma valid range starts at 0 and covers the whole
* coherent_dma_mask.
*/
arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
}
EXPORT_SYMBOL_GPL(acpi_dma_configure);
/**
* acpi_dma_deconfigure - Tear-down DMA configuration for the device.
* @dev: The pointer to the device
*/
void acpi_dma_deconfigure(struct device *dev)
{
arch_teardown_dma_ops(dev);
}
EXPORT_SYMBOL_GPL(acpi_dma_deconfigure);
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;

View file

@ -47,32 +47,15 @@ static void acpi_sleep_tts_switch(u32 acpi_state)
}
}
static void acpi_sleep_pts_switch(u32 acpi_state)
{
acpi_status status;
status = acpi_execute_simple_method(NULL, "\\_PTS", acpi_state);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
/*
* OS can't evaluate the _PTS object correctly. Some warning
* message will be printed. But it won't break anything.
*/
printk(KERN_NOTICE "Failure in evaluating _PTS object\n");
}
}
static int sleep_notify_reboot(struct notifier_block *this,
static int tts_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
acpi_sleep_tts_switch(ACPI_STATE_S5);
acpi_sleep_pts_switch(ACPI_STATE_S5);
return NOTIFY_DONE;
}
static struct notifier_block sleep_notifier = {
.notifier_call = sleep_notify_reboot,
static struct notifier_block tts_notifier = {
.notifier_call = tts_notify_reboot,
.next = NULL,
.priority = 0,
};
@ -691,6 +674,14 @@ static void acpi_sleep_suspend_setup(void)
if (acpi_sleep_state_supported(i))
sleep_states[i] = 1;
/*
* Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set and
* the default suspend mode was not selected from the command line.
*/
if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0 &&
mem_sleep_default > PM_SUSPEND_MEM)
mem_sleep_default = PM_SUSPEND_FREEZE;
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
freeze_set_ops(&acpi_freeze_ops);
@ -916,9 +907,9 @@ int __init acpi_sleep_init(void)
pr_info(PREFIX "(supports%s)\n", supported);
/*
* Register the sleep_notifier to reboot notifier list so that the _TTS
* and _PTS object can also be evaluated when the system enters S5.
* Register the tts_notifier to reboot notifier list so that the _TTS
* object can also be evaluated when the system enters S5.
*/
register_reboot_notifier(&sleep_notifier);
register_reboot_notifier(&tts_notifier);
return 0;
}

View file

@ -40,7 +40,7 @@
#include <linux/thermal.h>
#include <linux/acpi.h>
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <linux/uaccess.h>
#define PREFIX "ACPI: "

View file

@ -296,6 +296,26 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
},
},
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1123661 */
.callback = video_detect_force_native,
.ident = "Dell XPS 17 L702X",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
},
},
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1204476 */
/* https://bugs.launchpad.net/ubuntu/+source/linux-lts-trusty/+bug/1416940 */
.callback = video_detect_force_native,
.ident = "HP Pavilion dv6",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6 Notebook PC"),
},
},
{ },
};