Skip to content

Commit ab01f96

Browse files
committed
Merge tag 'pm+acpi-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI and power management fixes from Rafael Wysocki: "These are fixes received after my previous pull request plus one that has been in the works for quite a while, but its previous version caused problems to happen, so it's been deferred till now. Fixed are two recent regressions (MFD enumeration and cpufreq-dt), ACPI EC regression introduced in 3.17, system suspend error code path regression introduced in 3.15, an older bug related to recovery from failing resume from hibernation and a cpufreq-dt driver issue related to operation performance points. Specifics: - Fix a crash on r8a7791/koelsch during resume from system suspend caused by a recent cpufreq-dt commit (Geert Uytterhoeven). - Fix an MFD enumeration problem introduced by a recent commit adding ACPI support to the MFD subsystem that exposed a weakness in the ACPI core causing ACPI enumeration to be applied to all devices associated with one ACPI companion object, although it should be used for one of them only (Mika Westerberg). - Fix an ACPI EC regression introduced during the 3.17 cycle causing some Samsung laptops to misbehave as a result of a workaround targeted at some Acer machines. That includes a revert of a commit that went too far and a quirk for the Acer machines in question. From Lv Zheng. - Fix a regression in the system suspend error code path introduced during the 3.15 cycle that causes it to fail to take errors from asychronous execution of "late" suspend callbacks into account (Imre Deak). - Fix a long-standing bug in the hibernation resume error code path that fails to roll back everything correcty on "freeze" callback errors and leaves some devices in a "suspended" state causing more breakage to happen subsequently (Imre Deak). - Make the cpufreq-dt driver disable operation performance points that are not supported by the VR connected to the CPU voltage plane with acceptable tolerance instead of constantly failing voltage scaling later on (Lucas Stach)" * tag 'pm+acpi-3.18-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / EC: Fix regression due to conflicting firmware behavior between Samsung and Acer. Revert "ACPI / EC: Add support to disallow QR_EC to be issued before completing previous QR_EC" cpufreq: cpufreq-dt: Restore default cpumask_setall(policy->cpus) PM / Sleep: fix recovery during resuming from hibernation PM / Sleep: fix async suspend_late/freeze_late error handling ACPI: Use ACPI companion to match only the first physical device cpufreq: cpufreq-dt: disable unsupported OPPs
2 parents 08da742 + 7d62728 commit ab01f96

File tree

5 files changed

+126
-53
lines changed

5 files changed

+126
-53
lines changed

drivers/acpi/ec.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
126126
static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
127127
static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
128128
static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
129+
static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
129130

130131
/* --------------------------------------------------------------------------
131132
* Transaction Management
@@ -236,13 +237,8 @@ static bool advance_transaction(struct acpi_ec *ec)
236237
}
237238
return wakeup;
238239
} else {
239-
/*
240-
* There is firmware refusing to respond QR_EC when SCI_EVT
241-
* is not set, for which case, we complete the QR_EC
242-
* without issuing it to the firmware.
243-
* https://bugzilla.kernel.org/show_bug.cgi?id=86211
244-
*/
245-
if (!(status & ACPI_EC_FLAG_SCI) &&
240+
if (EC_FLAGS_QUERY_HANDSHAKE &&
241+
!(status & ACPI_EC_FLAG_SCI) &&
246242
(t->command == ACPI_EC_COMMAND_QUERY)) {
247243
t->flags |= ACPI_EC_COMMAND_POLL;
248244
t->rdata[t->ri++] = 0x00;
@@ -334,13 +330,13 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
334330
pr_debug("***** Command(%s) started *****\n",
335331
acpi_ec_cmd_string(t->command));
336332
start_transaction(ec);
337-
spin_unlock_irqrestore(&ec->lock, tmp);
338-
ret = ec_poll(ec);
339-
spin_lock_irqsave(&ec->lock, tmp);
340333
if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
341334
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
342335
pr_debug("***** Event stopped *****\n");
343336
}
337+
spin_unlock_irqrestore(&ec->lock, tmp);
338+
ret = ec_poll(ec);
339+
spin_lock_irqsave(&ec->lock, tmp);
344340
pr_debug("***** Command(%s) stopped *****\n",
345341
acpi_ec_cmd_string(t->command));
346342
ec->curr = NULL;
@@ -1011,6 +1007,18 @@ static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
10111007
return 0;
10121008
}
10131009

