summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorSubramaniam Chanderashekarapuram <subramaniam.ca@ti.com>2012-07-23 18:25:18 -0500
committerAndy Green <andy.green@linaro.org>2012-09-07 13:06:53 +0800
commitd5020386a19f5e30665f471968798d226a9d0c26 (patch)
tree9d90d41f60a685595a016a97b5b47905d6610a21 /drivers
parentce4356d83f49d32436953a20c22c64e0193da2ef (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.c91
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);