Skip to content

Commit

Permalink
PM / clk: Fix crash in clocks management code if !CONFIG_PM_RUNTIME
Browse files Browse the repository at this point in the history
Unlike the clocks management code for runtime PM, the code used for
system suspend does not check the pm_clock_entry.status field.
If pm_clk_acquire() failed, ce->status will be PCE_STATUS_ERROR, and
ce->clk will be a negative error code (e.g. 0xfffffffe = -2 = -ENOENT).

Depending on the clock implementation, suspend or resume may crash with:

    Unable to handle kernel NULL pointer dereference at virtual address 00000026

(CCF clk_disable() has an IS_ERR_OR_NULL() check, while CCF clk_enable()
 only has a NULL check; pre-CCF implementations may behave differently)

While just checking for PCE_STATUS_ERROR would be sufficient, it doesn't
hurt to use the same state machine as is done for runtime PM, as this
makes the two versions more similar, and eligible for a future
consolidation.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Geert Uytterhoeven authored and Rafael J. Wysocki committed Oct 3, 2014
1 parent fe82dce commit a968bed
Showing 1 changed file with 15 additions and 4 deletions.
19 changes: 15 additions & 4 deletions drivers/base/power/clock_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,13 @@ int pm_clk_suspend(struct device *dev)

spin_lock_irqsave(&psd->lock, flags);

list_for_each_entry_reverse(ce, &psd->clock_list, node)
clk_disable(ce->clk);
list_for_each_entry_reverse(ce, &psd->clock_list, node) {
if (ce->status < PCE_STATUS_ERROR) {
if (ce->status == PCE_STATUS_ENABLED)
clk_disable(ce->clk);
ce->status = PCE_STATUS_ACQUIRED;
}
}

spin_unlock_irqrestore(&psd->lock, flags);

Expand All @@ -385,6 +390,7 @@ int pm_clk_resume(struct device *dev)
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
unsigned long flags;
int ret;

dev_dbg(dev, "%s()\n", __func__);

Expand All @@ -394,8 +400,13 @@ int pm_clk_resume(struct device *dev)

spin_lock_irqsave(&psd->lock, flags);

list_for_each_entry(ce, &psd->clock_list, node)
__pm_clk_enable(dev, ce->clk);
list_for_each_entry(ce, &psd->clock_list, node) {
if (ce->status < PCE_STATUS_ERROR) {
ret = __pm_clk_enable(dev, ce->clk);
if (!ret)
ce->status = PCE_STATUS_ENABLED;
}
}

spin_unlock_irqrestore(&psd->lock, flags);

Expand Down

0 comments on commit a968bed

Please sign in to comment.