diff options
Diffstat (limited to 'drivers/staging/tidspbridge/core/ue_deh.c')
-rw-r--r-- | drivers/staging/tidspbridge/core/ue_deh.c | 50 |
1 files changed, 49 insertions, 1 deletions
diff --git a/drivers/staging/tidspbridge/core/ue_deh.c b/drivers/staging/tidspbridge/core/ue_deh.c index 904b837..26aec91 100644 --- a/drivers/staging/tidspbridge/core/ue_deh.c +++ b/drivers/staging/tidspbridge/core/ue_deh.c @@ -45,13 +45,61 @@ #include <hw_mmu.h> /* ----------------------------------- This */ -#include "mmu_fault.h" #include "_tiomap.h" #include "_deh.h" #include "_tiomap_pwr.h" #include <dspbridge/io_sm.h> +static void mmu_fault_dpc(unsigned long data) +{ + struct deh_mgr *hdeh_mgr = (void *)data; + + if (!hdeh_mgr) + return; + + bridge_deh_notify(hdeh_mgr, DSP_MMUFAULT, 0); +} + +static irqreturn_t mmu_fault_isr(int irq, void *data) +{ + struct deh_mgr *deh_mgr_obj = data; + struct cfg_hostres *resources; + u32 dmmu_event_mask; + + if (!deh_mgr_obj) + return IRQ_HANDLED; + + resources = deh_mgr_obj->hbridge_context->resources; + if (!resources) { + dev_dbg(bridge, "%s: Failed to get Host Resources\n", + __func__); + return IRQ_HANDLED; + } + + hw_mmu_event_status(resources->dw_dmmu_base, &dmmu_event_mask); + if (dmmu_event_mask == HW_MMU_TRANSLATION_FAULT) { + hw_mmu_fault_addr_read(resources->dw_dmmu_base, &deh_mgr_obj->fault_addr); + dev_info(bridge, "%s: status=0x%x, fault_addr=0x%x\n", __func__, + dmmu_event_mask, deh_mgr_obj->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_mgr_obj->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_mgr, struct dev_object *hdev_obj) { |