1010+
/*
1011+
* Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
1012+
* which case, we complete the QR_EC without issuing it to the firmware.
1013+
* https://bugzilla.kernel.org/show_bug.cgi?id=86211
1014+
*/
1015+
static int ec_flag_query_handshake(const struct dmi_system_id *id)
1016+
{
1017+
pr_debug("Detected the EC firmware requiring QR_EC issued when SCI_EVT set\n");
1018+
EC_FLAGS_QUERY_HANDSHAKE = 1;
1019+
return 0;
1020+
}
1021+
10141022
/*
10151023
* On some hardware it is necessary to clear events accumulated by the EC during
10161024
* sleep. These ECs stop reporting GPEs until they are manually polled, if too
@@ -1085,6 +1093,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
10851093
{
10861094
ec_clear_on_resume, "Samsung hardware", {
10871095
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
1096+
{
1097+
ec_flag_query_handshake, "Acer hardware", {
1098+
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
10881099
{},
10891100
};
10901101

drivers/acpi/scan.c

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
141141
return len;
142142
}
143143

144+
/*
145+
* acpi_companion_match() - Can we match via ACPI companion device
146+
* @dev: Device in question
147+
*
148+
* Check if the given device has an ACPI companion and if that companion has
149+
* a valid list of PNP IDs, and if the device is the first (primary) physical
150+
* device associated with it.
151+
*
152+
* If multiple physical devices are attached to a single ACPI companion, we need
153+
* to be careful. The usage scenario for this kind of relationship is that all
154+
* of the physical devices in question use resources provided by the ACPI
155+
* companion. A typical case is an MFD device where all the sub-devices share
156+
* the parent's ACPI companion. In such cases we can only allow the primary
157+
* (first) physical device to be matched with the help of the companion's PNP
158+
* IDs.
159+
*
160+
* Additional physical devices sharing the ACPI companion can still use
161+
* resources available from it but they will be matched normally using functions
162+
* provided by their bus types (and analogously for their modalias).
163+
*/
164+
static bool acpi_companion_match(const struct device *dev)
165+
{
166+
struct acpi_device *adev;
167+
bool ret;
168+
169+
adev = ACPI_COMPANION(dev);
170+
if (!adev)
171+
return false;
172+
173+
if (list_empty(&adev->pnp.ids))
174+
return false;
175+
176+
mutex_lock(&adev->physical_node_lock);
177+
if (list_empty(&adev->physical_node_list)) {
178+
ret = false;
179+
} else {
180+
const struct acpi_device_physical_node *node;
181+
182+
node = list_first_entry(&adev->physical_node_list,
183+
struct acpi_device_physical_node, node);
184+
ret = node->dev == dev;
185+
}
186+
mutex_unlock(&adev->physical_node_lock);
187+
188+
return ret;
189+
}
190+
144191
/*
145192
* Creates uevent modalias field for ACPI enumerated devices.
146193
* Because the other buses does not support ACPI HIDs & CIDs.
@@ -149,20 +196,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
149196
*/
150197
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
151198
{
152-
struct acpi_device *acpi_dev;
153199
int len;
154200

155-
acpi_dev = ACPI_COMPANION(dev);
156-
if (!acpi_dev)
157-
return -ENODEV;
158-
159-
/* Fall back to bus specific way of modalias exporting */
160-
if (list_empty(&acpi_dev->pnp.ids))
201+
if (!acpi_companion_match(dev))
161202
return -ENODEV;
162203

163204
if (add_uevent_var(env, "MODALIAS="))
164205
return -ENOMEM;
165-
len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
206+
len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
166207
sizeof(env->buf) - env->buflen);
167208
if (len <= 0)
168209
return len;
@@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
179220
*/
180221
int acpi_device_modalias(struct device *dev, char *buf, int size)
181222
{
182-
struct acpi_device *acpi_dev;
183223
int len;
184224

185-
acpi_dev = ACPI_COMPANION(dev);
186-
if (!acpi_dev)
225+
if (!acpi_companion_match(dev))
187226
return -ENODEV;
188227

189-
/* Fall back to bus specific way of modalias exporting */
190-
if (list_empty(&acpi_dev->pnp.ids))
191-
return -ENODEV;
192-
193-
len = create_modalias(acpi_dev, buf, size -1);
228+
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
194229
if (len <= 0)
195230
return len;
196231
buf[len++] = '\n';
@@ -853,6 +888,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
853888
if (!ids || !handle || acpi_bus_get_device(handle, &adev))
854889
return NULL;
855890

891+
if (!acpi_companion_match(dev))
892+
return NULL;
893+
856894
return __acpi_match_device(adev, ids);
857895
}
858896
EXPORT_SYMBOL_GPL(acpi_match_device);

