Skip to content

Commit 48ccded

Browse files
committed
Merge branches 'acpi-apei', 'acpi-pmic', 'acpi-video' and 'acpi-dptf'
* acpi-apei: arm64: acpi: Make apei_claim_sea() synchronise with APEI's irq work ACPI: APEI: Kick the memory_failure() queue for synchronous errors mm/memory-failure: Add memory_failure_queue_kick() * acpi-pmic: ACPI / PMIC: Add i2c address for thermal control * acpi-video: ACPI: video: Use native backlight on Acer TravelMate 5735Z * acpi-dptf: ACPI: DPTF: Add battery participant driver ACPI: DPTF: Additional sysfs attributes for power participant driver
5 parents 228b79a + 8fcc4ae + cc0594c + c41c36e + 7b52b20 commit 48ccded

File tree

10 files changed

+313
-30
lines changed

10 files changed

+313
-30
lines changed

Documentation/ABI/testing/sysfs-platform-dptf

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,68 @@ KernelVersion: v4.10
2727
2828
Description:
2929
(RO) Display the platform power source
30-
0x00 = DC
31-
0x01 = AC
32-
0x02 = USB
33-
0x03 = Wireless Charger
30+
bits[3:0] Current power source
31+
0x00 = DC
32+
0x01 = AC
33+
0x02 = USB
34+
0x03 = Wireless Charger
35+
bits[7:4] Power source sequence number
3436

3537
What: /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power
3638
Date: Jul, 2016
3739
KernelVersion: v4.10
3840
3941
Description:
4042
(RO) The maximum sustained power for battery in milliwatts.
43+
44+
What: /sys/bus/platform/devices/INT3407:00/dptf_power/rest_of_platform_power_mw
45+
Date: June, 2020
46+
KernelVersion: v5.8
47+
48+
Description:
49+
(RO) Shows the rest (outside of SoC) of worst-case platform power.
50+
51+
What: /sys/bus/platform/devices/INT3407:00/dptf_power/prochot_confirm
52+
Date: June, 2020
53+
KernelVersion: v5.8
54+
55+
Description:
56+
(WO) Confirm embedded controller about a prochot notification.
57+
58+
What: /sys/bus/platform/devices/INT3532:00/dptf_battery/max_platform_power_mw
59+
Date: June, 2020
60+
KernelVersion: v5.8
61+
62+
Description:
63+
(RO) The maximum platform power that can be supported by the battery in milli watts.
64+
65+
What: /sys/bus/platform/devices/INT3532:00/dptf_battery/max_steady_state_power_mw
66+
Date: June, 2020
67+
KernelVersion: v5.8
68+
69+
Description:
70+
(RO) The maximum sustained power for battery in milli watts.
71+
72+
What: /sys/bus/platform/devices/INT3532:00/dptf_battery/high_freq_impedance_mohm
73+
Date: June, 2020
74+
KernelVersion: v5.8
75+
76+
Description:
77+
(RO) The high frequency impedance value that can be obtained from battery
78+
fuel gauge in milli Ohms.
79+
80+
What: /sys/bus/platform/devices/INT3532:00/dptf_battery/no_load_voltage_mv
81+
Date: June, 2020
82+
KernelVersion: v5.8
83+
84+
Description:
85+
(RO) The no-load voltage that can be obtained from battery fuel gauge in
86+
milli volts.
87+
88+
What: /sys/bus/platform/devices/INT3532:00/dptf_battery/current_discharge_capbility_ma
89+
Date: June, 2020
90+
KernelVersion: v5.8
91+
92+
Description:
93+
(RO) The battery discharge current capability obtained from battery fuel gauge in
94+
milli Amps.

