From 96a2e61a617c33e73f529694ed836abd9edeb013 Mon Sep 17 00:00:00 2001 From: Miguel Vadillo Date: Thu, 7 Apr 2011 08:43:36 +0100 Subject: 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 Signed-off-by: Hari Kanigeri Signed-off-by: Fernando Guzman Lugo Signed-off-by: Juan Gutierrez Signed-off-by: Paul Hunt 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 Signed-off-by: Hari Kanigeri Signed-off-by: Fernando Guzman Lugo Signed-off-by: Juan Gutierrez Signed-off-by: Paul Hunt Signed-off-by: Juan Gutierrez Signed-off-by: Paul Hunt 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 Signed-off-by: Juan Gutierrez Signed-off-by: Paul Hunt 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 Signed-off-by: Hari Kanigeri --- arch/arm/plat-omap/include/plat/iommu.h | 14 ++-- arch/arm/plat-omap/include/plat/iommu2.h | 5 +- arch/arm/plat-omap/iommu-debug.c | 3 +- arch/arm/plat-omap/iommu.c | 108 ++++++++++++++++++++++++++++--- 4 files changed, 110 insertions(+), 20 deletions(-) (limited to 'arch/arm/plat-omap') 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; } -- cgit v1.2.3