drivers/base/power/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ int dpm_suspend_late(pm_message_t state)
12661266
}
12671267
mutex_unlock(&dpm_list_mtx);
12681268
async_synchronize_full();
1269+
if (!error)
1270+
error = async_error;
12691271
if (error) {
12701272
suspend_stats.failed_suspend_late++;
12711273
dpm_save_failed_step(SUSPEND_SUSPEND_LATE);

drivers/cpufreq/cpufreq-dt.c

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
187187
struct device *cpu_dev;
188188
struct regulator *cpu_reg;
189189
struct clk *cpu_clk;
190+
unsigned long min_uV = ~0, max_uV = 0;
190191
unsigned int transition_latency;
191192
int ret;
192193

@@ -206,16 +207,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
206207
/* OPPs might be populated at runtime, don't check for error here */
207208
of_init_opp_table(cpu_dev);
208209

209-
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
210-
if (ret) {
211-
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
212-
goto out_put_node;
213-
}
214-
215210
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
216211
if (!priv) {
217212
ret = -ENOMEM;
218-
goto out_free_table;
213+
goto out_put_node;
219214
}
220215

221216
of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
@@ -224,30 +219,51 @@ static int cpufreq_init(struct cpufreq_policy *policy)
224219
transition_latency = CPUFREQ_ETERNAL;
225220

226221
if (!IS_ERR(cpu_reg)) {
227-
struct dev_pm_opp *opp;
228-
unsigned long min_uV, max_uV;
229-
int i;
222+
unsigned long opp_freq = 0;
230223

231224
/*
232-
* OPP is maintained in order of increasing frequency, and
233-
* freq_table initialised from OPP is therefore sorted in the
234-
* same order.
225+
* Disable any OPPs where the connected regulator isn't able to
226+
* provide the specified voltage and record minimum and maximum
227+
* voltage levels.
235228
*/
236-
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
237-
;
238-
rcu_read_lock();
239-
opp = dev_pm_opp_find_freq_exact(cpu_dev,
240-
freq_table[0].frequency * 1000, true);
241-
min_uV = dev_pm_opp_get_voltage(opp);
242-
opp = dev_pm_opp_find_freq_exact(cpu_dev,
243-
freq_table[i-1].frequency * 1000, true);
244-
max_uV = dev_pm_opp_get_voltage(opp);
245-
rcu_read_unlock();
229+
while (1) {
230+
struct dev_pm_opp *opp;
231+
unsigned long opp_uV, tol_uV;
232+
233+
rcu_read_lock();
234+
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &opp_freq);
235+
if (IS_ERR(opp)) {
236+
rcu_read_unlock();
237+
break;
238+
}
239+
opp_uV = dev_pm_opp_get_voltage(opp);
240+
rcu_read_unlock();
241+
242+
tol_uV = opp_uV * priv->voltage_tolerance / 100;
243+
if (regulator_is_supported_voltage(cpu_reg, opp_uV,
244+
opp_uV + tol_uV)) {
245+
if (opp_uV < min_uV)
246+
min_uV = opp_uV;
247+
if (opp_uV > max_uV)
248+
max_uV = opp_uV;
249+
} else {
250+
dev_pm_opp_disable(cpu_dev, opp_freq);
251+
}
252+
253+
opp_freq++;
254+
}
255+
246256
ret = regulator_set_voltage_time(cpu_reg, min_uV, max_uV);
247257
if (ret > 0)
248258
transition_latency += ret * 1000;
249259
}
250260

261+
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
262+
if (ret) {
263+
pr_err("failed to init cpufreq table: %d\n", ret);
264+
goto out_free_priv;
265+
}
266+
251267
/*
252268
* For now, just loading the cooling device;
253269
* thermal DT code takes care of matching them.
@@ -277,7 +293,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
277293
policy->cpuinfo.transition_latency = transition_latency;
278294

279295
pd = cpufreq_get_driver_data();
280-
if (pd && !pd->independent_clocks)
296+
if (!pd || !pd->independent_clocks)
281297
cpumask_setall(policy->cpus);
282298

283299
of_node_put(np);
@@ -286,9 +302,9 @@ static int cpufreq_init(struct cpufreq_policy *policy)
286302

287303
out_cooling_unregister:
288304
cpufreq_cooling_unregister(priv->cdev);
289-
kfree(priv);
290-
out_free_table:
291305
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
306+
out_free_priv:
307+
kfree(priv);
292308
out_put_node:
293309
of_node_put(np);
294310
out_put_reg_clk:

kernel/power/hibernate.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,14 @@ int hibernation_restore(int platform_mode)
502502
error = dpm_suspend_start(PMSG_QUIESCE);
503503
if (!error) {
504504
error = resume_target_kernel(platform_mode);
505-
dpm_resume_end(PMSG_RECOVER);
505+
/*
506+
* The above should either succeed and jump to the new kernel,
507+
* or return with an error. Otherwise things are just
508+
* undefined, so let's be paranoid.
509+
*/
510+
BUG_ON(!error);
506511
}
512+
dpm_resume_end(PMSG_RECOVER);
507513
pm_restore_gfp_mask();
508514
resume_console();
509515
pm_restore_console();

0 commit comments

Comments
 (0)