iommu/rockchip: Handle errors returned from PM framework
pm_runtime_get_if_in_use can fail: either PM has been disabled
altogether (-EINVAL), or the device hasn't been enabled yet (0).
Sadly, the Rockchip IOMMU driver tends to conflate the two things
by considering a non-zero return value as successful.
This has the consequence of hiding other bugs, so let's handle this
case throughout the driver, with a WARN_ON_ONCE so that we can try
and work out what happened.
Fixes: 0f181d3cf7
("iommu/rockchip: Add runtime PM support")
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
parent
7db7a8f563
commit
3fc7c5c0cf
|
@ -521,10 +521,11 @@ static irqreturn_t rk_iommu_irq(int irq, void *dev_id)
|
||||||
u32 int_status;
|
u32 int_status;
|
||||||
dma_addr_t iova;
|
dma_addr_t iova;
|
||||||
irqreturn_t ret = IRQ_NONE;
|
irqreturn_t ret = IRQ_NONE;
|
||||||
int i;
|
int i, err;
|
||||||
|
|
||||||
if (WARN_ON(!pm_runtime_get_if_in_use(iommu->dev)))
|
err = pm_runtime_get_if_in_use(iommu->dev);
|
||||||
return 0;
|
if (WARN_ON_ONCE(err <= 0))
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
|
if (WARN_ON(clk_bulk_enable(iommu->num_clocks, iommu->clocks)))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -620,11 +621,15 @@ static void rk_iommu_zap_iova(struct rk_iommu_domain *rk_domain,
|
||||||
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
|
spin_lock_irqsave(&rk_domain->iommus_lock, flags);
|
||||||
list_for_each(pos, &rk_domain->iommus) {
|
list_for_each(pos, &rk_domain->iommus) {
|
||||||
struct rk_iommu *iommu;
|
struct rk_iommu *iommu;
|
||||||
|
int ret;
|
||||||
|
|
||||||
iommu = list_entry(pos, struct rk_iommu, node);
|
iommu = list_entry(pos, struct rk_iommu, node);
|
||||||
|
|
||||||
/* Only zap TLBs of IOMMUs that are powered on. */
|
/* Only zap TLBs of IOMMUs that are powered on. */
|
||||||
if (pm_runtime_get_if_in_use(iommu->dev)) {
|
ret = pm_runtime_get_if_in_use(iommu->dev);
|
||||||
|
if (WARN_ON_ONCE(ret < 0))
|
||||||
|
continue;
|
||||||
|
if (ret) {
|
||||||
WARN_ON(clk_bulk_enable(iommu->num_clocks,
|
WARN_ON(clk_bulk_enable(iommu->num_clocks,
|
||||||
iommu->clocks));
|
iommu->clocks));
|
||||||
rk_iommu_zap_lines(iommu, iova, size);
|
rk_iommu_zap_lines(iommu, iova, size);
|
||||||
|
@ -891,6 +896,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
|
||||||
struct rk_iommu *iommu;
|
struct rk_iommu *iommu;
|
||||||
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
|
struct rk_iommu_domain *rk_domain = to_rk_domain(domain);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* Allow 'virtual devices' (eg drm) to detach from domain */
|
/* Allow 'virtual devices' (eg drm) to detach from domain */
|
||||||
iommu = rk_iommu_from_dev(dev);
|
iommu = rk_iommu_from_dev(dev);
|
||||||
|
@ -909,7 +915,9 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
|
||||||
list_del_init(&iommu->node);
|
list_del_init(&iommu->node);
|
||||||
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
|
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
|
||||||
|
|
||||||
if (pm_runtime_get_if_in_use(iommu->dev)) {
|
ret = pm_runtime_get_if_in_use(iommu->dev);
|
||||||
|
WARN_ON_ONCE(ret < 0);
|
||||||
|
if (ret > 0) {
|
||||||
rk_iommu_disable(iommu);
|
rk_iommu_disable(iommu);
|
||||||
pm_runtime_put(iommu->dev);
|
pm_runtime_put(iommu->dev);
|
||||||
}
|
}
|
||||||
|
@ -946,7 +954,8 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
|
||||||
list_add_tail(&iommu->node, &rk_domain->iommus);
|
list_add_tail(&iommu->node, &rk_domain->iommus);
|
||||||
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
|
spin_unlock_irqrestore(&rk_domain->iommus_lock, flags);
|
||||||
|
|
||||||
if (!pm_runtime_get_if_in_use(iommu->dev))
|
ret = pm_runtime_get_if_in_use(iommu->dev);
|
||||||
|
if (!ret || WARN_ON_ONCE(ret < 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = rk_iommu_enable(iommu);
|
ret = rk_iommu_enable(iommu);
|
||||||
|
|
Loading…
Reference in New Issue