diff --git a/drivers/staging/tidspbridge/core/_deh.h b/drivers/staging/tidspbridge/core/_deh.h index f1254f0aa037..16723cd34831 100644 --- a/drivers/staging/tidspbridge/core/_deh.h +++ b/drivers/staging/tidspbridge/core/_deh.h @@ -32,6 +32,4 @@ struct deh_mgr { struct tasklet_struct dpc_tasklet; }; -int mmu_fault_isr(struct iommu *mmu); - #endif /* _DEH_ */ diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c index b68050a969a6..d643c2ba9dc1 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430.c +++ b/drivers/staging/tidspbridge/core/tiomap3430.c @@ -57,7 +57,6 @@ #include "_tiomap.h" #include "_tiomap_pwr.h" #include "tiomap_io.h" -#include "_deh.h" /* Offset in shared mem to write to in order to synchronize start with DSP */ #define SHMSYNCOFFSET 4 /* GPP byte offset */ @@ -380,7 +379,6 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, } if (!status) { dev_context->dsp_mmu = mmu; - mmu->isr = mmu_fault_isr; sm_sg = &dev_context->sh_s; sg0_da = iommu_kmap(mmu, sm_sg->seg0_da, sm_sg->seg0_pa, sm_sg->seg0_size, IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_32); diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c index 2e1ac89644d3..14f319134357 100644 --- a/drivers/staging/tidspbridge/core/ue_deh.c +++ b/drivers/staging/tidspbridge/core/ue_deh.c @@ -31,7 +31,7 @@ #include #include -#define MMU_CNTL_TWL_EN (1 << 2) +static u32 fault_addr; static void mmu_fault_dpc(unsigned long data) { @@ -43,18 +43,43 @@ static void mmu_fault_dpc(unsigned long data) bridge_deh_notify(deh, DSP_MMUFAULT, 0); } -int mmu_fault_isr(struct iommu *mmu) +static irqreturn_t mmu_fault_isr(int irq, void *data) { - struct deh_mgr *dm; + struct deh_mgr *deh = data; + struct cfg_hostres *resources; + u32 event; - dev_get_deh_mgr(dev_get_first(), &dm); + if (!deh) + return IRQ_HANDLED; - if (!dm) - return -EPERM; + resources = deh->hbridge_context->resources; + if (!resources) { + dev_dbg(bridge, "%s: Failed to get Host Resources\n", + __func__); + return IRQ_HANDLED; + } - iommu_write_reg(mmu, 0, MMU_IRQENABLE); - tasklet_schedule(&dm->dpc_tasklet); - return 0; + hw_mmu_event_status(resources->dw_dmmu_base, &event); + if (event == HW_MMU_TRANSLATION_FAULT) { + hw_mmu_fault_addr_read(resources->dw_dmmu_base, &fault_addr); + dev_dbg(bridge, "%s: event=0x%x, fault_addr=0x%x\n", __func__, + event, fault_addr); + /* + * Schedule a DPC directly. In the future, it may be + * necessary to check if DSP MMU fault is intended for + * Bridge. + */ + tasklet_schedule(&deh->dpc_tasklet); + + /* Disable the MMU events, else once we clear it will + * start to raise INTs again */ + hw_mmu_event_disable(resources->dw_dmmu_base, + HW_MMU_TRANSLATION_FAULT); + } else { + hw_mmu_event_disable(resources->dw_dmmu_base, + HW_MMU_ALL_INTERRUPTS); + } + return IRQ_HANDLED; } int bridge_deh_create(struct deh_mgr **ret_deh, @@ -136,45 +161,42 @@ int bridge_deh_register_notify(struct deh_mgr *deh, u32 event_mask, #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE static void mmu_fault_print_stack(struct bridge_dev_context *dev_context) { - void *dummy_addr; - u32 fa, tmp; - struct iotlb_entry e; - struct iommu *mmu = dev_context->dsp_mmu; - dummy_addr = (void *)__get_free_page(GFP_ATOMIC); + struct cfg_hostres *resources; + struct hw_mmu_map_attrs_t map_attrs = { + .endianism = HW_LITTLE_ENDIAN, + .element_size = HW_ELEM_SIZE16BIT, + .mixed_size = HW_MMU_CPUES, + }; + void *dummy_va_addr; + + resources = dev_context->resources; + dummy_va_addr = (void*)__get_free_page(GFP_ATOMIC); /* * Before acking the MMU fault, let's make sure MMU can only * access entry #0. Then add a new entry so that the DSP OS * can continue in order to dump the stack. */ - tmp = iommu_read_reg(mmu, MMU_CNTL); - tmp &= ~MMU_CNTL_TWL_EN; - iommu_write_reg(mmu, tmp, MMU_CNTL); - fa = iommu_read_reg(mmu, MMU_FAULT_AD); - e.da = fa & PAGE_MASK; - e.pa = virt_to_phys(dummy_addr); - e.valid = 1; - e.prsvd = 1; - e.pgsz = IOVMF_PGSZ_4K & MMU_CAM_PGSZ_MASK; - e.endian = MMU_RAM_ENDIAN_LITTLE; - e.elsz = MMU_RAM_ELSZ_32; - e.mixed = 0; + hw_mmu_twl_disable(resources->dw_dmmu_base); + hw_mmu_tlb_flush_all(resources->dw_dmmu_base); - load_iotlb_entry(dev_context->dsp_mmu, &e); + hw_mmu_tlb_add(resources->dw_dmmu_base, + virt_to_phys(dummy_va_addr), fault_addr, + HW_PAGE_SIZE4KB, 1, + &map_attrs, HW_SET, HW_SET); dsp_clk_enable(DSP_CLK_GPT8); dsp_gpt_wait_overflow(DSP_CLK_GPT8, 0xfffffffe); /* Clear MMU interrupt */ - tmp = iommu_read_reg(mmu, MMU_IRQSTATUS); - iommu_write_reg(mmu, tmp, MMU_IRQSTATUS); - + hw_mmu_event_ack(resources->dw_dmmu_base, + HW_MMU_TRANSLATION_FAULT); dump_dsp_stack(dev_context); dsp_clk_disable(DSP_CLK_GPT8); - iopgtable_clear_entry(mmu, fa); - free_page((unsigned long)dummy_addr); + hw_mmu_disable(resources->dw_dmmu_base); + free_page((unsigned long)dummy_va_addr); } #endif @@ -193,7 +215,6 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info) { struct bridge_dev_context *dev_context; const char *str = event_to_string(event); - u32 fa; if (!deh) return; @@ -211,8 +232,8 @@ void bridge_deh_notify(struct deh_mgr *deh, int event, int info) #endif break; case DSP_MMUFAULT: - fa = iommu_read_reg(dev_context->dsp_mmu, MMU_FAULT_AD); - dev_err(bridge, "%s: %s, addr=0x%x", __func__, str, fa); + dev_err(bridge, "%s: %s, addr=0x%x", __func__, + str, fault_addr); #ifdef CONFIG_TIDSPBRIDGE_BACKTRACE print_dsp_trace_buffer(dev_context); dump_dl_modules(dev_context);