1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
/*
* mmu_fault.c
*
* DSP-BIOS Bridge driver support functions for TI OMAP processors.
*
* Implements DSP MMU fault handling functions.
*
* Copyright (C) 2005-2006 Texas Instruments, Inc.
*
* This package is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/* ----------------------------------- DSP/BIOS Bridge */
#include <dspbridge/std.h>
#include <dspbridge/dbdefs.h>
/* ----------------------------------- Trace & Debug */
#include <dspbridge/host_os.h>
#include <dspbridge/dbc.h>
/* ----------------------------------- OS Adaptation Layer */
#include <dspbridge/drv.h>
/* ----------------------------------- Link Driver */
#include <dspbridge/dspdeh.h>
/* ------------------------------------ Hardware Abstraction Layer */
#include <hw_defs.h>
#include <hw_mmu.h>
/* ----------------------------------- This */
#include "_deh.h"
#include <dspbridge/cfg.h>
#include "_tiomap.h"
#include "mmu_fault.h"
u32 fault_addr;
/*
* ======== mmu_fault_dpc ========
* Deferred procedure call to handle DSP MMU fault.
*/
void mmu_fault_dpc(IN unsigned long pRefData)
{
struct deh_mgr *hdeh_mgr = (struct deh_mgr *)pRefData;
if (!hdeh_mgr)
return;
bridge_deh_notify(hdeh_mgr, DSP_MMUFAULT, 0L);
}
/*
* ======== mmu_fault_isr ========
* ISR to be triggered by a DSP MMU fault interrupt.
*/
irqreturn_t mmu_fault_isr(int irq, IN void *pRefData)
{
struct deh_mgr *deh_mgr_obj = pRefData;
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, &fault_addr);
dev_info(bridge, "%s: status=0x%x, fault_addr=0x%x\n", __func__,
dmmu_event_mask, 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);
/* Reset err_info structure before use. */
deh_mgr_obj->err_info.dw_err_mask = DSP_MMUFAULT;
deh_mgr_obj->err_info.dw_val1 = fault_addr >> 16;
deh_mgr_obj->err_info.dw_val2 = fault_addr & 0xFFFF;
deh_mgr_obj->err_info.dw_val3 = 0L;
/* 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;
}
|