summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorGary King <gking@nvidia.com>2010-05-27 16:37:47 -0700
committerGary King <gking@nvidia.com>2010-05-27 21:40:56 -0700
commit7d76a13011874ab1d56479f7c18d1d6095a5d550 (patch)
treebc4037d03a5a0876c6d6c4f0fd50531cfa6c1ec5 /arch
parentf8d6750d57c63fec8f8980c430522a231ca4c8ef (diff)
[ARM/tegra] iovmm: make iovmm suspend call explicit
IOVMM devices need to be suspended after the device drivers and coprocessors in the system are suspended, to ensure that no races exist between DMA devices and the IOVMM MMU. add new tegra_iovmm_suspend and tegra_iovmm_resume functions which should be called by the platform suspend prepare_late or enter callbacks, add corresponding callbacks to the iovmm device_ops structure, and move the GART suspend & resume operations to this callback Change-Id: I08babaf14d65477a0c724a943e7f9d868e64f0df
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/include/mach/iovmm.h13
-rw-r--r--arch/arm/mach-tegra/iovmm-gart.c25
-rw-r--r--arch/arm/mach-tegra/iovmm.c37
3 files changed, 60 insertions, 15 deletions
diff --git a/arch/arm/mach-tegra/include/mach/iovmm.h b/arch/arm/mach-tegra/include/mach/iovmm.h
index a5a78568ad1b..8f111605e065 100644
--- a/arch/arm/mach-tegra/include/mach/iovmm.h
+++ b/arch/arm/mach-tegra/include/mach/iovmm.h
@@ -112,6 +112,8 @@ struct tegra_iovmm_device_ops {
struct tegra_iovmm_client *client);
void (*free_domain)(struct tegra_iovmm_device *dev,
struct tegra_iovmm_domain *domain);
+ int (*suspend)(struct tegra_iovmm_device *dev);
+ void (*resume)(struct tegra_iovmm_device *dev);
};
struct tegra_iovmm_area_ops {
@@ -190,7 +192,11 @@ int tegra_iovmm_register(struct tegra_iovmm_device *dev);
/* called by drivers to remove an I/O VMM device from the system */
int tegra_iovmm_unregister(struct tegra_iovmm_device *dev);
+/* called by platform suspend code to save IOVMM context */
+int tegra_iovmm_suspend(void);
+/* restores IOVMM context */
+void tegra_iovmm_resume(void);
#else /* CONFIG_TEGRA_IOVMM */
@@ -267,6 +273,13 @@ static inline int tegra_iovmm_unregister(struct tegra_iovmm_device *dev)
{
return 0;
}
+
+static inline int tegra_iovmm_suspend(void)
+{
+ return 0;
+}
+
+static inline void tegra_iovmm_resume(void) { }
#endif /* CONFIG_TEGRA_IOVMM */
diff --git a/arch/arm/mach-tegra/iovmm-gart.c b/arch/arm/mach-tegra/iovmm-gart.c
index 42ac98c5fd6f..c29c031d304b 100644
--- a/arch/arm/mach-tegra/iovmm-gart.c
+++ b/arch/arm/mach-tegra/iovmm-gart.c
@@ -65,8 +65,8 @@ static struct tegra_iovmm_domain *gart_alloc_domain(
static int gart_probe(struct platform_device *);
static int gart_remove(struct platform_device *);
-static int gart_suspend(struct platform_device *, pm_message_t);
-static int gart_resume(struct platform_device *);
+static int gart_suspend(struct tegra_iovmm_device *dev);
+static void gart_resume(struct tegra_iovmm_device *dev);
static struct tegra_iovmm_device_ops tegra_iovmm_gart_ops = {
@@ -74,21 +74,21 @@ static struct tegra_iovmm_device_ops tegra_iovmm_gart_ops = {
.unmap = gart_unmap,
.map_pfn = gart_map_pfn,
.alloc_domain = gart_alloc_domain,
+ .suspend = gart_suspend,
+ .resume = gart_resume,
};
static struct platform_driver tegra_iovmm_gart_drv = {
.probe = gart_probe,
.remove = gart_remove,
- .suspend = gart_suspend,
- .resume = gart_resume,
.driver = {
.name = DRIVER_NAME,
},
};
-static int gart_suspend(struct platform_device *pdev, pm_message_t state)
+static int gart_suspend(struct tegra_iovmm_device *dev)
{
- struct gart_device *gart = platform_get_drvdata(pdev);
+ struct gart_device *gart = container_of(dev, struct gart_device, iovmm);
unsigned int i;
unsigned long reg;
@@ -127,21 +127,16 @@ static void do_gart_setup(struct gart_device *gart, const u32 *data)
wmb();
}
-static int gart_resume(struct platform_device *pdev)
+static void gart_resume(struct tegra_iovmm_device *dev)
{
- struct gart_device *gart = platform_get_drvdata(pdev);
+ struct gart_device *gart = container_of(dev, struct gart_device, iovmm);
- if (!gart || (gart->enable && !gart->savedata))
- return -ENODEV;
-
- if (!gart->enable)
- return 0;
+ if (!gart || !gart->enable || (gart->enable && !gart->savedata))
+ return;
spin_lock(&gart->pte_lock);
do_gart_setup(gart, gart->savedata);
spin_unlock(&gart->pte_lock);
-
- return 0;
}
static int gart_remove(struct platform_device *pdev)
diff --git a/arch/arm/mach-tegra/iovmm.c b/arch/arm/mach-tegra/iovmm.c
index 60e03a798c6d..7ef150183f4a 100644
--- a/arch/arm/mach-tegra/iovmm.c
+++ b/arch/arm/mach-tegra/iovmm.c
@@ -709,6 +709,43 @@ int tegra_iovmm_register(struct tegra_iovmm_device *dev)
return 0;
}
+int tegra_iovmm_suspend(void)
+{
+ int rc = 0;
+ struct tegra_iovmm_device *dev;
+
+ mutex_lock(&iovmm_list_lock);
+ list_for_each_entry(dev, &iovmm_devices, list) {
+
+ if (!dev->ops->suspend)
+ continue;
+
+ rc = dev->ops->suspend(dev);
+ if (rc) {
+ pr_err("%s: %s suspend returned %d\n",
+ __func__, dev->name, rc);
+ mutex_unlock(&iovmm_list_lock);
+ return rc;
+ }
+ }
+ mutex_unlock(&iovmm_list_lock);
+ return 0;
+}
+
+void tegra_iovmm_resume(void)
+{
+ struct tegra_iovmm_device *dev;
+
+ mutex_lock(&iovmm_list_lock);
+
+ list_for_each_entry(dev, &iovmm_devices, list) {
+ if (dev->ops->resume)
+ dev->ops->resume(dev);
+ }
+
+ mutex_unlock(&iovmm_list_lock);
+}
+
int tegra_iovmm_unregister(struct tegra_iovmm_device *dev)
{
mutex_lock(&iovmm_list_lock);