Skip to content

Commit 24b2b09

Browse files
committed
Merge branches 'acpi-ec', 'acpi-cppc', 'acpi-fan' and 'acpi-battery'
Merge ACPI EC driver changes, CPPC-related changes, ACPI fan driver changes and ACPI battery driver changes for 5.18-rc1: - Make wakeup events checks in the ACPI EC driver more straightforward and clean up acpi_ec_submit_event() (Rafael Wysocki). - Make it possible to obtain the CPU capacity with the help of CPPC information (Ionela Voinescu). - Improve fine grained fan control in the ACPI fan driver and document it (Srinivas Pandruvada). - Add device HID and quirk for Microsoft Surface Go 3 to the ACPI battery driver (Maximilian Luz). * acpi-ec: ACPI: EC: Rearrange code in acpi_ec_submit_event() ACPI: EC: Reduce indentation level in acpi_ec_submit_event() ACPI: EC: Do not return result from advance_transaction() * acpi-cppc: arm64, topology: enable use of init_cpu_capacity_cppc() arch_topology: obtain cpu capacity using information from CPPC x86, ACPI: rename init_freq_invariance_cppc() to arch_init_invariance_cppc() * acpi-fan: Documentation/admin-guide/acpi: Add documentation for fine grain control ACPI: fan: Add additional attributes for fine grain control ACPI: fan: Properly handle fine grain control ACPI: fan: Optimize struct acpi_fan_fif ACPI: fan: Separate file for attributes creation ACPI: fan: Fix error reporting to user space * acpi-battery: ACPI: battery: Add device HID and quirk for Microsoft Surface Go 3
5 parents 03d5c98 + 13a62d0 + 8290931 + 0750b8f + 7dacee0 commit 24b2b09

12 files changed

Lines changed: 409 additions & 165 deletions

File tree

Documentation/admin-guide/acpi/fan_performance_states.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,31 @@ For example::
6060

6161
When a given field is not populated or its value provided by the platform
6262
firmware is invalid, the "not-defined" string is shown instead of the value.
63+
64+
ACPI Fan Fine Grain Control
65+
=============================
66+
67+
When _FIF object specifies support for fine grain control, then fan speed
68+
can be set from 0 to 100% with the recommended minimum "step size" via
69+
_FSL object. User can adjust fan speed using thermal sysfs cooling device.
70+
71+
Here use can look at fan performance states for a reference speed (speed_rpm)
72+
and set it by changing cooling device cur_state. If the fine grain control
73+
is supported then user can also adjust to some other speeds which are
74+
not defined in the performance states.
75+
76+
The support of fine grain control is presented via sysfs attribute
77+
"fine_grain_control". If fine grain control is present, this attribute
78+
will show "1" otherwise "0".
79+
80+
This sysfs attribute is presented in the same directory as performance states.
81+
82+
ACPI Fan Performance Feedback
83+
=============================
84+
85+
The optional _FST object provides status information for the fan device.
86+
This includes field to provide current fan speed in revolutions per minute
87+
at which the fan is rotating.
88+
89+
This speed is presented in the sysfs using the attribute "fan_speed_rpm",
90+
in the same directory as performance states.

arch/arm64/include/asm/topology.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ void update_freq_counters_refs(void);
2424
#define arch_scale_freq_capacity topology_get_freq_scale
2525
#define arch_scale_freq_invariant topology_scale_freq_invariant
2626

27+
#ifdef CONFIG_ACPI_CPPC_LIB
28+
#define arch_init_invariance_cppc topology_init_cpu_capacity_cppc
29+
#endif
30+
2731
/* Replace task scheduler's default cpu-invariant accounting */
2832
#define arch_scale_cpu_capacity topology_get_cpu_scale
2933

arch/x86/include/asm/topology.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ static inline void init_freq_invariance(bool secondary, bool cppc_ready)
227227

228228
#ifdef CONFIG_ACPI_CPPC_LIB
229229
void init_freq_invariance_cppc(void);
230-
#define init_freq_invariance_cppc init_freq_invariance_cppc
230+
#define arch_init_invariance_cppc init_freq_invariance_cppc
231231

232232
bool amd_set_max_freq_ratio(u64 *ratio);
233233
#else

drivers/acpi/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ obj-$(CONFIG_ACPI_AC) += ac.o
8181
obj-$(CONFIG_ACPI_BUTTON) += button.o
8282
obj-$(CONFIG_ACPI_TINY_POWER_BUTTON) += tiny-power-button.o
8383
obj-$(CONFIG_ACPI_FAN) += fan.o
84+
fan-objs := fan_core.o
85+
fan-objs += fan_attr.o
86+
8487
obj-$(CONFIG_ACPI_VIDEO) += video.o
8588
obj-$(CONFIG_ACPI_TAD) += acpi_tad.o
8689
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o

drivers/acpi/battery.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
5959

6060
static const struct acpi_device_id battery_device_ids[] = {
6161
{"PNP0C0A", 0},
62+
63+
/* Microsoft Surface Go 3 */
64+
{"MSHW0146", 0},
65+
6266
{"", 0},
6367
};
6468