arch/arm64/kernel/acpi.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/init.h>
2020
#include <linux/irq.h>
2121
#include <linux/irqdomain.h>
22+
#include <linux/irq_work.h>
2223
#include <linux/memblock.h>
2324
#include <linux/of_fdt.h>
2425
#include <linux/smp.h>
@@ -269,13 +270,20 @@ pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
269270
int apei_claim_sea(struct pt_regs *regs)
270271
{
271272
int err = -ENOENT;
273+
bool return_to_irqs_enabled;
272274
unsigned long current_flags;
273275

274276
if (!IS_ENABLED(CONFIG_ACPI_APEI_GHES))
275277
return err;
276278

277279
current_flags = local_daif_save_flags();
278280

281+
/* current_flags isn't useful here as daif doesn't tell us about pNMI */
282+
return_to_irqs_enabled = !irqs_disabled_flags(arch_local_save_flags());
283+
284+
if (regs)
285+
return_to_irqs_enabled = interrupts_enabled(regs);
286+
279287
/*
280288
* SEA can interrupt SError, mask it and describe this as an NMI so
281289
* that APEI defers the handling.
@@ -284,6 +292,23 @@ int apei_claim_sea(struct pt_regs *regs)
284292
nmi_enter();
285293
err = ghes_notify_sea();
286294
nmi_exit();
295+
296+
/*
297+
* APEI NMI-like notifications are deferred to irq_work. Unless
298+
* we interrupted irqs-masked code, we can do that now.
299+
*/
300+
if (!err) {
301+
if (return_to_irqs_enabled) {
302+
local_daif_restore(DAIF_PROCCTX_NOIRQ);
303+
__irq_enter();
304+
irq_work_run();
305+
__irq_exit();
306+
} else {
307+
pr_warn_ratelimited("APEI work queued but not completed");
308+
err = -EINPROGRESS;
309+
}
310+
}
311+
287312
local_daif_restore(current_flags);
288313

289314
return err;

arch/arm64/mm/fault.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -635,11 +635,13 @@ static int do_sea(unsigned long addr, unsigned int esr, struct pt_regs *regs)
635635

636636
inf = esr_to_fault_info(esr);
637637

638-
/*
639-
* Return value ignored as we rely on signal merging.
640-
* Future patches will make this more robust.
641-
*/
642-
apei_claim_sea(regs);
638+
if (user_mode(regs) && apei_claim_sea(regs) == 0) {
639+
/*
640+
* APEI claimed this as a firmware-first notification.
641+
* Some processing deferred to task_work before ret_to_user().
642+
*/
643+
return 0;
644+
}
643645

644646
if (esr & ESR_ELx_FnV)
645647
siaddr = NULL;

drivers/acpi/apei/ghes.c

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <linux/sched/clock.h>
4141
#include <linux/uuid.h>
4242
#include <linux/ras.h>
43+
#include <linux/task_work.h>
4344

4445
#include <acpi/actbl1.h>
4546
#include <acpi/ghes.h>
@@ -414,23 +415,46 @@ static void ghes_clear_estatus(struct ghes *ghes,
414415
ghes_ack_error(ghes->generic_v2);
415416
}
416417

417-
static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
418+
/*
419+
* Called as task_work before returning to user-space.
420+
* Ensure any queued work has been done before we return to the context that
421+
* triggered the notification.
422+
*/
423+
static void ghes_kick_task_work(struct callback_head *head)
424+
{
425+
struct acpi_hest_generic_status *estatus;
426+
struct ghes_estatus_node *estatus_node;
427+
u32 node_len;
428+
429+
estatus_node = container_of(head, struct ghes_estatus_node, task_work);
430+
if (IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
431+
memory_failure_queue_kick(estatus_node->task_work_cpu);
432+
433+
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
434+
node_len = GHES_ESTATUS_NODE_LEN(cper_estatus_len(estatus));
435+
gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node, node_len);
436+
}
437+
438+
static bool ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata,
439+
int sev)
418440
{
419-
#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
420441
unsigned long pfn;
421442
int flags = -1;
422443
int sec_sev = ghes_severity(gdata->error_severity);
423444
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
424445

446+
if (!IS_ENABLED(CONFIG_ACPI_APEI_MEMORY_FAILURE))
447+
return false;
448+
425449
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
426-
return;
450+
return false;
427451

428452
pfn = mem_err->physical_addr >> PAGE_SHIFT;
429453
if (!pfn_valid(pfn)) {
430454
pr_warn_ratelimited(FW_WARN GHES_PFX
431455
"Invalid address in generic error data: %#llx\n",
432456
mem_err->physical_addr);
433-
return;
457+
return false;
434458
}
435459

436460
/* iff following two events can be handled properly by now */
@@ -440,9 +464,12 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
440464
if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE)
441465
flags = 0;
442466

