diff options
-rw-r--r-- | arch/arm/mach-omap2/iommu2.c | 43 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu.h | 14 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu2.h | 5 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu-debug.c | 3 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu.c | 108 |
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; } |