Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
mips
dec
kn01-berr.c
Go to the documentation of this file.
1
/*
2
* Bus error event handling code for DECstation/DECsystem 3100
3
* and 2100 (KN01) systems equipped with parity error detection
4
* logic.
5
*
6
* Copyright (c) 2005 Maciej W. Rozycki
7
*
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License
10
* as published by the Free Software Foundation; either version
11
* 2 of the License, or (at your option) any later version.
12
*/
13
14
#include <
linux/init.h
>
15
#include <
linux/interrupt.h
>
16
#include <linux/kernel.h>
17
#include <
linux/spinlock.h
>
18
#include <linux/types.h>
19
20
#include <asm/inst.h>
21
#include <asm/irq_regs.h>
22
#include <
asm/mipsregs.h
>
23
#include <asm/page.h>
24
#include <asm/ptrace.h>
25
#include <asm/traps.h>
26
#include <asm/uaccess.h>
27
28
#include <
asm/dec/kn01.h
>
29
30
31
/* CP0 hazard avoidance. */
32
#define BARRIER \
33
__asm__ __volatile__( \
34
".set push\n\t" \
35
".set noreorder\n\t" \
36
"nop\n\t" \
37
".set pop\n\t")
38
39
/*
40
* Bits 7:0 of the Control Register are write-only -- the
41
* corresponding bits of the Status Register have a different
42
* meaning. Hence we use a cache. It speeds up things a bit
43
* as well.
44
*
45
* There is no default value -- it has to be initialized.
46
*/
47
u16
cached_kn01_csr
;
48
static
DEFINE_RAW_SPINLOCK
(kn01_lock);
49
50
51
static
inline
void
dec_kn01_be_ack(
void
)
52
{
53
volatile
u16
*
csr
= (
void
*)
CKSEG1ADDR
(
KN01_SLOT_BASE
+
KN01_CSR
);
54
unsigned
long
flags
;
55
56
raw_spin_lock_irqsave
(&kn01_lock, flags);
57
58
*csr =
cached_kn01_csr
|
KN01_CSR_MEMERR
;
/* Clear bus IRQ. */
59
iob
();
60
61
raw_spin_unlock_irqrestore
(&kn01_lock, flags);
62
}
63
64
static
int
dec_kn01_be_backend(
struct
pt_regs
*
regs
,
int
is_fixup,
int
invoker)
65
{
66
volatile
u32
*kn01_erraddr = (
void
*)
CKSEG1ADDR
(
KN01_SLOT_BASE
+
67
KN01_ERRADDR
);
68
69
static
const
char
excstr[] =
"exception"
;
70
static
const
char
intstr[] =
"interrupt"
;
71
static
const
char
cpustr[] =
"CPU"
;
72
static
const
char
mreadstr[] =
"memory read"
;
73
static
const
char
readstr[] =
"read"
;
74
static
const
char
writestr[] =
"write"
;
75
static
const
char
timestr[] =
"timeout"
;
76
static
const
char
paritystr[] =
"parity error"
;
77
78
int
data
= regs->
cp0_cause
& 4;
79
unsigned
int
__user
*
pc
= (
unsigned
int
__user
*)regs->
cp0_epc
+
80
((regs->
cp0_cause
&
CAUSEF_BD
) != 0);
81
union
mips_instruction
insn
;
82
unsigned
long
entrylo,
offset
;
83
long
asid
, entryhi,
vaddr
;
84
85
const
char
*
kind
, *agent, *cycle, *
event
;
86
unsigned
long
address
;
87
88
u32
erraddr = *kn01_erraddr;
89
int
action
=
MIPS_BE_FATAL
;
90
91
/* Ack ASAP, so that any subsequent errors get caught. */
92
dec_kn01_be_ack();
93
94
kind = invoker ? intstr : excstr;
95
96
agent = cpustr;
97
98
if
(invoker)
99
address = erraddr;
100
else
{
101
/* Bloody hardware doesn't record the address for reads... */
102
if
(data) {
103
/* This never faults. */
104
__get_user
(
insn
.word, pc);
105
vaddr = regs->
regs
[
insn
.i_format.rs] +
106
insn
.i_format.simmediate;
107
}
else
108
vaddr = (
long
)pc;
109
if
(
KSEGX
(vaddr) ==
CKSEG0
||
KSEGX
(vaddr) ==
CKSEG1
)
110
address =
CPHYSADDR
(vaddr);
111
else
{
112
/* Peek at what physical address the CPU used. */
113
asid =
read_c0_entryhi
();
114
entryhi = asid & (
PAGE_SIZE
- 1);
115
entryhi |= vaddr & ~(
PAGE_SIZE
- 1);
116
write_c0_entryhi
(entryhi);
117
BARRIER
;
118
tlb_probe();
119
/* No need to check for presence. */
120
tlb_read();
121
entrylo =
read_c0_entrylo0
();
122
write_c0_entryhi
(asid);
123
offset = vaddr & (
PAGE_SIZE
- 1);
124
address = (entrylo & ~(
PAGE_SIZE
- 1)) |
offset
;
125
}
126
}
127
128
/* Treat low 256MB as memory, high -- as I/O. */
129
if
(address < 0x10000000) {
130
cycle = mreadstr;
131
event
= paritystr;
132
}
else
{
133
cycle = invoker ? writestr : readstr;
134
event
= timestr;
135
}
136
137
if
(is_fixup)
138
action =
MIPS_BE_FIXUP
;
139
140
if
(action !=
MIPS_BE_FIXUP
)
141
printk
(
KERN_ALERT
"Bus error %s: %s %s %s at %#010lx\n"
,
142
kind, agent, cycle, event, address);
143
144
return
action
;
145
}
146
147
int
dec_kn01_be_handler
(
struct
pt_regs
*regs,
int
is_fixup)
148
{
149
return
dec_kn01_be_backend(regs, is_fixup, 0);
150
}
151
152
irqreturn_t
dec_kn01_be_interrupt
(
int
irq,
void
*
dev_id
)
153
{
154
volatile
u16
*csr = (
void
*)
CKSEG1ADDR
(
KN01_SLOT_BASE
+
KN01_CSR
);
155
struct
pt_regs
*regs =
get_irq_regs
();
156
int
action
;
157
158
if
(!(*csr &
KN01_CSR_MEMERR
))
159
return
IRQ_NONE
;
/* Must have been video. */
160
161
action = dec_kn01_be_backend(regs, 0, 1);
162
163
if
(action ==
MIPS_BE_DISCARD
)
164
return
IRQ_HANDLED
;
165
166
/*
167
* FIXME: Find the affected processes and kill them, otherwise
168
* we must die.
169
*
170
* The interrupt is asynchronously delivered thus EPC and RA
171
* may be irrelevant, but are printed for a reference.
172
*/
173
printk
(
KERN_ALERT
"Fatal bus interrupt, epc == %08lx, ra == %08lx\n"
,
174
regs->
cp0_epc
, regs->
regs
[31]);
175
die
(
"Unrecoverable bus error"
, regs);
176
}
177
178
179
void
__init
dec_kn01_be_init
(
void
)
180
{
181
volatile
u16
*csr = (
void
*)
CKSEG1ADDR
(
KN01_SLOT_BASE
+
KN01_CSR
);
182
unsigned
long
flags
;
183
184
raw_spin_lock_irqsave
(&kn01_lock, flags);
185
186
/* Preset write-only bits of the Control Register cache. */
187
cached_kn01_csr
= *csr;
188
cached_kn01_csr
&=
KN01_CSR_STATUS
|
KN01_CSR_PARDIS
|
KN01_CSR_TXDIS
;
189
cached_kn01_csr
|=
KN01_CSR_LEDS
;
190
191
/* Enable parity error detection. */
192
cached_kn01_csr
&= ~
KN01_CSR_PARDIS
;
193
*csr =
cached_kn01_csr
;
194
iob
();
195
196
raw_spin_unlock_irqrestore
(&kn01_lock, flags);
197
198
/* Clear any leftover errors from the firmware. */
199
dec_kn01_be_ack();
200
}
Generated on Thu Jan 10 2013 13:09:14 for Linux Kernel by
1.8.2