aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/iommu2.c17
-rw-r--r--arch/arm/plat-omap/include/plat/iommu.h14
-rw-r--r--arch/arm/plat-omap/iommu.c52
3 files changed, 65 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 49a1e5e841c..adb083e41ac 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -146,18 +146,31 @@ static void omap2_iommu_set_twl(struct iommu *obj, bool on)
146static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) 146static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
147{ 147{
148 u32 stat, da; 148 u32 stat, da;
149 u32 errs = 0;
149 150
150 stat = iommu_read_reg(obj, MMU_IRQSTATUS); 151 stat = iommu_read_reg(obj, MMU_IRQSTATUS);
151 stat &= MMU_IRQ_MASK; 152 stat &= MMU_IRQ_MASK;
152 if (!stat) 153 if (!stat) {
154 *ra = 0;
153 return 0; 155 return 0;
156 }
154 157
155 da = iommu_read_reg(obj, MMU_FAULT_AD); 158 da = iommu_read_reg(obj, MMU_FAULT_AD);
156 *ra = da; 159 *ra = da;
157 160
161 if (stat & MMU_IRQ_TLBMISS)
162 errs |= OMAP_IOMMU_ERR_TLB_MISS;
163 if (stat & MMU_IRQ_TRANSLATIONFAULT)
164 errs |= OMAP_IOMMU_ERR_TRANS_FAULT;
165 if (stat & MMU_IRQ_EMUMISS)
166 errs |= OMAP_IOMMU_ERR_EMU_MISS;
167 if (stat & MMU_IRQ_TABLEWALKFAULT)
168 errs |= OMAP_IOMMU_ERR_TBLWALK_FAULT;
169 if (stat & MMU_IRQ_MULTIHITFAULT)
170 errs |= OMAP_IOMMU_ERR_MULTIHIT_FAULT;
158 iommu_write_reg(obj, stat, MMU_IRQSTATUS); 171 iommu_write_reg(obj, stat, MMU_IRQSTATUS);
159 172
160 return stat; 173 return errs;
161} 174}
162 175
163static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr) 176static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr)
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h
index 19cbb5e9ece..174f1b9c8c0 100644
--- a/arch/arm/plat-omap/include/plat/iommu.h
+++ b/arch/arm/plat-omap/include/plat/iommu.h
@@ -31,6 +31,7 @@ struct iommu {
31 struct clk *clk; 31 struct clk *clk;
32 void __iomem *regbase; 32 void __iomem *regbase;
33 struct device *dev; 33 struct device *dev;
34 void *isr_priv;
34 35
35 unsigned int refcount; 36 unsigned int refcount;
36 struct mutex iommu_lock; /* global for this whole object */ 37 struct mutex iommu_lock; /* global for this whole object */
@@ -47,7 +48,7 @@ struct iommu {
47 struct list_head mmap; 48 struct list_head mmap;
48 struct mutex mmap_lock; /* protect mmap */ 49 struct mutex mmap_lock; /* protect mmap */
49 50
50 int (*isr)(struct iommu *obj); 51 int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs, void *priv);
51 52
52 void *ctx; /* iommu context: registres saved area */ 53 void *ctx; /* iommu context: registres saved area */
53 u32 da_start; 54 u32 da_start;
@@ -109,6 +110,13 @@ struct iommu_platform_data {
109 u32 da_end; 110 u32 da_end;
110}; 111};
111 112
113/* IOMMU errors */
114#define OMAP_IOMMU_ERR_TLB_MISS (1 << 0)
115#define OMAP_IOMMU_ERR_TRANS_FAULT (1 << 1)
116#define OMAP_IOMMU_ERR_EMU_MISS (1 << 2)
117#define OMAP_IOMMU_ERR_TBLWALK_FAULT (1 << 3)
118#define OMAP_IOMMU_ERR_MULTIHIT_FAULT (1 << 4)
119
112#if defined(CONFIG_ARCH_OMAP1) 120#if defined(CONFIG_ARCH_OMAP1)
113#error "iommu for this processor not implemented yet" 121#error "iommu for this processor not implemented yet"
114#else 122#else
@@ -161,6 +169,10 @@ extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
161extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); 169extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end);
162extern struct iommu *iommu_get(const char *name); 170extern struct iommu *iommu_get(const char *name);
163extern void iommu_put(struct iommu *obj); 171extern void iommu_put(struct iommu *obj);
172extern int iommu_set_isr(const char *name,
173 int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
174 void *priv),
175 void *isr_priv);
164 176
165extern void iommu_save_ctx(struct iommu *obj); 177extern void iommu_save_ctx(struct iommu *obj);
166extern void iommu_restore_ctx(struct iommu *obj); 178extern void iommu_restore_ctx(struct iommu *obj);
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index 4b3218eaf3e..e3eb0380090 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -783,25 +783,19 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
783 */ 783 */
784static irqreturn_t iommu_fault_handler(int irq, void *data) 784static irqreturn_t iommu_fault_handler(int irq, void *data)
785{ 785{
786 u32 stat, da; 786 u32 da, errs;
787 u32 *iopgd, *iopte; 787 u32 *iopgd, *iopte;
788 int err = -EIO;
789 struct iommu *obj = data; 788 struct iommu *obj = data;
790 789
791 if (!obj->refcount) 790 if (!obj->refcount)
792 return IRQ_NONE; 791 return IRQ_NONE;
793 792
794 /* Dynamic loading TLB or PTE */
795 if (obj->isr)
796 err = obj->isr(obj);
797
798 if (!err)
799 return IRQ_HANDLED;
800
801 clk_enable(obj->clk); 793 clk_enable(obj->clk);
802 stat = iommu_report_fault(obj, &da); 794 errs = iommu_report_fault(obj, &da);
803 clk_disable(obj->clk); 795 clk_disable(obj->clk);
804 if (!stat) 796
797 /* Fault callback or TLB/PTE Dynamic loading */
798 if (obj->isr && !obj->isr(obj, da, errs, obj->isr_priv))
805 return IRQ_HANDLED; 799 return IRQ_HANDLED;
806 800
807 iommu_disable(obj); 801 iommu_disable(obj);
@@ -809,15 +803,16 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
809 iopgd = iopgd_offset(obj, da); 803 iopgd = iopgd_offset(obj, da);
810 804
811 if (!iopgd_is_table(*iopgd)) { 805 if (!iopgd_is_table(*iopgd)) {
812 dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", obj->name, 806 dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p "
813 da, iopgd, *iopgd); 807 "*pgd:px%08x\n", obj->name, errs, da, iopgd, *iopgd);
814 return IRQ_NONE; 808 return IRQ_NONE;
815 } 809 }
816 810
817 iopte = iopte_offset(iopgd, da); 811 iopte = iopte_offset(iopgd, da);
818 812
819 dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n", 813 dev_err(obj->dev, "%s: errs:0x%08x da:0x%08x pgd:0x%p *pgd:0x%08x "
820 obj->name, da, iopgd, *iopgd, iopte, *iopte); 814 "pte:0x%p *pte:0x%08x\n", obj->name, errs, da, iopgd, *iopgd,
815 iopte, *iopte);
821 816
822 return IRQ_NONE; 817 return IRQ_NONE;
823} 818}
@@ -920,6 +915,33 @@ void iommu_put(struct iommu *obj)
920} 915}
921EXPORT_SYMBOL_GPL(iommu_put); 916EXPORT_SYMBOL_GPL(iommu_put);
922 917
918int iommu_set_isr(const char *name,
919 int (*isr)(struct iommu *obj, u32 da, u32 iommu_errs,
920 void *priv),
921 void *isr_priv)
922{
923 struct device *dev;
924 struct iommu *obj;
925
926 dev = driver_find_device(&omap_iommu_driver.driver, NULL, (void *)name,
927 device_match_by_alias);
928 if (!dev)
929 return -ENODEV;
930
931 obj = to_iommu(dev);
932 mutex_lock(&obj->iommu_lock);
933 if (obj->refcount != 0) {
934 mutex_unlock(&obj->iommu_lock);
935 return -EBUSY;
936 }
937 obj->isr = isr;
938 obj->isr_priv = isr_priv;
939 mutex_unlock(&obj->iommu_lock);
940
941 return 0;
942}
943EXPORT_SYMBOL_GPL(iommu_set_isr);
944
923/* 945/*
924 * OMAP Device MMU(IOMMU) detection 946 * OMAP Device MMU(IOMMU) detection
925 */ 947 */