diff options
53 files changed, 1007 insertions, 459 deletions
diff --git a/Documentation/admin-guide/acpi/fan_performance_states.rst b/Documentation/admin-guide/acpi/fan_performance_states.rst index 98fe5c333121..b9e4b4d146c1 100644 --- a/Documentation/admin-guide/acpi/fan_performance_states.rst +++ b/Documentation/admin-guide/acpi/fan_performance_states.rst @@ -60,3 +60,31 @@ For example:: When a given field is not populated or its value provided by the platform firmware is invalid, the "not-defined" string is shown instead of the value. + +ACPI Fan Fine Grain Control +============================= + +When _FIF object specifies support for fine grain control, then fan speed +can be set from 0 to 100% with the recommended minimum "step size" via +_FSL object. User can adjust fan speed using thermal sysfs cooling device. + +Here use can look at fan performance states for a reference speed (speed_rpm) +and set it by changing cooling device cur_state. If the fine grain control +is supported then user can also adjust to some other speeds which are +not defined in the performance states. + +The support of fine grain control is presented via sysfs attribute +"fine_grain_control". If fine grain control is present, this attribute +will show "1" otherwise "0". + +This sysfs attribute is presented in the same directory as performance states. + +ACPI Fan Performance Feedback +============================= + +The optional _FST object provides status information for the fan device. +This includes field to provide current fan speed in revolutions per minute +at which the fan is rotating. + +This speed is presented in the sysfs using the attribute "fan_speed_rpm", +in the same directory as performance states. diff --git a/Documentation/driver-api/gpio/board.rst b/Documentation/driver-api/gpio/board.rst index 191fa867826a..4e3adf31c8d1 100644 --- a/Documentation/driver-api/gpio/board.rst +++ b/Documentation/driver-api/gpio/board.rst @@ -71,14 +71,14 @@ with the help of _DSD (Device Specific Data), introduced in ACPI 5.1:: Device (FOO) { Name (_CRS, ResourceTemplate () { - GpioIo (Exclusive, ..., IoRestrictionOutputOnly, - "\\_SB.GPI0") {15} // red - GpioIo (Exclusive, ..., IoRestrictionOutputOnly, - "\\_SB.GPI0") {16} // green - GpioIo (Exclusive, ..., IoRestrictionOutputOnly, - "\\_SB.GPI0") {17} // blue - GpioIo (Exclusive, ..., IoRestrictionOutputOnly, - "\\_SB.GPI0") {1} // power + GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, + "\\_SB.GPI0", 0, ResourceConsumer) { 15 } // red + GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, + "\\_SB.GPI0", 0, ResourceConsumer) { 16 } // green + GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, + "\\_SB.GPI0", 0, ResourceConsumer) { 17 } // blue + GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionOutputOnly, + "\\_SB.GPI0", 0, ResourceConsumer) { 1 } // power }) Name (_DSD, Package () { @@ -92,10 +92,7 @@ with the help of _DSD (Device Specific Data), introduced in ACPI 5.1:: ^FOO, 2, 0, 1, } }, - Package () { - "power-gpios", - Package () {^FOO, 3, 0, 0}, - }, + Package () { "power-gpios", Package () { ^FOO, 3, 0, 0 } }, } }) } diff --git a/Documentation/firmware-guide/acpi/enumeration.rst b/Documentation/firmware-guide/acpi/enumeration.rst index 74b830b2fd59..c414646a1bb4 100644 --- a/Documentation/firmware-guide/acpi/enumeration.rst +++ b/Documentation/firmware-guide/acpi/enumeration.rst @@ -19,16 +19,17 @@ possible we decided to do following: platform devices. - Devices behind real busses where there is a connector resource - are represented as struct spi_device or struct i2c_device - (standard UARTs are not busses so there is no struct uart_device). + are represented as struct spi_device or struct i2c_device. Note + that standard UARTs are not busses so there is no struct uart_device, + although some of them may be represented by sturct serdev_device. As both ACPI and Device Tree represent a tree of devices (and their resources) this implementation follows the Device Tree way as much as possible. -The ACPI implementation enumerates devices behind busses (platform, SPI and -I2C), creates the physical devices and binds them to their ACPI handle in -the ACPI namespace. +The ACPI implementation enumerates devices behind busses (platform, SPI, +I2C, and in some cases UART), creates the physical devices and binds them +to their ACPI handle in the ACPI namespace. This means that when ACPI_HANDLE(dev) returns non-NULL the device was enumerated from ACPI namespace. This handle can be used to extract other @@ -46,18 +47,16 @@ some minor changes. Adding ACPI support for an existing driver should be pretty straightforward. Here is the simplest example:: - #ifdef CONFIG_ACPI static const struct acpi_device_id mydrv_acpi_match[] = { /* ACPI IDs here */ { } }; MODULE_DEVICE_TABLE(acpi, mydrv_acpi_match); - #endif static struct platform_driver my_driver = { ... .driver = { - .acpi_match_table = ACPI_PTR(mydrv_acpi_match), + .acpi_match_table = mydrv_acpi_match, }, }; @@ -155,7 +154,7 @@ Here is what the ACPI namespace for a SPI slave might look like:: Device (EEP0) { Name (_ADR, 1) - Name (_CID, Package() { + Name (_CID, Package () { "ATML0025", "AT25", }) @@ -172,59 +171,51 @@ The SPI device drivers only need to add ACPI IDs in a similar way than with the platform device drivers. Below is an example where we add ACPI support to at25 SPI eeprom driver (this is meant for the above ACPI snippet):: - #ifdef CONFIG_ACPI static const struct acpi_device_id at25_acpi_match[] = { { "AT25", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, at25_acpi_match); - #endif static struct spi_driver at25_driver = { .driver = { ... - .acpi_match_table = ACPI_PTR(at25_acpi_match), + .acpi_match_table = at25_acpi_match, }, }; Note that this driver actually needs more information like page size of the -eeprom etc. but at the time writing this there is no standard way of -passing those. One idea is to return this in _DSM method like:: +eeprom, etc. This information can be passed via _DSD method like:: Device (EEP0) { ... - Method (_DSM, 4, NotSerialized) + Name (_DSD, Package () { - Store (Package (6) + ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + Package () { - "byte-len", 1024, - "addr-mode", 2, - "page-size, 32 - }, Local0) - - // Check UUIDs etc. - - Return (Local0) - } - -Then the at25 SPI driver can get this configuration by calling _DSM on its -ACPI handle like:: - - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_object_list input; - acpi_status status; + Package () { "size", 1024 }, + Package () { "pagesize", 32 }, + Package () { "address-width", 16 }, + } + }) + } - /* Fill in the input buffer */ +Then the at25 SPI driver can get this configuration by calling device property +APIs during ->probe() phase like:: - status = acpi_evaluate_object(ACPI_HANDLE(&spi->dev), "_DSM", - &input, &output); - if (ACPI_FAILURE(status)) - /* Handle the error */ + err = device_property_read_u32(dev, "size", &size); + if (err) + ...error handling... - /* Extract the data here */ + err = device_property_read_u32(dev, "pagesize", &page_size); + if (err) + ...error handling... - kfree(output.pointer); + err = device_property_read_u32(dev, "address-width", &addr_width); + if (err) + ...error handling... I2C serial bus support ====================== @@ -237,26 +228,24 @@ registered. Below is an example of how to add ACPI support to the existing mpu3050 input driver:: - #ifdef CONFIG_ACPI static const struct acpi_device_id mpu3050_acpi_match[] = { { "MPU3050", 0 }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, mpu3050_acpi_match); - #endif static struct i2c_driver mpu3050_i2c_driver = { .driver = { .name = "mpu3050", - .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, - .acpi_match_table = ACPI_PTR(mpu3050_acpi_match), + .acpi_match_table = mpu3050_acpi_match, }, .probe = mpu3050_probe, .remove = mpu3050_remove, .id_table = mpu3050_ids, }; + module_i2c_driver(mpu3050_i2c_driver); Reference to PWM device ======================= @@ -282,9 +271,9 @@ introduced, i.e.:: } } } - }) ... + } In the above example the PWM-based LED driver references to the PWM channel 0 of \_SB.PCI0.PWM device with initial period setting equal to 600 ms (note that @@ -306,26 +295,13 @@ For example:: { Name (SBUF, ResourceTemplate() { - ... // Used to power on/off the device - GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, - IoRestrictionOutputOnly, "\\_SB.PCI0.GPI0", - 0x00, ResourceConsumer,,) - { - // Pin List - 0x0055 - } + GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionOutputOnly, + "\\_SB.PCI0.GPI0", 0, ResourceConsumer) { 85 } // Interrupt for the device - GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, - 0x0000, "\\_SB.PCI0.GPI0", 0x00, ResourceConsumer,,) - { - // Pin list - 0x0058 - } - - ... - + GpioInt (Edge, ActiveHigh, ExclusiveAndWake, PullNone, 0, + "\\_SB.PCI0.GPI0", 0, ResourceConsumer) { 88 } } Return (SBUF) @@ -337,11 +313,12 @@ For example:: ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () {"power-gpios", Package() {^DEV, 0, 0, 0 }}, - Package () {"irq-gpios", Package() {^DEV, 1, 0, 0 }}, + Package () { "power-gpios", Package () { ^DEV, 0, 0, 0 } }, + Package () { "irq-gpios", Package () { ^DEV, 1, 0, 0 } }, } }) ... + } These GPIO numbers are controller relative and path "\\_SB.PCI0.GPI0" specifies the path to the controller. In order to use these GPIOs in Linux @@ -460,10 +437,10 @@ namespace link:: Device (TMP0) { Name (_HID, "PRP0001") - Name (_DSD, Package() { + Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package (2) { "compatible", "ti,tmp75" }, + Package () { "compatible", "ti,tmp75" }, } }) Method (_CRS, 0, Serialized) diff --git a/Documentation/firmware-guide/acpi/gpio-properties.rst b/Documentation/firmware-guide/acpi/gpio-properties.rst index df4b711053ee..eaec732cc77c 100644 --- a/Documentation/firmware-guide/acpi/gpio-properties.rst +++ b/Documentation/firmware-guide/acpi/gpio-properties.rst @@ -21,18 +21,18 @@ index, like the ASL example below shows:: Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, - "\\_SB.GPO0", 0, ResourceConsumer) {15} + "\\_SB.GPO0", 0, ResourceConsumer) { 15 } GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionOutputOnly, - "\\_SB.GPO0", 0, ResourceConsumer) {27, 31} + "\\_SB.GPO0", 0, ResourceConsumer) { 27, 31 } }) Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () - { - Package () {"reset-gpios", Package() {^BTH, 1, 1, 0 }}, - Package () {"shutdown-gpios", Package() {^BTH, 0, 0, 0 }}, + { + Package () { "reset-gpios", Package () { ^BTH, 1, 1, 0 } }, + Package () { "shutdown-gpios", Package () { ^BTH, 0, 0, 0 } }, } }) } @@ -123,17 +123,17 @@ Example:: // _DSD Hierarchical Properties Extension UUID ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), Package () { - Package () {"hog-gpio8", "G8PU"} + Package () { "hog-gpio8", "G8PU" } } }) Name (G8PU, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { - Package () {"gpio-hog", 1}, - Package () {"gpios", Package () {8, 0}}, - Package () {"output-high", 1}, - Package () {"line-name", "gpio8-pullup"}, + Package () { "gpio-hog", 1 }, + Package () { "gpios", Package () { 8, 0 } }, + Package () { "output-high", 1 }, + Package () { "line-name", "gpio8-pullup" }, } }) @@ -266,15 +266,17 @@ have a device like below:: Name (_CRS, ResourceTemplate () { GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone, - "\\_SB.GPO0", 0, ResourceConsumer) {15} + "\\_SB.GPO0", 0, ResourceConsumer) { 15 } GpioIo (Exclusive, PullNone, 0, 0, IoRestrictionNone, - "\\_SB.GPO0", 0, ResourceConsumer) {27} + "\\_SB.GPO0", 0, ResourceConsumer) { 27 } }) } The driver might expect to get the right GPIO when it does:: desc = gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(desc)) + ...error handling... but since there is no way to know the mapping between "reset" and the GpioIo() in _CRS desc will hold ERR_PTR(-ENOENT). diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index f386b90a79c8..9fab663dd2de 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -24,6 +24,10 @@ void update_freq_counters_refs(void); #define arch_scale_freq_capacity topology_get_freq_scale #define arch_scale_freq_invariant topology_scale_freq_invariant +#ifdef CONFIG_ACPI_CPPC_LIB +#define arch_init_invariance_cppc topology_init_cpu_capacity_cppc +#endif + /* Replace task scheduler's default cpu-invariant accounting */ #define arch_scale_cpu_capacity topology_get_cpu_scale diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 43a89476a522..9619385bf749 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -216,15 +216,26 @@ extern void arch_scale_freq_tick(void); #define arch_scale_freq_tick arch_scale_freq_tick extern void arch_set_max_freq_ratio(bool turbo_disabled); +void init_freq_invariance(bool secondary, bool cppc_ready); #else static inline void arch_set_max_freq_ratio(bool turbo_disabled) { } +static inline void init_freq_invariance(bool secondary, bool cppc_ready) +{ +} #endif -#if defined(CONFIG_ACPI_CPPC_LIB) && defined(CONFIG_SMP) +#ifdef CONFIG_ACPI_CPPC_LIB void init_freq_invariance_cppc(void); -#define init_freq_invariance_cppc init_freq_invariance_cppc +#define arch_init_invariance_cppc init_freq_invariance_cppc + +bool amd_set_max_freq_ratio(u64 *ratio); +#else +static inline bool amd_set_max_freq_ratio(u64 *ratio) +{ + return false; +} #endif #endif /* _ASM_X86_TOPOLOGY_H */ diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile index cf340d85946a..fc17b3f136fe 100644 --- a/arch/x86/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -3,7 +3,7 @@ obj-$(CONFIG_ACPI) += boot.o obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o obj-$(CONFIG_ACPI_APEI) += apei.o -obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_msr.o +obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 5b6d1a95776f..0d01e7f5078c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -1328,6 +1328,17 @@ static int __init disable_acpi_pci(const struct dmi_system_id *d) return 0; } +static int __init disable_acpi_xsdt(const struct dmi_system_id *d) +{ + if (!acpi_force) { + pr_notice("%s detected: force use of acpi=rsdt\n", d->ident); + acpi_gbl_do_not_use_xsdt = TRUE; + } else { + pr_notice("Warning: DMI blacklist says broken, but acpi XSDT forced\n"); + } + return 0; +} + static int __init dmi_disable_acpi(const struct dmi_system_id *d) { if (!acpi_force) { @@ -1451,6 +1462,19 @@ static const struct dmi_system_id acpi_dmi_table[] __initconst = { DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, + /* + * Boxes that need ACPI XSDT use disabled due to corrupted tables + */ + { + .callback = disable_acpi_xsdt, + .ident = "Advantech DAC-BJ01", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "Bearlake CRB Board"), + DMI_MATCH(DMI_BIOS_VERSION, "V1.12"), + DMI_MATCH(DMI_BIOS_DATE, "02/01/2011"), + }, + }, {} }; diff --git a/arch/x86/kernel/acpi/cppc.c b/arch/x86/kernel/acpi/cppc.c new file mode 100644 index 000000000000..df1644d9b3b6 --- /dev/null +++ b/arch/x86/kernel/acpi/cppc.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * cppc.c: CPPC Interface for x86 + * Copyright (c) 2016, Intel Corporation. + */ + +#include <acpi/cppc_acpi.h> +#include <asm/msr.h> +#include <asm/processor.h> +#include <asm/topology.h> + +/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */ + +bool cpc_ffh_supported(void) +{ + return true; +} + +int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val) +{ + int err; + + err = rdmsrl_safe_on_cpu(cpunum, reg->address, val); + if (!err) { + u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, + reg->bit_offset); + + *val &= mask; + *val >>= reg->bit_offset; + } + return err; +} + +int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) +{ + u64 rd_val; + int err; + + err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val); + if (!err) { + u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, + reg->bit_offset); + + val <<= reg->bit_offset; + val &= mask; + rd_val &= ~mask; + rd_val |= val; + err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val); + } + return err; +} + +bool amd_set_max_freq_ratio(u64 *ratio) +{ + struct cppc_perf_caps perf_caps; + u64 highest_perf, nominal_perf; + u64 perf_ratio; + int rc; + + if (!ratio) + return false; + + rc = cppc_get_perf_caps(0, &perf_caps); + if (rc) { + pr_debug("Could not retrieve perf counters (%d)\n", rc); + return false; + } + + highest_perf = amd_get_highest_perf(); + nominal_perf = perf_caps.nominal_perf; + + if (!highest_perf || !nominal_perf) { + pr_debug("Could not retrieve highest or nominal performance\n"); + return false; + } + + perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf); + /* midpoint between max_boost and max_P */ + perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1; + if (!perf_ratio) { + pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n"); + return false; + } + + *ratio = perf_ratio; + arch_set_max_freq_ratio(false); + + return true; +} + +static DEFINE_MUTEX(freq_invariance_lock); + +void init_freq_invariance_cppc(void) +{ + static bool secondary; + + mutex_lock(&freq_invariance_lock); + + init_freq_invariance(secondary, true); + secondary = true; + + mutex_unlock(&freq_invariance_lock); +} diff --git a/arch/x86/kernel/acpi/cppc_msr.c b/arch/x86/kernel/acpi/cppc_msr.c deleted file mode 100644 index b961de569e7e..000000000000 --- a/arch/x86/kernel/acpi/cppc_msr.c +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cppc_msr.c: MSR Interface for CPPC - * Copyright (c) 2016, Intel Corporation. - */ - -#include <acpi/cppc_acpi.h> -#include <asm/msr.h> - -/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */ - -bool cpc_ffh_supported(void) -{ - return true; -} - -int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val) -{ - int err; - - err = rdmsrl_safe_on_cpu(cpunum, reg->address, val); - if (!err) { - u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, - reg->bit_offset); - - *val &= mask; - *val >>= reg->bit_offset; - } - return err; -} - -int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val) -{ - u64 rd_val; - int err; - - err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val); - if (!err) { - u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1, - reg->bit_offset); - - val <<= reg->bit_offset; - val &= mask; |