summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
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;
}