@@ -1148,6 +1152,14 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
11481152
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad"),
11491153
},
11501154
},
1155+
{
1156+
/* Microsoft Surface Go 3 */
1157+
.callback = battery_notification_delay_quirk,
1158+
.matches = {
1159+
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
1160+
DMI_MATCH(DMI_PRODUCT_NAME, "Surface Go 3"),
1161+
},
1162+
},
11511163
{},
11521164
};
11531165

drivers/acpi/cppc_acpi.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -633,8 +633,8 @@ static bool is_cppc_supported(int revision, int num_ent)
633633
* )
634634
*/
635635

636-
#ifndef init_freq_invariance_cppc
637-
static inline void init_freq_invariance_cppc(void) { }
636+
#ifndef arch_init_invariance_cppc
637+
static inline void arch_init_invariance_cppc(void) { }
638638
#endif
639639

640640
/**
@@ -819,7 +819,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
819819
goto out_free;
820820
}
821821

822-
init_freq_invariance_cppc();
822+
arch_init_invariance_cppc();
823823

824824
kfree(output.pointer);
825825
return 0;

drivers/acpi/ec.c

Lines changed: 45 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ struct acpi_ec_query {
168168
};
169169

170170
static int acpi_ec_submit_query(struct acpi_ec *ec);
171-
static bool advance_transaction(struct acpi_ec *ec, bool interrupt);
171+
static void advance_transaction(struct acpi_ec *ec, bool interrupt);
172172
static void acpi_ec_event_handler(struct work_struct *work);
173173

174174
struct acpi_ec *first_ec;
@@ -441,36 +441,35 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
441441
return true;
442442
}
443443

444-
static bool acpi_ec_submit_event(struct acpi_ec *ec)
444+
static void acpi_ec_submit_event(struct acpi_ec *ec)
445445
{
446+
/*
447+
* It is safe to mask the events here, because acpi_ec_close_event()
448+
* will run at least once after this.
449+
*/
446450
acpi_ec_mask_events(ec);
447451
if (!acpi_ec_event_enabled(ec))
448-
return false;
449-
450-
if (ec->event_state == EC_EVENT_READY) {
451-
ec_dbg_evt("Command(%s) submitted/blocked",
452-
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
452+
return;
453453

454-
ec->event_state = EC_EVENT_IN_PROGRESS;
455-
/*
456-
* If events_to_process is greqter than 0 at this point, the
457-
* while () loop in acpi_ec_event_handler() is still running
458-
* and incrementing events_to_process will cause it to invoke
459-
* acpi_ec_submit_query() once more, so it is not necessary to
460-
* queue up the event work to start the same loop again.
461-
*/
462-
if (ec->events_to_process++ > 0)
463-
return true;
454+
if (ec->event_state != EC_EVENT_READY)
455+
return;
464456

465-
ec->events_in_progress++;
466-
return queue_work(ec_wq, &ec->work);
467-
}
457+
ec_dbg_evt("Command(%s) submitted/blocked",
458+
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
468459

460+
ec->event_state = EC_EVENT_IN_PROGRESS;
469461
/*
470-
* The event handling work has not been completed yet, so it needs to be
471-
* flushed.
462+
* If events_to_process is greater than 0 at this point, the while ()
463+
* loop in acpi_ec_event_handler() is still running and incrementing
464+
* events_to_process will cause it to invoke acpi_ec_submit_query() once
465+
* more, so it is not necessary to queue up the event work to start the
466+
* same loop again.
472467
*/
473-
return true;
468+
if (ec->events_to_process++ > 0)
469+
return;
470+
471+
ec->events_in_progress++;
472+
queue_work(ec_wq, &ec->work);
474473
}
475474

476475
static void acpi_ec_complete_event(struct acpi_ec *ec)
@@ -655,11 +654,10 @@ static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t
655654
acpi_ec_mask_events(ec);
656655
}
657656

658-
static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
657+
static void advance_transaction(struct acpi_ec *ec, bool interrupt)
659658
{
660659
struct transaction *t = ec->curr;
661660
bool wakeup = false;
662-
bool ret = false;
663661
u8 status;
664662

665663
ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
@@ -724,12 +722,10 @@ static bool advance_transaction(struct acpi_ec *ec, bool interrupt)
724722

725723
out:
726724
if (status & ACPI_EC_FLAG_SCI)
727-
ret = acpi_ec_submit_event(ec);
725+
acpi_ec_submit_event(ec);
728726

729727
if (wakeup && interrupt)
730728
wake_up(&ec->wait);
731-
732-
return ret;
733729
}
734730

735731
static void start_transaction(struct acpi_ec *ec)
@@ -1242,6 +1238,7 @@ static void acpi_ec_event_handler(struct work_struct *work)
12421238
acpi_ec_submit_query(ec);
12431239

12441240
spin_lock_irq(&ec->lock);
1241+
12451242
ec->events_to_process--;
12461243
}
12471244

