Merge branches 'acpi-x86', 'acpi-fan', 'acpi-soc' and 'acpi-cppc'
Merge changes in the ACPI x86-specific code, ACPI fan driverm ACPI LPSS (Intel SoC) driver and the ACPI CPPC library for 6.11-rc1: - Switch the ACPI x86 utility code and the ACPI LPSS driver to new Intel CPU model defines (Tony Luck). - Add hwmon interface support to the ACPI fan driver (Armin Wolf). - Add sysfs entry for guaranteed performance to the ACPI CPPC library and replace a ternary operator with umax() in it (Petr Tesařík, Prabhakar Pujeri). * acpi-x86: ACPI: x86: Switch to new Intel CPU model defines * acpi-fan: ACPI: fan: Add hwmon support * acpi-soc: ACPI: LPSS: Switch to new Intel CPU model defines * acpi-cppc: ACPI: CPPC: Replace ternary operator with umax() ACPI: CPPC: add sysfs entry for guaranteed performance
This commit is contained in:
commit
e598dd44b3
@ -77,6 +77,7 @@ obj-$(CONFIG_ACPI_TINY_POWER_BUTTON) += tiny-power-button.o
|
||||
obj-$(CONFIG_ACPI_FAN) += fan.o
|
||||
fan-objs := fan_core.o
|
||||
fan-objs += fan_attr.o
|
||||
fan-$(CONFIG_HWMON) += fan_hwmon.o
|
||||
|
||||
obj-$(CONFIG_ACPI_VIDEO) += video.o
|
||||
obj-$(CONFIG_ACPI_TAD) += acpi_tad.o
|
||||
|
@ -160,6 +160,7 @@ show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, guaranteed_perf);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
|
||||
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
|
||||
|
||||
@ -196,6 +197,7 @@ static struct attribute *cppc_attrs[] = {
|
||||
&highest_perf.attr,
|
||||
&lowest_perf.attr,
|
||||
&lowest_nonlinear_perf.attr,
|
||||
&guaranteed_perf.attr,
|
||||
&nominal_perf.attr,
|
||||
&nominal_freq.attr,
|
||||
&lowest_freq.attr,
|
||||
@ -1837,7 +1839,7 @@ static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
|
||||
dm->length >= DMI_ENTRY_PROCESSOR_MIN_LENGTH) {
|
||||
u16 val = (u16)get_unaligned((const u16 *)
|
||||
(dmi_data + DMI_PROCESSOR_MAX_SPEED));
|
||||
*mhz = val > *mhz ? val : *mhz;
|
||||
*mhz = umax(val, *mhz);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#ifndef _ACPI_FAN_H_
|
||||
#define _ACPI_FAN_H_
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
|
||||
#define ACPI_FAN_DEVICE_IDS \
|
||||
{"INT3404", }, /* Fan */ \
|
||||
{"INTC1044", }, /* Fan for Tiger Lake generation */ \
|
||||
@ -57,4 +59,11 @@ struct acpi_fan {
|
||||
int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst);
|
||||
int acpi_fan_create_attributes(struct acpi_device *device);
|
||||
void acpi_fan_delete_attributes(struct acpi_device *device);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_HWMON)
|
||||
int devm_acpi_fan_create_hwmon(struct acpi_device *device);
|
||||
#else
|
||||
static inline int devm_acpi_fan_create_hwmon(struct acpi_device *device) { return 0; };
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -336,6 +336,10 @@ static int acpi_fan_probe(struct platform_device *pdev)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = devm_acpi_fan_create_hwmon(device);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = acpi_fan_create_attributes(device);
|
||||
if (result)
|
||||
return result;
|
||||
|
170
drivers/acpi/fan_hwmon.c
Normal file
170
drivers/acpi/fan_hwmon.c
Normal file
@ -0,0 +1,170 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* hwmon interface for the ACPI Fan driver.
|
||||
*
|
||||
* Copyright (C) 2024 Armin Wolf <W_Armin@gmx.de>
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "fan.h"
|
||||
|
||||
/* Returned when the ACPI fan does not support speed reporting */
|
||||
#define FAN_SPEED_UNAVAILABLE U32_MAX
|
||||
#define FAN_POWER_UNAVAILABLE U32_MAX
|
||||
|
||||
static struct acpi_fan_fps *acpi_fan_get_current_fps(struct acpi_fan *fan, u64 control)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < fan->fps_count; i++) {
|
||||
if (fan->fps[i].control == control)
|
||||
return &fan->fps[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static umode_t acpi_fan_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct acpi_fan *fan = drvdata;
|
||||
unsigned int i;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
return 0444;
|
||||
case hwmon_fan_target:
|
||||
/*
|
||||
* When in fine grain control mode, not every fan control value
|
||||
* has an associated fan performance state.
|
||||
*/
|
||||
if (fan->fif.fine_grain_ctrl)
|
||||
return 0;
|
||||
|
||||
return 0444;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case hwmon_power:
|
||||
switch (attr) {
|
||||
case hwmon_power_input:
|
||||
/*
|
||||
* When in fine grain control mode, not every fan control value
|
||||
* has an associated fan performance state.
|
||||
*/
|
||||
if (fan->fif.fine_grain_ctrl)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* When all fan performance states contain no valid power data,
|
||||
* when the associated attribute should not be created.
|
||||
*/
|
||||
for (i = 0; i < fan->fps_count; i++) {
|
||||
if (fan->fps[i].power != FAN_POWER_UNAVAILABLE)
|
||||
return 0444;
|
||||
}
|
||||
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
||||
int channel, long *val)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev->parent);
|
||||
struct acpi_fan *fan = dev_get_drvdata(dev);
|
||||
struct acpi_fan_fps *fps;
|
||||
struct acpi_fan_fst fst;
|
||||
int ret;
|
||||
|
||||
ret = acpi_fan_get_fst(adev, &fst);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_fan:
|
||||
switch (attr) {
|
||||
case hwmon_fan_input:
|
||||
if (fst.speed == FAN_SPEED_UNAVAILABLE)
|
||||
return -ENODEV;
|
||||
|
||||
if (fst.speed > LONG_MAX)
|
||||
return -EOVERFLOW;
|
||||
|
||||
*val = fst.speed;
|
||||
return 0;
|
||||
case hwmon_fan_target:
|
||||
fps = acpi_fan_get_current_fps(fan, fst.control);
|
||||
if (!fps)
|
||||
return -EIO;
|
||||
|
||||
if (fps->speed > LONG_MAX)
|
||||
return -EOVERFLOW;
|
||||
|
||||
*val = fps->speed;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
case hwmon_power:
|
||||
switch (attr) {
|
||||
case hwmon_power_input:
|
||||
fps = acpi_fan_get_current_fps(fan, fst.control);
|
||||
if (!fps)
|
||||
return -EIO;
|
||||
|
||||
if (fps->power == FAN_POWER_UNAVAILABLE)
|
||||
return -ENODEV;
|
||||
|
||||
if (fps->power > LONG_MAX / MICROWATT_PER_MILLIWATT)
|
||||
return -EOVERFLOW;
|
||||
|
||||
*val = fps->power * MICROWATT_PER_MILLIWATT;
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct hwmon_ops acpi_fan_hwmon_ops = {
|
||||
.is_visible = acpi_fan_hwmon_is_visible,
|
||||
.read = acpi_fan_hwmon_read,
|
||||
};
|
||||
|
||||
static const struct hwmon_channel_info * const acpi_fan_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET),
|
||||
HWMON_CHANNEL_INFO(power, HWMON_P_INPUT),
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info acpi_fan_hwmon_chip_info = {
|
||||
.ops = &acpi_fan_hwmon_ops,
|
||||
.info = acpi_fan_hwmon_info,
|
||||
};
|
||||
|
||||
int devm_acpi_fan_create_hwmon(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_fan *fan = acpi_driver_data(device);
|
||||
struct device *hdev;
|
||||
|
||||
hdev = devm_hwmon_device_register_with_info(&device->dev, "acpi_fan", fan,
|
||||
&acpi_fan_hwmon_chip_info, NULL);
|
||||
return PTR_ERR_OR_ZERO(hdev);
|
||||
}
|
@ -338,8 +338,8 @@ static const struct lpss_device_desc bsw_spi_dev_desc = {
|
||||
};
|
||||
|
||||
static const struct x86_cpu_id lpss_cpu_ids[] = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, NULL),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL),
|
||||
X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, NULL),
|
||||
X86_MATCH_VFM(INTEL_ATOM_AIRMONT, NULL),
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -45,37 +45,37 @@ struct override_status_id {
|
||||
unsigned long long status;
|
||||
};
|
||||
|
||||
#define ENTRY(status, hid, uid, path, cpu_model, dmi...) { \
|
||||
#define ENTRY(status, hid, uid, path, cpu_vfm, dmi...) { \
|
||||
{ { hid, }, {} }, \
|
||||
{ X86_MATCH_INTEL_FAM6_MODEL(cpu_model, NULL), {} }, \
|
||||
{ X86_MATCH_VFM(cpu_vfm, NULL), {} }, \
|
||||
{ { .matches = dmi }, {} }, \
|
||||
uid, \
|
||||
path, \
|
||||
status, \
|
||||
}
|
||||
|
||||
#define PRESENT_ENTRY_HID(hid, uid, cpu_model, dmi...) \
|
||||
ENTRY(ACPI_STA_DEFAULT, hid, uid, NULL, cpu_model, dmi)
|
||||
#define PRESENT_ENTRY_HID(hid, uid, cpu_vfm, dmi...) \
|
||||
ENTRY(ACPI_STA_DEFAULT, hid, uid, NULL, cpu_vfm, dmi)
|
||||
|
||||
#define NOT_PRESENT_ENTRY_HID(hid, uid, cpu_model, dmi...) \
|
||||
ENTRY(0, hid, uid, NULL, cpu_model, dmi)
|
||||
#define NOT_PRESENT_ENTRY_HID(hid, uid, cpu_vfm, dmi...) \
|
||||
ENTRY(0, hid, uid, NULL, cpu_vfm, dmi)
|
||||
|
||||
#define PRESENT_ENTRY_PATH(path, cpu_model, dmi...) \
|
||||
ENTRY(ACPI_STA_DEFAULT, "", NULL, path, cpu_model, dmi)
|
||||
#define PRESENT_ENTRY_PATH(path, cpu_vfm, dmi...) \
|
||||
ENTRY(ACPI_STA_DEFAULT, "", NULL, path, cpu_vfm, dmi)
|
||||
|
||||
#define NOT_PRESENT_ENTRY_PATH(path, cpu_model, dmi...) \
|
||||
ENTRY(0, "", NULL, path, cpu_model, dmi)
|
||||
#define NOT_PRESENT_ENTRY_PATH(path, cpu_vfm, dmi...) \
|
||||
ENTRY(0, "", NULL, path, cpu_vfm, dmi)
|
||||
|
||||
static const struct override_status_id override_status_ids[] = {
|
||||
/*
|
||||
* Bay / Cherry Trail PWM directly poked by GPU driver in win10,
|
||||
* but Linux uses a separate PWM driver, harmless if not used.
|
||||
*/
|
||||
PRESENT_ENTRY_HID("80860F09", "1", ATOM_SILVERMONT, {}),
|
||||
PRESENT_ENTRY_HID("80862288", "1", ATOM_AIRMONT, {}),
|
||||
PRESENT_ENTRY_HID("80860F09", "1", INTEL_ATOM_SILVERMONT, {}),
|
||||
PRESENT_ENTRY_HID("80862288", "1", INTEL_ATOM_AIRMONT, {}),
|
||||
|
||||
/* The Xiaomi Mi Pad 2 uses PWM2 for touchkeys backlight control */
|
||||
PRESENT_ENTRY_HID("80862289", "2", ATOM_AIRMONT, {
|
||||
PRESENT_ENTRY_HID("80862289", "2", INTEL_ATOM_AIRMONT, {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
|
||||
}),
|
||||
@ -84,18 +84,18 @@ static const struct override_status_id override_status_ids[] = {
|
||||
* The INT0002 device is necessary to clear wakeup interrupt sources
|
||||
* on Cherry Trail devices, without it we get nobody cared IRQ msgs.
|
||||
*/
|
||||
PRESENT_ENTRY_HID("INT0002", "1", ATOM_AIRMONT, {}),
|
||||
PRESENT_ENTRY_HID("INT0002", "1", INTEL_ATOM_AIRMONT, {}),
|
||||
/*
|
||||
* On the Dell Venue 11 Pro 7130 and 7139, the DSDT hides
|
||||
* the touchscreen ACPI device until a certain time
|
||||
* after _SB.PCI0.GFX0.LCD.LCD1._ON gets called has passed
|
||||
* *and* _STA has been called at least 3 times since.
|
||||
*/
|
||||
PRESENT_ENTRY_HID("SYNA7500", "1", HASWELL_L, {
|
||||
PRESENT_ENTRY_HID("SYNA7500", "1", INTEL_HASWELL_L, {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7130"),
|
||||
}),
|
||||
PRESENT_ENTRY_HID("SYNA7500", "1", HASWELL_L, {
|
||||
PRESENT_ENTRY_HID("SYNA7500", "1", INTEL_HASWELL_L, {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 11 Pro 7139"),
|
||||
}),
|
||||
@ -104,7 +104,7 @@ static const struct override_status_id override_status_ids[] = {
|
||||
* The Dell XPS 15 9550 has a SMO8110 accelerometer /
|
||||
* HDD freefall sensor which is wrongly marked as not present.
|
||||
*/
|
||||
PRESENT_ENTRY_HID("SMO8810", "1", SKYLAKE, {
|
||||
PRESENT_ENTRY_HID("SMO8810", "1", INTEL_SKYLAKE, {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "XPS 15 9550"),
|
||||
}),
|
||||
@ -121,19 +121,19 @@ static const struct override_status_id override_status_ids[] = {
|
||||
* was copy-pasted from the GPD win, so it has a disabled KIOX000A
|
||||
* node which we should not enable, thus we also check the BIOS date.
|
||||
*/
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, {
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", INTEL_ATOM_AIRMONT, {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Default string"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
|
||||
DMI_MATCH(DMI_BIOS_DATE, "02/21/2017")
|
||||
}),
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, {
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", INTEL_ATOM_AIRMONT, {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Default string"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
|
||||
DMI_MATCH(DMI_BIOS_DATE, "03/20/2017")
|
||||
}),
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", ATOM_AIRMONT, {
|
||||
PRESENT_ENTRY_HID("KIOX000A", "1", INTEL_ATOM_AIRMONT, {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Default string"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
|
||||
@ -146,7 +146,7 @@ static const struct override_status_id override_status_ids[] = {
|
||||
* method sets a GPIO causing the PCI wifi card to turn off.
|
||||
* See above remark about uniqueness of the DMI match.
|
||||
*/
|
||||
NOT_PRESENT_ENTRY_PATH("\\_SB_.PCI0.SDHB.BRC1", ATOM_AIRMONT, {
|
||||
NOT_PRESENT_ENTRY_PATH("\\_SB_.PCI0.SDHB.BRC1", INTEL_ATOM_AIRMONT, {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
|
||||
DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
|
||||
@ -158,7 +158,7 @@ static const struct override_status_id override_status_ids[] = {
|
||||
* as both ACCL0001 and MAGN0001. As we can only ever register an
|
||||
* i2c client for one of them, ignore MAGN0001.
|
||||
*/
|
||||
NOT_PRESENT_ENTRY_HID("MAGN0001", "1", ATOM_SILVERMONT, {
|
||||
NOT_PRESENT_ENTRY_HID("MAGN0001", "1", INTEL_ATOM_SILVERMONT, {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "YOGATablet2"),
|
||||
}),
|
||||
|
Loading…
Reference in New Issue
Block a user