443-
if (flags != -1)
467+
if (flags != -1) {
444468
memory_failure_queue(pfn, flags);
445-
#endif
469+
return true;
470+
}
471+
472+
return false;
446473
}
447474

448475
/*
@@ -490,14 +517,15 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
490517
#endif
491518
}
492519

493-
static void ghes_do_proc(struct ghes *ghes,
520+
static bool ghes_do_proc(struct ghes *ghes,
494521
const struct acpi_hest_generic_status *estatus)
495522
{
496523
int sev, sec_sev;
497524
struct acpi_hest_generic_data *gdata;
498525
guid_t *sec_type;
499526
const guid_t *fru_id = &guid_null;
500527
char *fru_text = "";
528+
bool queued = false;
501529

502530
sev = ghes_severity(estatus->error_severity);
503531
apei_estatus_for_each_section(estatus, gdata) {
@@ -515,7 +543,7 @@ static void ghes_do_proc(struct ghes *ghes,
515543
ghes_edac_report_mem_error(sev, mem_err);
516544

517545
arch_apei_report_mem_error(sev, mem_err);
518-
ghes_handle_memory_failure(gdata, sev);
546+
queued = ghes_handle_memory_failure(gdata, sev);
519547
}
520548
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
521549
ghes_handle_aer(gdata);
@@ -532,6 +560,8 @@ static void ghes_do_proc(struct ghes *ghes,
532560
gdata->error_data_length);
533561
}
534562
}
563+
564+
return queued;
535565
}
536566

537567
static void __ghes_print_estatus(const char *pfx,
@@ -827,7 +857,9 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
827857
struct ghes_estatus_node *estatus_node;
828858
struct acpi_hest_generic *generic;
829859
struct acpi_hest_generic_status *estatus;
860+
bool task_work_pending;
830861
u32 len, node_len;
862+
int ret;
831863

832864
llnode = llist_del_all(&ghes_estatus_llist);
833865
/*
@@ -842,14 +874,26 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
842874
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
843875
len = cper_estatus_len(estatus);
844876
node_len = GHES_ESTATUS_NODE_LEN(len);
845-
ghes_do_proc(estatus_node->ghes, estatus);
877+
task_work_pending = ghes_do_proc(estatus_node->ghes, estatus);
846878
if (!ghes_estatus_cached(estatus)) {
847879
generic = estatus_node->generic;
848880
if (ghes_print_estatus(NULL, generic, estatus))
849881
ghes_estatus_cache_add(generic, estatus);
850882
}
851-
gen_pool_free(ghes_estatus_pool, (unsigned long)estatus_node,
852-
node_len);
883+
884+
if (task_work_pending && current->mm != &init_mm) {
885+
estatus_node->task_work.func = ghes_kick_task_work;
886+
estatus_node->task_work_cpu = smp_processor_id();
887+
ret = task_work_add(current, &estatus_node->task_work,
888+
true);
889+
if (ret)
890+
estatus_node->task_work.func = NULL;
891+
}
892+
893+
if (!estatus_node->task_work.func)
894+
gen_pool_free(ghes_estatus_pool,
895+
(unsigned long)estatus_node, node_len);
896+
853897
llnode = next;
854898
}
855899
}
@@ -909,6 +953,7 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
909953

910954
estatus_node->ghes = ghes;
911955
estatus_node->generic = ghes->generic;
956+
estatus_node->task_work.func = NULL;
912957
estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
913958

914959
if (__ghes_read_estatus(estatus, buf_paddr, fixmap_idx, len)) {

0 commit comments

Comments
 (0)