diff options
-rw-r--r-- | arch/arm/mach-omap2/iommu2.c | 17 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu.h | 14 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu.c | 52 |
3 files changed, 65 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index 49a1e5e841ca..adb083e41acd 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) | |||
146 | static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) | 146 | static 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 | ||
163 | static void omap2_tlb_read_cr(struct iommu *obj, struct cr_regs *cr) | 176 | static 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 19cbb5e9ece2..174f1b9c8c03 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); | |||
161 | extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); | 169 | extern int iommu_set_da_range(struct iommu *obj, u32 start, u32 end); |
162 | extern struct iommu *iommu_get(const char *name); | 170 | extern struct iommu *iommu_get(const char *name); |
163 | extern void iommu_put(struct iommu *obj); | 171 | extern void iommu_put(struct iommu *obj); |
172 | extern 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 | ||
165 | extern void iommu_save_ctx(struct iommu *obj); | 177 | extern void iommu_save_ctx(struct iommu *obj); |
166 | extern void iommu_restore_ctx(struct iommu *obj); | 178 | extern void iommu_restore_ctx(struct iommu *obj); |
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index 4b3218eaf3e5..e3eb0380090a 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 | */ |
784 | static irqreturn_t iommu_fault_handler(int irq, void *data) | 784 | static 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 | } |
921 | EXPORT_SYMBOL_GPL(iommu_put); | 916 | EXPORT_SYMBOL_GPL(iommu_put); |
922 | 917 | ||
918 | int 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 | } | ||
943 | EXPORT_SYMBOL_GPL(iommu_set_isr); | ||
944 | |||
923 | /* | 945 | /* |
924 | * OMAP Device MMU(IOMMU) detection | 946 | * OMAP Device MMU(IOMMU) detection |
925 | */ | 947 | */ |