提交 f40fd0e2 编写于 作者: T Tony Lindgren

Merge branch 'v2.6.35-rc3-iommu-for-next' of...

Merge branch 'v2.6.35-rc3-iommu-for-next' of git://gitorious.org/~doyu/lk/mainline into omap-for-linus
...@@ -89,7 +89,10 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o ...@@ -89,7 +89,10 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o
mailbox_mach-objs := mailbox.o mailbox_mach-objs := mailbox.o
obj-$(CONFIG_OMAP_IOMMU) := iommu2.o omap-iommu.o obj-$(CONFIG_OMAP_IOMMU) += iommu2.o
iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o
obj-y += $(iommu-m) $(iommu-y)
i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o
obj-y += $(i2c-omap-m) $(i2c-omap-y) obj-y += $(i2c-omap-m) $(i2c-omap-y)
......
...@@ -44,9 +44,13 @@ ...@@ -44,9 +44,13 @@
#define MMU_IRQ_EMUMISS (1 << 2) #define MMU_IRQ_EMUMISS (1 << 2)
#define MMU_IRQ_TRANSLATIONFAULT (1 << 1) #define MMU_IRQ_TRANSLATIONFAULT (1 << 1)
#define MMU_IRQ_TLBMISS (1 << 0) #define MMU_IRQ_TLBMISS (1 << 0)
#define MMU_IRQ_MASK \
(MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \ #define __MMU_IRQ_FAULT \
MMU_IRQ_TRANSLATIONFAULT) (MMU_IRQ_MULTIHITFAULT | MMU_IRQ_EMUMISS | MMU_IRQ_TRANSLATIONFAULT)
#define MMU_IRQ_MASK \
(__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_TLBMISS)
#define MMU_IRQ_TWL_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TABLEWALKFAULT)
#define MMU_IRQ_TLB_MISS_MASK (__MMU_IRQ_FAULT | MMU_IRQ_TLBMISS)
/* MMU_CNTL */ /* MMU_CNTL */
#define MMU_CNTL_SHIFT 1 #define MMU_CNTL_SHIFT 1
...@@ -61,6 +65,26 @@ ...@@ -61,6 +65,26 @@
((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \ ((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \
((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0) ((pgsz) == MMU_CAM_PGSZ_4K) ? 0xfffff000 : 0)
static void __iommu_set_twl(struct iommu *obj, bool on)
{
u32 l = iommu_read_reg(obj, MMU_CNTL);
if (on)
iommu_write_reg(obj, MMU_IRQ_TWL_MASK, MMU_IRQENABLE);
else
iommu_write_reg(obj, MMU_IRQ_TLB_MISS_MASK, MMU_IRQENABLE);
l &= ~MMU_CNTL_MASK;
if (on)
l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
else
l |= (MMU_CNTL_MMU_EN);
iommu_write_reg(obj, l, MMU_CNTL);
}
static int omap2_iommu_enable(struct iommu *obj) static int omap2_iommu_enable(struct iommu *obj)
{ {
u32 l, pa; u32 l, pa;
...@@ -96,13 +120,9 @@ static int omap2_iommu_enable(struct iommu *obj) ...@@ -96,13 +120,9 @@ static int omap2_iommu_enable(struct iommu *obj)
l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE); l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
iommu_write_reg(obj, l, MMU_SYSCONFIG); iommu_write_reg(obj, l, MMU_SYSCONFIG);
iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE);
iommu_write_reg(obj, pa, MMU_TTB); iommu_write_reg(obj, pa, MMU_TTB);
l = iommu_read_reg(obj, MMU_CNTL); __iommu_set_twl(obj, true);
l &= ~MMU_CNTL_MASK;
l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
iommu_write_reg(obj, l, MMU_CNTL);
return 0; return 0;
} }
...@@ -118,6 +138,11 @@ static void omap2_iommu_disable(struct iommu *obj) ...@@ -118,6 +138,11 @@ static void omap2_iommu_disable(struct iommu *obj)
dev_dbg(obj->dev, "%s is shutting down\n", obj->name); dev_dbg(obj->dev, "%s is shutting down\n", obj->name);
} }
static void omap2_iommu_set_twl(struct iommu *obj, bool on)
{
__iommu_set_twl(obj, false);
}
static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
{ {
int i; int i;
...@@ -147,7 +172,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra) ...@@ -147,7 +172,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
printk("\n"); printk("\n");
iommu_write_reg(obj, stat, MMU_IRQSTATUS); iommu_write_reg(obj, stat, MMU_IRQSTATUS);
omap2_iommu_disable(obj);
return stat; return stat;
} }
...@@ -300,6 +325,7 @@ static const struct iommu_functions omap2_iommu_ops = { ...@@ -300,6 +325,7 @@ static const struct iommu_functions omap2_iommu_ops = {
.enable = omap2_iommu_enable, .enable = omap2_iommu_enable,
.disable = omap2_iommu_disable, .disable = omap2_iommu_disable,
.set_twl = omap2_iommu_set_twl,
.fault_isr = omap2_iommu_fault_isr, .fault_isr = omap2_iommu_fault_isr,
.tlb_read_cr = omap2_tlb_read_cr, .tlb_read_cr = omap2_tlb_read_cr,
......
...@@ -59,7 +59,7 @@ static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES]; ...@@ -59,7 +59,7 @@ static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES];
static struct iommu_device omap4_devices[] = { static struct iommu_device omap4_devices[] = {
{ {
.base = OMAP4_MMU1_BASE, .base = OMAP4_MMU1_BASE,
.irq = INT_44XX_DUCATI_MMU_IRQ, .irq = OMAP44XX_IRQ_DUCATI_MMU,
.pdata = { .pdata = {
.name = "ducati", .name = "ducati",
.nr_tlb_entries = 32, .nr_tlb_entries = 32,
......
...@@ -80,6 +80,7 @@ struct iommu_functions { ...@@ -80,6 +80,7 @@ struct iommu_functions {
int (*enable)(struct iommu *obj); int (*enable)(struct iommu *obj);
void (*disable)(struct iommu *obj); void (*disable)(struct iommu *obj);
void (*set_twl)(struct iommu *obj, bool on);
u32 (*fault_isr)(struct iommu *obj, u32 *ra); u32 (*fault_isr)(struct iommu *obj, u32 *ra);
void (*tlb_read_cr)(struct iommu *obj, struct cr_regs *cr); 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,6 +144,7 @@ extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
extern u32 iotlb_cr_to_virt(struct cr_regs *cr); extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e); extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
extern void iommu_set_twl(struct iommu *obj, bool on);
extern void flush_iotlb_page(struct iommu *obj, u32 da); extern void flush_iotlb_page(struct iommu *obj, u32 da);
extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end); extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
extern void flush_iotlb_all(struct iommu *obj); extern void flush_iotlb_all(struct iommu *obj);
......
...@@ -370,6 +370,23 @@ void flush_iotlb_all(struct iommu *obj) ...@@ -370,6 +370,23 @@ void flush_iotlb_all(struct iommu *obj)
} }
EXPORT_SYMBOL_GPL(flush_iotlb_all); EXPORT_SYMBOL_GPL(flush_iotlb_all);
/**
* iommu_set_twl - enable/disable table walking logic
* @obj: target iommu
* @on: enable/disable
*
* Function used to enable/disable TWL. If one wants to work
* exclusively with locked TLB entries and receive notifications
* for TLB miss then call this function to disable TWL.
*/
void iommu_set_twl(struct iommu *obj, bool on)
{
clk_enable(obj->clk);
arch_iommu->set_twl(obj, on);
clk_disable(obj->clk);
}
EXPORT_SYMBOL_GPL(iommu_set_twl);
#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE) #if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes) 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,7 +670,7 @@ void iopgtable_lookup_entry(struct iommu *obj, u32 da, u32 **ppgd, u32 **ppte)
if (!*iopgd) if (!*iopgd)
goto out; goto out;
if (*iopgd & IOPGD_TABLE) if (iopgd_is_table(*iopgd))
iopte = iopte_offset(iopgd, da); iopte = iopte_offset(iopgd, da);
out: out:
*ppgd = iopgd; *ppgd = iopgd;
...@@ -670,7 +687,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da) ...@@ -670,7 +687,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da)
if (!*iopgd) if (!*iopgd)
return 0; return 0;
if (*iopgd & IOPGD_TABLE) { if (iopgd_is_table(*iopgd)) {
int i; int i;
u32 *iopte = iopte_offset(iopgd, da); u32 *iopte = iopte_offset(iopgd, da);
...@@ -745,7 +762,7 @@ static void iopgtable_clear_entry_all(struct iommu *obj) ...@@ -745,7 +762,7 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
if (!*iopgd) if (!*iopgd)
continue; continue;
if (*iopgd & IOPGD_TABLE) if (iopgd_is_table(*iopgd))
iopte_free(iopte_offset(iopgd, 0)); iopte_free(iopte_offset(iopgd, 0));
*iopgd = 0; *iopgd = 0;
...@@ -783,9 +800,11 @@ static irqreturn_t iommu_fault_handler(int irq, void *data) ...@@ -783,9 +800,11 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
if (!stat) if (!stat)
return IRQ_HANDLED; return IRQ_HANDLED;
iommu_disable(obj);
iopgd = iopgd_offset(obj, da); iopgd = iopgd_offset(obj, da);
if (!(*iopgd & IOPGD_TABLE)) { if (!iopgd_is_table(*iopgd)) {
dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__, dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x\n", __func__,
da, iopgd, *iopgd); da, iopgd, *iopgd);
return IRQ_NONE; return IRQ_NONE;
......
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#define IOPGD_SECTION (2 << 0) #define IOPGD_SECTION (2 << 0)
#define IOPGD_SUPER (1 << 18 | 2 << 0) #define IOPGD_SUPER (1 << 18 | 2 << 0)
#define iopgd_is_table(x) (((x) & 3) == IOPGD_TABLE)
#define IOPTE_SMALL (2 << 0) #define IOPTE_SMALL (2 << 0)
#define IOPTE_LARGE (1 << 0) #define IOPTE_LARGE (1 << 0)
...@@ -70,12 +72,12 @@ ...@@ -70,12 +72,12 @@
#define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1)) #define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
#define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da)) #define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da))
#define iopte_paddr(iopgd) (*iopgd & ~((1 << 10) - 1)) #define iopgd_page_paddr(iopgd) (*iopgd & ~((1 << 10) - 1))
#define iopte_vaddr(iopgd) ((u32 *)phys_to_virt(iopte_paddr(iopgd))) #define iopgd_page_vaddr(iopgd) ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd)))
/* to find an entry in the second-level page table. */ /* to find an entry in the second-level page table. */
#define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1)) #define iopte_index(da) (((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
#define iopte_offset(iopgd, da) (iopte_vaddr(iopgd) + iopte_index(da)) #define iopte_offset(iopgd, da) (iopgd_page_vaddr(iopgd) + iopte_index(da))
static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa, static inline u32 iotlb_init_entry(struct iotlb_entry *e, u32 da, u32 pa,
u32 flags) u32 flags)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册