diff options
author | Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com> | 2012-07-23 18:25:18 -0500 |
---|---|---|
committer | Andy Green <andy.green@linaro.org> | 2012-09-07 13:06:53 +0800 |
commit | d5020386a19f5e30665f471968798d226a9d0c26 (patch) | |
tree | 9d90d41f60a685595a016a97b5b47905d6610a21 /drivers | |
parent | ce4356d83f49d32436953a20c22c64e0193da2ef (diff) |
iommu: omap: use latency constraint apis to preserve context
A latency constraint could be used to ensure that a device responds
within the latency value specified.
The dev_pm_qos and the pm_qos apis provide a way to set latency
constraints. Specifically, the dev_pm_qos can be used to hold
latency constraints on power domains other than core, while the
pm_qos API is used for core power domain.
The iommu module could transition to a lower power state anytime
after it is powered up depending on the activity associated with it.
The MMUs associated with DSP and IPU processor subsystems would lose
their context in OSWR and lower power states. A transition to such
power state could cause the remoteproc to behave in an unpredictable
way (AMMU fault or MMU fault due to loss of MMU register context). A
latency constraint is therefore enforced on the power domain
containing the iommu to preserve its context.
Signed-off-by: Subramaniam Chanderashekarapuram <subramaniam.ca@ti.com>
Signed-off-by: Paul Hunt <hunt@ti.com>
Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com>
Signed-off-by: Suman Anna <s-anna@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/iommu/omap-iommu.c | 91 |
1 files changed, 85 insertions, 6 deletions
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index 495ceb447d63..eee7d26c8461 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -28,6 +28,9 @@ #include <plat/iopgtable.h> +#define dev_to_pm_constraint(dev) (((struct iommu_platform_data *) \ + dev->platform_data)->pm_constraint) + #define for_each_iotlb_cr(obj, n, __i, cr) \ for (__i = 0; \ (__i < (n)) && (cr = __iotlb_read_cr((obj), __i), true); \ @@ -111,6 +114,34 @@ void omap_iommu_restore_ctx(struct device *dev) } EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx); +static inline +void omap_iommu_remove_latency_req(struct omap_iommu *oiommu) +{ + if (!strcmp(oiommu->name, "ipu")) + pm_qos_remove_request(&oiommu->qos_request.pm_qos); + else if (dev_pm_qos_remove_request(&oiommu->qos_request.dev_pm_qos) < 0) + dev_err(oiommu->dev, "failed to remove latency constraint\n"); +} + +static inline +int omap_iommu_update_latency(struct omap_iommu *oiommu, int val) +{ + int ret = 0; + + if (!strcmp(oiommu->name, "ipu")) + pm_qos_update_request(&oiommu->qos_request.pm_qos, val); + else { + ret = dev_pm_qos_update_request( + &oiommu->qos_request.dev_pm_qos, val); + ret = ret > 0 ? 0 : ret; + if (ret) + dev_err(oiommu->dev, + "failed to update latency constraint, val = %d\n", val); + } + + return ret; +} + /** * omap_iommu_runtime_suspend - save iommu context * @dev: client device @@ -120,12 +151,18 @@ EXPORT_SYMBOL_GPL(omap_iommu_restore_ctx); static int omap_iommu_runtime_suspend(struct device *dev) { struct omap_iommu *obj = to_iommu(dev); + int pm_constraint, ret = 0; + dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name); if (arch_iommu && arch_iommu->save_ctx) arch_iommu->save_ctx(obj); - return 0; + pm_constraint = dev_to_pm_constraint(dev); + if (pm_constraint) + ret = omap_iommu_update_latency(obj, PM_QOS_DEFAULT_VALUE); + + return ret; } /** @@ -137,11 +174,20 @@ static int omap_iommu_runtime_suspend(struct device *dev) static int omap_iommu_runtime_resume(struct device *dev) { struct omap_iommu *obj = to_iommu(dev); + int pm_constraint, ret = 0; + dev_dbg(obj->dev, "%s: %s\n", __func__, obj->name); if (!arch_iommu) return 0; + pm_constraint = dev_to_pm_constraint(dev); + if (pm_constraint) { + ret = omap_iommu_update_latency(obj, pm_constraint); + if (ret) + return ret; + } + if (arch_iommu->restore_ctx) arch_iommu->restore_ctx(obj); @@ -891,6 +937,7 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) int err = -ENOMEM; struct device *dev; struct omap_iommu *obj; + int pm_constraint; dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name, @@ -909,6 +956,13 @@ static struct omap_iommu *omap_iommu_attach(const char *name, u32 *iopgd) goto err_enable; } + pm_constraint = dev_to_pm_constraint(dev); + if (pm_constraint) { + err = omap_iommu_update_latency(obj, pm_constraint); + if (err) + goto err_enable; + } + obj->iopgd = iopgd; err = iommu_enable(obj); if (err) @@ -927,7 +981,10 @@ err_module: if (obj->refcount == 1) iommu_disable(obj); err_enable: - obj->refcount--; + if (!--obj->refcount) { + if (pm_constraint) + omap_iommu_update_latency(obj, PM_QOS_DEFAULT_VALUE); + } spin_unlock(&obj->iommu_lock); return ERR_PTR(err); } @@ -938,14 +995,19 @@ err_enable: **/ static void omap_iommu_detach(struct omap_iommu *obj) { + int pm_constraint; + if (!obj || IS_ERR(obj)) return; spin_lock(&obj->iommu_lock); - if (--obj->refcount == 0) + if (--obj->refcount == 0) { iommu_disable(obj); - + pm_constraint = dev_to_pm_constraint(obj->dev); + if (pm_constraint) + omap_iommu_update_latency(obj, PM_QOS_DEFAULT_VALUE); + } module_put(obj->owner); obj->iopgd = NULL; @@ -982,17 +1044,30 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev) spin_lock_init(&obj->page_table_lock); INIT_LIST_HEAD(&obj->mmap); + if (!strcmp(obj->name, "ipu")) + pm_qos_add_request(&obj->qos_request.pm_qos, + PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); + else { + err = dev_pm_qos_add_request(obj->dev, + &obj->qos_request.dev_pm_qos, PM_QOS_DEFAULT_VALUE); + if (err < 0) { + dev_err(&pdev->dev, "failed to add constraint %d\n", + err); + goto err_mem; + } + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { err = -ENODEV; - goto err_mem; + goto err_rel_constraint; } res = request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev)); if (!res) { err = -EIO; - goto err_mem; + goto err_rel_constraint; } obj->regbase = ioremap(res->start, resource_size(res)); @@ -1021,6 +1096,8 @@ err_irq: iounmap(obj->regbase); err_ioremap: release_mem_region(res->start, resource_size(res)); +err_rel_constraint: + omap_iommu_remove_latency_req(obj); err_mem: kfree(obj); return err; @@ -1042,6 +1119,8 @@ static int __devexit omap_iommu_remove(struct platform_device *pdev) release_mem_region(res->start, resource_size(res)); iounmap(obj->regbase); + omap_iommu_remove_latency_req(obj); + pm_runtime_disable(obj->dev); dev_info(&pdev->dev, "%s removed\n", obj->name); |