diff options
author | Tony Lindgren <tony@atomide.com> | 2010-07-02 04:23:30 -0400 |
---|---|---|
committer | Tony Lindgren <tony@atomide.com> | 2010-07-02 04:23:30 -0400 |
commit | f40fd0e215b1bde4e43add1aacbe6faf6dbbea53 (patch) | |
tree | 05eeb8b7236f07303510162602afe05bfceecebe /arch/arm | |
parent | 9f2952dbcbc0a143cff19f2e44fc504901aad86f (diff) | |
parent | 1fd7f467127fcaea490451052fea22f234bbb206 (diff) |
Merge branch 'v2.6.35-rc3-iommu-for-next' of git://gitorious.org/~doyu/lk/mainline into omap-for-linus
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 5 | ||||
-rw-r--r-- | arch/arm/mach-omap2/iommu2.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap-iommu.c | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/iommu.h | 2 | ||||
-rw-r--r-- | arch/arm/plat-omap/iommu.c | 27 | ||||
-rw-r--r-- | arch/arm/plat-omap/iopgtable.h | 8 |
6 files changed, 70 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index ea52b034e963..6c6d7c6f7aee 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile | |||
@@ -89,7 +89,10 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o | |||
89 | obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o | 89 | obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o |
90 | mailbox_mach-objs := mailbox.o | 90 | mailbox_mach-objs := mailbox.o |
91 | 91 | ||
92 | obj-$(CONFIG_OMAP_IOMMU) := iommu2.o omap-iommu.o | 92 | obj-$(CONFIG_OMAP_IOMMU) += iommu2.o |
93 | |||
94 | iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o | ||
95 | obj-y += $(iommu-m) $(iommu-y) | ||
93 | 96 | ||
94 | i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o | 97 | i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o |
95 | obj-y += $(i2c-omap-m) $(i2c-omap-y) | 98 | obj-y += $(i2c-omap-m) $(i2c-omap-y) |
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c index e82da680d908..14ee686b6492 100644 --- a/arch/arm/mach-omap2/iommu2.c +++ b/arch/arm/mach-omap2/iommu2.c | |||
@@ -44,9 +44,13 @@ | |||
44 | #define MMU_IRQ_EMUMISS (1 << 2) | 44 | #define MMU_IRQ_EMUMISS (1 << 2) |
45 | #define MMU_IRQ_TRANSLATIONFAULT (1 << 1) | 45 | #define MMU_IRQ_TRANSLATIONFAULT (1 << 1) |
46 | #define MMU_IRQ_TLBMISS (1 << 0) | 46 | #define MMU_IRQ_TLBMISS (1 << 0) |
47 | #define MMU_IRQ_MASK \ | 47 | |
48 | (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \ | 48 | #define __MMU_IRQ_FAULT \ |
49 | MMU_IRQ_TRANSLATIONFAULT) | 49 | (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_EMUMISS | MMU_IRQ_TRANSLATIONFAULT) |
50 | #define MMU_IRQ_MASK \ | ||
51 | (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_TLBMISS) | ||
52 | #define MMU_IRQ_TWL_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT) | ||
53 | #define MMU_IRQ_TLB_MISS_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TLBMISS) | ||
50 | 54 | ||
51 | /* MMU_CNTL */ | 55 | /* MMU_CNTL */ |
52 | #define MMU_CNTL_SHIFT 1 | 56 | #define MMU_CNTL_SHIFT 1 |
@@ -61,6 +65,26 @@ | |||
61 | ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \ | 65 | ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \ |
62 | ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0) | 66 | ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0) |
63 | 67 | ||
68 | |||
69 | static void __iommu_set_twl(struct iommu *obj, bool on) | ||
70 | { | ||
71 | u32 l = iommu_read_reg(obj, MMU_CNTL); | ||
72 | |||
73 | if (on) | ||
74 | iommu_write_reg(obj, MMU_IRQ_TWL_MASK, MMU_IRQENABLE); | ||
75 | else | ||
76 | iommu_write_reg(obj, MMU_IRQ_TLB_MISS_MASK, MMU_IRQENABLE); | ||
77 | |||
78 | l &= ~MMU_CNTL_MASK; | ||
79 | if (on) | ||
80 | l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN); | ||
81 | else | ||
82 | l |= (MMU_CNTL_MMU_EN); | ||
83 | |||
84 | iommu_write_reg(obj, l, MMU_CNTL); | ||
85 | } | ||
86 | |||
87 | |||
64 | static int omap2_iommu_enable(struct iommu *obj) | 88 | static int omap2_iommu_enable(struct iommu *obj) |
65 | { | 89 | { |
66 | u32 l, pa; | 90 | u32 l, pa; |
@@ -96,13 +120,9 @@ static int omap2_iommu_enable(struct iommu *obj) | |||
96 | l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE); | 120 | l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE); |
97 | iommu_write_reg(obj, l, MMU_SYSCONFIG); | 121 | iommu_write_reg(obj, l, MMU_SYSCONFIG); |
98 | 122 | ||
99 | iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE); | ||
100 | iommu_write_reg(obj, pa, MMU_TTB); | 123 | iommu_write_reg(obj, pa, MMU_TTB); |
101 | 124 | ||
102 | l = iommu_read_reg(obj, MMU_CNTL); | 125 | __iommu_set_twl(obj, true); |
103 | l &= ~MMU_CNTL_MASK; | ||
104 | l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN); | ||
105 | iommu_write_reg(obj, l, MMU_CNTL); | ||
106 | 126 | ||
107 | return 0; | 127 | return 0; |
108 | } | 128 | } |
@@ -118,6 +138,11 @@ static void omap2_iommu_disable(struct iommu *obj) | |||
118 | dev_dbg(obj->dev, "%s is shutting down\n", obj->name); | 138 | dev_dbg(obj->dev, "%s is shutting down\n", obj->name); |
119 | } | 139 | } |
120 | 140 | ||
141 | static void omap2_iommu_set_twl(struct iommu *obj, bool on) | ||
142 | { | ||
143 | __iommu_set_twl(obj, false); | ||
144 | } | ||
145 | |||
121 | static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) | 146 | static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) |
122 | { | 147 | { |
123 | int i; | 148 | int i; |
@@ -147,7 +172,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) | |||
147 | printk("\n"); | 172 | printk("\n"); |
148 | 173 | ||
149 | iommu_write_reg(obj, stat, MMU_IRQSTATUS); | 174 | iommu_write_reg(obj, stat, MMU_IRQSTATUS); |
150 | omap2_iommu_disable(obj); | 175 | |
151 | return stat; | 176 | return stat; |
152 | } | 177 | } |
153 | 178 | ||
@@ -300,6 +325,7 @@ static const struct iommu_functions omap2_iommu_ops = { | |||
300 | 325 | ||
301 | .enable = omap2_iommu_enable, | 326 | .enable = omap2_iommu_enable, |
302 | .disable = omap2_iommu_disable, | 327 | .disable = omap2_iommu_disable, |
328 | .set_twl = omap2_iommu_set_twl, | ||
303 | .fault_isr = omap2_iommu_fault_isr, | 329 | .fault_isr = omap2_iommu_fault_isr, |
304 | 330 | ||
305 | .tlb_read_cr = omap2_tlb_read_cr, | 331 | .tlb_read_cr = omap2_tlb_read_cr, |
diff --git a/arch/arm/mach-omap2/omap-iommu.c b/arch/arm/mach-omap2/omap-iommu.c index eb9bee73e0cb..f5a1aad1a5c0 100644 --- a/arch/arm/mach-omap2/omap-iommu.c +++ b/arch/arm/mach-omap2/omap-iommu.c | |||
@@ -59,7 +59,7 @@ static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES]; | |||
59 | static struct iommu_device omap4_devices[] = { | 59 | static struct iommu_device omap4_devices[] = { |
60 | { | 60 | { |
61 | .base = OMAP4_MMU1_BASE, | 61 | .base = OMAP4_MMU1_BASE, |
62 | .irq = INT_44XX_DUCATI_MMU_IRQ, | 62 | .irq = OMAP44XX_IRQ_DUCATI_MMU, |
63 | .pdata = { | 63 | .pdata = { |
64 | .name = "ducati", | 64 | .name = "ducati", |
65 | .nr_tlb_entries = 32, | 65 | .nr_tlb_entries = 32, |
diff --git a/arch/arm/plat-omap/include/plat/iommu.h b/arch/arm/plat-omap/include/plat/iommu.h index 0752af9d099e..33c7d41cb6a5 100644 --- a/arch/arm/plat-omap/include/plat/iommu.h +++ b/arch/arm/plat-omap/include/plat/iommu.h | |||
@@ -80,6 +80,7 @@ struct iommu_functions { | |||
80 | 80 | ||
81 | int (*enable)(struct iommu *obj); | 81 | int (*enable)(struct iommu *obj); |
82 | void (*disable)(struct iommu *obj); | 82 | void (*disable)(struct iommu *obj); |
83 | void (*set_twl)(struct iommu *obj, bool on); | ||
83 | u32 (*fault_isr)(struct iommu *obj, u32 *ra); | 84 | u32 (*fault_isr)(struct iommu *obj, u32 *ra); |
84 | 85 | ||
85 | void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr); | 86 | void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr); |
@@ -143,6 +144,7 @@ extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e); | |||
143 | extern u32 iotlb_cr_to_virt(struct cr_regs *cr); | 144 | extern u32 iotlb_cr_to_virt(struct cr_regs *cr); |
144 | 145 | ||
145 | extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e); | 146 | extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e); |
147 | extern void iommu_set_twl(struct iommu *obj, bool on); | ||
146 | extern void flush_iotlb_page(struct iommu *obj, u32 da); | 148 | extern void flush_iotlb_page(struct iommu *obj, u32 da); |
147 | extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end); | 149 | extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end); |
148 | extern void flush_iotlb_all(struct iommu *obj); | 150 | extern void flush_iotlb_all(struct iommu *obj); |
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c index bc094dbacee6..a202a2ce6e3d 100644 --- a/arch/arm/plat-omap/iommu.c +++ b/arch/arm/plat-omap/iommu.c | |||
@@ -370,6 +370,23 @@ void flush_iotlb_all(struct iommu *obj) | |||
370 | } | 370 | } |
371 | EXPORT_SYMBOL_GPL(flush_iotlb_all); | 371 | EXPORT_SYMBOL_GPL(flush_iotlb_all); |
372 | 372 | ||
373 | /** | ||
374 | * iommu_set_twl - enable/disable table walking logic | ||
375 | * @obj: target iommu | ||
376 | * @on: enable/disable | ||
377 | * | ||
378 | * Function used to enable/disable TWL. If one wants to work | ||
379 | * exclusively with locked TLB entries and receive notifications | ||
380 | * for TLB miss then call this function to disable TWL. | ||
381 | */ | ||
382 | void iommu_set_twl(struct iommu *obj, bool on) | ||
383 | { | ||
384 | clk_enable(obj->clk); | ||
385 | arch_iommu->set_twl(obj, on); | ||
386 | clk_disable(obj->clk); | ||
387 | } | ||
388 | EXPORT_SYMBOL_GPL(iommu_set_twl); | ||
389 | |||
373 | #if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) | 390 | #if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) |
374 | 391 | ||
375 | ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes) | 392 | ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes) |
@@ -653,7 +670,7 @@ void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd, u32 **ppte) | |||
653 | if (!*iopgd) | 670 | if (!*iopgd) |
654 | goto out; | 671 | goto out; |
655 | 672 | ||
656 | if (*iopgd & IOPGD_TABLE) | 673 | if (iopgd_is_table(*iopgd)) |
657 | iopte = iopte_offset(iopgd, da); | 674 | iopte = iopte_offset(iopgd, da); |
658 | out: | 675 | out: |
659 | *ppgd = iopgd; | 676 | *ppgd = iopgd; |
@@ -670,7 +687,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da) | |||
670 | if (!*iopgd) | 687 | if (!*iopgd) |
671 | return 0; | 688 | return 0; |
672 | 689 | ||
673 | if (*iopgd & IOPGD_TABLE) { | 690 | if (iopgd_is_table(*iopgd)) { |
674 | int i; | 691 | int i; |
675 | u32 *iopte = iopte_offset(iopgd, da); | 692 | u32 *iopte = iopte_offset(iopgd, da); |
676 | 693 | ||
@@ -745,7 +762,7 @@ static void iopgtable_clear_entry_all(struct iommu *obj) | |||
745 | if (!*iopgd) | 762 | if (!*iopgd) |
746 | continue; | 763 | continue; |
747 | 764 | ||
748 | if (*iopgd & IOPGD_TABLE) | 765 | if (iopgd_is_table(*iopgd)) |
749 | iopte_free(iopte_offset(iopgd, 0)); | 766 | iopte_free(iopte_offset(iopgd, 0)); |
750 | 767 | ||
751 | *iopgd = 0; | 768 | *iopgd = 0; |
@@ -783,9 +800,11 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) | |||
783 | if (!stat) | 800 | if (!stat) |
784 | return IRQ_HANDLED; | 801 | return IRQ_HANDLED; |
785 | 802 | ||
803 | iommu_disable(obj); | ||
804 | |||
786 | iopgd = iopgd_offset(obj, da); | 805 | iopgd = iopgd_offset(obj, da); |
787 | 806 | ||
788 | if (!(*iopgd & IOPGD_TABLE)) { | 807 | if (!iopgd_is_table(*iopgd)) { |
789 | dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__, | 808 | dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__, |
790 | da, iopgd, *iopgd); | 809 | da, iopgd, *iopgd); |
791 | return IRQ_NONE; | 810 | return IRQ_NONE; |
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h index ab23b6a140fd..c3e93bb0911f 100644 --- a/arch/arm/plat-omap/iopgtable.h +++ b/arch/arm/plat-omap/iopgtable.h | |||
@@ -63,6 +63,8 @@ | |||
63 | #define IOPGD_SECTION (2 << 0) | 63 | #define IOPGD_SECTION (2 << 0) |
64 | #define IOPGD_SUPER (1 << 18 | 2 << 0) | 64 | #define IOPGD_SUPER (1 << 18 | 2 << 0) |
65 | 65 | ||
66 | #define iopgd_is_table(x) (((x) & 3) == IOPGD_TABLE) | ||
67 | |||
66 | #define IOPTE_SMALL (2 << 0) | 68 | #define IOPTE_SMALL (2 << 0) |
67 | #define IOPTE_LARGE (1 << 0) | 69 | #define IOPTE_LARGE (1 << 0) |
68 | 70 | ||
@@ -70,12 +72,12 @@ | |||
70 | #define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1)) | 72 | #define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1)) |
71 | #define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da)) | 73 | #define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da)) |
72 | 74 | ||
73 | #define iopte_paddr(iopgd) (*iopgd & ~((1 << 10) - 1)) | 75 | #define iopgd_page_paddr(iopgd) (*iopgd & ~((1 << 10) - 1)) |
74 | #define iopte_vaddr(iopgd) ((u32 *)phys_to_virt(iopte_paddr(iopgd))) | 76 | #define iopgd_page_vaddr(iopgd) ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd))) |
75 | 77 | ||
76 | /* to find an entry in the second-level page table. */ | 78 | /* to find an entry in the second-level page table. */ |
77 | #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) | 79 | #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) |
78 | #define iopte_offset(iopgd, da) (iopte_vaddr(iopgd) + iopte_index(da)) | 80 | #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da)) |
79 | 81 | ||
80 | static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, | 82 | static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, |
81 | u32 flags) | 83 | u32 flags) |