Merge branch 'v2.6.35-rc3-iommu-for-next' of git://gitorious.org/~doyu/lk/mainline into omap-for-linus
This commit is contained in:
commit
f40fd0e215
6 changed files with 70 additions and 18 deletions
|
@ -89,7 +89,10 @@ obj-$(CONFIG_OMAP3_EMU) += emu.o
|
|||
obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.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
|
||||
obj-y += $(i2c-omap-m) $(i2c-omap-y)
|
||||
|
|
|
@ -44,9 +44,13 @@
|
|||
#define MMU_IRQ_EMUMISS (1 << 2)
|
||||
#define MMU_IRQ_TRANSLATIONFAULT (1 << 1)
|
||||
#define MMU_IRQ_TLBMISS (1 << 0)
|
||||
#define MMU_IRQ_MASK \
|
||||
(MMU_IRQ_MULTIHITFAULT | MMU_IRQ_TABLEWALKFAULT | MMU_IRQ_EMUMISS | \
|
||||
MMU_IRQ_TRANSLATIONFAULT)
|
||||
|
||||
#define __MMU_IRQ_FAULT \
|
||||
(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 */
|
||||
#define MMU_CNTL_SHIFT 1
|
||||
|
@ -61,6 +65,26 @@
|
|||
((pgsz) == MMU_CAM_PGSZ_64K) ? 0xffff0000 : \
|
||||
((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)
|
||||
{
|
||||
u32 l, pa;
|
||||
|
@ -96,13 +120,9 @@ static int omap2_iommu_enable(struct iommu *obj)
|
|||
l |= (MMU_SYS_IDLE_SMART | MMU_SYS_AUTOIDLE);
|
||||
iommu_write_reg(obj, l, MMU_SYSCONFIG);
|
||||
|
||||
iommu_write_reg(obj, MMU_IRQ_MASK, MMU_IRQENABLE);
|
||||
iommu_write_reg(obj, pa, MMU_TTB);
|
||||
|
||||
l = iommu_read_reg(obj, MMU_CNTL);
|
||||
l &= ~MMU_CNTL_MASK;
|
||||
l |= (MMU_CNTL_MMU_EN | MMU_CNTL_TWL_EN);
|
||||
iommu_write_reg(obj, l, MMU_CNTL);
|
||||
__iommu_set_twl(obj, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -118,6 +138,11 @@ static void omap2_iommu_disable(struct iommu *obj)
|
|||
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)
|
||||
{
|
||||
int i;
|
||||
|
@ -147,7 +172,7 @@ static u32 omap2_iommu_fault_isr(struct iommu *obj, u32 *ra)
|
|||
printk("\n");
|
||||
|
||||
iommu_write_reg(obj, stat, MMU_IRQSTATUS);
|
||||
omap2_iommu_disable(obj);
|
||||
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
@ -300,6 +325,7 @@ static const struct iommu_functions omap2_iommu_ops = {
|
|||
|
||||
.enable = omap2_iommu_enable,
|
||||
.disable = omap2_iommu_disable,
|
||||
.set_twl = omap2_iommu_set_twl,
|
||||
.fault_isr = omap2_iommu_fault_isr,
|
||||
|
||||
.tlb_read_cr = omap2_tlb_read_cr,
|
||||
|
|
|
@ -59,7 +59,7 @@ static struct platform_device *omap3_iommu_pdev[NR_OMAP3_IOMMU_DEVICES];
|
|||
static struct iommu_device omap4_devices[] = {
|
||||
{
|
||||
.base = OMAP4_MMU1_BASE,
|
||||
.irq = INT_44XX_DUCATI_MMU_IRQ,
|
||||
.irq = OMAP44XX_IRQ_DUCATI_MMU,
|
||||
.pdata = {
|
||||
.name = "ducati",
|
||||
.nr_tlb_entries = 32,
|
||||
|
|
|
@ -80,6 +80,7 @@ struct iommu_functions {
|
|||
|
||||
int (*enable)(struct iommu *obj);
|
||||
void (*disable)(struct iommu *obj);
|
||||
void (*set_twl)(struct iommu *obj, bool on);
|
||||
u32 (*fault_isr)(struct iommu *obj, u32 *ra);
|
||||
|
||||
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);
|
|||
extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
|
||||
|
||||
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_range(struct iommu *obj, u32 start, u32 end);
|
||||
extern void flush_iotlb_all(struct iommu *obj);
|
||||
|
|
|
@ -370,6 +370,23 @@ void flush_iotlb_all(struct iommu *obj)
|
|||
}
|
||||
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)
|
||||
|
||||
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)
|
|||
if (!*iopgd)
|
||||
goto out;
|
||||
|
||||
if (*iopgd & IOPGD_TABLE)
|
||||
if (iopgd_is_table(*iopgd))
|
||||
iopte = iopte_offset(iopgd, da);
|
||||
out:
|
||||
*ppgd = iopgd;
|
||||
|
@ -670,7 +687,7 @@ static size_t iopgtable_clear_entry_core(struct iommu *obj, u32 da)
|
|||
if (!*iopgd)
|
||||
return 0;
|
||||
|
||||
if (*iopgd & IOPGD_TABLE) {
|
||||
if (iopgd_is_table(*iopgd)) {
|
||||
int i;
|
||||
u32 *iopte = iopte_offset(iopgd, da);
|
||||
|
||||
|
@ -745,7 +762,7 @@ static void iopgtable_clear_entry_all(struct iommu *obj)
|
|||
if (!*iopgd)
|
||||
continue;
|
||||
|
||||
if (*iopgd & IOPGD_TABLE)
|
||||
if (iopgd_is_table(*iopgd))
|
||||
iopte_free(iopte_offset(iopgd, 0));
|
||||
|
||||
*iopgd = 0;
|
||||
|
@ -783,9 +800,11 @@ static irqreturn_t iommu_fault_handler(int irq, void *data)
|
|||
if (!stat)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
iommu_disable(obj);
|
||||
|
||||
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__,
|
||||
da, iopgd, *iopgd);
|
||||
return IRQ_NONE;
|
||||
|
|
|
@ -63,6 +63,8 @@
|
|||
#define IOPGD_SECTION (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_LARGE (1 << 0)
|
||||
|
||||
|
@ -70,12 +72,12 @@
|
|||
#define iopgd_index(da) (((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
|
||||
#define iopgd_offset(obj, da) ((obj)->iopgd + iopgd_index(da))
|
||||
|
||||
#define iopte_paddr(iopgd) (*iopgd & ~((1 << 10) - 1))
|
||||
#define iopte_vaddr(iopgd) ((u32 *)phys_to_virt(iopte_paddr(iopgd)))
|
||||
#define iopgd_page_paddr(iopgd) (*iopgd & ~((1 << 10) - 1))
|
||||
#define iopgd_page_vaddr(iopgd) ((u32 *)phys_to_virt(iopgd_page_paddr(iopgd)))
|
||||
|
||||
/* to find an entry in the second-level page table. */
|
||||
#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,
|
||||
u32 flags)
|
||||
|
|
Loading…
Reference in a new issue