Commit e1e4528f authored by Suman Anna's avatar Suman Anna Committed by Ohad Ben-Cohen

hwspinlock/omap: enable module before reading SYSSTATUS register

The number of hwspinlocks are determined based on the value read
from the IP block's SYSSTATUS register. However, the module may
not be enabled and clocked, and the read may result in a bus error.

This particular issue is seen rather easily on AM33XX, since the
module wakeup is software controlled, and it is disabled out of
reset. Make sure the module is enabled and clocked before reading
the SYSSTATUS register.
Signed-off-by: default avatarSuman Anna <s-anna@ti.com>
[replace pm_runtime_put_sync with lenient pm_runtime_put]
Signed-off-by: default avatarOhad Ben-Cohen <ohad@wizery.com>
parent 9a3c4145
...@@ -98,10 +98,29 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) ...@@ -98,10 +98,29 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
if (!io_base) if (!io_base)
return -ENOMEM; return -ENOMEM;
/*
* make sure the module is enabled and clocked before reading
* the module SYSSTATUS register
*/
pm_runtime_enable(&pdev->dev);
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&pdev->dev);
goto iounmap_base;
}
/* Determine number of locks */ /* Determine number of locks */
i = readl(io_base + SYSSTATUS_OFFSET); i = readl(io_base + SYSSTATUS_OFFSET);
i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET; i >>= SPINLOCK_NUMLOCKS_BIT_OFFSET;
/*
* runtime PM will make sure the clock of this module is
* enabled again iff at least one lock is requested
*/
ret = pm_runtime_put(&pdev->dev);
if (ret < 0)
goto iounmap_base;
/* one of the four lsb's must be set, and nothing else */ /* one of the four lsb's must be set, and nothing else */
if (hweight_long(i & 0xf) != 1 || i > 8) { if (hweight_long(i & 0xf) != 1 || i > 8) {
ret = -EINVAL; ret = -EINVAL;
...@@ -121,12 +140,6 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) ...@@ -121,12 +140,6 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++) for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i; hwlock->priv = io_base + LOCK_BASE_OFFSET + sizeof(u32) * i;
/*
* runtime PM will make sure the clock of this module is
* enabled iff at least one lock is requested
*/
pm_runtime_enable(&pdev->dev);
ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops, ret = hwspin_lock_register(bank, &pdev->dev, &omap_hwspinlock_ops,
pdata->base_id, num_locks); pdata->base_id, num_locks);
if (ret) if (ret)
...@@ -135,9 +148,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev) ...@@ -135,9 +148,9 @@ static int omap_hwspinlock_probe(struct platform_device *pdev)
return 0; return 0;
reg_fail: reg_fail:
pm_runtime_disable(&pdev->dev);
kfree(bank); kfree(bank);
iounmap_base: iounmap_base:
pm_runtime_disable(&pdev->dev);
iounmap(io_base); iounmap(io_base);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment