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:
@ -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 @@
|
|||||||
#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 @@
|
|||||||
((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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 = {
|
|||||||
|
|
||||||
.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];
|
|||||||
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 {
|
|||||||
|
|
||||||
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);
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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 @@
|
|||||||
#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 @@
|
|||||||
#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)
|
||||||
|
Reference in New Issue
Block a user