summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorMiguel Vadillo <vadillo@ti.com>2011-05-31 09:24:39 +0100
committerAndy Green <andy.green@linaro.org>2011-05-31 11:06:07 +0100
commit437d875d6eba03dec0f732af4cbaf25364b3bf76 (patch)
tree960784e631074d3b0eba6bb1eb3b1fec6d1f1e72 /arch
parent2c66db0cc32f07957dd458e252fba3482e27fa98 (diff)
omap:iommu: save/restore changes for iommu
omap:iommu: save/restore tlbs entries Introduce a way to save/restore the tlbs entries. When saving is call all 32 entries are saved. When restoring just the valid ones are restored. A new member in iommu obj was added to save/restore the tlbs - iommu tlbs context: saved area struct iotlb_entry *tlbs_e Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> Signed-off-by: Fernando Guzman Lugo <x0095840@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> omap:iommu: Change in iommu to save/restore To save the context the tlbs are being saved using iommu_save_tlb_entries() then the iommu is disable. To restore the context the tlbs are being restored using iommu_restore_tlb_entries() then the iommu is enable. There is no need to save the registers that is why ctx was removed from the iommu struct. omap2_save/restore function were removed. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com> Signed-off-by: Fernando Guzman Lugo <x0095840@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com omap:iommu: dump ctx for omap4 Adding the two new registers just for omap4 in the dumping context function. Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> omap:iommu: iommu_debug fix due to api change New function to get the version of IOMMU was added since now there is a need to determine if its tesla or ducati. iommu_debug.c was updated to use this API Signed-off-by: Miguel Vadillo <vadillo@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com> Signed-off-by: Paul Hunt <hunt@ti.com> omap:iommu: set MMU_GP_REG to force a bus error upon MMU fault MMU_GP_REG[0] determines the behavior of Ducati cores upon hitting an MMU fault (address is not mapped in L2MMU). If it is not set, the cores are hung preventing the fault handler to run. If one introduces a bus error, the fault handler gets to run and prints state information which is useful for debug. Signed-off-by: Wajahat Khan <w-khan@ti.com> Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/iommu2.c43
-rw-r--r--arch/arm/plat-omap/include/plat/iommu.h14
-rw-r--r--arch/arm/plat-omap/include/plat/iommu2.h5
-rw-r--r--arch/arm/plat-omap/iommu-debug.c3
-rw-r--r--arch/arm/plat-omap/iommu.c108
5 files changed, 124 insertions, 49 deletions
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 74ba75b87af..ae66be2cb59 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -85,6 +85,11 @@ static void __iommu_set_twl(struct iommu *obj, bool on)
iommu_write_reg(obj, l, MMU_CNTL);
}
+static u32 omap2_get_version(struct iommu *obj)
+{
+ return iommu_read_reg(obj, MMU_REVISION);
+}
+
static int omap2_iommu_enable(struct iommu *obj)
{
u32 l, pa;
@@ -129,6 +134,9 @@ static int omap2_iommu_enable(struct iommu *obj)
__iommu_set_twl(obj, true);
+ if (cpu_is_omap44xx())
+ iommu_write_reg(obj, 0x1, MMU_GP_REG);
+
return 0;
}
@@ -286,41 +294,20 @@ static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len)
pr_reg(READ_CAM);
pr_reg(READ_RAM);
pr_reg(EMU_FAULT_AD);
+if (cpu_is_omap44xx()) {
+ pr_reg(FAULT_PC);
+ pr_reg(FAULT_STATUS);
+}
out:
return p - buf;
}
-static void omap2_iommu_save_ctx(struct iommu *obj)
-{
- int i;
- u32 *p = obj->ctx;
-
- for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
- p[i] = iommu_read_reg(obj, i * sizeof(u32));
- dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
- }
-
- BUG_ON(p[0] != IOMMU_ARCH_VERSION);
-}
-
-static void omap2_iommu_restore_ctx(struct iommu *obj)
-{
- int i;
- u32 *p = obj->ctx;
-
- for (i = 0; i < (MMU_REG_SIZE / sizeof(u32)); i++) {
- iommu_write_reg(obj, p[i], i * sizeof(u32));
- dev_dbg(obj->dev, "%s\t[%02d] %08x\n", __func__, i, p[i]);
- }
-
- BUG_ON(p[0] != IOMMU_ARCH_VERSION);
-}
-
static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
{
e->da = cr->cam & MMU_CAM_VATAG_MASK;
e->pa = cr->ram & MMU_RAM_PADDR_MASK;
e->valid = cr->cam & MMU_CAM_V;
+ e->prsvd = cr->cam & MMU_CAM_P;
e->pgsz = cr->cam & MMU_CAM_PGSZ_MASK;
e->endian = cr->ram & MMU_RAM_ENDIAN_MASK;
e->elsz = cr->ram & MMU_RAM_ELSZ_MASK;
@@ -328,7 +315,7 @@ static void omap2_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
}
static const struct iommu_functions omap2_iommu_ops = {
- .version = IOMMU_ARCH_VERSION,
+ .get_version = omap2_get_version,
.enable = omap2_iommu_enable,
.disable = omap2_iommu_disable,
@@ -346,8 +333,6 @@ static const struct iommu_functions omap2_iommu_ops = {
.get_pte_attr = omap2_get_pte_attr,
- .save_ctx = omap2_iommu_save_ctx,
- .restore_ctx = omap2_iommu_restore_ctx,
.dump_ctx = omap2_iommu_dump_ctx,
};
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h
index d8acbdaf82a..c1b3f6ef203 100644
--- a/arch/arm/plat-omap/include/plat/iommu.h
+++ b/arch/arm/plat-omap/include/plat/iommu.h
@@ -51,9 +51,9 @@ struct iommu {
struct blocking_notifier_head notifier;
- void *ctx; /* iommu context: registres saved area */
u32 da_start;
u32 da_end;
+ struct iotlb_entry *tlbs_e;/* iommu tlbs context: saved area */
struct platform_device *pdev;
struct list_head event_list;
spinlock_t event_lock;
@@ -89,7 +89,7 @@ struct iotlb_lock {
/* architecture specific functions */
struct iommu_functions {
- unsigned long version;
+ u32 (*get_version)(struct iommu *obj);
int (*enable)(struct iommu *obj);
void (*disable)(struct iommu *obj);
@@ -107,8 +107,6 @@ struct iommu_functions {
u32 (*get_pte_attr)(struct iotlb_entry *e);
- void (*save_ctx)(struct iommu *obj);
- void (*restore_ctx)(struct iommu *obj);
ssize_t (*dump_ctx)(struct iommu *obj, char *buf, ssize_t len);
};
@@ -167,7 +165,7 @@ struct iommu_platform_data {
/*
* global functions
*/
-extern u32 iommu_arch_version(void);
+extern u32 iommu_arch_version(struct iommu *obj);
extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
@@ -198,8 +196,10 @@ extern int iommu_set_isr(const char *name,
void *priv),
void *isr_priv);
-extern void iommu_save_ctx(struct iommu *obj);
-extern void iommu_restore_ctx(struct iommu *obj);
+u32 iommu_save_ctx(struct iommu *obj);
+u32 iommu_restore_ctx(struct iommu *obj);
+u32 iommu_save_tlb_entries(struct iommu *obj);
+u32 iommu_restore_tlb_entries(struct iommu *obj);
extern int install_iommu_arch(const struct iommu_functions *ops);
extern void uninstall_iommu_arch(const struct iommu_functions *ops);
diff --git a/arch/arm/plat-omap/include/plat/iommu2.h b/arch/arm/plat-omap/include/plat/iommu2.h
index 9b5c4c9f9e6..c1ed038dde6 100644
--- a/arch/arm/plat-omap/include/plat/iommu2.h
+++ b/arch/arm/plat-omap/include/plat/iommu2.h
@@ -36,8 +36,9 @@
#define MMU_READ_CAM 0x68
#define MMU_READ_RAM 0x6c
#define MMU_EMU_FAULT_AD 0x70
-
-#define MMU_REG_SIZE 256
+#define MMU_FAULT_PC 0x80
+#define MMU_FAULT_STATUS 0x84
+#define MMU_GP_REG 0x88
/*
* MMU Register bit definitions
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
index f07cf2f08e0..7a8725fd806 100644
--- a/arch/arm/plat-omap/iommu-debug.c
+++ b/arch/arm/plat-omap/iommu-debug.c
@@ -32,7 +32,8 @@ static struct dentry *iommu_debug_root;
static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
- u32 ver = iommu_arch_version();
+ struct iommu *obj = file->private_data;
+ u32 ver = iommu_arch_version(obj);
char buf[MAXCOLUMN], *p = buf;
p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index 09f9a67b84c..d86d47b6a5d 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -72,9 +72,19 @@ EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
* iommu_save_ctx - Save registers for pm off-mode support
* @obj: target iommu
**/
-void iommu_save_ctx(struct iommu *obj)
+u32 iommu_save_ctx(struct iommu *obj)
{
- arch_iommu->save_ctx(obj);
+ u32 err;
+
+ err = iommu_save_tlb_entries(obj);
+ if (err)
+ goto error;
+
+ arch_iommu->disable(obj);
+
+ return 0;
+error:
+ return err;
}
EXPORT_SYMBOL_GPL(iommu_save_ctx);
@@ -82,18 +92,30 @@ EXPORT_SYMBOL_GPL(iommu_save_ctx);
* iommu_restore_ctx - Restore registers for pm off-mode support
* @obj: target iommu
**/
-void iommu_restore_ctx(struct iommu *obj)
+u32 iommu_restore_ctx(struct iommu *obj)
{
- arch_iommu->restore_ctx(obj);
+ u32 err;
+
+ err = arch_iommu->enable(obj);
+ if (err)
+ goto error;
+
+ err = iommu_restore_tlb_entries(obj);
+ if (err)
+ goto error;
+
+ return 0;
+error:
+ return err;
}
EXPORT_SYMBOL_GPL(iommu_restore_ctx);
/**
* iommu_arch_version - Return running iommu arch version
**/
-u32 iommu_arch_version(void)
+u32 iommu_arch_version(struct iommu *obj)
{
- return arch_iommu->version;
+ return arch_iommu->get_version(obj);
}
EXPORT_SYMBOL_GPL(iommu_arch_version);
@@ -362,6 +384,69 @@ void iommu_set_twl(struct iommu *obj, bool on)
}
EXPORT_SYMBOL_GPL(iommu_set_twl);
+/**
+ * save_tlb_entries - save a num of locked tlb entries
+ * @obj: target iommu
+ *
+ */
+u32 iommu_save_tlb_entries(struct iommu *obj)
+{
+ int i;
+ struct cr_regs cr_tmp;
+ struct iotlb_entry *e = obj->tlbs_e;
+
+ if (!obj || !obj->tlbs_e)
+ goto error;
+
+ for_each_iotlb_cr(obj, obj->nr_tlb_entries, i, cr_tmp) {
+ iotlb_cr_to_e(&cr_tmp, e);
+ e++;
+
+ dev_dbg(obj->dev, "%s: [%02x] %08x %08x\n", __func__,
+ i, cr_tmp.cam, cr_tmp.ram);
+ }
+
+ return 0;
+error:
+ return -EINVAL;
+}
+
+/**
+ * restore_tlb_entries - restor a num of locked tlb entries
+ * @obj: target iommu
+ *
+ * Function used to restore exclusively the valid TLB entries
+ * based on the e->valid value
+ *
+ */
+u32 iommu_restore_tlb_entries(struct iommu *obj)
+{
+ int i;
+ int status;
+ struct iotlb_entry *e = obj->tlbs_e;
+
+ if (!obj || !obj->tlbs_e)
+ goto error;
+
+ for (i = 0; i < obj->nr_tlb_entries; i++) {
+ if (!e->valid) {
+ e++;
+ continue;
+ }
+ status = load_iotlb_entry(obj, e);
+ if (status)
+ goto error;
+ e++;
+
+ dev_dbg(obj->dev, "%s: [%02x] %08x\n", __func__,
+ i, e->pa);
+ }
+
+ return 0;
+error:
+ return -EINVAL;
+}
+
#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
@@ -939,7 +1024,7 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
struct iommu *obj;
struct iommu_platform_data *pdata = pdev->dev.platform_data;
- obj = kzalloc(sizeof(*obj) + MMU_REG_SIZE, GFP_KERNEL);
+ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
if (!obj)
return -ENOMEM;
@@ -947,9 +1032,12 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
obj->name = pdata->name;
obj->dev = &pdev->dev;
obj->pdev = pdev;
- obj->ctx = (void *)obj + sizeof(*obj);
obj->da_start = pdata->da_start;
obj->da_end = pdata->da_end;
+ obj->tlbs_e = kzalloc(sizeof(struct iotlb_entry) * obj->nr_tlb_entries,
+ GFP_KERNEL);
+ if (!obj->tlbs_e)
+ goto error;
mutex_init(&obj->iommu_lock);
mutex_init(&obj->mmap_lock);
@@ -965,7 +1053,7 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
err = request_irq(pdata->irq, iommu_fault_handler, IRQF_SHARED,
dev_name(&pdev->dev), obj);
if (err < 0)
- goto err_irq;
+ goto error;
platform_set_drvdata(pdev, obj);
p = (void *)__get_free_pages(GFP_KERNEL, get_order(IOPGD_TABLE_SIZE));
@@ -984,7 +1072,7 @@ static int __devinit omap_iommu_probe(struct platform_device *pdev)
err_pgd:
free_irq(pdata->irq, obj);
-err_irq:
+error:
kfree(obj);
return err;
}