summaryrefslogtreecommitdiff
path: root/drivers/staging/tidspbridge/core/mmu_fault.c
blob: 5c0124f70732b4fda2b9cc1f99f499a802f510df (plain)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * 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"

static u32 dmmu_event_mask;
u32 fault_addr;

static bool mmu_check_if_fault(struct bridge_dev_context *dev_context);

/*
 *  ======== 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)
		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 = (struct deh_mgr *)pRefData;
	struct bridge_dev_context *dev_context;
	struct cfg_hostres *resources;

	DBC_REQUIRE(irq == INT_DSP_MMU_IRQ);
	DBC_REQUIRE(deh_mgr_obj);

	if (deh_mgr_obj) {

		dev_context =
		    (struct bridge_dev_context *)deh_mgr_obj->hbridge_context;

		resources = dev_context->resources;

		if (!resources) {
			dev_dbg(bridge, "%s: Failed to get Host Resources\n",
				__func__);
			return IRQ_HANDLED;
		}
		if (mmu_check_if_fault(dev_context)) {
			printk(KERN_INFO "***** DSPMMU FAULT ***** IRQStatus "
			       "0x%x\n", dmmu_event_mask);
			printk(KERN_INFO "***** DSPMMU FAULT ***** fault_addr "
			       "0x%x\n", 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;
}

/*
 *  ======== mmu_check_if_fault ========
 *      Check to see if MMU Fault is valid TLB miss from DSP
 *  Note: This function is called from an ISR
 */
static bool mmu_check_if_fault(struct bridge_dev_context *dev_context)
{

	bool ret = false;
	hw_status hw_status_obj;
	struct cfg_hostres *resources = dev_context->resources;

	if (!resources) {
		dev_dbg(bridge, "%s: Failed to get Host Resources in\n",
			__func__);
		return ret;
	}
	hw_status_obj =
	    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);
		ret = true;
	}
	return ret;
}