Skip to content

Commit f62f012

Browse files
Johannes Stezenbachij-intel
authored andcommitted
x86/platform/atom: Check state of Punit managed devices on s2idle
For the Bay Trail or Cherry Trail SoC to enter the S0i3 power-level at s2idle suspend requires most of the hw-blocks / devices in the SoC to be in D3 when entering s2idle suspend. If some devices are not in D3 then the SoC will stay in a higher power state, consuming much more power from the battery then in S0i3. Use the new acpi_s2idle_dev_ops and acpi_register_lps0_dev() functionality to register a new s2idle check function which checks that all hardware blocks in the North complex (controlled by Punit) are in a state that allows the SoC to enter S0i3 and prints an error message for any device in D0. Signed-off-by: Johannes Stezenbach <[email protected]> Signed-off-by: Takashi Iwai <[email protected]> Acked-by: "Borislav Petkov (AMD)" <[email protected]> Reviewed-by: Ilpo Järvinen <[email protected]> [hdegoede: Use acpi_s2idle_dev_ops] Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ilpo Järvinen <[email protected]>
1 parent 86cef45 commit f62f012

File tree

1 file changed

+53
-1
lines changed

1 file changed

+53
-1
lines changed

arch/x86/platform/atom/punit_atom_debug.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
* Copyright (c) 2015, Intel Corporation.
88
*/
99

10+
#define pr_fmt(fmt) "punit_atom: " fmt
11+
12+
#include <linux/acpi.h>
1013
#include <linux/module.h>
1114
#include <linux/init.h>
1215
#include <linux/device.h>
@@ -117,6 +120,51 @@ static void punit_dbgfs_unregister(void)
117120
debugfs_remove_recursive(punit_dbg_file);
118121
}
119122

123+
#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
124+
static const struct punit_device *punit_dev;
125+
126+
static void punit_s2idle_check(void)
127+
{
128+
const struct punit_device *punit_devp;
129+
u32 punit_pwr_status, dstate;
130+
int status;
131+
132+
for (punit_devp = punit_dev; punit_devp->name; punit_devp++) {
133+
/* Skip MIO, it is on till the very last moment */
134+
if (punit_devp->reg == MIO_SS_PM)
135+
continue;
136+
137+
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
138+
punit_devp->reg, &punit_pwr_status);
139+
if (status) {
140+
pr_err("%s read failed\n", punit_devp->name);
141+
} else {
142+
dstate = (punit_pwr_status >> punit_devp->sss_pos) & 3;
143+
if (!dstate)
144+
pr_err("%s is in D0 prior to s2idle\n", punit_devp->name);
145+
}
146+
}
147+
}
148+
149+
static struct acpi_s2idle_dev_ops punit_s2idle_ops = {
150+
.check = punit_s2idle_check,
151+
};
152+
153+
static void punit_s2idle_check_register(struct punit_device *punit_device)
154+
{
155+
punit_dev = punit_device;
156+
acpi_register_lps0_dev(&punit_s2idle_ops);
157+
}
158+
159+
static void punit_s2idle_check_unregister(void)
160+
{
161+
acpi_unregister_lps0_dev(&punit_s2idle_ops);
162+
}
163+
#else
164+
static void punit_s2idle_check_register(struct punit_device *punit_device) {}
165+
static void punit_s2idle_check_unregister(void) {}
166+
#endif
167+
120168
#define X86_MATCH(model, data) \
121169
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
122170
X86_FEATURE_MWAIT, data)
@@ -131,19 +179,23 @@ MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
131179

132180
static int __init punit_atom_debug_init(void)
133181
{
182+
struct punit_device *punit_device;
134183
const struct x86_cpu_id *id;
135184

136185
id = x86_match_cpu(intel_punit_cpu_ids);
137186
if (!id)
138187
return -ENODEV;
139188

140-
punit_dbgfs_register((struct punit_device *)id->driver_data);
189+
punit_device = (struct punit_device *)id->driver_data;
190+
punit_dbgfs_register(punit_device);
191+
punit_s2idle_check_register(punit_device);
141192

142193
return 0;
143194
}
144195

145196
static void __exit punit_atom_debug_exit(void)
146197
{
198+
punit_s2idle_check_unregister();
147199
punit_dbgfs_unregister();
148200
}
149201

0 commit comments

Comments
 (0)