@@ -1250,27 +1247,30 @@ static void acpi_ec_event_handler(struct work_struct *work)
12501247
* event handling work again regardless of whether or not the query
12511248
* queued up above is processed successfully.
12521249
*/
1253-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT)
1250+
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
1251+
bool guard_timeout;
1252+
12541253
acpi_ec_complete_event(ec);
1255-
else
1256-
acpi_ec_close_event(ec);
12571254

1258-
spin_unlock_irq(&ec->lock);
1255+
ec_dbg_evt("Event stopped");
1256+
1257+
spin_unlock_irq(&ec->lock);
12591258

1260-
ec_dbg_evt("Event stopped");
1259+
guard_timeout = !!ec_guard(ec);
12611260

1262-
if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT && ec_guard(ec)) {
12631261
spin_lock_irq(&ec->lock);
12641262

12651263
/* Take care of SCI_EVT unless someone else is doing that. */
1266-
if (!ec->curr)
1264+
if (guard_timeout && !ec->curr)
12671265
advance_transaction(ec, false);
1266+
} else {
1267+
acpi_ec_close_event(ec);
12681268

1269-
spin_unlock_irq(&ec->lock);
1269+
ec_dbg_evt("Event stopped");
12701270
}
12711271

1272-
spin_lock_irq(&ec->lock);
12731272
ec->events_in_progress--;
1273+
12741274
spin_unlock_irq(&ec->lock);
12751275
}
12761276

@@ -2051,6 +2051,11 @@ void acpi_ec_set_gpe_wake_mask(u8 action)
20512051
acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
20522052
}
20532053

2054+
static bool acpi_ec_work_in_progress(struct acpi_ec *ec)
2055+
{
2056+
return ec->events_in_progress + ec->queries_in_progress > 0;
2057+
}
2058+
20542059
bool acpi_ec_dispatch_gpe(void)
20552060
{
20562061
bool work_in_progress = false;
@@ -2084,7 +2089,8 @@ bool acpi_ec_dispatch_gpe(void)
20842089
if (acpi_ec_gpe_status_set(first_ec)) {
20852090
pm_pr_dbg("ACPI EC GPE status set\n");
20862091

2087-
work_in_progress = advance_transaction(first_ec, false);
2092+
advance_transaction(first_ec, false);
2093+
work_in_progress = acpi_ec_work_in_progress(first_ec);
20882094
}
20892095

20902096
spin_unlock_irq(&first_ec->lock);
@@ -2102,8 +2108,7 @@ bool acpi_ec_dispatch_gpe(void)
21022108

21032109
spin_lock_irq(&first_ec->lock);
21042110

2105-
work_in_progress = first_ec->events_in_progress +
2106-
first_ec->queries_in_progress > 0;
2111+
work_in_progress = acpi_ec_work_in_progress(first_ec);
21072112

21082113
spin_unlock_irq(&first_ec->lock);
21092114
} while (work_in_progress && !pm_wakeup_pending());

drivers/acpi/fan.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,53 @@
66
*
77
* Add new device IDs before the generic ACPI fan one.
88
*/
9+
10+
#ifndef _ACPI_FAN_H_
11+
#define _ACPI_FAN_H_
12+
913
#define ACPI_FAN_DEVICE_IDS \
1014
{"INT3404", }, /* Fan */ \
1115
{"INTC1044", }, /* Fan for Tiger Lake generation */ \
1216
{"INTC1048", }, /* Fan for Alder Lake generation */ \
1317
{"INTC10A2", }, /* Fan for Raptor Lake generation */ \
1418
{"PNP0C0B", } /* Generic ACPI fan */
19+
20+
#define ACPI_FPS_NAME_LEN 20
21+
22+
struct acpi_fan_fps {
23+
u64 control;
24+
u64 trip_point;
25+
u64 speed;
26+
u64 noise_level;
27+
u64 power;
28+
char name[ACPI_FPS_NAME_LEN];
29+
struct device_attribute dev_attr;
30+
};
31+
32+
struct acpi_fan_fif {
33+
u8 revision;
34+
u8 fine_grain_ctrl;
35+
u8 step_size;
36+
u8 low_speed_notification;
37+
};
38+
39+
struct acpi_fan_fst {
40+
u64 revision;
41+
u64 control;
42+
u64 speed;
43+
};
44+
45+
struct acpi_fan {
46+
bool acpi4;
47+
struct acpi_fan_fif fif;
48+
struct acpi_fan_fps *fps;
49+
int fps_count;
50+
struct thermal_cooling_device *cdev;
51+
struct device_attribute fst_speed;
52+
struct device_attribute fine_grain_control;
53+
};
54+
55+
int acpi_fan_get_fst(struct acpi_device *device, struct acpi_fan_fst *fst);
56+
int acpi_fan_create_attributes(struct acpi_device *device);
57+
void acpi_fan_delete_attributes(struct acpi_device *device);
58+
#endif

0 commit comments

Comments
 (0)