aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mn10300
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-02-08 07:19:31 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:30 -0500
commitb920de1b77b72ca9432ac3f97edb26541e65e5dd (patch)
tree40fa9be1470e929c47927dea7eddf184c0204229 /arch/mn10300
parentef3d534754f31fed9c3b976fee1ece1b3bc38282 (diff)
mn10300: add the MN10300/AM33 architecture to the kernel
Add architecture support for the MN10300/AM33 CPUs produced by MEI to the kernel. This patch also adds board support for the ASB2303 with the ASB2308 daughter board, and the ASB2305. The only processor supported is the MN103E010, which is an AM33v2 core plus on-chip devices. [akpm@linux-foundation.org: nuke cvs control strings] Signed-off-by: Masakazu Urade <urade.masakazu@jp.panasonic.com> Signed-off-by: Koichi Yasutake <yasutake.koichi@jp.panasonic.com> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/mn10300')
-rw-r--r--arch/mn10300/Kconfig381
-rw-r--r--arch/mn10300/Kconfig.debug135
-rw-r--r--arch/mn10300/Makefile135
-rw-r--r--arch/mn10300/boot/.gitignore1
-rw-r--r--arch/mn10300/boot/Makefile28
-rw-r--r--arch/mn10300/boot/compressed/Makefile22
-rw-r--r--arch/mn10300/boot/compressed/head.S86
-rw-r--r--arch/mn10300/boot/compressed/misc.c429
-rw-r--r--arch/mn10300/boot/compressed/misc.h18
-rw-r--r--arch/mn10300/boot/compressed/vmlinux.lds9
-rw-r--r--arch/mn10300/boot/install.sh67
-rw-r--r--arch/mn10300/boot/tools/build.c190
-rw-r--r--arch/mn10300/configs/asb2303_defconfig555
-rw-r--r--arch/mn10300/kernel/Makefile27
-rw-r--r--arch/mn10300/kernel/asm-offsets.c108
-rw-r--r--arch/mn10300/kernel/entry.S721
-rw-r--r--arch/mn10300/kernel/fpu-low.S197
-rw-r--r--arch/mn10300/kernel/fpu.c223
-rw-r--r--arch/mn10300/kernel/gdb-cache.S105
-rw-r--r--arch/mn10300/kernel/gdb-io-serial-low.S90
-rw-r--r--arch/mn10300/kernel/gdb-io-serial.c155
-rw-r--r--arch/mn10300/kernel/gdb-io-ttysm-low.S93
-rw-r--r--arch/mn10300/kernel/gdb-io-ttysm.c299
-rw-r--r--arch/mn10300/kernel/gdb-low.S115
-rw-r--r--arch/mn10300/kernel/gdb-stub.c1947
-rw-r--r--arch/mn10300/kernel/head.S255
-rw-r--r--arch/mn10300/kernel/init_task.c45
-rw-r--r--arch/mn10300/kernel/internal.h20
-rw-r--r--arch/mn10300/kernel/io.c30
-rw-r--r--arch/mn10300/kernel/irq.c235
-rw-r--r--arch/mn10300/kernel/kernel_execve.S37
-rw-r--r--arch/mn10300/kernel/kprobes.c653
-rw-r--r--arch/mn10300/kernel/kthread.S31
-rw-r--r--arch/mn10300/kernel/mn10300-debug.c58
-rw-r--r--arch/mn10300/kernel/mn10300-serial-low.S191
-rw-r--r--arch/mn10300/kernel/mn10300-serial.c1480
-rw-r--r--arch/mn10300/kernel/mn10300-serial.h126
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog-low.S59
-rw-r--r--arch/mn10300/kernel/mn10300-watchdog.c183
-rw-r--r--arch/mn10300/kernel/mn10300_ksyms.c37
-rw-r--r--arch/mn10300/kernel/module.c206
-rw-r--r--arch/mn10300/kernel/process.c297
-rw-r--r--arch/mn10300/kernel/profile-low.S72
-rw-r--r--arch/mn10300/kernel/profile.c51
-rw-r--r--arch/mn10300/kernel/ptrace.c379
-rw-r--r--arch/mn10300/kernel/rtc.c173
-rw-r--r--arch/mn10300/kernel/semaphore.c149
-rw-r--r--arch/mn10300/kernel/setup.c298
-rw-r--r--arch/mn10300/kernel/sigframe.h33
-rw-r--r--arch/mn10300/kernel/signal.c564
-rw-r--r--arch/mn10300/kernel/switch_to.S71
-rw-r--r--arch/mn10300/kernel/sys_mn10300.c193
-rw-r--r--arch/mn10300/kernel/time.c129
-rw-r--r--arch/mn10300/kernel/traps.c619
-rw-r--r--arch/mn10300/kernel/vmlinux.lds.S159
-rw-r--r--arch/mn10300/lib/Makefile7
-rw-r--r--arch/mn10300/lib/__ashldi3.S51
-rw-r--r--arch/mn10300/lib/__ashrdi3.S52
-rw-r--r--arch/mn10300/lib/__lshrdi3.S52
-rw-r--r--arch/mn10300/lib/ashrdi3.c61
-rw-r--r--arch/mn10300/lib/bitops.c51
-rw-r--r--arch/mn10300/lib/checksum.c99
-rw-r--r--arch/mn10300/lib/delay.c50
-rw-r--r--arch/mn10300/lib/do_csum.S162
-rw-r--r--arch/mn10300/lib/internal.h15
-rw-r--r--arch/mn10300/lib/lshrdi3.c60
-rw-r--r--arch/mn10300/lib/memcpy.S135
-rw-r--r--arch/mn10300/lib/memmove.S160
-rw-r--r--arch/mn10300/lib/memset.S121
-rw-r--r--arch/mn10300/lib/negdi2.c57
-rw-r--r--arch/mn10300/lib/usercopy.c166
-rw-r--r--arch/mn10300/mm/Makefile14
-rw-r--r--arch/mn10300/mm/cache-flush-mn10300.S192
-rw-r--r--arch/mn10300/mm/cache-mn10300.S289
-rw-r--r--arch/mn10300/mm/cache.c121
-rw-r--r--arch/mn10300/mm/dma-alloc.c56
-rw-r--r--arch/mn10300/mm/extable.c26
-rw-r--r--arch/mn10300/mm/fault.c405
-rw-r--r--arch/mn10300/mm/init.c160
-rw-r--r--arch/mn10300/mm/misalignment.c661
-rw-r--r--arch/mn10300/mm/mmu-context.c80
-rw-r--r--arch/mn10300/mm/pgtable.c197
-rw-r--r--arch/mn10300/mm/tlb-mn10300.S207
-rw-r--r--arch/mn10300/oprofile/Kconfig23
-rw-r--r--arch/mn10300/oprofile/Makefile13
-rw-r--r--arch/mn10300/oprofile/op_model_null.c22
-rw-r--r--arch/mn10300/proc-mn103e010/Makefile5
-rw-r--r--arch/mn10300/proc-mn103e010/proc-init.c75
-rw-r--r--arch/mn10300/unit-asb2303/Makefile6
-rw-r--r--arch/mn10300/unit-asb2303/leds.c52
-rw-r--r--arch/mn10300/unit-asb2303/smc91111.c52
-rw-r--r--arch/mn10300/unit-asb2303/unit-init.c60
-rw-r--r--arch/mn10300/unit-asb2305/Makefile8
-rw-r--r--arch/mn10300/unit-asb2305/leds.c124
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.c303
-rw-r--r--arch/mn10300/unit-asb2305/pci-asb2305.h82
-rw-r--r--arch/mn10300/unit-asb2305/pci-iomap.c31
-rw-r--r--arch/mn10300/unit-asb2305/pci-irq.c51
-rw-r--r--arch/mn10300/unit-asb2305/pci.c545
-rw-r--r--arch/mn10300/unit-asb2305/unit-init.c61
100 files changed, 18189 insertions, 0 deletions
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
new file mode 100644
index 000000000000..eedc3a5e0d9b
--- /dev/null
+++ b/arch/mn10300/Kconfig
@@ -0,0 +1,381 @@
1#
2# For a description of the syntax of this configuration file,
3# see Documentation/kbuild/kconfig-language.txt.
4#
5
6mainmenu "Linux Kernel Configuration"
7
8config MN10300
9 def_bool y
10
11config AM33
12 def_bool y
13
14config MMU
15 def_bool y
16
17config HIGHMEM
18 def_bool n
19
20config NUMA
21 def_bool n
22
23config UID16
24 def_bool y
25
26config RWSEM_GENERIC_SPINLOCK
27 def_bool y
28
29config RWSEM_XCHGADD_ALGORITHM
30 bool
31
32config GENERIC_HARDIRQS_NO__DO_IRQ
33 def_bool y
34
35config GENERIC_CALIBRATE_DELAY
36 def_bool y
37
38config GENERIC_FIND_NEXT_BIT
39 def_bool y
40
41config GENERIC_HWEIGHT
42 def_bool y
43
44config GENERIC_TIME
45 def_bool y
46
47config GENERIC_BUG
48 def_bool y
49
50config QUICKLIST
51 def_bool y
52
53config ARCH_HAS_ILOG2_U32
54 def_bool y
55
56config ARCH_SUPPORTS_AOUT
57 def_bool n
58
59# Use the generic interrupt handling code in kernel/irq/
60config GENERIC_HARDIRQS
61 def_bool y
62
63config HOTPLUG_CPU
64 def_bool n
65
66mainmenu "Matsushita MN10300/AM33 Kernel Configuration"
67
68source "init/Kconfig"
69
70
71menu "Matsushita MN10300 system setup"
72
73choice
74 prompt "Unit type"
75 default MN10300_UNIT_ASB2303
76 help
77 This option specifies board for which the kernel will be
78 compiled. It affects the external peripherals catered for.
79
80config MN10300_UNIT_ASB2303
81 bool "ASB2303"
82
83config MN10300_UNIT_ASB2305
84 bool "ASB2305"
85
86endchoice
87
88choice
89 prompt "Processor support"
90 default MN10300_PROC_MN103E010
91 help
92 This option specifies the processor for which the kernel will be
93 compiled. It affects the on-chip peripherals catered for.
94
95config MN10300_PROC_MN103E010
96 bool "MN103E010"
97 depends on MN10300_UNIT_ASB2303 || MN10300_UNIT_ASB2305
98 select MN10300_PROC_HAS_TTYSM0
99 select MN10300_PROC_HAS_TTYSM1
100 select MN10300_PROC_HAS_TTYSM2
101
102endchoice
103
104choice
105 prompt "Processor core support"
106 default MN10300_CPU_AM33V2
107 help
108 This option specifies the processor core for which the kernel will be
109 compiled. It affects the instruction set used.
110
111config MN10300_CPU_AM33V2
112 bool "AM33v2"
113
114endchoice
115
116config FPU
117 bool "FPU present"
118 default y
119 depends on MN10300_PROC_MN103E010
120
121choice
122 prompt "CPU Caching mode"
123 default MN10300_CACHE_WBACK
124 help
125 This option determines the caching mode for the kernel.
126
127 Write-Back caching mode involves the all reads and writes causing
128 the affected cacheline to be read into the cache first before being
129 operated upon. Memory is not then updated by a write until the cache
130 is filled and a cacheline needs to be displaced from the cache to
131 make room. Only at that point is it written back.
132
133 Write-Through caching only fetches cachelines from memory on a
134 read. Writes always get written directly to memory. If the affected
135 cacheline is also in cache, it will be updated too.
136
137 The final option is to turn of caching entirely.
138
139config MN10300_CACHE_WBACK
140 bool "Write-Back"
141
142config MN10300_CACHE_WTHRU
143 bool "Write-Through"
144
145config MN10300_CACHE_DISABLED
146 bool "Disabled"
147
148endchoice
149
150menu "Memory layout options"
151
152config KERNEL_RAM_BASE_ADDRESS
153 hex "Base address of kernel RAM"
154 default "0x90000000"
155
156config INTERRUPT_VECTOR_BASE
157 hex "Base address of vector table"
158 default "0x90000000"
159 help
160 The base address of the vector table will be programmed into
161 the TBR register. It must be on 16MiB address boundary.
162
163config KERNEL_TEXT_ADDRESS
164 hex "Base address of kernel"
165 default "0x90001000"
166
167config KERNEL_ZIMAGE_BASE_ADDRESS
168 hex "Base address of compressed vmlinux image"
169 default "0x90700000"
170
171endmenu
172
173config PREEMPT
174 bool "Preemptible Kernel"
175 help
176 This option reduces the latency of the kernel when reacting to
177 real-time or interactive events by allowing a low priority process to
178 be preempted even if it is in kernel mode executing a system call.
179 This allows applications to run more reliably even when the system is
180 under load.
181
182 Say Y here if you are building a kernel for a desktop, embedded
183 or real-time system. Say N if you are unsure.
184
185config PREEMPT_BKL
186 bool "Preempt The Big Kernel Lock"
187 depends on PREEMPT
188 default y
189 help
190 This option reduces the latency of the kernel by making the
191 big kernel lock preemptible.
192
193 Say Y here if you are building a kernel for a desktop system.
194 Say N if you are unsure.
195
196config MN10300_CURRENT_IN_E2
197 bool "Hold current task address in E2 register"
198 default y
199 help
200 This option removes the E2/R2 register from the set available to gcc
201 for normal use and instead uses it to store the address of the
202 current process's task_struct whilst in the kernel.
203
204 This means the kernel doesn't need to calculate the address each time
205 "current" is used (take SP, AND with mask and dereference pointer
206 just to get the address), and instead can just use E2+offset
207 addressing each time.
208
209 This has no effect on userspace.
210
211config MN10300_USING_JTAG
212 bool "Using JTAG to debug kernel"
213 default y
214 help
215 This options indicates that JTAG will be used to debug the kernel. It
216 suppresses the use of certain hardware debugging features, such as
217 single-stepping, which are taken over completely by the JTAG unit.
218
219config MN10300_RTC
220 bool "Using MN10300 RTC"
221 depends on MN10300_PROC_MN103E010
222 default n
223 help
224
225 This option enables support for the RTC, thus enabling time to be
226 tracked, even when system is powered down. This is available on-chip
227 on the MN103E010.
228
229config MN10300_WD_TIMER
230 bool "Using MN10300 watchdog timer"
231 default y
232 help
233 This options indicates that the watchdog timer will be used.
234
235config PCI
236 bool "Use PCI"
237 depends on MN10300_UNIT_ASB2305
238 default y
239 help
240 Some systems (such as the ASB2305) have PCI onboard. If you have one
241 of these boards and you wish to use the PCI facilities, say Y here.
242
243 The PCI-HOWTO, available from
244 <http://www.tldp.org/docs.html#howto>, contains valuable
245 information about which PCI hardware does work under Linux and which
246 doesn't.
247
248source "drivers/pci/Kconfig"
249
250source "drivers/pcmcia/Kconfig"
251
252menu "MN10300 internal serial options"
253
254config MN10300_PROC_HAS_TTYSM0
255 bool
256 default n
257
258config MN10300_PROC_HAS_TTYSM1
259 bool
260 default n
261
262config MN10300_PROC_HAS_TTYSM2
263 bool
264 default n
265
266config MN10300_TTYSM
267 bool "Support for ttySM serial ports"
268 depends on MN10300
269 default y
270 select SERIAL_CORE
271 help
272 This option enables support for the on-chip serial ports that the
273 MN10300 has available.
274
275config MN10300_TTYSM_CONSOLE
276 bool "Support for console on ttySM serial ports"
277 depends on MN10300_TTYSM
278 select SERIAL_CORE_CONSOLE
279 help
280 This option enables support for a console on the on-chip serial ports
281 that the MN10300 has available.
282
283#
284# /dev/ttySM0
285#
286config MN10300_TTYSM0
287 bool "Enable SIF0 (/dev/ttySM0)"
288 depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM0
289 help
290 Enable access to SIF0 through /dev/ttySM0 or gdb-stub
291
292choice
293 prompt "Select the timer to supply the clock for SIF0"
294 default MN10300_TTYSM0_TIMER8
295 depends on MN10300_TTYSM0
296
297config MN10300_TTYSM0_TIMER8
298 bool "Use timer 8 (16-bit)"
299
300config MN10300_TTYSM0_TIMER2
301 bool "Use timer 2 (8-bit)"
302
303endchoice
304
305#
306# /dev/ttySM1
307#
308config MN10300_TTYSM1
309 bool "Enable SIF1 (/dev/ttySM1)"
310 depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM1
311 help
312 Enable access to SIF1 through /dev/ttySM1 or gdb-stub
313
314choice
315 prompt "Select the timer to supply the clock for SIF1"
316 default MN10300_TTYSM0_TIMER9
317 depends on MN10300_TTYSM1
318
319config MN10300_TTYSM1_TIMER9
320 bool "Use timer 9 (16-bit)"
321
322config MN10300_TTYSM1_TIMER3
323 bool "Use timer 3 (8-bit)"
324
325endchoice
326
327#
328# /dev/ttySM2
329#
330config MN10300_TTYSM2
331 bool "Enable SIF2 (/dev/ttySM2)"
332 depends on MN10300_TTYSM && MN10300_PROC_HAS_TTYSM2
333 help
334 Enable access to SIF2 through /dev/ttySM2 or gdb-stub
335
336choice
337 prompt "Select the timer to supply the clock for SIF2"
338 default MN10300_TTYSM0_TIMER10
339 depends on MN10300_TTYSM2
340
341config MN10300_TTYSM2_TIMER10
342 bool "Use timer 10 (16-bit)"
343
344endchoice
345
346config MN10300_TTYSM2_CTS
347 bool "Enable the use of the CTS line /dev/ttySM2"
348 depends on MN10300_TTYSM2
349
350endmenu
351
352source "mm/Kconfig"
353
354menu "Power management options"
355source kernel/power/Kconfig
356endmenu
357
358endmenu
359
360
361menu "Executable formats"
362
363source "fs/Kconfig.binfmt"
364
365endmenu
366
367source "net/Kconfig"
368
369source "drivers/Kconfig"
370
371source "fs/Kconfig"
372
373source "arch/mn10300/Kconfig.debug"
374
375source "security/Kconfig"
376
377source "crypto/Kconfig"
378
379source "lib/Kconfig"
380
381source "arch/mn10300/oprofile/Kconfig"
diff --git a/arch/mn10300/Kconfig.debug b/arch/mn10300/Kconfig.debug
new file mode 100644
index 000000000000..524e33819f32
--- /dev/null
+++ b/arch/mn10300/Kconfig.debug
@@ -0,0 +1,135 @@
1menu "Kernel hacking"
2
3source "lib/Kconfig.debug"
4
5config DEBUG_STACKOVERFLOW
6 bool "Check for stack overflows"
7 depends on DEBUG_KERNEL
8
9config DEBUG_DECOMPRESS_KERNEL
10 bool "Using serial port during decompressing kernel"
11 depends on DEBUG_KERNEL
12 default n
13 help
14 If you say Y here you will confirm the start and the end of
15 decompressing Linux seeing "Uncompressing Linux... " and
16 "Ok, booting the kernel.\n" on console.
17
18config KPROBES
19 bool "Kprobes"
20 depends on DEBUG_KERNEL
21 help
22 Kprobes allows you to trap at almost any kernel address and
23 execute a callback function. register_kprobe() establishes
24 a probepoint and specifies the callback. Kprobes is useful
25 for kernel debugging, non-intrusive instrumentation and testing.
26 If in doubt, say "N".
27
28config GDBSTUB
29 bool "Remote GDB kernel debugging"
30 depends on DEBUG_KERNEL
31 select DEBUG_INFO
32 select FRAME_POINTER
33 help
34 If you say Y here, it will be possible to remotely debug the kernel
35 using gdb. This enlarges your kernel ELF image disk size by several
36 megabytes and requires a machine with more than 16 MB, better 32 MB
37 RAM to avoid excessive linking time. This is only useful for kernel
38 hackers. If unsure, say N.
39
40config GDBSTUB_IMMEDIATE
41 bool "Break into GDB stub immediately"
42 depends on GDBSTUB
43 help
44 If you say Y here, GDB stub will break into the program as soon as
45 possible, leaving the program counter at the beginning of
46 start_kernel() in init/main.c.
47
48config GDB_CONSOLE
49 bool "Console output to GDB"
50 depends on GDBSTUB
51 help
52 If you are using GDB for remote debugging over a serial port and
53 would like kernel messages to be formatted into GDB $O packets so
54 that GDB prints them as program output, say 'Y'.
55
56config GDBSTUB_DEBUGGING
57 bool "Debug GDB stub by messages to serial port"
58 depends on GDBSTUB
59 help
60 This causes debugging messages to be displayed at various points
61 during execution of the GDB stub routines. Such messages will be
62 displayed on ttyS0 if that isn't the GDB stub's port, or ttySM0
63 otherwise.
64
65config GDBSTUB_DEBUG_ENTRY
66 bool "Debug GDB stub entry"
67 depends on GDBSTUB_DEBUGGING
68 help
69 This option causes information to be displayed about entry to or exit
70 from the main GDB stub routine.
71
72config GDBSTUB_DEBUG_PROTOCOL
73 bool "Debug GDB stub protocol"
74 depends on GDBSTUB_DEBUGGING
75 help
76 This option causes information to be displayed about the GDB remote
77 protocol messages generated exchanged with GDB.
78
79config GDBSTUB_DEBUG_IO
80 bool "Debug GDB stub I/O"
81 depends on GDBSTUB_DEBUGGING
82 help
83 This option causes information to be displayed about GDB stub's
84 low-level I/O.
85
86config GDBSTUB_DEBUG_BREAKPOINT
87 bool "Debug GDB stub breakpoint management"
88 depends on GDBSTUB_DEBUGGING
89 help
90 This option causes information to be displayed about GDB stub's
91 breakpoint management.
92
93choice
94 prompt "GDB stub port"
95 default GDBSTUB_TTYSM0
96 depends on GDBSTUB
97 help
98 Select the serial port used for GDB-stub.
99
100config GDBSTUB_ON_TTYSM0
101 bool "/dev/ttySM0 [SIF0]"
102 depends on MN10300_TTYSM0
103 select GDBSTUB_ON_TTYSMx
104
105config GDBSTUB_ON_TTYSM1
106 bool "/dev/ttySM1 [SIF1]"
107 depends on MN10300_TTYSM1
108 select GDBSTUB_ON_TTYSMx
109
110config GDBSTUB_ON_TTYSM2
111 bool "/dev/ttySM2 [SIF2]"
112 depends on MN10300_TTYSM2
113 select GDBSTUB_ON_TTYSMx
114
115config GDBSTUB_ON_TTYS0
116 bool "/dev/ttyS0"
117 select GDBSTUB_ON_TTYSx
118
119config GDBSTUB_ON_TTYS1
120 bool "/dev/ttyS1"
121 select GDBSTUB_ON_TTYSx
122
123endchoice
124
125config GDBSTUB_ON_TTYSMx
126 bool
127 depends on GDBSTUB_ON_TTYSM0 || GDBSTUB_ON_TTYSM1 || GDBSTUB_ON_TTYSM2
128 default y
129
130config GDBSTUB_ON_TTYSx
131 bool
132 depends on GDBSTUB_ON_TTYS0 || GDBSTUB_ON_TTYS1
133 default y
134
135endmenu
diff --git a/arch/mn10300/Makefile b/arch/mn10300/Makefile
new file mode 100644
index 000000000000..6673a28ec07a
--- /dev/null
+++ b/arch/mn10300/Makefile
@@ -0,0 +1,135 @@
1###############################################################################
2#
3# MN10300 Kernel makefile system specifications
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Modified by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14
15KBUILD_DEFCONFIG := asb2303_defconfig
16
17CCSPECS := $(shell $(CC) -v 2>&1 | grep "^Reading specs from " | head -1 | cut -c20-)
18CCDIR := $(strip $(patsubst %/specs,%,$(CCSPECS)))
19KBUILD_CPPFLAGS += -nostdinc -I$(CCDIR)/include
20
21LDFLAGS :=
22OBJCOPYFLAGS := -O binary -R .note -R .comment -S
23#LDFLAGS_vmlinux := -Map linkmap.txt
24CHECKFLAGS +=
25
26PROCESSOR := unset
27UNIT := unset
28
29KBUILD_CFLAGS += -mam33 -mmem-funcs -DCPU=AM33
30KBUILD_AFLAGS += -mam33 -DCPU=AM33
31
32ifeq ($(CONFIG_MN10300_CURRENT_IN_E2),y)
33KBUILD_CFLAGS += -ffixed-e2 -fcall-saved-e5
34endif
35
36ifeq ($(CONFIG_MN10300_PROC_MN103E010),y)
37PROCESSOR := mn103e010
38endif
39
40ifeq ($(CONFIG_MN10300_UNIT_ASB2303),y)
41UNIT := asb2303
42endif
43ifeq ($(CONFIG_MN10300_UNIT_ASB2305),y)
44UNIT := asb2305
45endif
46
47
48head-y := arch/mn10300/kernel/head.o arch/mn10300/kernel/init_task.o
49
50core-y += arch/mn10300/kernel/ arch/mn10300/mm/
51
52ifneq ($(PROCESSOR),unset)
53core-y += arch/mn10300/proc-$(PROCESSOR)/
54endif
55ifneq ($(UNIT),unset)
56core-y += arch/mn10300/unit-$(UNIT)/
57endif
58libs-y += arch/mn10300/lib/
59
60drivers-$(CONFIG_OPROFILE) += arch/mn10300/oprofile/
61
62boot := arch/mn10300/boot
63
64.PHONY: zImage
65
66KBUILD_IMAGE := $(boot)/zImage
67CLEAN_FILES += $(boot)/zImage
68CLEAN_FILES += $(boot)/compressed/vmlinux
69CLEAN_FILES += $(boot)/compressed/vmlinux.bin
70CLEAN_FILES += $(boot)/compressed/vmlinux.bin.gz
71
72zImage: vmlinux
73 $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
74
75all: zImage
76
77bootstrap:
78 $(Q)$(MAKEBOOT) bootstrap
79
80archclean:
81 $(Q)$(MAKE) $(clean)=arch/mn10300/proc-mn103e010
82 $(Q)$(MAKE) $(clean)=arch/mn10300/unit-asb2303
83 $(Q)$(MAKE) $(clean)=arch/mn10300/unit-asb2305
84
85define archhelp
86 echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
87endef
88
89# If you make sure the .S files get compiled with debug info,
90# uncomment the following to disable optimisations
91# that are unhelpful whilst debugging.
92ifdef CONFIG_DEBUG_INFO
93#KBUILD_CFLAGS += -O1
94KBUILD_AFLAGS += -Wa,--gdwarf2
95endif
96
97###################################################################################################
98#
99# juggle some symlinks in the MN10300 asm include dir
100#
101# Update machine proc and unit symlinks if something which affects
102# them changed. We use .proc / .unit to indicate when they were
103# updated last, otherwise make uses the target directory mtime.
104#
105###################################################################################################
106
107# processor specific definitions
108include/asm-mn10300/.proc: $(wildcard include/config/proc/*.h) include/config/auto.conf
109 @echo ' SYMLINK include/asm-mn10300/proc -> include/asm-mn10300/proc-$(PROCESSOR)'
110ifneq ($(KBUILD_SRC),)
111 $(Q)mkdir -p include/asm-mn10300
112 $(Q)ln -fsn $(srctree)/include/asm-mn10300/proc-$(PROCESSOR) include/asm-mn10300/proc
113else
114 $(Q)ln -fsn proc-$(PROCESSOR) include/asm-mn10300/proc
115endif
116 @touch $@
117
118CLEAN_FILES += include/asm-mn10300/proc include/asm-mn10300/.proc
119
120prepare: include/asm-mn10300/.proc
121
122# unit specific definitions
123include/asm-mn10300/.unit: $(wildcard include/config/unit/*.h) include/config/auto.conf
124 @echo ' SYMLINK include/asm-mn10300/unit -> include/asm-mn10300/unit-$(UNIT)'
125ifneq ($(KBUILD_SRC),)
126 $(Q)mkdir -p include/asm-mn10300
127 $(Q)ln -fsn $(srctree)/include/asm-mn10300/unit-$(UNIT) include/asm-mn10300/unit
128else
129 $(Q)ln -fsn unit-$(UNIT) include/asm-mn10300/unit
130endif
131 @touch $@
132
133CLEAN_FILES += include/asm-mn10300/unit include/asm-mn10300/.unit
134
135prepare: include/asm-mn10300/.unit
diff --git a/arch/mn10300/boot/.gitignore b/arch/mn10300/boot/.gitignore
new file mode 100644
index 000000000000..b6718de23693
--- /dev/null
+++ b/arch/mn10300/boot/.gitignore
@@ -0,0 +1 @@
zImage
diff --git a/arch/mn10300/boot/Makefile b/arch/mn10300/boot/Makefile
new file mode 100644
index 000000000000..36c9caf8ea0a
--- /dev/null
+++ b/arch/mn10300/boot/Makefile
@@ -0,0 +1,28 @@
1# MN10300 kernel compressor and wrapper
2#
3# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5# Written by David Howells (dhowells@redhat.com)
6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public Licence
9# as published by the Free Software Foundation; either version
10# 2 of the Licence, or (at your option) any later version.
11#
12
13targets := vmlinux.bin zImage
14
15subdir- := compressed
16
17# ---------------------------------------------------------------------------
18
19
20$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
21 $(call if_changed,objcopy)
22 @echo 'Kernel: $@ is ready'
23
24$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
25 $(call if_changed,objcopy)
26
27$(obj)/compressed/vmlinux: FORCE
28 $(Q)$(MAKE) $(build)=$(obj)/compressed IMAGE_OFFSET=$(IMAGE_OFFSET) $@
diff --git a/arch/mn10300/boot/compressed/Makefile b/arch/mn10300/boot/compressed/Makefile
new file mode 100644
index 000000000000..08a95e171685
--- /dev/null
+++ b/arch/mn10300/boot/compressed/Makefile
@@ -0,0 +1,22 @@
1#
2# Create a compressed vmlinux image from the original vmlinux
3#
4
5targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
6
7LDFLAGS_vmlinux := -Ttext $(CONFIG_KERNEL_ZIMAGE_BASE_ADDRESS) -e startup_32
8
9$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE
10 $(call if_changed,ld)
11 @:
12
13$(obj)/vmlinux.bin: vmlinux FORCE
14 $(call if_changed,objcopy)
15
16$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
17 $(call if_changed,gzip)
18
19LDFLAGS_piggy.o := -r --format binary --oformat elf32-am33lin -T
20
21$(obj)/piggy.o: $(obj)/vmlinux.lds $(obj)/vmlinux.bin.gz FORCE
22 $(call if_changed,ld)
diff --git a/arch/mn10300/boot/compressed/head.S b/arch/mn10300/boot/compressed/head.S
new file mode 100644
index 000000000000..502e1eb56709
--- /dev/null
+++ b/arch/mn10300/boot/compressed/head.S
@@ -0,0 +1,86 @@
1/* Boot entry point for a compressed MN10300 kernel
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11 .section .text
12
13#define DEBUG
14
15#include <linux/linkage.h>
16#include <asm/cpu-regs.h>
17
18 .globl startup_32
19startup_32:
20 # first save off parameters from bootloader
21 mov param_save_area,a0
22 mov d0,(a0)
23 mov d1,(4,a0)
24 mov d2,(8,a0)
25
26 mov sp,a3
27 mov decomp_stack+0x2000-4,a0
28 mov a0,sp
29
30 # invalidate and enable both of the caches
31 mov CHCTR,a0
32 clr d0
33 movhu d0,(a0) # turn off first
34 mov CHCTR_ICINV|CHCTR_DCINV,d0
35 movhu d0,(a0)
36 setlb
37 mov (a0),d0
38 btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy
39 lne
40 mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD,d0 # writethru dcache
41 movhu d0,(a0) # enable
42
43 # clear the BSS area
44 mov __bss_start,a0
45 mov _end,a1
46 clr d0
47bssclear:
48 cmp a1,a0
49 bge bssclear_end
50 movbu d0,(a0)
51 inc a0
52 bra bssclear
53bssclear_end:
54
55 # decompress the kernel
56 call decompress_kernel[],0
57
58 # disable caches again
59 mov CHCTR,a0
60 clr d0
61 movhu d0,(a0)
62 setlb
63 mov (a0),d0
64 btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy
65 lne
66
67 mov param_save_area,a0
68 mov (a0),d0
69 mov (4,a0),d1
70 mov (8,a0),d2
71
72 mov a3,sp
73 mov CONFIG_KERNEL_TEXT_ADDRESS,a0
74 jmp (a0)
75
76 .data
77 .align 4
78param_save_area:
79 .rept 3
80 .word 0
81 .endr
82
83 .section .bss
84 .align 4
85decomp_stack:
86 .space 0x2000
diff --git a/arch/mn10300/boot/compressed/misc.c b/arch/mn10300/boot/compressed/misc.c
new file mode 100644
index 000000000000..ded207efc97a
--- /dev/null
+++ b/arch/mn10300/boot/compressed/misc.c
@@ -0,0 +1,429 @@
1/* MN10300 Miscellaneous helper routines for kernel decompressor
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 * - Derived from arch/x86/boot/compressed/misc_32.c
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public Licence
10 * as published by the Free Software Foundation; either version
11 * 2 of the Licence, or (at your option) any later version.
12 */
13#include <linux/compiler.h>
14#include <asm/serial-regs.h>
15#include "misc.h"
16
17#ifndef CONFIG_GDBSTUB_ON_TTYSx
18/* display 'Uncompressing Linux... ' messages on ttyS0 or ttyS1 */
19#if 1 /* ttyS0 */
20#define CYG_DEV_BASE 0xA6FB0000
21#else /* ttyS1 */
22#define CYG_DEV_BASE 0xA6FC0000
23#endif
24
25#define CYG_DEV_THR (*((volatile __u8*)(CYG_DEV_BASE + 0x00)))
26#define CYG_DEV_MCR (*((volatile __u8*)(CYG_DEV_BASE + 0x10)))
27#define SIO_MCR_DTR 0x01
28#define SIO_MCR_RTS 0x02
29#define CYG_DEV_LSR (*((volatile __u8*)(CYG_DEV_BASE + 0x14)))
30#define SIO_LSR_THRE 0x20 /* transmitter holding register empty */
31#define SIO_LSR_TEMT 0x40 /* transmitter register empty */
32#define CYG_DEV_MSR (*((volatile __u8*)(CYG_DEV_BASE + 0x18)))
33#define SIO_MSR_CTS 0x10 /* clear to send */
34#define SIO_MSR_DSR 0x20 /* data set ready */
35
36#define LSR_WAIT_FOR(STATE) \
37 do { while (!(CYG_DEV_LSR & SIO_LSR_##STATE)) {} } while (0)
38#define FLOWCTL_QUERY(LINE) \
39 ({ CYG_DEV_MSR & SIO_MSR_##LINE; })
40#define FLOWCTL_WAIT_FOR(LINE) \
41 do { while (!(CYG_DEV_MSR & SIO_MSR_##LINE)) {} } while (0)
42#define FLOWCTL_CLEAR(LINE) \
43 do { CYG_DEV_MCR &= ~SIO_MCR_##LINE; } while (0)
44#define FLOWCTL_SET(LINE) \
45 do { CYG_DEV_MCR |= SIO_MCR_##LINE; } while (0)
46#endif
47
48/*
49 * gzip declarations
50 */
51
52#define OF(args) args
53#define STATIC static
54
55#undef memset
56#undef memcpy
57
58static inline void *memset(const void *s, int c, size_t n)
59{
60 int i;
61 char *ss = (char *) s;
62
63 for (i = 0; i < n; i++)
64 ss[i] = c;
65 return (void *)s;
66}
67
68#define memzero(s, n) memset((s), 0, (n))
69
70static inline void *memcpy(void *__dest, const void *__src, size_t __n)
71{
72 int i;
73 const char *s = __src;
74 char *d = __dest;
75
76 for (i = 0; i < __n; i++)
77 d[i] = s[i];
78 return __dest;
79}
80
81typedef unsigned char uch;
82typedef unsigned short ush;
83typedef unsigned long ulg;
84
85#define WSIZE 0x8000 /* Window size must be at least 32k, and a power of
86 * two */
87
88static uch *inbuf; /* input buffer */
89static uch window[WSIZE]; /* sliding window buffer */
90
91static unsigned insize; /* valid bytes in inbuf */
92static unsigned inptr; /* index of next byte to be processed in inbuf */
93static unsigned outcnt; /* bytes in output buffer */
94
95/* gzip flag byte */
96#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
97#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
98#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
99#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
100#define COMMENT 0x10 /* bit 4 set: file comment present */
101#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
102#define RESERVED 0xC0 /* bit 6,7: reserved */
103
104/* Diagnostic functions */
105#ifdef DEBUG
106# define Assert(cond, msg) { if (!(cond)) error(msg); }
107# define Trace(x) fprintf x
108# define Tracev(x) { if (verbose) fprintf x ; }
109# define Tracevv(x) { if (verbose > 1) fprintf x ; }
110# define Tracec(c, x) { if (verbose && (c)) fprintf x ; }
111# define Tracecv(c, x) { if (verbose > 1 && (c)) fprintf x ; }
112#else
113# define Assert(cond, msg)
114# define Trace(x)
115# define Tracev(x)
116# define Tracevv(x)
117# define Tracec(c, x)
118# define Tracecv(c, x)
119#endif
120
121static int fill_inbuf(void);
122static void flush_window(void);
123static void error(const char *) __attribute__((noreturn));
124static void kputs(const char *);
125
126static inline unsigned char get_byte(void)
127{
128 unsigned char ch = inptr < insize ? inbuf[inptr++] : fill_inbuf();
129
130#if 0
131 char hex[3];
132 hex[0] = ((ch & 0x0f) > 9) ?
133 ((ch & 0x0f) + 'A' - 0xa) : ((ch & 0x0f) + '0');
134 hex[1] = ((ch >> 4) > 9) ?
135 ((ch >> 4) + 'A' - 0xa) : ((ch >> 4) + '0');
136 hex[2] = 0;
137 kputs(hex);
138#endif
139 return ch;
140}
141
142/*
143 * This is set up by the setup-routine at boot-time
144 */
145#define EXT_MEM_K (*(unsigned short *)0x90002)
146#ifndef STANDARD_MEMORY_BIOS_CALL
147#define ALT_MEM_K (*(unsigned long *) 0x901e0)
148#endif
149#define SCREEN_INFO (*(struct screen_info *)0x90000)
150
151static long bytes_out;
152static uch *output_data;
153static unsigned long output_ptr;
154
155
156static void *malloc(int size);
157
158static inline void free(void *where)
159{ /* Don't care */
160}
161
162static unsigned long free_mem_ptr = (unsigned long) &end;
163static unsigned long free_mem_end_ptr = (unsigned long) &end + 0x90000;
164
165static inline void gzip_mark(void **ptr)
166{
167 kputs(".");
168 *ptr = (void *) free_mem_ptr;
169}
170
171static inline void gzip_release(void **ptr)
172{
173 free_mem_ptr = (unsigned long) *ptr;
174}
175
176#define INPLACE_MOVE_ROUTINE 0x1000
177#define LOW_BUFFER_START 0x2000
178#define LOW_BUFFER_END 0x90000
179#define LOW_BUFFER_SIZE (LOW_BUFFER_END - LOW_BUFFER_START)
180#define HEAP_SIZE 0x3000
181static int high_loaded;
182static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/;
183
184static char *vidmem = (char *)0xb8000;
185static int lines, cols;
186
187#include "../../../../lib/inflate.c"
188
189static void *malloc(int size)
190{
191 void *p;
192
193 if (size < 0)
194 error("Malloc error\n");
195 if (!free_mem_ptr)
196 error("Memory error\n");
197
198 free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
199
200 p = (void *) free_mem_ptr;
201 free_mem_ptr += size;
202
203 if (free_mem_ptr >= free_mem_end_ptr)
204 error("\nOut of memory\n");
205
206 return p;
207}
208
209static inline void scroll(void)
210{
211 int i;
212
213 memcpy(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
214 for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
215 vidmem[i] = ' ';
216}
217
218static inline void kputchar(unsigned char ch)
219{
220#ifdef CONFIG_MN10300_UNIT_ASB2305
221 while (SC0STR & SC01STR_TBF)
222 continue;
223
224 if (ch == 0x0a) {
225 SC0TXB = 0x0d;
226 while (SC0STR & SC01STR_TBF)
227 continue;
228 }
229
230 SC0TXB = ch;
231
232#else
233 while (SC1STR & SC01STR_TBF)
234 continue;
235
236 if (ch == 0x0a) {
237 SC1TXB = 0x0d;
238 while (SC1STR & SC01STR_TBF)
239 continue;
240 }
241
242 SC1TXB = ch;
243
244#endif
245}
246
247static void kputs(const char *s)
248{
249#ifdef CONFIG_DEBUG_DECOMPRESS_KERNEL
250#ifndef CONFIG_GDBSTUB_ON_TTYSx
251 char ch;
252
253 FLOWCTL_SET(DTR);
254
255 while (*s) {
256 LSR_WAIT_FOR(THRE);
257
258 ch = *s++;
259 if (ch == 0x0a) {
260 CYG_DEV_THR = 0x0d;
261 LSR_WAIT_FOR(THRE);
262 }
263 CYG_DEV_THR = ch;
264 }
265
266 FLOWCTL_CLEAR(DTR);
267#else
268
269 for (; *s; s++)
270 kputchar(*s);
271
272#endif
273#endif /* CONFIG_DEBUG_DECOMPRESS_KERNEL */
274}
275
276/* ===========================================================================
277 * Fill the input buffer. This is called only when the buffer is empty
278 * and at least one byte is really needed.
279 */
280static int fill_inbuf()
281{
282 if (insize != 0)
283 error("ran out of input data\n");
284
285 inbuf = input_data;
286 insize = input_len;
287 inptr = 1;
288 return inbuf[0];
289}
290
291/* ===========================================================================
292 * Write the output window window[0..outcnt-1] and update crc and bytes_out.
293 * (Used for the decompressed data only.)
294 */
295static void flush_window_low(void)
296{
297 ulg c = crc; /* temporary variable */
298 unsigned n;
299 uch *in, *out, ch;
300
301 in = window;
302 out = &output_data[output_ptr];
303 for (n = 0; n < outcnt; n++) {
304 ch = *out++ = *in++;
305 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
306 }
307 crc = c;
308 bytes_out += (ulg)outcnt;
309 output_ptr += (ulg)outcnt;
310 outcnt = 0;
311}
312
313static void flush_window_high(void)
314{
315 ulg c = crc; /* temporary variable */
316 unsigned n;
317 uch *in, ch;
318 in = window;
319 for (n = 0; n < outcnt; n++) {
320 ch = *output_data++ = *in++;
321 if ((ulg) output_data == LOW_BUFFER_END)
322 output_data = high_buffer_start;
323 c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
324 }
325 crc = c;
326 bytes_out += (ulg)outcnt;
327 outcnt = 0;
328}
329
330static void flush_window(void)
331{
332 if (high_loaded)
333 flush_window_high();
334 else
335 flush_window_low();
336}
337
338static void error(const char *x)
339{
340 kputs("\n\n");
341 kputs(x);
342 kputs("\n\n -- System halted");
343
344 while (1)
345 /* Halt */;
346}
347
348#define STACK_SIZE (4096)
349
350long user_stack[STACK_SIZE];
351
352struct {
353 long *a;
354 short b;
355} stack_start = { &user_stack[STACK_SIZE], 0 };
356
357void setup_normal_output_buffer(void)
358{
359#ifdef STANDARD_MEMORY_BIOS_CALL
360 if (EXT_MEM_K < 1024)
361 error("Less than 2MB of memory.\n");
362#else
363 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024)
364 error("Less than 2MB of memory.\n");
365#endif
366 output_data = (char *) 0x100000; /* Points to 1M */
367}
368
369struct moveparams {
370 uch *low_buffer_start;
371 int lcount;
372 uch *high_buffer_start;
373 int hcount;
374};
375
376void setup_output_buffer_if_we_run_high(struct moveparams *mv)
377{
378 high_buffer_start = (uch *)(((ulg) &end) + HEAP_SIZE);
379#ifdef STANDARD_MEMORY_BIOS_CALL
380 if (EXT_MEM_K < (3 * 1024))
381 error("Less than 4MB of memory.\n");
382#else
383 if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3 * 1024))
384 error("Less than 4MB of memory.\n");
385#endif
386 mv->low_buffer_start = output_data = (char *) LOW_BUFFER_START;
387 high_loaded = 1;
388 free_mem_end_ptr = (long) high_buffer_start;
389 if (0x100000 + LOW_BUFFER_SIZE > (ulg) high_buffer_start) {
390 high_buffer_start = (uch *)(0x100000 + LOW_BUFFER_SIZE);
391 mv->hcount = 0; /* say: we need not to move high_buffer */
392 } else {
393 mv->hcount = -1;
394 }
395 mv->high_buffer_start = high_buffer_start;
396}
397
398void close_output_buffer_if_we_run_high(struct moveparams *mv)
399{
400 mv->lcount = bytes_out;
401 if (bytes_out > LOW_BUFFER_SIZE) {
402 mv->lcount = LOW_BUFFER_SIZE;
403 if (mv->hcount)
404 mv->hcount = bytes_out - LOW_BUFFER_SIZE;
405 } else {
406 mv->hcount = 0;
407 }
408}
409
410#undef DEBUGFLAG
411#ifdef DEBUGFLAG
412int debugflag;
413#endif
414
415int decompress_kernel(struct moveparams *mv)
416{
417#ifdef DEBUGFLAG
418 while (!debugflag)
419 barrier();
420#endif
421
422 output_data = (char *) CONFIG_KERNEL_TEXT_ADDRESS;
423
424 makecrc();
425 kputs("Uncompressing Linux... ");
426 gunzip();
427 kputs("Ok, booting the kernel.\n");
428 return 0;
429}
diff --git a/arch/mn10300/boot/compressed/misc.h b/arch/mn10300/boot/compressed/misc.h
new file mode 100644
index 000000000000..da921cd172fb
--- /dev/null
+++ b/arch/mn10300/boot/compressed/misc.h
@@ -0,0 +1,18 @@
1/* Internal definitions for the MN10300 kernel decompressor
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12extern int end;
13
14/*
15 * vmlinux.lds
16 */
17extern char input_data[];
18extern int input_len;
diff --git a/arch/mn10300/boot/compressed/vmlinux.lds b/arch/mn10300/boot/compressed/vmlinux.lds
new file mode 100644
index 000000000000..a084903603fe
--- /dev/null
+++ b/arch/mn10300/boot/compressed/vmlinux.lds
@@ -0,0 +1,9 @@
1SECTIONS
2{
3 .data : {
4 input_len = .;
5 LONG(input_data_end - input_data) input_data = .;
6 *(.data)
7 input_data_end = .;
8 }
9}
diff --git a/arch/mn10300/boot/install.sh b/arch/mn10300/boot/install.sh
new file mode 100644
index 000000000000..072951c83976
--- /dev/null
+++ b/arch/mn10300/boot/install.sh
@@ -0,0 +1,67 @@
1#!/bin/sh
2#
3# arch/mn10300/boot/install -c.sh
4#
5# This file is subject to the terms and conditions of the GNU General Public
6# Licence. See the file "COPYING" in the main directory of this archive
7# for more details.
8#
9# Copyright (C) 1995 by Linus Torvalds
10#
11# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
12#
13# "make install -c" script for i386 architecture
14#
15# Arguments:
16# $1 - kernel version
17# $2 - kernel image file
18# $3 - kernel map file
19# $4 - default install -c path (blank if root directory)
20# $5 - boot rom file
21#
22
23# User may have a custom install -c script
24
25rm -fr $4/../usr/include/linux $4/../usr/include/asm
26install -c -m 0755 $2 $4/vmlinuz
27install -c -m 0755 $5 $4/boot.rom
28install -c -m 0755 -d $4/../usr/include/linux
29cd $TOPDIR/include/linux
30for i in `find . -maxdepth 1 -name '*.h' -print`; do
31 install -c -m 0644 $i $4/../usr/include/linux
32done
33install -c -m 0755 -d $4/../usr/include/linux/byteorder
34cd $TOPDIR/include/linux/byteorder
35for i in `find . -name '*.h' -print`; do
36 install -c -m 0644 $i $4/../usr/include/linux/byteorder
37done
38install -c -m 0755 -d $4/../usr/include/linux/lockd
39cd $TOPDIR/include/linux/lockd
40for i in `find . -name '*.h' -print`; do
41 install -c -m 0644 $i $4/../usr/include/linux/lockd
42done
43install -c -m 0755 -d $4/../usr/include/linux/netfilter_ipv4
44cd $TOPDIR/include/linux/netfilter_ipv4
45for i in `find . -name '*.h' -print`; do
46 install -c -m 0644 $i $4/../usr/include/linux/netfilter_ipv4
47done
48install -c -m 0755 -d $4/../usr/include/linux/nfsd
49cd $TOPDIR/include/linux/nfsd
50for i in `find . -name '*.h' -print`; do
51 install -c -m 0644 $i $4/../usr/include/linux/nfsd/$i
52done
53install -c -m 0755 -d $4/../usr/include/linux/raid
54cd $TOPDIR/include/linux/raid
55for i in `find . -name '*.h' -print`; do
56 install -c -m 0644 $i $4/../usr/include/linux/raid
57done
58install -c -m 0755 -d $4/../usr/include/linux/sunrpc
59cd $TOPDIR/include/linux/sunrpc
60for i in `find . -name '*.h' -print`; do
61 install -c -m 0644 $i $4/../usr/include/linux/sunrpc
62done
63install -c -m 0755 -d $4/../usr/include/asm
64cd $TOPDIR/include/asm
65for i in `find . -name '*.h' -print`; do
66 install -c -m 0644 $i $4/../usr/include/asm
67done
diff --git a/arch/mn10300/boot/tools/build.c b/arch/mn10300/boot/tools/build.c
new file mode 100644
index 000000000000..4f552ead0f8e
--- /dev/null
+++ b/arch/mn10300/boot/tools/build.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright (C) 1997 Martin Mares
4 */
5
6/*
7 * This file builds a disk-image from three different files:
8 *
9 * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
10 * - setup: 8086 machine code, sets up system parm
11 * - system: 80386 code for actual system
12 *
13 * It does some checking that all files are of the correct type, and
14 * just writes the result to stdout, removing headers and padding to
15 * the right amount. It also writes some system data to stderr.
16 */
17
18/*
19 * Changes by tytso to allow root device specification
20 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
21 * Cross compiling fixes by Gertjan van Wingerde, July 1996
22 * Rewritten by Martin Mares, April 1997
23 */
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <stdarg.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31#include <sys/sysmacros.h>
32#include <unistd.h>
33#include <fcntl.h>
34#include <asm/boot.h>
35
36#define DEFAULT_MAJOR_ROOT 0
37#define DEFAULT_MINOR_ROOT 0
38
39/* Minimal number of setup sectors (see also bootsect.S) */
40#define SETUP_SECTS 4
41
42uint8_t buf[1024];
43int fd;
44int is_big_kernel;
45
46__attribute__((noreturn))
47void die(const char *str, ...)
48{
49 va_list args;
50 va_start(args, str);
51 vfprintf(stderr, str, args);
52 fputc('\n', stderr);
53 exit(1);
54}
55
56void file_open(const char *name)
57{
58 fd = open(name, O_RDONLY, 0);
59 if (fd < 0)
60 die("Unable to open `%s': %m", name);
61}
62
63__attribute__((noreturn))
64void usage(void)
65{
66 die("Usage: build [-b] bootsect setup system [rootdev] [> image]");
67}
68
69int main(int argc, char **argv)
70{
71 unsigned int i, c, sz, setup_sectors;
72 uint32_t sys_size;
73 uint8_t major_root, minor_root;
74 struct stat sb;
75
76 if (argc > 2 && !strcmp(argv[1], "-b")) {
77 is_big_kernel = 1;
78 argc--, argv++;
79 }
80 if ((argc < 4) || (argc > 5))
81 usage();
82 if (argc > 4) {
83 if (!strcmp(argv[4], "CURRENT")) {
84 if (stat("/", &sb)) {
85 perror("/");
86 die("Couldn't stat /");
87 }
88 major_root = major(sb.st_dev);
89 minor_root = minor(sb.st_dev);
90 } else if (strcmp(argv[4], "FLOPPY")) {
91 if (stat(argv[4], &sb)) {
92 perror(argv[4]);
93 die("Couldn't stat root device.");
94 }
95 major_root = major(sb.st_rdev);
96 minor_root = minor(sb.st_rdev);
97 } else {
98 major_root = 0;
99 minor_root = 0;
100 }
101 } else {
102 major_root = DEFAULT_MAJOR_ROOT;
103 minor_root = DEFAULT_MINOR_ROOT;
104 }
105 fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root);
106
107 file_open(argv[1]);
108 i = read(fd, buf, sizeof(buf));
109 fprintf(stderr, "Boot sector %d bytes.\n", i);
110 if (i != 512)
111 die("Boot block must be exactly 512 bytes");
112 if (buf[510] != 0x55 || buf[511] != 0xaa)
113 die("Boot block hasn't got boot flag (0xAA55)");
114 buf[508] = minor_root;
115 buf[509] = major_root;
116 if (write(1, buf, 512) != 512)
117 die("Write call failed");
118 close(fd);
119
120 /* Copy the setup code */
121 file_open(argv[2]);
122 for (i = 0; (c = read(fd, buf, sizeof(buf))) > 0; i += c)
123 if (write(1, buf, c) != c)
124 die("Write call failed");
125 if (c != 0)
126 die("read-error on `setup'");
127 close(fd);
128
129 /* Pad unused space with zeros */
130 setup_sectors = (i + 511) / 512;
131 /* for compatibility with ancient versions of LILO. */
132 if (setup_sectors < SETUP_SECTS)
133 setup_sectors = SETUP_SECTS;
134 fprintf(stderr, "Setup is %d bytes.\n", i);
135 memset(buf, 0, sizeof(buf));
136 while (i < setup_sectors * 512) {
137 c = setup_sectors * 512 - i;
138 if (c > sizeof(buf))
139 c = sizeof(buf);
140 if (write(1, buf, c) != c)
141 die("Write call failed");
142 i += c;
143 }
144
145 file_open(argv[3]);
146 if (fstat(fd, &sb))
147 die("Unable to stat `%s': %m", argv[3]);
148 sz = sb.st_size;
149 fprintf(stderr, "System is %d kB\n", sz / 1024);
150 sys_size = (sz + 15) / 16;
151 /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */
152 if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE))
153 die("System is too big. Try using %smodules.",
154 is_big_kernel ? "" : "bzImage or ");
155 if (sys_size > 0xffff)
156 fprintf(stderr,
157 "warning: kernel is too big for standalone boot "
158 "from floppy\n");
159 while (sz > 0) {
160 int l, n;
161
162 l = (sz > sizeof(buf)) ? sizeof(buf) : sz;
163 n = read(fd, buf, l);
164 if (n != l) {
165 if (n < 0)
166 die("Error reading %s: %m", argv[3]);
167 else
168 die("%s: Unexpected EOF", argv[3]);
169 }
170 if (write(1, buf, l) != l)
171 die("Write failed");
172 sz -= l;
173 }
174 close(fd);
175
176 /* Write sizes to the bootsector */
177 if (lseek(1, 497, SEEK_SET) != 497)
178 die("Output: seek failed");
179 buf[0] = setup_sectors;
180 if (write(1, buf, 1) != 1)
181 die("Write of setup sector count failed");
182 if (lseek(1, 500, SEEK_SET) != 500)
183 die("Output: seek failed");
184 buf[0] = (sys_size & 0xff);
185 buf[1] = ((sys_size >> 8) & 0xff);
186 if (write(1, buf, 2) != 2)
187 die("Write of image length failed");
188
189 return 0;
190}
diff --git a/arch/mn10300/configs/asb2303_defconfig b/arch/mn10300/configs/asb2303_defconfig
new file mode 100644
index 000000000000..0189a058da9f
--- /dev/null
+++ b/arch/mn10300/configs/asb2303_defconfig
@@ -0,0 +1,555 @@
1#
2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.24-rc2
4# Fri Nov 16 13:36:38 2007
5#
6CONFIG_MN10300=y
7CONFIG_AM33=y
8CONFIG_MMU=y
9# CONFIG_HIGHMEM is not set
10# CONFIG_NUMA is not set
11CONFIG_UID16=y
12CONFIG_RWSEM_GENERIC_SPINLOCK=y
13CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
14CONFIG_GENERIC_CALIBRATE_DELAY=y
15CONFIG_GENERIC_FIND_NEXT_BIT=y
16CONFIG_GENERIC_HWEIGHT=y
17CONFIG_GENERIC_TIME=y
18CONFIG_GENERIC_BUG=y
19CONFIG_QUICKLIST=y
20CONFIG_ARCH_HAS_ILOG2_U32=y
21# CONFIG_ARCH_SUPPORTS_AOUT is not set
22CONFIG_GENERIC_HARDIRQS=y
23# CONFIG_HOTPLUG_CPU is not set
24CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
25
26#
27# General setup
28#
29CONFIG_EXPERIMENTAL=y
30CONFIG_BROKEN_ON_SMP=y
31CONFIG_LOCK_KERNEL=y
32CONFIG_INIT_ENV_ARG_LIMIT=32
33CONFIG_LOCALVERSION=""
34CONFIG_LOCALVERSION_AUTO=y
35CONFIG_SYSVIPC=y
36CONFIG_SYSVIPC_SYSCTL=y
37# CONFIG_POSIX_MQUEUE is not set
38CONFIG_BSD_PROCESS_ACCT=y
39# CONFIG_BSD_PROCESS_ACCT_V3 is not set
40# CONFIG_TASKSTATS is not set
41# CONFIG_USER_NS is not set
42# CONFIG_PID_NS is not set
43# CONFIG_AUDIT is not set
44# CONFIG_IKCONFIG is not set
45CONFIG_LOG_BUF_SHIFT=14
46# CONFIG_CGROUPS is not set
47# CONFIG_FAIR_GROUP_SCHED is not set
48# CONFIG_SYSFS_DEPRECATED is not set
49# CONFIG_RELAY is not set
50# CONFIG_BLK_DEV_INITRD is not set
51# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
52CONFIG_SYSCTL=y
53CONFIG_EMBEDDED=y
54CONFIG_SYSCTL_SYSCALL=y
55# CONFIG_KALLSYMS is not set
56# CONFIG_HOTPLUG is not set
57CONFIG_PRINTK=y
58CONFIG_BUG=y
59CONFIG_ELF_CORE=y
60CONFIG_BASE_FULL=y
61CONFIG_FUTEX=y
62CONFIG_ANON_INODES=y
63CONFIG_EPOLL=y
64CONFIG_SIGNALFD=y
65CONFIG_EVENTFD=y
66CONFIG_SHMEM=y
67# CONFIG_VM_EVENT_COUNTERS is not set
68CONFIG_SLAB=y
69# CONFIG_SLUB is not set
70# CONFIG_SLOB is not set
71CONFIG_RT_MUTEXES=y
72# CONFIG_TINY_SHMEM is not set
73CONFIG_BASE_SMALL=0
74# CONFIG_MODULES is not set
75# CONFIG_BLOCK is not set
76
77#
78# Matsushita MN10300 system setup
79#
80CONFIG_MN10300_UNIT_ASB2303=y
81# CONFIG_MN10300_UNIT_ASB2305 is not set
82CONFIG_MN10300_PROC_MN103E010=y
83CONFIG_MN10300_CPU_AM33V2=y
84CONFIG_FPU=y
85CONFIG_MN10300_CACHE_WBACK=y
86# CONFIG_MN10300_CACHE_WTHRU is not set
87# CONFIG_MN10300_CACHE_DISABLED is not set
88
89#
90# Memory layout options
91#
92CONFIG_KERNEL_RAM_BASE_ADDRESS=0x90000000
93CONFIG_INTERRUPT_VECTOR_BASE=0x90000000
94CONFIG_KERNEL_TEXT_ADDRESS=0x90001000
95CONFIG_KERNEL_ZIMAGE_BASE_ADDRESS=0x90700000
96CONFIG_PREEMPT=y
97CONFIG_PREEMPT_BKL=y
98CONFIG_MN10300_CURRENT_IN_E2=y
99CONFIG_MN10300_USING_JTAG=y
100CONFIG_MN10300_RTC=y
101CONFIG_MN10300_WD_TIMER=y
102# CONFIG_ARCH_SUPPORTS_MSI is not set
103
104#
105# MN10300 internal serial options
106#
107CONFIG_MN10300_PROC_HAS_TTYSM0=y
108CONFIG_MN10300_PROC_HAS_TTYSM1=y
109CONFIG_MN10300_PROC_HAS_TTYSM2=y
110CONFIG_MN10300_TTYSM=y
111CONFIG_MN10300_TTYSM_CONSOLE=y
112CONFIG_MN10300_TTYSM0=y
113CONFIG_MN10300_TTYSM0_TIMER8=y
114# CONFIG_MN10300_TTYSM0_TIMER2 is not set
115CONFIG_MN10300_TTYSM1=y
116CONFIG_MN10300_TTYSM1_TIMER9=y
117# CONFIG_MN10300_TTYSM1_TIMER3 is not set
118# CONFIG_MN10300_TTYSM2 is not set
119CONFIG_SELECT_MEMORY_MODEL=y
120CONFIG_FLATMEM_MANUAL=y
121# CONFIG_DISCONTIGMEM_MANUAL is not set
122# CONFIG_SPARSEMEM_MANUAL is not set
123CONFIG_FLATMEM=y
124CONFIG_FLAT_NODE_MEM_MAP=y
125# CONFIG_SPARSEMEM_STATIC is not set
126# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
127CONFIG_SPLIT_PTLOCK_CPUS=4
128# CONFIG_RESOURCES_64BIT is not set
129CONFIG_ZONE_DMA_FLAG=0
130CONFIG_NR_QUICK=1
131CONFIG_VIRT_TO_BUS=y
132
133#
134# Power management options
135#
136# CONFIG_PM is not set
137
138#
139# Executable formats
140#
141CONFIG_BINFMT_ELF=y
142# CONFIG_BINFMT_MISC is not set
143
144#
145# Networking
146#
147CONFIG_NET=y
148
149#
150# Networking options
151#
152CONFIG_PACKET=y
153CONFIG_PACKET_MMAP=y
154CONFIG_UNIX=y
155# CONFIG_NET_KEY is not set
156CONFIG_INET=y
157CONFIG_IP_MULTICAST=y
158# CONFIG_IP_ADVANCED_ROUTER is not set
159CONFIG_IP_FIB_HASH=y
160CONFIG_IP_PNP=y
161# CONFIG_IP_PNP_DHCP is not set
162CONFIG_IP_PNP_BOOTP=y
163# CONFIG_IP_PNP_RARP is not set
164# CONFIG_NET_IPIP is not set
165# CONFIG_NET_IPGRE is not set
166# CONFIG_IP_MROUTE is not set
167# CONFIG_ARPD is not set
168# CONFIG_SYN_COOKIES is not set
169# CONFIG_INET_AH is not set
170# CONFIG_INET_ESP is not set
171# CONFIG_INET_IPCOMP is not set
172# CONFIG_INET_XFRM_TUNNEL is not set
173# CONFIG_INET_TUNNEL is not set
174# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
175# CONFIG_INET_XFRM_MODE_TUNNEL is not set
176# CONFIG_INET_XFRM_MODE_BEET is not set
177# CONFIG_INET_LRO is not set
178# CONFIG_INET_DIAG is not set
179# CONFIG_TCP_CONG_ADVANCED is not set
180CONFIG_TCP_CONG_CUBIC=y
181CONFIG_DEFAULT_TCP_CONG="cubic"
182# CONFIG_TCP_MD5SIG is not set
183# CONFIG_IPV6 is not set
184# CONFIG_INET6_XFRM_TUNNEL is not set
185# CONFIG_INET6_TUNNEL is not set
186# CONFIG_NETWORK_SECMARK is not set
187# CONFIG_NETFILTER is not set
188# CONFIG_IP_DCCP is not set
189# CONFIG_IP_SCTP is not set
190# CONFIG_TIPC is not set
191# CONFIG_ATM is not set
192# CONFIG_BRIDGE is not set
193# CONFIG_VLAN_8021Q is not set
194# CONFIG_DECNET is not set
195# CONFIG_LLC2 is not set
196# CONFIG_IPX is not set
197# CONFIG_ATALK is not set
198# CONFIG_X25 is not set
199# CONFIG_LAPB is not set
200# CONFIG_ECONET is not set
201# CONFIG_WAN_ROUTER is not set
202# CONFIG_NET_SCHED is not set
203
204#
205# Network testing
206#
207# CONFIG_NET_PKTGEN is not set
208# CONFIG_HAMRADIO is not set
209# CONFIG_IRDA is not set
210# CONFIG_BT is not set
211# CONFIG_AF_RXRPC is not set
212
213#
214# Wireless
215#
216# CONFIG_CFG80211 is not set
217# CONFIG_WIRELESS_EXT is not set
218# CONFIG_MAC80211 is not set
219# CONFIG_IEEE80211 is not set
220# CONFIG_RFKILL is not set
221# CONFIG_NET_9P is not set
222
223#
224# Device Drivers
225#
226
227#
228# Generic Driver Options
229#
230CONFIG_STANDALONE=y
231CONFIG_PREVENT_FIRMWARE_BUILD=y
232# CONFIG_SYS_HYPERVISOR is not set
233# CONFIG_CONNECTOR is not set
234CONFIG_MTD=y
235CONFIG_MTD_DEBUG=y
236CONFIG_MTD_DEBUG_VERBOSE=0
237# CONFIG_MTD_CONCAT is not set
238CONFIG_MTD_PARTITIONS=y
239CONFIG_MTD_REDBOOT_PARTS=y
240CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
241CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
242# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
243# CONFIG_MTD_CMDLINE_PARTS is not set
244
245#
246# User Modules And Translation Layers
247#
248CONFIG_MTD_CHAR=y
249# CONFIG_MTD_OOPS is not set
250
251#
252# RAM/ROM/Flash chip drivers
253#
254CONFIG_MTD_CFI=y
255CONFIG_MTD_JEDECPROBE=y
256CONFIG_MTD_GEN_PROBE=y
257CONFIG_MTD_CFI_ADV_OPTIONS=y
258CONFIG_MTD_CFI_NOSWAP=y
259# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
260# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
261CONFIG_MTD_CFI_GEOMETRY=y
262CONFIG_MTD_MAP_BANK_WIDTH_1=y
263CONFIG_MTD_MAP_BANK_WIDTH_2=y
264CONFIG_MTD_MAP_BANK_WIDTH_4=y
265# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
266# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
267# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
268CONFIG_MTD_CFI_I1=y
269CONFIG_MTD_CFI_I2=y
270CONFIG_MTD_CFI_I4=y
271# CONFIG_MTD_CFI_I8 is not set
272# CONFIG_MTD_OTP is not set
273# CONFIG_MTD_CFI_INTELEXT is not set
274CONFIG_MTD_CFI_AMDSTD=y
275# CONFIG_MTD_CFI_STAA is not set
276CONFIG_MTD_CFI_UTIL=y
277# CONFIG_MTD_RAM is not set
278# CONFIG_MTD_ROM is not set
279# CONFIG_MTD_ABSENT is not set
280
281#
282# Mapping drivers for chip access
283#
284# CONFIG_MTD_COMPLEX_MAPPINGS is not set
285# CONFIG_MTD_PHYSMAP is not set
286# CONFIG_MTD_PLATRAM is not set
287
288#
289# Self-contained MTD device drivers
290#
291# CONFIG_MTD_SLRAM is not set
292# CONFIG_MTD_PHRAM is not set
293# CONFIG_MTD_MTDRAM is not set
294
295#
296# Disk-On-Chip Device Drivers
297#
298# CONFIG_MTD_DOC2000 is not set
299# CONFIG_MTD_DOC2001 is not set
300# CONFIG_MTD_DOC2001PLUS is not set
301# CONFIG_MTD_NAND is not set
302# CONFIG_MTD_ONENAND is not set
303
304#
305# UBI - Unsorted block images
306#
307# CONFIG_MTD_UBI is not set
308# CONFIG_PARPORT is not set
309CONFIG_MISC_DEVICES=y
310# CONFIG_EEPROM_93CX6 is not set
311
312#
313# SCSI device support
314#
315# CONFIG_SCSI_DMA is not set
316# CONFIG_SCSI_NETLINK is not set
317CONFIG_NETDEVICES=y
318# CONFIG_NETDEVICES_MULTIQUEUE is not set
319# CONFIG_DUMMY is not set
320# CONFIG_BONDING is not set
321# CONFIG_MACVLAN is not set
322# CONFIG_EQUALIZER is not set
323# CONFIG_TUN is not set
324# CONFIG_VETH is not set
325# CONFIG_PHYLIB is not set
326CONFIG_NET_ETHERNET=y
327CONFIG_MII=y
328CONFIG_SMC91X=y
329# CONFIG_IBM_NEW_EMAC_ZMII is not set
330# CONFIG_IBM_NEW_EMAC_RGMII is not set
331# CONFIG_IBM_NEW_EMAC_TAH is not set
332# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
333# CONFIG_B44 is not set
334# CONFIG_NETDEV_1000 is not set
335# CONFIG_NETDEV_10000 is not set
336
337#
338# Wireless LAN
339#
340# CONFIG_WLAN_PRE80211 is not set
341# CONFIG_WLAN_80211 is not set
342# CONFIG_WAN is not set
343# CONFIG_PPP is not set
344# CONFIG_SLIP is not set
345# CONFIG_SHAPER is not set
346# CONFIG_NETCONSOLE is not set
347# CONFIG_NETPOLL is not set
348# CONFIG_NET_POLL_CONTROLLER is not set
349# CONFIG_ISDN is not set
350# CONFIG_PHONE is not set
351
352#
353# Input device support
354#
355# CONFIG_INPUT is not set
356
357#
358# Hardware I/O ports
359#
360# CONFIG_SERIO is not set
361# CONFIG_GAMEPORT is not set
362
363#
364# Character devices
365#
366# CONFIG_VT is not set
367# CONFIG_SERIAL_NONSTANDARD is not set
368
369#
370# Serial drivers
371#
372CONFIG_SERIAL_8250=y
373CONFIG_SERIAL_8250_CONSOLE=y
374CONFIG_SERIAL_8250_NR_UARTS=4
375CONFIG_SERIAL_8250_RUNTIME_UARTS=4
376CONFIG_SERIAL_8250_EXTENDED=y
377# CONFIG_SERIAL_8250_MANY_PORTS is not set
378CONFIG_SERIAL_8250_SHARE_IRQ=y
379# CONFIG_SERIAL_8250_DETECT_IRQ is not set
380# CONFIG_SERIAL_8250_RSA is not set
381
382#
383# Non-8250 serial port support
384#
385CONFIG_SERIAL_CORE=y
386CONFIG_SERIAL_CORE_CONSOLE=y
387CONFIG_UNIX98_PTYS=y
388CONFIG_LEGACY_PTYS=y
389CONFIG_LEGACY_PTY_COUNT=256
390# CONFIG_IPMI_HANDLER is not set
391# CONFIG_HW_RANDOM is not set
392CONFIG_RTC=y
393# CONFIG_R3964 is not set
394# CONFIG_TCG_TPM is not set
395# CONFIG_I2C is not set
396
397#
398# SPI support
399#
400# CONFIG_SPI is not set
401# CONFIG_SPI_MASTER is not set
402# CONFIG_W1 is not set
403# CONFIG_POWER_SUPPLY is not set
404# CONFIG_HWMON is not set
405# CONFIG_WATCHDOG is not set
406
407#
408# Sonics Silicon Backplane
409#
410CONFIG_SSB_POSSIBLE=y
411# CONFIG_SSB is not set
412
413#
414# Multifunction device drivers
415#
416# CONFIG_MFD_SM501 is not set
417
418#
419# Multimedia devices
420#
421# CONFIG_VIDEO_DEV is not set
422# CONFIG_DVB_CORE is not set
423# CONFIG_DAB is not set
424
425#
426# Graphics support
427#
428# CONFIG_VGASTATE is not set
429# CONFIG_VIDEO_OUTPUT_CONTROL is not set
430# CONFIG_FB is not set
431# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
432
433#
434# Display device support
435#
436# CONFIG_DISPLAY_SUPPORT is not set
437
438#
439# Sound
440#
441# CONFIG_SOUND is not set
442# CONFIG_USB_SUPPORT is not set
443# CONFIG_MMC is not set
444# CONFIG_NEW_LEDS is not set
445# CONFIG_RTC_CLASS is not set
446
447#
448# Userspace I/O
449#
450# CONFIG_UIO is not set
451
452#
453# File systems
454#
455CONFIG_INOTIFY=y
456CONFIG_INOTIFY_USER=y
457# CONFIG_QUOTA is not set
458CONFIG_DNOTIFY=y
459# CONFIG_AUTOFS_FS is not set
460# CONFIG_AUTOFS4_FS is not set
461# CONFIG_FUSE_FS is not set
462
463#
464# Pseudo filesystems
465#
466CONFIG_PROC_FS=y
467CONFIG_PROC_KCORE=y
468CONFIG_PROC_SYSCTL=y
469CONFIG_SYSFS=y
470CONFIG_TMPFS=y
471# CONFIG_TMPFS_POSIX_ACL is not set
472# CONFIG_HUGETLB_PAGE is not set
473# CONFIG_CONFIGFS_FS is not set
474
475#
476# Miscellaneous filesystems
477#
478CONFIG_JFFS2_FS=y
479CONFIG_JFFS2_FS_DEBUG=0
480CONFIG_JFFS2_FS_WRITEBUFFER=y
481# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
482# CONFIG_JFFS2_SUMMARY is not set
483# CONFIG_JFFS2_FS_XATTR is not set
484# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
485CONFIG_JFFS2_ZLIB=y
486# CONFIG_JFFS2_LZO is not set
487CONFIG_JFFS2_RTIME=y
488# CONFIG_JFFS2_RUBIN is not set
489CONFIG_NETWORK_FILESYSTEMS=y
490CONFIG_NFS_FS=y
491CONFIG_NFS_V3=y
492# CONFIG_NFS_V3_ACL is not set
493# CONFIG_NFS_V4 is not set
494# CONFIG_NFS_DIRECTIO is not set
495# CONFIG_NFSD is not set
496CONFIG_ROOT_NFS=y
497CONFIG_LOCKD=y
498CONFIG_LOCKD_V4=y
499CONFIG_NFS_COMMON=y
500CONFIG_SUNRPC=y
501# CONFIG_SUNRPC_BIND34 is not set
502# CONFIG_RPCSEC_GSS_KRB5 is not set
503# CONFIG_RPCSEC_GSS_SPKM3 is not set
504# CONFIG_SMB_FS is not set
505# CONFIG_CIFS is not set
506# CONFIG_NCP_FS is not set
507# CONFIG_CODA_FS is not set
508# CONFIG_AFS_FS is not set
509# CONFIG_NLS is not set
510# CONFIG_DLM is not set
511
512#
513# Kernel hacking
514#
515# CONFIG_PRINTK_TIME is not set
516CONFIG_ENABLE_WARN_DEPRECATED=y
517CONFIG_ENABLE_MUST_CHECK=y
518CONFIG_MAGIC_SYSRQ=y
519# CONFIG_UNUSED_SYMBOLS is not set
520# CONFIG_DEBUG_FS is not set
521# CONFIG_HEADERS_CHECK is not set
522# CONFIG_DEBUG_KERNEL is not set
523# CONFIG_DEBUG_BUGVERBOSE is not set
524# CONFIG_SAMPLES is not set
525
526#
527# Security options
528#
529# CONFIG_KEYS is not set
530# CONFIG_SECURITY is not set
531# CONFIG_SECURITY_FILE_CAPABILITIES is not set
532# CONFIG_CRYPTO is not set
533
534#
535# Library routines
536#
537CONFIG_BITREVERSE=y
538# CONFIG_CRC_CCITT is not set
539# CONFIG_CRC16 is not set
540# CONFIG_CRC_ITU_T is not set
541CONFIG_CRC32=y
542# CONFIG_CRC7 is not set
543# CONFIG_LIBCRC32C is not set
544CONFIG_ZLIB_INFLATE=y
545CONFIG_ZLIB_DEFLATE=y
546CONFIG_PLIST=y
547CONFIG_HAS_IOMEM=y
548CONFIG_HAS_IOPORT=y
549CONFIG_HAS_DMA=y
550
551#
552# Profiling support
553#
554CONFIG_PROFILING=y
555CONFIG_OPROFILE=y
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile
new file mode 100644
index 000000000000..ef07c956170a
--- /dev/null
+++ b/arch/mn10300/kernel/Makefile
@@ -0,0 +1,27 @@
1#
2# Makefile for the MN10300-specific core kernel code
3#
4extra-y := head.o init_task.o vmlinux.lds
5
6obj-y := process.o semaphore.o signal.o entry.o fpu.o traps.o irq.o \
7 ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \
8 switch_to.o mn10300_ksyms.o kernel_execve.o
9
10obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o
11
12obj-$(CONFIG_FPU) += fpu-low.o
13
14obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \
15 mn10300-debug.o
16obj-$(CONFIG_GDBSTUB) += gdb-stub.o gdb-low.o
17obj-$(CONFIG_GDBSTUB_ON_TTYSx) += gdb-io-serial.o gdb-io-serial-low.o
18obj-$(CONFIG_GDBSTUB_ON_TTYSMx) += gdb-io-ttysm.o gdb-io-ttysm-low.o
19
20ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
21obj-$(CONFIG_GDBSTUB) += gdb-cache.o
22endif
23
24obj-$(CONFIG_MN10300_RTC) += rtc.o
25obj-$(CONFIG_PROFILE) += profile.o profile-low.o
26obj-$(CONFIG_MODULES) += module.o
27obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c
new file mode 100644
index 000000000000..ee2d9f8af5ad
--- /dev/null
+++ b/arch/mn10300/kernel/asm-offsets.c
@@ -0,0 +1,108 @@
1/*
2 * Generate definitions needed by assembly language modules.
3 * This code generates raw asm output which is post-processed
4 * to extract and format the required data.
5 */
6
7#include <linux/sched.h>
8#include <linux/signal.h>
9#include <linux/personality.h>
10#include <asm/ucontext.h>
11#include <asm/processor.h>
12#include <asm/thread_info.h>
13#include <asm/ptrace.h>
14#include "sigframe.h"
15#include "mn10300-serial.h"
16
17#define DEFINE(sym, val) \
18 asm volatile("\n->" #sym " %0 " #val : : "i" (val))
19
20#define BLANK() asm volatile("\n->")
21
22#define OFFSET(sym, str, mem) \
23 DEFINE(sym, offsetof(struct str, mem));
24
25void foo(void)
26{
27 OFFSET(SIGCONTEXT_d0, sigcontext, d0);
28 OFFSET(SIGCONTEXT_d1, sigcontext, d1);
29 BLANK();
30
31 OFFSET(TI_task, thread_info, task);
32 OFFSET(TI_exec_domain, thread_info, exec_domain);
33 OFFSET(TI_flags, thread_info, flags);
34 OFFSET(TI_cpu, thread_info, cpu);
35 OFFSET(TI_preempt_count, thread_info, preempt_count);
36 OFFSET(TI_addr_limit, thread_info, addr_limit);
37 OFFSET(TI_restart_block, thread_info, restart_block);
38 BLANK();
39
40 OFFSET(REG_D0, pt_regs, d0);
41 OFFSET(REG_D1, pt_regs, d1);
42 OFFSET(REG_D2, pt_regs, d2);
43 OFFSET(REG_D3, pt_regs, d3);
44 OFFSET(REG_A0, pt_regs, a0);
45 OFFSET(REG_A1, pt_regs, a1);
46 OFFSET(REG_A2, pt_regs, a2);
47 OFFSET(REG_A3, pt_regs, a3);
48 OFFSET(REG_E0, pt_regs, e0);
49 OFFSET(REG_E1, pt_regs, e1);
50 OFFSET(REG_E2, pt_regs, e2);
51 OFFSET(REG_E3, pt_regs, e3);
52 OFFSET(REG_E4, pt_regs, e4);
53 OFFSET(REG_E5, pt_regs, e5);
54 OFFSET(REG_E6, pt_regs, e6);
55 OFFSET(REG_E7, pt_regs, e7);
56 OFFSET(REG_SP, pt_regs, sp);
57 OFFSET(REG_EPSW, pt_regs, epsw);
58 OFFSET(REG_PC, pt_regs, pc);
59 OFFSET(REG_LAR, pt_regs, lar);
60 OFFSET(REG_LIR, pt_regs, lir);
61 OFFSET(REG_MDR, pt_regs, mdr);
62 OFFSET(REG_MCVF, pt_regs, mcvf);
63 OFFSET(REG_MCRL, pt_regs, mcrl);
64 OFFSET(REG_MCRH, pt_regs, mcrh);
65 OFFSET(REG_MDRQ, pt_regs, mdrq);
66 OFFSET(REG_ORIG_D0, pt_regs, orig_d0);
67 OFFSET(REG_NEXT, pt_regs, next);
68 DEFINE(REG__END, sizeof(struct pt_regs));
69 BLANK();
70
71 OFFSET(THREAD_UREGS, thread_struct, uregs);
72 OFFSET(THREAD_PC, thread_struct, pc);
73 OFFSET(THREAD_SP, thread_struct, sp);
74 OFFSET(THREAD_A3, thread_struct, a3);
75 OFFSET(THREAD_USP, thread_struct, usp);
76 OFFSET(THREAD_FRAME, thread_struct, __frame);
77 BLANK();
78
79 DEFINE(CLONE_VM_asm, CLONE_VM);
80 DEFINE(CLONE_FS_asm, CLONE_FS);
81 DEFINE(CLONE_FILES_asm, CLONE_FILES);
82 DEFINE(CLONE_SIGHAND_asm, CLONE_SIGHAND);
83 DEFINE(CLONE_UNTRACED_asm, CLONE_UNTRACED);
84 DEFINE(SIGCHLD_asm, SIGCHLD);
85 BLANK();
86
87 OFFSET(EXEC_DOMAIN_handler, exec_domain, handler);
88 OFFSET(RT_SIGFRAME_sigcontext, rt_sigframe, uc.uc_mcontext);
89
90 DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
91
92 OFFSET(__rx_buffer, mn10300_serial_port, rx_buffer);
93 OFFSET(__rx_inp, mn10300_serial_port, rx_inp);
94 OFFSET(__rx_outp, mn10300_serial_port, rx_outp);
95 OFFSET(__tx_info_buffer, mn10300_serial_port, uart.info);
96 OFFSET(__tx_xchar, mn10300_serial_port, tx_xchar);
97 OFFSET(__tx_break, mn10300_serial_port, tx_break);
98 OFFSET(__intr_flags, mn10300_serial_port, intr_flags);
99 OFFSET(__rx_icr, mn10300_serial_port, rx_icr);
100 OFFSET(__tx_icr, mn10300_serial_port, tx_icr);
101 OFFSET(__tm_icr, mn10300_serial_port, _tmicr);
102 OFFSET(__iobase, mn10300_serial_port, _iobase);
103
104 DEFINE(__UART_XMIT_SIZE, UART_XMIT_SIZE);
105 OFFSET(__xmit_buffer, uart_info, xmit.buf);
106 OFFSET(__xmit_head, uart_info, xmit.head);
107 OFFSET(__xmit_tail, uart_info, xmit.tail);
108}
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
new file mode 100644
index 000000000000..11de3606eee6
--- /dev/null
+++ b/arch/mn10300/kernel/entry.S
@@ -0,0 +1,721 @@
1###############################################################################
2#
3# MN10300 Exception and interrupt entry points
4#
5# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
6# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
7# Modified by David Howells (dhowells@redhat.com)
8#
9# This program is free software; you can redistribute it and/or
10# modify it under the terms of the GNU General Public Licence
11# as published by the Free Software Foundation; either version
12# 2 of the Licence, or (at your option) any later version.
13#
14###############################################################################
15#include <linux/sys.h>
16#include <linux/linkage.h>
17#include <asm/smp.h>
18#include <asm/system.h>
19#include <asm/thread_info.h>
20#include <asm/intctl-regs.h>
21#include <asm/busctl-regs.h>
22#include <asm/timer-regs.h>
23#include <asm/unit/leds.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/errno.h>
27#include <asm/asm-offsets.h>
28#include <asm/frame.inc>
29
30#ifdef CONFIG_PREEMPT
31#define preempt_stop __cli
32#else
33#define preempt_stop
34#define resume_kernel restore_all
35#endif
36
37 .macro __cli
38 and ~EPSW_IM,epsw
39 or EPSW_IE|MN10300_CLI_LEVEL,epsw
40 nop
41 nop
42 nop
43 .endm
44 .macro __sti
45 or EPSW_IE|EPSW_IM_7,epsw
46 .endm
47
48
49 .am33_2
50
51###############################################################################
52#
53# the return path for a forked child
54# - on entry, D0 holds the address of the previous task to run
55#
56###############################################################################
57ENTRY(ret_from_fork)
58 call schedule_tail[],0
59 GET_THREAD_INFO a2
60
61 # return 0 to indicate child process
62 clr d0
63 mov d0,(REG_D0,fp)
64 jmp syscall_exit
65
66###############################################################################
67#
68# system call handler
69#
70###############################################################################
71ENTRY(system_call)
72 add -4,sp
73 SAVE_ALL
74 mov d0,(REG_ORIG_D0,fp)
75 GET_THREAD_INFO a2
76 cmp nr_syscalls,d0
77 bcc syscall_badsys
78 btst _TIF_SYSCALL_TRACE,(TI_flags,a2)
79 bne syscall_trace_entry
80syscall_call:
81 add d0,d0,a1
82 add a1,a1
83 mov (REG_A0,fp),d0
84 mov (sys_call_table,a1),a0
85 calls (a0)
86 mov d0,(REG_D0,fp)
87syscall_exit:
88 # make sure we don't miss an interrupt setting need_resched or
89 # sigpending between sampling and the rti
90 __cli
91 mov (TI_flags,a2),d2
92 btst _TIF_ALLWORK_MASK,d2
93 bne syscall_exit_work
94restore_all:
95 RESTORE_ALL
96
97###############################################################################
98#
99# perform work that needs to be done immediately before resumption and syscall
100# tracing
101#
102###############################################################################
103 ALIGN
104syscall_exit_work:
105 btst _TIF_SYSCALL_TRACE,d2
106 beq work_pending
107 __sti # could let do_syscall_trace() call
108 # schedule() instead
109 mov fp,d0
110 mov 1,d1
111 call do_syscall_trace[],0 # do_syscall_trace(regs,entryexit)
112 jmp resume_userspace
113
114 ALIGN
115work_pending:
116 btst _TIF_NEED_RESCHED,d2
117 beq work_notifysig
118
119work_resched:
120 call schedule[],0
121
122 # make sure we don't miss an interrupt setting need_resched or
123 # sigpending between sampling and the rti
124 __cli
125
126 # is there any work to be done other than syscall tracing?
127 mov (TI_flags,a2),d2
128 btst _TIF_WORK_MASK,d2
129 beq restore_all
130 btst _TIF_NEED_RESCHED,d2
131 bne work_resched
132
133 # deal with pending signals and notify-resume requests
134work_notifysig:
135 mov fp,d0
136 mov d2,d1
137 call do_notify_resume[],0
138 jmp resume_userspace
139
140 # perform syscall entry tracing
141syscall_trace_entry:
142 mov -ENOSYS,d0
143 mov d0,(REG_D0,fp)
144 mov fp,d0
145 clr d1
146 call do_syscall_trace[],0
147 mov (REG_ORIG_D0,fp),d0
148 mov (REG_D1,fp),d1
149 cmp nr_syscalls,d0
150 bcs syscall_call
151 jmp syscall_exit
152
153syscall_badsys:
154 mov -ENOSYS,d0
155 mov d0,(REG_D0,fp)
156 jmp resume_userspace
157
158 # userspace resumption stub bypassing syscall exit tracing
159 .globl ret_from_exception, ret_from_intr
160 ALIGN
161ret_from_exception:
162 preempt_stop
163ret_from_intr:
164 GET_THREAD_INFO a2
165 mov (REG_EPSW,fp),d0 # need to deliver signals before
166 # returning to userspace
167 and EPSW_nSL,d0
168 beq resume_kernel # returning to supervisor mode
169
170ENTRY(resume_userspace)
171 # make sure we don't miss an interrupt setting need_resched or
172 # sigpending between sampling and the rti
173 __cli
174
175 # is there any work to be done on int/exception return?
176 mov (TI_flags,a2),d2
177 btst _TIF_WORK_MASK,d2
178 bne work_pending
179 jmp restore_all
180
181#ifdef CONFIG_PREEMPT
182ENTRY(resume_kernel)
183 mov (TI_preempt_count,a2),d0 # non-zero preempt_count ?
184 cmp 0,d0
185 bne restore_all
186
187need_resched:
188 btst _TIF_NEED_RESCHED,(TI_flags,a2)
189 beq restore_all
190 mov (REG_EPSW,fp),d0
191 and EPSW_IM,d0
192 cmp EPSW_IM_7,d0 # interrupts off (exception path) ?
193 beq restore_all
194 call preempt_schedule_irq[],0
195 jmp need_resched
196#endif
197
198
199###############################################################################
200#
201# IRQ handler entry point
202# - intended to be entered at multiple priorities
203#
204###############################################################################
205ENTRY(irq_handler)
206 add -4,sp
207 SAVE_ALL
208
209 # it's not a syscall
210 mov 0xffffffff,d0
211 mov d0,(REG_ORIG_D0,fp)
212
213 mov fp,d0
214 call do_IRQ[],0 # do_IRQ(regs)
215
216 jmp ret_from_intr
217
218###############################################################################
219#
220# Monitor Signal handler entry point
221#
222###############################################################################
223ENTRY(monitor_signal)
224 movbu (0xae000001),d1
225 cmp 1,d1
226 beq monsignal
227 ret [],0
228
229monsignal:
230 or EPSW_NMID,epsw
231 mov d0,a0
232 mov a0,sp
233 mov (REG_EPSW,fp),d1
234 and ~EPSW_nSL,d1
235 mov d1,(REG_EPSW,fp)
236 movm (sp),[d2,d3,a2,a3,exreg0,exreg1,exother]
237 mov (sp),a1
238 mov a1,usp
239 movm (sp),[other]
240 add 4,sp
241here: jmp 0x8e000008-here+0x8e000008
242
243###############################################################################
244#
245# Double Fault handler entry point
246# - note that there will not be a stack, D0/A0 will hold EPSW/PC as were
247#
248###############################################################################
249 .section .bss
250 .balign THREAD_SIZE
251 .space THREAD_SIZE
252__df_stack:
253 .previous
254
255ENTRY(double_fault)
256 mov a0,(__df_stack-4) # PC as was
257 mov d0,(__df_stack-8) # EPSW as was
258 mn10300_set_dbfleds # display 'db-f' on the LEDs
259 mov 0xaa55aa55,d0
260 mov d0,(__df_stack-12) # no ORIG_D0
261 mov sp,a0 # save corrupted SP
262 mov __df_stack-12,sp # emergency supervisor stack
263 SAVE_ALL
264 mov a0,(REG_A0,fp) # save corrupted SP as A0 (which got
265 # clobbered by the CPU)
266 mov fp,d0
267 calls do_double_fault
268double_fault_loop:
269 bra double_fault_loop
270
271###############################################################################
272#
273# Bus Error handler entry point
274# - handle external (async) bus errors separately
275#
276###############################################################################
277ENTRY(raw_bus_error)
278 add -4,sp
279 mov d0,(sp)
280 mov (BCBERR),d0 # what
281 btst BCBERR_BEMR_DMA,d0 # see if it was an external bus error
282 beq __common_exception_aux # it wasn't
283
284 SAVE_ALL
285 mov (BCBEAR),d1 # destination of erroneous access
286
287 mov (REG_ORIG_D0,fp),d2
288 mov d2,(REG_D0,fp)
289 mov -1,d2
290 mov d2,(REG_ORIG_D0,fp)
291
292 add -4,sp
293 mov fp,(12,sp) # frame pointer
294 call io_bus_error[],0
295 jmp restore_all
296
297###############################################################################
298#
299# Miscellaneous exception entry points
300#
301###############################################################################
302ENTRY(nmi_handler)
303 add -4,sp
304 mov d0,(sp)
305 mov (TBR),d0
306 bra __common_exception_nonmi
307
308ENTRY(__common_exception)
309 add -4,sp
310 mov d0,(sp)
311
312__common_exception_aux:
313 mov (TBR),d0
314 and ~EPSW_NMID,epsw # turn NMIs back on if not NMI
315 or EPSW_IE,epsw
316
317__common_exception_nonmi:
318 and 0x0000FFFF,d0 # turn the exception code into a vector
319 # table index
320
321 btst 0x00000007,d0
322 bne 1f
323 cmp 0x00000400,d0
324 bge 1f
325
326 SAVE_ALL # build the stack frame
327
328 mov (REG_D0,fp),a2 # get the exception number
329 mov (REG_ORIG_D0,fp),d0
330 mov d0,(REG_D0,fp)
331 mov -1,d0
332 mov d0,(REG_ORIG_D0,fp)
333
334#ifdef CONFIG_GDBSTUB
335 btst 0x01,(gdbstub_busy)
336 beq 2f
337 and ~EPSW_IE,epsw
338 mov fp,d0
339 mov a2,d1
340 call gdbstub_exception[],0 # gdbstub itself caused an exception
341 bra restore_all
3422:
343#endif
344
345 mov fp,d0 # arg 0: stacked register file
346 mov a2,d1 # arg 1: exception number
347 lsr 1,a2
348
349 mov (exception_table,a2),a2
350 calls (a2)
351 jmp ret_from_exception
352
3531: pi # BUG() equivalent
354
355###############################################################################
356#
357# Exception handler functions table
358#
359###############################################################################
360 .data
361ENTRY(exception_table)
362 .rept 0x400>>1
363 .long uninitialised_exception
364 .endr
365 .previous
366
367###############################################################################
368#
369# Change an entry in the exception table
370# - D0 exception code, D1 handler
371#
372###############################################################################
373ENTRY(set_excp_vector)
374 lsr 1,d0
375 add exception_table,d0
376 mov d1,(d0)
377 mov 4,d1
378#if defined(CONFIG_MN10300_CACHE_WBACK)
379 jmp mn10300_dcache_flush_inv_range2
380#else
381 ret [],0
382#endif
383
384###############################################################################
385#
386# System call table
387#
388###############################################################################
389 .data
390ENTRY(sys_call_table)
391 .long sys_restart_syscall /* 0 */
392 .long sys_exit
393 .long sys_fork
394 .long sys_read
395 .long sys_write
396 .long sys_open /* 5 */
397 .long sys_close
398 .long sys_waitpid
399 .long sys_creat
400 .long sys_link
401 .long sys_unlink /* 10 */
402 .long sys_execve
403 .long sys_chdir
404 .long sys_time
405 .long sys_mknod
406 .long sys_chmod /* 15 */
407 .long sys_lchown16
408 .long sys_ni_syscall /* old break syscall holder */
409 .long sys_stat
410 .long sys_lseek
411 .long sys_getpid /* 20 */
412 .long sys_mount
413 .long sys_oldumount
414 .long sys_setuid16
415 .long sys_getuid16
416 .long sys_stime /* 25 */
417 .long sys_ptrace
418 .long sys_alarm
419 .long sys_fstat
420 .long sys_pause
421 .long sys_utime /* 30 */
422 .long sys_ni_syscall /* old stty syscall holder */
423 .long sys_ni_syscall /* old gtty syscall holder */
424 .long sys_access
425 .long sys_nice
426 .long sys_ni_syscall /* 35 - old ftime syscall holder */
427 .long sys_sync
428 .long sys_kill
429 .long sys_rename
430 .long sys_mkdir
431 .long sys_rmdir /* 40 */
432 .long sys_dup
433 .long sys_pipe
434 .long sys_times
435 .long sys_ni_syscall /* old prof syscall holder */
436 .long sys_brk /* 45 */
437 .long sys_setgid16
438 .long sys_getgid16
439 .long sys_signal
440 .long sys_geteuid16
441 .long sys_getegid16 /* 50 */
442 .long sys_acct
443 .long sys_umount /* recycled never used phys() */
444 .long sys_ni_syscall /* old lock syscall holder */
445 .long sys_ioctl
446 .long sys_fcntl /* 55 */
447 .long sys_ni_syscall /* old mpx syscall holder */
448 .long sys_setpgid
449 .long sys_ni_syscall /* old ulimit syscall holder */
450 .long sys_ni_syscall /* old sys_olduname */
451 .long sys_umask /* 60 */
452 .long sys_chroot
453 .long sys_ustat
454 .long sys_dup2
455 .long sys_getppid
456 .long sys_getpgrp /* 65 */
457 .long sys_setsid
458 .long sys_sigaction
459 .long sys_sgetmask
460 .long sys_ssetmask
461 .long sys_setreuid16 /* 70 */
462 .long sys_setregid16
463 .long sys_sigsuspend
464 .long sys_sigpending
465 .long sys_sethostname
466 .long sys_setrlimit /* 75 */
467 .long sys_old_getrlimit
468 .long sys_getrusage
469 .long sys_gettimeofday
470 .long sys_settimeofday
471 .long sys_getgroups16 /* 80 */
472 .long sys_setgroups16
473 .long old_select
474 .long sys_symlink
475 .long sys_lstat
476 .long sys_readlink /* 85 */
477 .long sys_uselib
478 .long sys_swapon
479 .long sys_reboot
480 .long old_readdir
481 .long old_mmap /* 90 */
482 .long sys_munmap
483 .long sys_truncate
484 .long sys_ftruncate
485 .long sys_fchmod
486 .long sys_fchown16 /* 95 */
487 .long sys_getpriority
488 .long sys_setpriority
489 .long sys_ni_syscall /* old profil syscall holder */
490 .long sys_statfs
491 .long sys_fstatfs /* 100 */
492 .long sys_ni_syscall /* ioperm */
493 .long sys_socketcall
494 .long sys_syslog
495 .long sys_setitimer
496 .long sys_getitimer /* 105 */
497 .long sys_newstat
498 .long sys_newlstat
499 .long sys_newfstat
500 .long sys_ni_syscall /* old sys_uname */
501 .long sys_ni_syscall /* 110 - iopl */
502 .long sys_vhangup
503 .long sys_ni_syscall /* old "idle" system call */
504 .long sys_ni_syscall /* vm86old */
505 .long sys_wait4
506 .long sys_swapoff /* 115 */
507 .long sys_sysinfo
508 .long sys_ipc
509 .long sys_fsync
510 .long sys_sigreturn
511 .long sys_clone /* 120 */
512 .long sys_setdomainname
513 .long sys_newuname
514 .long sys_ni_syscall /* modify_ldt */
515 .long sys_adjtimex
516 .long sys_mprotect /* 125 */
517 .long sys_sigprocmask
518 .long sys_ni_syscall /* old "create_module" */
519 .long sys_init_module
520 .long sys_delete_module
521 .long sys_ni_syscall /* 130: old "get_kernel_syms" */
522 .long sys_quotactl
523 .long sys_getpgid
524 .long sys_fchdir
525 .long sys_bdflush
526 .long sys_sysfs /* 135 */
527 .long sys_personality
528 .long sys_ni_syscall /* reserved for afs_syscall */
529 .long sys_setfsuid16
530 .long sys_setfsgid16
531 .long sys_llseek /* 140 */
532 .long sys_getdents
533 .long sys_select
534 .long sys_flock
535 .long sys_msync
536 .long sys_readv /* 145 */
537 .long sys_writev
538 .long sys_getsid
539 .long sys_fdatasync
540 .long sys_sysctl
541 .long sys_mlock /* 150 */
542 .long sys_munlock
543 .long sys_mlockall
544 .long sys_munlockall
545 .long sys_sched_setparam
546 .long sys_sched_getparam /* 155 */
547 .long sys_sched_setscheduler
548 .long sys_sched_getscheduler
549 .long sys_sched_yield
550 .long sys_sched_get_priority_max
551 .long sys_sched_get_priority_min /* 160 */
552 .long sys_sched_rr_get_interval
553 .long sys_nanosleep
554 .long sys_mremap
555 .long sys_setresuid16
556 .long sys_getresuid16 /* 165 */
557 .long sys_ni_syscall /* vm86 */
558 .long sys_ni_syscall /* Old sys_query_module */
559 .long sys_poll
560 .long sys_nfsservctl
561 .long sys_setresgid16 /* 170 */
562 .long sys_getresgid16
563 .long sys_prctl
564 .long sys_rt_sigreturn
565 .long sys_rt_sigaction
566 .long sys_rt_sigprocmask /* 175 */
567 .long sys_rt_sigpending
568 .long sys_rt_sigtimedwait
569 .long sys_rt_sigqueueinfo
570 .long sys_rt_sigsuspend
571 .long sys_pread64 /* 180 */
572 .long sys_pwrite64
573 .long sys_chown16
574 .long sys_getcwd
575 .long sys_capget
576 .long sys_capset /* 185 */
577 .long sys_sigaltstack
578 .long sys_sendfile
579 .long sys_ni_syscall /* reserved for streams1 */
580 .long sys_ni_syscall /* reserved for streams2 */
581 .long sys_vfork /* 190 */
582 .long sys_getrlimit
583 .long sys_mmap2
584 .long sys_truncate64
585 .long sys_ftruncate64
586 .long sys_stat64 /* 195 */
587 .long sys_lstat64
588 .long sys_fstat64
589 .long sys_lchown
590 .long sys_getuid
591 .long sys_getgid /* 200 */
592 .long sys_geteuid
593 .long sys_getegid
594 .long sys_setreuid
595 .long sys_setregid
596 .long sys_getgroups /* 205 */
597 .long sys_setgroups
598 .long sys_fchown
599 .long sys_setresuid
600 .long sys_getresuid
601 .long sys_setresgid /* 210 */
602 .long sys_getresgid
603 .long sys_chown
604 .long sys_setuid
605 .long sys_setgid
606 .long sys_setfsuid /* 215 */
607 .long sys_setfsgid
608 .long sys_pivot_root
609 .long sys_mincore
610 .long sys_madvise
611 .long sys_getdents64 /* 220 */
612 .long sys_fcntl64
613 .long sys_ni_syscall /* reserved for TUX */
614 .long sys_ni_syscall
615 .long sys_gettid
616 .long sys_readahead /* 225 */
617 .long sys_setxattr
618 .long sys_lsetxattr
619 .long sys_fsetxattr
620 .long sys_getxattr
621 .long sys_lgetxattr /* 230 */
622 .long sys_fgetxattr
623 .long sys_listxattr
624 .long sys_llistxattr
625 .long sys_flistxattr
626 .long sys_removexattr /* 235 */
627 .long sys_lremovexattr
628 .long sys_fremovexattr
629 .long sys_tkill
630 .long sys_sendfile64
631 .long sys_futex /* 240 */
632 .long sys_sched_setaffinity
633 .long sys_sched_getaffinity
634 .long sys_ni_syscall /* sys_set_thread_area */
635 .long sys_ni_syscall /* sys_get_thread_area */
636 .long sys_io_setup /* 245 */
637 .long sys_io_destroy
638 .long sys_io_getevents
639 .long sys_io_submit
640 .long sys_io_cancel
641 .long sys_fadvise64 /* 250 */
642 .long sys_ni_syscall
643 .long sys_exit_group
644 .long sys_lookup_dcookie
645 .long sys_epoll_create
646 .long sys_epoll_ctl /* 255 */
647 .long sys_epoll_wait
648 .long sys_remap_file_pages
649 .long sys_set_tid_address
650 .long sys_timer_create
651 .long sys_timer_settime /* 260 */
652 .long sys_timer_gettime
653 .long sys_timer_getoverrun
654 .long sys_timer_delete
655 .long sys_clock_settime
656 .long sys_clock_gettime /* 265 */
657 .long sys_clock_getres
658 .long sys_clock_nanosleep
659 .long sys_statfs64
660 .long sys_fstatfs64
661 .long sys_tgkill /* 270 */
662 .long sys_utimes
663 .long sys_fadvise64_64
664 .long sys_ni_syscall /* sys_vserver */
665 .long sys_mbind
666 .long sys_get_mempolicy /* 275 */
667 .long sys_set_mempolicy
668 .long sys_mq_open
669 .long sys_mq_unlink
670 .long sys_mq_timedsend
671 .long sys_mq_timedreceive /* 280 */
672 .long sys_mq_notify
673 .long sys_mq_getsetattr
674 .long sys_kexec_load
675 .long sys_waitid
676 .long sys_ni_syscall /* 285 */ /* available */
677 .long sys_add_key
678 .long sys_request_key
679 .long sys_keyctl
680 .long sys_cacheflush
681 .long sys_ioprio_set /* 290 */
682 .long sys_ioprio_get
683 .long sys_inotify_init
684 .long sys_inotify_add_watch
685 .long sys_inotify_rm_watch
686 .long sys_migrate_pages /* 295 */
687 .long sys_openat
688 .long sys_mkdirat
689 .long sys_mknodat
690 .long sys_fchownat
691 .long sys_futimesat /* 300 */
692 .long sys_fstatat64
693 .long sys_unlinkat
694 .long sys_renameat
695 .long sys_linkat
696 .long sys_symlinkat /* 305 */
697 .long sys_readlinkat
698 .long sys_fchmodat
699 .long sys_faccessat
700 .long sys_pselect6
701 .long sys_ppoll /* 310 */
702 .long sys_unshare
703 .long sys_set_robust_list
704 .long sys_get_robust_list
705 .long sys_splice
706 .long sys_sync_file_range /* 315 */
707 .long sys_tee
708 .long sys_vmsplice
709 .long sys_move_pages
710 .long sys_getcpu
711 .long sys_epoll_pwait /* 320 */
712 .long sys_utimensat
713 .long sys_signalfd
714 .long sys_timerfd_create
715 .long sys_eventfd
716 .long sys_fallocate /* 325 */
717 .long sys_timerfd_settime
718 .long sys_timerfd_gettime
719
720
721nr_syscalls=(.-sys_call_table)/4
diff --git a/arch/mn10300/kernel/fpu-low.S b/arch/mn10300/kernel/fpu-low.S
new file mode 100644
index 000000000000..96cfd47e68d5
--- /dev/null
+++ b/arch/mn10300/kernel/fpu-low.S
@@ -0,0 +1,197 @@
1/* MN10300 Low level FPU management operations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cpu-regs.h>
12
13###############################################################################
14#
15# void fpu_init_state(void)
16# - initialise the FPU
17#
18###############################################################################
19 .globl fpu_init_state
20 .type fpu_init_state,@function
21fpu_init_state:
22 mov epsw,d0
23 or EPSW_FE,epsw
24
25#ifdef CONFIG_MN10300_PROC_MN103E010
26 nop
27 nop
28 nop
29#endif
30 fmov 0,fs0
31 fmov fs0,fs1
32 fmov fs0,fs2
33 fmov fs0,fs3
34 fmov fs0,fs4
35 fmov fs0,fs5
36 fmov fs0,fs6
37 fmov fs0,fs7
38 fmov fs0,fs8
39 fmov fs0,fs9
40 fmov fs0,fs10
41 fmov fs0,fs11
42 fmov fs0,fs12
43 fmov fs0,fs13
44 fmov fs0,fs14
45 fmov fs0,fs15
46 fmov fs0,fs16
47 fmov fs0,fs17
48 fmov fs0,fs18
49 fmov fs0,fs19
50 fmov fs0,fs20
51 fmov fs0,fs21
52 fmov fs0,fs22
53 fmov fs0,fs23
54 fmov fs0,fs24
55 fmov fs0,fs25
56 fmov fs0,fs26
57 fmov fs0,fs27
58 fmov fs0,fs28
59 fmov fs0,fs29
60 fmov fs0,fs30
61 fmov fs0,fs31
62 fmov FPCR_INIT,fpcr
63
64#ifdef CONFIG_MN10300_PROC_MN103E010
65 nop
66 nop
67 nop
68#endif
69 mov d0,epsw
70 ret [],0
71
72 .size fpu_init_state,.-fpu_init_state
73
74###############################################################################
75#
76# void fpu_save(struct fpu_state_struct *)
77# - save the fpu state
78# - note that an FPU Operational exception might occur during this process
79#
80###############################################################################
81 .globl fpu_save
82 .type fpu_save,@function
83fpu_save:
84 mov epsw,d1
85 or EPSW_FE,epsw /* enable the FPU so we can access it */
86
87#ifdef CONFIG_MN10300_PROC_MN103E010
88 nop
89 nop
90#endif
91 mov d0,a0
92 fmov fs0,(a0+)
93 fmov fs1,(a0+)
94 fmov fs2,(a0+)
95 fmov fs3,(a0+)
96 fmov fs4,(a0+)
97 fmov fs5,(a0+)
98 fmov fs6,(a0+)
99 fmov fs7,(a0+)
100 fmov fs8,(a0+)
101 fmov fs9,(a0+)
102 fmov fs10,(a0+)
103 fmov fs11,(a0+)
104 fmov fs12,(a0+)
105 fmov fs13,(a0+)
106 fmov fs14,(a0+)
107 fmov fs15,(a0+)
108 fmov fs16,(a0+)
109 fmov fs17,(a0+)
110 fmov fs18,(a0+)
111 fmov fs19,(a0+)
112 fmov fs20,(a0+)
113 fmov fs21,(a0+)
114 fmov fs22,(a0+)
115 fmov fs23,(a0+)
116 fmov fs24,(a0+)
117 fmov fs25,(a0+)
118 fmov fs26,(a0+)
119 fmov fs27,(a0+)
120 fmov fs28,(a0+)
121 fmov fs29,(a0+)
122 fmov fs30,(a0+)
123 fmov fs31,(a0+)
124 fmov fpcr,d0
125 mov d0,(a0)
126#ifdef CONFIG_MN10300_PROC_MN103E010
127 nop
128 nop
129#endif
130
131 mov d1,epsw
132 ret [],0
133
134 .size fpu_save,.-fpu_save
135
136###############################################################################
137#
138# void fpu_restore(struct fpu_state_struct *)
139# - restore the fpu state
140# - note that an FPU Operational exception might occur during this process
141#
142###############################################################################
143 .globl fpu_restore
144 .type fpu_restore,@function
145fpu_restore:
146 mov epsw,d1
147 or EPSW_FE,epsw /* enable the FPU so we can access it */
148
149#ifdef CONFIG_MN10300_PROC_MN103E010
150 nop
151 nop
152#endif
153 mov d0,a0
154 fmov (a0+),fs0
155 fmov (a0+),fs1
156 fmov (a0+),fs2
157 fmov (a0+),fs3
158 fmov (a0+),fs4
159 fmov (a0+),fs5
160 fmov (a0+),fs6
161 fmov (a0+),fs7
162 fmov (a0+),fs8
163 fmov (a0+),fs9
164 fmov (a0+),fs10
165 fmov (a0+),fs11
166 fmov (a0+),fs12
167 fmov (a0+),fs13
168 fmov (a0+),fs14
169 fmov (a0+),fs15
170 fmov (a0+),fs16
171 fmov (a0+),fs17
172 fmov (a0+),fs18
173 fmov (a0+),fs19
174 fmov (a0+),fs20
175 fmov (a0+),fs21
176 fmov (a0+),fs22
177 fmov (a0+),fs23
178 fmov (a0+),fs24
179 fmov (a0+),fs25
180 fmov (a0+),fs26
181 fmov (a0+),fs27
182 fmov (a0+),fs28
183 fmov (a0+),fs29
184 fmov (a0+),fs30
185 fmov (a0+),fs31
186 mov (a0),d0
187 fmov d0,fpcr
188#ifdef CONFIG_MN10300_PROC_MN103E010
189 nop
190 nop
191 nop
192#endif
193
194 mov d1,epsw
195 ret [],0
196
197 .size fpu_restore,.-fpu_restore
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c
new file mode 100644
index 000000000000..e705f25ad5ff
--- /dev/null
+++ b/arch/mn10300/kernel/fpu.c
@@ -0,0 +1,223 @@
1/* MN10300 FPU management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/uaccess.h>
12#include <asm/fpu.h>
13#include <asm/elf.h>
14#include <asm/exceptions.h>
15
16struct task_struct *fpu_state_owner;
17
18/*
19 * handle an exception due to the FPU being disabled
20 */
21asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code)
22{
23 struct task_struct *tsk = current;
24
25 if (!user_mode(regs))
26 die_if_no_fixup("An FPU Disabled exception happened in"
27 " kernel space\n",
28 regs, code);
29
30#ifdef CONFIG_FPU
31 preempt_disable();
32
33 /* transfer the last process's FPU state to memory */
34 if (fpu_state_owner) {
35 fpu_save(&fpu_state_owner->thread.fpu_state);
36 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
37 }
38
39 /* the current process now owns the FPU state */
40 fpu_state_owner = tsk;
41 regs->epsw |= EPSW_FE;
42
43 /* load the FPU with the current process's FPU state or invent a new
44 * clean one if the process doesn't have one */
45 if (is_using_fpu(tsk)) {
46 fpu_restore(&tsk->thread.fpu_state);
47 } else {
48 fpu_init_state();
49 set_using_fpu(tsk);
50 }
51
52 preempt_enable();
53#else
54 {
55 siginfo_t info;
56
57 info.si_signo = SIGFPE;
58 info.si_errno = 0;
59 info.si_addr = (void *) tsk->thread.uregs->pc;
60 info.si_code = FPE_FLTINV;
61
62 force_sig_info(SIGFPE, &info, tsk);
63 }
64#endif /* CONFIG_FPU */
65}
66
67/*
68 * handle an FPU operational exception
69 * - there's a possibility that if the FPU is asynchronous, the signal might
70 * be meant for a process other than the current one
71 */
72asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code)
73{
74 struct task_struct *tsk = fpu_state_owner;
75 siginfo_t info;
76
77 if (!user_mode(regs))
78 die_if_no_fixup("An FPU Operation exception happened in"
79 " kernel space\n",
80 regs, code);
81
82 if (!tsk)
83 die_if_no_fixup("An FPU Operation exception happened,"
84 " but the FPU is not in use",
85 regs, code);
86
87 info.si_signo = SIGFPE;
88 info.si_errno = 0;
89 info.si_addr = (void *) tsk->thread.uregs->pc;
90 info.si_code = FPE_FLTINV;
91
92#ifdef CONFIG_FPU
93 {
94 u32 fpcr;
95
96 /* get FPCR (we need to enable the FPU whilst we do this) */
97 asm volatile(" or %1,epsw \n"
98#ifdef CONFIG_MN10300_PROC_MN103E010
99 " nop \n"
100 " nop \n"
101 " nop \n"
102#endif
103 " fmov fpcr,%0 \n"
104#ifdef CONFIG_MN10300_PROC_MN103E010
105 " nop \n"
106 " nop \n"
107 " nop \n"
108#endif
109 " and %2,epsw \n"
110 : "=&d"(fpcr)
111 : "i"(EPSW_FE), "i"(~EPSW_FE)
112 );
113
114 if (fpcr & FPCR_EC_Z)
115 info.si_code = FPE_FLTDIV;
116 else if (fpcr & FPCR_EC_O)
117 info.si_code = FPE_FLTOVF;
118 else if (fpcr & FPCR_EC_U)
119 info.si_code = FPE_FLTUND;
120 else if (fpcr & FPCR_EC_I)
121 info.si_code = FPE_FLTRES;
122 }
123#endif
124
125 force_sig_info(SIGFPE, &info, tsk);
126}
127
128/*
129 * save the FPU state to a signal context
130 */
131int fpu_setup_sigcontext(struct fpucontext *fpucontext)
132{
133#ifdef CONFIG_FPU
134 struct task_struct *tsk = current;
135
136 if (!is_using_fpu(tsk))
137 return 0;
138
139 /* transfer the current FPU state to memory and cause fpu_init() to be
140 * triggered by the next attempted FPU operation by the current
141 * process.
142 */
143 preempt_disable();
144
145 if (fpu_state_owner == tsk) {
146 fpu_save(&tsk->thread.fpu_state);
147 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
148 fpu_state_owner = NULL;
149 }
150
151 preempt_enable();
152
153 /* we no longer have a valid current FPU state */
154 clear_using_fpu(tsk);
155
156 /* transfer the saved FPU state onto the userspace stack */
157 if (copy_to_user(fpucontext,
158 &tsk->thread.fpu_state,
159 min(sizeof(struct fpu_state_struct),
160 sizeof(struct fpucontext))))
161 return -1;
162
163 return 1;
164#else
165 return 0;
166#endif
167}
168
169/*
170 * kill a process's FPU state during restoration after signal handling
171 */
172void fpu_kill_state(struct task_struct *tsk)
173{
174#ifdef CONFIG_FPU
175 /* disown anything left in the FPU */
176 preempt_disable();
177
178 if (fpu_state_owner == tsk) {
179 fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE;
180 fpu_state_owner = NULL;
181 }
182
183 preempt_enable();
184#endif
185 /* we no longer have a valid current FPU state */
186 clear_using_fpu(tsk);
187}
188
189/*
190 * restore the FPU state from a signal context
191 */
192int fpu_restore_sigcontext(struct fpucontext *fpucontext)
193{
194 struct task_struct *tsk = current;
195 int ret;
196
197 /* load up the old FPU state */
198 ret = copy_from_user(&tsk->thread.fpu_state,
199 fpucontext,
200 min(sizeof(struct fpu_state_struct),
201 sizeof(struct fpucontext)));
202 if (!ret)
203 set_using_fpu(tsk);
204
205 return ret;
206}
207
208/*
209 * fill in the FPU structure for a core dump
210 */
211int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg)
212{
213 struct task_struct *tsk = current;
214 int fpvalid;
215
216 fpvalid = is_using_fpu(tsk);
217 if (fpvalid) {
218 unlazy_fpu(tsk);
219 memcpy(fpreg, &tsk->thread.fpu_state, sizeof(*fpreg));
220 }
221
222 return fpvalid;
223}
diff --git a/arch/mn10300/kernel/gdb-cache.S b/arch/mn10300/kernel/gdb-cache.S
new file mode 100644
index 000000000000..1108badc3d32
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-cache.S
@@ -0,0 +1,105 @@
1###############################################################################
2#
3# MN10300 Low-level cache purging routines for gdbstub
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/smp.h>
17#include <asm/cache.h>
18#include <asm/cpu-regs.h>
19#include <asm/exceptions.h>
20#include <asm/frame.inc>
21#include <asm/serial-regs.h>
22
23 .text
24
25###############################################################################
26#
27# GDB stub cache purge
28#
29###############################################################################
30 .type gdbstub_purge_cache,@function
31ENTRY(gdbstub_purge_cache)
32 #######################################################################
33 # read the addresses tagged in the cache's tag RAM and attempt to flush
34 # those addresses specifically
35 # - we rely on the hardware to filter out invalid tag entry addresses
36 mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address
37 mov DCACHE_PURGE(0,0),a1 # dcache purge request address
38 mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
39
40mn10300_dcache_flush_loop:
41 mov (a0),d0
42 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
43 or L1_CACHE_TAG_VALID,d0 # retain valid entries in the
44 # cache
45 mov d0,(a1) # conditional purge
46
47mn10300_dcache_flush_skip:
48 add L1_CACHE_BYTES,a0
49 add L1_CACHE_BYTES,a1
50 add -1,d1
51 bne mn10300_dcache_flush_loop
52
53;; # unconditionally flush and invalidate the dcache
54;; mov DCACHE_PURGE(0,0),a1 # dcache purge request address
55;; mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of
56;; # entries
57;;
58;; gdbstub_purge_cache__dcache_loop:
59;; mov (a1),d0 # unconditional purge
60;;
61;; add L1_CACHE_BYTES,a1
62;; add -1,d1
63;; bne gdbstub_purge_cache__dcache_loop
64
65 #######################################################################
66 # now invalidate the icache
67 mov CHCTR,a0
68 movhu (a0),a1
69
70 mov epsw,d1
71 and ~EPSW_IE,epsw
72 nop
73 nop
74
75 # disable the icache
76 and ~CHCTR_ICEN,d0
77 movhu d0,(a0)
78
79 # and wait for it to calm down
80 setlb
81 movhu (a0),d0
82 btst CHCTR_ICBUSY,d0
83 lne
84
85 # invalidate
86 or CHCTR_ICINV,d0
87 movhu d0,(a0)
88
89 # wait for the cache to finish
90 mov CHCTR,a0
91 setlb
92 movhu (a0),d0
93 btst CHCTR_ICBUSY,d0
94 lne
95
96 # and reenable it
97 movhu a1,(a0)
98 movhu (a0),d0 # read back to flush
99 # (SIGILLs all over without this)
100
101 mov d1,epsw
102
103 ret [],0
104
105 .size gdbstub_purge_cache,.-gdbstub_purge_cache
diff --git a/arch/mn10300/kernel/gdb-io-serial-low.S b/arch/mn10300/kernel/gdb-io-serial-low.S
new file mode 100644
index 000000000000..c68dcd052201
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-io-serial-low.S
@@ -0,0 +1,90 @@
1###############################################################################
2#
3# 16550 serial Rx interrupt handler for gdbstub I/O
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/smp.h>
17#include <asm/cpu-regs.h>
18#include <asm/thread_info.h>
19#include <asm/frame.inc>
20#include <asm/intctl-regs.h>
21#include <asm/unit/serial.h>
22
23 .text
24
25###############################################################################
26#
27# GDB stub serial receive interrupt entry point
28# - intended to run at interrupt priority 0
29#
30###############################################################################
31 .globl gdbstub_io_rx_handler
32 .type gdbstub_io_rx_handler,@function
33gdbstub_io_rx_handler:
34 movm [d2,d3,a2,a3],(sp)
35
36#if 1
37 movbu (GDBPORT_SERIAL_IIR),d2
38#endif
39
40 mov (gdbstub_rx_inp),a3
41gdbstub_io_rx_more:
42 mov a3,a2
43 add 2,a3
44 and 0x00000fff,a3
45 mov (gdbstub_rx_outp),d3
46 cmp a3,d3
47 beq gdbstub_io_rx_overflow
48
49 movbu (GDBPORT_SERIAL_LSR),d3
50 btst UART_LSR_DR,d3
51 beq gdbstub_io_rx_done
52 movbu (GDBPORT_SERIAL_RX),d2
53 movbu d3,(gdbstub_rx_buffer+1,a2)
54 movbu d2,(gdbstub_rx_buffer,a2)
55 mov a3,(gdbstub_rx_inp)
56 bra gdbstub_io_rx_more
57
58gdbstub_io_rx_done:
59 mov GxICR_DETECT,d2
60 movbu d2,(XIRQxICR(GDBPORT_SERIAL_IRQ)) # ACK the interrupt
61 movhu (XIRQxICR(GDBPORT_SERIAL_IRQ)),d2 # flush
62 movm (sp),[d2,d3,a2,a3]
63 bset 0x01,(gdbstub_busy)
64 beq gdbstub_io_rx_enter
65 rti
66
67gdbstub_io_rx_overflow:
68 bset 0x01,(gdbstub_rx_overflow)
69 bra gdbstub_io_rx_done
70
71gdbstub_io_rx_enter:
72 or EPSW_IE|EPSW_IM_1,epsw
73 add -4,sp
74 SAVE_ALL
75
76 mov 0xffffffff,d0
77 mov d0,(REG_ORIG_D0,fp)
78 mov 0x280,d1
79
80 mov fp,d0
81 call gdbstub_rx_irq[],0 # gdbstub_rx_irq(regs,excep)
82
83 and ~EPSW_IE,epsw
84 bclr 0x01,(gdbstub_busy)
85
86 .globl gdbstub_return
87gdbstub_return:
88 RESTORE_ALL
89
90 .size gdbstub_io_rx_handler,.-gdbstub_io_rx_handler
diff --git a/arch/mn10300/kernel/gdb-io-serial.c b/arch/mn10300/kernel/gdb-io-serial.c
new file mode 100644
index 000000000000..9a6d4e8ebe73
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-io-serial.c
@@ -0,0 +1,155 @@
1/* 16550 serial driver for gdbstub I/O
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/string.h>
12#include <linux/kernel.h>
13#include <linux/signal.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/console.h>
17#include <linux/init.h>
18#include <linux/nmi.h>
19
20#include <asm/pgtable.h>
21#include <asm/system.h>
22#include <asm/gdb-stub.h>
23#include <asm/exceptions.h>
24#include <asm/serial-regs.h>
25#include <asm/unit/serial.h>
26
27/*
28 * initialise the GDB stub
29 */
30void gdbstub_io_init(void)
31{
32 u16 tmp;
33
34 /* set up the serial port */
35 GDBPORT_SERIAL_LCR = UART_LCR_WLEN8; /* 1N8 */
36 GDBPORT_SERIAL_FCR = (UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
37 UART_FCR_CLEAR_XMIT);
38
39 FLOWCTL_CLEAR(DTR);
40 FLOWCTL_SET(RTS);
41
42 gdbstub_io_set_baud(115200);
43
44 /* we want to get serial receive interrupts */
45 XIRQxICR(GDBPORT_SERIAL_IRQ) = 0;
46 tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
47
48 IVAR0 = EXCEP_IRQ_LEVEL0;
49 set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
50
51 XIRQxICR(GDBPORT_SERIAL_IRQ) &= ~GxICR_REQUEST;
52 XIRQxICR(GDBPORT_SERIAL_IRQ) = GxICR_ENABLE | GxICR_LEVEL_0;
53 tmp = XIRQxICR(GDBPORT_SERIAL_IRQ);
54
55 GDBPORT_SERIAL_IER = UART_IER_RDI | UART_IER_RLSI;
56
57 /* permit level 0 IRQs to take place */
58 asm volatile(
59 " and %0,epsw \n"
60 " or %1,epsw \n"
61 :
62 : "i"(~EPSW_IM), "i"(EPSW_IE | EPSW_IM_1)
63 );
64}
65
66/*
67 * set up the GDB stub serial port baud rate timers
68 */
69void gdbstub_io_set_baud(unsigned baud)
70{
71 unsigned value;
72 u8 lcr;
73
74 value = 18432000 / 16 / baud;
75
76 lcr = GDBPORT_SERIAL_LCR;
77 GDBPORT_SERIAL_LCR |= UART_LCR_DLAB;
78 GDBPORT_SERIAL_DLL = value & 0xff;
79 GDBPORT_SERIAL_DLM = (value >> 8) & 0xff;
80 GDBPORT_SERIAL_LCR = lcr;
81}
82
83/*
84 * wait for a character to come from the debugger
85 */
86int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
87{
88 unsigned ix;
89 u8 ch, st;
90
91 *_ch = 0xff;
92
93 if (gdbstub_rx_unget) {
94 *_ch = gdbstub_rx_unget;
95 gdbstub_rx_unget = 0;
96 return 0;
97 }
98
99 try_again:
100 /* pull chars out of the buffer */
101 ix = gdbstub_rx_outp;
102 if (ix == gdbstub_rx_inp) {
103 if (nonblock)
104 return -EAGAIN;
105#ifdef CONFIG_MN10300_WD_TIMER
106 watchdog_alert_counter = 0;
107#endif /* CONFIG_MN10300_WD_TIMER */
108 goto try_again;
109 }
110
111 ch = gdbstub_rx_buffer[ix++];
112 st = gdbstub_rx_buffer[ix++];
113 gdbstub_rx_outp = ix & 0x00000fff;
114
115 if (st & UART_LSR_BI) {
116 gdbstub_proto("### GDB Rx Break Detected ###\n");
117 return -EINTR;
118 } else if (st & (UART_LSR_FE | UART_LSR_OE | UART_LSR_PE)) {
119 gdbstub_proto("### GDB Rx Error (st=%02x) ###\n", st);
120 return -EIO;
121 } else {
122 gdbstub_proto("### GDB Rx %02x (st=%02x) ###\n", ch, st);
123 *_ch = ch & 0x7f;
124 return 0;
125 }
126}
127
128/*
129 * send a character to the debugger
130 */
131void gdbstub_io_tx_char(unsigned char ch)
132{
133 FLOWCTL_SET(DTR);
134 LSR_WAIT_FOR(THRE);
135 /* FLOWCTL_WAIT_FOR(CTS); */
136
137 if (ch == 0x0a) {
138 GDBPORT_SERIAL_TX = 0x0d;
139 LSR_WAIT_FOR(THRE);
140 /* FLOWCTL_WAIT_FOR(CTS); */
141 }
142 GDBPORT_SERIAL_TX = ch;
143
144 FLOWCTL_CLEAR(DTR);
145}
146
147/*
148 * send a character to the debugger
149 */
150void gdbstub_io_tx_flush(void)
151{
152 LSR_WAIT_FOR(TEMT);
153 LSR_WAIT_FOR(THRE);
154 FLOWCTL_CLEAR(DTR);
155}
diff --git a/arch/mn10300/kernel/gdb-io-ttysm-low.S b/arch/mn10300/kernel/gdb-io-ttysm-low.S
new file mode 100644
index 000000000000..677c7876307c
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-io-ttysm-low.S
@@ -0,0 +1,93 @@
1###############################################################################
2#
3# MN10300 On-chip serial Rx interrupt handler for GDB stub I/O
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/smp.h>
17#include <asm/thread_info.h>
18#include <asm/cpu-regs.h>
19#include <asm/frame.inc>
20#include <asm/intctl-regs.h>
21#include <asm/unit/serial.h>
22#include "mn10300-serial.h"
23
24 .text
25
26###############################################################################
27#
28# GDB stub serial receive interrupt entry point
29# - intended to run at interrupt priority 0
30#
31###############################################################################
32 .globl gdbstub_io_rx_handler
33 .type gdbstub_io_rx_handler,@function
34gdbstub_io_rx_handler:
35 movm [d2,d3,a2,a3],(sp)
36
37 mov (gdbstub_rx_inp),a3
38gdbstub_io_rx_more:
39 mov a3,a2
40 add 2,a3
41 and PAGE_SIZE_asm-1,a3
42 mov (gdbstub_rx_outp),d3
43 cmp a3,d3
44 beq gdbstub_io_rx_overflow
45
46 movbu (SCgSTR),d3
47 btst SC01STR_RBF,d3
48 beq gdbstub_io_rx_done
49 movbu (SCgRXB),d2
50 movbu d3,(gdbstub_rx_buffer+1,a2)
51 movbu d2,(gdbstub_rx_buffer,a2)
52 mov a3,(gdbstub_rx_inp)
53 bra gdbstub_io_rx_more
54
55gdbstub_io_rx_done:
56 mov GxICR_DETECT,d2
57 movbu d2,(GxICR(SCgRXIRQ)) # ACK the interrupt
58 movhu (GxICR(SCgRXIRQ)),d2 # flush
59
60 movm (sp),[d2,d3,a2,a3]
61 bset 0x01,(gdbstub_busy)
62 beq gdbstub_io_rx_enter
63 rti
64
65gdbstub_io_rx_overflow:
66 bset 0x01,(gdbstub_rx_overflow)
67 bra gdbstub_io_rx_done
68
69###############################################################################
70#
71# debugging interrupt - enter the GDB stub proper
72#
73###############################################################################
74gdbstub_io_rx_enter:
75 or EPSW_IE|EPSW_IM_1,epsw
76 add -4,sp
77 SAVE_ALL
78
79 mov 0xffffffff,d0
80 mov d0,(REG_ORIG_D0,fp)
81 mov 0x280,d1
82
83 mov fp,d0
84 call gdbstub_rx_irq[],0 # gdbstub_io_rx_irq(regs,excep)
85
86 and ~EPSW_IE,epsw
87 bclr 0x01,(gdbstub_busy)
88
89 .globl gdbstub_return
90gdbstub_return:
91 RESTORE_ALL
92
93 .size gdbstub_io_rx_handler,.-gdbstub_io_rx_handler
diff --git a/arch/mn10300/kernel/gdb-io-ttysm.c b/arch/mn10300/kernel/gdb-io-ttysm.c
new file mode 100644
index 000000000000..c5451592d403
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-io-ttysm.c
@@ -0,0 +1,299 @@
1/* MN10300 On-chip serial driver for gdbstub I/O
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/string.h>
12#include <linux/kernel.h>
13#include <linux/signal.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <linux/console.h>
17#include <linux/init.h>
18#include <linux/tty.h>
19#include <asm/pgtable.h>
20#include <asm/system.h>
21#include <asm/gdb-stub.h>
22#include <asm/exceptions.h>
23#include <asm/unit/clock.h>
24#include "mn10300-serial.h"
25
26#if defined(CONFIG_GDBSTUB_ON_TTYSM0)
27struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif0;
28#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
29struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif1;
30#else
31struct mn10300_serial_port *const gdbstub_port = &mn10300_serial_port_sif2;
32#endif
33
34
35/*
36 * initialise the GDB stub I/O routines
37 */
38void __init gdbstub_io_init(void)
39{
40 uint16_t scxctr;
41 int tmp;
42
43 switch (gdbstub_port->clock_src) {
44 case MNSCx_CLOCK_SRC_IOCLK:
45 gdbstub_port->ioclk = MN10300_IOCLK;
46 break;
47
48#ifdef MN10300_IOBCLK
49 case MNSCx_CLOCK_SRC_IOBCLK:
50 gdbstub_port->ioclk = MN10300_IOBCLK;
51 break;
52#endif
53 default:
54 BUG();
55 }
56
57 /* set up the serial port */
58 gdbstub_io_set_baud(115200);
59
60 /* we want to get serial receive interrupts */
61 set_intr_level(gdbstub_port->rx_irq, GxICR_LEVEL_0);
62 set_intr_level(gdbstub_port->tx_irq, GxICR_LEVEL_0);
63 set_intr_stub(EXCEP_IRQ_LEVEL0, gdbstub_io_rx_handler);
64
65 *gdbstub_port->rx_icr |= GxICR_ENABLE;
66 tmp = *gdbstub_port->rx_icr;
67
68 /* enable the device */
69 scxctr = SC01CTR_CLN_8BIT; /* 1N8 */
70 switch (gdbstub_port->div_timer) {
71 case MNSCx_DIV_TIMER_16BIT:
72 scxctr |= SC0CTR_CK_TM8UFLOW_8; /* == SC1CTR_CK_TM9UFLOW_8
73 == SC2CTR_CK_TM10UFLOW_8 */
74 break;
75
76 case MNSCx_DIV_TIMER_8BIT:
77 scxctr |= SC0CTR_CK_TM2UFLOW_8;
78 break;
79 }
80
81 scxctr |= SC01CTR_TXE | SC01CTR_RXE;
82
83 *gdbstub_port->_control = scxctr;
84 tmp = *gdbstub_port->_control;
85
86 /* permit level 0 IRQs only */
87 asm volatile(
88 " and %0,epsw \n"
89 " or %1,epsw \n"
90 :
91 : "i"(~EPSW_IM), "i"(EPSW_IE|EPSW_IM_1)
92 );
93}
94
95/*
96 * set up the GDB stub serial port baud rate timers
97 */
98void gdbstub_io_set_baud(unsigned baud)
99{
100 const unsigned bits = 10; /* 1 [start] + 8 [data] + 0 [parity] +
101 * 1 [stop] */
102 unsigned long ioclk = gdbstub_port->ioclk;
103 unsigned xdiv, tmp;
104 uint16_t tmxbr;
105 uint8_t tmxmd;
106
107 if (!baud) {
108 baud = 9600;
109 } else if (baud == 134) {
110 baud = 269; /* 134 is really 134.5 */
111 xdiv = 2;
112 }
113
114try_alternative:
115 xdiv = 1;
116
117 switch (gdbstub_port->div_timer) {
118 case MNSCx_DIV_TIMER_16BIT:
119 tmxmd = TM8MD_SRC_IOCLK;
120 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
121 if (tmp > 0 && tmp <= 65535)
122 goto timer_okay;
123
124 tmxmd = TM8MD_SRC_IOCLK_8;
125 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
126 if (tmp > 0 && tmp <= 65535)
127 goto timer_okay;
128
129 tmxmd = TM8MD_SRC_IOCLK_32;
130 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
131 if (tmp > 0 && tmp <= 65535)
132 goto timer_okay;
133
134 break;
135
136 case MNSCx_DIV_TIMER_8BIT:
137 tmxmd = TM2MD_SRC_IOCLK;
138 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
139 if (tmp > 0 && tmp <= 255)
140 goto timer_okay;
141
142 tmxmd = TM2MD_SRC_IOCLK_8;
143 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
144 if (tmp > 0 && tmp <= 255)
145 goto timer_okay;
146
147 tmxmd = TM2MD_SRC_IOCLK_32;
148 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
149 if (tmp > 0 && tmp <= 255)
150 goto timer_okay;
151 break;
152 }
153
154 /* as a last resort, if the quotient is zero, default to 9600 bps */
155 baud = 9600;
156 goto try_alternative;
157
158timer_okay:
159 gdbstub_port->uart.timeout = (2 * bits * HZ) / baud;
160 gdbstub_port->uart.timeout += HZ / 50;
161
162 /* set the timer to produce the required baud rate */
163 switch (gdbstub_port->div_timer) {
164 case MNSCx_DIV_TIMER_16BIT:
165 *gdbstub_port->_tmxmd = 0;
166 *gdbstub_port->_tmxbr = tmxbr;
167 *gdbstub_port->_tmxmd = TM8MD_INIT_COUNTER;
168 *gdbstub_port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
169 break;
170
171 case MNSCx_DIV_TIMER_8BIT:
172 *gdbstub_port->_tmxmd = 0;
173 *(volatile u8 *) gdbstub_port->_tmxbr = (u8)tmxbr;
174 *gdbstub_port->_tmxmd = TM2MD_INIT_COUNTER;
175 *gdbstub_port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
176 break;
177 }
178}
179
180/*
181 * wait for a character to come from the debugger
182 */
183int gdbstub_io_rx_char(unsigned char *_ch, int nonblock)
184{
185 unsigned ix;
186 u8 ch, st;
187
188 *_ch = 0xff;
189
190 if (gdbstub_rx_unget) {
191 *_ch = gdbstub_rx_unget;
192 gdbstub_rx_unget = 0;
193 return 0;
194 }
195
196try_again:
197 /* pull chars out of the buffer */
198 ix = gdbstub_rx_outp;
199 if (ix == gdbstub_rx_inp) {
200 if (nonblock)
201 return -EAGAIN;
202#ifdef CONFIG_MN10300_WD_TIMER
203 watchdog_alert_counter = 0;
204#endif /* CONFIG_MN10300_WD_TIMER */
205 goto try_again;
206 }
207
208 ch = gdbstub_rx_buffer[ix++];
209 st = gdbstub_rx_buffer[ix++];
210 gdbstub_rx_outp = ix & (PAGE_SIZE - 1);
211
212 st &= SC01STR_RXF | SC01STR_RBF | SC01STR_FEF | SC01STR_PEF |
213 SC01STR_OEF;
214
215 /* deal with what we've got
216 * - note that the UART doesn't do BREAK-detection for us
217 */
218 if (st & SC01STR_FEF && ch == 0) {
219 switch (gdbstub_port->rx_brk) {
220 case 0: gdbstub_port->rx_brk = 1; goto try_again;
221 case 1: gdbstub_port->rx_brk = 2; goto try_again;
222 case 2:
223 gdbstub_port->rx_brk = 3;
224 gdbstub_proto("### GDB MNSERIAL Rx Break Detected"
225 " ###\n");
226 return -EINTR;
227 default:
228 goto try_again;
229 }
230 } else if (st & SC01STR_FEF) {
231 if (gdbstub_port->rx_brk)
232 goto try_again;
233
234 gdbstub_proto("### GDB MNSERIAL Framing Error ###\n");
235 return -EIO;
236 } else if (st & SC01STR_OEF) {
237 if (gdbstub_port->rx_brk)
238 goto try_again;
239
240 gdbstub_proto("### GDB MNSERIAL Overrun Error ###\n");
241 return -EIO;
242 } else if (st & SC01STR_PEF) {
243 if (gdbstub_port->rx_brk)
244 goto try_again;
245
246 gdbstub_proto("### GDB MNSERIAL Parity Error ###\n");
247 return -EIO;
248 } else {
249 /* look for the tail-end char on a break run */
250 if (gdbstub_port->rx_brk == 3) {
251 switch (ch) {
252 case 0xFF:
253 case 0xFE:
254 case 0xFC:
255 case 0xF8:
256 case 0xF0:
257 case 0xE0:
258 case 0xC0:
259 case 0x80:
260 case 0x00:
261 gdbstub_port->rx_brk = 0;
262 goto try_again;
263 default:
264 break;
265 }
266 }
267
268 gdbstub_port->rx_brk = 0;
269 gdbstub_io("### GDB Rx %02x (st=%02x) ###\n", ch, st);
270 *_ch = ch & 0x7f;
271 return 0;
272 }
273}
274
275/*
276 * send a character to the debugger
277 */
278void gdbstub_io_tx_char(unsigned char ch)
279{
280 while (*gdbstub_port->_status & SC01STR_TBF)
281 continue;
282
283 if (ch == 0x0a) {
284 *(u8 *) gdbstub_port->_txb = 0x0d;
285 while (*gdbstub_port->_status & SC01STR_TBF)
286 continue;
287 }
288
289 *(u8 *) gdbstub_port->_txb = ch;
290}
291
292/*
293 * flush the transmission buffers
294 */
295void gdbstub_io_tx_flush(void)
296{
297 while (*gdbstub_port->_status & (SC01STR_TBF | SC01STR_TXF))
298 continue;
299}
diff --git a/arch/mn10300/kernel/gdb-low.S b/arch/mn10300/kernel/gdb-low.S
new file mode 100644
index 000000000000..e2725552cd82
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-low.S
@@ -0,0 +1,115 @@
1###############################################################################
2#
3# MN10300 Low-level gdbstub routines
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/smp.h>
17#include <asm/cache.h>
18#include <asm/cpu-regs.h>
19#include <asm/exceptions.h>
20#include <asm/frame.inc>
21#include <asm/serial-regs.h>
22
23 .text
24
25###############################################################################
26#
27# GDB stub read memory with guard
28# - D0 holds the memory address to read
29# - D1 holds the address to store the byte into
30#
31###############################################################################
32 .globl gdbstub_read_byte_guard
33 .globl gdbstub_read_byte_cont
34ENTRY(gdbstub_read_byte)
35 mov d0,a0
36 mov d1,a1
37 clr d0
38gdbstub_read_byte_guard:
39 movbu (a0),d1
40gdbstub_read_byte_cont:
41 movbu d1,(a1)
42 ret [],0
43
44 .globl gdbstub_read_word_guard
45 .globl gdbstub_read_word_cont
46ENTRY(gdbstub_read_word)
47 mov d0,a0
48 mov d1,a1
49 clr d0
50gdbstub_read_word_guard:
51 movhu (a0),d1
52gdbstub_read_word_cont:
53 movhu d1,(a1)
54 ret [],0
55
56 .globl gdbstub_read_dword_guard
57 .globl gdbstub_read_dword_cont
58ENTRY(gdbstub_read_dword)
59 mov d0,a0
60 mov d1,a1
61 clr d0
62gdbstub_read_dword_guard:
63 mov (a0),d1
64gdbstub_read_dword_cont:
65 mov d1,(a1)
66 ret [],0
67
68###############################################################################
69#
70# GDB stub write memory with guard
71# - D0 holds the byte to store
72# - D1 holds the memory address to write
73#
74###############################################################################
75 .globl gdbstub_write_byte_guard
76 .globl gdbstub_write_byte_cont
77ENTRY(gdbstub_write_byte)
78 mov d0,a0
79 mov d1,a1
80 clr d0
81gdbstub_write_byte_guard:
82 movbu a0,(a1)
83gdbstub_write_byte_cont:
84 ret [],0
85
86 .globl gdbstub_write_word_guard
87 .globl gdbstub_write_word_cont
88ENTRY(gdbstub_write_word)
89 mov d0,a0
90 mov d1,a1
91 clr d0
92gdbstub_write_word_guard:
93 movhu a0,(a1)
94gdbstub_write_word_cont:
95 ret [],0
96
97 .globl gdbstub_write_dword_guard
98 .globl gdbstub_write_dword_cont
99ENTRY(gdbstub_write_dword)
100 mov d0,a0
101 mov d1,a1
102 clr d0
103gdbstub_write_dword_guard:
104 mov a0,(a1)
105gdbstub_write_dword_cont:
106 ret [],0
107
108###############################################################################
109#
110# GDB stub BUG() trap
111#
112###############################################################################
113ENTRY(__gdbstub_bug_trap)
114 .byte 0xF7,0xF7 # don't use 0xFF as the JTAG unit preempts that
115 ret [],0
diff --git a/arch/mn10300/kernel/gdb-stub.c b/arch/mn10300/kernel/gdb-stub.c
new file mode 100644
index 000000000000..21891c71d549
--- /dev/null
+++ b/arch/mn10300/kernel/gdb-stub.c
@@ -0,0 +1,1947 @@
1/* MN10300 GDB stub
2 *
3 * Originally written by Glenn Engel, Lake Stevens Instrument Division
4 *
5 * Contributed by HP Systems
6 *
7 * Modified for SPARC by Stu Grossman, Cygnus Support.
8 *
9 * Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
10 * Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
11 *
12 * Copyright (C) 1995 Andreas Busse
13 *
14 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
15 * Modified for Linux/mn10300 by David Howells <dhowells@redhat.com>
16 */
17
18/*
19 * To enable debugger support, two things need to happen. One, a
20 * call to set_debug_traps() is necessary in order to allow any breakpoints
21 * or error conditions to be properly intercepted and reported to gdb.
22 * Two, a breakpoint needs to be generated to begin communication. This
23 * is most easily accomplished by a call to breakpoint(). Breakpoint()
24 * simulates a breakpoint by executing a BREAK instruction.
25 *
26 *
27 * The following gdb commands are supported:
28 *
29 * command function Return value
30 *
31 * g return the value of the CPU registers hex data or ENN
32 * G set the value of the CPU registers OK or ENN
33 *
34 * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
35 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
36 *
37 * c Resume at current address SNN ( signal NN)
38 * cAA..AA Continue at address AA..AA SNN
39 *
40 * s Step one instruction SNN
41 * sAA..AA Step one instruction from AA..AA SNN
42 *
43 * k kill
44 *
45 * ? What was the last sigval ? SNN (signal NN)
46 *
47 * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
48 * baud rate
49 *
50 * All commands and responses are sent with a packet which includes a
51 * checksum. A packet consists of
52 *
53 * $<packet info>#<checksum>.
54 *
55 * where
56 * <packet info> :: <characters representing the command or response>
57 * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
58 *
59 * When a packet is received, it is first acknowledged with either '+' or '-'.
60 * '+' indicates a successful transfer. '-' indicates a failed transfer.
61 *
62 * Example:
63 *
64 * Host: Reply:
65 * $m0,10#2a +$00010203040506070809101112131415#42
66 *
67 *
68 * ==============
69 * MORE EXAMPLES:
70 * ==============
71 *
72 * For reference -- the following are the steps that one
73 * company took (RidgeRun Inc) to get remote gdb debugging
74 * going. In this scenario the host machine was a PC and the
75 * target platform was a Galileo EVB64120A MIPS evaluation
76 * board.
77 *
78 * Step 1:
79 * First download gdb-5.0.tar.gz from the internet.
80 * and then build/install the package.
81 *
82 * Example:
83 * $ tar zxf gdb-5.0.tar.gz
84 * $ cd gdb-5.0
85 * $ ./configure --target=am33_2.0-linux-gnu
86 * $ make
87 * $ install
88 * am33_2.0-linux-gnu-gdb
89 *
90 * Step 2:
91 * Configure linux for remote debugging and build it.
92 *
93 * Example:
94 * $ cd ~/linux
95 * $ make menuconfig <go to "Kernel Hacking" and turn on remote debugging>
96 * $ make dep; make vmlinux
97 *
98 * Step 3:
99 * Download the kernel to the remote target and start
100 * the kernel running. It will promptly halt and wait
101 * for the host gdb session to connect. It does this
102 * since the "Kernel Hacking" option has defined
103 * CONFIG_REMOTE_DEBUG which in turn enables your calls
104 * to:
105 * set_debug_traps();
106 * breakpoint();
107 *
108 * Step 4:
109 * Start the gdb session on the host.
110 *
111 * Example:
112 * $ am33_2.0-linux-gnu-gdb vmlinux
113 * (gdb) set remotebaud 115200
114 * (gdb) target remote /dev/ttyS1
115 * ...at this point you are connected to
116 * the remote target and can use gdb
117 * in the normal fasion. Setting
118 * breakpoints, single stepping,
119 * printing variables, etc.
120 *
121 */
122
123#include <linux/string.h>
124#include <linux/kernel.h>
125#include <linux/signal.h>
126#include <linux/sched.h>
127#include <linux/mm.h>
128#include <linux/console.h>
129#include <linux/init.h>
130#include <linux/bug.h>
131
132#include <asm/pgtable.h>
133#include <asm/system.h>
134#include <asm/gdb-stub.h>
135#include <asm/exceptions.h>
136#include <asm/cacheflush.h>
137#include <asm/serial-regs.h>
138#include <asm/busctl-regs.h>
139#include <asm/unit/leds.h>
140#include <asm/unit/serial.h>
141
142/* define to use F7F7 rather than FF which is subverted by JTAG debugger */
143#undef GDBSTUB_USE_F7F7_AS_BREAKPOINT
144
145/*
146 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
147 * at least NUMREGBYTES*2 are needed for register packets
148 */
149#define BUFMAX 2048
150
151static const char gdbstub_banner[] =
152 "Linux/MN10300 GDB Stub (c) RedHat 2007\n";
153
154u8 gdbstub_rx_buffer[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE)));
155u32 gdbstub_rx_inp;
156u32 gdbstub_rx_outp;
157u8 gdbstub_busy;
158u8 gdbstub_rx_overflow;
159u8 gdbstub_rx_unget;
160
161static u8 gdbstub_flush_caches;
162static char input_buffer[BUFMAX];
163static char output_buffer[BUFMAX];
164static char trans_buffer[BUFMAX];
165
166static const char hexchars[] = "0123456789abcdef";
167
168struct gdbstub_bkpt {
169 u8 *addr; /* address of breakpoint */
170 u8 len; /* size of breakpoint */
171 u8 origbytes[7]; /* original bytes */
172};
173
174static struct gdbstub_bkpt gdbstub_bkpts[256];
175
176/*
177 * local prototypes
178 */
179static void getpacket(char *buffer);
180static int putpacket(char *buffer);
181static int computeSignal(enum exception_code excep);
182static int hex(unsigned char ch);
183static int hexToInt(char **ptr, int *intValue);
184static unsigned char *mem2hex(const void *mem, char *buf, int count,
185 int may_fault);
186static const char *hex2mem(const char *buf, void *_mem, int count,
187 int may_fault);
188
189/*
190 * Convert ch from a hex digit to an int
191 */
192static int hex(unsigned char ch)
193{
194 if (ch >= 'a' && ch <= 'f')
195 return ch - 'a' + 10;
196 if (ch >= '0' && ch <= '9')
197 return ch - '0';
198 if (ch >= 'A' && ch <= 'F')
199 return ch - 'A' + 10;
200 return -1;
201}
202
203#ifdef CONFIG_GDBSTUB_DEBUGGING
204
205void debug_to_serial(const char *p, int n)
206{
207 __debug_to_serial(p, n);
208 /* gdbstub_console_write(NULL, p, n); */
209}
210
211void gdbstub_printk(const char *fmt, ...)
212{
213 va_list args;
214 int len;
215
216 /* Emit the output into the temporary buffer */
217 va_start(args, fmt);
218 len = vsnprintf(trans_buffer, sizeof(trans_buffer), fmt, args);
219 va_end(args);
220 debug_to_serial(trans_buffer, len);
221}
222
223#endif
224
225static inline char *gdbstub_strcpy(char *dst, const char *src)
226{
227 int loop = 0;
228 while ((dst[loop] = src[loop]))
229 loop++;
230 return dst;
231}
232
233/*
234 * scan for the sequence $<data>#<checksum>
235 */
236static void getpacket(char *buffer)
237{
238 unsigned char checksum;
239 unsigned char xmitcsum;
240 unsigned char ch;
241 int count, i, ret, error;
242
243 for (;;) {
244 /*
245 * wait around for the start character,
246 * ignore all other characters
247 */
248 do {
249 gdbstub_io_rx_char(&ch, 0);
250 } while (ch != '$');
251
252 checksum = 0;
253 xmitcsum = -1;
254 count = 0;
255 error = 0;
256
257 /*
258 * now, read until a # or end of buffer is found
259 */
260 while (count < BUFMAX) {
261 ret = gdbstub_io_rx_char(&ch, 0);
262 if (ret < 0)
263 error = ret;
264
265 if (ch == '#')
266 break;
267 checksum += ch;
268 buffer[count] = ch;
269 count++;
270 }
271
272 if (error == -EIO) {
273 gdbstub_proto("### GDB Rx Error - Skipping packet"
274 " ###\n");
275 gdbstub_proto("### GDB Tx NAK\n");
276 gdbstub_io_tx_char('-');
277 continue;
278 }
279
280 if (count >= BUFMAX || error)
281 continue;
282
283 buffer[count] = 0;
284
285 /* read the checksum */
286 ret = gdbstub_io_rx_char(&ch, 0);
287 if (ret < 0)
288 error = ret;
289 xmitcsum = hex(ch) << 4;
290
291 ret = gdbstub_io_rx_char(&ch, 0);
292 if (ret < 0)
293 error = ret;
294 xmitcsum |= hex(ch);
295
296 if (error) {
297 if (error == -EIO)
298 gdbstub_io("### GDB Rx Error -"
299 " Skipping packet\n");
300 gdbstub_io("### GDB Tx NAK\n");
301 gdbstub_io_tx_char('-');
302 continue;
303 }
304
305 /* check the checksum */
306 if (checksum != xmitcsum) {
307 gdbstub_io("### GDB Tx NAK\n");
308 gdbstub_io_tx_char('-'); /* failed checksum */
309 continue;
310 }
311
312 gdbstub_proto("### GDB Rx '$%s#%02x' ###\n", buffer, checksum);
313 gdbstub_io("### GDB Tx ACK\n");
314 gdbstub_io_tx_char('+'); /* successful transfer */
315
316 /*
317 * if a sequence char is present,
318 * reply the sequence ID
319 */
320 if (buffer[2] == ':') {
321 gdbstub_io_tx_char(buffer[0]);
322 gdbstub_io_tx_char(buffer[1]);
323
324 /*
325 * remove sequence chars from buffer
326 */
327 count = 0;
328 while (buffer[count])
329 count++;
330 for (i = 3; i <= count; i++)
331 buffer[i - 3] = buffer[i];
332 }
333
334 break;
335 }
336}
337
338/*
339 * send the packet in buffer.
340 * - return 0 if successfully ACK'd
341 * - return 1 if abandoned due to new incoming packet
342 */
343static int putpacket(char *buffer)
344{
345 unsigned char checksum;
346 unsigned char ch;
347 int count;
348
349 /*
350 * $<packet info>#<checksum>.
351 */
352 gdbstub_proto("### GDB Tx $'%s'#?? ###\n", buffer);
353
354 do {
355 gdbstub_io_tx_char('$');
356 checksum = 0;
357 count = 0;
358
359 while ((ch = buffer[count]) != 0) {
360 gdbstub_io_tx_char(ch);
361 checksum += ch;
362 count += 1;
363 }
364
365 gdbstub_io_tx_char('#');
366 gdbstub_io_tx_char(hexchars[checksum >> 4]);
367 gdbstub_io_tx_char(hexchars[checksum & 0xf]);
368
369 } while (gdbstub_io_rx_char(&ch, 0),
370 ch == '-' && (gdbstub_io("### GDB Rx NAK\n"), 0),
371 ch != '-' && ch != '+' &&
372 (gdbstub_io("### GDB Rx ??? %02x\n", ch), 0),
373 ch != '+' && ch != '$');
374
375 if (ch == '+') {
376 gdbstub_io("### GDB Rx ACK\n");
377 return 0;
378 }
379
380 gdbstub_io("### GDB Tx Abandoned\n");
381 gdbstub_rx_unget = ch;
382 return 1;
383}
384
385/*
386 * While we find nice hex chars, build an int.
387 * Return number of chars processed.
388 */
389static int hexToInt(char **ptr, int *intValue)
390{
391 int numChars = 0;
392 int hexValue;
393
394 *intValue = 0;
395
396 while (**ptr) {
397 hexValue = hex(**ptr);
398 if (hexValue < 0)
399 break;
400
401 *intValue = (*intValue << 4) | hexValue;
402 numChars++;
403
404 (*ptr)++;
405 }
406
407 return (numChars);
408}
409
410/*
411 * We single-step by setting breakpoints. When an exception
412 * is handled, we need to restore the instructions hoisted
413 * when the breakpoints were set.
414 *
415 * This is where we save the original instructions.
416 */
417static struct gdb_bp_save {
418 u8 *addr;
419 u8 opcode[2];
420} step_bp[2];
421
422static const unsigned char gdbstub_insn_sizes[256] =
423{
424 /* 1 2 3 4 5 6 7 8 9 a b c d e f */
425 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */
426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
427 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */
428 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */
429 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */
430 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */
431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
433 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */
434 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */
435 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */
436 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */
437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */
438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
440 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1 /* f */
441};
442
443static int __gdbstub_mark_bp(u8 *addr, int ix)
444{
445 if (addr < (u8 *) 0x70000000UL)
446 return 0;
447 /* 70000000-7fffffff: vmalloc area */
448 if (addr < (u8 *) 0x80000000UL)
449 goto okay;
450 if (addr < (u8 *) 0x8c000000UL)
451 return 0;
452 /* 8c000000-93ffffff: SRAM, SDRAM */
453 if (addr < (u8 *) 0x94000000UL)
454 goto okay;
455 return 0;
456
457okay:
458 if (gdbstub_read_byte(addr + 0, &step_bp[ix].opcode[0]) < 0 ||
459 gdbstub_read_byte(addr + 1, &step_bp[ix].opcode[1]) < 0)
460 return 0;
461
462 step_bp[ix].addr = addr;
463 return 1;
464}
465
466static inline void __gdbstub_restore_bp(void)
467{
468#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
469 if (step_bp[0].addr) {
470 gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0);
471 gdbstub_write_byte(step_bp[0].opcode[1], step_bp[0].addr + 1);
472 }
473 if (step_bp[1].addr) {
474 gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0);
475 gdbstub_write_byte(step_bp[1].opcode[1], step_bp[1].addr + 1);
476 }
477#else
478 if (step_bp[0].addr)
479 gdbstub_write_byte(step_bp[0].opcode[0], step_bp[0].addr + 0);
480 if (step_bp[1].addr)
481 gdbstub_write_byte(step_bp[1].opcode[0], step_bp[1].addr + 0);
482#endif
483
484 gdbstub_flush_caches = 1;
485
486 step_bp[0].addr = NULL;
487 step_bp[0].opcode[0] = 0;
488 step_bp[0].opcode[1] = 0;
489 step_bp[1].addr = NULL;
490 step_bp[1].opcode[0] = 0;
491 step_bp[1].opcode[1] = 0;
492}
493
494/*
495 * emulate single stepping by means of breakpoint instructions
496 */
497static int gdbstub_single_step(struct pt_regs *regs)
498{
499 unsigned size;
500 uint32_t x;
501 uint8_t cur, *pc, *sp;
502
503 step_bp[0].addr = NULL;
504 step_bp[0].opcode[0] = 0;
505 step_bp[0].opcode[1] = 0;
506 step_bp[1].addr = NULL;
507 step_bp[1].opcode[0] = 0;
508 step_bp[1].opcode[1] = 0;
509 x = 0;
510
511 pc = (u8 *) regs->pc;
512 sp = (u8 *) (regs + 1);
513 if (gdbstub_read_byte(pc, &cur) < 0)
514 return -EFAULT;
515
516 gdbstub_bkpt("Single Step from %p { %02x }\n", pc, cur);
517
518 gdbstub_flush_caches = 1;
519
520 size = gdbstub_insn_sizes[cur];
521 if (size > 0) {
522 if (!__gdbstub_mark_bp(pc + size, 0))
523 goto fault;
524 } else {
525 switch (cur) {
526 /* Bxx (d8,PC) */
527 case 0xc0:
528 case 0xc1:
529 case 0xc2:
530 case 0xc3:
531 case 0xc4:
532 case 0xc5:
533 case 0xc6:
534 case 0xc7:
535 case 0xc8:
536 case 0xc9:
537 case 0xca:
538 if (gdbstub_read_byte(pc + 1, (u8 *) &x) < 0)
539 goto fault;
540 if (!__gdbstub_mark_bp(pc + 2, 0))
541 goto fault;
542 if ((x < 0 || x > 2) &&
543 !__gdbstub_mark_bp(pc + (s8) x, 1))
544 goto fault;
545 break;
546
547 /* LXX (d8,PC) */
548 case 0xd0:
549 case 0xd1:
550 case 0xd2:
551 case 0xd3:
552 case 0xd4:
553 case 0xd5:
554 case 0xd6:
555 case 0xd7:
556 case 0xd8:
557 case 0xd9:
558 case 0xda:
559 if (!__gdbstub_mark_bp(pc + 1, 0))
560 goto fault;
561 if (regs->pc != regs->lar &&
562 !__gdbstub_mark_bp((u8 *) regs->lar, 1))
563 goto fault;
564 break;
565
566 /* SETLB - loads the next for bytes into the LIR
567 * register */
568 case 0xdb:
569 if (!__gdbstub_mark_bp(pc + 1, 0))
570 goto fault;
571 break;
572
573 /* JMP (d16,PC) or CALL (d16,PC) */
574 case 0xcc:
575 case 0xcd:
576 if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 ||
577 gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0)
578 goto fault;
579 if (!__gdbstub_mark_bp(pc + (s16) x, 0))
580 goto fault;
581 break;
582
583 /* JMP (d32,PC) or CALL (d32,PC) */
584 case 0xdc:
585 case 0xdd:
586 if (gdbstub_read_byte(pc + 1, ((u8 *) &x) + 0) < 0 ||
587 gdbstub_read_byte(pc + 2, ((u8 *) &x) + 1) < 0 ||
588 gdbstub_read_byte(pc + 3, ((u8 *) &x) + 2) < 0 ||
589 gdbstub_read_byte(pc + 4, ((u8 *) &x) + 3) < 0)
590 goto fault;
591 if (!__gdbstub_mark_bp(pc + (s32) x, 0))
592 goto fault;
593 break;
594
595 /* RETF */
596 case 0xde:
597 if (!__gdbstub_mark_bp((u8 *) regs->mdr, 0))
598 goto fault;
599 break;
600
601 /* RET */
602 case 0xdf:
603 if (gdbstub_read_byte(pc + 2, (u8 *) &x) < 0)
604 goto fault;
605 sp += (s8)x;
606 if (gdbstub_read_byte(sp + 0, ((u8 *) &x) + 0) < 0 ||
607 gdbstub_read_byte(sp + 1, ((u8 *) &x) + 1) < 0 ||
608 gdbstub_read_byte(sp + 2, ((u8 *) &x) + 2) < 0 ||
609 gdbstub_read_byte(sp + 3, ((u8 *) &x) + 3) < 0)
610 goto fault;
611 if (!__gdbstub_mark_bp((u8 *) x, 0))
612 goto fault;
613 break;
614
615 case 0xf0:
616 if (gdbstub_read_byte(pc + 1, &cur) < 0)
617 goto fault;
618
619 if (cur >= 0xf0 && cur <= 0xf7) {
620 /* JMP (An) / CALLS (An) */
621 switch (cur & 3) {
622 case 0: x = regs->a0; break;
623 case 1: x = regs->a1; break;
624 case 2: x = regs->a2; break;
625 case 3: x = regs->a3; break;
626 }
627 if (!__gdbstub_mark_bp((u8 *) x, 0))
628 goto fault;
629 } else if (cur == 0xfc) {
630 /* RETS */
631 if (gdbstub_read_byte(
632 sp + 0, ((u8 *) &x) + 0) < 0 ||
633 gdbstub_read_byte(
634 sp + 1, ((u8 *) &x) + 1) < 0 ||
635 gdbstub_read_byte(
636 sp + 2, ((u8 *) &x) + 2) < 0 ||
637 gdbstub_read_byte(
638 sp + 3, ((u8 *) &x) + 3) < 0)
639 goto fault;
640 if (!__gdbstub_mark_bp((u8 *) x, 0))
641 goto fault;
642 } else if (cur == 0xfd) {
643 /* RTI */
644 if (gdbstub_read_byte(
645 sp + 4, ((u8 *) &x) + 0) < 0 ||
646 gdbstub_read_byte(
647 sp + 5, ((u8 *) &x) + 1) < 0 ||
648 gdbstub_read_byte(
649 sp + 6, ((u8 *) &x) + 2) < 0 ||
650 gdbstub_read_byte(
651 sp + 7, ((u8 *) &x) + 3) < 0)
652 goto fault;
653 if (!__gdbstub_mark_bp((u8 *) x, 0))
654 goto fault;
655 } else {
656 if (!__gdbstub_mark_bp(pc + 2, 0))
657 goto fault;
658 }
659
660 break;
661
662 /* potential 3-byte conditional branches */
663 case 0xf8:
664 if (gdbstub_read_byte(pc + 1, &cur) < 0)
665 goto fault;
666 if (!__gdbstub_mark_bp(pc + 3, 0))
667 goto fault;
668
669 if (cur >= 0xe8 && cur <= 0xeb) {
670 if (gdbstub_read_byte(
671 pc + 2, ((u8 *) &x) + 0) < 0)
672 goto fault;
673 if ((x < 0 || x > 3) &&
674 !__gdbstub_mark_bp(pc + (s8) x, 1))
675 goto fault;
676 }
677 break;
678
679 case 0xfa:
680 if (gdbstub_read_byte(pc + 1, &cur) < 0)
681 goto fault;
682
683 if (cur == 0xff) {
684 /* CALLS (d16,PC) */
685 if (gdbstub_read_byte(
686 pc + 2, ((u8 *) &x) + 0) < 0 ||
687 gdbstub_read_byte(
688 pc + 3, ((u8 *) &x) + 1) < 0)
689 goto fault;
690 if (!__gdbstub_mark_bp(pc + (s16) x, 0))
691 goto fault;
692 } else {
693 if (!__gdbstub_mark_bp(pc + 4, 0))
694 goto fault;
695 }
696 break;
697
698 case 0xfc:
699 if (gdbstub_read_byte(pc + 1, &cur) < 0)
700 goto fault;
701 if (cur == 0xff) {
702 /* CALLS (d32,PC) */
703 if (gdbstub_read_byte(
704 pc + 2, ((u8 *) &x) + 0) < 0 ||
705 gdbstub_read_byte(
706 pc + 3, ((u8 *) &x) + 1) < 0 ||
707 gdbstub_read_byte(
708 pc + 4, ((u8 *) &x) + 2) < 0 ||
709 gdbstub_read_byte(
710 pc + 5, ((u8 *) &x) + 3) < 0)
711 goto fault;
712 if (!__gdbstub_mark_bp(
713 pc + (s32) x, 0))
714 goto fault;
715 } else {
716 if (!__gdbstub_mark_bp(
717 pc + 6, 0))
718 goto fault;
719 }
720 break;
721
722 }
723 }
724
725 gdbstub_bkpt("Step: %02x at %p; %02x at %p\n",
726 step_bp[0].opcode[0], step_bp[0].addr,
727 step_bp[1].opcode[0], step_bp[1].addr);
728
729 if (step_bp[0].addr) {
730#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
731 if (gdbstub_write_byte(0xF7, step_bp[0].addr + 0) < 0 ||
732 gdbstub_write_byte(0xF7, step_bp[0].addr + 1) < 0)
733 goto fault;
734#else
735 if (gdbstub_write_byte(0xFF, step_bp[0].addr + 0) < 0)
736 goto fault;
737#endif
738 }
739
740 if (step_bp[1].addr) {
741#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
742 if (gdbstub_write_byte(0xF7, step_bp[1].addr + 0) < 0 ||
743 gdbstub_write_byte(0xF7, step_bp[1].addr + 1) < 0)
744 goto fault;
745#else
746 if (gdbstub_write_byte(0xFF, step_bp[1].addr + 0) < 0)
747 goto fault;
748#endif
749 }
750
751 return 0;
752
753 fault:
754 /* uh-oh - silly address alert, try and restore things */
755 __gdbstub_restore_bp();
756 return -EFAULT;
757}
758
759#ifdef CONFIG_GDBSTUB_CONSOLE
760
761void gdbstub_console_write(struct console *con, const char *p, unsigned n)
762{
763 static const char gdbstub_cr[] = { 0x0d };
764 char outbuf[26];
765 int qty;
766 u8 busy;
767
768 busy = gdbstub_busy;
769 gdbstub_busy = 1;
770
771 outbuf[0] = 'O';
772
773 while (n > 0) {
774 qty = 1;
775
776 while (n > 0 && qty < 20) {
777 mem2hex(p, outbuf + qty, 2, 0);
778 qty += 2;
779 if (*p == 0x0a) {
780 mem2hex(gdbstub_cr, outbuf + qty, 2, 0);
781 qty += 2;
782 }
783 p++;
784 n--;
785 }
786
787 outbuf[qty] = 0;
788 putpacket(outbuf);
789 }
790
791 gdbstub_busy = busy;
792}
793
794static kdev_t gdbstub_console_dev(struct console *con)
795{
796 return MKDEV(1, 3); /* /dev/null */
797}
798
799static struct console gdbstub_console = {
800 .name = "gdb",
801 .write = gdbstub_console_write,
802 .device = gdbstub_console_dev,
803 .flags = CON_PRINTBUFFER,
804 .index = -1,
805};
806
807#endif
808
809/*
810 * Convert the memory pointed to by mem into hex, placing result in buf.
811 * - if successful, return a pointer to the last char put in buf (NUL)
812 * - in case of mem fault, return NULL
813 * may_fault is non-zero if we are reading from arbitrary memory, but is
814 * currently not used.
815 */
816static
817unsigned char *mem2hex(const void *_mem, char *buf, int count, int may_fault)
818{
819 const u8 *mem = _mem;
820 u8 ch[4];
821
822 if ((u32) mem & 1 && count >= 1) {
823 if (gdbstub_read_byte(mem, ch) != 0)
824 return 0;
825 *buf++ = hexchars[ch[0] >> 4];
826 *buf++ = hexchars[ch[0] & 0xf];
827 mem++;
828 count--;
829 }
830
831 if ((u32) mem & 3 && count >= 2) {
832 if (gdbstub_read_word(mem, ch) != 0)
833 return 0;
834 *buf++ = hexchars[ch[0] >> 4];
835 *buf++ = hexchars[ch[0] & 0xf];
836 *buf++ = hexchars[ch[1] >> 4];
837 *buf++ = hexchars[ch[1] & 0xf];
838 mem += 2;
839 count -= 2;
840 }
841
842 while (count >= 4) {
843 if (gdbstub_read_dword(mem, ch) != 0)
844 return 0;
845 *buf++ = hexchars[ch[0] >> 4];
846 *buf++ = hexchars[ch[0] & 0xf];
847 *buf++ = hexchars[ch[1] >> 4];
848 *buf++ = hexchars[ch[1] & 0xf];
849 *buf++ = hexchars[ch[2] >> 4];
850 *buf++ = hexchars[ch[2] & 0xf];
851 *buf++ = hexchars[ch[3] >> 4];
852 *buf++ = hexchars[ch[3] & 0xf];
853 mem += 4;
854 count -= 4;
855 }
856
857 if (count >= 2) {
858 if (gdbstub_read_word(mem, ch) != 0)
859 return 0;
860 *buf++ = hexchars[ch[0] >> 4];
861 *buf++ = hexchars[ch[0] & 0xf];
862 *buf++ = hexchars[ch[1] >> 4];
863 *buf++ = hexchars[ch[1] & 0xf];
864 mem += 2;
865 count -= 2;
866 }
867
868 if (count >= 1) {
869 if (gdbstub_read_byte(mem, ch) != 0)
870 return 0;
871 *buf++ = hexchars[ch[0] >> 4];
872 *buf++ = hexchars[ch[0] & 0xf];
873 }
874
875 *buf = 0;
876 return buf;
877}
878
879/*
880 * convert the hex array pointed to by buf into binary to be placed in mem
881 * return a pointer to the character AFTER the last byte written
882 * may_fault is non-zero if we are reading from arbitrary memory, but is
883 * currently not used.
884 */
885static
886const char *hex2mem(const char *buf, void *_mem, int count, int may_fault)
887{
888 u8 *mem = _mem;
889 union {
890 u32 val;
891 u8 b[4];
892 } ch;
893
894 if ((u32) mem & 1 && count >= 1) {
895 ch.b[0] = hex(*buf++) << 4;
896 ch.b[0] |= hex(*buf++);
897 if (gdbstub_write_byte(ch.val, mem) != 0)
898 return 0;
899 mem++;
900 count--;
901 }
902
903 if ((u32) mem & 3 && count >= 2) {
904 ch.b[0] = hex(*buf++) << 4;
905 ch.b[0] |= hex(*buf++);
906 ch.b[1] = hex(*buf++) << 4;
907 ch.b[1] |= hex(*buf++);
908 if (gdbstub_write_word(ch.val, mem) != 0)
909 return 0;
910 mem += 2;
911 count -= 2;
912 }
913
914 while (count >= 4) {
915 ch.b[0] = hex(*buf++) << 4;
916 ch.b[0] |= hex(*buf++);
917 ch.b[1] = hex(*buf++) << 4;
918 ch.b[1] |= hex(*buf++);
919 ch.b[2] = hex(*buf++) << 4;
920 ch.b[2] |= hex(*buf++);
921 ch.b[3] = hex(*buf++) << 4;
922 ch.b[3] |= hex(*buf++);
923 if (gdbstub_write_dword(ch.val, mem) != 0)
924 return 0;
925 mem += 4;
926 count -= 4;
927 }
928
929 if (count >= 2) {
930 ch.b[0] = hex(*buf++) << 4;
931 ch.b[0] |= hex(*buf++);
932 ch.b[1] = hex(*buf++) << 4;
933 ch.b[1] |= hex(*buf++);
934 if (gdbstub_write_word(ch.val, mem) != 0)
935 return 0;
936 mem += 2;
937 count -= 2;
938 }
939
940 if (count >= 1) {
941 ch.b[0] = hex(*buf++) << 4;
942 ch.b[0] |= hex(*buf++);
943 if (gdbstub_write_byte(ch.val, mem) != 0)
944 return 0;
945 }
946
947 return buf;
948}
949
950/*
951 * This table contains the mapping between MN10300 exception codes, and
952 * signals, which are primarily what GDB understands. It also indicates
953 * which hardware traps we need to commandeer when initializing the stub.
954 */
955static const struct excep_to_sig_map {
956 enum exception_code excep; /* MN10300 exception code */
957 unsigned char signo; /* Signal that we map this into */
958} excep_to_sig_map[] = {
959 { EXCEP_ITLBMISS, SIGSEGV },
960 { EXCEP_DTLBMISS, SIGSEGV },
961 { EXCEP_TRAP, SIGTRAP },
962 { EXCEP_ISTEP, SIGTRAP },
963 { EXCEP_IBREAK, SIGTRAP },
964 { EXCEP_OBREAK, SIGTRAP },
965 { EXCEP_UNIMPINS, SIGILL },
966 { EXCEP_UNIMPEXINS, SIGILL },
967 { EXCEP_MEMERR, SIGSEGV },
968 { EXCEP_MISALIGN, SIGSEGV },
969 { EXCEP_BUSERROR, SIGBUS },
970 { EXCEP_ILLINSACC, SIGSEGV },
971 { EXCEP_ILLDATACC, SIGSEGV },
972 { EXCEP_IOINSACC, SIGSEGV },
973 { EXCEP_PRIVINSACC, SIGSEGV },
974 { EXCEP_PRIVDATACC, SIGSEGV },
975 { EXCEP_FPU_DISABLED, SIGFPE },
976 { EXCEP_FPU_UNIMPINS, SIGFPE },
977 { EXCEP_FPU_OPERATION, SIGFPE },
978 { EXCEP_WDT, SIGALRM },
979 { EXCEP_NMI, SIGQUIT },
980 { EXCEP_IRQ_LEVEL0, SIGINT },
981 { EXCEP_IRQ_LEVEL1, SIGINT },
982 { EXCEP_IRQ_LEVEL2, SIGINT },
983 { EXCEP_IRQ_LEVEL3, SIGINT },
984 { EXCEP_IRQ_LEVEL4, SIGINT },
985 { EXCEP_IRQ_LEVEL5, SIGINT },
986 { EXCEP_IRQ_LEVEL6, SIGINT },
987 { 0, 0}
988};
989
990/*
991 * convert the MN10300 exception code into a UNIX signal number
992 */
993static int computeSignal(enum exception_code excep)
994{
995 const struct excep_to_sig_map *map;
996
997 for (map = excep_to_sig_map; map->signo; map++)
998 if (map->excep == excep)
999 return map->signo;
1000
1001 return SIGHUP; /* default for things we don't know about */
1002}
1003
1004static u32 gdbstub_fpcr, gdbstub_fpufs_array[32];
1005
1006/*
1007 *
1008 */
1009static void gdbstub_store_fpu(void)
1010{
1011#ifdef CONFIG_FPU
1012
1013 asm volatile(
1014 "or %2,epsw\n"
1015#ifdef CONFIG_MN10300_PROC_MN103E010
1016 "nop\n"
1017 "nop\n"
1018#endif
1019 "mov %1, a1\n"
1020 "fmov fs0, (a1+)\n"
1021 "fmov fs1, (a1+)\n"
1022 "fmov fs2, (a1+)\n"
1023 "fmov fs3, (a1+)\n"
1024 "fmov fs4, (a1+)\n"
1025 "fmov fs5, (a1+)\n"
1026 "fmov fs6, (a1+)\n"
1027 "fmov fs7, (a1+)\n"
1028 "fmov fs8, (a1+)\n"
1029 "fmov fs9, (a1+)\n"
1030 "fmov fs10, (a1+)\n"
1031 "fmov fs11, (a1+)\n"
1032 "fmov fs12, (a1+)\n"
1033 "fmov fs13, (a1+)\n"
1034 "fmov fs14, (a1+)\n"
1035 "fmov fs15, (a1+)\n"
1036 "fmov fs16, (a1+)\n"
1037 "fmov fs17, (a1+)\n"
1038 "fmov fs18, (a1+)\n"
1039 "fmov fs19, (a1+)\n"
1040 "fmov fs20, (a1+)\n"
1041 "fmov fs21, (a1+)\n"
1042 "fmov fs22, (a1+)\n"
1043 "fmov fs23, (a1+)\n"
1044 "fmov fs24, (a1+)\n"
1045 "fmov fs25, (a1+)\n"
1046 "fmov fs26, (a1+)\n"
1047 "fmov fs27, (a1+)\n"
1048 "fmov fs28, (a1+)\n"
1049 "fmov fs29, (a1+)\n"
1050 "fmov fs30, (a1+)\n"
1051 "fmov fs31, (a1+)\n"
1052 "fmov fpcr, %0\n"
1053 : "=d"(gdbstub_fpcr)
1054 : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE)
1055 : "a1"
1056 );
1057#endif
1058}
1059
1060/*
1061 *
1062 */
1063static void gdbstub_load_fpu(void)
1064{
1065#ifdef CONFIG_FPU
1066
1067 asm volatile(
1068 "or %1,epsw\n"
1069#ifdef CONFIG_MN10300_PROC_MN103E010
1070 "nop\n"
1071 "nop\n"
1072#endif
1073 "mov %0, a1\n"
1074 "fmov (a1+), fs0\n"
1075 "fmov (a1+), fs1\n"
1076 "fmov (a1+), fs2\n"
1077 "fmov (a1+), fs3\n"
1078 "fmov (a1+), fs4\n"
1079 "fmov (a1+), fs5\n"
1080 "fmov (a1+), fs6\n"
1081 "fmov (a1+), fs7\n"
1082 "fmov (a1+), fs8\n"
1083 "fmov (a1+), fs9\n"
1084 "fmov (a1+), fs10\n"
1085 "fmov (a1+), fs11\n"
1086 "fmov (a1+), fs12\n"
1087 "fmov (a1+), fs13\n"
1088 "fmov (a1+), fs14\n"
1089 "fmov (a1+), fs15\n"
1090 "fmov (a1+), fs16\n"
1091 "fmov (a1+), fs17\n"
1092 "fmov (a1+), fs18\n"
1093 "fmov (a1+), fs19\n"
1094 "fmov (a1+), fs20\n"
1095 "fmov (a1+), fs21\n"
1096 "fmov (a1+), fs22\n"
1097 "fmov (a1+), fs23\n"
1098 "fmov (a1+), fs24\n"
1099 "fmov (a1+), fs25\n"
1100 "fmov (a1+), fs26\n"
1101 "fmov (a1+), fs27\n"
1102 "fmov (a1+), fs28\n"
1103 "fmov (a1+), fs29\n"
1104 "fmov (a1+), fs30\n"
1105 "fmov (a1+), fs31\n"
1106 "fmov %2, fpcr\n"
1107 :
1108 : "g" (&gdbstub_fpufs_array), "i"(EPSW_FE), "d"(gdbstub_fpcr)
1109 : "a1"
1110 );
1111#endif
1112}
1113
1114/*
1115 * set a software breakpoint
1116 */
1117int gdbstub_set_breakpoint(u8 *addr, int len)
1118{
1119 int bkpt, loop, xloop;
1120
1121#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
1122 len = (len + 1) & ~1;
1123#endif
1124
1125 gdbstub_bkpt("setbkpt(%p,%d)\n", addr, len);
1126
1127 for (bkpt = 255; bkpt >= 0; bkpt--)
1128 if (!gdbstub_bkpts[bkpt].addr)
1129 break;
1130 if (bkpt < 0)
1131 return -ENOSPC;
1132
1133 for (loop = 0; loop < len; loop++)
1134 if (gdbstub_read_byte(&addr[loop],
1135 &gdbstub_bkpts[bkpt].origbytes[loop]
1136 ) < 0)
1137 return -EFAULT;
1138
1139 gdbstub_flush_caches = 1;
1140
1141#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
1142 for (loop = 0; loop < len; loop++)
1143 if (gdbstub_write_byte(0xF7, &addr[loop]) < 0)
1144 goto restore;
1145#else
1146 for (loop = 0; loop < len; loop++)
1147 if (gdbstub_write_byte(0xFF, &addr[loop]) < 0)
1148 goto restore;
1149#endif
1150
1151 gdbstub_bkpts[bkpt].addr = addr;
1152 gdbstub_bkpts[bkpt].len = len;
1153
1154 gdbstub_bkpt("Set BKPT[%02x]: %p-%p {%02x%02x%02x%02x%02x%02x%02x}\n",
1155 bkpt,
1156 gdbstub_bkpts[bkpt].addr,
1157 gdbstub_bkpts[bkpt].addr + gdbstub_bkpts[bkpt].len - 1,
1158 gdbstub_bkpts[bkpt].origbytes[0],
1159 gdbstub_bkpts[bkpt].origbytes[1],
1160 gdbstub_bkpts[bkpt].origbytes[2],
1161 gdbstub_bkpts[bkpt].origbytes[3],
1162 gdbstub_bkpts[bkpt].origbytes[4],
1163 gdbstub_bkpts[bkpt].origbytes[5],
1164 gdbstub_bkpts[bkpt].origbytes[6]
1165 );
1166
1167 return 0;
1168
1169restore:
1170 for (xloop = 0; xloop < loop; xloop++)
1171 gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[xloop],
1172 addr + xloop);
1173 return -EFAULT;
1174}
1175
1176/*
1177 * clear a software breakpoint
1178 */
1179int gdbstub_clear_breakpoint(u8 *addr, int len)
1180{
1181 int bkpt, loop;
1182
1183#ifdef GDBSTUB_USE_F7F7_AS_BREAKPOINT
1184 len = (len + 1) & ~1;
1185#endif
1186
1187 gdbstub_bkpt("clearbkpt(%p,%d)\n", addr, len);
1188
1189 for (bkpt = 255; bkpt >= 0; bkpt--)
1190 if (gdbstub_bkpts[bkpt].addr == addr &&
1191 gdbstub_bkpts[bkpt].len == len)
1192 break;
1193 if (bkpt < 0)
1194 return -ENOENT;
1195
1196 gdbstub_bkpts[bkpt].addr = NULL;
1197
1198 gdbstub_flush_caches = 1;
1199
1200 for (loop = 0; loop < len; loop++)
1201 if (gdbstub_write_byte(gdbstub_bkpts[bkpt].origbytes[loop],
1202 addr + loop) < 0)
1203 return -EFAULT;
1204
1205 return 0;
1206}
1207
1208/*
1209 * This function does all command processing for interfacing to gdb
1210 * - returns 1 if the exception should be skipped, 0 otherwise.
1211 */
1212static int gdbstub(struct pt_regs *regs, enum exception_code excep)
1213{
1214 unsigned long *stack;
1215 unsigned long epsw, mdr;
1216 uint32_t zero, ssp;
1217 uint8_t broke;
1218 char *ptr;
1219 int sigval;
1220 int addr;
1221 int length;
1222 int loop;
1223
1224 if (excep == EXCEP_FPU_DISABLED)
1225 return 0;
1226
1227 gdbstub_flush_caches = 0;
1228
1229 mn10300_set_gdbleds(1);
1230
1231 asm volatile("mov mdr,%0" : "=d"(mdr));
1232 asm volatile("mov epsw,%0" : "=d"(epsw));
1233 asm volatile("mov %0,epsw"
1234 :: "d"((epsw & ~EPSW_IM) | EPSW_IE | EPSW_IM_1));
1235
1236 gdbstub_store_fpu();
1237
1238#ifdef CONFIG_GDBSTUB_IMMEDIATE
1239 /* skip the initial pause loop */
1240 if (regs->pc == (unsigned long) __gdbstub_pause)
1241 regs->pc = (unsigned long) start_kernel;
1242#endif
1243
1244 /* if we were single stepping, restore the opcodes hoisted for the
1245 * breakpoint[s] */
1246 broke = 0;
1247 if ((step_bp[0].addr && step_bp[0].addr == (u8 *) regs->pc) ||
1248 (step_bp[1].addr && step_bp[1].addr == (u8 *) regs->pc))
1249 broke = 1;
1250
1251 __gdbstub_restore_bp();
1252
1253 if (gdbstub_rx_unget) {
1254 sigval = SIGINT;
1255 if (gdbstub_rx_unget != 3)
1256 goto packet_waiting;
1257 gdbstub_rx_unget = 0;
1258 }
1259
1260 stack = (unsigned long *) regs->sp;
1261 sigval = broke ? SIGTRAP : computeSignal(excep);
1262
1263 /* send information about a BUG() */
1264 if (!user_mode(regs) && excep == EXCEP_SYSCALL15) {
1265 const struct bug_entry *bug;
1266
1267 bug = find_bug(regs->pc);
1268 if (bug)
1269 goto found_bug;
1270 length = snprintf(trans_buffer, sizeof(trans_buffer),
1271 "BUG() at address %lx\n", regs->pc);
1272 goto send_bug_pkt;
1273
1274 found_bug:
1275 length = snprintf(trans_buffer, sizeof(trans_buffer),
1276 "BUG() at address %lx (%s:%d)\n",
1277 regs->pc, bug->file, bug->line);
1278
1279 send_bug_pkt:
1280 ptr = output_buffer;
1281 *ptr++ = 'O';
1282 ptr = mem2hex(trans_buffer, ptr, length, 0);
1283 *ptr = 0;
1284 putpacket(output_buffer);
1285
1286 regs->pc -= 2;
1287 sigval = SIGABRT;
1288 } else if (regs->pc == (unsigned long) __gdbstub_bug_trap) {
1289 regs->pc = regs->mdr;
1290 sigval = SIGABRT;
1291 }
1292
1293 /*
1294 * send a message to the debugger's user saying what happened if it may
1295 * not be clear cut (we can't map exceptions onto signals properly)
1296 */
1297 if (sigval != SIGINT && sigval != SIGTRAP && sigval != SIGILL) {
1298 static const char title[] = "Excep ", tbcberr[] = "BCBERR ";
1299 static const char crlf[] = "\r\n";
1300 char hx;
1301 u32 bcberr = BCBERR;
1302
1303 ptr = output_buffer;
1304 *ptr++ = 'O';
1305 ptr = mem2hex(title, ptr, sizeof(title) - 1, 0);
1306
1307 hx = hexchars[(excep & 0xf000) >> 12];
1308 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1309 hx = hexchars[(excep & 0x0f00) >> 8];
1310 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1311 hx = hexchars[(excep & 0x00f0) >> 4];
1312 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1313 hx = hexchars[(excep & 0x000f)];
1314 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1315
1316 ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0);
1317 *ptr = 0;
1318 putpacket(output_buffer); /* send it off... */
1319
1320 /* BCBERR */
1321 ptr = output_buffer;
1322 *ptr++ = 'O';
1323 ptr = mem2hex(tbcberr, ptr, sizeof(tbcberr) - 1, 0);
1324
1325 hx = hexchars[(bcberr & 0xf0000000) >> 28];
1326 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1327 hx = hexchars[(bcberr & 0x0f000000) >> 24];
1328 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1329 hx = hexchars[(bcberr & 0x00f00000) >> 20];
1330 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1331 hx = hexchars[(bcberr & 0x000f0000) >> 16];
1332 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1333 hx = hexchars[(bcberr & 0x0000f000) >> 12];
1334 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1335 hx = hexchars[(bcberr & 0x00000f00) >> 8];
1336 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1337 hx = hexchars[(bcberr & 0x000000f0) >> 4];
1338 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1339 hx = hexchars[(bcberr & 0x0000000f)];
1340 *ptr++ = hexchars[hx >> 4]; *ptr++ = hexchars[hx & 0xf];
1341
1342 ptr = mem2hex(crlf, ptr, sizeof(crlf) - 1, 0);
1343 *ptr = 0;
1344 putpacket(output_buffer); /* send it off... */
1345 }
1346
1347 /*
1348 * tell the debugger that an exception has occurred
1349 */
1350 ptr = output_buffer;
1351
1352 /*
1353 * Send trap type (converted to signal)
1354 */
1355 *ptr++ = 'T';
1356 *ptr++ = hexchars[sigval >> 4];
1357 *ptr++ = hexchars[sigval & 0xf];
1358
1359 /*
1360 * Send Error PC
1361 */
1362 *ptr++ = hexchars[GDB_REGID_PC >> 4];
1363 *ptr++ = hexchars[GDB_REGID_PC & 0xf];
1364 *ptr++ = ':';
1365 ptr = mem2hex(&regs->pc, ptr, 4, 0);
1366 *ptr++ = ';';
1367
1368 /*
1369 * Send frame pointer
1370 */
1371 *ptr++ = hexchars[GDB_REGID_FP >> 4];
1372 *ptr++ = hexchars[GDB_REGID_FP & 0xf];
1373 *ptr++ = ':';
1374 ptr = mem2hex(&regs->a3, ptr, 4, 0);
1375 *ptr++ = ';';
1376
1377 /*
1378 * Send stack pointer
1379 */
1380 ssp = (unsigned long) (regs + 1);
1381 *ptr++ = hexchars[GDB_REGID_SP >> 4];
1382 *ptr++ = hexchars[GDB_REGID_SP & 0xf];
1383 *ptr++ = ':';
1384 ptr = mem2hex(&ssp, ptr, 4, 0);
1385 *ptr++ = ';';
1386
1387 *ptr++ = 0;
1388 putpacket(output_buffer); /* send it off... */
1389
1390packet_waiting:
1391 /*
1392 * Wait for input from remote GDB
1393 */
1394 while (1) {
1395 output_buffer[0] = 0;
1396 getpacket(input_buffer);
1397
1398 switch (input_buffer[0]) {
1399 /* request repeat of last signal number */
1400 case '?':
1401 output_buffer[0] = 'S';
1402 output_buffer[1] = hexchars[sigval >> 4];
1403 output_buffer[2] = hexchars[sigval & 0xf];
1404 output_buffer[3] = 0;
1405 break;
1406
1407 case 'd':
1408 /* toggle debug flag */
1409 break;
1410
1411 /*
1412 * Return the value of the CPU registers
1413 */
1414 case 'g':
1415 zero = 0;
1416 ssp = (u32) (regs + 1);
1417 ptr = output_buffer;
1418 ptr = mem2hex(&regs->d0, ptr, 4, 0);
1419 ptr = mem2hex(&regs->d1, ptr, 4, 0);
1420 ptr = mem2hex(&regs->d2, ptr, 4, 0);
1421 ptr = mem2hex(&regs->d3, ptr, 4, 0);
1422 ptr = mem2hex(&regs->a0, ptr, 4, 0);
1423 ptr = mem2hex(&regs->a1, ptr, 4, 0);
1424 ptr = mem2hex(&regs->a2, ptr, 4, 0);
1425 ptr = mem2hex(&regs->a3, ptr, 4, 0);
1426
1427 ptr = mem2hex(&ssp, ptr, 4, 0); /* 8 */
1428 ptr = mem2hex(&regs->pc, ptr, 4, 0);
1429 ptr = mem2hex(&regs->mdr, ptr, 4, 0);
1430 ptr = mem2hex(&regs->epsw, ptr, 4, 0);
1431 ptr = mem2hex(&regs->lir, ptr, 4, 0);
1432 ptr = mem2hex(&regs->lar, ptr, 4, 0);
1433 ptr = mem2hex(&regs->mdrq, ptr, 4, 0);
1434
1435 ptr = mem2hex(&regs->e0, ptr, 4, 0); /* 15 */
1436 ptr = mem2hex(&regs->e1, ptr, 4, 0);
1437 ptr = mem2hex(&regs->e2, ptr, 4, 0);
1438 ptr = mem2hex(&regs->e3, ptr, 4, 0);
1439 ptr = mem2hex(&regs->e4, ptr, 4, 0);
1440 ptr = mem2hex(&regs->e5, ptr, 4, 0);
1441 ptr = mem2hex(&regs->e6, ptr, 4, 0);
1442 ptr = mem2hex(&regs->e7, ptr, 4, 0);
1443
1444 ptr = mem2hex(&ssp, ptr, 4, 0);
1445 ptr = mem2hex(&regs, ptr, 4, 0);
1446 ptr = mem2hex(&regs->sp, ptr, 4, 0);
1447 ptr = mem2hex(&regs->mcrh, ptr, 4, 0); /* 26 */
1448 ptr = mem2hex(&regs->mcrl, ptr, 4, 0);
1449 ptr = mem2hex(&regs->mcvf, ptr, 4, 0);
1450
1451 ptr = mem2hex(&gdbstub_fpcr, ptr, 4, 0); /* 29 - FPCR */
1452 ptr = mem2hex(&zero, ptr, 4, 0);
1453 ptr = mem2hex(&zero, ptr, 4, 0);
1454 for (loop = 0; loop < 32; loop++)
1455 ptr = mem2hex(&gdbstub_fpufs_array[loop],
1456 ptr, 4, 0); /* 32 - FS0-31 */
1457
1458 break;
1459
1460 /*
1461 * set the value of the CPU registers - return OK
1462 */
1463 case 'G':
1464 {
1465 const char *ptr;
1466
1467 ptr = &input_buffer[1];
1468 ptr = hex2mem(ptr, &regs->d0, 4, 0);
1469 ptr = hex2mem(ptr, &regs->d1, 4, 0);
1470 ptr = hex2mem(ptr, &regs->d2, 4, 0);
1471 ptr = hex2mem(ptr, &regs->d3, 4, 0);
1472 ptr = hex2mem(ptr, &regs->a0, 4, 0);
1473 ptr = hex2mem(ptr, &regs->a1, 4, 0);
1474 ptr = hex2mem(ptr, &regs->a2, 4, 0);
1475 ptr = hex2mem(ptr, &regs->a3, 4, 0);
1476
1477 ptr = hex2mem(ptr, &ssp, 4, 0); /* 8 */
1478 ptr = hex2mem(ptr, &regs->pc, 4, 0);
1479 ptr = hex2mem(ptr, &regs->mdr, 4, 0);
1480 ptr = hex2mem(ptr, &regs->epsw, 4, 0);
1481 ptr = hex2mem(ptr, &regs->lir, 4, 0);
1482 ptr = hex2mem(ptr, &regs->lar, 4, 0);
1483 ptr = hex2mem(ptr, &regs->mdrq, 4, 0);
1484
1485 ptr = hex2mem(ptr, &regs->e0, 4, 0); /* 15 */
1486 ptr = hex2mem(ptr, &regs->e1, 4, 0);
1487 ptr = hex2mem(ptr, &regs->e2, 4, 0);
1488 ptr = hex2mem(ptr, &regs->e3, 4, 0);
1489 ptr = hex2mem(ptr, &regs->e4, 4, 0);
1490 ptr = hex2mem(ptr, &regs->e5, 4, 0);
1491 ptr = hex2mem(ptr, &regs->e6, 4, 0);
1492 ptr = hex2mem(ptr, &regs->e7, 4, 0);
1493
1494 ptr = hex2mem(ptr, &ssp, 4, 0);
1495 ptr = hex2mem(ptr, &zero, 4, 0);
1496 ptr = hex2mem(ptr, &regs->sp, 4, 0);
1497 ptr = hex2mem(ptr, &regs->mcrh, 4, 0); /* 26 */
1498 ptr = hex2mem(ptr, &regs->mcrl, 4, 0);
1499 ptr = hex2mem(ptr, &regs->mcvf, 4, 0);
1500
1501 ptr = hex2mem(ptr, &zero, 4, 0); /* 29 - FPCR */
1502 ptr = hex2mem(ptr, &zero, 4, 0);
1503 ptr = hex2mem(ptr, &zero, 4, 0);
1504 for (loop = 0; loop < 32; loop++) /* 32 - FS0-31 */
1505 ptr = hex2mem(ptr, &zero, 4, 0);
1506
1507#if 0
1508 /*
1509 * See if the stack pointer has moved. If so, then copy
1510 * the saved locals and ins to the new location.
1511 */
1512 unsigned long *newsp = (unsigned long *) registers[SP];
1513 if (sp != newsp)
1514 sp = memcpy(newsp, sp, 16 * 4);
1515#endif
1516
1517 gdbstub_strcpy(output_buffer, "OK");
1518 }
1519 break;
1520
1521 /*
1522 * mAA..AA,LLLL Read LLLL bytes at address AA..AA
1523 */
1524 case 'm':
1525 ptr = &input_buffer[1];
1526
1527 if (hexToInt(&ptr, &addr) &&
1528 *ptr++ == ',' &&
1529 hexToInt(&ptr, &length)
1530 ) {
1531 if (mem2hex((char *) addr, output_buffer,
1532 length, 1))
1533 break;
1534 gdbstub_strcpy(output_buffer, "E03");
1535 } else {
1536 gdbstub_strcpy(output_buffer, "E01");
1537 }
1538 break;
1539
1540 /*
1541 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA
1542 * return OK
1543 */
1544 case 'M':
1545 ptr = &input_buffer[1];
1546
1547 if (hexToInt(&ptr, &addr) &&
1548 *ptr++ == ',' &&
1549 hexToInt(&ptr, &length) &&
1550 *ptr++ == ':'
1551 ) {
1552 if (hex2mem(ptr, (char *) addr, length, 1))
1553 gdbstub_strcpy(output_buffer, "OK");
1554 else
1555 gdbstub_strcpy(output_buffer, "E03");
1556
1557 gdbstub_flush_caches = 1;
1558 } else {
1559 gdbstub_strcpy(output_buffer, "E02");
1560 }
1561 break;
1562
1563 /*
1564 * cAA..AA Continue at address AA..AA(optional)
1565 */
1566 case 'c':
1567 /* try to read optional parameter, pc unchanged if no
1568 * parm */
1569
1570 ptr = &input_buffer[1];
1571 if (hexToInt(&ptr, &addr))
1572 regs->pc = addr;
1573 goto done;
1574
1575 /*
1576 * kill the program
1577 */
1578 case 'k' :
1579 goto done; /* just continue */
1580
1581 /*
1582 * Reset the whole machine (FIXME: system dependent)
1583 */
1584 case 'r':
1585 break;
1586
1587 /*
1588 * Step to next instruction
1589 */
1590 case 's':
1591 /*
1592 * using the T flag doesn't seem to perform single
1593 * stepping (it seems to wind up being caught by the
1594 * JTAG unit), so we have to use breakpoints and
1595 * continue instead.
1596 */
1597 if (gdbstub_single_step(regs) < 0)
1598 /* ignore any fault error for now */
1599 gdbstub_printk("unable to set single-step"
1600 " bp\n");
1601 goto done;
1602
1603 /*
1604 * Set baud rate (bBB)
1605 */
1606 case 'b':
1607 do {
1608 int baudrate;
1609
1610 ptr = &input_buffer[1];
1611 if (!hexToInt(&ptr, &baudrate)) {
1612 gdbstub_strcpy(output_buffer, "B01");
1613 break;
1614 }
1615
1616 if (baudrate) {
1617 /* ACK before changing speed */
1618 putpacket("OK");
1619 gdbstub_io_set_baud(baudrate);
1620 }
1621 } while (0);
1622 break;
1623
1624 /*
1625 * Set breakpoint
1626 */
1627 case 'Z':
1628 ptr = &input_buffer[1];
1629
1630 if (!hexToInt(&ptr, &loop) || *ptr++ != ',' ||
1631 !hexToInt(&ptr, &addr) || *ptr++ != ',' ||
1632 !hexToInt(&ptr, &length)
1633 ) {
1634 gdbstub_strcpy(output_buffer, "E01");
1635 break;
1636 }
1637
1638 /* only support software breakpoints */
1639 gdbstub_strcpy(output_buffer, "E03");
1640 if (loop != 0 ||
1641 length < 1 ||
1642 length > 7 ||
1643 (unsigned long) addr < 4096)
1644 break;
1645
1646 if (gdbstub_set_breakpoint((u8 *) addr, length) < 0)
1647 break;
1648
1649 gdbstub_strcpy(output_buffer, "OK");
1650 break;
1651
1652 /*
1653 * Clear breakpoint
1654 */
1655 case 'z':
1656 ptr = &input_buffer[1];
1657
1658 if (!hexToInt(&ptr, &loop) || *ptr++ != ',' ||
1659 !hexToInt(&ptr, &addr) || *ptr++ != ',' ||
1660 !hexToInt(&ptr, &length)
1661 ) {
1662 gdbstub_strcpy(output_buffer, "E01");
1663 break;
1664 }
1665
1666 /* only support software breakpoints */
1667 gdbstub_strcpy(output_buffer, "E03");
1668 if (loop != 0 ||
1669 length < 1 ||
1670 length > 7 ||
1671 (unsigned long) addr < 4096)
1672 break;
1673
1674 if (gdbstub_clear_breakpoint((u8 *) addr, length) < 0)
1675 break;
1676
1677 gdbstub_strcpy(output_buffer, "OK");
1678 break;
1679
1680 default:
1681 gdbstub_proto("### GDB Unsupported Cmd '%s'\n",
1682 input_buffer);
1683 break;
1684 }
1685
1686 /* reply to the request */
1687 putpacket(output_buffer);
1688 }
1689
1690done:
1691 /*
1692 * Need to flush the instruction cache here, as we may
1693 * have deposited a breakpoint, and the icache probably
1694 * has no way of knowing that a data ref to some location
1695 * may have changed something that is in the instruction
1696 * cache.
1697 * NB: We flush both caches, just to be sure...
1698 */
1699 if (gdbstub_flush_caches)
1700 gdbstub_purge_cache();
1701
1702 gdbstub_load_fpu();
1703 mn10300_set_gdbleds(0);
1704 if (excep == EXCEP_NMI)
1705 NMICR = NMICR_NMIF;
1706
1707 touch_softlockup_watchdog();
1708
1709 local_irq_restore(epsw);
1710 return 1;
1711}
1712
1713/*
1714 * handle event interception
1715 */
1716asmlinkage int gdbstub_intercept(struct pt_regs *regs,
1717 enum exception_code excep)
1718{
1719 static u8 notfirst = 1;
1720 int ret;
1721
1722 if (gdbstub_busy)
1723 gdbstub_printk("--> gdbstub reentered itself\n");
1724 gdbstub_busy = 1;
1725
1726 if (notfirst) {
1727 unsigned long mdr;
1728 asm("mov mdr,%0" : "=d"(mdr));
1729
1730 gdbstub_entry(
1731 "--> gdbstub_intercept(%p,%04x) [MDR=%lx PC=%lx]\n",
1732 regs, excep, mdr, regs->pc);
1733
1734 gdbstub_entry(
1735 "PC: %08lx EPSW: %08lx SSP: %08lx mode: %s\n",
1736 regs->pc, regs->epsw, (unsigned long) &ret,
1737 user_mode(regs) ? "User" : "Super");
1738 gdbstub_entry(
1739 "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
1740 regs->d0, regs->d1, regs->d2, regs->d3);
1741 gdbstub_entry(
1742 "a0: %08lx a1: %08lx a2: %08lx a3: %08lx\n",
1743 regs->a0, regs->a1, regs->a2, regs->a3);
1744 gdbstub_entry(
1745 "e0: %08lx e1: %08lx e2: %08lx e3: %08lx\n",
1746 regs->e0, regs->e1, regs->e2, regs->e3);
1747 gdbstub_entry(
1748 "e4: %08lx e5: %08lx e6: %08lx e7: %08lx\n",
1749 regs->e4, regs->e5, regs->e6, regs->e7);
1750 gdbstub_entry(
1751 "lar: %08lx lir: %08lx mdr: %08lx usp: %08lx\n",
1752 regs->lar, regs->lir, regs->mdr, regs->sp);
1753 gdbstub_entry(
1754 "cvf: %08lx crl: %08lx crh: %08lx drq: %08lx\n",
1755 regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq);
1756 gdbstub_entry(
1757 "threadinfo=%p task=%p)\n",
1758 current_thread_info(), current);
1759 } else {
1760 notfirst = 1;
1761 }
1762
1763 ret = gdbstub(regs, excep);
1764
1765 gdbstub_entry("<-- gdbstub_intercept()\n");
1766 gdbstub_busy = 0;
1767 return ret;
1768}
1769
1770/*
1771 * handle the GDB stub itself causing an exception
1772 */
1773asmlinkage void gdbstub_exception(struct pt_regs *regs,
1774 enum exception_code excep)
1775{
1776 unsigned long mdr;
1777
1778 asm("mov mdr,%0" : "=d"(mdr));
1779 gdbstub_entry("--> gdbstub exception({%p},%04x) [MDR=%lx]\n",
1780 regs, excep, mdr);
1781
1782 while ((unsigned long) regs == 0xffffffff) {}
1783
1784 /* handle guarded memory accesses where we know it might fault */
1785 if (regs->pc == (unsigned) gdbstub_read_byte_guard) {
1786 regs->pc = (unsigned) gdbstub_read_byte_cont;
1787 goto fault;
1788 }
1789
1790 if (regs->pc == (unsigned) gdbstub_read_word_guard) {
1791 regs->pc = (unsigned) gdbstub_read_word_cont;
1792 goto fault;
1793 }
1794
1795 if (regs->pc == (unsigned) gdbstub_read_dword_guard) {
1796 regs->pc = (unsigned) gdbstub_read_dword_cont;
1797 goto fault;
1798 }
1799
1800 if (regs->pc == (unsigned) gdbstub_write_byte_guard) {
1801 regs->pc = (unsigned) gdbstub_write_byte_cont;
1802 goto fault;
1803 }
1804
1805 if (regs->pc == (unsigned) gdbstub_write_word_guard) {
1806 regs->pc = (unsigned) gdbstub_write_word_cont;
1807 goto fault;
1808 }
1809
1810 if (regs->pc == (unsigned) gdbstub_write_dword_guard) {
1811 regs->pc = (unsigned) gdbstub_write_dword_cont;
1812 goto fault;
1813 }
1814
1815 gdbstub_printk("\n### GDB stub caused an exception ###\n");
1816
1817 /* something went horribly wrong */
1818 console_verbose();
1819 show_registers(regs);
1820
1821 panic("GDB Stub caused an unexpected exception - can't continue\n");
1822
1823 /* we caught an attempt by the stub to access silly memory */
1824fault:
1825 gdbstub_entry("<-- gdbstub exception() = EFAULT\n");
1826 regs->d0 = -EFAULT;
1827 return;
1828}
1829
1830/*
1831 * send an exit message to GDB
1832 */
1833void gdbstub_exit(int status)
1834{
1835 unsigned char checksum;
1836 unsigned char ch;
1837 int count;
1838
1839 gdbstub_busy = 1;
1840 output_buffer[0] = 'W';
1841 output_buffer[1] = hexchars[(status >> 4) & 0x0F];
1842 output_buffer[2] = hexchars[status & 0x0F];
1843 output_buffer[3] = 0;
1844
1845 gdbstub_io_tx_char('$');
1846 checksum = 0;
1847 count = 0;
1848
1849 while ((ch = output_buffer[count]) != 0) {
1850 gdbstub_io_tx_char(ch);
1851 checksum += ch;
1852 count += 1;
1853 }
1854
1855 gdbstub_io_tx_char('#');
1856 gdbstub_io_tx_char(hexchars[checksum >> 4]);
1857 gdbstub_io_tx_char(hexchars[checksum & 0xf]);
1858
1859 /* make sure the output is flushed, or else RedBoot might clobber it */
1860 gdbstub_io_tx_flush();
1861
1862 gdbstub_busy = 0;
1863}
1864
1865/*
1866 * initialise the GDB stub
1867 */
1868asmlinkage void __init gdbstub_init(void)
1869{
1870#ifdef CONFIG_GDBSTUB_IMMEDIATE
1871 unsigned char ch;
1872 int ret;
1873#endif
1874
1875 gdbstub_busy = 1;
1876
1877 printk(KERN_INFO "%s", gdbstub_banner);
1878
1879 gdbstub_io_init();
1880
1881 gdbstub_entry("--> gdbstub_init\n");
1882
1883 /* try to talk to GDB (or anyone insane enough to want to type GDB
1884 * protocol by hand) */
1885 gdbstub_io("### GDB Tx ACK\n");
1886 gdbstub_io_tx_char('+'); /* 'hello world' */
1887
1888#ifdef CONFIG_GDBSTUB_IMMEDIATE
1889 gdbstub_printk("GDB Stub waiting for packet\n");
1890
1891 /* in case GDB is started before us, ACK any packets that are already
1892 * sitting there (presumably "$?#xx")
1893 */
1894 do { gdbstub_io_rx_char(&ch, 0); } while (ch != '$');
1895 do { gdbstub_io_rx_char(&ch, 0); } while (ch != '#');
1896 /* eat first csum byte */
1897 do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0);
1898 /* eat second csum byte */
1899 do { ret = gdbstub_io_rx_char(&ch, 0); } while (ret != 0);
1900
1901 gdbstub_io("### GDB Tx NAK\n");
1902 gdbstub_io_tx_char('-'); /* NAK it */
1903
1904#else
1905 printk("GDB Stub ready\n");
1906#endif
1907
1908 gdbstub_busy = 0;
1909 gdbstub_entry("<-- gdbstub_init\n");
1910}
1911
1912/*
1913 * register the console at a more appropriate time
1914 */
1915#ifdef CONFIG_GDBSTUB_CONSOLE
1916static int __init gdbstub_postinit(void)
1917{
1918 printk(KERN_NOTICE "registering console\n");
1919 register_console(&gdbstub_console);
1920 return 0;
1921}
1922
1923__initcall(gdbstub_postinit);
1924#endif
1925
1926/*
1927 * handle character reception on GDB serial port
1928 * - jump into the GDB stub if BREAK is detected on the serial line
1929 */
1930asmlinkage void gdbstub_rx_irq(struct pt_regs *regs, enum exception_code excep)
1931{
1932 char ch;
1933 int ret;
1934
1935 gdbstub_entry("--> gdbstub_rx_irq\n");
1936
1937 do {
1938 ret = gdbstub_io_rx_char(&ch, 1);
1939 if (ret != -EIO && ret != -EAGAIN) {
1940 if (ret != -EINTR)
1941 gdbstub_rx_unget = ch;
1942 gdbstub(regs, excep);
1943 }
1944 } while (ret != -EAGAIN);
1945
1946 gdbstub_entry("<-- gdbstub_rx_irq\n");
1947}
diff --git a/arch/mn10300/kernel/head.S b/arch/mn10300/kernel/head.S
new file mode 100644
index 000000000000..606bd8c6758d
--- /dev/null
+++ b/arch/mn10300/kernel/head.S
@@ -0,0 +1,255 @@
1/* Boot entry point for MN10300 kernel
2 *
3 * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/threads.h>
13#include <linux/linkage.h>
14#include <linux/serial_reg.h>
15#include <asm/thread_info.h>
16#include <asm/page.h>
17#include <asm/pgtable.h>
18#include <asm/frame.inc>
19#include <asm/param.h>
20#include <asm/unit/serial.h>
21
22 .section .text.head,"ax"
23
24###############################################################################
25#
26# bootloader entry point
27#
28###############################################################################
29 .globl _start
30 .type _start,@function
31_start:
32 # save commandline pointer
33 mov d0,a3
34
35 # preload the PGD pointer register
36 mov swapper_pg_dir,d0
37 mov d0,(PTBR)
38
39 # turn on the TLBs
40 mov MMUCTR_IIV|MMUCTR_DIV,d0
41 mov d0,(MMUCTR)
42 mov MMUCTR_ITE|MMUCTR_DTE|MMUCTR_CE,d0
43 mov d0,(MMUCTR)
44
45 # turn on AM33v2 exception handling mode and set the trap table base
46 movhu (CPUP),d0
47 or CPUP_EXM_AM33V2,d0
48 movhu d0,(CPUP)
49 mov CONFIG_INTERRUPT_VECTOR_BASE,d0
50 mov d0,(TBR)
51
52 # invalidate and enable both of the caches
53 mov CHCTR,a0
54 clr d0
55 movhu d0,(a0) # turn off first
56 mov CHCTR_ICINV|CHCTR_DCINV,d0
57 movhu d0,(a0)
58 setlb
59 mov (a0),d0
60 btst CHCTR_ICBUSY|CHCTR_DCBUSY,d0 # wait till not busy
61 lne
62
63#ifndef CONFIG_MN10300_CACHE_DISABLED
64#ifdef CONFIG_MN10300_CACHE_WBACK
65#ifndef CONFIG_MN10300_CACHE_WBACK_NOWRALLOC
66 mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK,d0
67#else
68 mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRBACK|CHCTR_DCALMD,d0
69#endif /* CACHE_DISABLED */
70#else
71 mov CHCTR_ICEN|CHCTR_DCEN|CHCTR_DCWTMD_WRTHROUGH,d0
72#endif /* WBACK */
73 movhu d0,(a0) # enable
74#endif /* NOWRALLOC */
75
76 # turn on RTS on the debug serial port if applicable
77#ifdef CONFIG_MN10300_UNIT_ASB2305
78 bset UART_MCR_RTS,(ASB2305_DEBUG_MCR)
79#endif
80
81 # clear the BSS area
82 mov __bss_start,a0
83 mov __bss_stop,a1
84 clr d0
85bssclear:
86 cmp a1,a0
87 bge bssclear_end
88 mov d0,(a0)
89 inc4 a0
90 bra bssclear
91bssclear_end:
92
93 # retrieve the parameters (including command line) before we overwrite
94 # them
95 cmp 0xabadcafe,d1
96 bne __no_parameters
97
98__copy_parameters:
99 mov redboot_command_line,a0
100 mov a0,a1
101 add COMMAND_LINE_SIZE,a1
1021:
103 movbu (a3),d0
104 inc a3
105 movbu d0,(a0)
106 inc a0
107 cmp a1,a0
108 blt 1b
109
110 mov redboot_platform_name,a0
111 mov a0,a1
112 add COMMAND_LINE_SIZE,a1
113 mov d2,a3
1141:
115 movbu (a3),d0
116 inc a3
117 movbu d0,(a0)
118 inc a0
119 cmp a1,a0
120 blt 1b
121
122__no_parameters:
123
124 # set up the registers with recognisable rubbish in them
125 mov init_thread_union+THREAD_SIZE-12,sp
126
127 mov 0xea01eaea,d0
128 mov d0,(4,sp) # EPSW save area
129 mov 0xea02eaea,d0
130 mov d0,(8,sp) # PC save area
131
132 mov 0xeb0060ed,d0
133 mov d0,mdr
134 mov 0xeb0061ed,d0
135 mov d0,mdrq
136 mov 0xeb0062ed,d0
137 mov d0,mcrh
138 mov 0xeb0063ed,d0
139 mov d0,mcrl
140 mov 0xeb0064ed,d0
141 mov d0,mcvf
142 mov 0xed0065ed,a3
143 mov a3,usp
144
145 mov 0xed00e0ed,e0
146 mov 0xed00e1ed,e1
147 mov 0xed00e2ed,e2
148 mov 0xed00e3ed,e3
149 mov 0xed00e4ed,e4
150 mov 0xed00e5ed,e5
151 mov 0xed00e6ed,e6
152 mov 0xed00e7ed,e7
153
154 mov 0xed00d0ed,d0
155 mov 0xed00d1ed,d1
156 mov 0xed00d2ed,d2
157 mov 0xed00d3ed,d3
158 mov 0xed00a0ed,a0
159 mov 0xed00a1ed,a1
160 mov 0xed00a2ed,a2
161 mov 0,a3
162
163 # set up the initial kernel stack
164 SAVE_ALL
165 mov 0xffffffff,d0
166 mov d0,(REG_ORIG_D0,fp)
167
168 # put different recognisable rubbish in the regs
169 mov 0xfb0060ed,d0
170 mov d0,mdr
171 mov 0xfb0061ed,d0
172 mov d0,mdrq
173 mov 0xfb0062ed,d0
174 mov d0,mcrh
175 mov 0xfb0063ed,d0
176 mov d0,mcrl
177 mov 0xfb0064ed,d0
178 mov d0,mcvf
179 mov 0xfd0065ed,a0
180 mov a0,usp
181
182 mov 0xfd00e0ed,e0
183 mov 0xfd00e1ed,e1
184 mov 0xfd00e2ed,e2
185 mov 0xfd00e3ed,e3
186 mov 0xfd00e4ed,e4
187 mov 0xfd00e5ed,e5
188 mov 0xfd00e6ed,e6
189 mov 0xfd00e7ed,e7
190
191 mov 0xfd00d0ed,d0
192 mov 0xfd00d1ed,d1
193 mov 0xfd00d2ed,d2
194 mov 0xfd00d3ed,d3
195 mov 0xfd00a0ed,a0
196 mov 0xfd00a1ed,a1
197 mov 0xfd00a2ed,a2
198
199 # we may be holding current in E2
200#ifdef CONFIG_MN10300_CURRENT_IN_E2
201 mov init_task,e2
202#endif
203
204 # initialise the processor and the unit
205 call processor_init[],0
206 call unit_init[],0
207
208#ifdef CONFIG_GDBSTUB
209 call gdbstub_init[],0
210
211#ifdef CONFIG_GDBSTUB_IMMEDIATE
212 .globl __gdbstub_pause
213__gdbstub_pause:
214 bra __gdbstub_pause
215#endif
216#endif
217
218 jmp start_kernel
219 .size _start, _start-.
220ENTRY(__head_end)
221
222/*
223 * This is initialized to disallow all access to the low 2G region
224 * - the high 2G region is managed directly by the MMU
225 * - range 0x70000000-0x7C000000 are initialised for use by VMALLOC
226 */
227 .section .bss
228 .balign PAGE_SIZE
229ENTRY(swapper_pg_dir)
230 .space PTRS_PER_PGD*4
231
232/*
233 * The page tables are initialized to only 8MB here - the final page
234 * tables are set up later depending on memory size.
235 */
236
237 .balign PAGE_SIZE
238ENTRY(empty_zero_page)
239 .space PAGE_SIZE
240
241 .balign PAGE_SIZE
242ENTRY(empty_bad_page)
243 .space PAGE_SIZE
244
245 .balign PAGE_SIZE
246ENTRY(empty_bad_pte_table)
247 .space PAGE_SIZE
248
249 .balign PAGE_SIZE
250ENTRY(large_page_table)
251 .space PAGE_SIZE
252
253 .balign PAGE_SIZE
254ENTRY(kernel_vmalloc_ptes)
255 .space ((VMALLOC_END-VMALLOC_START)/PAGE_SIZE)*4
diff --git a/arch/mn10300/kernel/init_task.c b/arch/mn10300/kernel/init_task.c
new file mode 100644
index 000000000000..39fe6882dd1d
--- /dev/null
+++ b/arch/mn10300/kernel/init_task.c
@@ -0,0 +1,45 @@
1/* MN10300 Initial task definitions
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/mm.h>
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/init.h>
15#include <linux/init_task.h>
16#include <linux/fs.h>
17#include <linux/mqueue.h>
18#include <asm/uaccess.h>
19#include <asm/pgtable.h>
20
21static struct fs_struct init_fs = INIT_FS;
22static struct files_struct init_files = INIT_FILES;
23static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
24static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
25struct mm_struct init_mm = INIT_MM(init_mm);
26EXPORT_SYMBOL(init_mm);
27
28/*
29 * Initial thread structure.
30 *
31 * We need to make sure that this is THREAD_SIZE aligned due to the
32 * way process stacks are handled. This is done by having a special
33 * "init_task" linker map entry..
34 */
35union thread_union init_thread_union
36 __attribute__((__section__(".data.init_task"))) =
37 { INIT_THREAD_INFO(init_task) };
38
39/*
40 * Initial task structure.
41 *
42 * All other task structs will be allocated on slabs in fork.c
43 */
44struct task_struct init_task = INIT_TASK(init_task);
45EXPORT_SYMBOL(init_task);
diff --git a/arch/mn10300/kernel/internal.h b/arch/mn10300/kernel/internal.h
new file mode 100644
index 000000000000..eee2eee86267
--- /dev/null
+++ b/arch/mn10300/kernel/internal.h
@@ -0,0 +1,20 @@
1/* Internal definitions for the arch part of the core kernel
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12/*
13 * kthread.S
14 */
15extern int kernel_thread_helper(int);
16
17/*
18 * entry.S
19 */
20extern void ret_from_fork(struct task_struct *) __attribute__((noreturn));
diff --git a/arch/mn10300/kernel/io.c b/arch/mn10300/kernel/io.c
new file mode 100644
index 000000000000..e96fdf6bb542
--- /dev/null
+++ b/arch/mn10300/kernel/io.c
@@ -0,0 +1,30 @@
1/* MN10300 Misaligned multibyte-word I/O
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/string.h>
13#include <linux/kernel.h>
14#include <asm/io.h>
15
16/*
17 * output data from a potentially misaligned buffer
18 */
19void __outsl(unsigned long addr, const void *buffer, int count)
20{
21 const unsigned char *buf = buffer;
22 unsigned long val;
23
24 while (count--) {
25 memcpy(&val, buf, 4);
26 outl(val, addr);
27 buf += 4;
28 }
29}
30EXPORT_SYMBOL(__outsl);
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
new file mode 100644
index 000000000000..761c434a2488
--- /dev/null
+++ b/arch/mn10300/kernel/irq.c
@@ -0,0 +1,235 @@
1/* MN10300 Arch-specific interrupt handling
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/interrupt.h>
13#include <linux/kernel_stat.h>
14#include <linux/seq_file.h>
15#include <asm/setup.h>
16
17unsigned long __mn10300_irq_enabled_epsw = EPSW_IE | EPSW_IM_7;
18EXPORT_SYMBOL(__mn10300_irq_enabled_epsw);
19
20atomic_t irq_err_count;
21
22/*
23 * MN10300 INTC controller operations
24 */
25static void mn10300_cpupic_disable(unsigned int irq)
26{
27 u16 tmp = GxICR(irq);
28 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
29 tmp = GxICR(irq);
30}
31
32static void mn10300_cpupic_enable(unsigned int irq)
33{
34 u16 tmp = GxICR(irq);
35 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
36 tmp = GxICR(irq);
37}
38
39static void mn10300_cpupic_ack(unsigned int irq)
40{
41 u16 tmp;
42 *(volatile u8 *) &GxICR(irq) = GxICR_DETECT;
43 tmp = GxICR(irq);
44}
45
46static void mn10300_cpupic_mask(unsigned int irq)
47{
48 u16 tmp = GxICR(irq);
49 GxICR(irq) = (tmp & GxICR_LEVEL);
50 tmp = GxICR(irq);
51}
52
53static void mn10300_cpupic_mask_ack(unsigned int irq)
54{
55 u16 tmp = GxICR(irq);
56 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_DETECT;
57 tmp = GxICR(irq);
58}
59
60static void mn10300_cpupic_unmask(unsigned int irq)
61{
62 u16 tmp = GxICR(irq);
63 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
64 tmp = GxICR(irq);
65}
66
67static void mn10300_cpupic_end(unsigned int irq)
68{
69 u16 tmp = GxICR(irq);
70 GxICR(irq) = (tmp & GxICR_LEVEL) | GxICR_ENABLE;
71 tmp = GxICR(irq);
72}
73
74static struct irq_chip mn10300_cpu_pic = {
75 .name = "cpu",
76 .disable = mn10300_cpupic_disable,
77 .enable = mn10300_cpupic_enable,
78 .ack = mn10300_cpupic_ack,
79 .mask = mn10300_cpupic_mask,
80 .mask_ack = mn10300_cpupic_mask_ack,
81 .unmask = mn10300_cpupic_unmask,
82 .end = mn10300_cpupic_end,
83};
84
85/*
86 * 'what should we do if we get a hw irq event on an illegal vector'.
87 * each architecture has to answer this themselves.
88 */
89void ack_bad_irq(int irq)
90{
91 printk(KERN_WARNING "unexpected IRQ trap at vector %02x\n", irq);
92}
93
94/*
95 * change the level at which an IRQ executes
96 * - must not be called whilst interrupts are being processed!
97 */
98void set_intr_level(int irq, u16 level)
99{
100 u16 tmp;
101
102 if (in_interrupt())
103 BUG();
104
105 tmp = GxICR(irq);
106 GxICR(irq) = (tmp & GxICR_ENABLE) | level;
107 tmp = GxICR(irq);
108}
109
110/*
111 * mark an interrupt to be ACK'd after interrupt handlers have been run rather
112 * than before
113 * - see Documentation/mn10300/features.txt
114 */
115void set_intr_postackable(int irq)
116{
117 set_irq_handler(irq, handle_level_irq);
118}
119
120/*
121 * initialise the interrupt system
122 */
123void __init init_IRQ(void)
124{
125 int irq;
126
127 for (irq = 0; irq < NR_IRQS; irq++)
128 if (irq_desc[irq].chip == &no_irq_type)
129 set_irq_chip_and_handler(irq, &mn10300_cpu_pic,
130 handle_edge_irq);
131 unit_init_IRQ();
132}
133
134/*
135 * handle normal device IRQs
136 */
137asmlinkage void do_IRQ(void)
138{
139 unsigned long sp, epsw, irq_disabled_epsw, old_irq_enabled_epsw;
140 int irq;
141
142 sp = current_stack_pointer();
143 if (sp - (sp & ~(THREAD_SIZE - 1)) < STACK_WARN)
144 BUG();
145
146 /* make sure local_irq_enable() doesn't muck up the interrupt priority
147 * setting in EPSW */
148 old_irq_enabled_epsw = __mn10300_irq_enabled_epsw;
149 local_save_flags(epsw);
150 __mn10300_irq_enabled_epsw = EPSW_IE | (EPSW_IM & epsw);
151 irq_disabled_epsw = EPSW_IE | MN10300_CLI_LEVEL;
152
153 __IRQ_STAT(smp_processor_id(), __irq_count)++;
154
155 irq_enter();
156
157 for (;;) {
158 /* ask the interrupt controller for the next IRQ to process
159 * - the result we get depends on EPSW.IM
160 */
161 irq = IAGR & IAGR_GN;
162 if (!irq)
163 break;
164
165 local_irq_restore(irq_disabled_epsw);
166
167 generic_handle_irq(irq >> 2);
168
169 /* restore IRQ controls for IAGR access */
170 local_irq_restore(epsw);
171 }
172
173 __mn10300_irq_enabled_epsw = old_irq_enabled_epsw;
174
175 irq_exit();
176}
177
178/*
179 * Display interrupt management information through /proc/interrupts
180 */
181int show_interrupts(struct seq_file *p, void *v)
182{
183 int i = *(loff_t *) v, j, cpu;
184 struct irqaction *action;
185 unsigned long flags;
186
187 switch (i) {
188 /* display column title bar naming CPUs */
189 case 0:
190 seq_printf(p, " ");
191 for (j = 0; j < NR_CPUS; j++)
192 if (cpu_online(j))
193 seq_printf(p, "CPU%d ", j);
194 seq_putc(p, '\n');
195 break;
196
197 /* display information rows, one per active CPU */
198 case 1 ... NR_IRQS - 1:
199 spin_lock_irqsave(&irq_desc[i].lock, flags);
200
201 action = irq_desc[i].action;
202 if (action) {
203 seq_printf(p, "%3d: ", i);
204 for_each_present_cpu(cpu)
205 seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]);
206 seq_printf(p, " %14s.%u", irq_desc[i].chip->name,
207 (GxICR(i) & GxICR_LEVEL) >>
208 GxICR_LEVEL_SHIFT);
209 seq_printf(p, " %s", action->name);
210
211 for (action = action->next;
212 action;
213 action = action->next)
214 seq_printf(p, ", %s", action->name);
215
216 seq_putc(p, '\n');
217 }
218
219 spin_unlock_irqrestore(&irq_desc[i].lock, flags);
220 break;
221
222 /* polish off with NMI and error counters */
223 case NR_IRQS:
224 seq_printf(p, "NMI: ");
225 for (j = 0; j < NR_CPUS; j++)
226 if (cpu_online(j))
227 seq_printf(p, "%10u ", nmi_count(j));
228 seq_putc(p, '\n');
229
230 seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
231 break;
232 }
233
234 return 0;
235}
diff --git a/arch/mn10300/kernel/kernel_execve.S b/arch/mn10300/kernel/kernel_execve.S
new file mode 100644
index 000000000000..86039f105268
--- /dev/null
+++ b/arch/mn10300/kernel/kernel_execve.S
@@ -0,0 +1,37 @@
1/* MN10300 In-kernel program execution
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/linkage.h>
12#include <asm/unistd.h>
13
14###############################################################################
15#
16# Do a system call from kernel instead of calling sys_execve so we end up with
17# proper pt_regs.
18#
19# int kernel_execve(const char *filename, char *const argv[],
20# char *const envp[])
21#
22# On entry: D0/D1/8(SP): arguments to function
23# On return: D0: syscall return.
24#
25###############################################################################
26 .globl kernel_execve
27 .type kernel_execve,@function
28kernel_execve:
29 mov a3,a1
30 mov d0,a0
31 mov (12,sp),a3
32 mov +__NR_execve,d0
33 syscall 0
34 mov a1,a3
35 rets
36
37 .size kernel_execve,.-kernel_execve
diff --git a/arch/mn10300/kernel/kprobes.c b/arch/mn10300/kernel/kprobes.c
new file mode 100644
index 000000000000..dacafab00eb2
--- /dev/null
+++ b/arch/mn10300/kernel/kprobes.c
@@ -0,0 +1,653 @@
1/* MN10300 Kernel probes implementation
2 *
3 * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public Licence as published by
8 * the Free Software Foundation; either version 2 of the Licence, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public Licence for more details.
15 *
16 * You should have received a copy of the GNU General Public Licence
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20#include <linux/kprobes.h>
21#include <linux/ptrace.h>
22#include <linux/spinlock.h>
23#include <linux/preempt.h>
24#include <linux/kdebug.h>
25#include <asm/cacheflush.h>
26
27struct kretprobe_blackpoint kretprobe_blacklist[] = { { NULL, NULL } };
28const int kretprobe_blacklist_size = ARRAY_SIZE(kretprobe_blacklist);
29
30/* kprobe_status settings */
31#define KPROBE_HIT_ACTIVE 0x00000001
32#define KPROBE_HIT_SS 0x00000002
33
34static struct kprobe *current_kprobe;
35static unsigned long current_kprobe_orig_pc;
36static unsigned long current_kprobe_next_pc;
37static int current_kprobe_ss_flags;
38static unsigned long kprobe_status;
39static kprobe_opcode_t current_kprobe_ss_buf[MAX_INSN_SIZE + 2];
40static unsigned long current_kprobe_bp_addr;
41
42DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
43
44
45/* singlestep flag bits */
46#define SINGLESTEP_BRANCH 1
47#define SINGLESTEP_PCREL 2
48
49#define READ_BYTE(p, valp) \
50 do { *(u8 *)(valp) = *(u8 *)(p); } while (0)
51
52#define READ_WORD16(p, valp) \
53 do { \
54 READ_BYTE((p), (valp)); \
55 READ_BYTE((u8 *)(p) + 1, (u8 *)(valp) + 1); \
56 } while (0)
57
58#define READ_WORD32(p, valp) \
59 do { \
60 READ_BYTE((p), (valp)); \
61 READ_BYTE((u8 *)(p) + 1, (u8 *)(valp) + 1); \
62 READ_BYTE((u8 *)(p) + 2, (u8 *)(valp) + 2); \
63 READ_BYTE((u8 *)(p) + 3, (u8 *)(valp) + 3); \
64 } while (0)
65
66
67static const u8 mn10300_insn_sizes[256] =
68{
69 /* 1 2 3 4 5 6 7 8 9 a b c d e f */
70 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, /* 0 */
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 1 */
72 2, 2, 2, 2, 3, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, /* 2 */
73 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, /* 3 */
74 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, /* 4 */
75 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, /* 5 */
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6 */
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
78 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 8 */
79 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* 9 */
80 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* a */
81 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, /* b */
82 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 2, /* c */
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* d */
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* e */
85 0, 2, 2, 2, 2, 2, 2, 4, 0, 3, 0, 4, 0, 6, 7, 1 /* f */
86};
87
88#define LT (1 << 0)
89#define GT (1 << 1)
90#define GE (1 << 2)
91#define LE (1 << 3)
92#define CS (1 << 4)
93#define HI (1 << 5)
94#define CC (1 << 6)
95#define LS (1 << 7)
96#define EQ (1 << 8)
97#define NE (1 << 9)
98#define RA (1 << 10)
99#define VC (1 << 11)
100#define VS (1 << 12)
101#define NC (1 << 13)
102#define NS (1 << 14)
103
104static const u16 cond_table[] = {
105 /* V C N Z */
106 /* 0 0 0 0 */ (NE | NC | CC | VC | GE | GT | HI),
107 /* 0 0 0 1 */ (EQ | NC | CC | VC | GE | LE | LS),
108 /* 0 0 1 0 */ (NE | NS | CC | VC | LT | LE | HI),
109 /* 0 0 1 1 */ (EQ | NS | CC | VC | LT | LE | LS),
110 /* 0 1 0 0 */ (NE | NC | CS | VC | GE | GT | LS),
111 /* 0 1 0 1 */ (EQ | NC | CS | VC | GE | LE | LS),
112 /* 0 1 1 0 */ (NE | NS | CS | VC | LT | LE | LS),
113 /* 0 1 1 1 */ (EQ | NS | CS | VC | LT | LE | LS),
114 /* 1 0 0 0 */ (NE | NC | CC | VS | LT | LE | HI),
115 /* 1 0 0 1 */ (EQ | NC | CC | VS | LT | LE | LS),
116 /* 1 0 1 0 */ (NE | NS | CC | VS | GE | GT | HI),
117 /* 1 0 1 1 */ (EQ | NS | CC | VS | GE | LE | LS),
118 /* 1 1 0 0 */ (NE | NC | CS | VS | LT | LE | LS),
119 /* 1 1 0 1 */ (EQ | NC | CS | VS | LT | LE | LS),
120 /* 1 1 1 0 */ (NE | NS | CS | VS | GE | GT | LS),
121 /* 1 1 1 1 */ (EQ | NS | CS | VS | GE | LE | LS),
122};
123
124/*
125 * Calculate what the PC will be after executing next instruction
126 */
127static unsigned find_nextpc(struct pt_regs *regs, int *flags)
128{
129 unsigned size;
130 s8 x8;
131 s16 x16;
132 s32 x32;
133 u8 opc, *pc, *sp, *next;
134
135 next = 0;
136 *flags = SINGLESTEP_PCREL;
137
138 pc = (u8 *) regs->pc;
139 sp = (u8 *) (regs + 1);
140 opc = *pc;
141
142 size = mn10300_insn_sizes[opc];
143 if (size > 0) {
144 next = pc + size;
145 } else {
146 switch (opc) {
147 /* Bxx (d8,PC) */
148 case 0xc0 ... 0xca:
149 x8 = 2;
150 if (cond_table[regs->epsw & 0xf] & (1 << (opc & 0xf)))
151 x8 = (s8)pc[1];
152 next = pc + x8;
153 *flags |= SINGLESTEP_BRANCH;
154 break;
155
156 /* JMP (d16,PC) or CALL (d16,PC) */
157 case 0xcc:
158 case 0xcd:
159 READ_WORD16(pc + 1, &x16);
160 next = pc + x16;
161 *flags |= SINGLESTEP_BRANCH;
162 break;
163
164 /* JMP (d32,PC) or CALL (d32,PC) */
165 case 0xdc:
166 case 0xdd:
167 READ_WORD32(pc + 1, &x32);
168 next = pc + x32;
169 *flags |= SINGLESTEP_BRANCH;
170 break;
171
172 /* RETF */
173 case 0xde:
174 next = (u8 *)regs->mdr;
175 *flags &= ~SINGLESTEP_PCREL;
176 *flags |= SINGLESTEP_BRANCH;
177 break;
178
179 /* RET */
180 case 0xdf:
181 sp += pc[2];
182 READ_WORD32(sp, &x32);
183 next = (u8 *)x32;
184 *flags &= ~SINGLESTEP_PCREL;
185 *flags |= SINGLESTEP_BRANCH;
186 break;
187
188 case 0xf0:
189 next = pc + 2;
190 opc = pc[1];
191 if (opc >= 0xf0 && opc <= 0xf7) {
192 /* JMP (An) / CALLS (An) */
193 switch (opc & 3) {
194 case 0:
195 next = (u8 *)regs->a0;
196 break;
197 case 1:
198 next = (u8 *)regs->a1;
199 break;
200 case 2:
201 next = (u8 *)regs->a2;
202 break;
203 case 3:
204 next = (u8 *)regs->a3;
205 break;
206 }
207 *flags &= ~SINGLESTEP_PCREL;
208 *flags |= SINGLESTEP_BRANCH;
209 } else if (opc == 0xfc) {
210 /* RETS */
211 READ_WORD32(sp, &x32);
212 next = (u8 *)x32;
213 *flags &= ~SINGLESTEP_PCREL;
214 *flags |= SINGLESTEP_BRANCH;
215 } else if (opc == 0xfd) {
216 /* RTI */
217 READ_WORD32(sp + 4, &x32);
218 next = (u8 *)x32;
219 *flags &= ~SINGLESTEP_PCREL;
220 *flags |= SINGLESTEP_BRANCH;
221 }
222 break;
223
224 /* potential 3-byte conditional branches */
225 case 0xf8:
226 next = pc + 3;
227 opc = pc[1];
228 if (opc >= 0xe8 && opc <= 0xeb &&
229 (cond_table[regs->epsw & 0xf] &
230 (1 << ((opc & 0xf) + 3)))
231 ) {
232 READ_BYTE(pc+2, &x8);
233 next = pc + x8;
234 *flags |= SINGLESTEP_BRANCH;
235 }
236 break;
237
238 case 0xfa:
239 if (pc[1] == 0xff) {
240 /* CALLS (d16,PC) */
241 READ_WORD16(pc + 2, &x16);
242 next = pc + x16;
243 } else
244 next = pc + 4;
245 *flags |= SINGLESTEP_BRANCH;
246 break;
247
248 case 0xfc:
249 x32 = 6;
250 if (pc[1] == 0xff) {
251 /* CALLS (d32,PC) */
252 READ_WORD32(pc + 2, &x32);
253 }
254 next = pc + x32;
255 *flags |= SINGLESTEP_BRANCH;
256 break;
257 /* LXX (d8,PC) */
258 /* SETLB - loads the next four bytes into the LIR reg */
259 case 0xd0 ... 0xda:
260 case 0xdb:
261 panic("Can't singlestep Lxx/SETLB\n");
262 break;
263 }
264 }
265 return (unsigned)next;
266
267}
268
269/*
270 * set up out of place singlestep of some branching instructions
271 */
272static unsigned __kprobes singlestep_branch_setup(struct pt_regs *regs)
273{
274 u8 opc, *pc, *sp, *next;
275
276 next = NULL;
277 pc = (u8 *) regs->pc;
278 sp = (u8 *) (regs + 1);
279
280 switch (pc[0]) {
281 case 0xc0 ... 0xca: /* Bxx (d8,PC) */
282 case 0xcc: /* JMP (d16,PC) */
283 case 0xdc: /* JMP (d32,PC) */
284 case 0xf8: /* Bxx (d8,PC) 3-byte version */
285 /* don't really need to do anything except cause trap */
286 next = pc;
287 break;
288
289 case 0xcd: /* CALL (d16,PC) */
290 pc[1] = 5;
291 pc[2] = 0;
292 next = pc + 5;
293 break;
294
295 case 0xdd: /* CALL (d32,PC) */
296 pc[1] = 7;
297 pc[2] = 0;
298 pc[3] = 0;
299 pc[4] = 0;
300 next = pc + 7;
301 break;
302
303 case 0xde: /* RETF */
304 next = pc + 3;
305 regs->mdr = (unsigned) next;
306 break;
307
308 case 0xdf: /* RET */
309 sp += pc[2];
310 next = pc + 3;
311 *(unsigned *)sp = (unsigned) next;
312 break;
313
314 case 0xf0:
315 next = pc + 2;
316 opc = pc[1];
317 if (opc >= 0xf0 && opc <= 0xf3) {
318 /* CALLS (An) */
319 /* use CALLS (d16,PC) to avoid mucking with An */
320 pc[0] = 0xfa;
321 pc[1] = 0xff;
322 pc[2] = 4;
323 pc[3] = 0;
324 next = pc + 4;
325 } else if (opc >= 0xf4 && opc <= 0xf7) {
326 /* JMP (An) */
327 next = pc;
328 } else if (opc == 0xfc) {
329 /* RETS */
330 next = pc + 2;
331 *(unsigned *) sp = (unsigned) next;
332 } else if (opc == 0xfd) {
333 /* RTI */
334 next = pc + 2;
335 *(unsigned *)(sp + 4) = (unsigned) next;
336 }
337 break;
338
339 case 0xfa: /* CALLS (d16,PC) */
340 pc[2] = 4;
341 pc[3] = 0;
342 next = pc + 4;
343 break;
344
345 case 0xfc: /* CALLS (d32,PC) */
346 pc[2] = 6;
347 pc[3] = 0;
348 pc[4] = 0;
349 pc[5] = 0;
350 next = pc + 6;
351 break;
352
353 case 0xd0 ... 0xda: /* LXX (d8,PC) */
354 case 0xdb: /* SETLB */
355 panic("Can't singlestep Lxx/SETLB\n");
356 }
357
358 return (unsigned) next;
359}
360
361int __kprobes arch_prepare_kprobe(struct kprobe *p)
362{
363 return 0;
364}
365
366void __kprobes arch_copy_kprobe(struct kprobe *p)
367{
368 memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE);
369}
370
371void __kprobes arch_arm_kprobe(struct kprobe *p)
372{
373 *p->addr = BREAKPOINT_INSTRUCTION;
374 flush_icache_range((unsigned long) p->addr,
375 (unsigned long) p->addr + sizeof(kprobe_opcode_t));
376}
377
378void __kprobes arch_disarm_kprobe(struct kprobe *p)
379{
380 mn10300_dcache_flush();
381 mn10300_icache_inv();
382}
383
384void arch_remove_kprobe(struct kprobe *p)
385{
386}
387
388static inline
389void __kprobes disarm_kprobe(struct kprobe *p, struct pt_regs *regs)
390{
391 *p->addr = p->opcode;
392 regs->pc = (unsigned long) p->addr;
393 mn10300_dcache_flush();
394 mn10300_icache_inv();
395}
396
397static inline
398void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
399{
400 unsigned long nextpc;
401
402 current_kprobe_orig_pc = regs->pc;
403 memcpy(current_kprobe_ss_buf, &p->ainsn.insn[0], MAX_INSN_SIZE);
404 regs->pc = (unsigned long) current_kprobe_ss_buf;
405
406 nextpc = find_nextpc(regs, &current_kprobe_ss_flags);
407 if (current_kprobe_ss_flags & SINGLESTEP_PCREL)
408 current_kprobe_next_pc =
409 current_kprobe_orig_pc + (nextpc - regs->pc);
410 else
411 current_kprobe_next_pc = nextpc;
412
413 /* branching instructions need special handling */
414 if (current_kprobe_ss_flags & SINGLESTEP_BRANCH)
415 nextpc = singlestep_branch_setup(regs);
416
417 current_kprobe_bp_addr = nextpc;
418
419 *(u8 *) nextpc = BREAKPOINT_INSTRUCTION;
420 mn10300_dcache_flush_range2((unsigned) current_kprobe_ss_buf,
421 sizeof(current_kprobe_ss_buf));
422 mn10300_icache_inv();
423}
424
425static inline int __kprobes kprobe_handler(struct pt_regs *regs)
426{
427 struct kprobe *p;
428 int ret = 0;
429 unsigned int *addr = (unsigned int *) regs->pc;
430
431 /* We're in an interrupt, but this is clear and BUG()-safe. */
432 preempt_disable();
433
434 /* Check we're not actually recursing */
435 if (kprobe_running()) {
436 /* We *are* holding lock here, so this is safe.
437 Disarm the probe we just hit, and ignore it. */
438 p = get_kprobe(addr);
439 if (p) {
440 disarm_kprobe(p, regs);
441 ret = 1;
442 } else {
443 p = current_kprobe;
444 if (p->break_handler && p->break_handler(p, regs))
445 goto ss_probe;
446 }
447 /* If it's not ours, can't be delete race, (we hold lock). */
448 goto no_kprobe;
449 }
450
451 p = get_kprobe(addr);
452 if (!p) {
453 if (*addr != BREAKPOINT_INSTRUCTION) {
454 /* The breakpoint instruction was removed right after
455 * we hit it. Another cpu has removed either a
456 * probepoint or a debugger breakpoint at this address.
457 * In either case, no further handling of this
458 * interrupt is appropriate.
459 */
460 ret = 1;
461 }
462 /* Not one of ours: let kernel handle it */
463 goto no_kprobe;
464 }
465
466 kprobe_status = KPROBE_HIT_ACTIVE;
467 current_kprobe = p;
468 if (p->pre_handler(p, regs)) {
469 /* handler has already set things up, so skip ss setup */
470 return 1;
471 }
472
473ss_probe:
474 prepare_singlestep(p, regs);
475 kprobe_status = KPROBE_HIT_SS;
476 return 1;
477
478no_kprobe:
479 preempt_enable_no_resched();
480 return ret;
481}
482
483/*
484 * Called after single-stepping. p->addr is the address of the
485 * instruction whose first byte has been replaced by the "breakpoint"
486 * instruction. To avoid the SMP problems that can occur when we
487 * temporarily put back the original opcode to single-step, we
488 * single-stepped a copy of the instruction. The address of this
489 * copy is p->ainsn.insn.
490 */
491static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
492{
493 /* we may need to fixup regs/stack after singlestepping a call insn */
494 if (current_kprobe_ss_flags & SINGLESTEP_BRANCH) {
495 regs->pc = current_kprobe_orig_pc;
496 switch (p->ainsn.insn[0]) {
497 case 0xcd: /* CALL (d16,PC) */
498 *(unsigned *) regs->sp = regs->mdr = regs->pc + 5;
499 break;
500 case 0xdd: /* CALL (d32,PC) */
501 /* fixup mdr and return address on stack */
502 *(unsigned *) regs->sp = regs->mdr = regs->pc + 7;
503 break;
504 case 0xf0:
505 if (p->ainsn.insn[1] >= 0xf0 &&
506 p->ainsn.insn[1] <= 0xf3) {
507 /* CALLS (An) */
508 /* fixup MDR and return address on stack */
509 regs->mdr = regs->pc + 2;
510 *(unsigned *) regs->sp = regs->mdr;
511 }
512 break;
513
514 case 0xfa: /* CALLS (d16,PC) */
515 /* fixup MDR and return address on stack */
516 *(unsigned *) regs->sp = regs->mdr = regs->pc + 4;
517 break;
518
519 case 0xfc: /* CALLS (d32,PC) */
520 /* fixup MDR and return address on stack */
521 *(unsigned *) regs->sp = regs->mdr = regs->pc + 6;
522 break;
523 }
524 }
525
526 regs->pc = current_kprobe_next_pc;
527 current_kprobe_bp_addr = 0;
528}
529
530static inline int __kprobes post_kprobe_handler(struct pt_regs *regs)
531{
532 if (!kprobe_running())
533 return 0;
534
535 if (current_kprobe->post_handler)
536 current_kprobe->post_handler(current_kprobe, regs, 0);
537
538 resume_execution(current_kprobe, regs);
539 reset_current_kprobe();
540 preempt_enable_no_resched();
541 return 1;
542}
543
544/* Interrupts disabled, kprobe_lock held. */
545static inline
546int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
547{
548 if (current_kprobe->fault_handler &&
549 current_kprobe->fault_handler(current_kprobe, regs, trapnr))
550 return 1;
551
552 if (kprobe_status & KPROBE_HIT_SS) {
553 resume_execution(current_kprobe, regs);
554 reset_current_kprobe();
555 preempt_enable_no_resched();
556 }
557 return 0;
558}
559
560/*
561 * Wrapper routine to for handling exceptions.
562 */
563int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
564 unsigned long val, void *data)
565{
566 struct die_args *args = data;
567
568 switch (val) {
569 case DIE_BREAKPOINT:
570 if (current_kprobe_bp_addr != args->regs->pc) {
571 if (kprobe_handler(args->regs))
572 return NOTIFY_STOP;
573 } else {
574 if (post_kprobe_handler(args->regs))
575 return NOTIFY_STOP;
576 }
577 break;
578 case DIE_GPF:
579 if (kprobe_running() &&
580 kprobe_fault_handler(args->regs, args->trapnr))
581 return NOTIFY_STOP;
582 break;
583 default:
584 break;
585 }
586 return NOTIFY_DONE;
587}
588
589/* Jprobes support. */
590static struct pt_regs jprobe_saved_regs;
591static struct pt_regs *jprobe_saved_regs_location;
592static kprobe_opcode_t jprobe_saved_stack[MAX_STACK_SIZE];
593
594int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
595{
596 struct jprobe *jp = container_of(p, struct jprobe, kp);
597
598 jprobe_saved_regs_location = regs;
599 memcpy(&jprobe_saved_regs, regs, sizeof(struct pt_regs));
600
601 /* Save a whole stack frame, this gets arguments
602 * pushed onto the stack after using up all the
603 * arg registers.
604 */
605 memcpy(&jprobe_saved_stack, regs + 1, sizeof(jprobe_saved_stack));
606
607 /* setup return addr to the jprobe handler routine */
608 regs->pc = (unsigned long) jp->entry;
609 return 1;
610}
611
612void __kprobes jprobe_return(void)
613{
614 void *orig_sp = jprobe_saved_regs_location + 1;
615
616 preempt_enable_no_resched();
617 asm volatile(" mov %0,sp\n"
618 ".globl jprobe_return_bp_addr\n"
619 "jprobe_return_bp_addr:\n\t"
620 " .byte 0xff\n"
621 : : "d" (orig_sp));
622}
623
624extern void jprobe_return_bp_addr(void);
625
626int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
627{
628 u8 *addr = (u8 *) regs->pc;
629
630 if (addr == (u8 *) jprobe_return_bp_addr) {
631 if (jprobe_saved_regs_location != regs) {
632 printk(KERN_ERR"JPROBE:"
633 " Current regs (%p) does not match saved regs"
634 " (%p).\n",
635 regs, jprobe_saved_regs_location);
636 BUG();
637 }
638
639 /* Restore old register state.
640 */
641 memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
642
643 memcpy(regs + 1, &jprobe_saved_stack,
644 sizeof(jprobe_saved_stack));
645 return 1;
646 }
647 return 0;
648}
649
650int __init arch_init_kprobes(void)
651{
652 return 0;
653}
diff --git a/arch/mn10300/kernel/kthread.S b/arch/mn10300/kernel/kthread.S
new file mode 100644
index 000000000000..b5ae467ac5ec
--- /dev/null
+++ b/arch/mn10300/kernel/kthread.S
@@ -0,0 +1,31 @@
1/* MN10300 Kernel thread trampoline function
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11 .text
12
13###############################################################################
14#
15# kernel_thread_helper - trampoline for kernel_thread()
16#
17# On entry:
18# A2 = address of function to call
19# D2 = function argument
20#
21###############################################################################
22 .globl kernel_thread_helper
23 .type kernel_thread_helper,@function
24kernel_thread_helper:
25 mov do_exit,d1
26 mov d1,(sp)
27 mov d1,mdr
28 mov d2,d0
29 jmp (a2)
30
31 .size kernel_thread_helper,.-kernel_thread_helper
diff --git a/arch/mn10300/kernel/mn10300-debug.c b/arch/mn10300/kernel/mn10300-debug.c
new file mode 100644
index 000000000000..bd8196478cbc
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-debug.c
@@ -0,0 +1,58 @@
1/* Debugging stuff for the MN10300-based processors
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sched.h>
12#include <asm/serial-regs.h>
13
14#undef MN10300_CONSOLE_ON_SERIO
15
16/*
17 * write a string directly through one of the serial ports on-board the MN10300
18 */
19#ifdef MN10300_CONSOLE_ON_SERIO
20void debug_to_serial_mnser(const char *p, int n)
21{
22 char ch;
23
24 for (; n > 0; n--) {
25 ch = *p++;
26
27#if MN10300_CONSOLE_ON_SERIO == 0
28 while (SC0STR & (SC01STR_TBF)) continue;
29 SC0TXB = ch;
30 while (SC0STR & (SC01STR_TBF)) continue;
31 if (ch == 0x0a) {
32 SC0TXB = 0x0d;
33 while (SC0STR & (SC01STR_TBF)) continue;
34 }
35
36#elif MN10300_CONSOLE_ON_SERIO == 1
37 while (SC1STR & (SC01STR_TBF)) continue;
38 SC1TXB = ch;
39 while (SC1STR & (SC01STR_TBF)) continue;
40 if (ch == 0x0a) {
41 SC1TXB = 0x0d;
42 while (SC1STR & (SC01STR_TBF)) continue;
43 }
44
45#elif MN10300_CONSOLE_ON_SERIO == 2
46 while (SC2STR & (SC2STR_TBF)) continue;
47 SC2TXB = ch;
48 while (SC2STR & (SC2STR_TBF)) continue;
49 if (ch == 0x0a) {
50 SC2TXB = 0x0d;
51 while (SC2STR & (SC2STR_TBF)) continue;
52 }
53
54#endif
55 }
56}
57#endif
58
diff --git a/arch/mn10300/kernel/mn10300-serial-low.S b/arch/mn10300/kernel/mn10300-serial-low.S
new file mode 100644
index 000000000000..ef3f4c1df2a4
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-serial-low.S
@@ -0,0 +1,191 @@
1###############################################################################
2#
3# Virtual DMA driver for MN10300 serial ports
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/page.h>
17#include <asm/smp.h>
18#include <asm/cpu-regs.h>
19#include <asm/frame.inc>
20#include <asm/timer-regs.h>
21#include <asm/proc/cache.h>
22#include <asm/unit/timex.h>
23#include "mn10300-serial.h"
24
25#define SCxCTR 0x00
26#define SCxICR 0x04
27#define SCxTXB 0x08
28#define SCxRXB 0x09
29#define SCxSTR 0x0c
30#define SCxTIM 0x0d
31
32 .text
33
34###############################################################################
35#
36# serial port interrupt virtual DMA entry point
37# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
38#
39###############################################################################
40 .balign L1_CACHE_BYTES
41ENTRY(mn10300_serial_vdma_interrupt)
42 or EPSW_IE,psw # permit overriding by
43 # debugging interrupts
44 movm [d2,d3,a2,a3,exreg0],(sp)
45
46 movhu (IAGR),a2 # see if which interrupt is
47 # pending
48 and IAGR_GN,a2
49 add a2,a2
50 add mn10300_serial_int_tbl,a2
51
52 mov (a2+),a3
53 mov (__iobase,a3),e2
54 mov (a2),a2
55 jmp (a2)
56
57###############################################################################
58#
59# serial port receive interrupt virtual DMA entry point
60# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
61# - stores data/status byte pairs in the ring buffer
62# - induces a scheduler tick timer interrupt when done, which we then subvert
63# on entry:
64# A3 struct mn10300_serial_port *
65# E2 I/O port base
66#
67###############################################################################
68ENTRY(mn10300_serial_vdma_rx_handler)
69 mov (__rx_icr,a3),e3
70 mov GxICR_DETECT,d2
71 movbu d2,(e3) # ACK the interrupt
72 movhu (e3),d2 # flush
73
74 mov (__rx_inp,a3),d3
75 mov d3,a2
76 add 2,d3
77 and MNSC_BUFFER_SIZE-1,d3
78 mov (__rx_outp,a3),d2
79 cmp d3,d2
80 beq mnsc_vdma_rx_overflow
81
82 mov (__rx_buffer,a3),d2
83 add d2,a2
84 movhu (SCxSTR,e2),d2
85 movbu d2,(1,a2)
86 movbu (SCxRXB,e2),d2
87 movbu d2,(a2)
88 mov d3,(__rx_inp,a3)
89 bset MNSCx_RX_AVAIL,(__intr_flags,a3)
90
91mnsc_vdma_rx_done:
92 mov (__tm_icr,a3),a2
93 mov GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
94 movhu d2,(a2) # request a slow interrupt
95 movhu (a2),d2 # flush
96
97 movm (sp),[d2,d3,a2,a3,exreg0]
98 rti
99
100mnsc_vdma_rx_overflow:
101 bset MNSCx_RX_OVERF,(__intr_flags,a3)
102 bra mnsc_vdma_rx_done
103
104###############################################################################
105#
106# serial port transmit interrupt virtual DMA entry point
107# - intended to run at interrupt priority 1 (not affected by local_irq_disable)
108# - retrieves data bytes from the ring buffer and passes them to the serial port
109# - induces a scheduler tick timer interrupt when done, which we then subvert
110# A3 struct mn10300_serial_port *
111# E2 I/O port base
112#
113###############################################################################
114 .balign L1_CACHE_BYTES
115ENTRY(mn10300_serial_vdma_tx_handler)
116 mov (__tx_icr,a3),e3
117 mov GxICR_DETECT,d2
118 movbu d2,(e3) # ACK the interrupt
119 movhu (e3),d2 # flush
120
121 btst 0x01,(__tx_break,a3) # handle transmit break request
122 bne mnsc_vdma_tx_break
123
124 movbu (SCxSTR,e2),d2 # don't try and transmit a char if the
125 # buffer is not empty
126 btst SC01STR_TBF,d2 # (may have tried to jumpstart)
127 bne mnsc_vdma_tx_noint
128
129 movbu (__tx_xchar,a3),d2 # handle hi-pri XON/XOFF
130 or d2,d2
131 bne mnsc_vdma_tx_xchar
132
133 mov (__tx_info_buffer,a3),a2 # get the uart_info struct for Tx
134 mov (__xmit_tail,a2),d3
135 mov (__xmit_head,a2),d2
136 cmp d3,d2
137 beq mnsc_vdma_tx_empty
138
139 mov (__xmit_buffer,a2),d2 # get a char from the buffer and
140 # transmit it
141 movbu (d3,d2),d2
142 movbu d2,(SCxTXB,e2) # Tx
143
144 inc d3 # advance the buffer pointer
145 and __UART_XMIT_SIZE-1,d3
146 mov (__xmit_head,a2),d2
147 mov d3,(__xmit_tail,a2)
148
149 sub d3,d2 # see if we've written everything
150 beq mnsc_vdma_tx_empty
151
152 and __UART_XMIT_SIZE-1,d2 # see if we just made a hole
153 cmp __UART_XMIT_SIZE-2,d2
154 beq mnsc_vdma_tx_made_hole
155
156mnsc_vdma_tx_done:
157 mov (__tm_icr,a3),a2
158 mov GxICR_LEVEL_6|GxICR_ENABLE|GxICR_REQUEST|GxICR_DETECT,d2
159 movhu d2,(a2) # request a slow interrupt
160 movhu (a2),d2 # flush
161
162mnsc_vdma_tx_noint:
163 movm (sp),[d2,d3,a2,a3,exreg0]
164 rti
165
166mnsc_vdma_tx_empty:
167 mov +(GxICR_LEVEL_1|GxICR_DETECT),d2
168 movhu d2,(e3) # disable the interrupt
169 movhu (e3),d2 # flush
170
171 bset MNSCx_TX_EMPTY,(__intr_flags,a3)
172 bra mnsc_vdma_tx_done
173
174mnsc_vdma_tx_break:
175 movhu (SCxCTR,e2),d2 # turn on break mode
176 or SC01CTR_BKE,d2
177 movhu d2,(SCxCTR,e2)
178 mov +(GxICR_LEVEL_1|GxICR_DETECT),d2
179 movhu d2,(e3) # disable transmit interrupts on this
180 # channel
181 movhu (e3),d2 # flush
182 bra mnsc_vdma_tx_noint
183
184mnsc_vdma_tx_xchar:
185 bclr 0xff,(__tx_xchar,a3)
186 movbu d2,(SCxTXB,e2)
187 bra mnsc_vdma_tx_done
188
189mnsc_vdma_tx_made_hole:
190 bset MNSCx_TX_SPACE,(__intr_flags,a3)
191 bra mnsc_vdma_tx_done
diff --git a/arch/mn10300/kernel/mn10300-serial.c b/arch/mn10300/kernel/mn10300-serial.c
new file mode 100644
index 000000000000..b9c268c6b2fb
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-serial.c
@@ -0,0 +1,1480 @@
1/* MN10300 On-chip serial port UART driver
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12static const char serial_name[] = "MN10300 Serial driver";
13static const char serial_version[] = "mn10300_serial-1.0";
14static const char serial_revdate[] = "2007-11-06";
15
16#if defined(CONFIG_MN10300_TTYSM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
17#define SUPPORT_SYSRQ
18#endif
19
20#include <linux/version.h>
21#include <linux/module.h>
22#include <linux/serial.h>
23#include <linux/circ_buf.h>
24#include <linux/errno.h>
25#include <linux/signal.h>
26#include <linux/sched.h>
27#include <linux/timer.h>
28#include <linux/interrupt.h>
29#include <linux/tty.h>
30#include <linux/tty_flip.h>
31#include <linux/major.h>
32#include <linux/string.h>
33#include <linux/ioport.h>
34#include <linux/mm.h>
35#include <linux/slab.h>
36#include <linux/init.h>
37#include <linux/console.h>
38#include <linux/sysrq.h>
39
40#include <asm/system.h>
41#include <asm/io.h>
42#include <asm/irq.h>
43#include <asm/bitops.h>
44#include <asm/serial-regs.h>
45#include <asm/unit/timex.h>
46#include "mn10300-serial.h"
47
48static inline __attribute__((format(printf, 1, 2)))
49void no_printk(const char *fmt, ...)
50{
51}
52
53#define kenter(FMT, ...) \
54 printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)
55#define _enter(FMT, ...) \
56 no_printk(KERN_DEBUG "-->%s(" FMT ")\n", __func__, ##__VA_ARGS__)
57#define kdebug(FMT, ...) \
58 printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__)
59#define _debug(FMT, ...) \
60 no_printk(KERN_DEBUG "--- " FMT "\n", ##__VA_ARGS__)
61#define kproto(FMT, ...) \
62 printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__)
63#define _proto(FMT, ...) \
64 no_printk(KERN_DEBUG "### MNSERIAL " FMT " ###\n", ##__VA_ARGS__)
65
66#define NR_UARTS 3
67
68#ifdef CONFIG_MN10300_TTYSM_CONSOLE
69static void mn10300_serial_console_write(struct console *co,
70 const char *s, unsigned count);
71static int __init mn10300_serial_console_setup(struct console *co,
72 char *options);
73
74static struct uart_driver mn10300_serial_driver;
75static struct console mn10300_serial_console = {
76 .name = "ttySM",
77 .write = mn10300_serial_console_write,
78 .device = uart_console_device,
79 .setup = mn10300_serial_console_setup,
80 .flags = CON_PRINTBUFFER,
81 .index = -1,
82 .data = &mn10300_serial_driver,
83};
84#endif
85
86static struct uart_driver mn10300_serial_driver = {
87 .owner = NULL,
88 .driver_name = "mn10300-serial",
89 .dev_name = "ttySM",
90 .major = TTY_MAJOR,
91 .minor = 128,
92 .nr = NR_UARTS,
93#ifdef CONFIG_MN10300_TTYSM_CONSOLE
94 .cons = &mn10300_serial_console,
95#endif
96};
97
98static unsigned int mn10300_serial_tx_empty(struct uart_port *);
99static void mn10300_serial_set_mctrl(struct uart_port *, unsigned int mctrl);
100static unsigned int mn10300_serial_get_mctrl(struct uart_port *);
101static void mn10300_serial_stop_tx(struct uart_port *);
102static void mn10300_serial_start_tx(struct uart_port *);
103static void mn10300_serial_send_xchar(struct uart_port *, char ch);
104static void mn10300_serial_stop_rx(struct uart_port *);
105static void mn10300_serial_enable_ms(struct uart_port *);
106static void mn10300_serial_break_ctl(struct uart_port *, int ctl);
107static int mn10300_serial_startup(struct uart_port *);
108static void mn10300_serial_shutdown(struct uart_port *);
109static void mn10300_serial_set_termios(struct uart_port *,
110 struct ktermios *new,
111 struct ktermios *old);
112static const char *mn10300_serial_type(struct uart_port *);
113static void mn10300_serial_release_port(struct uart_port *);
114static int mn10300_serial_request_port(struct uart_port *);
115static void mn10300_serial_config_port(struct uart_port *, int);
116static int mn10300_serial_verify_port(struct uart_port *,
117 struct serial_struct *);
118
119static const struct uart_ops mn10300_serial_ops = {
120 .tx_empty = mn10300_serial_tx_empty,
121 .set_mctrl = mn10300_serial_set_mctrl,
122 .get_mctrl = mn10300_serial_get_mctrl,
123 .stop_tx = mn10300_serial_stop_tx,
124 .start_tx = mn10300_serial_start_tx,
125 .send_xchar = mn10300_serial_send_xchar,
126 .stop_rx = mn10300_serial_stop_rx,
127 .enable_ms = mn10300_serial_enable_ms,
128 .break_ctl = mn10300_serial_break_ctl,
129 .startup = mn10300_serial_startup,
130 .shutdown = mn10300_serial_shutdown,
131 .set_termios = mn10300_serial_set_termios,
132 .type = mn10300_serial_type,
133 .release_port = mn10300_serial_release_port,
134 .request_port = mn10300_serial_request_port,
135 .config_port = mn10300_serial_config_port,
136 .verify_port = mn10300_serial_verify_port,
137};
138
139static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id);
140
141/*
142 * the first on-chip serial port: ttySM0 (aka SIF0)
143 */
144#ifdef CONFIG_MN10300_TTYSM0
145struct mn10300_serial_port mn10300_serial_port_sif0 = {
146 .uart.ops = &mn10300_serial_ops,
147 .uart.membase = (void __iomem *) &SC0CTR,
148 .uart.mapbase = (unsigned long) &SC0CTR,
149 .uart.iotype = UPIO_MEM,
150 .uart.irq = 0,
151 .uart.uartclk = 0, /* MN10300_IOCLK, */
152 .uart.fifosize = 1,
153 .uart.flags = UPF_BOOT_AUTOCONF,
154 .uart.line = 0,
155 .uart.type = PORT_MN10300,
156 .uart.lock =
157 __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif0.uart.lock),
158 .name = "ttySM0",
159 ._iobase = &SC0CTR,
160 ._control = &SC0CTR,
161 ._status = (volatile u8 *) &SC0STR,
162 ._intr = &SC0ICR,
163 ._rxb = &SC0RXB,
164 ._txb = &SC0TXB,
165 .rx_name = "ttySM0/Rx",
166 .tx_name = "ttySM0/Tx",
167#ifdef CONFIG_MN10300_TTYSM0_TIMER8
168 .tm_name = "ttySM0/Timer8",
169 ._tmxmd = &TM8MD,
170 ._tmxbr = &TM8BR,
171 ._tmicr = &TM8ICR,
172 .tm_irq = TM8IRQ,
173 .div_timer = MNSCx_DIV_TIMER_16BIT,
174#else /* CONFIG_MN10300_TTYSM0_TIMER2 */
175 .tm_name = "ttySM0/Timer2",
176 ._tmxmd = &TM2MD,
177 ._tmxbr = (volatile u16 *) &TM2BR,
178 ._tmicr = &TM2ICR,
179 .tm_irq = TM2IRQ,
180 .div_timer = MNSCx_DIV_TIMER_8BIT,
181#endif
182 .rx_irq = SC0RXIRQ,
183 .tx_irq = SC0TXIRQ,
184 .rx_icr = &GxICR(SC0RXIRQ),
185 .tx_icr = &GxICR(SC0TXIRQ),
186 .clock_src = MNSCx_CLOCK_SRC_IOCLK,
187 .options = 0,
188#ifdef CONFIG_GDBSTUB_ON_TTYSM0
189 .gdbstub = 1,
190#endif
191};
192#endif /* CONFIG_MN10300_TTYSM0 */
193
194/*
195 * the second on-chip serial port: ttySM1 (aka SIF1)
196 */
197#ifdef CONFIG_MN10300_TTYSM1
198struct mn10300_serial_port mn10300_serial_port_sif1 = {
199 .uart.ops = &mn10300_serial_ops,
200 .uart.membase = (void __iomem *) &SC1CTR,
201 .uart.mapbase = (unsigned long) &SC1CTR,
202 .uart.iotype = UPIO_MEM,
203 .uart.irq = 0,
204 .uart.uartclk = 0, /* MN10300_IOCLK, */
205 .uart.fifosize = 1,
206 .uart.flags = UPF_BOOT_AUTOCONF,
207 .uart.line = 1,
208 .uart.type = PORT_MN10300,
209 .uart.lock =
210 __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif1.uart.lock),
211 .name = "ttySM1",
212 ._iobase = &SC1CTR,
213 ._control = &SC1CTR,
214 ._status = (volatile u8 *) &SC1STR,
215 ._intr = &SC1ICR,
216 ._rxb = &SC1RXB,
217 ._txb = &SC1TXB,
218 .rx_name = "ttySM1/Rx",
219 .tx_name = "ttySM1/Tx",
220#ifdef CONFIG_MN10300_TTYSM1_TIMER9
221 .tm_name = "ttySM1/Timer9",
222 ._tmxmd = &TM9MD,
223 ._tmxbr = &TM9BR,
224 ._tmicr = &TM9ICR,
225 .tm_irq = TM9IRQ,
226 .div_timer = MNSCx_DIV_TIMER_16BIT,
227#else /* CONFIG_MN10300_TTYSM1_TIMER3 */
228 .tm_name = "ttySM1/Timer3",
229 ._tmxmd = &TM3MD,
230 ._tmxbr = (volatile u16 *) &TM3BR,
231 ._tmicr = &TM3ICR,
232 .tm_irq = TM3IRQ,
233 .div_timer = MNSCx_DIV_TIMER_8BIT,
234#endif
235 .rx_irq = SC1RXIRQ,
236 .tx_irq = SC1TXIRQ,
237 .rx_icr = &GxICR(SC1RXIRQ),
238 .tx_icr = &GxICR(SC1TXIRQ),
239 .clock_src = MNSCx_CLOCK_SRC_IOCLK,
240 .options = 0,
241#ifdef CONFIG_GDBSTUB_ON_TTYSM1
242 .gdbstub = 1,
243#endif
244};
245#endif /* CONFIG_MN10300_TTYSM1 */
246
247/*
248 * the third on-chip serial port: ttySM2 (aka SIF2)
249 */
250#ifdef CONFIG_MN10300_TTYSM2
251struct mn10300_serial_port mn10300_serial_port_sif2 = {
252 .uart.ops = &mn10300_serial_ops,
253 .uart.membase = (void __iomem *) &SC2CTR,
254 .uart.mapbase = (unsigned long) &SC2CTR,
255 .uart.iotype = UPIO_MEM,
256 .uart.irq = 0,
257 .uart.uartclk = 0, /* MN10300_IOCLK, */
258 .uart.fifosize = 1,
259 .uart.flags = UPF_BOOT_AUTOCONF,
260 .uart.line = 2,
261#ifdef CONFIG_MN10300_TTYSM2_CTS
262 .uart.type = PORT_MN10300_CTS,
263#else
264 .uart.type = PORT_MN10300,
265#endif
266 .uart.lock =
267 __SPIN_LOCK_UNLOCKED(mn10300_serial_port_sif2.uart.lock),
268 .name = "ttySM2",
269 .rx_name = "ttySM2/Rx",
270 .tx_name = "ttySM2/Tx",
271 .tm_name = "ttySM2/Timer10",
272 ._iobase = &SC2CTR,
273 ._control = &SC2CTR,
274 ._status = &SC2STR,
275 ._intr = &SC2ICR,
276 ._rxb = &SC2RXB,
277 ._txb = &SC2TXB,
278 ._tmxmd = &TM10MD,
279 ._tmxbr = &TM10BR,
280 ._tmicr = &TM10ICR,
281 .tm_irq = TM10IRQ,
282 .div_timer = MNSCx_DIV_TIMER_16BIT,
283 .rx_irq = SC2RXIRQ,
284 .tx_irq = SC2TXIRQ,
285 .rx_icr = &GxICR(SC2RXIRQ),
286 .tx_icr = &GxICR(SC2TXIRQ),
287 .clock_src = MNSCx_CLOCK_SRC_IOCLK,
288#ifdef CONFIG_MN10300_TTYSM2_CTS
289 .options = MNSCx_OPT_CTS,
290#else
291 .options = 0,
292#endif
293#ifdef CONFIG_GDBSTUB_ON_TTYSM2
294 .gdbstub = 1,
295#endif
296};
297#endif /* CONFIG_MN10300_TTYSM2 */
298
299
300/*
301 * list of available serial ports
302 */
303struct mn10300_serial_port *mn10300_serial_ports[NR_UARTS + 1] = {
304#ifdef CONFIG_MN10300_TTYSM0
305 [0] = &mn10300_serial_port_sif0,
306#endif
307#ifdef CONFIG_MN10300_TTYSM1
308 [1] = &mn10300_serial_port_sif1,
309#endif
310#ifdef CONFIG_MN10300_TTYSM2
311 [2] = &mn10300_serial_port_sif2,
312#endif
313 [NR_UARTS] = NULL,
314};
315
316
317/*
318 * we abuse the serial ports' baud timers' interrupt lines to get the ability
319 * to deliver interrupts to userspace as we use the ports' interrupt lines to
320 * do virtual DMA on account of the ports having no hardware FIFOs
321 *
322 * we can generate an interrupt manually in the assembly stubs by writing to
323 * the enable and detect bits in the interrupt control register, so all we need
324 * to do here is disable the interrupt line
325 *
326 * note that we can't just leave the line enabled as the baud rate timer *also*
327 * generates interrupts
328 */
329static void mn10300_serial_mask_ack(unsigned int irq)
330{
331 u16 tmp;
332 GxICR(irq) = GxICR_LEVEL_6;
333 tmp = GxICR(irq); /* flush write buffer */
334}
335
336static void mn10300_serial_nop(unsigned int irq)
337{
338}
339
340static struct irq_chip mn10300_serial_pic = {
341 .name = "mnserial",
342 .ack = mn10300_serial_mask_ack,
343 .mask = mn10300_serial_mask_ack,
344 .mask_ack = mn10300_serial_mask_ack,
345 .unmask = mn10300_serial_nop,
346 .end = mn10300_serial_nop,
347};
348
349
350/*
351 * serial virtual DMA interrupt jump table
352 */
353struct mn10300_serial_int mn10300_serial_int_tbl[NR_IRQS];
354
355static void mn10300_serial_dis_tx_intr(struct mn10300_serial_port *port)
356{
357 u16 x;
358 *port->tx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
359 x = *port->tx_icr;
360}
361
362static void mn10300_serial_en_tx_intr(struct mn10300_serial_port *port)
363{
364 u16 x;
365 *port->tx_icr = GxICR_LEVEL_1 | GxICR_ENABLE;
366 x = *port->tx_icr;
367}
368
369static void mn10300_serial_dis_rx_intr(struct mn10300_serial_port *port)
370{
371 u16 x;
372 *port->rx_icr = GxICR_LEVEL_1 | GxICR_DETECT;
373 x = *port->rx_icr;
374}
375
376/*
377 * multi-bit equivalent of test_and_clear_bit()
378 */
379static int mask_test_and_clear(volatile u8 *ptr, u8 mask)
380{
381 u32 epsw;
382 asm volatile(" bclr %1,(%2) \n"
383 " mov epsw,%0 \n"
384 : "=d"(epsw) : "d"(mask), "a"(ptr));
385 return !(epsw & EPSW_FLAG_Z);
386}
387
388/*
389 * receive chars from the ring buffer for this serial port
390 * - must do break detection here (not done in the UART)
391 */
392static void mn10300_serial_receive_interrupt(struct mn10300_serial_port *port)
393{
394 struct uart_icount *icount = &port->uart.icount;
395 struct tty_struct *tty = port->uart.info->tty;
396 unsigned ix;
397 int count;
398 u8 st, ch, push, status, overrun;
399
400 _enter("%s", port->name);
401
402 push = 0;
403
404 count = CIRC_CNT(port->rx_inp, port->rx_outp, MNSC_BUFFER_SIZE);
405 count = tty_buffer_request_room(tty, count);
406 if (count == 0) {
407 if (!tty->low_latency)
408 tty_flip_buffer_push(tty);
409 return;
410 }
411
412try_again:
413 /* pull chars out of the hat */
414 ix = port->rx_outp;
415 if (ix == port->rx_inp) {
416 if (push && !tty->low_latency)
417 tty_flip_buffer_push(tty);
418 return;
419 }
420
421 ch = port->rx_buffer[ix++];
422 st = port->rx_buffer[ix++];
423 smp_rmb();
424 port->rx_outp = ix & (MNSC_BUFFER_SIZE - 1);
425 port->uart.icount.rx++;
426
427 st &= SC01STR_FEF | SC01STR_PEF | SC01STR_OEF;
428 status = 0;
429 overrun = 0;
430
431 /* the UART doesn't detect BREAK, so we have to do that ourselves
432 * - it starts as a framing error on a NUL character
433 * - then we count another two NUL characters before issuing TTY_BREAK
434 * - then we end on a normal char or one that has all the bottom bits
435 * zero and the top bits set
436 */
437 switch (port->rx_brk) {
438 case 0:
439 /* not breaking at the moment */
440 break;
441
442 case 1:
443 if (st & SC01STR_FEF && ch == 0) {
444 port->rx_brk = 2;
445 goto try_again;
446 }
447 goto not_break;
448
449 case 2:
450 if (st & SC01STR_FEF && ch == 0) {
451 port->rx_brk = 3;
452 _proto("Rx Break Detected");
453 icount->brk++;
454 if (uart_handle_break(&port->uart))
455 goto ignore_char;
456 status |= 1 << TTY_BREAK;
457 goto insert;
458 }
459 goto not_break;
460
461 default:
462 if (st & (SC01STR_FEF | SC01STR_PEF | SC01STR_OEF))
463 goto try_again; /* still breaking */
464
465 port->rx_brk = 0; /* end of the break */
466
467 switch (ch) {
468 case 0xFF:
469 case 0xFE:
470 case 0xFC:
471 case 0xF8:
472 case 0xF0:
473 case 0xE0:
474 case 0xC0:
475 case 0x80:
476 case 0x00:
477 /* discard char at probable break end */
478 goto try_again;
479 }
480 break;
481 }
482
483process_errors:
484 /* handle framing error */
485 if (st & SC01STR_FEF) {
486 if (ch == 0) {
487 /* framing error with NUL char is probably a BREAK */
488 port->rx_brk = 1;
489 goto try_again;
490 }
491
492 _proto("Rx Framing Error");
493 icount->frame++;
494 status |= 1 << TTY_FRAME;
495 }
496
497 /* handle parity error */
498 if (st & SC01STR_PEF) {
499 _proto("Rx Parity Error");
500 icount->parity++;
501 status = TTY_PARITY;
502 }
503
504 /* handle normal char */
505 if (status == 0) {
506 if (uart_handle_sysrq_char(&port->uart, ch))
507 goto ignore_char;
508 status = (1 << TTY_NORMAL);
509 }
510
511 /* handle overrun error */
512 if (st & SC01STR_OEF) {
513 if (port->rx_brk)
514 goto try_again;
515
516 _proto("Rx Overrun Error");
517 icount->overrun++;
518 overrun = 1;
519 }
520
521insert:
522 status &= port->uart.read_status_mask;
523
524 if (!overrun && !(status & port->uart.ignore_status_mask)) {
525 int flag;
526
527 if (status & (1 << TTY_BREAK))
528 flag = TTY_BREAK;
529 else if (status & (1 << TTY_PARITY))
530 flag = TTY_PARITY;
531 else if (status & (1 << TTY_FRAME))
532 flag = TTY_FRAME;
533 else
534 flag = TTY_NORMAL;
535
536 tty_insert_flip_char(tty, ch, flag);
537 }
538
539 /* overrun is special, since it's reported immediately, and doesn't
540 * affect the current character
541 */
542 if (overrun)
543 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
544
545 count--;
546 if (count <= 0) {
547 if (!tty->low_latency)
548 tty_flip_buffer_push(tty);
549 return;
550 }
551
552ignore_char:
553 push = 1;
554 goto try_again;
555
556not_break:
557 port->rx_brk = 0;
558 goto process_errors;
559}
560
561/*
562 * handle an interrupt from the serial transmission "virtual DMA" driver
563 * - note: the interrupt routine will disable its own interrupts when the Tx
564 * buffer is empty
565 */
566static void mn10300_serial_transmit_interrupt(struct mn10300_serial_port *port)
567{
568 _enter("%s", port->name);
569
570 if (uart_tx_stopped(&port->uart) ||
571 uart_circ_empty(&port->uart.info->xmit))
572 mn10300_serial_dis_tx_intr(port);
573
574 if (uart_circ_chars_pending(&port->uart.info->xmit) < WAKEUP_CHARS)
575 uart_write_wakeup(&port->uart);
576}
577
578/*
579 * deal with a change in the status of the CTS line
580 */
581static void mn10300_serial_cts_changed(struct mn10300_serial_port *port, u8 st)
582{
583 u16 ctr;
584
585 port->tx_cts = st;
586 port->uart.icount.cts++;
587
588 /* flip the CTS state selector flag to interrupt when it changes
589 * back */
590 ctr = *port->_control;
591 ctr ^= SC2CTR_TWS;
592 *port->_control = ctr;
593
594 uart_handle_cts_change(&port->uart, st & SC2STR_CTS);
595 wake_up_interruptible(&port->uart.info->delta_msr_wait);
596}
597
598/*
599 * handle a virtual interrupt generated by the lower level "virtual DMA"
600 * routines (irq is the baud timer interrupt)
601 */
602static irqreturn_t mn10300_serial_interrupt(int irq, void *dev_id)
603{
604 struct mn10300_serial_port *port = dev_id;
605 u8 st;
606
607 spin_lock(&port->uart.lock);
608
609 if (port->intr_flags) {
610 _debug("INT %s: %x", port->name, port->intr_flags);
611
612 if (mask_test_and_clear(&port->intr_flags, MNSCx_RX_AVAIL))
613 mn10300_serial_receive_interrupt(port);
614
615 if (mask_test_and_clear(&port->intr_flags,
616 MNSCx_TX_SPACE | MNSCx_TX_EMPTY))
617 mn10300_serial_transmit_interrupt(port);
618 }
619
620 /* the only modem control line amongst the whole lot is CTS on
621 * serial port 2 */
622 if (port->type == PORT_MN10300_CTS) {
623 st = *port->_status;
624 if ((port->tx_cts ^ st) & SC2STR_CTS)
625 mn10300_serial_cts_changed(port, st);
626 }
627
628 spin_unlock(&port->uart.lock);
629
630 return IRQ_HANDLED;
631}
632
633/*
634 * return indication of whether the hardware transmit buffer is empty
635 */
636static unsigned int mn10300_serial_tx_empty(struct uart_port *_port)
637{
638 struct mn10300_serial_port *port =
639 container_of(_port, struct mn10300_serial_port, uart);
640
641 _enter("%s", port->name);
642
643 return (*port->_status & (SC01STR_TXF | SC01STR_TBF)) ?
644 0 : TIOCSER_TEMT;
645}
646
647/*
648 * set the modem control lines (we don't have any)
649 */
650static void mn10300_serial_set_mctrl(struct uart_port *_port,
651 unsigned int mctrl)
652{
653 struct mn10300_serial_port *port =
654 container_of(_port, struct mn10300_serial_port, uart);
655
656 _enter("%s,%x", port->name, mctrl);
657}
658
659/*
660 * get the modem control line statuses
661 */
662static unsigned int mn10300_serial_get_mctrl(struct uart_port *_port)
663{
664 struct mn10300_serial_port *port =
665 container_of(_port, struct mn10300_serial_port, uart);
666
667 _enter("%s", port->name);
668
669 if (port->type == PORT_MN10300_CTS && !(*port->_status & SC2STR_CTS))
670 return TIOCM_CAR | TIOCM_DSR;
671
672 return TIOCM_CAR | TIOCM_CTS | TIOCM_DSR;
673}
674
675/*
676 * stop transmitting characters
677 */
678static void mn10300_serial_stop_tx(struct uart_port *_port)
679{
680 struct mn10300_serial_port *port =
681 container_of(_port, struct mn10300_serial_port, uart);
682
683 _enter("%s", port->name);
684
685 /* disable the virtual DMA */
686 mn10300_serial_dis_tx_intr(port);
687}
688
689/*
690 * start transmitting characters
691 * - jump-start transmission if it has stalled
692 * - enable the serial Tx interrupt (used by the virtual DMA controller)
693 * - force an interrupt to happen if necessary
694 */
695static void mn10300_serial_start_tx(struct uart_port *_port)
696{
697 struct mn10300_serial_port *port =
698 container_of(_port, struct mn10300_serial_port, uart);
699
700 u16 x;
701
702 _enter("%s{%lu}",
703 port->name,
704 CIRC_CNT(&port->uart.info->xmit.head,
705 &port->uart.info->xmit.tail,
706 UART_XMIT_SIZE));
707
708 /* kick the virtual DMA controller */
709 x = *port->tx_icr;
710 x |= GxICR_ENABLE;
711
712 if (*port->_status & SC01STR_TBF)
713 x &= ~(GxICR_REQUEST | GxICR_DETECT);
714 else
715 x |= GxICR_REQUEST | GxICR_DETECT;
716
717 _debug("CTR=%04hx ICR=%02hx STR=%04x TMD=%02hx TBR=%04hx ICR=%04hx",
718 *port->_control, *port->_intr, *port->_status,
719 *port->_tmxmd, *port->_tmxbr, *port->tx_icr);
720
721 *port->tx_icr = x;
722 x = *port->tx_icr;
723}
724
725/*
726 * transmit a high-priority XON/XOFF character
727 */
728static void mn10300_serial_send_xchar(struct uart_port *_port, char ch)
729{
730 struct mn10300_serial_port *port =
731 container_of(_port, struct mn10300_serial_port, uart);
732
733 _enter("%s,%02x", port->name, ch);
734
735 if (likely(port->gdbstub)) {
736 port->tx_xchar = ch;
737 if (ch)
738 mn10300_serial_en_tx_intr(port);
739 }
740}
741
742/*
743 * stop receiving characters
744 * - called whilst the port is being closed
745 */
746static void mn10300_serial_stop_rx(struct uart_port *_port)
747{
748 struct mn10300_serial_port *port =
749 container_of(_port, struct mn10300_serial_port, uart);
750
751 u16 ctr;
752
753 _enter("%s", port->name);
754
755 ctr = *port->_control;
756 ctr &= ~SC01CTR_RXE;
757 *port->_control = ctr;
758
759 mn10300_serial_dis_rx_intr(port);
760}
761
762/*
763 * enable modem status interrupts
764 */
765static void mn10300_serial_enable_ms(struct uart_port *_port)
766{
767 struct mn10300_serial_port *port =
768 container_of(_port, struct mn10300_serial_port, uart);
769
770 u16 ctr, cts;
771
772 _enter("%s", port->name);
773
774 if (port->type == PORT_MN10300_CTS) {
775 /* want to interrupt when CTS goes low if CTS is now high and
776 * vice versa
777 */
778 port->tx_cts = *port->_status;
779
780 cts = (port->tx_cts & SC2STR_CTS) ?
781 SC2CTR_TWE : SC2CTR_TWE | SC2CTR_TWS;
782
783 ctr = *port->_control;
784 ctr &= ~SC2CTR_TWS;
785 ctr |= cts;
786 *port->_control = ctr;
787
788 mn10300_serial_en_tx_intr(port);
789 }
790}
791
792/*
793 * transmit or cease transmitting a break signal
794 */
795static void mn10300_serial_break_ctl(struct uart_port *_port, int ctl)
796{
797 struct mn10300_serial_port *port =
798 container_of(_port, struct mn10300_serial_port, uart);
799
800 _enter("%s,%d", port->name, ctl);
801
802 if (ctl) {
803 /* tell the virtual DMA handler to assert BREAK */
804 port->tx_break = 1;
805 mn10300_serial_en_tx_intr(port);
806 } else {
807 port->tx_break = 0;
808 *port->_control &= ~SC01CTR_BKE;
809 mn10300_serial_en_tx_intr(port);
810 }
811}
812
813/*
814 * grab the interrupts and enable the port for reception
815 */
816static int mn10300_serial_startup(struct uart_port *_port)
817{
818 struct mn10300_serial_port *port =
819 container_of(_port, struct mn10300_serial_port, uart);
820 struct mn10300_serial_int *pint;
821
822 _enter("%s{%d}", port->name, port->gdbstub);
823
824 if (unlikely(port->gdbstub))
825 return -EBUSY;
826
827 /* allocate an Rx buffer for the virtual DMA handler */
828 port->rx_buffer = kmalloc(MNSC_BUFFER_SIZE, GFP_KERNEL);
829 if (!port->rx_buffer)
830 return -ENOMEM;
831
832 port->rx_inp = port->rx_outp = 0;
833
834 /* finally, enable the device */
835 *port->_intr = SC01ICR_TI;
836 *port->_control |= SC01CTR_TXE | SC01CTR_RXE;
837
838 pint = &mn10300_serial_int_tbl[port->rx_irq];
839 pint->port = port;
840 pint->vdma = mn10300_serial_vdma_rx_handler;
841 pint = &mn10300_serial_int_tbl[port->tx_irq];
842 pint->port = port;
843 pint->vdma = mn10300_serial_vdma_tx_handler;
844
845 set_intr_level(port->rx_irq, GxICR_LEVEL_1);
846 set_intr_level(port->tx_irq, GxICR_LEVEL_1);
847 set_irq_chip(port->tm_irq, &mn10300_serial_pic);
848
849 if (request_irq(port->rx_irq, mn10300_serial_interrupt,
850 IRQF_DISABLED, port->rx_name, port) < 0)
851 goto error;
852
853 if (request_irq(port->tx_irq, mn10300_serial_interrupt,
854 IRQF_DISABLED, port->tx_name, port) < 0)
855 goto error2;
856
857 if (request_irq(port->tm_irq, mn10300_serial_interrupt,
858 IRQF_DISABLED, port->tm_name, port) < 0)
859 goto error3;
860 mn10300_serial_mask_ack(port->tm_irq);
861
862 return 0;
863
864error3:
865 free_irq(port->tx_irq, port);
866error2:
867 free_irq(port->rx_irq, port);
868error:
869 kfree(port->rx_buffer);
870 port->rx_buffer = NULL;
871 return -EBUSY;
872}
873
874/*
875 * shutdown the port and release interrupts
876 */
877static void mn10300_serial_shutdown(struct uart_port *_port)
878{
879 struct mn10300_serial_port *port =
880 container_of(_port, struct mn10300_serial_port, uart);
881
882 _enter("%s", port->name);
883
884 /* disable the serial port and its baud rate timer */
885 port->tx_break = 0;
886 *port->_control &= ~(SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE);
887 *port->_tmxmd = 0;
888
889 if (port->rx_buffer) {
890 void *buf = port->rx_buffer;
891 port->rx_buffer = NULL;
892 kfree(buf);
893 }
894
895 /* disable all intrs */
896 free_irq(port->tm_irq, port);
897 free_irq(port->rx_irq, port);
898 free_irq(port->tx_irq, port);
899
900 *port->rx_icr = GxICR_LEVEL_1;
901 *port->tx_icr = GxICR_LEVEL_1;
902}
903
904/*
905 * this routine is called to set the UART divisor registers to match the
906 * specified baud rate for a serial port.
907 */
908static void mn10300_serial_change_speed(struct mn10300_serial_port *port,
909 struct ktermios *new,
910 struct ktermios *old)
911{
912 unsigned long flags;
913 unsigned long ioclk = port->ioclk;
914 unsigned cflag;
915 int baud, bits, xdiv, tmp;
916 u16 tmxbr, scxctr;
917 u8 tmxmd, battempt;
918 u8 div_timer = port->div_timer;
919
920 _enter("%s{%lu}", port->name, ioclk);
921
922 /* byte size and parity */
923 cflag = new->c_cflag;
924 switch (cflag & CSIZE) {
925 case CS7: scxctr = SC01CTR_CLN_7BIT; bits = 9; break;
926 case CS8: scxctr = SC01CTR_CLN_8BIT; bits = 10; break;
927 default: scxctr = SC01CTR_CLN_8BIT; bits = 10; break;
928 }
929
930 if (cflag & CSTOPB) {
931 scxctr |= SC01CTR_STB_2BIT;
932 bits++;
933 }
934
935 if (cflag & PARENB) {
936 bits++;
937 if (cflag & PARODD)
938 scxctr |= SC01CTR_PB_ODD;
939#ifdef CMSPAR
940 else if (cflag & CMSPAR)
941 scxctr |= SC01CTR_PB_FIXED0;
942#endif
943 else
944 scxctr |= SC01CTR_PB_EVEN;
945 }
946
947 /* Determine divisor based on baud rate */
948 battempt = 0;
949
950 if (div_timer == MNSCx_DIV_TIMER_16BIT)
951 scxctr |= SC0CTR_CK_TM8UFLOW_8; /* ( == SC1CTR_CK_TM9UFLOW_8
952 * == SC2CTR_CK_TM10UFLOW) */
953 else if (div_timer == MNSCx_DIV_TIMER_8BIT)
954 scxctr |= SC0CTR_CK_TM2UFLOW_8;
955
956try_alternative:
957 baud = uart_get_baud_rate(&port->uart, new, old, 0,
958 port->ioclk / 8);
959
960 _debug("ALT %d [baud %d]", battempt, baud);
961
962 if (!baud)
963 baud = 9600; /* B0 transition handled in rs_set_termios */
964 xdiv = 1;
965 if (baud == 134) {
966 baud = 269; /* 134 is really 134.5 */
967 xdiv = 2;
968 }
969
970 if (baud == 38400 &&
971 (port->uart.flags & UPF_SPD_MASK) == UPF_SPD_CUST
972 ) {
973 _debug("CUSTOM %u", port->uart.custom_divisor);
974
975 if (div_timer == MNSCx_DIV_TIMER_16BIT) {
976 if (port->uart.custom_divisor <= 65535) {
977 tmxmd = TM8MD_SRC_IOCLK;
978 tmxbr = port->uart.custom_divisor;
979 port->uart.uartclk = ioclk;
980 goto timer_okay;
981 }
982 if (port->uart.custom_divisor / 8 <= 65535) {
983 tmxmd = TM8MD_SRC_IOCLK_8;
984 tmxbr = port->uart.custom_divisor / 8;
985 port->uart.custom_divisor = tmxbr * 8;
986 port->uart.uartclk = ioclk / 8;
987 goto timer_okay;
988 }
989 if (port->uart.custom_divisor / 32 <= 65535) {
990 tmxmd = TM8MD_SRC_IOCLK_32;
991 tmxbr = port->uart.custom_divisor / 32;
992 port->uart.custom_divisor = tmxbr * 32;
993 port->uart.uartclk = ioclk / 32;
994 goto timer_okay;
995 }
996
997 } else if (div_timer == MNSCx_DIV_TIMER_8BIT) {
998 if (port->uart.custom_divisor <= 255) {
999 tmxmd = TM2MD_SRC_IOCLK;
1000 tmxbr = port->uart.custom_divisor;
1001 port->uart.uartclk = ioclk;
1002 goto timer_okay;
1003 }
1004 if (port->uart.custom_divisor / 8 <= 255) {
1005 tmxmd = TM2MD_SRC_IOCLK_8;
1006 tmxbr = port->uart.custom_divisor / 8;
1007 port->uart.custom_divisor = tmxbr * 8;
1008 port->uart.uartclk = ioclk / 8;
1009 goto timer_okay;
1010 }
1011 if (port->uart.custom_divisor / 32 <= 255) {
1012 tmxmd = TM2MD_SRC_IOCLK_32;
1013 tmxbr = port->uart.custom_divisor / 32;
1014 port->uart.custom_divisor = tmxbr * 32;
1015 port->uart.uartclk = ioclk / 32;
1016 goto timer_okay;
1017 }
1018 }
1019 }
1020
1021 switch (div_timer) {
1022 case MNSCx_DIV_TIMER_16BIT:
1023 port->uart.uartclk = ioclk;
1024 tmxmd = TM8MD_SRC_IOCLK;
1025 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
1026 if (tmp > 0 && tmp <= 65535)
1027 goto timer_okay;
1028
1029 port->uart.uartclk = ioclk / 8;
1030 tmxmd = TM8MD_SRC_IOCLK_8;
1031 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
1032 if (tmp > 0 && tmp <= 65535)
1033 goto timer_okay;
1034
1035 port->uart.uartclk = ioclk / 32;
1036 tmxmd = TM8MD_SRC_IOCLK_32;
1037 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
1038 if (tmp > 0 && tmp <= 65535)
1039 goto timer_okay;
1040 break;
1041
1042 case MNSCx_DIV_TIMER_8BIT:
1043 port->uart.uartclk = ioclk;
1044 tmxmd = TM2MD_SRC_IOCLK;
1045 tmxbr = tmp = (ioclk / (baud * xdiv) + 4) / 8 - 1;
1046 if (tmp > 0 && tmp <= 255)
1047 goto timer_okay;
1048
1049 port->uart.uartclk = ioclk / 8;
1050 tmxmd = TM2MD_SRC_IOCLK_8;
1051 tmxbr = tmp = (ioclk / (baud * 8 * xdiv) + 4) / 8 - 1;
1052 if (tmp > 0 && tmp <= 255)
1053 goto timer_okay;
1054
1055 port->uart.uartclk = ioclk / 32;
1056 tmxmd = TM2MD_SRC_IOCLK_32;
1057 tmxbr = tmp = (ioclk / (baud * 32 * xdiv) + 4) / 8 - 1;
1058 if (tmp > 0 && tmp <= 255)
1059 goto timer_okay;
1060 break;
1061
1062 default:
1063 BUG();
1064 return;
1065 }
1066
1067 /* refuse to change to a baud rate we can't support */
1068 _debug("CAN'T SUPPORT");
1069
1070 switch (battempt) {
1071 case 0:
1072 if (old) {
1073 new->c_cflag &= ~CBAUD;
1074 new->c_cflag |= (old->c_cflag & CBAUD);
1075 battempt = 1;
1076 goto try_alternative;
1077 }
1078
1079 case 1:
1080 /* as a last resort, if the quotient is zero, default to 9600
1081 * bps */
1082 new->c_cflag &= ~CBAUD;
1083 new->c_cflag |= B9600;
1084 battempt = 2;
1085 goto try_alternative;
1086
1087 default:
1088 /* hmmm... can't seem to support 9600 either
1089 * - we could try iterating through the speeds we know about to
1090 * find the lowest
1091 */
1092 new->c_cflag &= ~CBAUD;
1093 new->c_cflag |= B0;
1094
1095 if (div_timer == MNSCx_DIV_TIMER_16BIT)
1096 tmxmd = TM8MD_SRC_IOCLK_32;
1097 else if (div_timer == MNSCx_DIV_TIMER_8BIT)
1098 tmxmd = TM2MD_SRC_IOCLK_32;
1099 tmxbr = 1;
1100
1101 port->uart.uartclk = ioclk / 32;
1102 break;
1103 }
1104timer_okay:
1105
1106 _debug("UARTCLK: %u / %hu", port->uart.uartclk, tmxbr);
1107
1108 /* make the changes */
1109 spin_lock_irqsave(&port->uart.lock, flags);
1110
1111 uart_update_timeout(&port->uart, new->c_cflag, baud);
1112
1113 /* set the timer to produce the required baud rate */
1114 switch (div_timer) {
1115 case MNSCx_DIV_TIMER_16BIT:
1116 *port->_tmxmd = 0;
1117 *port->_tmxbr = tmxbr;
1118 *port->_tmxmd = TM8MD_INIT_COUNTER;
1119 *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
1120 break;
1121
1122 case MNSCx_DIV_TIMER_8BIT:
1123 *port->_tmxmd = 0;
1124 *(volatile u8 *) port->_tmxbr = (u8) tmxbr;
1125 *port->_tmxmd = TM2MD_INIT_COUNTER;
1126 *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
1127 break;
1128 }
1129
1130 /* CTS flow control flag and modem status interrupts */
1131 scxctr &= ~(SC2CTR_TWE | SC2CTR_TWS);
1132
1133 if (port->type == PORT_MN10300_CTS && cflag & CRTSCTS) {
1134 /* want to interrupt when CTS goes low if CTS is now
1135 * high and vice versa
1136 */
1137 port->tx_cts = *port->_status;
1138
1139 if (port->tx_cts & SC2STR_CTS)
1140 scxctr |= SC2CTR_TWE;
1141 else
1142 scxctr |= SC2CTR_TWE | SC2CTR_TWS;
1143 }
1144
1145 /* set up parity check flag */
1146 port->uart.read_status_mask = (1 << TTY_NORMAL) | (1 << TTY_OVERRUN);
1147 if (new->c_iflag & INPCK)
1148 port->uart.read_status_mask |=
1149 (1 << TTY_PARITY) | (1 << TTY_FRAME);
1150 if (new->c_iflag & (BRKINT | PARMRK))
1151 port->uart.read_status_mask |= (1 << TTY_BREAK);
1152
1153 /* characters to ignore */
1154 port->uart.ignore_status_mask = 0;
1155 if (new->c_iflag & IGNPAR)
1156 port->uart.ignore_status_mask |=
1157 (1 << TTY_PARITY) | (1 << TTY_FRAME);
1158 if (new->c_iflag & IGNBRK) {
1159 port->uart.ignore_status_mask |= (1 << TTY_BREAK);
1160 /*
1161 * If we're ignoring parity and break indicators,
1162 * ignore overruns to (for real raw support).
1163 */
1164 if (new->c_iflag & IGNPAR)
1165 port->uart.ignore_status_mask |= (1 << TTY_OVERRUN);
1166 }
1167
1168 /* Ignore all characters if CREAD is not set */
1169 if ((new->c_cflag & CREAD) == 0)
1170 port->uart.ignore_status_mask |= (1 << TTY_NORMAL);
1171
1172 scxctr |= *port->_control & (SC01CTR_TXE | SC01CTR_RXE | SC01CTR_BKE);
1173 *port->_control = scxctr;
1174
1175 spin_unlock_irqrestore(&port->uart.lock, flags);
1176}
1177
1178/*
1179 * set the terminal I/O parameters
1180 */
1181static void mn10300_serial_set_termios(struct uart_port *_port,
1182 struct ktermios *new,
1183 struct ktermios *old)
1184{
1185 struct mn10300_serial_port *port =
1186 container_of(_port, struct mn10300_serial_port, uart);
1187
1188 _enter("%s,%p,%p", port->name, new, old);
1189
1190 mn10300_serial_change_speed(port, new, old);
1191
1192 /* handle turning off CRTSCTS */
1193 if (!(new->c_cflag & CRTSCTS)) {
1194 u16 ctr = *port->_control;
1195 ctr &= ~SC2CTR_TWE;
1196 *port->_control = ctr;
1197 }
1198}
1199
1200/*
1201 * return description of port type
1202 */
1203static const char *mn10300_serial_type(struct uart_port *_port)
1204{
1205 struct mn10300_serial_port *port =
1206 container_of(_port, struct mn10300_serial_port, uart);
1207
1208 if (port->uart.type == PORT_MN10300_CTS)
1209 return "MN10300 SIF_CTS";
1210
1211 return "MN10300 SIF";
1212}
1213
1214/*
1215 * release I/O and memory regions in use by port
1216 */
1217static void mn10300_serial_release_port(struct uart_port *_port)
1218{
1219 struct mn10300_serial_port *port =
1220 container_of(_port, struct mn10300_serial_port, uart);
1221
1222 _enter("%s", port->name);
1223
1224 release_mem_region((unsigned long) port->_iobase, 16);
1225}
1226
1227/*
1228 * request I/O and memory regions for port
1229 */
1230static int mn10300_serial_request_port(struct uart_port *_port)
1231{
1232 struct mn10300_serial_port *port =
1233 container_of(_port, struct mn10300_serial_port, uart);
1234
1235 _enter("%s", port->name);
1236
1237 request_mem_region((unsigned long) port->_iobase, 16, port->name);
1238 return 0;
1239}
1240
1241/*
1242 * configure the type and reserve the ports
1243 */
1244static void mn10300_serial_config_port(struct uart_port *_port, int type)
1245{
1246 struct mn10300_serial_port *port =
1247 container_of(_port, struct mn10300_serial_port, uart);
1248
1249 _enter("%s", port->name);
1250
1251 port->uart.type = PORT_MN10300;
1252
1253 if (port->options & MNSCx_OPT_CTS)
1254 port->uart.type = PORT_MN10300_CTS;
1255
1256 mn10300_serial_request_port(_port);
1257}
1258
1259/*
1260 * verify serial parameters are suitable for this port type
1261 */
1262static int mn10300_serial_verify_port(struct uart_port *_port,
1263 struct serial_struct *ss)
1264{
1265 struct mn10300_serial_port *port =
1266 container_of(_port, struct mn10300_serial_port, uart);
1267 void *mapbase = (void *) (unsigned long) port->uart.mapbase;
1268
1269 _enter("%s", port->name);
1270
1271 /* these things may not be changed */
1272 if (ss->irq != port->uart.irq ||
1273 ss->port != port->uart.iobase ||
1274 ss->io_type != port->uart.iotype ||
1275 ss->iomem_base != mapbase ||
1276 ss->iomem_reg_shift != port->uart.regshift ||
1277 ss->hub6 != port->uart.hub6 ||
1278 ss->xmit_fifo_size != port->uart.fifosize)
1279 return -EINVAL;
1280
1281 /* type may be changed on a port that supports CTS */
1282 if (ss->type != port->uart.type) {
1283 if (!(port->options & MNSCx_OPT_CTS))
1284 return -EINVAL;
1285
1286 if (ss->type != PORT_MN10300 &&
1287 ss->type != PORT_MN10300_CTS)
1288 return -EINVAL;
1289 }
1290
1291 return 0;
1292}
1293
1294/*
1295 * initialise the MN10300 on-chip UARTs
1296 */
1297static int __init mn10300_serial_init(void)
1298{
1299 struct mn10300_serial_port *port;
1300 int ret, i;
1301
1302 printk(KERN_INFO "%s version %s (%s)\n",
1303 serial_name, serial_version, serial_revdate);
1304
1305#ifdef CONFIG_MN10300_TTYSM2
1306 SC2TIM = 8; /* make the baud base of timer 2 IOCLK/8 */
1307#endif
1308
1309 set_intr_stub(EXCEP_IRQ_LEVEL1, mn10300_serial_vdma_interrupt);
1310
1311 ret = uart_register_driver(&mn10300_serial_driver);
1312 if (!ret) {
1313 for (i = 0 ; i < NR_PORTS ; i++) {
1314 port = mn10300_serial_ports[i];
1315 if (!port || port->gdbstub)
1316 continue;
1317
1318 switch (port->clock_src) {
1319 case MNSCx_CLOCK_SRC_IOCLK:
1320 port->ioclk = MN10300_IOCLK;
1321 break;
1322
1323#ifdef MN10300_IOBCLK
1324 case MNSCx_CLOCK_SRC_IOBCLK:
1325 port->ioclk = MN10300_IOBCLK;
1326 break;
1327#endif
1328 default:
1329 BUG();
1330 }
1331
1332 ret = uart_add_one_port(&mn10300_serial_driver,
1333 &port->uart);
1334
1335 if (ret < 0) {
1336 _debug("ERROR %d", -ret);
1337 break;
1338 }
1339 }
1340
1341 if (ret)
1342 uart_unregister_driver(&mn10300_serial_driver);
1343 }
1344
1345 return ret;
1346}
1347
1348__initcall(mn10300_serial_init);
1349
1350
1351#ifdef CONFIG_MN10300_TTYSM_CONSOLE
1352
1353/*
1354 * print a string to the serial port without disturbing the real user of the
1355 * port too much
1356 * - the console must be locked by the caller
1357 */
1358static void mn10300_serial_console_write(struct console *co,
1359 const char *s, unsigned count)
1360{
1361 struct mn10300_serial_port *port;
1362 unsigned i;
1363 u16 scxctr, txicr, tmp;
1364 u8 tmxmd;
1365
1366 port = mn10300_serial_ports[co->index];
1367
1368 /* firstly hijack the serial port from the "virtual DMA" controller */
1369 txicr = *port->tx_icr;
1370 *port->tx_icr = GxICR_LEVEL_1;
1371 tmp = *port->tx_icr;
1372
1373 /* the transmitter may be disabled */
1374 scxctr = *port->_control;
1375 if (!(scxctr & SC01CTR_TXE)) {
1376 /* restart the UART clock */
1377 tmxmd = *port->_tmxmd;
1378
1379 switch (port->div_timer) {
1380 case MNSCx_DIV_TIMER_16BIT:
1381 *port->_tmxmd = 0;
1382 *port->_tmxmd = TM8MD_INIT_COUNTER;
1383 *port->_tmxmd = tmxmd | TM8MD_COUNT_ENABLE;
1384 break;
1385
1386 case MNSCx_DIV_TIMER_8BIT:
1387 *port->_tmxmd = 0;
1388 *port->_tmxmd = TM2MD_INIT_COUNTER;
1389 *port->_tmxmd = tmxmd | TM2MD_COUNT_ENABLE;
1390 break;
1391 }
1392
1393 /* enable the transmitter */
1394 *port->_control = (scxctr & ~SC01CTR_BKE) | SC01CTR_TXE;
1395
1396 } else if (scxctr & SC01CTR_BKE) {
1397 /* stop transmitting BREAK */
1398 *port->_control = (scxctr & ~SC01CTR_BKE);
1399 }
1400
1401 /* send the chars into the serial port (with LF -> LFCR conversion) */
1402 for (i = 0; i < count; i++) {
1403 char ch = *s++;
1404
1405 while (*port->_status & SC01STR_TBF)
1406 continue;
1407 *(u8 *) port->_txb = ch;
1408
1409 if (ch == 0x0a) {
1410 while (*port->_status & SC01STR_TBF)
1411 continue;
1412 *(u8 *) port->_txb = 0xd;
1413 }
1414 }
1415
1416 /* can't let the transmitter be turned off if it's actually
1417 * transmitting */
1418 while (*port->_status & (SC01STR_TXF | SC01STR_TBF))
1419 continue;
1420
1421 /* disable the transmitter if we re-enabled it */
1422 if (!(scxctr & SC01CTR_TXE))
1423 *port->_control = scxctr;
1424
1425 *port->tx_icr = txicr;
1426 tmp = *port->tx_icr;
1427}
1428
1429/*
1430 * set up a serial port as a console
1431 * - construct a cflag setting for the first rs_open()
1432 * - initialize the serial port
1433 * - return non-zero if we didn't find a serial port.
1434 */
1435static int __init mn10300_serial_console_setup(struct console *co,
1436 char *options)
1437{
1438 struct mn10300_serial_port *port;
1439 int i, parity = 'n', baud = 9600, bits = 8, flow = 0;
1440
1441 for (i = 0 ; i < NR_PORTS ; i++) {
1442 port = mn10300_serial_ports[i];
1443 if (port && !port->gdbstub && port->uart.line == co->index)
1444 goto found_device;
1445 }
1446
1447 return -ENODEV;
1448
1449found_device:
1450 switch (port->clock_src) {
1451 case MNSCx_CLOCK_SRC_IOCLK:
1452 port->ioclk = MN10300_IOCLK;
1453 break;
1454
1455#ifdef MN10300_IOBCLK
1456 case MNSCx_CLOCK_SRC_IOBCLK:
1457 port->ioclk = MN10300_IOBCLK;
1458 break;
1459#endif
1460 default:
1461 BUG();
1462 }
1463
1464 if (options)
1465 uart_parse_options(options, &baud, &parity, &bits, &flow);
1466
1467 return uart_set_options(&port->uart, co, baud, parity, bits, flow);
1468}
1469
1470/*
1471 * register console
1472 */
1473static int __init mn10300_serial_console_init(void)
1474{
1475 register_console(&mn10300_serial_console);
1476 return 0;
1477}
1478
1479console_initcall(mn10300_serial_console_init);
1480#endif
diff --git a/arch/mn10300/kernel/mn10300-serial.h b/arch/mn10300/kernel/mn10300-serial.h
new file mode 100644
index 000000000000..6796499bf789
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-serial.h
@@ -0,0 +1,126 @@
1/* MN10300 On-chip serial port driver definitions
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#ifndef _MN10300_SERIAL_H
12#define _MN10300_SERIAL_H
13
14#ifndef __ASSEMBLY__
15#include <linux/serial_core.h>
16#include <linux/termios.h>
17#endif
18
19#include <asm/page.h>
20#include <asm/serial-regs.h>
21
22#define NR_PORTS 3 /* should be set 3 or 9 or 16 */
23
24#define MNSC_BUFFER_SIZE +(PAGE_SIZE / 2)
25
26/* intr_flags bits */
27#define MNSCx_RX_AVAIL 0x01
28#define MNSCx_RX_OVERF 0x02
29#define MNSCx_TX_SPACE 0x04
30#define MNSCx_TX_EMPTY 0x08
31
32#ifndef __ASSEMBLY__
33
34struct mn10300_serial_port {
35 char *rx_buffer; /* reception buffer base */
36 unsigned rx_inp; /* pointer to rx input offset */
37 unsigned rx_outp; /* pointer to rx output offset */
38 u8 tx_xchar; /* high-priority XON/XOFF buffer */
39 u8 tx_break; /* transmit break request */
40 u8 intr_flags; /* interrupt flags */
41 volatile u16 *rx_icr; /* Rx interrupt control register */
42 volatile u16 *tx_icr; /* Tx interrupt control register */
43 int rx_irq; /* reception IRQ */
44 int tx_irq; /* transmission IRQ */
45 int tm_irq; /* timer IRQ */
46
47 const char *name; /* name of serial port */
48 const char *rx_name; /* Rx interrupt handler name of serial port */
49 const char *tx_name; /* Tx interrupt handler name of serial port */
50 const char *tm_name; /* Timer interrupt handler name */
51 unsigned short type; /* type of serial port */
52 unsigned char isconsole; /* T if it's a console */
53 volatile void *_iobase; /* pointer to base of I/O control regs */
54 volatile u16 *_control; /* control register pointer */
55 volatile u8 *_status; /* status register pointer */
56 volatile u8 *_intr; /* interrupt register pointer */
57 volatile void *_rxb; /* receive buffer register pointer */
58 volatile void *_txb; /* transmit buffer register pointer */
59 volatile u16 *_tmicr; /* timer interrupt control register */
60 volatile u8 *_tmxmd; /* baud rate timer mode register */
61 volatile u16 *_tmxbr; /* baud rate timer base register */
62
63 /* this must come down here so that assembly can use BSET to access the
64 * above fields */
65 struct uart_port uart;
66
67 unsigned short rx_brk; /* current break reception status */
68 u16 tx_cts; /* current CTS status */
69 int gdbstub; /* preemptively stolen by GDB stub */
70
71 u8 clock_src; /* clock source */
72#define MNSCx_CLOCK_SRC_IOCLK 0
73#define MNSCx_CLOCK_SRC_IOBCLK 1
74
75 u8 div_timer; /* timer used as divisor */
76#define MNSCx_DIV_TIMER_16BIT 0
77#define MNSCx_DIV_TIMER_8BIT 1
78
79 u16 options; /* options */
80#define MNSCx_OPT_CTS 0x0001
81
82 unsigned long ioclk; /* base clock rate */
83};
84
85#ifdef CONFIG_MN10300_TTYSM0
86extern struct mn10300_serial_port mn10300_serial_port_sif0;
87#endif
88
89#ifdef CONFIG_MN10300_TTYSM1
90extern struct mn10300_serial_port mn10300_serial_port_sif1;
91#endif
92
93#ifdef CONFIG_MN10300_TTYSM2
94extern struct mn10300_serial_port mn10300_serial_port_sif2;
95#endif
96
97extern struct mn10300_serial_port *mn10300_serial_ports[];
98
99struct mn10300_serial_int {
100 struct mn10300_serial_port *port;
101 asmlinkage void (*vdma)(void);
102};
103
104extern struct mn10300_serial_int mn10300_serial_int_tbl[];
105
106extern asmlinkage void mn10300_serial_vdma_interrupt(void);
107extern asmlinkage void mn10300_serial_vdma_rx_handler(void);
108extern asmlinkage void mn10300_serial_vdma_tx_handler(void);
109
110#endif /* __ASSEMBLY__ */
111
112#if defined(CONFIG_GDBSTUB_ON_TTYSM0)
113#define SCgSTR SC0STR
114#define SCgRXB SC0RXB
115#define SCgRXIRQ SC0RXIRQ
116#elif defined(CONFIG_GDBSTUB_ON_TTYSM1)
117#define SCgSTR SC1STR
118#define SCgRXB SC1RXB
119#define SCgRXIRQ SC1RXIRQ
120#elif defined(CONFIG_GDBSTUB_ON_TTYSM2)
121#define SCgSTR SC2STR
122#define SCgRXB SC2RXB
123#define SCgRXIRQ SC2RXIRQ
124#endif
125
126#endif /* _MN10300_SERIAL_H */
diff --git a/arch/mn10300/kernel/mn10300-watchdog-low.S b/arch/mn10300/kernel/mn10300-watchdog-low.S
new file mode 100644
index 000000000000..996244745cca
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-watchdog-low.S
@@ -0,0 +1,59 @@
1###############################################################################
2#
3# MN10300 Watchdog interrupt handler
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/intctl-regs.h>
17#include <asm/timer-regs.h>
18#include <asm/frame.inc>
19
20 .text
21
22###############################################################################
23#
24# Watchdog handler entry point
25# - special non-maskable interrupt
26#
27###############################################################################
28 .globl watchdog_handler
29 .type watchdog_handler,@function
30watchdog_handler:
31 add -4,sp
32 SAVE_ALL
33
34 mov 0xffffffff,d0
35 mov d0,(REG_ORIG_D0,fp)
36
37 mov fp,d0
38 lsr 2,d1
39 call watchdog_interrupt[],0 # watchdog_interrupt(regs,irq)
40
41 jmp ret_from_intr
42
43 .size watchdog_handler,.-watchdog_handler
44
45###############################################################################
46#
47# Watchdog touch entry point
48# - kept to absolute minimum (unfortunately, it's prototyped in linux/nmi.h so
49# we can't inline it)
50#
51###############################################################################
52 .globl touch_nmi_watchdog
53 .type touch_nmi_watchdog,@function
54touch_nmi_watchdog:
55 clr d0
56 mov d0,(watchdog_alert_counter)
57 ret [],0
58
59 .size touch_nmi_watchdog,.-touch_nmi_watchdog
diff --git a/arch/mn10300/kernel/mn10300-watchdog.c b/arch/mn10300/kernel/mn10300-watchdog.c
new file mode 100644
index 000000000000..10811e981d20
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300-watchdog.c
@@ -0,0 +1,183 @@
1/* MN10300 Watchdog timer
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/i386/kernel/nmi.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/module.h>
13#include <linux/sched.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/interrupt.h>
18#include <linux/kernel_stat.h>
19#include <linux/nmi.h>
20#include <asm/processor.h>
21#include <asm/system.h>
22#include <asm/atomic.h>
23#include <asm/intctl-regs.h>
24#include <asm/rtc-regs.h>
25#include <asm/div64.h>
26#include <asm/smp.h>
27#include <asm/gdb-stub.h>
28#include <asm/proc/clock.h>
29
30static DEFINE_SPINLOCK(watchdog_print_lock);
31static unsigned int watchdog;
32static unsigned int watchdog_hz = 1;
33unsigned int watchdog_alert_counter;
34
35EXPORT_SYMBOL(touch_nmi_watchdog);
36
37/*
38 * the best way to detect whether a CPU has a 'hard lockup' problem
39 * is to check its timer makes IRQ counts. If they are not
40 * changing then that CPU has some problem.
41 *
42 * as these watchdog NMI IRQs are generated on every CPU, we only
43 * have to check the current processor.
44 *
45 * since NMIs dont listen to _any_ locks, we have to be extremely
46 * careful not to rely on unsafe variables. The printk might lock
47 * up though, so we have to break up any console locks first ...
48 * [when there will be more tty-related locks, break them up
49 * here too!]
50 */
51static unsigned int last_irq_sums[NR_CPUS];
52
53int __init check_watchdog(void)
54{
55 irq_cpustat_t tmp[1];
56
57 printk(KERN_INFO "Testing Watchdog... ");
58
59 memcpy(tmp, irq_stat, sizeof(tmp));
60 local_irq_enable();
61 mdelay((10 * 1000) / watchdog_hz); /* wait 10 ticks */
62 local_irq_disable();
63
64 if (nmi_count(0) - tmp[0].__nmi_count <= 5) {
65 printk(KERN_WARNING "CPU#%d: Watchdog appears to be stuck!\n",
66 0);
67 return -1;
68 }
69
70 printk(KERN_INFO "OK.\n");
71
72 /* now that we know it works we can reduce NMI frequency to
73 * something more reasonable; makes a difference in some configs
74 */
75 watchdog_hz = 1;
76
77 return 0;
78}
79
80static int __init setup_watchdog(char *str)
81{
82 unsigned tmp;
83 int opt;
84 u8 ctr;
85
86 get_option(&str, &opt);
87 if (opt != 1)
88 return 0;
89
90 watchdog = opt;
91 if (watchdog) {
92 set_intr_stub(EXCEP_WDT, watchdog_handler);
93 ctr = WDCTR_WDCK_65536th;
94 WDCTR = WDCTR_WDRST | ctr;
95 WDCTR = ctr;
96 tmp = WDCTR;
97
98 tmp = __muldiv64u(1 << (16 + ctr * 2), 1000000, MN10300_WDCLK);
99 tmp = 1000000000 / tmp;
100 watchdog_hz = (tmp + 500) / 1000;
101 }
102
103 return 1;
104}
105
106__setup("watchdog=", setup_watchdog);
107
108void __init watchdog_go(void)
109{
110 u8 wdt;
111
112 if (watchdog) {
113 printk(KERN_INFO "Watchdog: running at %uHz\n", watchdog_hz);
114 wdt = WDCTR & ~WDCTR_WDCNE;
115 WDCTR = wdt | WDCTR_WDRST;
116 wdt = WDCTR;
117 WDCTR = wdt | WDCTR_WDCNE;
118 wdt = WDCTR;
119
120 check_watchdog();
121 }
122}
123
124asmlinkage
125void watchdog_interrupt(struct pt_regs *regs, enum exception_code excep)
126{
127
128 /*
129 * Since current-> is always on the stack, and we always switch
130 * the stack NMI-atomically, it's safe to use smp_processor_id().
131 */
132 int sum, cpu = smp_processor_id();
133 u8 wdt, tmp;
134
135 wdt = WDCTR & ~WDCTR_WDCNE;
136 WDCTR = wdt;
137 tmp = WDCTR;
138 NMICR = NMICR_WDIF;
139
140 nmi_count(cpu)++;
141 kstat_this_cpu.irqs[NMIIRQ]++;
142 sum = irq_stat[cpu].__irq_count;
143
144 if (last_irq_sums[cpu] == sum) {
145 /*
146 * Ayiee, looks like this CPU is stuck ...
147 * wait a few IRQs (5 seconds) before doing the oops ...
148 */
149 watchdog_alert_counter++;
150 if (watchdog_alert_counter == 5 * watchdog_hz) {
151 spin_lock(&watchdog_print_lock);
152 /*
153 * We are in trouble anyway, lets at least try
154 * to get a message out.
155 */
156 bust_spinlocks(1);
157 printk(KERN_ERR
158 "NMI Watchdog detected LOCKUP on CPU%d,"
159 " pc %08lx, registers:\n",
160 cpu, regs->pc);
161 show_registers(regs);
162 printk("console shuts up ...\n");
163 console_silent();
164 spin_unlock(&watchdog_print_lock);
165 bust_spinlocks(0);
166#ifdef CONFIG_GDBSTUB
167 if (gdbstub_busy)
168 gdbstub_exception(regs, excep);
169 else
170 gdbstub_intercept(regs, excep);
171#endif
172 do_exit(SIGSEGV);
173 }
174 } else {
175 last_irq_sums[cpu] = sum;
176 watchdog_alert_counter = 0;
177 }
178
179 WDCTR = wdt | WDCTR_WDRST;
180 tmp = WDCTR;
181 WDCTR = wdt | WDCTR_WDCNE;
182 tmp = WDCTR;
183}
diff --git a/arch/mn10300/kernel/mn10300_ksyms.c b/arch/mn10300/kernel/mn10300_ksyms.c
new file mode 100644
index 000000000000..6d19628634e3
--- /dev/null
+++ b/arch/mn10300/kernel/mn10300_ksyms.c
@@ -0,0 +1,37 @@
1/* MN10300 Miscellaneous and library kernel exports
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <asm/uaccess.h>
13
14
15EXPORT_SYMBOL(change_bit);
16EXPORT_SYMBOL(test_and_change_bit);
17
18EXPORT_SYMBOL(memcpy);
19EXPORT_SYMBOL(memmove);
20EXPORT_SYMBOL(memset);
21
22EXPORT_SYMBOL(strncpy_from_user);
23EXPORT_SYMBOL(__strncpy_from_user);
24EXPORT_SYMBOL(clear_user);
25EXPORT_SYMBOL(__clear_user);
26EXPORT_SYMBOL(__generic_copy_from_user);
27EXPORT_SYMBOL(__generic_copy_to_user);
28EXPORT_SYMBOL(strnlen_user);
29
30extern u64 __ashrdi3(u64, unsigned);
31extern u64 __ashldi3(u64, unsigned);
32extern u64 __lshrdi3(u64, unsigned);
33extern s64 __negdi2(s64);
34EXPORT_SYMBOL(__ashrdi3);
35EXPORT_SYMBOL(__ashldi3);
36EXPORT_SYMBOL(__lshrdi3);
37EXPORT_SYMBOL(__negdi2);
diff --git a/arch/mn10300/kernel/module.c b/arch/mn10300/kernel/module.c
new file mode 100644
index 000000000000..0e4d2f6fa6e8
--- /dev/null
+++ b/arch/mn10300/kernel/module.c
@@ -0,0 +1,206 @@
1/* MN10300 Kernel module helper routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by Mark Salter (msalter@redhat.com)
5 * - Derived from arch/i386/kernel/module.c
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public Licence as published by
9 * the Free Software Foundation; either version 2 of the Licence, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public Licence for more details.
16 *
17 * You should have received a copy of the GNU General Public Licence
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21#include <linux/moduleloader.h>
22#include <linux/elf.h>
23#include <linux/vmalloc.h>
24#include <linux/fs.h>
25#include <linux/string.h>
26#include <linux/kernel.h>
27
28#if 0
29#define DEBUGP printk
30#else
31#define DEBUGP(fmt, ...)
32#endif
33
34/*
35 * allocate storage for a module
36 */
37void *module_alloc(unsigned long size)
38{
39 if (size == 0)
40 return NULL;
41 return vmalloc_exec(size);
42}
43
44/*
45 * free memory returned from module_alloc()
46 */
47void module_free(struct module *mod, void *module_region)
48{
49 vfree(module_region);
50 /* FIXME: If module_region == mod->init_region, trim exception
51 * table entries. */
52}
53
54/*
55 * allow the arch to fix up the section table
56 * - we don't need anything special
57 */
58int module_frob_arch_sections(Elf_Ehdr *hdr,
59 Elf_Shdr *sechdrs,
60 char *secstrings,
61 struct module *mod)
62{
63 return 0;
64}
65
66static uint32_t reloc_get16(uint8_t *p)
67{
68 return p[0] | (p[1] << 8);
69}
70
71static uint32_t reloc_get24(uint8_t *p)
72{
73 return reloc_get16(p) | (p[2] << 16);
74}
75
76static uint32_t reloc_get32(uint8_t *p)
77{
78 return reloc_get16(p) | (reloc_get16(p+2) << 16);
79}
80
81static void reloc_put16(uint8_t *p, uint32_t val)
82{
83 p[0] = val & 0xff;
84 p[1] = (val >> 8) & 0xff;
85}
86
87static void reloc_put24(uint8_t *p, uint32_t val)
88{
89 reloc_put16(p, val);
90 p[2] = (val >> 16) & 0xff;
91}
92
93static void reloc_put32(uint8_t *p, uint32_t val)
94{
95 reloc_put16(p, val);
96 reloc_put16(p+2, val >> 16);
97}
98
99/*
100 * apply a REL relocation
101 */
102int apply_relocate(Elf32_Shdr *sechdrs,
103 const char *strtab,
104 unsigned int symindex,
105 unsigned int relsec,
106 struct module *me)
107{
108 printk(KERN_ERR "module %s: RELOCATION unsupported\n",
109 me->name);
110 return -ENOEXEC;
111}
112
113/*
114 * apply a RELA relocation
115 */
116int apply_relocate_add(Elf32_Shdr *sechdrs,
117 const char *strtab,
118 unsigned int symindex,
119 unsigned int relsec,
120 struct module *me)
121{
122 unsigned int i;
123 Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
124 Elf32_Sym *sym;
125 Elf32_Addr relocation;
126 uint8_t *location;
127 uint32_t value;
128
129 DEBUGP("Applying relocate section %u to %u\n",
130 relsec, sechdrs[relsec].sh_info);
131
132 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
133 /* this is where to make the change */
134 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
135 + rel[i].r_offset;
136
137 /* this is the symbol the relocation is referring to (note that
138 * all undefined symbols have been resolved by the caller) */
139 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
140 + ELF32_R_SYM(rel[i].r_info);
141
142 /* this is the adjustment to be made */
143 relocation = sym->st_value + rel[i].r_addend;
144
145 switch (ELF32_R_TYPE(rel[i].r_info)) {
146 /* for the first four relocation types, we add the
147 * adjustment into the value at the location given */
148 case R_MN10300_32:
149 value = reloc_get32(location);
150 value += relocation;
151 reloc_put32(location, value);
152 break;
153 case R_MN10300_24:
154 value = reloc_get24(location);
155 value += relocation;
156 reloc_put24(location, value);
157 break;
158 case R_MN10300_16:
159 value = reloc_get16(location);
160 value += relocation;
161 reloc_put16(location, value);
162 break;
163 case R_MN10300_8:
164 *location += relocation;
165 break;
166
167 /* for the next three relocation types, we write the
168 * adjustment with the address subtracted over the
169 * value at the location given */
170 case R_MN10300_PCREL32:
171 value = relocation - (uint32_t) location;
172 reloc_put32(location, value);
173 break;
174 case R_MN10300_PCREL16:
175 value = relocation - (uint32_t) location;
176 reloc_put16(location, value);
177 break;
178 case R_MN10300_PCREL8:
179 *location = relocation - (uint32_t) location;
180 break;
181
182 default:
183 printk(KERN_ERR "module %s: Unknown relocation: %u\n",
184 me->name, ELF32_R_TYPE(rel[i].r_info));
185 return -ENOEXEC;
186 }
187 }
188 return 0;
189}
190
191/*
192 * finish loading the module
193 */
194int module_finalize(const Elf_Ehdr *hdr,
195 const Elf_Shdr *sechdrs,
196 struct module *me)
197{
198 return 0;
199}
200
201/*
202 * finish clearing the module
203 */
204void module_arch_cleanup(struct module *mod)
205{
206}
diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c
new file mode 100644
index 000000000000..3b0d579fc15d
--- /dev/null
+++ b/arch/mn10300/kernel/process.c
@@ -0,0 +1,297 @@
1/* MN10300 Process handling code
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/errno.h>
13#include <linux/sched.h>
14#include <linux/kernel.h>
15#include <linux/mm.h>
16#include <linux/smp.h>
17#include <linux/smp_lock.h>
18#include <linux/stddef.h>
19#include <linux/unistd.h>
20#include <linux/ptrace.h>
21#include <linux/slab.h>
22#include <linux/user.h>
23#include <linux/a.out.h>
24#include <linux/interrupt.h>
25#include <linux/delay.h>
26#include <linux/reboot.h>
27#include <linux/percpu.h>
28#include <linux/err.h>
29#include <linux/fs.h>
30#include <asm/uaccess.h>
31#include <asm/pgtable.h>
32#include <asm/system.h>
33#include <asm/io.h>
34#include <asm/processor.h>
35#include <asm/mmu_context.h>
36#include <asm/fpu.h>
37#include <asm/reset-regs.h>
38#include <asm/gdb-stub.h>
39#include "internal.h"
40
41/*
42 * power management idle function, if any..
43 */
44void (*pm_idle)(void);
45EXPORT_SYMBOL(pm_idle);
46
47/*
48 * return saved PC of a blocked thread.
49 */
50unsigned long thread_saved_pc(struct task_struct *tsk)
51{
52 return ((unsigned long *) tsk->thread.sp)[3];
53}
54
55/*
56 * power off function, if any
57 */
58void (*pm_power_off)(void);
59EXPORT_SYMBOL(pm_power_off);
60
61/*
62 * we use this if we don't have any better idle routine
63 */
64static void default_idle(void)
65{
66 local_irq_disable();
67 if (!need_resched())
68 safe_halt();
69 else
70 local_irq_enable();
71}
72
73/*
74 * the idle thread
75 * - there's no useful work to be done, so just try to conserve power and have
76 * a low exit latency (ie sit in a loop waiting for somebody to say that
77 * they'd like to reschedule)
78 */
79void cpu_idle(void)
80{
81 int cpu = smp_processor_id();
82
83 /* endless idle loop with no priority at all */
84 for (;;) {
85 while (!need_resched()) {
86 void (*idle)(void);
87
88 smp_rmb();
89 idle = pm_idle;
90 if (!idle)
91 idle = default_idle;
92
93 irq_stat[cpu].idle_timestamp = jiffies;
94 idle();
95 }
96
97 preempt_enable_no_resched();
98 schedule();
99 preempt_disable();
100 }
101}
102
103void release_segments(struct mm_struct *mm)
104{
105}
106
107void machine_restart(char *cmd)
108{
109#ifdef CONFIG_GDBSTUB
110 gdbstub_exit(0);
111#endif
112
113#ifdef mn10300_unit_hard_reset
114 mn10300_unit_hard_reset();
115#else
116 mn10300_proc_hard_reset();
117#endif
118}
119
120void machine_halt(void)
121{
122#ifdef CONFIG_GDBSTUB
123 gdbstub_exit(0);
124#endif
125}
126
127void machine_power_off(void)
128{
129#ifdef CONFIG_GDBSTUB
130 gdbstub_exit(0);
131#endif
132}
133
134void show_regs(struct pt_regs *regs)
135{
136}
137
138/*
139 * create a kernel thread
140 */
141int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
142{
143 struct pt_regs regs;
144
145 memset(&regs, 0, sizeof(regs));
146
147 regs.a2 = (unsigned long) fn;
148 regs.d2 = (unsigned long) arg;
149 regs.pc = (unsigned long) kernel_thread_helper;
150 local_save_flags(regs.epsw);
151 regs.epsw |= EPSW_IE | EPSW_IM_7;
152
153 /* Ok, create the new process.. */
154 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,
155 NULL, NULL);
156}
157
158/*
159 * free current thread data structures etc..
160 */
161void exit_thread(void)
162{
163 exit_fpu();
164}
165
166void flush_thread(void)
167{
168 flush_fpu();
169}
170
171void release_thread(struct task_struct *dead_task)
172{
173}
174
175/*
176 * we do not have to muck with descriptors here, that is
177 * done in switch_mm() as needed.
178 */
179void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
180{
181}
182
183/*
184 * this gets called before we allocate a new thread and copy the current task
185 * into it so that we can store lazy state into memory
186 */
187void prepare_to_copy(struct task_struct *tsk)
188{
189 unlazy_fpu(tsk);
190}
191
192/*
193 * set up the kernel stack for a new thread and copy arch-specific thread
194 * control information
195 */
196int copy_thread(int nr, unsigned long clone_flags,
197 unsigned long c_usp, unsigned long ustk_size,
198 struct task_struct *p, struct pt_regs *kregs)
199{
200 struct pt_regs *c_uregs, *c_kregs, *uregs;
201 unsigned long c_ksp;
202
203 uregs = current->thread.uregs;
204
205 c_ksp = (unsigned long) task_stack_page(p) + THREAD_SIZE;
206
207 /* allocate the userspace exception frame and set it up */
208 c_ksp -= sizeof(struct pt_regs);
209 c_uregs = (struct pt_regs *) c_ksp;
210
211 p->thread.uregs = c_uregs;
212 *c_uregs = *uregs;
213 c_uregs->sp = c_usp;
214 c_uregs->epsw &= ~EPSW_FE; /* my FPU */
215
216 c_ksp -= 12; /* allocate function call ABI slack */
217
218 /* the new TLS pointer is passed in as arg #5 to sys_clone() */
219 if (clone_flags & CLONE_SETTLS)
220 c_uregs->e2 = __frame->d3;
221
222 /* set up the return kernel frame if called from kernel_thread() */
223 c_kregs = c_uregs;
224 if (kregs != uregs) {
225 c_ksp -= sizeof(struct pt_regs);
226 c_kregs = (struct pt_regs *) c_ksp;
227 *c_kregs = *kregs;
228 c_kregs->sp = c_usp;
229 c_kregs->next = c_uregs;
230#ifdef CONFIG_MN10300_CURRENT_IN_E2
231 c_kregs->e2 = (unsigned long) p; /* current */
232#endif
233
234 c_ksp -= 12; /* allocate function call ABI slack */
235 }
236
237 /* set up things up so the scheduler can start the new task */
238 p->thread.__frame = c_kregs;
239 p->thread.a3 = (unsigned long) c_kregs;
240 p->thread.sp = c_ksp;
241 p->thread.pc = (unsigned long) ret_from_fork;
242 p->thread.wchan = (unsigned long) ret_from_fork;
243 p->thread.usp = c_usp;
244
245 return 0;
246}
247
248/*
249 * clone a process
250 * - tlsptr is retrieved by copy_thread() from __frame->d3
251 */
252asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
253 int __user *parent_tidptr, int __user *child_tidptr,
254 int __user *tlsptr)
255{
256 return do_fork(clone_flags, newsp ?: __frame->sp, __frame, 0,
257 parent_tidptr, child_tidptr);
258}
259
260asmlinkage long sys_fork(void)
261{
262 return do_fork(SIGCHLD, __frame->sp, __frame, 0, NULL, NULL);
263}
264
265asmlinkage long sys_vfork(void)
266{
267 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, __frame->sp, __frame,
268 0, NULL, NULL);
269}
270
271asmlinkage long sys_execve(char __user *name,
272 char __user * __user *argv,
273 char __user * __user *envp)
274{
275 char *filename;
276 int error;
277
278 lock_kernel();
279
280 filename = getname(name);
281 error = PTR_ERR(filename);
282 if (!IS_ERR(filename)) {
283 error = do_execve(filename, argv, envp, __frame);
284 if (error == 0)
285 current->ptrace &= ~PT_DTRACE;
286
287 putname(filename);
288 }
289
290 unlock_kernel();
291 return error;
292}
293
294unsigned long get_wchan(struct task_struct *p)
295{
296 return p->thread.wchan;
297}
diff --git a/arch/mn10300/kernel/profile-low.S b/arch/mn10300/kernel/profile-low.S
new file mode 100644
index 000000000000..94ffac12d02d
--- /dev/null
+++ b/arch/mn10300/kernel/profile-low.S
@@ -0,0 +1,72 @@
1###############################################################################
2#
3# Fast profiling interrupt handler
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/segment.h>
17#include <asm/smp.h>
18#include <asm/intctl-regs.h>
19#include <asm/timer-regs.h>
20
21#define pi break
22
23 .balign 4
24counter:
25 .long -1
26
27###############################################################################
28#
29# Profiling interrupt entry point
30# - intended to run at interrupt priority 1
31#
32###############################################################################
33ENTRY(profile_handler)
34 movm [d2,d3,a2],(sp)
35
36 # ignore userspace
37 mov (12,sp),d2
38 and EPSW_nSL,d2
39 bne out
40
41 # do nothing if there's no buffer
42 mov (prof_buffer),a2
43 and a2,a2
44 beq out
45 or 0x20000000,a2
46
47 # calculate relative position in text segment
48 mov (16,sp),d2
49 sub _stext,d2
50 mov (prof_shift),d3
51 lsr d3,d2
52 mov (prof_len),d3
53 cmp d3,d2
54 bcc outside_text
55
56 # increment the appropriate profile bucket
57do_inc:
58 asl2 d2
59 mov (a2,d2),d3
60 inc d3
61 mov d3,(a2,d2)
62out:
63 mov GxICR_DETECT,d2
64 movbu d2,(TM11ICR) # ACK the interrupt
65 movbu (TM11ICR),d2
66 movm (sp),[d2,d3,a2]
67 rti
68
69outside_text:
70 sub 1,d3
71 mov d3,d2
72 bra do_inc
diff --git a/arch/mn10300/kernel/profile.c b/arch/mn10300/kernel/profile.c
new file mode 100644
index 000000000000..20d7d0306b16
--- /dev/null
+++ b/arch/mn10300/kernel/profile.c
@@ -0,0 +1,51 @@
1/* MN10300 Profiling setup
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12/*
13 * initialise the profiling if enabled
14 * - using with gdbstub will give anomalous results
15 * - can't be used with gdbstub if running at IRQ priority 0
16 */
17static __init int profile_init(void)
18{
19 u16 tmp;
20
21 if (!prof_buffer)
22 return 0;
23
24 /* use timer 11 to drive the profiling interrupts */
25 set_intr_stub(EXCEP_IRQ_LEVEL0, profile_handler);
26
27 /* set IRQ priority at which to run */
28 set_intr_level(TM11IRQ, GxICR_LEVEL_0);
29
30 /* set up timer 11
31 * - source: (IOCLK 33MHz)*2 = 66MHz
32 * - frequency: (33330000*2) / 8 / 20625 = 202Hz
33 */
34 TM11BR = 20625 - 1;
35 TM11MD = TM8MD_SRC_IOCLK_8;
36 TM11MD |= TM8MD_INIT_COUNTER;
37 TM11MD &= ~TM8MD_INIT_COUNTER;
38 TM11MD |= TM8MD_COUNT_ENABLE;
39
40 TM11ICR |= GxICR_ENABLE;
41 tmp = TM11ICR;
42
43 printk(KERN_INFO "Profiling initiated on timer 11, priority 0, %uHz\n",
44 mn10300_ioclk / 8 / (TM11BR + 1));
45 printk(KERN_INFO "Profile histogram stored %p-%p\n",
46 prof_buffer, (u8 *)(prof_buffer + prof_len) - 1);
47
48 return 0;
49}
50
51__initcall(profile_init);
diff --git a/arch/mn10300/kernel/ptrace.c b/arch/mn10300/kernel/ptrace.c
new file mode 100644
index 000000000000..d6d6cdc75c52
--- /dev/null
+++ b/arch/mn10300/kernel/ptrace.c
@@ -0,0 +1,379 @@
1/* MN10300 Process tracing
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17#include <linux/errno.h>
18#include <linux/ptrace.h>
19#include <linux/user.h>
20#include <asm/uaccess.h>
21#include <asm/pgtable.h>
22#include <asm/system.h>
23#include <asm/processor.h>
24#include <asm/cacheflush.h>
25#include <asm/fpu.h>
26#include <asm/asm-offsets.h>
27
28/*
29 * translate ptrace register IDs into struct pt_regs offsets
30 */
31static const u8 ptrace_regid_to_frame[] = {
32 [PT_A3 << 2] = REG_A3,
33 [PT_A2 << 2] = REG_A2,
34 [PT_D3 << 2] = REG_D3,
35 [PT_D2 << 2] = REG_D2,
36 [PT_MCVF << 2] = REG_MCVF,
37 [PT_MCRL << 2] = REG_MCRL,
38 [PT_MCRH << 2] = REG_MCRH,
39 [PT_MDRQ << 2] = REG_MDRQ,
40 [PT_E1 << 2] = REG_E1,
41 [PT_E0 << 2] = REG_E0,
42 [PT_E7 << 2] = REG_E7,
43 [PT_E6 << 2] = REG_E6,
44 [PT_E5 << 2] = REG_E5,
45 [PT_E4 << 2] = REG_E4,
46 [PT_E3 << 2] = REG_E3,
47 [PT_E2 << 2] = REG_E2,
48 [PT_SP << 2] = REG_SP,
49 [PT_LAR << 2] = REG_LAR,
50 [PT_LIR << 2] = REG_LIR,
51 [PT_MDR << 2] = REG_MDR,
52 [PT_A1 << 2] = REG_A1,
53 [PT_A0 << 2] = REG_A0,
54 [PT_D1 << 2] = REG_D1,
55 [PT_D0 << 2] = REG_D0,
56 [PT_ORIG_D0 << 2] = REG_ORIG_D0,
57 [PT_EPSW << 2] = REG_EPSW,
58 [PT_PC << 2] = REG_PC,
59};
60
61static inline int get_stack_long(struct task_struct *task, int offset)
62{
63 return *(unsigned long *)
64 ((unsigned long) task->thread.uregs + offset);
65}
66
67/*
68 * this routine will put a word on the processes privileged stack.
69 * the offset is how far from the base addr as stored in the TSS.
70 * this routine assumes that all the privileged stacks are in our
71 * data space.
72 */
73static inline
74int put_stack_long(struct task_struct *task, int offset, unsigned long data)
75{
76 unsigned long stack;
77
78 stack = (unsigned long) task->thread.uregs + offset;
79 *(unsigned long *) stack = data;
80 return 0;
81}
82
83static inline unsigned long get_fpregs(struct fpu_state_struct *buf,
84 struct task_struct *tsk)
85{
86 return __copy_to_user(buf, &tsk->thread.fpu_state,
87 sizeof(struct fpu_state_struct));
88}
89
90static inline unsigned long set_fpregs(struct task_struct *tsk,
91 struct fpu_state_struct *buf)
92{
93 return __copy_from_user(&tsk->thread.fpu_state, buf,
94 sizeof(struct fpu_state_struct));
95}
96
97static inline void fpsave_init(struct task_struct *task)
98{
99 memset(&task->thread.fpu_state, 0, sizeof(struct fpu_state_struct));
100}
101
102/*
103 * make sure the single step bit is not set
104 */
105void ptrace_disable(struct task_struct *child)
106{
107#ifndef CONFIG_MN10300_USING_JTAG
108 struct user *dummy = NULL;
109 long tmp;
110
111 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
112 tmp &= ~EPSW_T;
113 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
114#endif
115}
116
117/*
118 * set the single step bit
119 */
120void ptrace_enable(struct task_struct *child)
121{
122#ifndef CONFIG_MN10300_USING_JTAG
123 struct user *dummy = NULL;
124 long tmp;
125
126 tmp = get_stack_long(child, (unsigned long) &dummy->regs.epsw);
127 tmp |= EPSW_T;
128 put_stack_long(child, (unsigned long) &dummy->regs.epsw, tmp);
129#endif
130}
131
132/*
133 * handle the arch-specific side of process tracing
134 */
135long arch_ptrace(struct task_struct *child, long request, long addr, long data)
136{
137 struct fpu_state_struct fpu_state;
138 int i, ret;
139
140 switch (request) {
141 /* read the word at location addr. */
142 case PTRACE_PEEKTEXT: {
143 unsigned long tmp;
144 int copied;
145
146 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
147 ret = -EIO;
148 if (copied != sizeof(tmp))
149 break;
150 ret = put_user(tmp, (unsigned long *) data);
151 break;
152 }
153
154 /* read the word at location addr. */
155 case PTRACE_PEEKDATA: {
156 unsigned long tmp;
157 int copied;
158
159 copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
160 ret = -EIO;
161 if (copied != sizeof(tmp))
162 break;
163 ret = put_user(tmp, (unsigned long *) data);
164 break;
165 }
166
167 /* read the word at location addr in the USER area. */
168 case PTRACE_PEEKUSR: {
169 unsigned long tmp;
170
171 ret = -EIO;
172 if ((addr & 3) || addr < 0 ||
173 addr > sizeof(struct user) - 3)
174 break;
175
176 tmp = 0; /* Default return condition */
177 if (addr < NR_PTREGS << 2)
178 tmp = get_stack_long(child,
179 ptrace_regid_to_frame[addr]);
180 ret = put_user(tmp, (unsigned long *) data);
181 break;
182 }
183
184 /* write the word at location addr. */
185 case PTRACE_POKETEXT:
186 case PTRACE_POKEDATA:
187 if (access_process_vm(child, addr, &data, sizeof(data), 1) ==
188 sizeof(data))
189 ret = 0;
190 else
191 ret = -EIO;
192 break;
193
194 /* write the word at location addr in the USER area */
195 case PTRACE_POKEUSR:
196 ret = -EIO;
197 if ((addr & 3) || addr < 0 ||
198 addr > sizeof(struct user) - 3)
199 break;
200
201 ret = 0;
202 if (addr < NR_PTREGS << 2)
203 ret = put_stack_long(child, ptrace_regid_to_frame[addr],
204 data);
205 break;
206
207 /* continue and stop at next (return from) syscall */
208 case PTRACE_SYSCALL:
209 /* restart after signal. */
210 case PTRACE_CONT:
211 ret = -EIO;
212 if ((unsigned long) data > _NSIG)
213 break;
214 if (request == PTRACE_SYSCALL)
215 set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
216 else
217 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
218 child->exit_code = data;
219 ptrace_disable(child);
220 wake_up_process(child);
221 ret = 0;
222 break;
223
224 /*
225 * make the child exit
226 * - the best I can do is send it a sigkill
227 * - perhaps it should be put in the status that it wants to
228 * exit
229 */
230 case PTRACE_KILL:
231 ret = 0;
232 if (child->exit_state == EXIT_ZOMBIE) /* already dead */
233 break;
234 child->exit_code = SIGKILL;
235 clear_tsk_thread_flag(child, TIF_SINGLESTEP);
236 ptrace_disable(child);
237 wake_up_process(child);
238 break;
239
240 case PTRACE_SINGLESTEP: /* set the trap flag. */
241#ifndef CONFIG_MN10300_USING_JTAG
242 ret = -EIO;
243 if ((unsigned long) data > _NSIG)
244 break;
245 clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
246 ptrace_enable(child);
247 child->exit_code = data;
248 wake_up_process(child);
249 ret = 0;
250#else
251 ret = -EINVAL;
252#endif
253 break;
254
255 case PTRACE_DETACH: /* detach a process that was attached. */
256 ret = ptrace_detach(child, data);
257 break;
258
259 /* Get all gp regs from the child. */
260 case PTRACE_GETREGS: {
261 unsigned long tmp;
262
263 if (!access_ok(VERIFY_WRITE, (unsigned *) data, NR_PTREGS << 2)) {
264 ret = -EIO;
265 break;
266 }
267
268 for (i = 0; i < NR_PTREGS << 2; i += 4) {
269 tmp = get_stack_long(child, ptrace_regid_to_frame[i]);
270 __put_user(tmp, (unsigned long *) data);
271 data += sizeof(tmp);
272 }
273 ret = 0;
274 break;
275 }
276
277 case PTRACE_SETREGS: { /* Set all gp regs in the child. */
278 unsigned long tmp;
279
280 if (!access_ok(VERIFY_READ, (unsigned long *)data,
281 sizeof(struct pt_regs))) {
282 ret = -EIO;
283 break;
284 }
285
286 for (i = 0; i < NR_PTREGS << 2; i += 4) {
287 __get_user(tmp, (unsigned long *) data);
288 put_stack_long(child, ptrace_regid_to_frame[i], tmp);
289 data += sizeof(tmp);
290 }
291 ret = 0;
292 break;
293 }
294
295 case PTRACE_GETFPREGS: { /* Get the child FPU state. */
296 if (is_using_fpu(child)) {
297 unlazy_fpu(child);
298 fpu_state = child->thread.fpu_state;
299 } else {
300 memset(&fpu_state, 0, sizeof(fpu_state));
301 }
302
303 ret = -EIO;
304 if (copy_to_user((void *) data, &fpu_state,
305 sizeof(fpu_state)) == 0)
306 ret = 0;
307 break;
308 }
309
310 case PTRACE_SETFPREGS: { /* Set the child FPU state. */
311 ret = -EFAULT;
312 if (copy_from_user(&fpu_state, (const void *) data,
313 sizeof(fpu_state)) == 0) {
314 fpu_kill_state(child);
315 child->thread.fpu_state = fpu_state;
316 set_using_fpu(child);
317 ret = 0;
318 }
319 break;
320 }
321
322 case PTRACE_SETOPTIONS: {
323 if (data & PTRACE_O_TRACESYSGOOD)
324 child->ptrace |= PT_TRACESYSGOOD;
325 else
326 child->ptrace &= ~PT_TRACESYSGOOD;
327 ret = 0;
328 break;
329 }
330
331 default:
332 ret = -EIO;
333 break;
334 }
335
336 return ret;
337}
338
339/*
340 * notification of system call entry/exit
341 * - triggered by current->work.syscall_trace
342 */
343asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
344{
345#if 0
346 /* just in case... */
347 printk(KERN_DEBUG "[%d] syscall_%lu(%lx,%lx,%lx,%lx) = %lx\n",
348 current->pid,
349 regs->orig_d0,
350 regs->a0,
351 regs->d1,
352 regs->a3,
353 regs->a2,
354 regs->d0);
355 return;
356#endif
357
358 if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
359 !test_thread_flag(TIF_SINGLESTEP))
360 return;
361 if (!(current->ptrace & PT_PTRACED))
362 return;
363
364 /* the 0x80 provides a way for the tracing parent to distinguish
365 between a syscall stop and SIGTRAP delivery */
366 ptrace_notify(SIGTRAP |
367 ((current->ptrace & PT_TRACESYSGOOD) &&
368 !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0));
369
370 /*
371 * this isn't the same as continuing with a signal, but it will do
372 * for normal use. strace only continues with a signal if the
373 * stopping signal is not SIGTRAP. -brl
374 */
375 if (current->exit_code) {
376 send_sig(current->exit_code, current, 1);
377 current->exit_code = 0;
378 }
379}
diff --git a/arch/mn10300/kernel/rtc.c b/arch/mn10300/kernel/rtc.c
new file mode 100644
index 000000000000..042f792d8430
--- /dev/null
+++ b/arch/mn10300/kernel/rtc.c
@@ -0,0 +1,173 @@
1/* MN10300 RTC management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/mc146818rtc.h>
15#include <linux/bcd.h>
16#include <linux/timex.h>
17#include <asm/rtc-regs.h>
18#include <asm/rtc.h>
19
20DEFINE_SPINLOCK(rtc_lock);
21EXPORT_SYMBOL(rtc_lock);
22
23/* last time the RTC got updated */
24static long last_rtc_update;
25
26/* time for RTC to update itself in ioclks */
27static unsigned long mn10300_rtc_update_period;
28
29/*
30 * read the current RTC time
31 */
32unsigned long __init get_initial_rtc_time(void)
33{
34 struct rtc_time tm;
35
36 get_rtc_time(&tm);
37
38 return mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
39 tm.tm_hour, tm.tm_min, tm.tm_sec);
40}
41
42/*
43 * In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
44 * ms after the second nowtime has started, because when nowtime is written
45 * into the registers of the CMOS clock, it will jump to the next second
46 * precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data
47 * sheet for details.
48 *
49 * BUG: This routine does not handle hour overflow properly; it just
50 * sets the minutes. Usually you'll only notice that after reboot!
51 */
52static int set_rtc_mmss(unsigned long nowtime)
53{
54 unsigned char save_control, save_freq_select;
55 int retval = 0;
56 int real_seconds, real_minutes, cmos_minutes;
57
58 /* gets recalled with irq locally disabled */
59 spin_lock(&rtc_lock);
60 save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being
61 * set */
62 CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
63
64 save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset
65 * prescaler */
66 CMOS_WRITE(save_freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
67
68 cmos_minutes = CMOS_READ(RTC_MINUTES);
69 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
70 BCD_TO_BIN(cmos_minutes);
71
72 /*
73 * since we're only adjusting minutes and seconds,
74 * don't interfere with hour overflow. This avoids
75 * messing with unknown time zones but requires your
76 * RTC not to be off by more than 15 minutes
77 */
78 real_seconds = nowtime % 60;
79 real_minutes = nowtime / 60;
80 if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
81 /* correct for half hour time zone */
82 real_minutes += 30;
83 real_minutes %= 60;
84
85 if (abs(real_minutes - cmos_minutes) < 30) {
86 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
87 BIN_TO_BCD(real_seconds);
88 BIN_TO_BCD(real_minutes);
89 }
90 CMOS_WRITE(real_seconds, RTC_SECONDS);
91 CMOS_WRITE(real_minutes, RTC_MINUTES);
92 } else {
93 printk(KERN_WARNING
94 "set_rtc_mmss: can't update from %d to %d\n",
95 cmos_minutes, real_minutes);
96 retval = -1;
97 }
98
99 /* The following flags have to be released exactly in this order,
100 * otherwise the DS12887 (popular MC146818A clone with integrated
101 * battery and quartz) will not reset the oscillator and will not
102 * update precisely 500 ms later. You won't find this mentioned in
103 * the Dallas Semiconductor data sheets, but who believes data
104 * sheets anyway ... -- Markus Kuhn
105 */
106 CMOS_WRITE(save_control, RTC_CONTROL);
107 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
108 spin_unlock(&rtc_lock);
109
110 return retval;
111}
112
113void check_rtc_time(void)
114{
115 /* the RTC clock just finished ticking over again this second
116 * - if we have an externally synchronized Linux clock, then update
117 * RTC clock accordingly every ~11 minutes. set_rtc_mmss() has to be
118 * called as close as possible to 500 ms before the new second starts.
119 */
120 if ((time_status & STA_UNSYNC) == 0 &&
121 xtime.tv_sec > last_rtc_update + 660 &&
122 xtime.tv_nsec / 1000 >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
123 xtime.tv_nsec / 1000 <= 500000 + ((unsigned) TICK_SIZE) / 2
124 ) {
125 if (set_rtc_mmss(xtime.tv_sec) == 0)
126 last_rtc_update = xtime.tv_sec;
127 else
128 /* do it again in 60s */
129 last_rtc_update = xtime.tv_sec - 600;
130 }
131}
132
133/*
134 * calibrate the TSC clock against the RTC
135 */
136void __init calibrate_clock(void)
137{
138 unsigned long count0, counth, count1;
139 unsigned char status;
140
141 /* make sure the RTC is running and is set to operate in 24hr mode */
142 status = RTSRC;
143 RTCRB |= RTCRB_SET;
144 RTCRB |= RTCRB_TM_24HR;
145 RTCRA |= RTCRA_DVR;
146 RTCRA &= ~RTCRA_DVR;
147 RTCRB &= ~RTCRB_SET;
148
149 /* work out the clock speed by counting clock cycles between ends of
150 * the RTC update cycle - track the RTC through one complete update
151 * cycle (1 second)
152 */
153 startup_timestamp_counter();
154
155 while (!(RTCRA & RTCRA_UIP)) {}
156 while ((RTCRA & RTCRA_UIP)) {}
157
158 count0 = TMTSCBC;
159
160 while (!(RTCRA & RTCRA_UIP)) {}
161
162 counth = TMTSCBC;
163
164 while ((RTCRA & RTCRA_UIP)) {}
165
166 count1 = TMTSCBC;
167
168 shutdown_timestamp_counter();
169
170 MN10300_TSCCLK = count0 - count1; /* the timers count down */
171 mn10300_rtc_update_period = counth - count1;
172 MN10300_TSC_PER_HZ = MN10300_TSCCLK / HZ;
173}
diff --git a/arch/mn10300/kernel/semaphore.c b/arch/mn10300/kernel/semaphore.c
new file mode 100644
index 000000000000..9153c4039fd2
--- /dev/null
+++ b/arch/mn10300/kernel/semaphore.c
@@ -0,0 +1,149 @@
1/* MN10300 Semaphore implementation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sched.h>
12#include <linux/module.h>
13#include <asm/semaphore.h>
14
15struct sem_waiter {
16 struct list_head list;
17 struct task_struct *task;
18};
19
20#if SEMAPHORE_DEBUG
21void semtrace(struct semaphore *sem, const char *str)
22{
23 if (sem->debug)
24 printk(KERN_DEBUG "[%d] %s({%d,%d})\n",
25 current->pid,
26 str,
27 atomic_read(&sem->count),
28 list_empty(&sem->wait_list) ? 0 : 1);
29}
30#else
31#define semtrace(SEM, STR) do { } while (0)
32#endif
33
34/*
35 * wait for a token to be granted from a semaphore
36 * - entered with lock held and interrupts disabled
37 */
38void __down(struct semaphore *sem, unsigned long flags)
39{
40 struct task_struct *tsk = current;
41 struct sem_waiter waiter;
42
43 semtrace(sem, "Entering __down");
44
45 /* set up my own style of waitqueue */
46 waiter.task = tsk;
47 get_task_struct(tsk);
48
49 list_add_tail(&waiter.list, &sem->wait_list);
50
51 /* we don't need to touch the semaphore struct anymore */
52 spin_unlock_irqrestore(&sem->wait_lock, flags);
53
54 /* wait to be given the semaphore */
55 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
56
57 for (;;) {
58 if (!waiter.task)
59 break;
60 schedule();
61 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
62 }
63
64 tsk->state = TASK_RUNNING;
65 semtrace(sem, "Leaving __down");
66}
67EXPORT_SYMBOL(__down);
68
69/*
70 * interruptibly wait for a token to be granted from a semaphore
71 * - entered with lock held and interrupts disabled
72 */
73int __down_interruptible(struct semaphore *sem, unsigned long flags)
74{
75 struct task_struct *tsk = current;
76 struct sem_waiter waiter;
77 int ret;
78
79 semtrace(sem, "Entering __down_interruptible");
80
81 /* set up my own style of waitqueue */
82 waiter.task = tsk;
83 get_task_struct(tsk);
84
85 list_add_tail(&waiter.list, &sem->wait_list);
86
87 /* we don't need to touch the semaphore struct anymore */
88 set_task_state(tsk, TASK_INTERRUPTIBLE);
89
90 spin_unlock_irqrestore(&sem->wait_lock, flags);
91
92 /* wait to be given the semaphore */
93 ret = 0;
94 for (;;) {
95 if (!waiter.task)
96 break;
97 if (unlikely(signal_pending(current)))
98 goto interrupted;
99 schedule();
100 set_task_state(tsk, TASK_INTERRUPTIBLE);
101 }
102
103 out:
104 tsk->state = TASK_RUNNING;
105 semtrace(sem, "Leaving __down_interruptible");
106 return ret;
107
108 interrupted:
109 spin_lock_irqsave(&sem->wait_lock, flags);
110 list_del(&waiter.list);
111 spin_unlock_irqrestore(&sem->wait_lock, flags);
112
113 ret = 0;
114 if (!waiter.task) {
115 put_task_struct(current);
116 ret = -EINTR;
117 }
118 goto out;
119}
120EXPORT_SYMBOL(__down_interruptible);
121
122/*
123 * release a single token back to a semaphore
124 * - entered with lock held and interrupts disabled
125 */
126void __up(struct semaphore *sem)
127{
128 struct task_struct *tsk;
129 struct sem_waiter *waiter;
130
131 semtrace(sem, "Entering __up");
132
133 /* grant the token to the process at the front of the queue */
134 waiter = list_entry(sem->wait_list.next, struct sem_waiter, list);
135
136 /* We must be careful not to touch 'waiter' after we set ->task = NULL.
137 * It is an allocated on the waiter's stack and may become invalid at
138 * any time after that point (due to a wakeup from another source).
139 */
140 list_del_init(&waiter->list);
141 tsk = waiter->task;
142 smp_mb();
143 waiter->task = NULL;
144 wake_up_process(tsk);
145 put_task_struct(tsk);
146
147 semtrace(sem, "Leaving __up");
148}
149EXPORT_SYMBOL(__up);
diff --git a/arch/mn10300/kernel/setup.c b/arch/mn10300/kernel/setup.c
new file mode 100644
index 000000000000..6b7ce2636851
--- /dev/null
+++ b/arch/mn10300/kernel/setup.c
@@ -0,0 +1,298 @@
1/* MN10300 Arch-specific initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/mm.h>
15#include <linux/stddef.h>
16#include <linux/unistd.h>
17#include <linux/ptrace.h>
18#include <linux/slab.h>
19#include <linux/user.h>
20#include <linux/a.out.h>
21#include <linux/tty.h>
22#include <linux/ioport.h>
23#include <linux/delay.h>
24#include <linux/init.h>
25#include <linux/bootmem.h>
26#include <linux/seq_file.h>
27#include <asm/processor.h>
28#include <linux/console.h>
29#include <asm/uaccess.h>
30#include <asm/system.h>
31#include <asm/setup.h>
32#include <asm/io.h>
33#include <asm/smp.h>
34#include <asm/proc/proc.h>
35#include <asm/busctl-regs.h>
36#include <asm/fpu.h>
37#include <asm/sections.h>
38
39struct mn10300_cpuinfo boot_cpu_data;
40
41/* For PCI or other memory-mapped resources */
42unsigned long pci_mem_start = 0x18000000;
43
44char redboot_command_line[COMMAND_LINE_SIZE] =
45 "console=ttyS0,115200 root=/dev/mtdblock3 rw";
46
47char __initdata redboot_platform_name[COMMAND_LINE_SIZE];
48
49static struct resource code_resource = {
50 .start = 0x100000,
51 .end = 0,
52 .name = "Kernel code",
53};
54
55static struct resource data_resource = {
56 .start = 0,
57 .end = 0,
58 .name = "Kernel data",
59};
60
61static unsigned long __initdata phys_memory_base;
62static unsigned long __initdata phys_memory_end;
63static unsigned long __initdata memory_end;
64unsigned long memory_size;
65
66struct thread_info *__current_ti = &init_thread_union.thread_info;
67struct task_struct *__current = &init_task;
68
69#define mn10300_known_cpus 3
70static const char *const mn10300_cputypes[] = {
71 "am33v1",
72 "am33v2",
73 "am34v1",
74 "unknown"
75};
76
77/*
78 *
79 */
80static void __init parse_mem_cmdline(char **cmdline_p)
81{
82 char *from, *to, c;
83
84 /* save unparsed command line copy for /proc/cmdline */
85 strcpy(boot_command_line, redboot_command_line);
86
87 /* see if there's an explicit memory size option */
88 from = redboot_command_line;
89 to = redboot_command_line;
90 c = ' ';
91
92 for (;;) {
93 if (c == ' ' && !memcmp(from, "mem=", 4)) {
94 if (to != redboot_command_line)
95 to--;
96 memory_size = memparse(from + 4, &from);
97 }
98
99 c = *(from++);
100 if (!c)
101 break;
102
103 *(to++) = c;
104 }
105
106 *to = '\0';
107 *cmdline_p = redboot_command_line;
108
109 if (memory_size == 0)
110 panic("Memory size not known\n");
111
112 memory_end = (unsigned long) CONFIG_KERNEL_RAM_BASE_ADDRESS +
113 memory_size;
114 if (memory_end > phys_memory_end)
115 memory_end = phys_memory_end;
116}
117
118/*
119 * architecture specific setup
120 */
121void __init setup_arch(char **cmdline_p)
122{
123 unsigned long bootmap_size;
124 unsigned long kstart_pfn, start_pfn, free_pfn, end_pfn;
125
126 cpu_init();
127 unit_setup();
128 parse_mem_cmdline(cmdline_p);
129
130 init_mm.start_code = (unsigned long)&_text;
131 init_mm.end_code = (unsigned long) &_etext;
132 init_mm.end_data = (unsigned long) &_edata;
133 init_mm.brk = (unsigned long) &_end;
134
135 code_resource.start = virt_to_bus(&_text);
136 code_resource.end = virt_to_bus(&_etext)-1;
137 data_resource.start = virt_to_bus(&_etext);
138 data_resource.end = virt_to_bus(&_edata)-1;
139
140#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
141#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
142#define PFN_PHYS(x) ((x) << PAGE_SHIFT)
143
144 start_pfn = (CONFIG_KERNEL_RAM_BASE_ADDRESS >> PAGE_SHIFT);
145 kstart_pfn = PFN_UP(__pa(&_text));
146 free_pfn = PFN_UP(__pa(&_end));
147 end_pfn = PFN_DOWN(__pa(memory_end));
148
149 bootmap_size = init_bootmem_node(&contig_page_data,
150 free_pfn,
151 start_pfn,
152 end_pfn);
153
154 if (kstart_pfn > start_pfn)
155 free_bootmem(PFN_PHYS(start_pfn),
156 PFN_PHYS(kstart_pfn - start_pfn));
157
158 free_bootmem(PFN_PHYS(free_pfn),
159 PFN_PHYS(end_pfn - free_pfn));
160
161 /* If interrupt vector table is in main ram, then we need to
162 reserve the page it is occupying. */
163 if (CONFIG_INTERRUPT_VECTOR_BASE >= CONFIG_KERNEL_RAM_BASE_ADDRESS &&
164 CONFIG_INTERRUPT_VECTOR_BASE < memory_end)
165 reserve_bootmem(CONFIG_INTERRUPT_VECTOR_BASE, 1,
166 BOOTMEM_DEFAULT);
167
168 reserve_bootmem(PAGE_ALIGN(PFN_PHYS(free_pfn)), bootmap_size,
169 BOOTMEM_DEFAULT);
170
171#ifdef CONFIG_VT
172#if defined(CONFIG_VGA_CONSOLE)
173 conswitchp = &vga_con;
174#elif defined(CONFIG_DUMMY_CONSOLE)
175 conswitchp = &dummy_con;
176#endif
177#endif
178
179 paging_init();
180}
181
182/*
183 * perform CPU initialisation
184 */
185void __init cpu_init(void)
186{
187 unsigned long cpurev = CPUREV, type;
188 unsigned long base, size;
189
190 type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
191 if (type > mn10300_known_cpus)
192 type = mn10300_known_cpus;
193
194 printk(KERN_INFO "Matsushita %s, rev %ld\n",
195 mn10300_cputypes[type],
196 (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S);
197
198 /* determine the memory size and base from the memory controller regs */
199 memory_size = 0;
200
201 base = SDBASE(0);
202 if (base & SDBASE_CE) {
203 size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
204 size = ~size + 1;
205 base &= SDBASE_CBA;
206
207 printk(KERN_INFO "SDRAM[0]: %luMb @%08lx\n", size >> 20, base);
208 memory_size += size;
209 phys_memory_base = base;
210 }
211
212 base = SDBASE(1);
213 if (base & SDBASE_CE) {
214 size = (base & SDBASE_CBAM) << SDBASE_CBAM_SHIFT;
215 size = ~size + 1;
216 base &= SDBASE_CBA;
217
218 printk(KERN_INFO "SDRAM[1]: %luMb @%08lx\n", size >> 20, base);
219 memory_size += size;
220 if (phys_memory_base == 0)
221 phys_memory_base = base;
222 }
223
224 phys_memory_end = phys_memory_base + memory_size;
225
226#ifdef CONFIG_FPU
227 fpu_init_state();
228#endif
229}
230
231/*
232 * Get CPU information for use by the procfs.
233 */
234static int show_cpuinfo(struct seq_file *m, void *v)
235{
236 unsigned long cpurev = CPUREV, type, icachesz, dcachesz;
237
238 type = (CPUREV & CPUREV_TYPE) >> CPUREV_TYPE_S;
239 if (type > mn10300_known_cpus)
240 type = mn10300_known_cpus;
241
242 icachesz =
243 ((cpurev & CPUREV_ICWAY ) >> CPUREV_ICWAY_S) *
244 ((cpurev & CPUREV_ICSIZE) >> CPUREV_ICSIZE_S) *
245 1024;
246
247 dcachesz =
248 ((cpurev & CPUREV_DCWAY ) >> CPUREV_DCWAY_S) *
249 ((cpurev & CPUREV_DCSIZE) >> CPUREV_DCSIZE_S) *
250 1024;
251
252 seq_printf(m,
253 "processor : 0\n"
254 "vendor_id : Matsushita\n"
255 "cpu core : %s\n"
256 "cpu rev : %lu\n"
257 "model name : " PROCESSOR_MODEL_NAME "\n"
258 "icache size: %lu\n"
259 "dcache size: %lu\n",
260 mn10300_cputypes[type],
261 (cpurev & CPUREV_REVISION) >> CPUREV_REVISION_S,
262 icachesz,
263 dcachesz
264 );
265
266 seq_printf(m,
267 "ioclk speed: %lu.%02luMHz\n"
268 "bogomips : %lu.%02lu\n\n",
269 MN10300_IOCLK / 1000000,
270 (MN10300_IOCLK / 10000) % 100,
271 loops_per_jiffy / (500000 / HZ),
272 (loops_per_jiffy / (5000 / HZ)) % 100
273 );
274
275 return 0;
276}
277
278static void *c_start(struct seq_file *m, loff_t *pos)
279{
280 return *pos < NR_CPUS ? cpu_data + *pos : NULL;
281}
282
283static void *c_next(struct seq_file *m, void *v, loff_t *pos)
284{
285 ++*pos;
286 return c_start(m, pos);
287}
288
289static void c_stop(struct seq_file *m, void *v)
290{
291}
292
293struct seq_operations cpuinfo_op = {
294 .start = c_start,
295 .next = c_next,
296 .stop = c_stop,
297 .show = show_cpuinfo,
298};
diff --git a/arch/mn10300/kernel/sigframe.h b/arch/mn10300/kernel/sigframe.h
new file mode 100644
index 000000000000..0decba28ae84
--- /dev/null
+++ b/arch/mn10300/kernel/sigframe.h
@@ -0,0 +1,33 @@
1/* MN10300 Signal frame definitions
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12struct sigframe
13{
14 void (*pretcode)(void);
15 int sig;
16 struct sigcontext *psc;
17 struct sigcontext sc;
18 struct fpucontext fpuctx;
19 unsigned long extramask[_NSIG_WORDS-1];
20 char retcode[8];
21};
22
23struct rt_sigframe
24{
25 void (*pretcode)(void);
26 int sig;
27 struct siginfo *pinfo;
28 void *puc;
29 struct siginfo info;
30 struct ucontext uc;
31 struct fpucontext fpuctx;
32 char retcode[8];
33};
diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c
new file mode 100644
index 000000000000..841ca9955a18
--- /dev/null
+++ b/arch/mn10300/kernel/signal.c
@@ -0,0 +1,564 @@
1/* MN10300 Signal handling
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/sched.h>
13#include <linux/mm.h>
14#include <linux/smp.h>
15#include <linux/smp_lock.h>
16#include <linux/kernel.h>
17#include <linux/signal.h>
18#include <linux/errno.h>
19#include <linux/wait.h>
20#include <linux/ptrace.h>
21#include <linux/unistd.h>
22#include <linux/stddef.h>
23#include <linux/tty.h>
24#include <linux/personality.h>
25#include <linux/suspend.h>
26#include <asm/cacheflush.h>
27#include <asm/ucontext.h>
28#include <asm/uaccess.h>
29#include <asm/fpu.h>
30#include "sigframe.h"
31
32#define DEBUG_SIG 0
33
34#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
35
36/*
37 * atomically swap in the new signal mask, and wait for a signal.
38 */
39asmlinkage long sys_sigsuspend(int history0, int history1, old_sigset_t mask)
40{
41 mask &= _BLOCKABLE;
42 spin_lock_irq(&current->sighand->siglock);
43 current->saved_sigmask = current->blocked;
44 siginitset(&current->blocked, mask);
45 recalc_sigpending();
46 spin_unlock_irq(&current->sighand->siglock);
47
48 current->state = TASK_INTERRUPTIBLE;
49 schedule();
50 set_thread_flag(TIF_RESTORE_SIGMASK);
51 return -ERESTARTNOHAND;
52}
53
54/*
55 * set signal action syscall
56 */
57asmlinkage long sys_sigaction(int sig,
58 const struct old_sigaction __user *act,
59 struct old_sigaction __user *oact)
60{
61 struct k_sigaction new_ka, old_ka;
62 int ret;
63
64 if (act) {
65 old_sigset_t mask;
66 if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
67 __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
68 __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
69 return -EFAULT;
70 __get_user(new_ka.sa.sa_flags, &act->sa_flags);
71 __get_user(mask, &act->sa_mask);
72 siginitset(&new_ka.sa.sa_mask, mask);
73 }
74
75 ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
76
77 if (!ret && oact) {
78 if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
79 __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
80 __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
81 return -EFAULT;
82 __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
83 __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
84 }
85
86 return ret;
87}
88
89/*
90 * set alternate signal stack syscall
91 */
92asmlinkage long sys_sigaltstack(const stack_t __user *uss, stack_t *uoss)
93{
94 return do_sigaltstack(uss, uoss, __frame->sp);
95}
96
97/*
98 * do a signal return; undo the signal stack.
99 */
100static int restore_sigcontext(struct pt_regs *regs,
101 struct sigcontext __user *sc, long *_d0)
102{
103 unsigned int err = 0;
104
105 if (is_using_fpu(current))
106 fpu_kill_state(current);
107
108#define COPY(x) err |= __get_user(regs->x, &sc->x)
109 COPY(d1); COPY(d2); COPY(d3);
110 COPY(a0); COPY(a1); COPY(a2); COPY(a3);
111 COPY(e0); COPY(e1); COPY(e2); COPY(e3);
112 COPY(e4); COPY(e5); COPY(e6); COPY(e7);
113 COPY(lar); COPY(lir);
114 COPY(mdr); COPY(mdrq);
115 COPY(mcvf); COPY(mcrl); COPY(mcrh);
116 COPY(sp); COPY(pc);
117#undef COPY
118
119 {
120 unsigned int tmpflags;
121#ifndef CONFIG_MN10300_USING_JTAG
122#define USER_EPSW (EPSW_FLAG_Z | EPSW_FLAG_N | EPSW_FLAG_C | EPSW_FLAG_V | \
123 EPSW_T | EPSW_nAR)
124#else
125#define USER_EPSW (EPSW_FLAG_Z | EPSW_FLAG_N | EPSW_FLAG_C | EPSW_FLAG_V | \
126 EPSW_nAR)
127#endif
128 err |= __get_user(tmpflags, &sc->epsw);
129 regs->epsw = (regs->epsw & ~USER_EPSW) |
130 (tmpflags & USER_EPSW);
131 regs->orig_d0 = -1; /* disable syscall checks */
132 }
133
134 {
135 struct fpucontext *buf;
136 err |= __get_user(buf, &sc->fpucontext);
137 if (buf) {
138 if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
139 goto badframe;
140 err |= fpu_restore_sigcontext(buf);
141 }
142 }
143
144 err |= __get_user(*_d0, &sc->d0);
145 return err;
146
147badframe:
148 return 1;
149}
150
151/*
152 * standard signal return syscall
153 */
154asmlinkage long sys_sigreturn(void)
155{
156 struct sigframe __user *frame = (struct sigframe __user *) __frame->sp;
157 sigset_t set;
158 long d0;
159
160 if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
161 goto badframe;
162 if (__get_user(set.sig[0], &frame->sc.oldmask))
163 goto badframe;
164
165 if (_NSIG_WORDS > 1 &&
166 __copy_from_user(&set.sig[1], &frame->extramask,
167 sizeof(frame->extramask)))
168 goto badframe;
169
170 sigdelsetmask(&set, ~_BLOCKABLE);
171 spin_lock_irq(&current->sighand->siglock);
172 current->blocked = set;
173 recalc_sigpending();
174 spin_unlock_irq(&current->sighand->siglock);
175
176 if (restore_sigcontext(__frame, &frame->sc, &d0))
177 goto badframe;
178
179 return d0;
180
181badframe:
182 force_sig(SIGSEGV, current);
183 return 0;
184}
185
186/*
187 * realtime signal return syscall
188 */
189asmlinkage long sys_rt_sigreturn(void)
190{
191 struct rt_sigframe __user *frame =
192 (struct rt_sigframe __user *) __frame->sp;
193 sigset_t set;
194 unsigned long d0;
195
196 if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
197 goto badframe;
198 if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
199 goto badframe;
200
201 sigdelsetmask(&set, ~_BLOCKABLE);
202 spin_lock_irq(&current->sighand->siglock);
203 current->blocked = set;
204 recalc_sigpending();
205 spin_unlock_irq(&current->sighand->siglock);
206
207 if (restore_sigcontext(__frame, &frame->uc.uc_mcontext, &d0))
208 goto badframe;
209
210 if (do_sigaltstack(&frame->uc.uc_stack, NULL, __frame->sp) == -EFAULT)
211 goto badframe;
212
213 return d0;
214
215badframe:
216 force_sig(SIGSEGV, current);
217 return 0;
218}
219
220/*
221 * store the userspace context into a signal frame
222 */
223static int setup_sigcontext(struct sigcontext __user *sc,
224 struct fpucontext *fpuctx,
225 struct pt_regs *regs,
226 unsigned long mask)
227{
228 int tmp, err = 0;
229
230#define COPY(x) err |= __put_user(regs->x, &sc->x)
231 COPY(d0); COPY(d1); COPY(d2); COPY(d3);
232 COPY(a0); COPY(a1); COPY(a2); COPY(a3);
233 COPY(e0); COPY(e1); COPY(e2); COPY(e3);
234 COPY(e4); COPY(e5); COPY(e6); COPY(e7);
235 COPY(lar); COPY(lir);
236 COPY(mdr); COPY(mdrq);
237 COPY(mcvf); COPY(mcrl); COPY(mcrh);
238 COPY(sp); COPY(epsw); COPY(pc);
239#undef COPY
240
241 tmp = fpu_setup_sigcontext(fpuctx);
242 if (tmp < 0)
243 err = 1;
244 else
245 err |= __put_user(tmp ? fpuctx : NULL, &sc->fpucontext);
246
247 /* non-iBCS2 extensions.. */
248 err |= __put_user(mask, &sc->oldmask);
249
250 return err;
251}
252
253/*
254 * determine which stack to use..
255 */
256static inline void __user *get_sigframe(struct k_sigaction *ka,
257 struct pt_regs *regs,
258 size_t frame_size)
259{
260 unsigned long sp;
261
262 /* default to using normal stack */
263 sp = regs->sp;
264
265 /* this is the X/Open sanctioned signal stack switching. */
266 if (ka->sa.sa_flags & SA_ONSTACK) {
267 if (!on_sig_stack(sp))
268 sp = current->sas_ss_sp + current->sas_ss_size;
269 }
270
271 return (void __user *) ((sp - frame_size) & ~7UL);
272}
273
274/*
275 * set up a normal signal frame
276 */
277static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
278 struct pt_regs *regs)
279{
280 struct sigframe __user *frame;
281 int rsig;
282
283 frame = get_sigframe(ka, regs, sizeof(*frame));
284
285 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
286 goto give_sigsegv;
287
288 rsig = sig;
289 if (sig < 32 &&
290 current_thread_info()->exec_domain &&
291 current_thread_info()->exec_domain->signal_invmap)
292 rsig = current_thread_info()->exec_domain->signal_invmap[sig];
293
294 if (__put_user(rsig, &frame->sig) < 0 ||
295 __put_user(&frame->sc, &frame->psc) < 0)
296 goto give_sigsegv;
297
298 if (setup_sigcontext(&frame->sc, &frame->fpuctx, regs, set->sig[0]))
299 goto give_sigsegv;
300
301 if (_NSIG_WORDS > 1) {
302 if (__copy_to_user(frame->extramask, &set->sig[1],
303 sizeof(frame->extramask)))
304 goto give_sigsegv;
305 }
306
307 /* set up to return from userspace. If provided, use a stub already in
308 * userspace */
309 if (ka->sa.sa_flags & SA_RESTORER) {
310 if (__put_user(ka->sa.sa_restorer, &frame->pretcode))
311 goto give_sigsegv;
312 } else {
313 if (__put_user((void (*)(void))frame->retcode,
314 &frame->pretcode))
315 goto give_sigsegv;
316 /* this is mov $,d0; syscall 0 */
317 if (__put_user(0x2c, (char *)(frame->retcode + 0)) ||
318 __put_user(__NR_sigreturn, (char *)(frame->retcode + 1)) ||
319 __put_user(0x00, (char *)(frame->retcode + 2)) ||
320 __put_user(0xf0, (char *)(frame->retcode + 3)) ||
321 __put_user(0xe0, (char *)(frame->retcode + 4)))
322 goto give_sigsegv;
323 flush_icache_range((unsigned long) frame->retcode,
324 (unsigned long) frame->retcode + 5);
325 }
326
327 /* set up registers for signal handler */
328 regs->sp = (unsigned long) frame;
329 regs->pc = (unsigned long) ka->sa.sa_handler;
330 regs->d0 = sig;
331 regs->d1 = (unsigned long) &frame->sc;
332
333 set_fs(USER_DS);
334
335 /* the tracer may want to single-step inside the handler */
336 if (test_thread_flag(TIF_SINGLESTEP))
337 ptrace_notify(SIGTRAP);
338
339#if DEBUG_SIG
340 printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
341 sig, current->comm, current->pid, frame, regs->pc,
342 frame->pretcode);
343#endif
344
345 return 0;
346
347give_sigsegv:
348 force_sig(SIGSEGV, current);
349 return -EFAULT;
350}
351
352/*
353 * set up a realtime signal frame
354 */
355static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
356 sigset_t *set, struct pt_regs *regs)
357{
358 struct rt_sigframe __user *frame;
359 int rsig;
360
361 frame = get_sigframe(ka, regs, sizeof(*frame));
362
363 if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
364 goto give_sigsegv;
365
366 rsig = sig;
367 if (sig < 32 &&
368 current_thread_info()->exec_domain &&
369 current_thread_info()->exec_domain->signal_invmap)
370 rsig = current_thread_info()->exec_domain->signal_invmap[sig];
371
372 if (__put_user(rsig, &frame->sig) ||
373 __put_user(&frame->info, &frame->pinfo) ||
374 __put_user(&frame->uc, &frame->puc) ||
375 copy_siginfo_to_user(&frame->info, info))
376 goto give_sigsegv;
377
378 /* create the ucontext. */
379 if (__put_user(0, &frame->uc.uc_flags) ||
380 __put_user(0, &frame->uc.uc_link) ||
381 __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp) ||
382 __put_user(sas_ss_flags(regs->sp), &frame->uc.uc_stack.ss_flags) ||
383 __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size) ||
384 setup_sigcontext(&frame->uc.uc_mcontext,
385 &frame->fpuctx, regs, set->sig[0]) ||
386 __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)))
387 goto give_sigsegv;
388
389 /* set up to return from userspace. If provided, use a stub already in
390 * userspace */
391 if (ka->sa.sa_flags & SA_RESTORER) {
392 if (__put_user(ka->sa.sa_restorer, &frame->pretcode))
393 goto give_sigsegv;
394 } else {
395 if (__put_user((void(*)(void))frame->retcode,
396 &frame->pretcode) ||
397 /* This is mov $,d0; syscall 0 */
398 __put_user(0x2c, (char *)(frame->retcode + 0)) ||
399 __put_user(__NR_rt_sigreturn,
400 (char *)(frame->retcode + 1)) ||
401 __put_user(0x00, (char *)(frame->retcode + 2)) ||
402 __put_user(0xf0, (char *)(frame->retcode + 3)) ||
403 __put_user(0xe0, (char *)(frame->retcode + 4)))
404 goto give_sigsegv;
405
406 flush_icache_range((u_long) frame->retcode,
407 (u_long) frame->retcode + 5);
408 }
409
410 /* Set up registers for signal handler */
411 regs->sp = (unsigned long) frame;
412 regs->pc = (unsigned long) ka->sa.sa_handler;
413 regs->d0 = sig;
414 regs->d1 = (long) &frame->info;
415
416 set_fs(USER_DS);
417
418 /* the tracer may want to single-step inside the handler */
419 if (test_thread_flag(TIF_SINGLESTEP))
420 ptrace_notify(SIGTRAP);
421
422#if DEBUG_SIG
423 printk(KERN_DEBUG "SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
424 sig, current->comm, current->pid, frame, regs->pc,
425 frame->pretcode);
426#endif
427
428 return 0;
429
430give_sigsegv:
431 force_sig(SIGSEGV, current);
432 return -EFAULT;
433}
434
435/*
436 * handle the actual delivery of a signal to userspace
437 */
438static int handle_signal(int sig,
439 siginfo_t *info, struct k_sigaction *ka,
440 sigset_t *oldset, struct pt_regs *regs)
441{
442 int ret;
443
444 /* Are we from a system call? */
445 if (regs->orig_d0 >= 0) {
446 /* If so, check system call restarting.. */
447 switch (regs->d0) {
448 case -ERESTART_RESTARTBLOCK:
449 case -ERESTARTNOHAND:
450 regs->d0 = -EINTR;
451 break;
452
453 case -ERESTARTSYS:
454 if (!(ka->sa.sa_flags & SA_RESTART)) {
455 regs->d0 = -EINTR;
456 break;
457 }
458
459 /* fallthrough */
460 case -ERESTARTNOINTR:
461 regs->d0 = regs->orig_d0;
462 regs->pc -= 2;
463 }
464 }
465
466 /* Set up the stack frame */
467 if (ka->sa.sa_flags & SA_SIGINFO)
468 ret = setup_rt_frame(sig, ka, info, oldset, regs);
469 else
470 ret = setup_frame(sig, ka, oldset, regs);
471
472 if (ret == 0) {
473 spin_lock_irq(&current->sighand->siglock);
474 sigorsets(&current->blocked, &current->blocked,
475 &ka->sa.sa_mask);
476 if (!(ka->sa.sa_flags & SA_NODEFER))
477 sigaddset(&current->blocked, sig);
478 recalc_sigpending();
479 spin_unlock_irq(&current->sighand->siglock);
480 }
481
482 return ret;
483}
484
485/*
486 * handle a potential signal
487 */
488static void do_signal(struct pt_regs *regs)
489{
490 struct k_sigaction ka;
491 siginfo_t info;
492 sigset_t *oldset;
493 int signr;
494
495 /* we want the common case to go fast, which is why we may in certain
496 * cases get here from kernel mode */
497 if (!user_mode(regs))
498 return;
499
500 if (test_thread_flag(TIF_RESTORE_SIGMASK))
501 oldset = &current->saved_sigmask;
502 else
503 oldset = &current->blocked;
504
505 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
506 if (signr > 0) {
507 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
508 /* a signal was successfully delivered; the saved
509 * sigmask will have been stored in the signal frame,
510 * and will be restored by sigreturn, so we can simply
511 * clear the TIF_RESTORE_SIGMASK flag */
512 if (test_thread_flag(TIF_RESTORE_SIGMASK))
513 clear_thread_flag(TIF_RESTORE_SIGMASK);
514 }
515
516 return;
517 }
518
519 /* did we come from a system call? */
520 if (regs->orig_d0 >= 0) {
521 /* restart the system call - no handlers present */
522 switch (regs->d0) {
523 case -ERESTARTNOHAND:
524 case -ERESTARTSYS:
525 case -ERESTARTNOINTR:
526 regs->d0 = regs->orig_d0;
527 regs->pc -= 2;
528 break;
529
530 case -ERESTART_RESTARTBLOCK:
531 regs->d0 = __NR_restart_syscall;
532 regs->pc -= 2;
533 break;
534 }
535 }
536
537 /* if there's no signal to deliver, we just put the saved sigmask
538 * back */
539 if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
540 clear_thread_flag(TIF_RESTORE_SIGMASK);
541 sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
542 }
543}
544
545/*
546 * notification of userspace execution resumption
547 * - triggered by current->work.notify_resume
548 */
549asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
550{
551 /* Pending single-step? */
552 if (thread_info_flags & _TIF_SINGLESTEP) {
553#ifndef CONFIG_MN10300_USING_JTAG
554 regs->epsw |= EPSW_T;
555 clear_thread_flag(TIF_SINGLESTEP);
556#else
557 BUG(); /* no h/w single-step if using JTAG unit */
558#endif
559 }
560
561 /* deal with pending signal delivery */
562 if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
563 do_signal(regs);
564}
diff --git a/arch/mn10300/kernel/switch_to.S b/arch/mn10300/kernel/switch_to.S
new file mode 100644
index 000000000000..630aad71b946
--- /dev/null
+++ b/arch/mn10300/kernel/switch_to.S
@@ -0,0 +1,71 @@
1###############################################################################
2#
3# MN10300 Context switch operation
4#
5# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
6# Written by David Howells (dhowells@redhat.com)
7#
8# This program is free software; you can redistribute it and/or
9# modify it under the terms of the GNU General Public Licence
10# as published by the Free Software Foundation; either version
11# 2 of the Licence, or (at your option) any later version.
12#
13###############################################################################
14#include <linux/sys.h>
15#include <linux/linkage.h>
16#include <asm/thread_info.h>
17#include <asm/cpu-regs.h>
18
19 .text
20
21###############################################################################
22#
23# struct task_struct *__switch_to(struct thread_struct *prev,
24# struct thread_struct *next,
25# struct task_struct *prev_task)
26#
27###############################################################################
28ENTRY(__switch_to)
29 movm [d2,d3,a2,a3,exreg1],(sp)
30 or EPSW_NMID,epsw
31
32 mov (44,sp),d2
33
34 mov d0,a0
35 mov d1,a1
36
37 # save prev context
38 mov (__frame),d0
39 mov d0,(THREAD_FRAME,a0)
40 mov __switch_back,d0
41 mov d0,(THREAD_PC,a0)
42 mov sp,a2
43 mov a2,(THREAD_SP,a0)
44 mov a3,(THREAD_A3,a0)
45
46 mov (THREAD_A3,a1),a3
47 mov (THREAD_SP,a1),a2
48
49 # switch
50 mov a2,sp
51
52 # load next context
53 GET_THREAD_INFO a2
54 mov a2,(__current_ti)
55 mov (TI_task,a2),a2
56 mov a2,(__current)
57#ifdef CONFIG_MN10300_CURRENT_IN_E2
58 mov a2,e2
59#endif
60
61 mov (THREAD_FRAME,a1),a2
62 mov a2,(__frame)
63 mov (THREAD_PC,a1),a2
64 mov d2,d0 # for ret_from_fork
65 mov d0,a0 # for __switch_to
66
67 jmp (a2)
68
69__switch_back:
70 and ~EPSW_NMID,epsw
71 ret [d2,d3,a2,a3,exreg1],32
diff --git a/arch/mn10300/kernel/sys_mn10300.c b/arch/mn10300/kernel/sys_mn10300.c
new file mode 100644
index 000000000000..5f17a1ebc825
--- /dev/null
+++ b/arch/mn10300/kernel/sys_mn10300.c
@@ -0,0 +1,193 @@
1/* MN10300 Weird system calls
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/errno.h>
12#include <linux/sched.h>
13#include <linux/syscalls.h>
14#include <linux/mm.h>
15#include <linux/smp.h>
16#include <linux/smp_lock.h>
17#include <linux/sem.h>
18#include <linux/msg.h>
19#include <linux/shm.h>
20#include <linux/stat.h>
21#include <linux/mman.h>
22#include <linux/file.h>
23#include <linux/utsname.h>
24#include <linux/syscalls.h>
25#include <linux/tty.h>
26
27#include <asm/uaccess.h>
28
29#define MIN_MAP_ADDR PAGE_SIZE /* minimum fixed mmap address */
30
31/*
32 * sys_pipe() is the normal C calling standard for creating
33 * a pipe. It's not the way Unix traditionally does this, though.
34 */
35asmlinkage long sys_pipe(unsigned long __user *fildes)
36{
37 int fd[2];
38 int error;
39
40 error = do_pipe(fd);
41 if (!error) {
42 if (copy_to_user(fildes, fd, 2 * sizeof(int)))
43 error = -EFAULT;
44 }
45 return error;
46}
47
48/*
49 * memory mapping syscall
50 */
51asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
52 unsigned long prot, unsigned long flags,
53 unsigned long fd, unsigned long pgoff)
54{
55 struct file *file = NULL;
56 long error = -EINVAL;
57
58 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
59
60 if (flags & MAP_FIXED && addr < MIN_MAP_ADDR)
61 goto out;
62
63 error = -EBADF;
64 if (!(flags & MAP_ANONYMOUS)) {
65 file = fget(fd);
66 if (!file)
67 goto out;
68 }
69
70 down_write(&current->mm->mmap_sem);
71 error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
72 up_write(&current->mm->mmap_sem);
73
74 if (file)
75 fput(file);
76out:
77 return error;
78}
79
80asmlinkage long old_mmap(unsigned long addr, unsigned long len,
81 unsigned long prot, unsigned long flags,
82 unsigned long fd, unsigned long offset)
83{
84 if (offset & ~PAGE_MASK)
85 return -EINVAL;
86 return sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
87}
88
89struct sel_arg_struct {
90 unsigned long n;
91 fd_set *inp;
92 fd_set *outp;
93 fd_set *exp;
94 struct timeval *tvp;
95};
96
97asmlinkage int old_select(struct sel_arg_struct __user *arg)
98{
99 struct sel_arg_struct a;
100
101 if (copy_from_user(&a, arg, sizeof(a)))
102 return -EFAULT;
103 /* sys_select() does the appropriate kernel locking */
104 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
105}
106
107/*
108 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
109 *
110 * This is really horribly ugly.
111 */
112asmlinkage long sys_ipc(uint call, int first, int second,
113 int third, void __user *ptr, long fifth)
114{
115 int version, ret;
116
117 version = call >> 16; /* hack for backward compatibility */
118 call &= 0xffff;
119
120 switch (call) {
121 case SEMOP:
122 return sys_semtimedop(first, (struct sembuf __user *)ptr,
123 second, NULL);
124 case SEMTIMEDOP:
125 return sys_semtimedop(first, (struct sembuf __user *)ptr,
126 second,
127 (const struct timespec __user *)fifth);
128 case SEMGET:
129 return sys_semget(first, second, third);
130 case SEMCTL: {
131 union semun fourth;
132 if (!ptr)
133 return -EINVAL;
134 if (get_user(fourth.__pad, (void __user * __user *) ptr))
135 return -EFAULT;
136 return sys_semctl(first, second, third, fourth);
137 }
138
139 case MSGSND:
140 return sys_msgsnd(first, (struct msgbuf __user *) ptr,
141 second, third);
142 case MSGRCV:
143 switch (version) {
144 case 0: {
145 struct ipc_kludge tmp;
146 if (!ptr)
147 return -EINVAL;
148
149 if (copy_from_user(&tmp,
150 (struct ipc_kludge __user *) ptr,
151 sizeof(tmp)))
152 return -EFAULT;
153 return sys_msgrcv(first, tmp.msgp, second,
154 tmp.msgtyp, third);
155 }
156 default:
157 return sys_msgrcv(first,
158 (struct msgbuf __user *) ptr,
159 second, fifth, third);
160 }
161 case MSGGET:
162 return sys_msgget((key_t) first, second);
163 case MSGCTL:
164 return sys_msgctl(first, second,
165 (struct msqid_ds __user *) ptr);
166
167 case SHMAT:
168 switch (version) {
169 default: {
170 ulong raddr;
171 ret = do_shmat(first, (char __user *) ptr, second,
172 &raddr);
173 if (ret)
174 return ret;
175 return put_user(raddr, (ulong *) third);
176 }
177 case 1: /* iBCS2 emulator entry point */
178 if (!segment_eq(get_fs(), get_ds()))
179 return -EINVAL;
180 return do_shmat(first, (char __user *) ptr, second,
181 (ulong *) third);
182 }
183 case SHMDT:
184 return sys_shmdt((char __user *)ptr);
185 case SHMGET:
186 return sys_shmget(first, second, third);
187 case SHMCTL:
188 return sys_shmctl(first, second,
189 (struct shmid_ds __user *) ptr);
190 default:
191 return -EINVAL;
192 }
193}
diff --git a/arch/mn10300/kernel/time.c b/arch/mn10300/kernel/time.c
new file mode 100644
index 000000000000..ff492e3b3457
--- /dev/null
+++ b/arch/mn10300/kernel/time.c
@@ -0,0 +1,129 @@
1/* MN10300 Low level time management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/i386/kernel/time.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/interrupt.h>
15#include <linux/time.h>
16#include <linux/init.h>
17#include <linux/smp.h>
18#include <linux/profile.h>
19#include <asm/irq.h>
20#include <asm/div64.h>
21#include <asm/processor.h>
22#include <asm/intctl-regs.h>
23#include <asm/rtc.h>
24
25#ifdef CONFIG_MN10300_RTC
26unsigned long mn10300_ioclk; /* system I/O clock frequency */
27unsigned long mn10300_iobclk; /* system I/O clock frequency */
28unsigned long mn10300_tsc_per_HZ; /* number of ioclks per jiffy */
29#endif /* CONFIG_MN10300_RTC */
30
31static unsigned long mn10300_last_tsc; /* time-stamp counter at last time
32 * interrupt occurred */
33
34static irqreturn_t timer_interrupt(int irq, void *dev_id);
35
36static struct irqaction timer_irq = {
37 .handler = timer_interrupt,
38 .flags = IRQF_DISABLED | IRQF_SHARED | IRQF_TIMER,
39 .mask = CPU_MASK_NONE,
40 .name = "timer",
41};
42
43/*
44 * scheduler clock - returns current time in nanosec units.
45 */
46unsigned long long sched_clock(void)
47{
48 union {
49 unsigned long long l;
50 u32 w[2];
51 } quot;
52
53 quot.w[0] = mn10300_last_tsc - get_cycles();
54 quot.w[1] = 1000000000;
55
56 asm("mulu %2,%3,%0,%1"
57 : "=r"(quot.w[1]), "=r"(quot.w[0])
58 : "0"(quot.w[1]), "1"(quot.w[0])
59 : "cc");
60
61 do_div(quot.l, MN10300_TSCCLK);
62
63 return quot.l;
64}
65
66/*
67 * advance the kernel's time keeping clocks (xtime and jiffies)
68 * - we use Timer 0 & 1 cascaded as a clock to nudge us the next time
69 * there's a need to update
70 */
71static irqreturn_t timer_interrupt(int irq, void *dev_id)
72{
73 unsigned tsc, elapse;
74
75 write_seqlock(&xtime_lock);
76
77 while (tsc = get_cycles(),
78 elapse = mn10300_last_tsc - tsc, /* time elapsed since last
79 * tick */
80 elapse > MN10300_TSC_PER_HZ
81 ) {
82 mn10300_last_tsc -= MN10300_TSC_PER_HZ;
83
84 /* advance the kernel's time tracking system */
85 profile_tick(CPU_PROFILING);
86 do_timer(1);
87 update_process_times(user_mode(get_irq_regs()));
88 check_rtc_time();
89 }
90
91 write_sequnlock(&xtime_lock);
92 return IRQ_HANDLED;
93}
94
95/*
96 * initialise the various timers used by the main part of the kernel
97 */
98void __init time_init(void)
99{
100 /* we need the prescalar running to be able to use IOCLK/8
101 * - IOCLK runs at 1/4 (ST5 open) or 1/8 (ST5 closed) internal CPU clock
102 * - IOCLK runs at Fosc rate (crystal speed)
103 */
104 TMPSCNT |= TMPSCNT_ENABLE;
105
106 startup_timestamp_counter();
107
108 printk(KERN_INFO
109 "timestamp counter I/O clock running at %lu.%02lu"
110 " (calibrated against RTC)\n",
111 MN10300_TSCCLK / 1000000, (MN10300_TSCCLK / 10000) % 100);
112
113 xtime.tv_sec = get_initial_rtc_time();
114 xtime.tv_nsec = 0;
115
116 mn10300_last_tsc = TMTSCBC;
117
118 /* use timer 0 & 1 cascaded to tick at as close to HZ as possible */
119 setup_irq(TMJCIRQ, &timer_irq);
120
121 set_intr_level(TMJCIRQ, TMJCICR_LEVEL);
122
123 startup_jiffies_counter();
124
125#ifdef CONFIG_MN10300_WD_TIMER
126 /* start the watchdog timer */
127 watchdog_go();
128#endif
129}
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c
new file mode 100644
index 000000000000..8b9dc6d9dcc6
--- /dev/null
+++ b/arch/mn10300/kernel/traps.c
@@ -0,0 +1,619 @@
1/* MN10300 Exception handling
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/string.h>
15#include <linux/errno.h>
16#include <linux/ptrace.h>
17#include <linux/timer.h>
18#include <linux/mm.h>
19#include <linux/smp.h>
20#include <linux/smp_lock.h>
21#include <linux/init.h>
22#include <linux/delay.h>
23#include <linux/spinlock.h>
24#include <linux/interrupt.h>
25#include <linux/kallsyms.h>
26#include <linux/pci.h>
27#include <linux/kdebug.h>
28#include <linux/bug.h>
29#include <linux/irq.h>
30#include <asm/processor.h>
31#include <asm/system.h>
32#include <asm/uaccess.h>
33#include <asm/io.h>
34#include <asm/atomic.h>
35#include <asm/smp.h>
36#include <asm/pgalloc.h>
37#include <asm/cacheflush.h>
38#include <asm/cpu-regs.h>
39#include <asm/busctl-regs.h>
40#include <asm/unit/leds.h>
41#include <asm/fpu.h>
42#include <asm/gdb-stub.h>
43#include <asm/sections.h>
44
45#if (CONFIG_INTERRUPT_VECTOR_BASE & 0xffffff)
46#error "INTERRUPT_VECTOR_BASE not aligned to 16MiB boundary!"
47#endif
48
49struct pt_regs *__frame; /* current frame pointer */
50EXPORT_SYMBOL(__frame);
51
52int kstack_depth_to_print = 24;
53
54spinlock_t die_lock = __SPIN_LOCK_UNLOCKED(die_lock);
55
56ATOMIC_NOTIFIER_HEAD(mn10300_die_chain);
57
58/*
59 * These constants are for searching for possible module text
60 * segments. MODULE_RANGE is a guess of how much space is likely
61 * to be vmalloced.
62 */
63#define MODULE_RANGE (8 * 1024 * 1024)
64
65#define DO_ERROR(signr, prologue, str, name) \
66asmlinkage void name(struct pt_regs *regs, u32 intcode) \
67{ \
68 prologue; \
69 if (die_if_no_fixup(str, regs, intcode)) \
70 return; \
71 force_sig(signr, current); \
72}
73
74#define DO_EINFO(signr, prologue, str, name, sicode) \
75asmlinkage void name(struct pt_regs *regs, u32 intcode) \
76{ \
77 siginfo_t info; \
78 prologue; \
79 if (die_if_no_fixup(str, regs, intcode)) \
80 return; \
81 info.si_signo = signr; \
82 if (signr == SIGILL && sicode == ILL_ILLOPC) { \
83 uint8_t opcode; \
84 if (get_user(opcode, (uint8_t __user *)regs->pc) == 0) \
85 if (opcode == 0xff) \
86 info.si_signo = SIGTRAP; \
87 } \
88 info.si_errno = 0; \
89 info.si_code = sicode; \
90 info.si_addr = (void *) regs->pc; \
91 force_sig_info(info.si_signo, &info, current); \
92}
93
94DO_ERROR(SIGTRAP, {}, "trap", trap);
95DO_ERROR(SIGSEGV, {}, "ibreak", ibreak);
96DO_ERROR(SIGSEGV, {}, "obreak", obreak);
97DO_EINFO(SIGSEGV, {}, "access error", access_error, SEGV_ACCERR);
98DO_EINFO(SIGSEGV, {}, "insn access error", insn_acc_error, SEGV_ACCERR);
99DO_EINFO(SIGSEGV, {}, "data access error", data_acc_error, SEGV_ACCERR);
100DO_EINFO(SIGILL, {}, "privileged opcode", priv_op, ILL_PRVOPC);
101DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC);
102DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC);
103DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR);
104DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR);
105DO_EINFO(SIGILL, {}, "FPU invalid opcode", fpu_invalid_op, ILL_COPROC);
106
107DO_ERROR(SIGTRAP,
108#ifndef CONFIG_MN10300_USING_JTAG
109 DCR &= ~0x0001,
110#else
111 {},
112#endif
113 "single step", istep);
114
115/*
116 * handle NMI
117 */
118asmlinkage void nmi(struct pt_regs *regs, enum exception_code code)
119{
120 /* see if gdbstub wants to deal with it */
121#ifdef CONFIG_GDBSTUB
122 if (gdbstub_intercept(regs, code))
123 return;
124#endif
125
126 printk(KERN_WARNING "--- Register Dump ---\n");
127 show_registers(regs);
128 printk(KERN_WARNING "---------------------\n");
129}
130
131/*
132 * show a stack trace from the specified stack pointer
133 */
134void show_trace(unsigned long *sp)
135{
136 unsigned long *stack, addr, module_start, module_end;
137 int i;
138
139 printk(KERN_EMERG "\n"
140 KERN_EMERG "Call Trace:");
141
142 stack = sp;
143 i = 0;
144 module_start = VMALLOC_START;
145 module_end = VMALLOC_END;
146
147 while (((long) stack & (THREAD_SIZE - 1)) != 0) {
148 addr = *stack++;
149 if (__kernel_text_address(addr)) {
150#if 1
151 printk(" [<%08lx>]", addr);
152 print_symbol(" %s", addr);
153 printk("\n");
154#else
155 if ((i % 6) == 0)
156 printk("\n" KERN_EMERG " ");
157 printk("[<%08lx>] ", addr);
158 i++;
159#endif
160 }
161 }
162
163 printk("\n");
164}
165
166/*
167 * show the raw stack from the specified stack pointer
168 */
169void show_stack(struct task_struct *task, unsigned long *sp)
170{
171 unsigned long *stack;
172 int i;
173
174 if (!sp)
175 sp = (unsigned long *) &sp;
176
177 stack = sp;
178 printk(KERN_EMERG "Stack:");
179 for (i = 0; i < kstack_depth_to_print; i++) {
180 if (((long) stack & (THREAD_SIZE - 1)) == 0)
181 break;
182 if ((i % 8) == 0)
183 printk("\n" KERN_EMERG " ");
184 printk("%08lx ", *stack++);
185 }
186
187 show_trace(sp);
188}
189
190/*
191 * the architecture-independent dump_stack generator
192 */
193void dump_stack(void)
194{
195 unsigned long stack;
196
197 show_stack(current, &stack);
198}
199EXPORT_SYMBOL(dump_stack);
200
201/*
202 * dump the register file in the specified exception frame
203 */
204void show_registers_only(struct pt_regs *regs)
205{
206 unsigned long ssp;
207
208 ssp = (unsigned long) regs + sizeof(*regs);
209
210 printk(KERN_EMERG "PC: %08lx EPSW: %08lx SSP: %08lx mode: %s\n",
211 regs->pc, regs->epsw, ssp, user_mode(regs) ? "User" : "Super");
212 printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
213 regs->d0, regs->d1, regs->d2, regs->d3);
214 printk(KERN_EMERG "a0: %08lx a1: %08lx a2: %08lx a3: %08lx\n",
215 regs->a0, regs->a1, regs->a2, regs->a3);
216 printk(KERN_EMERG "e0: %08lx e1: %08lx e2: %08lx e3: %08lx\n",
217 regs->e0, regs->e1, regs->e2, regs->e3);
218 printk(KERN_EMERG "e4: %08lx e5: %08lx e6: %08lx e7: %08lx\n",
219 regs->e4, regs->e5, regs->e6, regs->e7);
220 printk(KERN_EMERG "lar: %08lx lir: %08lx mdr: %08lx usp: %08lx\n",
221 regs->lar, regs->lir, regs->mdr, regs->sp);
222 printk(KERN_EMERG "cvf: %08lx crl: %08lx crh: %08lx drq: %08lx\n",
223 regs->mcvf, regs->mcrl, regs->mcrh, regs->mdrq);
224 printk(KERN_EMERG "threadinfo=%p task=%p)\n",
225 current_thread_info(), current);
226
227 if ((unsigned long) current >= 0x90000000UL &&
228 (unsigned long) current < 0x94000000UL)
229 printk(KERN_EMERG "Process %s (pid: %d)\n",
230 current->comm, current->pid);
231
232 printk(KERN_EMERG "CPUP: %04hx\n", CPUP);
233 printk(KERN_EMERG "TBR: %08x\n", TBR);
234 printk(KERN_EMERG "DEAR: %08x\n", DEAR);
235 printk(KERN_EMERG "sISR: %08x\n", sISR);
236 printk(KERN_EMERG "NMICR: %04hx\n", NMICR);
237 printk(KERN_EMERG "BCBERR: %08x\n", BCBERR);
238 printk(KERN_EMERG "BCBEAR: %08x\n", BCBEAR);
239 printk(KERN_EMERG "MMUFCR: %08x\n", MMUFCR);
240 printk(KERN_EMERG "IPTEU : %08x IPTEL2: %08x\n", IPTEU, IPTEL2);
241 printk(KERN_EMERG "DPTEU: %08x DPTEL2: %08x\n", DPTEU, DPTEL2);
242}
243
244/*
245 * dump the registers and the stack
246 */
247void show_registers(struct pt_regs *regs)
248{
249 unsigned long sp;
250 int i;
251
252 show_registers_only(regs);
253
254 if (!user_mode(regs))
255 sp = (unsigned long) regs + sizeof(*regs);
256 else
257 sp = regs->sp;
258
259 /* when in-kernel, we also print out the stack and code at the
260 * time of the fault..
261 */
262 if (!user_mode(regs)) {
263 printk(KERN_EMERG "\n");
264 show_stack(current, (unsigned long *) sp);
265
266#if 0
267 printk(KERN_EMERG "\n"
268 KERN_EMERG "Code: ");
269 if (regs->pc < PAGE_OFFSET)
270 goto bad;
271
272 for (i = 0; i < 20; i++) {
273 unsigned char c;
274 if (__get_user(c, &((unsigned char *) regs->pc)[i]))
275 goto bad;
276 printk("%02x ", c);
277 }
278#else
279 i = 0;
280#endif
281 }
282
283 printk("\n");
284 return;
285
286#if 0
287bad:
288 printk(KERN_EMERG " Bad PC value.");
289 break;
290#endif
291}
292
293/*
294 *
295 */
296void show_trace_task(struct task_struct *tsk)
297{
298 unsigned long sp = tsk->thread.sp;
299
300 /* User space on another CPU? */
301 if ((sp ^ (unsigned long) tsk) & (PAGE_MASK << 1))
302 return;
303
304 show_trace((unsigned long *) sp);
305}
306
307/*
308 * note the untimely death of part of the kernel
309 */
310void die(const char *str, struct pt_regs *regs, enum exception_code code)
311{
312 console_verbose();
313 spin_lock_irq(&die_lock);
314 printk(KERN_EMERG "\n"
315 KERN_EMERG "%s: %04x\n",
316 str, code & 0xffff);
317 show_registers(regs);
318
319 if (regs->pc >= 0x02000000 && regs->pc < 0x04000000 &&
320 (regs->epsw & (EPSW_IM | EPSW_IE)) != (EPSW_IM | EPSW_IE)) {
321 printk(KERN_EMERG "Exception in usermode interrupt handler\n");
322 printk(KERN_EMERG "\n"
323 KERN_EMERG " Please connect to kernel debugger !!\n");
324 asm volatile ("0: bra 0b");
325 }
326
327 spin_unlock_irq(&die_lock);
328 do_exit(SIGSEGV);
329}
330
331/*
332 * see if there's a fixup handler we can force a jump to when an exception
333 * happens due to something kernel code did
334 */
335int die_if_no_fixup(const char *str, struct pt_regs *regs,
336 enum exception_code code)
337{
338 if (user_mode(regs))
339 return 0;
340
341 peripheral_leds_display_exception(code);
342
343 switch (code) {
344 /* see if we can fixup the kernel accessing memory */
345 case EXCEP_ITLBMISS:
346 case EXCEP_DTLBMISS:
347 case EXCEP_IAERROR:
348 case EXCEP_DAERROR:
349 case EXCEP_MEMERR:
350 case EXCEP_MISALIGN:
351 case EXCEP_BUSERROR:
352 case EXCEP_ILLDATACC:
353 case EXCEP_IOINSACC:
354 case EXCEP_PRIVINSACC:
355 case EXCEP_PRIVDATACC:
356 case EXCEP_DATINSACC:
357 if (fixup_exception(regs))
358 return 1;
359 case EXCEP_UNIMPINS:
360 if (regs->pc && *(uint8_t *)regs->pc == 0xff)
361 if (notify_die(DIE_BREAKPOINT, str, regs, code, 0, 0))
362 return 1;
363 break;
364 default:
365 break;
366 }
367
368 /* see if gdbstub wants to deal with it */
369#ifdef CONFIG_GDBSTUB
370 if (gdbstub_intercept(regs, code))
371 return 1;
372#endif
373
374 if (notify_die(DIE_GPF, str, regs, code, 0, 0))
375 return 1;
376
377 /* make the process die as the last resort */
378 die(str, regs, code);
379}
380
381/*
382 * handle unsupported syscall instructions (syscall 1-15)
383 */
384static asmlinkage void unsupported_syscall(struct pt_regs *regs,
385 enum exception_code code)
386{
387 struct task_struct *tsk = current;
388 siginfo_t info;
389
390 /* catch a kernel BUG() */
391 if (code == EXCEP_SYSCALL15 && !user_mode(regs)) {
392 if (report_bug(regs->pc, regs) == BUG_TRAP_TYPE_BUG) {
393#ifdef CONFIG_GDBSTUB
394 __gdbstub_bug_trap();
395#endif
396 }
397 }
398
399 regs->pc -= 2; /* syscall return addr is _after_ the instruction */
400
401 die_if_no_fixup("An unsupported syscall insn was used by the kernel\n",
402 regs, code);
403
404 info.si_signo = SIGILL;
405 info.si_errno = ENOSYS;
406 info.si_code = ILL_ILLTRP;
407 info.si_addr = (void *) regs->pc;
408 force_sig_info(SIGILL, &info, tsk);
409}
410
411/*
412 * display the register file when the stack pointer gets clobbered
413 */
414asmlinkage void do_double_fault(struct pt_regs *regs)
415{
416 struct task_struct *tsk = current;
417
418 strcpy(tsk->comm, "emergency tsk");
419 tsk->pid = 0;
420 console_verbose();
421 printk(KERN_EMERG "--- double fault ---\n");
422 show_registers(regs);
423}
424
425/*
426 * asynchronous bus error (external, usually I/O DMA)
427 */
428asmlinkage void io_bus_error(u32 bcberr, u32 bcbear, struct pt_regs *regs)
429{
430 console_verbose();
431
432 printk(KERN_EMERG "\n"
433 KERN_EMERG "Asynchronous I/O Bus Error\n"
434 KERN_EMERG "==========================\n");
435
436 if (bcberr & BCBERR_BEME)
437 printk(KERN_EMERG "- Multiple recorded errors\n");
438
439 printk(KERN_EMERG "- Faulting Buses:%s%s%s\n",
440 bcberr & BCBERR_BEMR_CI ? " CPU-Ins-Fetch" : "",
441 bcberr & BCBERR_BEMR_CD ? " CPU-Data" : "",
442 bcberr & BCBERR_BEMR_DMA ? " DMA" : "");
443
444 printk(KERN_EMERG "- %s %s access made to %s at address %08x\n",
445 bcberr & BCBERR_BEBST ? "Burst" : "Single",
446 bcberr & BCBERR_BERW ? "Read" : "Write",
447 bcberr & BCBERR_BESB_MON ? "Monitor Space" :
448 bcberr & BCBERR_BESB_IO ? "Internal CPU I/O Space" :
449 bcberr & BCBERR_BESB_EX ? "External I/O Bus" :
450 bcberr & BCBERR_BESB_OPEX ? "External Memory Bus" :
451 "On Chip Memory",
452 bcbear
453 );
454
455 printk(KERN_EMERG "- Detected by the %s\n",
456 bcberr&BCBERR_BESD ? "Bus Control Unit" : "Slave Bus");
457
458#ifdef CONFIG_PCI
459#define BRIDGEREGB(X) (*(volatile __u8 *)(0xBE040000 + (X)))
460#define BRIDGEREGW(X) (*(volatile __u16 *)(0xBE040000 + (X)))
461#define BRIDGEREGL(X) (*(volatile __u32 *)(0xBE040000 + (X)))
462
463 printk(KERN_EMERG "- PCI Memory Paging Reg: %08x\n",
464 *(volatile __u32 *) (0xBFFFFFF4));
465 printk(KERN_EMERG "- PCI Bridge Base Address 0: %08x\n",
466 BRIDGEREGL(PCI_BASE_ADDRESS_0));
467 printk(KERN_EMERG "- PCI Bridge AMPCI Base Address: %08x\n",
468 BRIDGEREGL(0x48));
469 printk(KERN_EMERG "- PCI Bridge Command: %04hx\n",
470 BRIDGEREGW(PCI_COMMAND));
471 printk(KERN_EMERG "- PCI Bridge Status: %04hx\n",
472 BRIDGEREGW(PCI_STATUS));
473 printk(KERN_EMERG "- PCI Bridge Int Status: %08hx\n",
474 BRIDGEREGL(0x4c));
475#endif
476
477 printk(KERN_EMERG "\n");
478 show_registers(regs);
479
480 panic("Halted due to asynchronous I/O Bus Error\n");
481}
482
483/*
484 * handle an exception for which a handler has not yet been installed
485 */
486asmlinkage void uninitialised_exception(struct pt_regs *regs,
487 enum exception_code code)
488{
489
490 /* see if gdbstub wants to deal with it */
491#ifdef CONFIG_GDBSTUB
492 if (gdbstub_intercept(regs, code))
493 return;
494#endif
495
496 peripheral_leds_display_exception(code);
497 printk(KERN_EMERG "Uninitialised Exception 0x%04x\n", code & 0xFFFF);
498 show_registers(regs);
499
500 for (;;)
501 continue;
502}
503
504/*
505 * set an interrupt stub to jump to a handler
506 * ! NOTE: this does *not* flush the caches
507 */
508void __init __set_intr_stub(enum exception_code code, void *handler)
509{
510 unsigned long addr;
511 u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
512
513 addr = (unsigned long) handler - (unsigned long) vector;
514 vector[0] = 0xdc; /* JMP handler */
515 vector[1] = addr;
516 vector[2] = addr >> 8;
517 vector[3] = addr >> 16;
518 vector[4] = addr >> 24;
519 vector[5] = 0xcb;
520 vector[6] = 0xcb;
521 vector[7] = 0xcb;
522}
523
524/*
525 * set an interrupt stub to jump to a handler
526 */
527void __init set_intr_stub(enum exception_code code, void *handler)
528{
529 unsigned long addr;
530 u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
531
532 addr = (unsigned long) handler - (unsigned long) vector;
533 vector[0] = 0xdc; /* JMP handler */
534 vector[1] = addr;
535 vector[2] = addr >> 8;
536 vector[3] = addr >> 16;
537 vector[4] = addr >> 24;
538 vector[5] = 0xcb;
539 vector[6] = 0xcb;
540 vector[7] = 0xcb;
541
542 mn10300_dcache_flush_inv();
543 mn10300_icache_inv();
544}
545
546/*
547 * set an interrupt stub to invoke the JTAG unit and then jump to a handler
548 */
549void __init set_jtag_stub(enum exception_code code, void *handler)
550{
551 unsigned long addr;
552 u8 *vector = (u8 *)(CONFIG_INTERRUPT_VECTOR_BASE + code);
553
554 addr = (unsigned long) handler - ((unsigned long) vector + 1);
555 vector[0] = 0xff; /* PI to jump into JTAG debugger */
556 vector[1] = 0xdc; /* jmp handler */
557 vector[2] = addr;
558 vector[3] = addr >> 8;
559 vector[4] = addr >> 16;
560 vector[5] = addr >> 24;
561 vector[6] = 0xcb;
562 vector[7] = 0xcb;
563
564 mn10300_dcache_flush_inv();
565 flush_icache_range((unsigned long) vector, (unsigned long) vector + 8);
566}
567
568/*
569 * initialise the exception table
570 */
571void __init trap_init(void)
572{
573 set_excp_vector(EXCEP_TRAP, trap);
574 set_excp_vector(EXCEP_ISTEP, istep);
575 set_excp_vector(EXCEP_IBREAK, ibreak);
576 set_excp_vector(EXCEP_OBREAK, obreak);
577
578 set_excp_vector(EXCEP_PRIVINS, priv_op);
579 set_excp_vector(EXCEP_UNIMPINS, invalid_op);
580 set_excp_vector(EXCEP_UNIMPEXINS, invalid_exop);
581 set_excp_vector(EXCEP_MEMERR, mem_error);
582 set_excp_vector(EXCEP_MISALIGN, misalignment);
583 set_excp_vector(EXCEP_BUSERROR, bus_error);
584 set_excp_vector(EXCEP_ILLINSACC, insn_acc_error);
585 set_excp_vector(EXCEP_ILLDATACC, data_acc_error);
586 set_excp_vector(EXCEP_IOINSACC, insn_acc_error);
587 set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error);
588 set_excp_vector(EXCEP_PRIVDATACC, data_acc_error);
589 set_excp_vector(EXCEP_DATINSACC, insn_acc_error);
590 set_excp_vector(EXCEP_FPU_DISABLED, fpu_disabled);
591 set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op);
592 set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception);
593
594 set_excp_vector(EXCEP_NMI, nmi);
595
596 set_excp_vector(EXCEP_SYSCALL1, unsupported_syscall);
597 set_excp_vector(EXCEP_SYSCALL2, unsupported_syscall);
598 set_excp_vector(EXCEP_SYSCALL3, unsupported_syscall);
599 set_excp_vector(EXCEP_SYSCALL4, unsupported_syscall);
600 set_excp_vector(EXCEP_SYSCALL5, unsupported_syscall);
601 set_excp_vector(EXCEP_SYSCALL6, unsupported_syscall);
602 set_excp_vector(EXCEP_SYSCALL7, unsupported_syscall);
603 set_excp_vector(EXCEP_SYSCALL8, unsupported_syscall);
604 set_excp_vector(EXCEP_SYSCALL9, unsupported_syscall);
605 set_excp_vector(EXCEP_SYSCALL10, unsupported_syscall);
606 set_excp_vector(EXCEP_SYSCALL11, unsupported_syscall);
607 set_excp_vector(EXCEP_SYSCALL12, unsupported_syscall);
608 set_excp_vector(EXCEP_SYSCALL13, unsupported_syscall);
609 set_excp_vector(EXCEP_SYSCALL14, unsupported_syscall);
610 set_excp_vector(EXCEP_SYSCALL15, unsupported_syscall);
611}
612
613/*
614 * determine if a program counter value is a valid bug address
615 */
616int is_valid_bugaddr(unsigned long pc)
617{
618 return pc >= PAGE_OFFSET;
619}
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..a3e80f444f55
--- /dev/null
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -0,0 +1,159 @@
1/* MN10300 Main kernel linker script
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#define __VMLINUX_LDS__
12#include <asm-generic/vmlinux.lds.h>
13#include <asm/thread_info.h>
14
15OUTPUT_FORMAT("elf32-am33lin", "elf32-am33lin", "elf32-am33lin")
16OUTPUT_ARCH(mn10300)
17ENTRY(_start)
18jiffies = jiffies_64;
19#ifndef CONFIG_MN10300_CURRENT_IN_E2
20current = __current;
21#endif
22SECTIONS
23{
24 . = CONFIG_KERNEL_TEXT_ADDRESS;
25 /* read-only */
26 _stext = .;
27 _text = .; /* Text and read-only data */
28 .text : {
29 *(
30 .text.head
31 .text
32 )
33 TEXT_TEXT
34 SCHED_TEXT
35 LOCK_TEXT
36 KPROBES_TEXT
37 *(.fixup)
38 *(.gnu.warning)
39 } = 0xcb
40
41 _etext = .; /* End of text section */
42
43 . = ALIGN(16); /* Exception table */
44 __start___ex_table = .;
45 __ex_table : { *(__ex_table) }
46 __stop___ex_table = .;
47
48 BUG_TABLE
49
50 RODATA
51
52 /* writeable */
53 .data : { /* Data */
54 DATA_DATA
55 CONSTRUCTORS
56 }
57
58 . = ALIGN(4096);
59 __nosave_begin = .;
60 .data_nosave : { *(.data.nosave) }
61 . = ALIGN(4096);
62 __nosave_end = .;
63
64 . = ALIGN(4096);
65 .data.page_aligned : { *(.data.idt) }
66
67 . = ALIGN(32);
68 .data.cacheline_aligned : { *(.data.cacheline_aligned) }
69
70 /* rarely changed data like cpu maps */
71 . = ALIGN(32);
72 .data.read_mostly : AT(ADDR(.data.read_mostly)) {
73 *(.data.read_mostly)
74 _edata = .; /* End of data section */
75 }
76
77 . = ALIGN(THREAD_SIZE); /* init_task */
78 .data.init_task : { *(.data.init_task) }
79
80 /* might get freed after init */
81 . = ALIGN(4096);
82 .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) {
83 __smp_locks = .;
84 *(.smp_locks)
85 __smp_locks_end = .;
86 }
87
88 /* will be freed after init */
89 . = ALIGN(4096); /* Init code and data */
90 __init_begin = .;
91 .init.text : {
92 _sinittext = .;
93 *(.init.text)
94 _einittext = .;
95 }
96 .init.data : { *(.init.data) }
97 . = ALIGN(16);
98 __setup_start = .;
99 .setup.init : { KEEP(*(.init.setup)) }
100 __setup_end = .;
101
102 __initcall_start = .;
103 .initcall.init : {
104 INITCALLS
105 }
106 __initcall_end = .;
107 __con_initcall_start = .;
108 .con_initcall.init : { *(.con_initcall.init) }
109 __con_initcall_end = .;
110
111 SECURITY_INIT
112 . = ALIGN(4);
113 __alt_instructions = .;
114 .altinstructions : { *(.altinstructions) }
115 __alt_instructions_end = .;
116 .altinstr_replacement : { *(.altinstr_replacement) }
117 /* .exit.text is discard at runtime, not link time, to deal with references
118 from .altinstructions and .eh_frame */
119 .exit.text : { *(.exit.text) }
120 .exit.data : { *(.exit.data) }
121
122#ifdef CONFIG_BLK_DEV_INITRD
123 . = ALIGN(4096);
124 __initramfs_start = .;
125 .init.ramfs : { *(.init.ramfs) }
126 __initramfs_end = .;
127#endif
128
129 . = ALIGN(32);
130 __per_cpu_start = .;
131 .data.percpu : { *(.data.percpu) }
132 __per_cpu_end = .;
133 . = ALIGN(4096);
134 __init_end = .;
135 /* freed after init ends here */
136
137 __bss_start = .; /* BSS */
138 .bss : {
139 *(.bss.page_aligned)
140 *(.bss)
141 }
142 . = ALIGN(4);
143 __bss_stop = .;
144
145 _end = . ;
146
147 /* This is where the kernel creates the early boot page tables */
148 . = ALIGN(4096);
149 pg0 = .;
150
151 /* Sections to be discarded */
152 /DISCARD/ : {
153 *(.exitcall.exit)
154 }
155
156 STABS_DEBUG
157
158 DWARF_DEBUG
159}
diff --git a/arch/mn10300/lib/Makefile b/arch/mn10300/lib/Makefile
new file mode 100644
index 000000000000..fdfa9ec5b5bb
--- /dev/null
+++ b/arch/mn10300/lib/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the MN10300-specific library files..
3#
4
5lib-y = delay.o usercopy.o checksum.o bitops.o memcpy.o memmove.o memset.o
6lib-y += do_csum.o
7lib-y += __ashldi3.o __ashrdi3.o __lshrdi3.o negdi2.o
diff --git a/arch/mn10300/lib/__ashldi3.S b/arch/mn10300/lib/__ashldi3.S
new file mode 100644
index 000000000000..a51a9506f00c
--- /dev/null
+++ b/arch/mn10300/lib/__ashldi3.S
@@ -0,0 +1,51 @@
1/* MN10300 64-bit arithmetic left shift
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cache.h>
12
13 .text
14 .balign L1_CACHE_BYTES
15
16###############################################################################
17#
18# unsigned long long __ashldi3(unsigned long long value [D1:D0],
19# unsigned by [(12,SP)])
20#
21###############################################################################
22 .globl __ashldi3
23 .type __ashldi3,@function
24__ashldi3:
25 mov (12,sp),a0
26 and +63,a0
27 beq __ashldi3_zero
28
29 cmp +31,a0
30 bhi __ashldi3_32plus
31
32 # the count is in the range 1-31
33 asl a0,d1
34
35 mov +32,a1
36 sub a0,a1,a1 # a1 = 32 - count
37 lsr a1,d0,a1 # get overflow from LSW -> MSW
38
39 or_asl a1,d1,a0,d0 # insert overflow into MSW and
40 # shift the LSW
41 rets
42
43 .balign L1_CACHE_BYTES
44 # the count is in the range 32-63
45__ashldi3_32plus:
46 asl a0,d0,d1
47 clr d0
48__ashldi3_zero:
49 rets
50
51 .size __ashldi3, .-__ashldi3
diff --git a/arch/mn10300/lib/__ashrdi3.S b/arch/mn10300/lib/__ashrdi3.S
new file mode 100644
index 000000000000..6f42382728cb
--- /dev/null
+++ b/arch/mn10300/lib/__ashrdi3.S
@@ -0,0 +1,52 @@
1/* MN10300 64-bit arithmetic right shift
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cache.h>
12
13 .text
14 .balign L1_CACHE_BYTES
15
16###############################################################################
17#
18# unsigned long long __ashrdi3(unsigned long long value [D1:D0],
19# unsigned by [(12,SP)])
20#
21###############################################################################
22 .globl __ashrdi3
23 .type __ashrdi3,@function
24__ashrdi3:
25 mov (12,sp),a0
26 and +63,a0
27 beq __ashrdi3_zero
28
29 cmp +31,a0
30 bhi __ashrdi3_32plus
31
32 # the count is in the range 1-31
33 lsr a0,d0
34
35 mov +32,a1
36 sub a0,a1,a1 # a1 = 32 - count
37 asl a1,d1,a1 # get underflow from MSW -> LSW
38
39 or_asr a1,d0,a0,d1 # insert underflow into LSW and
40 # shift the MSW
41 rets
42
43 .balign L1_CACHE_BYTES
44 # the count is in the range 32-63
45__ashrdi3_32plus:
46 asr a0,d1,d0
47 ext d0 # sign-extend result through MDR
48 mov mdr,d1
49__ashrdi3_zero:
50 rets
51
52 .size __ashrdi3, .-__ashrdi3
diff --git a/arch/mn10300/lib/__lshrdi3.S b/arch/mn10300/lib/__lshrdi3.S
new file mode 100644
index 000000000000..a686aef31e90
--- /dev/null
+++ b/arch/mn10300/lib/__lshrdi3.S
@@ -0,0 +1,52 @@
1/* MN10300 64-bit logical right shift
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <asm/cache.h>
13
14 .text
15 .balign L1_CACHE_BYTES
16
17###############################################################################
18#
19# unsigned long long __lshrdi3(unsigned long long value [D1:D0],
20# unsigned by [(12,SP)])
21#
22###############################################################################
23 .globl __lshrdi3
24 .type __lshrdi3,@function
25__lshrdi3:
26 mov (12,sp),a0
27 and +63,a0
28 beq __lshrdi3_zero
29
30 cmp +31,a0
31 bhi __lshrdi3_32plus
32
33 # the count is in the range 1-31
34 lsr a0,d0
35
36 mov +32,a1
37 sub a0,a1,a1 # a1 = 32 - count
38 asl a1,d1,a1 # get underflow from MSW -> LSW
39
40 or_lsr a1,d0,a0,d1 # insert underflow into LSW and
41 # shift the MSW
42 rets
43
44 .balign L1_CACHE_BYTES
45 # the count is in the range 32-63
46__lshrdi3_32plus:
47 lsr a0,d1,d0
48 clr d1
49__lshrdi3_zero:
50 rets
51
52 .size __lshrdi3, .-__lshrdi3
diff --git a/arch/mn10300/lib/ashrdi3.c b/arch/mn10300/lib/ashrdi3.c
new file mode 100644
index 000000000000..c54f61ddf0b5
--- /dev/null
+++ b/arch/mn10300/lib/ashrdi3.c
@@ -0,0 +1,61 @@
1/* ashrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
2/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public Licence as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public Licence for more details.
15
16You should have received a copy of the GNU General Public Licence
17along with GNU CC; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#define BITS_PER_UNIT 8
22
23typedef int SItype __attribute__((mode(SI)));
24typedef unsigned int USItype __attribute__((mode(SI)));
25typedef int DItype __attribute__((mode(DI)));
26typedef int word_type __attribute__((mode(__word__)));
27
28struct DIstruct {
29 SItype low;
30 SItype high;
31};
32
33union DIunion {
34 struct DIstruct s;
35 DItype ll;
36};
37
38DItype __ashrdi3(DItype u, word_type b)
39{
40 union DIunion w;
41 union DIunion uu;
42 word_type bm;
43
44 if (b == 0)
45 return u;
46
47 uu.ll = u;
48
49 bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
50 if (bm <= 0) {
51 /* w.s.high = 1..1 or 0..0 */
52 w.s.high = uu.s.high >> (sizeof(SItype) * BITS_PER_UNIT - 1);
53 w.s.low = uu.s.high >> -bm;
54 } else {
55 USItype carries = (USItype)uu.s.high << bm;
56 w.s.high = uu.s.high >> b;
57 w.s.low = ((USItype)uu.s.low >> b) | carries;
58 }
59
60 return w.ll;
61}
diff --git a/arch/mn10300/lib/bitops.c b/arch/mn10300/lib/bitops.c
new file mode 100644
index 000000000000..440a7dcbf87b
--- /dev/null
+++ b/arch/mn10300/lib/bitops.c
@@ -0,0 +1,51 @@
1/* MN10300 Non-trivial bit operations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <asm/bitops.h>
13#include <asm/system.h>
14
15/*
16 * try flipping a bit using BSET and BCLR
17 */
18void change_bit(int nr, volatile void *addr)
19{
20 if (test_bit(nr, addr))
21 goto try_clear_bit;
22
23try_set_bit:
24 if (!test_and_set_bit(nr, addr))
25 return;
26
27try_clear_bit:
28 if (test_and_clear_bit(nr, addr))
29 return;
30
31 goto try_set_bit;
32}
33
34/*
35 * try flipping a bit using BSET and BCLR and returning the old value
36 */
37int test_and_change_bit(int nr, volatile void *addr)
38{
39 if (test_bit(nr, addr))
40 goto try_clear_bit;
41
42try_set_bit:
43 if (!test_and_set_bit(nr, addr))
44 return 0;
45
46try_clear_bit:
47 if (test_and_clear_bit(nr, addr))
48 return 1;
49
50 goto try_set_bit;
51}
diff --git a/arch/mn10300/lib/checksum.c b/arch/mn10300/lib/checksum.c
new file mode 100644
index 000000000000..274f29ec33c1
--- /dev/null
+++ b/arch/mn10300/lib/checksum.c
@@ -0,0 +1,99 @@
1/* MN10300 Optimised checksumming wrappers
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/module.h>
13#include <linux/errno.h>
14#include <asm/byteorder.h>
15#include <asm/uaccess.h>
16#include <asm/checksum.h>
17#include "internal.h"
18
19static inline unsigned short from32to16(__wsum sum)
20{
21 asm(" add %1,%0 \n"
22 " addc 0xffff,%0 \n"
23 : "=r" (sum)
24 : "r" (sum << 16), "0" (sum & 0xffff0000)
25 );
26 return sum >> 16;
27}
28
29__sum16 ip_fast_csum(const void *iph, unsigned int ihl)
30{
31 return ~do_csum(iph, ihl * 4);
32}
33EXPORT_SYMBOL(ip_fast_csum);
34
35__wsum csum_partial(const void *buff, int len, __wsum sum)
36{
37 __wsum result;
38
39 result = do_csum(buff, len);
40 result += sum;
41 if (sum > result)
42 result++;
43 return result;
44}
45EXPORT_SYMBOL(csum_partial);
46
47__sum16 ip_compute_csum(const void *buff, int len)
48{
49 return ~from32to16(do_csum(buff, len));
50}
51EXPORT_SYMBOL(ip_compute_csum);
52
53__wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum)
54{
55 copy_from_user(dst, src, len);
56 return csum_partial(dst, len, sum);
57}
58EXPORT_SYMBOL(csum_partial_copy);
59
60__wsum csum_partial_copy_nocheck(const void *src, void *dst,
61 int len, __wsum sum)
62{
63 sum = csum_partial(src, len, sum);
64 memcpy(dst, src, len);
65 return sum;
66}
67EXPORT_SYMBOL(csum_partial_copy_nocheck);
68
69__wsum csum_partial_copy_from_user(const void *src, void *dst,
70 int len, __wsum sum,
71 int *err_ptr)
72{
73 int missing;
74
75 missing = copy_from_user(dst, src, len);
76 if (missing) {
77 memset(dst + len - missing, 0, missing);
78 *err_ptr = -EFAULT;
79 }
80
81 return csum_partial(dst, len, sum);
82}
83EXPORT_SYMBOL(csum_partial_copy_from_user);
84
85__wsum csum_and_copy_to_user(const void *src, void *dst,
86 int len, __wsum sum,
87 int *err_ptr)
88{
89 int missing;
90
91 missing = copy_to_user(dst, src, len);
92 if (missing) {
93 memset(dst + len - missing, 0, missing);
94 *err_ptr = -EFAULT;
95 }
96
97 return csum_partial(src, len, sum);
98}
99EXPORT_SYMBOL(csum_and_copy_to_user);
diff --git a/arch/mn10300/lib/delay.c b/arch/mn10300/lib/delay.c
new file mode 100644
index 000000000000..cce66bc0822d
--- /dev/null
+++ b/arch/mn10300/lib/delay.c
@@ -0,0 +1,50 @@
1/* MN10300 Short delay interpolation routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/sched.h>
13#include <linux/delay.h>
14#include <asm/div64.h>
15
16/*
17 * basic delay loop
18 */
19void __delay(unsigned long loops)
20{
21 int d0;
22
23 asm volatile(
24 " bra 1f \n"
25 " .align 4 \n"
26 "1: bra 2f \n"
27 " .align 4 \n"
28 "2: add -1,%0 \n"
29 " bne 2b \n"
30 : "=&d" (d0)
31 : "0" (loops));
32}
33EXPORT_SYMBOL(__delay);
34
35/*
36 * handle a delay specified in terms of microseconds
37 */
38void __udelay(unsigned long usecs)
39{
40 signed long ioclk, stop;
41
42 /* usecs * CLK / 1E6 */
43 stop = __muldiv64u(usecs, MN10300_TSCCLK, 1000000);
44 stop = TMTSCBC - stop;
45
46 do {
47 ioclk = TMTSCBC;
48 } while (stop < ioclk);
49}
50EXPORT_SYMBOL(__udelay);
diff --git a/arch/mn10300/lib/do_csum.S b/arch/mn10300/lib/do_csum.S
new file mode 100644
index 000000000000..e138994e1667
--- /dev/null
+++ b/arch/mn10300/lib/do_csum.S
@@ -0,0 +1,162 @@
1/* Optimised simple memory checksum
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cache.h>
12
13 .section .text
14 .balign L1_CACHE_BYTES
15
16###############################################################################
17#
18# unsigned int do_csum(const unsigned char *buff, size_t len)
19#
20###############################################################################
21 .globl do_csum
22 .type do_csum,@function
23do_csum:
24 movm [d2,d3],(sp)
25 mov d0,(12,sp)
26 mov d1,(16,sp)
27 mov d1,d2 # count
28 mov d0,a0 # buff
29 clr d1 # accumulator
30
31 cmp +0,d2
32 beq do_csum_done # return if zero-length buffer
33
34 # 4-byte align the buffer pointer
35 btst +3,a0
36 beq do_csum_now_4b_aligned
37
38 btst +1,a0
39 beq do_csum_addr_not_odd
40 movbu (a0),d0
41 inc a0
42 asl +8,d0
43 add d0,d1
44 addc +0,d1
45 add -1,d2
46do_csum_addr_not_odd:
47
48 cmp +2,d2
49 bcs do_csum_fewer_than_4
50 btst +2,a0
51 beq do_csum_now_4b_aligned
52 movhu (a0+),d0
53 add d0,d1
54 addc +0,d1
55 add -2,d2
56 cmp +4,d2
57 bcs do_csum_fewer_than_4
58
59do_csum_now_4b_aligned:
60 # we want to checksum as much as we can in chunks of 32 bytes
61 cmp +31,d2
62 bls do_csum_remainder # 4-byte aligned remainder
63
64 add -32,d2
65 mov +32,d3
66
67do_csum_loop:
68 mov (a0+),d0
69 add d0,d1
70 mov (a0+),e0
71 addc e0,d1
72 mov (a0+),e1
73 addc e1,d1
74 mov (a0+),e3
75 addc e3,d1
76 mov (a0+),d0
77 addc d0,d1
78 mov (a0+),e0
79 addc e0,d1
80 mov (a0+),e1
81 addc e1,d1
82 mov (a0+),e3
83 addc e3,d1
84 addc +0,d1
85
86 sub d3,d2
87 bcc do_csum_loop
88
89 add d3,d2
90 beq do_csum_done
91
92do_csum_remainder:
93 # cut 16-31 bytes down to 0-15
94 cmp +16,d2
95 bcs do_csum_fewer_than_16
96 mov (a0+),d0
97 add d0,d1
98 mov (a0+),e0
99 addc e0,d1
100 mov (a0+),e1
101 addc e1,d1
102 mov (a0+),e3
103 addc e3,d1
104 addc +0,d1
105 add -16,d2
106 beq do_csum_done
107
108do_csum_fewer_than_16:
109 # copy the remaining whole words
110 cmp +4,d2
111 bcs do_csum_fewer_than_4
112 cmp +8,d2
113 bcs do_csum_one_word
114 cmp +12,d2
115 bcs do_csum_two_words
116 mov (a0+),d0
117 add d0,d1
118 addc +0,d1
119do_csum_two_words:
120 mov (a0+),d0
121 add d0,d1
122 addc +0,d1
123do_csum_one_word:
124 mov (a0+),d0
125 add d0,d1
126 addc +0,d1
127
128do_csum_fewer_than_4:
129 and +3,d2
130 beq do_csum_done
131 xor_cmp d0,d0,+2,d2
132 bcs do_csum_fewer_than_2
133 movhu (a0+),d0
134do_csum_fewer_than_2:
135 and +1,d2
136 beq do_csum_add_last_bit
137 movbu (a0),d3
138 add d3,d0
139do_csum_add_last_bit:
140 add d0,d1
141 addc +0,d1
142
143do_csum_done:
144 # compress the checksum down to 16 bits
145 mov +0xffff0000,d2
146 and d1,d2
147 asl +16,d1
148 add d2,d1,d0
149 addc +0xffff,d0
150 lsr +16,d0
151
152 # flip the halves of the word result if the buffer was oddly aligned
153 mov (12,sp),d1
154 and +1,d1
155 beq do_csum_not_oddly_aligned
156 swaph d0,d0 # exchange bits 15:8 with 7:0
157
158do_csum_not_oddly_aligned:
159 ret [d2,d3],8
160
161do_csum_end:
162 .size do_csum, do_csum_end-do_csum
diff --git a/arch/mn10300/lib/internal.h b/arch/mn10300/lib/internal.h
new file mode 100644
index 000000000000..0014eee5f04f
--- /dev/null
+++ b/arch/mn10300/lib/internal.h
@@ -0,0 +1,15 @@
1/* Internal definitions for the arch part of the kernel library
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12/*
13 * do_csum.S
14 */
15extern unsigned int do_csum(const unsigned char *, size_t);
diff --git a/arch/mn10300/lib/lshrdi3.c b/arch/mn10300/lib/lshrdi3.c
new file mode 100644
index 000000000000..e05e64e9ce96
--- /dev/null
+++ b/arch/mn10300/lib/lshrdi3.c
@@ -0,0 +1,60 @@
1/* lshrdi3.c extracted from gcc-2.7.2/libgcc2.c which is: */
2/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public Licence as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public Licence for more details.
15
16You should have received a copy of the GNU General Public Licence
17along with GNU CC; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#define BITS_PER_UNIT 8
22
23typedef int SItype __attribute__((mode(SI)));
24typedef unsigned int USItype __attribute__((mode(SI)));
25typedef int DItype __attribute__((mode(DI)));
26typedef int word_type __attribute__((mode(__word__)));
27
28struct DIstruct {
29 SItype low;
30 SItype high;
31};
32
33union DIunion {
34 struct DIstruct s;
35 DItype ll;
36};
37
38DItype __lshrdi3(DItype u, word_type b)
39{
40 union DIunion w;
41 word_type bm;
42 union DIunion uu;
43
44 if (b == 0)
45 return u;
46
47 uu.ll = u;
48
49 bm = (sizeof(SItype) * BITS_PER_UNIT) - b;
50 if (bm <= 0) {
51 w.s.high = 0;
52 w.s.low = (USItype) uu.s.high >> -bm;
53 } else {
54 USItype carries = (USItype) uu.s.high << bm;
55 w.s.high = (USItype) uu.s.high >> b;
56 w.s.low = ((USItype) uu.s.low >> b) | carries;
57 }
58
59 return w.ll;
60}
diff --git a/arch/mn10300/lib/memcpy.S b/arch/mn10300/lib/memcpy.S
new file mode 100644
index 000000000000..25fb9bb2604f
--- /dev/null
+++ b/arch/mn10300/lib/memcpy.S
@@ -0,0 +1,135 @@
1/* MN10300 Optimised simple memory to memory copy
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cache.h>
12
13 .section .text
14 .balign L1_CACHE_BYTES
15
16###############################################################################
17#
18# void *memcpy(void *dst, const void *src, size_t n)
19#
20###############################################################################
21 .globl memcpy
22 .type memcpy,@function
23memcpy:
24 movm [d2,d3],(sp)
25 mov d0,(12,sp)
26 mov d1,(16,sp)
27 mov (20,sp),d2 # count
28 mov d0,a0 # dst
29 mov d1,a1 # src
30 mov d0,e3 # the return value
31
32 cmp +0,d2
33 beq memcpy_done # return if zero-length copy
34
35 # see if the three parameters are all four-byte aligned
36 or d0,d1,d3
37 or d2,d3
38 and +3,d3
39 bne memcpy_1 # jump if not
40
41 # we want to transfer as much as we can in chunks of 32 bytes
42 cmp +31,d2
43 bls memcpy_4_remainder # 4-byte aligned remainder
44
45 movm [exreg1],(sp)
46 add -32,d2
47 mov +32,d3
48
49memcpy_4_loop:
50 mov (a1+),d0
51 mov (a1+),d1
52 mov (a1+),e0
53 mov (a1+),e1
54 mov (a1+),e4
55 mov (a1+),e5
56 mov (a1+),e6
57 mov (a1+),e7
58 mov d0,(a0+)
59 mov d1,(a0+)
60 mov e0,(a0+)
61 mov e1,(a0+)
62 mov e4,(a0+)
63 mov e5,(a0+)
64 mov e6,(a0+)
65 mov e7,(a0+)
66
67 sub d3,d2
68 bcc memcpy_4_loop
69
70 movm (sp),[exreg1]
71 add d3,d2
72 beq memcpy_4_no_remainder
73
74memcpy_4_remainder:
75 # cut 4-7 words down to 0-3
76 cmp +16,d2
77 bcs memcpy_4_three_or_fewer_words
78 mov (a1+),d0
79 mov (a1+),d1
80 mov (a1+),e0
81 mov (a1+),e1
82 mov d0,(a0+)
83 mov d1,(a0+)
84 mov e0,(a0+)
85 mov e1,(a0+)
86 add -16,d2
87 beq memcpy_4_no_remainder
88
89 # copy the remaining 1, 2 or 3 words
90memcpy_4_three_or_fewer_words:
91 cmp +8,d2
92 bcs memcpy_4_one_word
93 beq memcpy_4_two_words
94 mov (a1+),d0
95 mov d0,(a0+)
96memcpy_4_two_words:
97 mov (a1+),d0
98 mov d0,(a0+)
99memcpy_4_one_word:
100 mov (a1+),d0
101 mov d0,(a0+)
102
103memcpy_4_no_remainder:
104 # check we copied the correct amount
105 # TODO: REMOVE CHECK
106 sub e3,a0,d2
107 mov (20,sp),d1
108 cmp d2,d1
109 beq memcpy_done
110 break
111 break
112 break
113
114memcpy_done:
115 mov e3,a0
116 ret [d2,d3],8
117
118 # handle misaligned copying
119memcpy_1:
120 add -1,d2
121 mov +1,d3
122 setlb # setlb requires the next insns
123 # to occupy exactly 4 bytes
124
125 sub d3,d2
126 movbu (a1),d0
127 movbu d0,(a0)
128 add_add d3,a1,d3,a0
129 lcc
130
131 mov e3,a0
132 ret [d2,d3],8
133
134memcpy_end:
135 .size memcpy, memcpy_end-memcpy
diff --git a/arch/mn10300/lib/memmove.S b/arch/mn10300/lib/memmove.S
new file mode 100644
index 000000000000..20b07b62b77c
--- /dev/null
+++ b/arch/mn10300/lib/memmove.S
@@ -0,0 +1,160 @@
1/* MN10300 Optimised simple memory to memory copy, with support for overlapping
2 * regions
3 *
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <asm/cache.h>
13
14 .section .text
15 .balign L1_CACHE_BYTES
16
17###############################################################################
18#
19# void *memmove(void *dst, const void *src, size_t n)
20#
21###############################################################################
22 .globl memmove
23 .type memmove,@function
24memmove:
25 # fall back to memcpy if dst < src to work bottom up
26 cmp d1,d0
27 bcs memmove_memcpy
28
29 # work top down
30 movm [d2,d3],(sp)
31 mov d0,(12,sp)
32 mov d1,(16,sp)
33 mov (20,sp),d2 # count
34 add d0,d2,a0 # dst end
35 add d1,d2,a1 # src end
36 mov d0,e3 # the return value
37
38 cmp +0,d2
39 beq memmove_done # return if zero-length copy
40
41 # see if the three parameters are all four-byte aligned
42 or d0,d1,d3
43 or d2,d3
44 and +3,d3
45 bne memmove_1 # jump if not
46
47 # we want to transfer as much as we can in chunks of 32 bytes
48 add -4,a1
49 cmp +31,d2
50 bls memmove_4_remainder # 4-byte aligned remainder
51
52 add -32,d2
53 mov +32,d3
54
55memmove_4_loop:
56 mov (a1),d0
57 sub_sub +4,a1,+4,a0
58 mov d0,(a0)
59 mov (a1),d1
60 sub_sub +4,a1,+4,a0
61 mov d1,(a0)
62
63 mov (a1),d0
64 sub_sub +4,a1,+4,a0
65 mov d0,(a0)
66 mov (a1),d1
67 sub_sub +4,a1,+4,a0
68 mov d1,(a0)
69
70 mov (a1),d0
71 sub_sub +4,a1,+4,a0
72 mov d0,(a0)
73 mov (a1),d1
74 sub_sub +4,a1,+4,a0
75 mov d1,(a0)
76
77 mov (a1),d0
78 sub_sub +4,a1,+4,a0
79 mov d0,(a0)
80 mov (a1),d1
81 sub_sub +4,a1,+4,a0
82 mov d1,(a0)
83
84 sub d3,d2
85 bcc memmove_4_loop
86
87 add d3,d2
88 beq memmove_4_no_remainder
89
90memmove_4_remainder:
91 # cut 4-7 words down to 0-3
92 cmp +16,d2
93 bcs memmove_4_three_or_fewer_words
94 mov (a1),d0
95 sub_sub +4,a1,+4,a0
96 mov d0,(a0)
97 mov (a1),d1
98 sub_sub +4,a1,+4,a0
99 mov d1,(a0)
100 mov (a1),e0
101 sub_sub +4,a1,+4,a0
102 mov e0,(a0)
103 mov (a1),e1
104 sub_sub +4,a1,+4,a0
105 mov e1,(a0)
106 add -16,d2
107 beq memmove_4_no_remainder
108
109 # copy the remaining 1, 2 or 3 words
110memmove_4_three_or_fewer_words:
111 cmp +8,d2
112 bcs memmove_4_one_word
113 beq memmove_4_two_words
114 mov (a1),d0
115 sub_sub +4,a1,+4,a0
116 mov d0,(a0)
117memmove_4_two_words:
118 mov (a1),d0
119 sub_sub +4,a1,+4,a0
120 mov d0,(a0)
121memmove_4_one_word:
122 mov (a1),d0
123 sub_sub +4,a1,+4,a0
124 mov d0,(a0)
125
126memmove_4_no_remainder:
127 # check we copied the correct amount
128 # TODO: REMOVE CHECK
129 sub e3,a0,d2
130 beq memmove_done
131 break
132 break
133 break
134
135memmove_done:
136 mov e3,a0
137 ret [d2,d3],8
138
139 # handle misaligned copying
140memmove_1:
141 add -1,a1
142 add -1,d2
143 mov +1,d3
144 setlb # setlb requires the next insns
145 # to occupy exactly 4 bytes
146
147 sub d3,d2
148 movbu (a1),d0
149 sub_sub d3,a1,d3,a0
150 movbu d0,(a0)
151 lcc
152
153 mov e3,a0
154 ret [d2,d3],8
155
156memmove_memcpy:
157 jmp memcpy
158
159memmove_end:
160 .size memmove, memmove_end-memmove
diff --git a/arch/mn10300/lib/memset.S b/arch/mn10300/lib/memset.S
new file mode 100644
index 000000000000..bc02e39629b7
--- /dev/null
+++ b/arch/mn10300/lib/memset.S
@@ -0,0 +1,121 @@
1/* Optimised simple memory fill
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <asm/cache.h>
12
13 .section .text
14 .balign L1_CACHE_BYTES
15
16###############################################################################
17#
18# void *memset(void *dst, int c, size_t n)
19#
20###############################################################################
21 .globl memset
22 .type memset,@function
23memset:
24 movm [d2,d3],(sp)
25 mov d0,(12,sp)
26 mov d1,(16,sp)
27 mov (20,sp),d2 # count
28 mov d0,a0 # dst
29 mov d0,e3 # the return value
30
31 cmp +0,d2
32 beq memset_done # return if zero-length fill
33
34 # see if the region parameters are four-byte aligned
35 or d0,d2,d3
36 and +3,d3
37 bne memset_1 # jump if not
38
39 extbu d1
40 mov_asl d1,d3,8,d1
41 or_asl d1,d3,8,d1
42 or_asl d1,d3,8,d1
43 or d3,d1
44
45 # we want to transfer as much as we can in chunks of 32 bytes
46 cmp +31,d2
47 bls memset_4_remainder # 4-byte aligned remainder
48
49 add -32,d2
50 mov +32,d3
51
52memset_4_loop:
53 mov d1,(a0+)
54 mov d1,(a0+)
55 mov d1,(a0+)
56 mov d1,(a0+)
57 mov d1,(a0+)
58 mov d1,(a0+)
59 mov d1,(a0+)
60 mov d1,(a0+)
61
62 sub d3,d2
63 bcc memset_4_loop
64
65 add d3,d2
66 beq memset_4_no_remainder
67
68memset_4_remainder:
69 # cut 4-7 words down to 0-3
70 cmp +16,d2
71 bcs memset_4_three_or_fewer_words
72 mov d1,(a0+)
73 mov d1,(a0+)
74 mov d1,(a0+)
75 mov d1,(a0+)
76 add -16,d2
77 beq memset_4_no_remainder
78
79 # copy the remaining 1, 2 or 3 words
80memset_4_three_or_fewer_words:
81 cmp +8,d2
82 bcs memset_4_one_word
83 beq memset_4_two_words
84 mov d1,(a0+)
85memset_4_two_words:
86 mov d1,(a0+)
87memset_4_one_word:
88 mov d1,(a0+)
89
90memset_4_no_remainder:
91 # check we set the correct amount
92 # TODO: REMOVE CHECK
93 sub e3,a0,d2
94 mov (20,sp),d1
95 cmp d2,d1
96 beq memset_done
97 break
98 break
99 break
100
101memset_done:
102 mov e3,a0
103 ret [d2,d3],8
104
105 # handle misaligned copying
106memset_1:
107 add -1,d2
108 mov +1,d3
109 setlb # setlb requires the next insns
110 # to occupy exactly 4 bytes
111
112 sub d3,d2
113 movbu d1,(a0)
114 inc a0
115 lcc
116
117 mov e3,a0
118 ret [d2,d3],8
119
120memset_end:
121 .size memset, memset_end-memset
diff --git a/arch/mn10300/lib/negdi2.c b/arch/mn10300/lib/negdi2.c
new file mode 100644
index 000000000000..eae4ecdd5f69
--- /dev/null
+++ b/arch/mn10300/lib/negdi2.c
@@ -0,0 +1,57 @@
1/* More subroutines needed by GCC output code on some machines. */
2/* Compile this one with gcc. */
3/* Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
4 2000, 2001 Free Software Foundation, Inc.
5
6This file is part of GNU CC.
7
8GNU CC is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public Licence as published by
10the Free Software Foundation; either version 2, or (at your option)
11any later version.
12
13In addition to the permissions in the GNU General Public Licence, the
14Free Software Foundation gives you unlimited permission to link the
15compiled version of this file into combinations with other programs,
16and to distribute those combinations without any restriction coming
17from the use of this file. (The General Public Licence restrictions
18do apply in other respects; for example, they cover modification of
19the file, and distribution when not linked into a combine
20executable.)
21
22GNU CC is distributed in the hope that it will be useful,
23but WITHOUT ANY WARRANTY; without even the implied warranty of
24MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25GNU General Public Licence for more details.
26
27You should have received a copy of the GNU General Public Licence
28along with GNU CC; see the file COPYING. If not, write to
29the Free Software Foundation, 59 Temple Place - Suite 330,
30Boston, MA 02111-1307, USA. */
31
32/* It is incorrect to include config.h here, because this file is being
33 compiled for the target, and hence definitions concerning only the host
34 do not apply. */
35
36#include <linux/types.h>
37
38union DWunion {
39 s64 ll;
40 struct {
41 s32 low;
42 s32 high;
43 } s;
44};
45
46s64 __negdi2(s64 u)
47{
48 union DWunion w;
49 union DWunion uu;
50
51 uu.ll = u;
52
53 w.s.low = -uu.s.low;
54 w.s.high = -uu.s.high - ((u32) w.s.low > 0);
55
56 return w.ll;
57}
diff --git a/arch/mn10300/lib/usercopy.c b/arch/mn10300/lib/usercopy.c
new file mode 100644
index 000000000000..a75b203059c1
--- /dev/null
+++ b/arch/mn10300/lib/usercopy.c
@@ -0,0 +1,166 @@
1/* MN10300 Userspace accessor functions
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <asm/uaccess.h>
13
14unsigned long
15__generic_copy_to_user(void *to, const void *from, unsigned long n)
16{
17 if (access_ok(VERIFY_WRITE, to, n))
18 __copy_user(to, from, n);
19 return n;
20}
21
22unsigned long
23__generic_copy_from_user(void *to, const void *from, unsigned long n)
24{
25 if (access_ok(VERIFY_READ, from, n))
26 __copy_user_zeroing(to, from, n);
27 return n;
28}
29
30/*
31 * Copy a null terminated string from userspace.
32 */
33#define __do_strncpy_from_user(dst, src, count, res) \
34do { \
35 int w; \
36 asm volatile( \
37 " mov %1,%0\n" \
38 " cmp 0,%1\n" \
39 " beq 2f\n" \
40 "0:\n" \
41 " movbu (%5),%2\n" \
42 "1:\n" \
43 " movbu %2,(%6)\n" \
44 " inc %5\n" \
45 " inc %6\n" \
46 " cmp 0,%2\n" \
47 " beq 2f\n" \
48 " add -1,%1\n" \
49 " bne 0b\n" \
50 "2:\n" \
51 " sub %1,%0\n" \
52 "3:\n" \
53 " .section .fixup,\"ax\"\n" \
54 "4:\n" \
55 " mov %3,%0\n" \
56 " jmp 3b\n" \
57 " .previous\n" \
58 " .section __ex_table,\"a\"\n" \
59 " .balign 4\n" \
60 " .long 0b,4b\n" \
61 " .long 1b,4b\n" \
62 " .previous" \
63 :"=&r"(res), "=r"(count), "=&r"(w) \
64 :"i"(-EFAULT), "1"(count), "a"(src), "a"(dst) \
65 :"memory"); \
66} while (0)
67
68long
69__strncpy_from_user(char *dst, const char *src, long count)
70{
71 long res;
72 __do_strncpy_from_user(dst, src, count, res);
73 return res;
74}
75
76long
77strncpy_from_user(char *dst, const char *src, long count)
78{
79 long res = -EFAULT;
80 if (access_ok(VERIFY_READ, src, 1))
81 __do_strncpy_from_user(dst, src, count, res);
82 return res;
83}
84
85
86/*
87 * Clear a userspace memory
88 */
89#define __do_clear_user(addr, size) \
90do { \
91 int w; \
92 asm volatile( \
93 " cmp 0,%0\n" \
94 " beq 1f\n" \
95 " clr %1\n" \
96 "0: movbu %1,(%3,%2)\n" \
97 " inc %3\n" \
98 " cmp %0,%3\n" \
99 " bne 0b\n" \
100 "1:\n" \
101 " sub %3,%0\n" \
102 "2:\n" \
103 ".section .fixup,\"ax\"\n" \
104 "3: jmp 2b\n" \
105 ".previous\n" \
106 ".section __ex_table,\"a\"\n" \
107 " .balign 4\n" \
108 " .long 0b,3b\n" \
109 ".previous\n" \
110 : "+r"(size), "=&r"(w) \
111 : "a"(addr), "d"(0) \
112 : "memory"); \
113} while (0)
114
115unsigned long
116__clear_user(void *to, unsigned long n)
117{
118 __do_clear_user(to, n);
119 return n;
120}
121
122unsigned long
123clear_user(void *to, unsigned long n)
124{
125 if (access_ok(VERIFY_WRITE, to, n))
126 __do_clear_user(to, n);
127 return n;
128}
129
130/*
131 * Return the size of a string (including the ending 0)
132 *
133 * Return 0 on exception, a value greater than N if too long
134 */
135long strnlen_user(const char *s, long n)
136{
137 unsigned long res, w;
138
139 if (!__addr_ok(s))
140 return 0;
141
142 if (n < 0 || n + (u_long) s > current_thread_info()->addr_limit.seg)
143 n = current_thread_info()->addr_limit.seg - (u_long)s;
144
145 asm volatile(
146 "0: cmp %4,%0\n"
147 " beq 2f\n"
148 "1: movbu (%0,%3),%1\n"
149 " inc %0\n"
150 " cmp 0,%1\n"
151 " beq 3f\n"
152 " bra 0b\n"
153 "2: clr %0\n"
154 "3:\n"
155 ".section .fixup,\"ax\"\n"
156 "4: jmp 2b\n"
157 ".previous\n"
158 ".section __ex_table,\"a\"\n"
159 " .balign 4\n"
160 " .long 1b,4b\n"
161 ".previous\n"
162 :"=d"(res), "=&r"(w)
163 :"0"(0), "a"(s), "r"(n)
164 :"memory");
165 return res;
166}
diff --git a/arch/mn10300/mm/Makefile b/arch/mn10300/mm/Makefile
new file mode 100644
index 000000000000..28b9d983db0c
--- /dev/null
+++ b/arch/mn10300/mm/Makefile
@@ -0,0 +1,14 @@
1#
2# Makefile for the MN10300-specific memory management code
3#
4
5obj-y := \
6 init.o fault.o pgtable.o extable.o tlb-mn10300.o mmu-context.o \
7 misalignment.o dma-alloc.o
8
9ifneq ($(CONFIG_MN10300_CACHE_DISABLED),y)
10obj-y += cache.o cache-mn10300.o
11ifeq ($(CONFIG_MN10300_CACHE_WBACK),y)
12obj-y += cache-flush-mn10300.o
13endif
14endif
diff --git a/arch/mn10300/mm/cache-flush-mn10300.S b/arch/mn10300/mm/cache-flush-mn10300.S
new file mode 100644
index 000000000000..c8ed1cbac107
--- /dev/null
+++ b/arch/mn10300/mm/cache-flush-mn10300.S
@@ -0,0 +1,192 @@
1/* MN10300 CPU core caching routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/sys.h>
13#include <linux/linkage.h>
14#include <asm/smp.h>
15#include <asm/page.h>
16#include <asm/cache.h>
17
18 .am33_2
19 .globl mn10300_dcache_flush
20 .globl mn10300_dcache_flush_page
21 .globl mn10300_dcache_flush_range
22 .globl mn10300_dcache_flush_range2
23 .globl mn10300_dcache_flush_inv
24 .globl mn10300_dcache_flush_inv_page
25 .globl mn10300_dcache_flush_inv_range
26 .globl mn10300_dcache_flush_inv_range2
27
28###############################################################################
29#
30# void mn10300_dcache_flush(void)
31# Flush the entire data cache back to RAM
32#
33###############################################################################
34 ALIGN
35mn10300_dcache_flush:
36 movhu (CHCTR),d0
37 btst CHCTR_DCEN,d0
38 beq mn10300_dcache_flush_end
39
40 # read the addresses tagged in the cache's tag RAM and attempt to flush
41 # those addresses specifically
42 # - we rely on the hardware to filter out invalid tag entry addresses
43 mov DCACHE_TAG(0,0),a0 # dcache tag RAM access address
44 mov DCACHE_PURGE(0,0),a1 # dcache purge request address
45 mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
46
47mn10300_dcache_flush_loop:
48 mov (a0),d0
49 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
50 or L1_CACHE_TAG_VALID,d0 # retain valid entries in the
51 # cache
52 mov d0,(a1) # conditional purge
53
54mn10300_dcache_flush_skip:
55 add L1_CACHE_BYTES,a0
56 add L1_CACHE_BYTES,a1
57 add -1,d1
58 bne mn10300_dcache_flush_loop
59
60mn10300_dcache_flush_end:
61 ret [],0
62
63###############################################################################
64#
65# void mn10300_dcache_flush_page(unsigned start)
66# void mn10300_dcache_flush_range(unsigned start, unsigned end)
67# void mn10300_dcache_flush_range2(unsigned start, unsigned size)
68# Flush a range of addresses on a page in the dcache
69#
70###############################################################################
71 ALIGN
72mn10300_dcache_flush_page:
73 mov PAGE_SIZE,d1
74mn10300_dcache_flush_range2:
75 add d0,d1
76mn10300_dcache_flush_range:
77 movm [d2,d3],(sp)
78
79 movhu (CHCTR),d2
80 btst CHCTR_DCEN,d2
81 beq mn10300_dcache_flush_range_end
82
83 # round start addr down
84 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0
85 mov d0,a1
86
87 add L1_CACHE_BYTES,d1 # round end addr up
88 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
89
90 # write a request to flush all instances of an address from the cache
91 mov DCACHE_PURGE(0,0),a0
92 mov a1,d0
93 and L1_CACHE_TAG_ENTRY,d0
94 add d0,a0 # starting dcache purge control
95 # reg address
96
97 sub a1,d1
98 lsr L1_CACHE_SHIFT,d1 # total number of entries to
99 # examine
100
101 or L1_CACHE_TAG_VALID,a1 # retain valid entries in the
102 # cache
103
104mn10300_dcache_flush_range_loop:
105 mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
106 # all ways
107
108 add L1_CACHE_BYTES,a0
109 add L1_CACHE_BYTES,a1
110 and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
111 add -1,d1
112 bne mn10300_dcache_flush_range_loop
113
114mn10300_dcache_flush_range_end:
115 ret [d2,d3],8
116
117###############################################################################
118#
119# void mn10300_dcache_flush_inv(void)
120# Flush the entire data cache and invalidate all entries
121#
122###############################################################################
123 ALIGN
124mn10300_dcache_flush_inv:
125 movhu (CHCTR),d0
126 btst CHCTR_DCEN,d0
127 beq mn10300_dcache_flush_inv_end
128
129 # hit each line in the dcache with an unconditional purge
130 mov DCACHE_PURGE(0,0),a1 # dcache purge request address
131 mov L1_CACHE_NWAYS*L1_CACHE_NENTRIES,d1 # total number of entries
132
133mn10300_dcache_flush_inv_loop:
134 mov (a1),d0 # unconditional purge
135
136 add L1_CACHE_BYTES,a1
137 add -1,d1
138 bne mn10300_dcache_flush_inv_loop
139
140mn10300_dcache_flush_inv_end:
141 ret [],0
142
143###############################################################################
144#
145# void mn10300_dcache_flush_inv_page(unsigned start)
146# void mn10300_dcache_flush_inv_range(unsigned start, unsigned end)
147# void mn10300_dcache_flush_inv_range2(unsigned start, unsigned size)
148# Flush and invalidate a range of addresses on a page in the dcache
149#
150###############################################################################
151 ALIGN
152mn10300_dcache_flush_inv_page:
153 mov PAGE_SIZE,d1
154mn10300_dcache_flush_inv_range2:
155 add d0,d1
156mn10300_dcache_flush_inv_range:
157 movm [d2,d3],(sp)
158 movhu (CHCTR),d2
159 btst CHCTR_DCEN,d2
160 beq mn10300_dcache_flush_inv_range_end
161
162 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
163 # addr down
164 mov d0,a1
165
166 add L1_CACHE_BYTES,d1 # round end addr up
167 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
168
169 # write a request to flush and invalidate all instances of an address
170 # from the cache
171 mov DCACHE_PURGE(0,0),a0
172 mov a1,d0
173 and L1_CACHE_TAG_ENTRY,d0
174 add d0,a0 # starting dcache purge control
175 # reg address
176
177 sub a1,d1
178 lsr L1_CACHE_SHIFT,d1 # total number of entries to
179 # examine
180
181mn10300_dcache_flush_inv_range_loop:
182 mov a1,(L1_CACHE_WAYDISP*0,a0) # conditionally purge this line
183 # in all ways
184
185 add L1_CACHE_BYTES,a0
186 add L1_CACHE_BYTES,a1
187 and ~L1_CACHE_WAYDISP,a0 # make sure way stay on way 0
188 add -1,d1
189 bne mn10300_dcache_flush_inv_range_loop
190
191mn10300_dcache_flush_inv_range_end:
192 ret [d2,d3],8
diff --git a/arch/mn10300/mm/cache-mn10300.S b/arch/mn10300/mm/cache-mn10300.S
new file mode 100644
index 000000000000..e839d0aedd69
--- /dev/null
+++ b/arch/mn10300/mm/cache-mn10300.S
@@ -0,0 +1,289 @@
1/* MN10300 CPU core caching routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sys.h>
12#include <linux/linkage.h>
13#include <asm/smp.h>
14#include <asm/page.h>
15#include <asm/cache.h>
16
17#define mn10300_dcache_inv_range_intr_interval \
18 +((1 << MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL) - 1)
19
20#if mn10300_dcache_inv_range_intr_interval > 0xff
21#error MN10300_DCACHE_INV_RANGE_INTR_LOG2_INTERVAL must be 8 or less
22#endif
23
24 .am33_2
25
26 .globl mn10300_icache_inv
27 .globl mn10300_dcache_inv
28 .globl mn10300_dcache_inv_range
29 .globl mn10300_dcache_inv_range2
30 .globl mn10300_dcache_inv_page
31
32###############################################################################
33#
34# void mn10300_icache_inv(void)
35# Invalidate the entire icache
36#
37###############################################################################
38 ALIGN
39mn10300_icache_inv:
40 mov CHCTR,a0
41
42 movhu (a0),d0
43 btst CHCTR_ICEN,d0
44 beq mn10300_icache_inv_end
45
46 mov epsw,d1
47 and ~EPSW_IE,epsw
48 nop
49 nop
50
51 # disable the icache
52 and ~CHCTR_ICEN,d0
53 movhu d0,(a0)
54
55 # and wait for it to calm down
56 setlb
57 movhu (a0),d0
58 btst CHCTR_ICBUSY,d0
59 lne
60
61 # invalidate
62 or CHCTR_ICINV,d0
63 movhu d0,(a0)
64
65 # wait for the cache to finish
66 mov CHCTR,a0
67 setlb
68 movhu (a0),d0
69 btst CHCTR_ICBUSY,d0
70 lne
71
72 # and reenable it
73 and ~CHCTR_ICINV,d0
74 or CHCTR_ICEN,d0
75 movhu d0,(a0)
76 movhu (a0),d0
77
78 mov d1,epsw
79
80mn10300_icache_inv_end:
81 ret [],0
82
83###############################################################################
84#
85# void mn10300_dcache_inv(void)
86# Invalidate the entire dcache
87#
88###############################################################################
89 ALIGN
90mn10300_dcache_inv:
91 mov CHCTR,a0
92
93 movhu (a0),d0
94 btst CHCTR_DCEN,d0
95 beq mn10300_dcache_inv_end
96
97 mov epsw,d1
98 and ~EPSW_IE,epsw
99 nop
100 nop
101
102 # disable the dcache
103 and ~CHCTR_DCEN,d0
104 movhu d0,(a0)
105
106 # and wait for it to calm down
107 setlb
108 movhu (a0),d0
109 btst CHCTR_DCBUSY,d0
110 lne
111
112 # invalidate
113 or CHCTR_DCINV,d0
114 movhu d0,(a0)
115
116 # wait for the cache to finish
117 mov CHCTR,a0
118 setlb
119 movhu (a0),d0
120 btst CHCTR_DCBUSY,d0
121 lne
122
123 # and reenable it
124 and ~CHCTR_DCINV,d0
125 or CHCTR_DCEN,d0
126 movhu d0,(a0)
127 movhu (a0),d0
128
129 mov d1,epsw
130
131mn10300_dcache_inv_end:
132 ret [],0
133
134###############################################################################
135#
136# void mn10300_dcache_inv_range(unsigned start, unsigned end)
137# void mn10300_dcache_inv_range2(unsigned start, unsigned size)
138# void mn10300_dcache_inv_page(unsigned start)
139# Invalidate a range of addresses on a page in the dcache
140#
141###############################################################################
142 ALIGN
143mn10300_dcache_inv_page:
144 mov PAGE_SIZE,d1
145mn10300_dcache_inv_range2:
146 add d0,d1
147mn10300_dcache_inv_range:
148 movm [d2,d3,a2],(sp)
149 mov CHCTR,a2
150
151 movhu (a2),d2
152 btst CHCTR_DCEN,d2
153 beq mn10300_dcache_inv_range_end
154
155 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d0 # round start
156 # addr down
157 mov d0,a1
158
159 add L1_CACHE_BYTES,d1 # round end addr up
160 and L1_CACHE_TAG_ADDRESS|L1_CACHE_TAG_ENTRY,d1
161
162 clr d2 # we're going to clear tag ram
163 # entries
164
165 # read the tags from the tag RAM, and if they indicate a valid dirty
166 # cache line then invalidate that line
167 mov DCACHE_TAG(0,0),a0
168 mov a1,d0
169 and L1_CACHE_TAG_ENTRY,d0
170 add d0,a0 # starting dcache tag RAM
171 # access address
172
173 sub a1,d1
174 lsr L1_CACHE_SHIFT,d1 # total number of entries to
175 # examine
176
177 and ~(L1_CACHE_DISPARITY-1),a1 # determine comparator base
178
179mn10300_dcache_inv_range_outer_loop:
180 # disable interrupts
181 mov epsw,d3
182 and ~EPSW_IE,epsw
183 nop # note that reading CHCTR and
184 # AND'ing D0 occupy two delay
185 # slots after disabling
186 # interrupts
187
188 # disable the dcache
189 movhu (a2),d0
190 and ~CHCTR_DCEN,d0
191 movhu d0,(a2)
192
193 # and wait for it to calm down
194 setlb
195 movhu (a2),d0
196 btst CHCTR_DCBUSY,d0
197 lne
198
199mn10300_dcache_inv_range_loop:
200
201 # process the way 0 slot
202 mov (L1_CACHE_WAYDISP*0,a0),d0 # read the tag in the way 0 slot
203 btst L1_CACHE_TAG_VALID,d0
204 beq mn10300_dcache_inv_range_skip_0 # jump if this cacheline is not
205 # valid
206
207 xor a1,d0
208 lsr 12,d0
209 bne mn10300_dcache_inv_range_skip_0 # jump if not this cacheline
210
211 mov d2,(a0) # kill the tag
212
213mn10300_dcache_inv_range_skip_0:
214
215 # process the way 1 slot
216 mov (L1_CACHE_WAYDISP*1,a0),d0 # read the tag in the way 1 slot
217 btst L1_CACHE_TAG_VALID,d0
218 beq mn10300_dcache_inv_range_skip_1 # jump if this cacheline is not
219 # valid
220
221 xor a1,d0
222 lsr 12,d0
223 bne mn10300_dcache_inv_range_skip_1 # jump if not this cacheline
224
225 mov d2,(a0) # kill the tag
226
227mn10300_dcache_inv_range_skip_1:
228
229 # process the way 2 slot
230 mov (L1_CACHE_WAYDISP*2,a0),d0 # read the tag in the way 2 slot
231 btst L1_CACHE_TAG_VALID,d0
232 beq mn10300_dcache_inv_range_skip_2 # jump if this cacheline is not
233 # valid
234
235 xor a1,d0
236 lsr 12,d0
237 bne mn10300_dcache_inv_range_skip_2 # jump if not this cacheline
238
239 mov d2,(a0) # kill the tag
240
241mn10300_dcache_inv_range_skip_2:
242
243 # process the way 3 slot
244 mov (L1_CACHE_WAYDISP*3,a0),d0 # read the tag in the way 3 slot
245 btst L1_CACHE_TAG_VALID,d0
246 beq mn10300_dcache_inv_range_skip_3 # jump if this cacheline is not
247 # valid
248
249 xor a1,d0
250 lsr 12,d0
251 bne mn10300_dcache_inv_range_skip_3 # jump if not this cacheline
252
253 mov d2,(a0) # kill the tag
254
255mn10300_dcache_inv_range_skip_3:
256
257 # approx every N steps we re-enable the cache and see if there are any
258 # interrupts to be processed
259 # we also break out if we've reached the end of the loop
260 # (the bottom nibble of the count is zero in both cases)
261 add L1_CACHE_BYTES,a0
262 add L1_CACHE_BYTES,a1
263 add -1,d1
264 btst mn10300_dcache_inv_range_intr_interval,d1
265 bne mn10300_dcache_inv_range_loop
266
267 # wait for the cache to finish what it's doing
268 setlb
269 movhu (a2),d0
270 btst CHCTR_DCBUSY,d0
271 lne
272
273 # and reenable it
274 or CHCTR_DCEN,d0
275 movhu d0,(a2)
276 movhu (a2),d0
277
278 # re-enable interrupts
279 # - we don't bother with delay NOPs as we'll have enough instructions
280 # before we disable interrupts again to give the interrupts a chance
281 # to happen
282 mov d3,epsw
283
284 # go around again if the counter hasn't yet reached zero
285 add 0,d1
286 bne mn10300_dcache_inv_range_outer_loop
287
288mn10300_dcache_inv_range_end:
289 ret [d2,d3,a2],12
diff --git a/arch/mn10300/mm/cache.c b/arch/mn10300/mm/cache.c
new file mode 100644
index 000000000000..1b76719ec1c3
--- /dev/null
+++ b/arch/mn10300/mm/cache.c
@@ -0,0 +1,121 @@
1/* MN10300 Cache flushing routines
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/mm.h>
13#include <linux/mman.h>
14#include <linux/threads.h>
15#include <asm/page.h>
16#include <asm/pgtable.h>
17#include <asm/processor.h>
18#include <asm/cacheflush.h>
19#include <asm/io.h>
20#include <asm/uaccess.h>
21
22EXPORT_SYMBOL(mn10300_icache_inv);
23EXPORT_SYMBOL(mn10300_dcache_inv);
24EXPORT_SYMBOL(mn10300_dcache_inv_range);
25EXPORT_SYMBOL(mn10300_dcache_inv_range2);
26EXPORT_SYMBOL(mn10300_dcache_inv_page);
27
28#ifdef CONFIG_MN10300_CACHE_WBACK
29EXPORT_SYMBOL(mn10300_dcache_flush);
30EXPORT_SYMBOL(mn10300_dcache_flush_inv);
31EXPORT_SYMBOL(mn10300_dcache_flush_inv_range);
32EXPORT_SYMBOL(mn10300_dcache_flush_inv_range2);
33EXPORT_SYMBOL(mn10300_dcache_flush_inv_page);
34EXPORT_SYMBOL(mn10300_dcache_flush_range);
35EXPORT_SYMBOL(mn10300_dcache_flush_range2);
36EXPORT_SYMBOL(mn10300_dcache_flush_page);
37#endif
38
39/*
40 * write a page back from the dcache and invalidate the icache so that we can
41 * run code from it that we've just written into it
42 */
43void flush_icache_page(struct vm_area_struct *vma, struct page *page)
44{
45 mn10300_dcache_flush_page(page_to_phys(page));
46 mn10300_icache_inv();
47}
48EXPORT_SYMBOL(flush_icache_page);
49
50/*
51 * write some code we've just written back from the dcache and invalidate the
52 * icache so that we can run that code
53 */
54void flush_icache_range(unsigned long start, unsigned long end)
55{
56#ifdef CONFIG_MN10300_CACHE_WBACK
57 unsigned long addr, size, off;
58 struct page *page;
59 pgd_t *pgd;
60 pud_t *pud;
61 pmd_t *pmd;
62 pte_t *ppte, pte;
63
64 for (; start < end; start += size) {
65 /* work out how much of the page to flush */
66 off = start & (PAGE_SIZE - 1);
67
68 size = end - start;
69 if (size > PAGE_SIZE - off)
70 size = PAGE_SIZE - off;
71
72 /* get the physical address the page is mapped to from the page
73 * tables */
74 pgd = pgd_offset(current->mm, start);
75 if (!pgd || !pgd_val(*pgd))
76 continue;
77
78 pud = pud_offset(pgd, start);
79 if (!pud || !pud_val(*pud))
80 continue;
81
82 pmd = pmd_offset(pud, start);
83 if (!pmd || !pmd_val(*pmd))
84 continue;
85
86 ppte = pte_offset_map(pmd, start);
87 if (!ppte)
88 continue;
89 pte = *ppte;
90 pte_unmap(ppte);
91
92 if (pte_none(pte))
93 continue;
94
95 page = pte_page(pte);
96 if (!page)
97 continue;
98
99 addr = page_to_phys(page);
100
101 /* flush the dcache and invalidate the icache coverage on that
102 * region */
103 mn10300_dcache_flush_range2(addr + off, size);
104 }
105#endif
106
107 mn10300_icache_inv();
108}
109EXPORT_SYMBOL(flush_icache_range);
110
111/*
112 * allow userspace to flush the instruction cache
113 */
114asmlinkage long sys_cacheflush(unsigned long start, unsigned long end)
115{
116 if (end < start)
117 return -EINVAL;
118
119 flush_icache_range(start, end);
120 return 0;
121}
diff --git a/arch/mn10300/mm/dma-alloc.c b/arch/mn10300/mm/dma-alloc.c
new file mode 100644
index 000000000000..f3649d8f50e3
--- /dev/null
+++ b/arch/mn10300/mm/dma-alloc.c
@@ -0,0 +1,56 @@
1/* MN10300 Dynamic DMA mapping support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * Derived from: arch/i386/kernel/pci-dma.c
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#include <linux/types.h>
14#include <linux/mm.h>
15#include <linux/string.h>
16#include <linux/pci.h>
17#include <asm/io.h>
18
19void *dma_alloc_coherent(struct device *dev, size_t size,
20 dma_addr_t *dma_handle, int gfp)
21{
22 unsigned long addr;
23 void *ret;
24
25 /* ignore region specifiers */
26 gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
27
28 if (dev == NULL || dev->coherent_dma_mask < 0xffffffff)
29 gfp |= GFP_DMA;
30
31 addr = __get_free_pages(gfp, get_order(size));
32 if (!addr)
33 return NULL;
34
35 /* map the coherent memory through the uncached memory window */
36 ret = (void *) (addr | 0x20000000);
37
38 /* fill the memory with obvious rubbish */
39 memset((void *) addr, 0xfb, size);
40
41 /* write back and evict all cache lines covering this region */
42 mn10300_dcache_flush_inv_range2(virt_to_phys((void *) addr), PAGE_SIZE);
43
44 *dma_handle = virt_to_bus((void *) addr);
45 return ret;
46}
47EXPORT_SYMBOL(dma_alloc_coherent);
48
49void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
50 dma_addr_t dma_handle)
51{
52 unsigned long addr = (unsigned long) vaddr & ~0x20000000;
53
54 free_pages(addr, get_order(size));
55}
56EXPORT_SYMBOL(dma_free_coherent);
diff --git a/arch/mn10300/mm/extable.c b/arch/mn10300/mm/extable.c
new file mode 100644
index 000000000000..25e5485ab87d
--- /dev/null
+++ b/arch/mn10300/mm/extable.c
@@ -0,0 +1,26 @@
1/* MN10300 In-kernel exception handling
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/spinlock.h>
13#include <asm/uaccess.h>
14
15int fixup_exception(struct pt_regs *regs)
16{
17 const struct exception_table_entry *fixup;
18
19 fixup = search_exception_tables(regs->pc);
20 if (fixup) {
21 regs->pc = fixup->fixup;
22 return 1;
23 }
24
25 return 0;
26}
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
new file mode 100644
index 000000000000..78f092ca0316
--- /dev/null
+++ b/arch/mn10300/mm/fault.c
@@ -0,0 +1,405 @@
1/* MN10300 MMU Fault handler
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12
13#include <linux/signal.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/types.h>
19#include <linux/ptrace.h>
20#include <linux/mman.h>
21#include <linux/mm.h>
22#include <linux/smp.h>
23#include <linux/smp_lock.h>
24#include <linux/interrupt.h>
25#include <linux/init.h>
26#include <linux/vt_kern.h> /* For unblank_screen() */
27
28#include <asm/system.h>
29#include <asm/uaccess.h>
30#include <asm/pgalloc.h>
31#include <asm/hardirq.h>
32#include <asm/gdb-stub.h>
33#include <asm/cpu-regs.h>
34
35/*
36 * Unlock any spinlocks which will prevent us from getting the
37 * message out
38 */
39void bust_spinlocks(int yes)
40{
41 if (yes) {
42 oops_in_progress = 1;
43#ifdef CONFIG_SMP
44 /* Many serial drivers do __global_cli() */
45 global_irq_lock = 0;
46#endif
47 } else {
48 int loglevel_save = console_loglevel;
49#ifdef CONFIG_VT
50 unblank_screen();
51#endif
52 oops_in_progress = 0;
53 /*
54 * OK, the message is on the console. Now we call printk()
55 * without oops_in_progress set so that printk will give klogd
56 * a poke. Hold onto your hats...
57 */
58 console_loglevel = 15; /* NMI oopser may have shut the console
59 * up */
60 printk(" ");
61 console_loglevel = loglevel_save;
62 }
63}
64
65void do_BUG(const char *file, int line)
66{
67 bust_spinlocks(1);
68 printk(KERN_EMERG "------------[ cut here ]------------\n");
69 printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
70}
71
72#if 0
73static void print_pagetable_entries(pgd_t *pgdir, unsigned long address)
74{
75 pgd_t *pgd;
76 pmd_t *pmd;
77 pte_t *pte;
78
79 pgd = pgdir + __pgd_offset(address);
80 printk(KERN_DEBUG "pgd entry %p: %016Lx\n",
81 pgd, (long long) pgd_val(*pgd));
82
83 if (!pgd_present(*pgd)) {
84 printk(KERN_DEBUG "... pgd not present!\n");
85 return;
86 }
87 pmd = pmd_offset(pgd, address);
88 printk(KERN_DEBUG "pmd entry %p: %016Lx\n",
89 pmd, (long long)pmd_val(*pmd));
90
91 if (!pmd_present(*pmd)) {
92 printk(KERN_DEBUG "... pmd not present!\n");
93 return;
94 }
95 pte = pte_offset(pmd, address);
96 printk(KERN_DEBUG "pte entry %p: %016Lx\n",
97 pte, (long long) pte_val(*pte));
98
99 if (!pte_present(*pte))
100 printk(KERN_DEBUG "... pte not present!\n");
101}
102#endif
103
104asmlinkage void monitor_signal(struct pt_regs *);
105
106/*
107 * This routine handles page faults. It determines the address,
108 * and the problem, and then passes it off to one of the appropriate
109 * routines.
110 *
111 * fault_code:
112 * - LSW: either MMUFCR_IFC or MMUFCR_DFC as appropriate
113 * - MSW: 0 if data access, 1 if instruction access
114 * - bit 0: TLB miss flag
115 * - bit 1: initial write
116 * - bit 2: page invalid
117 * - bit 3: protection violation
118 * - bit 4: accessor (0=user 1=kernel)
119 * - bit 5: 0=read 1=write
120 * - bit 6-8: page protection spec
121 * - bit 9: illegal address
122 * - bit 16: 0=data 1=ins
123 *
124 */
125asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
126 unsigned long address)
127{
128 struct vm_area_struct *vma;
129 struct task_struct *tsk;
130 struct mm_struct *mm;
131 unsigned long page;
132 siginfo_t info;
133 int write, fault;
134
135#ifdef CONFIG_GDBSTUB
136 /* handle GDB stub causing a fault */
137 if (gdbstub_busy) {
138 gdbstub_exception(regs, TBR & TBR_INT_CODE);
139 return;
140 }
141#endif
142
143#if 0
144 printk(KERN_DEBUG "--- do_page_fault(%p,%s:%04lx,%08lx)\n",
145 regs,
146 fault_code & 0x10000 ? "ins" : "data",
147 fault_code & 0xffff, address);
148#endif
149
150 tsk = current;
151
152 /*
153 * We fault-in kernel-space virtual memory on-demand. The
154 * 'reference' page table is init_mm.pgd.
155 *
156 * NOTE! We MUST NOT take any locks for this case. We may
157 * be in an interrupt or a critical region, and should
158 * only copy the information from the master page table,
159 * nothing more.
160 *
161 * This verifies that the fault happens in kernel space
162 * and that the fault was a page not present (invalid) error
163 */
164 if (address >= VMALLOC_START && address < VMALLOC_END &&
165 (fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR &&
166 (fault_code & MMUFCR_xFC_PGINVAL) == MMUFCR_xFC_PGINVAL
167 )
168 goto vmalloc_fault;
169
170 mm = tsk->mm;
171 info.si_code = SEGV_MAPERR;
172
173 /*
174 * If we're in an interrupt or have no user
175 * context, we must not take the fault..
176 */
177 if (in_interrupt() || !mm)
178 goto no_context;
179
180 down_read(&mm->mmap_sem);
181
182 vma = find_vma(mm, address);
183 if (!vma)
184 goto bad_area;
185 if (vma->vm_start <= address)
186 goto good_area;
187 if (!(vma->vm_flags & VM_GROWSDOWN))
188 goto bad_area;
189
190 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) {
191 /* accessing the stack below the stack pointer is always a
192 * bug */
193 if ((address & PAGE_MASK) + 2 * PAGE_SIZE < regs->sp) {
194#if 0
195 printk(KERN_WARNING
196 "[%d] ### Access below stack @%lx (sp=%lx)\n",
197 current->pid, address, regs->sp);
198 printk(KERN_WARNING
199 "vma [%08x - %08x]\n",
200 vma->vm_start, vma->vm_end);
201 show_registers(regs);
202 printk(KERN_WARNING
203 "[%d] ### Code: [%08lx]"
204 " %02x %02x %02x %02x %02x %02x %02x %02x\n",
205 current->pid,
206 regs->pc,
207 ((u8 *) regs->pc)[0],
208 ((u8 *) regs->pc)[1],
209 ((u8 *) regs->pc)[2],
210 ((u8 *) regs->pc)[3],
211 ((u8 *) regs->pc)[4],
212 ((u8 *) regs->pc)[5],
213 ((u8 *) regs->pc)[6],
214 ((u8 *) regs->pc)[7]
215 );
216#endif
217 goto bad_area;
218 }
219 }
220
221 if (expand_stack(vma, address))
222 goto bad_area;
223
224/*
225 * Ok, we have a good vm_area for this memory access, so
226 * we can handle it..
227 */
228good_area:
229 info.si_code = SEGV_ACCERR;
230 write = 0;
231 switch (fault_code & (MMUFCR_xFC_PGINVAL|MMUFCR_xFC_TYPE)) {
232 default: /* 3: write, present */
233 case MMUFCR_xFC_TYPE_WRITE:
234#ifdef TEST_VERIFY_AREA
235 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR)
236 printk(KERN_DEBUG "WP fault at %08lx\n", regs->pc);
237#endif
238 /* write to absent page */
239 case MMUFCR_xFC_PGINVAL | MMUFCR_xFC_TYPE_WRITE:
240 if (!(vma->vm_flags & VM_WRITE))
241 goto bad_area;
242 write++;
243 break;
244
245 /* read from protected page */
246 case MMUFCR_xFC_TYPE_READ:
247 goto bad_area;
248
249 /* read from absent page present */
250 case MMUFCR_xFC_PGINVAL | MMUFCR_xFC_TYPE_READ:
251 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
252 goto bad_area;
253 break;
254 }
255
256 /*
257 * If for any reason at all we couldn't handle the fault,
258 * make sure we exit gracefully rather than endlessly redo
259 * the fault.
260 */
261 fault = handle_mm_fault(mm, vma, address, write);
262 if (unlikely(fault & VM_FAULT_ERROR)) {
263 if (fault & VM_FAULT_OOM)
264 goto out_of_memory;
265 else if (fault & VM_FAULT_SIGBUS)
266 goto do_sigbus;
267 BUG();
268 }
269 if (fault & VM_FAULT_MAJOR)
270 current->maj_flt++;
271 else
272 current->min_flt++;
273
274 up_read(&mm->mmap_sem);
275 return;
276
277/*
278 * Something tried to access memory that isn't in our memory map..
279 * Fix it, but check if it's kernel or user first..
280 */
281bad_area:
282 up_read(&mm->mmap_sem);
283 monitor_signal(regs);
284
285 /* User mode accesses just cause a SIGSEGV */
286 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR) {
287 info.si_signo = SIGSEGV;
288 info.si_errno = 0;
289 /* info.si_code has been set above */
290 info.si_addr = (void *)address;
291 force_sig_info(SIGSEGV, &info, tsk);
292 return;
293 }
294
295no_context:
296 monitor_signal(regs);
297 /* Are we prepared to handle this kernel fault? */
298 if (fixup_exception(regs))
299 return;
300
301/*
302 * Oops. The kernel tried to access some bad page. We'll have to
303 * terminate things with extreme prejudice.
304 */
305
306 bust_spinlocks(1);
307
308 if (address < PAGE_SIZE)
309 printk(KERN_ALERT
310 "Unable to handle kernel NULL pointer dereference");
311 else
312 printk(KERN_ALERT
313 "Unable to handle kernel paging request");
314 printk(" at virtual address %08lx\n", address);
315 printk(" printing pc:\n");
316 printk(KERN_ALERT "%08lx\n", regs->pc);
317
318#ifdef CONFIG_GDBSTUB
319 gdbstub_intercept(
320 regs, fault_code & 0x00010000 ? EXCEP_IAERROR : EXCEP_DAERROR);
321#endif
322
323 page = PTBR;
324 page = ((unsigned long *) __va(page))[address >> 22];
325 printk(KERN_ALERT "*pde = %08lx\n", page);
326 if (page & 1) {
327 page &= PAGE_MASK;
328 address &= 0x003ff000;
329 page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
330 printk(KERN_ALERT "*pte = %08lx\n", page);
331 }
332
333 die("Oops", regs, fault_code);
334 do_exit(SIGKILL);
335
336/*
337 * We ran out of memory, or some other thing happened to us that made
338 * us unable to handle the page fault gracefully.
339 */
340out_of_memory:
341 up_read(&mm->mmap_sem);
342 monitor_signal(regs);
343 printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
344 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
345 do_exit(SIGKILL);
346 goto no_context;
347
348do_sigbus:
349 up_read(&mm->mmap_sem);
350 monitor_signal(regs);
351
352 /*
353 * Send a sigbus, regardless of whether we were in kernel
354 * or user mode.
355 */
356 info.si_signo = SIGBUS;
357 info.si_errno = 0;
358 info.si_code = BUS_ADRERR;
359 info.si_addr = (void *)address;
360 force_sig_info(SIGBUS, &info, tsk);
361
362 /* Kernel mode? Handle exceptions or die */
363 if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_SR)
364 goto no_context;
365 return;
366
367vmalloc_fault:
368 {
369 /*
370 * Synchronize this task's top level page-table
371 * with the 'reference' page table.
372 *
373 * Do _not_ use "tsk" here. We might be inside
374 * an interrupt in the middle of a task switch..
375 */
376 int index = pgd_index(address);
377 pgd_t *pgd, *pgd_k;
378 pud_t *pud, *pud_k;
379 pmd_t *pmd, *pmd_k;
380 pte_t *pte_k;
381
382 pgd_k = init_mm.pgd + index;
383
384 if (!pgd_present(*pgd_k))
385 goto no_context;
386
387 pud_k = pud_offset(pgd_k, address);
388 if (!pud_present(*pud_k))
389 goto no_context;
390
391 pmd_k = pmd_offset(pud_k, address);
392 if (!pmd_present(*pmd_k))
393 goto no_context;
394
395 pgd = (pgd_t *) PTBR + index;
396 pud = pud_offset(pgd, address);
397 pmd = pmd_offset(pud, address);
398 set_pmd(pmd, *pmd_k);
399
400 pte_k = pte_offset_kernel(pmd_k, address);
401 if (!pte_present(*pte_k))
402 goto no_context;
403 return;
404 }
405}
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
new file mode 100644
index 000000000000..8c5d88c7b90a
--- /dev/null
+++ b/arch/mn10300/mm/init.c
@@ -0,0 +1,160 @@
1/* MN10300 Memory management initialisation
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/signal.h>
13#include <linux/sched.h>
14#include <linux/kernel.h>
15#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/types.h>
18#include <linux/ptrace.h>
19#include <linux/mman.h>
20#include <linux/slab.h>
21#include <linux/fs.h>
22#include <linux/mm.h>
23#include <linux/swap.h>
24#include <linux/smp.h>
25#include <linux/init.h>
26#include <linux/initrd.h>
27#include <linux/highmem.h>
28#include <linux/pagemap.h>
29#include <linux/bootmem.h>
30
31#include <asm/processor.h>
32#include <asm/system.h>
33#include <asm/uaccess.h>
34#include <asm/pgtable.h>
35#include <asm/pgalloc.h>
36#include <asm/dma.h>
37#include <asm/tlb.h>
38#include <asm/sections.h>
39
40DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
41
42unsigned long highstart_pfn, highend_pfn;
43
44/*
45 * set up paging
46 */
47void __init paging_init(void)
48{
49 unsigned long zones_size[MAX_NR_ZONES] = {0,};
50 pte_t *ppte;
51 int loop;
52
53 /* main kernel space -> RAM mapping is handled as 1:1 transparent by
54 * the MMU */
55 memset(swapper_pg_dir, 0, sizeof(swapper_pg_dir));
56 memset(kernel_vmalloc_ptes, 0, sizeof(kernel_vmalloc_ptes));
57
58 /* load the VMALLOC area PTE table addresses into the kernel PGD */
59 ppte = kernel_vmalloc_ptes;
60 for (loop = VMALLOC_START / (PAGE_SIZE * PTRS_PER_PTE);
61 loop < VMALLOC_END / (PAGE_SIZE * PTRS_PER_PTE);
62 loop++
63 ) {
64 set_pgd(swapper_pg_dir + loop, __pgd(__pa(ppte) | _PAGE_TABLE));
65 ppte += PAGE_SIZE / sizeof(pte_t);
66 }
67
68 /* declare the sizes of the RAM zones (only use the normal zone) */
69 zones_size[ZONE_NORMAL] =
70 (contig_page_data.bdata->node_low_pfn) -
71 (contig_page_data.bdata->node_boot_start >> PAGE_SHIFT);
72
73 /* pass the memory from the bootmem allocator to the main allocator */
74 free_area_init(zones_size);
75
76 __flush_tlb_all();
77}
78
79/*
80 * transfer all the memory from the bootmem allocator to the runtime allocator
81 */
82void __init mem_init(void)
83{
84 int codesize, reservedpages, datasize, initsize;
85 int tmp;
86
87 if (!mem_map)
88 BUG();
89
90#define START_PFN (contig_page_data.bdata->node_boot_start >> PAGE_SHIFT)
91#define MAX_LOW_PFN (contig_page_data.bdata->node_low_pfn)
92
93 max_mapnr = num_physpages = MAX_LOW_PFN - START_PFN;
94 high_memory = (void *) __va(MAX_LOW_PFN * PAGE_SIZE);
95
96 /* clear the zero-page */
97 memset(empty_zero_page, 0, PAGE_SIZE);
98
99 /* this will put all low memory onto the freelists */
100 totalram_pages += free_all_bootmem();
101
102 reservedpages = 0;
103 for (tmp = 0; tmp < num_physpages; tmp++)
104 if (PageReserved(&mem_map[tmp]))
105 reservedpages++;
106
107 codesize = (unsigned long) &_etext - (unsigned long) &_stext;
108 datasize = (unsigned long) &_edata - (unsigned long) &_etext;
109 initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
110
111 printk(KERN_INFO
112 "Memory: %luk/%luk available"
113 " (%dk kernel code, %dk reserved, %dk data, %dk init,"
114 " %ldk highmem)\n",
115 (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10),
116 max_mapnr << (PAGE_SHIFT - 10),
117 codesize >> 10,
118 reservedpages << (PAGE_SHIFT - 10),
119 datasize >> 10,
120 initsize >> 10,
121 (unsigned long) (totalhigh_pages << (PAGE_SHIFT - 10))
122 );
123}
124
125/*
126 *
127 */
128void free_init_pages(char *what, unsigned long begin, unsigned long end)
129{
130 unsigned long addr;
131
132 for (addr = begin; addr < end; addr += PAGE_SIZE) {
133 ClearPageReserved(virt_to_page(addr));
134 init_page_count(virt_to_page(addr));
135 memset((void *) addr, 0xcc, PAGE_SIZE);
136 free_page(addr);
137 totalram_pages++;
138 }
139 printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
140}
141
142/*
143 * recycle memory containing stuff only required for initialisation
144 */
145void free_initmem(void)
146{
147 free_init_pages("unused kernel memory",
148 (unsigned long) &__init_begin,
149 (unsigned long) &__init_end);
150}
151
152/*
153 * dispose of the memory on which the initial ramdisk resided
154 */
155#ifdef CONFIG_BLK_DEV_INITRD
156void free_initrd_mem(unsigned long start, unsigned long end)
157{
158 free_init_pages("initrd memory", start, end);
159}
160#endif
diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c
new file mode 100644
index 000000000000..32aa89dc3848
--- /dev/null
+++ b/arch/mn10300/mm/misalignment.c
@@ -0,0 +1,661 @@
1/* MN10300 Misalignment fixup handler
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/module.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/string.h>
15#include <linux/errno.h>
16#include <linux/ptrace.h>
17#include <linux/timer.h>
18#include <linux/mm.h>
19#include <linux/smp.h>
20#include <linux/smp_lock.h>
21#include <linux/init.h>
22#include <linux/delay.h>
23#include <linux/spinlock.h>
24#include <linux/interrupt.h>
25#include <linux/pci.h>
26#include <asm/processor.h>
27#include <asm/system.h>
28#include <asm/uaccess.h>
29#include <asm/io.h>
30#include <asm/atomic.h>
31#include <asm/smp.h>
32#include <asm/pgalloc.h>
33#include <asm/cpu-regs.h>
34#include <asm/busctl-regs.h>
35#include <asm/fpu.h>
36#include <asm/gdb-stub.h>
37#include <asm/asm-offsets.h>
38
39#if 0
40#define kdebug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
41#else
42#define kdebug(FMT, ...) do {} while (0)
43#endif
44
45static int misalignment_addr(unsigned long *registers, unsigned params,
46 unsigned opcode, unsigned disp,
47 void **_address, unsigned long **_postinc);
48
49static int misalignment_reg(unsigned long *registers, unsigned params,
50 unsigned opcode, unsigned disp,
51 unsigned long **_register);
52
53static inline unsigned int_log2(unsigned x)
54{
55 unsigned y;
56 asm("bsch %1,%0" : "=r"(y) : "r"(x), "0"(0));
57 return y;
58}
59#define log2(x) int_log2(x)
60
61static const unsigned Dreg_index[] = {
62 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
63};
64
65static const unsigned Areg_index[] = {
66 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2
67};
68
69static const unsigned Rreg_index[] = {
70 REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2,
71 REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2,
72 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2,
73 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2
74};
75
76enum format_id {
77 FMT_S0,
78 FMT_S1,
79 FMT_S2,
80 FMT_S4,
81 FMT_D0,
82 FMT_D1,
83 FMT_D2,
84 FMT_D4,
85 FMT_D6,
86 FMT_D7,
87 FMT_D8,
88 FMT_D9,
89};
90
91struct {
92 u_int8_t opsz, dispsz;
93} format_tbl[16] = {
94 [FMT_S0] = { 8, 0 },
95 [FMT_S1] = { 8, 8 },
96 [FMT_S2] = { 8, 16 },
97 [FMT_S4] = { 8, 32 },
98 [FMT_D0] = { 16, 0 },
99 [FMT_D1] = { 16, 8 },
100 [FMT_D2] = { 16, 16 },
101 [FMT_D4] = { 16, 32 },
102 [FMT_D6] = { 24, 0 },
103 [FMT_D7] = { 24, 8 },
104 [FMT_D8] = { 24, 24 },
105 [FMT_D9] = { 24, 32 },
106};
107
108enum value_id {
109 DM0, /* data reg in opcode in bits 0-1 */
110 DM1, /* data reg in opcode in bits 2-3 */
111 DM2, /* data reg in opcode in bits 4-5 */
112 AM0, /* addr reg in opcode in bits 0-1 */
113 AM1, /* addr reg in opcode in bits 2-3 */
114 AM2, /* addr reg in opcode in bits 4-5 */
115 RM0, /* reg in opcode in bits 0-3 */
116 RM1, /* reg in opcode in bits 2-5 */
117 RM2, /* reg in opcode in bits 4-7 */
118 RM4, /* reg in opcode in bits 8-11 */
119 RM6, /* reg in opcode in bits 12-15 */
120
121 RD0, /* reg in displacement in bits 0-3 */
122 RD2, /* reg in displacement in bits 4-7 */
123
124 SP, /* stack pointer */
125
126 SD8, /* 8-bit signed displacement */
127 SD16, /* 16-bit signed displacement */
128 SD24, /* 24-bit signed displacement */
129 SIMM4_2, /* 4-bit signed displacement in opcode bits 4-7 */
130 SIMM8, /* 8-bit signed immediate */
131 IMM24, /* 24-bit unsigned immediate */
132 IMM32, /* 32-bit unsigned immediate */
133 IMM32_HIGH8, /* 32-bit unsigned immediate, high 8-bits in opcode */
134
135 DN0 = DM0,
136 DN1 = DM1,
137 DN2 = DM2,
138 AN0 = AM0,
139 AN1 = AM1,
140 AN2 = AM2,
141 RN0 = RM0,
142 RN1 = RM1,
143 RN2 = RM2,
144 RN4 = RM4,
145 RN6 = RM6,
146 DI = DM1,
147 RI = RM2,
148
149};
150
151struct mn10300_opcode {
152 const char *name;
153 u_int32_t opcode;
154 u_int32_t opmask;
155 unsigned exclusion;
156
157 enum format_id format;
158
159 unsigned cpu_mask;
160#define AM33 330
161
162 unsigned params[2];
163#define MEM(ADDR) (0x80000000 | (ADDR))
164#define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2))
165#define MEMINC(ADDR) (0x81000000 | (ADDR))
166#define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC))
167};
168
169/* LIBOPCODES EXCERPT
170 Assemble Matsushita MN10300 instructions.
171 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
172
173 This program is free software; you can redistribute it and/or modify
174 it under the terms of the GNU General Public Licence as published by
175 the Free Software Foundation; either version 2 of the Licence, or
176 (at your option) any later version.
177
178 This program is distributed in the hope that it will be useful,
179 but WITHOUT ANY WARRANTY; without even the implied warranty of
180 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181 GNU General Public Licence for more details.
182
183 You should have received a copy of the GNU General Public Licence
184 along with this program; if not, write to the Free Software
185 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
186*/
187static const struct mn10300_opcode mn10300_opcodes[] = {
188{ "mov", 0x60, 0xf0, 0, FMT_S0, 0, {DM1, MEM(AN0)}},
189{ "mov", 0x70, 0xf0, 0, FMT_S0, 0, {MEM(AM0), DN1}},
190{ "mov", 0xf000, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), AN1}},
191{ "mov", 0xf010, 0xfff0, 0, FMT_D0, 0, {AM1, MEM(AN0)}},
192{ "mov", 0xf300, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
193{ "mov", 0xf340, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
194{ "mov", 0xf380, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), AN2}},
195{ "mov", 0xf3c0, 0xffc0, 0, FMT_D0, 0, {AM2, MEM2(DI, AN0)}},
196{ "mov", 0xf80000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
197{ "mov", 0xf81000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
198{ "mov", 0xf82000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8,AM0), AN1}},
199{ "mov", 0xf83000, 0xfff000, 0, FMT_D1, 0, {AM1, MEM2(SD8, AN0)}},
200{ "mov", 0xf8f000, 0xfffc00, 0, FMT_D1, AM33, {MEM2(SD8, AM0), SP}},
201{ "mov", 0xf8f400, 0xfffc00, 0, FMT_D1, AM33, {SP, MEM2(SD8, AN0)}},
202{ "mov", 0xf90a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
203{ "mov", 0xf91a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
204{ "mov", 0xf96a00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
205{ "mov", 0xf97a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
206{ "mov", 0xfa000000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
207{ "mov", 0xfa100000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
208{ "mov", 0xfa200000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), AN1}},
209{ "mov", 0xfa300000, 0xfff00000, 0, FMT_D2, 0, {AM1, MEM2(SD16, AN0)}},
210{ "mov", 0xfb0a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
211{ "mov", 0xfb1a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
212{ "mov", 0xfb6a0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
213{ "mov", 0xfb7a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
214{ "mov", 0xfb8e0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
215{ "mov", 0xfb9e0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
216{ "mov", 0xfc000000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
217{ "mov", 0xfc100000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
218{ "mov", 0xfc200000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), AN1}},
219{ "mov", 0xfc300000, 0xfff00000, 0, FMT_D4, 0, {AM1, MEM2(IMM32,AN0)}},
220{ "mov", 0xfd0a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
221{ "mov", 0xfd1a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
222{ "mov", 0xfd6a0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
223{ "mov", 0xfd7a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
224{ "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
225{ "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
226{ "mov", 0xfe6a0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
227{ "mov", 0xfe7a0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
228
229{ "movhu", 0xf060, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), DN1}},
230{ "movhu", 0xf070, 0xfff0, 0, FMT_D0, 0, {DM1, MEM(AN0)}},
231{ "movhu", 0xf480, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}},
232{ "movhu", 0xf4c0, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}},
233{ "movhu", 0xf86000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}},
234{ "movhu", 0xf87000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}},
235{ "movhu", 0xf94a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}},
236{ "movhu", 0xf95a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}},
237{ "movhu", 0xf9ea00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}},
238{ "movhu", 0xf9fa00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}},
239{ "movhu", 0xfa600000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}},
240{ "movhu", 0xfa700000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}},
241{ "movhu", 0xfb4a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}},
242{ "movhu", 0xfb5a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}},
243{ "movhu", 0xfbce0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}},
244{ "movhu", 0xfbde0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}},
245{ "movhu", 0xfbea0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}},
246{ "movhu", 0xfbfa0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}},
247{ "movhu", 0xfc600000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}},
248{ "movhu", 0xfc700000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}},
249{ "movhu", 0xfd4a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}},
250{ "movhu", 0xfd5a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}},
251{ "movhu", 0xfdea0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}},
252{ "movhu", 0xfdfa0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}},
253{ "movhu", 0xfe4a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}},
254{ "movhu", 0xfe5a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}},
255{ "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}},
256{ "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}},
257{ 0, 0, 0, 0, 0, 0, {0}},
258};
259
260/*
261 * fix up misalignment problems where possible
262 */
263asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code)
264{
265 const struct exception_table_entry *fixup;
266 const struct mn10300_opcode *pop;
267 unsigned long *registers = (unsigned long *) regs;
268 unsigned long data, *store, *postinc;
269 mm_segment_t seg;
270 siginfo_t info;
271 uint32_t opcode, disp, noc, xo, xm;
272 uint8_t *pc, byte;
273 void *address;
274 unsigned tmp, npop;
275
276 kdebug("MISALIGN at %lx\n", regs->pc);
277
278 if (in_interrupt())
279 die("Misalignment trap in interrupt context", regs, code);
280
281 if (regs->epsw & EPSW_IE)
282 asm volatile("or %0,epsw" : : "i"(EPSW_IE));
283
284 seg = get_fs();
285 set_fs(KERNEL_DS);
286
287 fixup = search_exception_tables(regs->pc);
288
289 /* first thing to do is to match the opcode */
290 pc = (u_int8_t *) regs->pc;
291
292 if (__get_user(byte, pc) != 0)
293 goto fetch_error;
294 opcode = byte;
295 noc = 8;
296
297 for (pop = mn10300_opcodes; pop->name; pop++) {
298 npop = log2(pop->opcode | pop->opmask);
299 if (npop <= 0 || npop > 31)
300 continue;
301 npop = (npop + 8) & ~7;
302
303 got_more_bits:
304 if (npop == noc) {
305 if ((opcode & pop->opmask) == pop->opcode)
306 goto found_opcode;
307 } else if (npop > noc) {
308 xo = pop->opcode >> (npop - noc);
309 xm = pop->opmask >> (npop - noc);
310
311 if ((opcode & xm) != xo)
312 continue;
313
314 /* we've got a partial match (an exact match on the
315 * first N bytes), so we need to get some more data */
316 pc++;
317 if (__get_user(byte, pc) != 0)
318 goto fetch_error;
319 opcode = opcode << 8 | byte;
320 noc += 8;
321 goto got_more_bits;
322 } else {
323 /* there's already been a partial match as long as the
324 * complete match we're now considering, so this one
325 * should't match */
326 continue;
327 }
328 }
329
330 /* didn't manage to find a fixup */
331 if (!user_mode(regs))
332 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n",
333 regs->pc, opcode);
334
335failed:
336 set_fs(seg);
337 if (die_if_no_fixup("misalignment error", regs, code))
338 return;
339
340 info.si_signo = SIGBUS;
341 info.si_errno = 0;
342 info.si_code = BUS_ADRALN;
343 info.si_addr = (void *) regs->pc;
344 force_sig_info(SIGBUS, &info, current);
345 return;
346
347 /* error reading opcodes */
348fetch_error:
349 if (!user_mode(regs))
350 printk(KERN_CRIT
351 "MISALIGN: %p: fault whilst reading instruction data\n",
352 pc);
353 goto failed;
354
355bad_addr_mode:
356 if (!user_mode(regs))
357 printk(KERN_CRIT
358 "MISALIGN: %lx: unsupported addressing mode %x\n",
359 regs->pc, opcode);
360 goto failed;
361
362bad_reg_mode:
363 if (!user_mode(regs))
364 printk(KERN_CRIT
365 "MISALIGN: %lx: unsupported register mode %x\n",
366 regs->pc, opcode);
367 goto failed;
368
369unsupported_instruction:
370 if (!user_mode(regs))
371 printk(KERN_CRIT
372 "MISALIGN: %lx: unsupported instruction %x (%s)\n",
373 regs->pc, opcode, pop->name);
374 goto failed;
375
376transfer_failed:
377 set_fs(seg);
378 if (fixup) {
379 regs->pc = fixup->fixup;
380 return;
381 }
382 if (die_if_no_fixup("misalignment fixup", regs, code))
383 return;
384
385 info.si_signo = SIGSEGV;
386 info.si_errno = 0;
387 info.si_code = 0;
388 info.si_addr = (void *) regs->pc;
389 force_sig_info(SIGSEGV, &info, current);
390 return;
391
392 /* we matched the opcode */
393found_opcode:
394 kdebug("MISALIGN: %lx: %x==%x { %x, %x }\n",
395 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]);
396
397 tmp = format_tbl[pop->format].opsz;
398 if (tmp > noc)
399 BUG(); /* match was less complete than it ought to have been */
400
401 if (tmp < noc) {
402 tmp = noc - tmp;
403 opcode >>= tmp;
404 pc -= tmp >> 3;
405 }
406
407 /* grab the extra displacement (note it's LSB first) */
408 disp = 0;
409 tmp = format_tbl[pop->format].dispsz >> 3;
410 while (tmp > 0) {
411 tmp--;
412 disp <<= 8;
413
414 pc++;
415 if (__get_user(byte, pc) != 0)
416 goto fetch_error;
417 disp |= byte;
418 }
419
420 set_fs(KERNEL_XDS);
421 if (fixup || regs->epsw & EPSW_nSL)
422 set_fs(seg);
423
424 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000;
425 if (!tmp) {
426 if (!user_mode(regs))
427 printk(KERN_CRIT
428 "MISALIGN: %lx:"
429 " insn not move to/from memory %x\n",
430 regs->pc, opcode);
431 goto failed;
432 }
433
434 if (pop->params[0] & 0x80000000) {
435 /* move memory to register */
436 if (!misalignment_addr(registers, pop->params[0], opcode, disp,
437 &address, &postinc))
438 goto bad_addr_mode;
439
440 if (!misalignment_reg(registers, pop->params[1], opcode, disp,
441 &store))
442 goto bad_reg_mode;
443
444 if (strcmp(pop->name, "mov") == 0) {
445 kdebug("FIXUP: mov (%p),DARn\n", address);
446 if (copy_from_user(&data, (void *) address, 4) != 0)
447 goto transfer_failed;
448 if (pop->params[0] & 0x1000000)
449 *postinc += 4;
450 } else if (strcmp(pop->name, "movhu") == 0) {
451 kdebug("FIXUP: movhu (%p),DARn\n", address);
452 data = 0;
453 if (copy_from_user(&data, (void *) address, 2) != 0)
454 goto transfer_failed;
455 if (pop->params[0] & 0x1000000)
456 *postinc += 2;
457 } else {
458 goto unsupported_instruction;
459 }
460
461 *store = data;
462 } else {
463 /* move register to memory */
464 if (!misalignment_reg(registers, pop->params[0], opcode, disp,
465 &store))
466 goto bad_reg_mode;
467
468 if (!misalignment_addr(registers, pop->params[1], opcode, disp,
469 &address, &postinc))
470 goto bad_addr_mode;
471
472 data = *store;
473
474 if (strcmp(pop->name, "mov") == 0) {
475 kdebug("FIXUP: mov %lx,(%p)\n", data, address);
476 if (copy_to_user((void *) address, &data, 4) != 0)
477 goto transfer_failed;
478 if (pop->params[1] & 0x1000000)
479 *postinc += 4;
480 } else if (strcmp(pop->name, "movhu") == 0) {
481 kdebug("FIXUP: movhu %hx,(%p)\n",
482 (uint16_t) data, address);
483 if (copy_to_user((void *) address, &data, 2) != 0)
484 goto transfer_failed;
485 if (pop->params[1] & 0x1000000)
486 *postinc += 2;
487 } else {
488 goto unsupported_instruction;
489 }
490 }
491
492 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz;
493 regs->pc += tmp >> 3;
494
495 set_fs(seg);
496 return;
497}
498
499/*
500 * determine the address that was being accessed
501 */
502static int misalignment_addr(unsigned long *registers, unsigned params,
503 unsigned opcode, unsigned disp,
504 void **_address, unsigned long **_postinc)
505{
506 unsigned long *postinc = NULL, address = 0, tmp;
507
508 params &= 0x7fffffff;
509
510 do {
511 switch (params & 0xff) {
512 case DM0:
513 postinc = &registers[Dreg_index[opcode & 0x03]];
514 address += *postinc;
515 break;
516 case DM1:
517 postinc = &registers[Dreg_index[opcode >> 2 & 0x0c]];
518 address += *postinc;
519 break;
520 case DM2:
521 postinc = &registers[Dreg_index[opcode >> 4 & 0x30]];
522 address += *postinc;
523 break;
524 case AM0:
525 postinc = &registers[Areg_index[opcode & 0x03]];
526 address += *postinc;
527 break;
528 case AM1:
529 postinc = &registers[Areg_index[opcode >> 2 & 0x0c]];
530 address += *postinc;
531 break;
532 case AM2:
533 postinc = &registers[Areg_index[opcode >> 4 & 0x30]];
534 address += *postinc;
535 break;
536 case RM0:
537 postinc = &registers[Rreg_index[opcode & 0x0f]];
538 address += *postinc;
539 break;
540 case RM1:
541 postinc = &registers[Rreg_index[opcode >> 2 & 0x0f]];
542 address += *postinc;
543 break;
544 case RM2:
545 postinc = &registers[Rreg_index[opcode >> 4 & 0x0f]];
546 address += *postinc;
547 break;
548 case RM4:
549 postinc = &registers[Rreg_index[opcode >> 8 & 0x0f]];
550 address += *postinc;
551 break;
552 case RM6:
553 postinc = &registers[Rreg_index[opcode >> 12 & 0x0f]];
554 address += *postinc;
555 break;
556 case RD0:
557 postinc = &registers[Rreg_index[disp & 0x0f]];
558 address += *postinc;
559 break;
560 case RD2:
561 postinc = &registers[Rreg_index[disp >> 4 & 0x0f]];
562 address += *postinc;
563 break;
564
565 case SD8:
566 case SIMM8:
567 address += (int32_t) (int8_t) (disp & 0xff);
568 break;
569 case SD16:
570 address += (int32_t) (int16_t) (disp & 0xffff);
571 break;
572 case SD24:
573 tmp = disp << 8;
574 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp));
575 address += tmp;
576 break;
577 case SIMM4_2:
578 tmp = opcode >> 4 & 0x0f;
579 tmp <<= 28;
580 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp));
581 address += tmp;
582 break;
583 case IMM24:
584 address += disp & 0x00ffffff;
585 break;
586 case IMM32:
587 case IMM32_HIGH8:
588 address += disp;
589 break;
590 default:
591 return 0;
592 }
593 } while ((params >>= 8));
594
595 *_address = (void *) address;
596 *_postinc = postinc;
597 return 1;
598}
599
600/*
601 * determine the register that is acting as source/dest
602 */
603static int misalignment_reg(unsigned long *registers, unsigned params,
604 unsigned opcode, unsigned disp,
605 unsigned long **_register)
606{
607 params &= 0x7fffffff;
608
609 if (params & 0xffffff00)
610 return 0;
611
612 switch (params & 0xff) {
613 case DM0:
614 *_register = &registers[Dreg_index[opcode & 0x03]];
615 break;
616 case DM1:
617 *_register = &registers[Dreg_index[opcode >> 2 & 0x03]];
618 break;
619 case DM2:
620 *_register = &registers[Dreg_index[opcode >> 4 & 0x03]];
621 break;
622 case AM0:
623 *_register = &registers[Areg_index[opcode & 0x03]];
624 break;
625 case AM1:
626 *_register = &registers[Areg_index[opcode >> 2 & 0x03]];
627 break;
628 case AM2:
629 *_register = &registers[Areg_index[opcode >> 4 & 0x03]];
630 break;
631 case RM0:
632 *_register = &registers[Rreg_index[opcode & 0x0f]];
633 break;
634 case RM1:
635 *_register = &registers[Rreg_index[opcode >> 2 & 0x0f]];
636 break;
637 case RM2:
638 *_register = &registers[Rreg_index[opcode >> 4 & 0x0f]];
639 break;
640 case RM4:
641 *_register = &registers[Rreg_index[opcode >> 8 & 0x0f]];
642 break;
643 case RM6:
644 *_register = &registers[Rreg_index[opcode >> 12 & 0x0f]];
645 break;
646 case RD0:
647 *_register = &registers[Rreg_index[disp & 0x0f]];
648 break;
649 case RD2:
650 *_register = &registers[Rreg_index[disp >> 4 & 0x0f]];
651 break;
652 case SP:
653 *_register = &registers[REG_SP >> 2];
654 break;
655
656 default:
657 return 0;
658 }
659
660 return 1;
661}
diff --git a/arch/mn10300/mm/mmu-context.c b/arch/mn10300/mm/mmu-context.c
new file mode 100644
index 000000000000..31c9d27a75ae
--- /dev/null
+++ b/arch/mn10300/mm/mmu-context.c
@@ -0,0 +1,80 @@
1/* MN10300 MMU context allocation and management
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/sched.h>
12#include <linux/mm.h>
13#include <asm/mmu_context.h>
14#include <asm/tlbflush.h>
15
16/*
17 * list of the MMU contexts last allocated on each CPU
18 */
19unsigned long mmu_context_cache[NR_CPUS] = {
20 [0 ... NR_CPUS - 1] = MMU_CONTEXT_FIRST_VERSION * 2 - 1,
21};
22
23/*
24 * flush the specified TLB entry
25 */
26void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
27{
28 unsigned long pteu, cnx, flags;
29
30 addr &= PAGE_MASK;
31
32 /* make sure the context doesn't migrate and defend against
33 * interference from vmalloc'd regions */
34 local_irq_save(flags);
35
36 cnx = mm_context(vma->vm_mm);
37
38 if (cnx != MMU_NO_CONTEXT) {
39 pteu = addr | (cnx & 0x000000ffUL);
40 IPTEU = pteu;
41 DPTEU = pteu;
42 if (IPTEL & xPTEL_V)
43 IPTEL = 0;
44 if (DPTEL & xPTEL_V)
45 DPTEL = 0;
46 }
47
48 local_irq_restore(flags);
49}
50
51/*
52 * preemptively set a TLB entry
53 */
54void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
55{
56 unsigned long pteu, ptel, cnx, flags;
57
58 addr &= PAGE_MASK;
59 ptel = pte_val(pte) & ~(xPTEL_UNUSED1 | xPTEL_UNUSED2);
60
61 /* make sure the context doesn't migrate and defend against
62 * interference from vmalloc'd regions */
63 local_irq_save(flags);
64
65 cnx = mm_context(vma->vm_mm);
66
67 if (cnx != MMU_NO_CONTEXT) {
68 pteu = addr | (cnx & 0x000000ffUL);
69 if (!(pte_val(pte) & _PAGE_NX)) {
70 IPTEU = pteu;
71 if (IPTEL & xPTEL_V)
72 IPTEL = ptel;
73 }
74 DPTEU = pteu;
75 if (DPTEL & xPTEL_V)
76 DPTEL = ptel;
77 }
78
79 local_irq_restore(flags);
80}
diff --git a/arch/mn10300/mm/pgtable.c b/arch/mn10300/mm/pgtable.c
new file mode 100644
index 000000000000..a477038752ba
--- /dev/null
+++ b/arch/mn10300/mm/pgtable.c
@@ -0,0 +1,197 @@
1/* MN10300 Page table management
2 *
3 * Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Modified by David Howells (dhowells@redhat.com)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/errno.h>
15#include <linux/mm.h>
16#include <linux/swap.h>
17#include <linux/smp.h>
18#include <linux/highmem.h>
19#include <linux/slab.h>
20#include <linux/pagemap.h>
21#include <linux/spinlock.h>
22#include <linux/quicklist.h>
23
24#include <asm/system.h>
25#include <asm/pgtable.h>
26#include <asm/pgalloc.h>
27#include <asm/tlb.h>
28#include <asm/tlbflush.h>
29
30void show_mem(void)
31{
32 unsigned long i;
33 int free = 0, total = 0, reserved = 0, shared = 0;
34
35 int cached = 0;
36 printk(KERN_INFO "Mem-info:\n");
37 show_free_areas();
38 i = max_mapnr;
39 while (i-- > 0) {
40 total++;
41 if (PageReserved(mem_map + i))
42 reserved++;
43 else if (PageSwapCache(mem_map + i))
44 cached++;
45 else if (!page_count(mem_map + i))
46 free++;
47 else
48 shared += page_count(mem_map + i) - 1;
49 }
50 printk(KERN_INFO "%d pages of RAM\n", total);
51 printk(KERN_INFO "%d free pages\n", free);
52 printk(KERN_INFO "%d reserved pages\n", reserved);
53 printk(KERN_INFO "%d pages shared\n", shared);
54 printk(KERN_INFO "%d pages swap cached\n", cached);
55}
56
57/*
58 * Associate a large virtual page frame with a given physical page frame
59 * and protection flags for that frame. pfn is for the base of the page,
60 * vaddr is what the page gets mapped to - both must be properly aligned.
61 * The pmd must already be instantiated. Assumes PAE mode.
62 */
63void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
64{
65 pgd_t *pgd;
66 pud_t *pud;
67 pmd_t *pmd;
68
69 if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */
70 printk(KERN_ERR "set_pmd_pfn: vaddr misaligned\n");
71 return; /* BUG(); */
72 }
73 if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */
74 printk(KERN_ERR "set_pmd_pfn: pfn misaligned\n");
75 return; /* BUG(); */
76 }
77 pgd = swapper_pg_dir + pgd_index(vaddr);
78 if (pgd_none(*pgd)) {
79 printk(KERN_ERR "set_pmd_pfn: pgd_none\n");
80 return; /* BUG(); */
81 }
82 pud = pud_offset(pgd, vaddr);
83 pmd = pmd_offset(pud, vaddr);
84 set_pmd(pmd, pfn_pmd(pfn, flags));
85 /*
86 * It's enough to flush this one mapping.
87 * (PGE mappings get flushed as well)
88 */
89 __flush_tlb_one(vaddr);
90}
91
92pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
93{
94 pte_t *pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
95 if (pte)
96 clear_page(pte);
97 return pte;
98}
99
100struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
101{
102 struct page *pte;
103
104#ifdef CONFIG_HIGHPTE
105 pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT, 0);
106#else
107 pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);
108#endif
109 if (pte)
110 clear_highpage(pte);
111 return pte;
112}
113
114/*
115 * List of all pgd's needed for non-PAE so it can invalidate entries
116 * in both cached and uncached pgd's; not needed for PAE since the
117 * kernel pmd is shared. If PAE were not to share the pmd a similar
118 * tactic would be needed. This is essentially codepath-based locking
119 * against pageattr.c; it is the unique case in which a valid change
120 * of kernel pagetables can't be lazily synchronized by vmalloc faults.
121 * vmalloc faults work because attached pagetables are never freed.
122 * If the locking proves to be non-performant, a ticketing scheme with
123 * checks at dup_mmap(), exec(), and other mmlist addition points
124 * could be used. The locking scheme was chosen on the basis of
125 * manfred's recommendations and having no core impact whatsoever.
126 * -- wli
127 */
128DEFINE_SPINLOCK(pgd_lock);
129struct page *pgd_list;
130
131static inline void pgd_list_add(pgd_t *pgd)
132{
133 struct page *page = virt_to_page(pgd);
134 page->index = (unsigned long) pgd_list;
135 if (pgd_list)
136 set_page_private(pgd_list, (unsigned long) &page->index);
137 pgd_list = page;
138 set_page_private(page, (unsigned long) &pgd_list);
139}
140
141static inline void pgd_list_del(pgd_t *pgd)
142{
143 struct page *next, **pprev, *page = virt_to_page(pgd);
144 next = (struct page *) page->index;
145 pprev = (struct page **) page_private(page);
146 *pprev = next;
147 if (next)
148 set_page_private(next, (unsigned long) pprev);
149}
150
151void pgd_ctor(void *pgd)
152{
153 unsigned long flags;
154
155 if (PTRS_PER_PMD == 1)
156 spin_lock_irqsave(&pgd_lock, flags);
157
158 memcpy((pgd_t *)pgd + USER_PTRS_PER_PGD,
159 swapper_pg_dir + USER_PTRS_PER_PGD,
160 (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
161
162 if (PTRS_PER_PMD > 1)
163 return;
164
165 pgd_list_add(pgd);
166 spin_unlock_irqrestore(&pgd_lock, flags);
167 memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
168}
169
170/* never called when PTRS_PER_PMD > 1 */
171void pgd_dtor(void *pgd)
172{
173 unsigned long flags; /* can be called from interrupt context */
174
175 spin_lock_irqsave(&pgd_lock, flags);
176 pgd_list_del(pgd);
177 spin_unlock_irqrestore(&pgd_lock, flags);
178}
179
180pgd_t *pgd_alloc(struct mm_struct *mm)
181{
182 return quicklist_alloc(0, GFP_KERNEL, pgd_ctor);
183}
184
185void pgd_free(struct mm_struct *mm, pgd_t *pgd)
186{
187 quicklist_free(0, pgd_dtor, pgd);
188}
189
190void __init pgtable_cache_init(void)
191{
192}
193
194void check_pgt_cache(void)
195{
196 quicklist_trim(0, pgd_dtor, 25, 16);
197}
diff --git a/arch/mn10300/mm/tlb-mn10300.S b/arch/mn10300/mm/tlb-mn10300.S
new file mode 100644
index 000000000000..789208094e98
--- /dev/null
+++ b/arch/mn10300/mm/tlb-mn10300.S
@@ -0,0 +1,207 @@
1###############################################################################
2#
3# TLB loading functions
4#
5# Copyright (C) 2007 Matsushita Electric Industrial Co., Ltd.
6# Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
7# Modified by David Howells (dhowells@redhat.com)
8#
9# This program is free software; you can redistribute it and/or
10# modify it under the terms of the GNU General Public Licence
11# as published by the Free Software Foundation; either version
12# 2 of the Licence, or (at your option) any later version.
13#
14###############################################################################
15#include <linux/sys.h>
16#include <linux/linkage.h>
17#include <asm/smp.h>
18#include <asm/intctl-regs.h>
19#include <asm/frame.inc>
20#include <asm/page.h>
21#include <asm/pgtable.h>
22
23###############################################################################
24#
25# Instruction TLB Miss handler entry point
26#
27###############################################################################
28 .type itlb_miss,@function
29ENTRY(itlb_miss)
30 and ~EPSW_NMID,epsw
31#ifdef CONFIG_GDBSTUB
32 movm [d2,d3,a2],(sp)
33#else
34 or EPSW_nAR,epsw # switch D0-D3 & A0-A3 to the alternate
35 # register bank
36 nop
37 nop
38 nop
39#endif
40
41 mov (IPTEU),d3
42 mov (PTBR),a2
43 mov d3,d2
44 and 0xffc00000,d2
45 lsr 20,d2
46 mov (a2,d2),a2 # PTD *ptd = PGD[addr 31..22]
47 btst _PAGE_VALID,a2
48 beq itlb_miss_fault # jump if doesn't point anywhere
49
50 and ~(PAGE_SIZE-1),a2
51 mov d3,d2
52 and 0x003ff000,d2
53 lsr 10,d2
54 add d2,a2
55 mov (a2),d2 # get pte from PTD[addr 21..12]
56 btst _PAGE_VALID,d2
57 beq itlb_miss_fault # jump if doesn't point to a page
58 # (might be a swap id)
59 bset _PAGE_ACCESSED,(0,a2)
60 and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
61itlb_miss_set:
62 mov d2,(IPTEL) # change the TLB
63#ifdef CONFIG_GDBSTUB
64 movm (sp),[d2,d3,a2]
65#endif
66 rti
67
68itlb_miss_fault:
69 mov _PAGE_VALID,d2 # force address error handler to be
70 # invoked
71 bra itlb_miss_set
72
73 .size itlb_miss, . - itlb_miss
74
75###############################################################################
76#
77# Data TLB Miss handler entry point
78#
79###############################################################################
80 .type dtlb_miss,@function
81ENTRY(dtlb_miss)
82 and ~EPSW_NMID,epsw
83#ifdef CONFIG_GDBSTUB
84 movm [d2,d3,a2],(sp)
85#else
86 or EPSW_nAR,epsw # switch D0-D3 & A0-A3 to the alternate
87 # register bank
88 nop
89 nop
90 nop
91#endif
92
93 mov (DPTEU),d3
94 mov (PTBR),a2
95 mov d3,d2
96 and 0xffc00000,d2
97 lsr 20,d2
98 mov (a2,d2),a2 # PTD *ptd = PGD[addr 31..22]
99 btst _PAGE_VALID,a2
100 beq dtlb_miss_fault # jump if doesn't point anywhere
101
102 and ~(PAGE_SIZE-1),a2
103 mov d3,d2
104 and 0x003ff000,d2
105 lsr 10,d2
106 add d2,a2
107 mov (a2),d2 # get pte from PTD[addr 21..12]
108 btst _PAGE_VALID,d2
109 beq dtlb_miss_fault # jump if doesn't point to a page
110 # (might be a swap id)
111 bset _PAGE_ACCESSED,(0,a2)
112 and ~(xPTEL_UNUSED1|xPTEL_UNUSED2),d2
113dtlb_miss_set:
114 mov d2,(DPTEL) # change the TLB
115#ifdef CONFIG_GDBSTUB
116 movm (sp),[d2,d3,a2]
117#endif
118 rti
119
120dtlb_miss_fault:
121 mov _PAGE_VALID,d2 # force address error handler to be
122 # invoked
123 bra dtlb_miss_set
124 .size dtlb_miss, . - dtlb_miss
125
126###############################################################################
127#
128# Instruction TLB Address Error handler entry point
129#
130###############################################################################
131 .type itlb_aerror,@function
132ENTRY(itlb_aerror)
133 and ~EPSW_NMID,epsw
134 add -4,sp
135 SAVE_ALL
136 add -4,sp # need to pass three params
137
138 # calculate the fault code
139 movhu (MMUFCR_IFC),d1
140 or 0x00010000,d1 # it's an instruction fetch
141
142 # determine the page address
143 mov (IPTEU),a2
144 mov a2,d0
145 and PAGE_MASK,d0
146 mov d0,(12,sp)
147
148 clr d0
149 mov d0,(IPTEL)
150
151 and ~EPSW_NMID,epsw
152 or EPSW_IE,epsw
153 mov fp,d0
154 call do_page_fault[],0 # do_page_fault(regs,code,addr
155
156 jmp ret_from_exception
157 .size itlb_aerror, . - itlb_aerror
158
159###############################################################################
160#
161# Data TLB Address Error handler entry point
162#
163###############################################################################
164 .type dtlb_aerror,@function
165ENTRY(dtlb_aerror)
166 and ~EPSW_NMID,epsw
167 add -4,sp
168 mov d1,(sp)
169
170 movhu (MMUFCR_DFC),d1 # is it the initial valid write
171 # to this page?
172 and MMUFCR_xFC_INITWR,d1
173 beq dtlb_pagefault # jump if not
174
175 mov (DPTEL),d1 # set the dirty bit
176 # (don't replace with BSET!)
177 or _PAGE_DIRTY,d1
178 mov d1,(DPTEL)
179 mov (sp),d1
180 add 4,sp
181 rti
182
183 ALIGN
184dtlb_pagefault:
185 mov (sp),d1
186 SAVE_ALL
187 add -4,sp # need to pass three params
188
189 # calculate the fault code
190 movhu (MMUFCR_DFC),d1
191
192 # determine the page address
193 mov (DPTEU),a2
194 mov a2,d0
195 and PAGE_MASK,d0
196 mov d0,(12,sp)
197
198 clr d0
199 mov d0,(DPTEL)
200
201 and ~EPSW_NMID,epsw
202 or EPSW_IE,epsw
203 mov fp,d0
204 call do_page_fault[],0 # do_page_fault(regs,code,addr
205
206 jmp ret_from_exception
207 .size dtlb_aerror, . - dtlb_aerror
diff --git a/arch/mn10300/oprofile/Kconfig b/arch/mn10300/oprofile/Kconfig
new file mode 100644
index 000000000000..19d37730b664
--- /dev/null
+++ b/arch/mn10300/oprofile/Kconfig
@@ -0,0 +1,23 @@
1
2menu "Profiling support"
3 depends on EXPERIMENTAL
4
5config PROFILING
6 bool "Profiling support (EXPERIMENTAL)"
7 help
8 Say Y here to enable the extended profiling support mechanisms used
9 by profilers such as OProfile.
10
11
12config OPROFILE
13 tristate "OProfile system profiling (EXPERIMENTAL)"
14 depends on PROFILING
15 help
16 OProfile is a profiling system capable of profiling the
17 whole system, include the kernel, kernel modules, libraries,
18 and applications.
19
20 If unsure, say N.
21
22endmenu
23
diff --git a/arch/mn10300/oprofile/Makefile b/arch/mn10300/oprofile/Makefile
new file mode 100644
index 000000000000..918dbe60ebb6
--- /dev/null
+++ b/arch/mn10300/oprofile/Makefile
@@ -0,0 +1,13 @@
1#
2# Makefile for the MN10300-specific profiling code
3#
4obj-$(CONFIG_OPROFILE) += oprofile.o
5
6DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
7 oprof.o cpu_buffer.o buffer_sync.o \
8 event_buffer.o oprofile_files.o \
9 oprofilefs.o oprofile_stats.o \
10 timer_int.o )
11
12oprofile-y := $(DRIVER_OBJS) op_model_null.o
13
diff --git a/arch/mn10300/oprofile/op_model_null.c b/arch/mn10300/oprofile/op_model_null.c
new file mode 100644
index 000000000000..cd4ab374bc4f
--- /dev/null
+++ b/arch/mn10300/oprofile/op_model_null.c
@@ -0,0 +1,22 @@
1/* Null profiling driver
2 *
3 * Copyright (C) 2003 Paul Mundt
4 *
5 * This file is subject to the terms and conditions of the GNU General Public
6 * Licence. See the file "COPYING" in the main directory of this archive
7 * for more details.
8 */
9#include <linux/kernel.h>
10#include <linux/oprofile.h>
11#include <linux/init.h>
12#include <linux/errno.h>
13
14int __init oprofile_arch_init(struct oprofile_operations *ops)
15{
16 return -ENODEV;
17}
18
19void oprofile_arch_exit(void)
20{
21}
22
diff --git a/arch/mn10300/proc-mn103e010/Makefile b/arch/mn10300/proc-mn103e010/Makefile
new file mode 100644
index 000000000000..ac2c9784cd21
--- /dev/null
+++ b/arch/mn10300/proc-mn103e010/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the MN103E010 processor chip specific code
3#
4obj-y := proc-init.o
5
diff --git a/arch/mn10300/proc-mn103e010/proc-init.c b/arch/mn10300/proc-mn103e010/proc-init.c
new file mode 100644
index 000000000000..9a482efafa82
--- /dev/null
+++ b/arch/mn10300/proc-mn103e010/proc-init.c
@@ -0,0 +1,75 @@
1/* MN103E010 Processor initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <asm/rtc.h>
13
14/*
15 * initialise the on-silicon processor peripherals
16 */
17asmlinkage void __init processor_init(void)
18{
19 int loop;
20
21 /* set up the exception table first */
22 for (loop = 0x000; loop < 0x400; loop += 8)
23 __set_intr_stub(loop, __common_exception);
24
25 __set_intr_stub(EXCEP_ITLBMISS, itlb_miss);
26 __set_intr_stub(EXCEP_DTLBMISS, dtlb_miss);
27 __set_intr_stub(EXCEP_IAERROR, itlb_aerror);
28 __set_intr_stub(EXCEP_DAERROR, dtlb_aerror);
29 __set_intr_stub(EXCEP_BUSERROR, raw_bus_error);
30 __set_intr_stub(EXCEP_DOUBLE_FAULT, double_fault);
31 __set_intr_stub(EXCEP_SYSCALL0, system_call);
32
33 __set_intr_stub(EXCEP_NMI, nmi_handler);
34 __set_intr_stub(EXCEP_WDT, nmi_handler);
35 __set_intr_stub(EXCEP_IRQ_LEVEL0, irq_handler);
36 __set_intr_stub(EXCEP_IRQ_LEVEL1, irq_handler);
37 __set_intr_stub(EXCEP_IRQ_LEVEL2, irq_handler);
38 __set_intr_stub(EXCEP_IRQ_LEVEL3, irq_handler);
39 __set_intr_stub(EXCEP_IRQ_LEVEL4, irq_handler);
40 __set_intr_stub(EXCEP_IRQ_LEVEL5, irq_handler);
41 __set_intr_stub(EXCEP_IRQ_LEVEL6, irq_handler);
42
43 IVAR0 = EXCEP_IRQ_LEVEL0;
44 IVAR1 = EXCEP_IRQ_LEVEL1;
45 IVAR2 = EXCEP_IRQ_LEVEL2;
46 IVAR3 = EXCEP_IRQ_LEVEL3;
47 IVAR4 = EXCEP_IRQ_LEVEL4;
48 IVAR5 = EXCEP_IRQ_LEVEL5;
49 IVAR6 = EXCEP_IRQ_LEVEL6;
50
51 mn10300_dcache_flush_inv();
52 mn10300_icache_inv();
53
54 /* disable all interrupts and set to priority 6 (lowest) */
55 for (loop = 0; loop < NR_IRQS; loop++)
56 GxICR(loop) = GxICR_LEVEL_6 | GxICR_DETECT;
57
58 /* clear the timers */
59 TM0MD = 0;
60 TM1MD = 0;
61 TM2MD = 0;
62 TM3MD = 0;
63 TM4MD = 0;
64 TM5MD = 0;
65 TM6MD = 0;
66 TM6MDA = 0;
67 TM6MDB = 0;
68 TM7MD = 0;
69 TM8MD = 0;
70 TM9MD = 0;
71 TM10MD = 0;
72 TM11MD = 0;
73
74 calibrate_clock();
75}
diff --git a/arch/mn10300/unit-asb2303/Makefile b/arch/mn10300/unit-asb2303/Makefile
new file mode 100644
index 000000000000..03e579fa99d0
--- /dev/null
+++ b/arch/mn10300/unit-asb2303/Makefile
@@ -0,0 +1,6 @@
1###############################################################################
2#
3# Makefile for the ASB2303 board
4#
5###############################################################################
6obj-y := unit-init.o smc91111.o leds.o
diff --git a/arch/mn10300/unit-asb2303/leds.c b/arch/mn10300/unit-asb2303/leds.c
new file mode 100644
index 000000000000..cd4bc78ccfc8
--- /dev/null
+++ b/arch/mn10300/unit-asb2303/leds.c
@@ -0,0 +1,52 @@
1/* ASB2303 peripheral 7-segment LEDs x1 support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/init.h>
14
15#include <asm/io.h>
16#include <asm/processor.h>
17#include <asm/intctl-regs.h>
18#include <asm/rtc-regs.h>
19#include <asm/unit/leds.h>
20
21#if 0
22static const u8 asb2303_led_hex_tbl[16] = {
23 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0,
24 0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c
25};
26#endif
27
28static const u8 asb2303_led_chase_tbl[6] = {
29 ~0x02, /* top - segA */
30 ~0x04, /* right top - segB */
31 ~0x08, /* right bottom - segC */
32 ~0x10, /* bottom - segD */
33 ~0x20, /* left bottom - segE */
34 ~0x40, /* left top - segF */
35};
36
37static unsigned asb2303_led_chase;
38
39void peripheral_leds_display_exception(enum exception_code code)
40{
41 ASB2303_GPIO0DEF = 0x5555; /* configure as an output port */
42 ASB2303_7SEGLEDS = 0x6d; /* triple horizontal bar */
43}
44
45void peripheral_leds_led_chase(void)
46{
47 ASB2303_GPIO0DEF = 0x5555; /* configure as an output port */
48 ASB2303_7SEGLEDS = asb2303_led_chase_tbl[asb2303_led_chase];
49 asb2303_led_chase++;
50 if (asb2303_led_chase >= 6)
51 asb2303_led_chase = 0;
52}
diff --git a/arch/mn10300/unit-asb2303/smc91111.c b/arch/mn10300/unit-asb2303/smc91111.c
new file mode 100644
index 000000000000..30875dd65631
--- /dev/null
+++ b/arch/mn10300/unit-asb2303/smc91111.c
@@ -0,0 +1,52 @@
1/* ASB2303 initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/param.h>
14#include <linux/init.h>
15#include <linux/platform_device.h>
16
17#include <asm/io.h>
18#include <asm/timex.h>
19#include <asm/processor.h>
20#include <asm/intctl-regs.h>
21#include <asm/unit/smc91111.h>
22
23static struct resource smc91c111_resources[] = {
24 [0] = {
25 .start = SMC91111_BASE,
26 .end = SMC91111_BASE_END,
27 .flags = IORESOURCE_MEM,
28 },
29 [1] = {
30 .start = SMC91111_IRQ,
31 .end = SMC91111_IRQ,
32 .flags = IORESOURCE_IRQ,
33 },
34};
35
36static struct platform_device smc91c111_device = {
37 .name = "smc91x",
38 .id = 0,
39 .num_resources = ARRAY_SIZE(smc91c111_resources),
40 .resource = smc91c111_resources,
41};
42
43/*
44 * add platform devices
45 */
46static int __init unit_device_init(void)
47{
48 platform_device_register(&smc91c111_device);
49 return 0;
50}
51
52device_initcall(unit_device_init);
diff --git a/arch/mn10300/unit-asb2303/unit-init.c b/arch/mn10300/unit-asb2303/unit-init.c
new file mode 100644
index 000000000000..14b2c817cff8
--- /dev/null
+++ b/arch/mn10300/unit-asb2303/unit-init.c
@@ -0,0 +1,60 @@
1/* ASB2303 initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11
12#include <linux/kernel.h>
13#include <linux/param.h>
14#include <linux/init.h>
15#include <linux/device.h>
16
17#include <asm/io.h>
18#include <asm/setup.h>
19#include <asm/processor.h>
20#include <asm/irq.h>
21#include <asm/intctl-regs.h>
22
23/*
24 * initialise some of the unit hardware before gdbstub is set up
25 */
26asmlinkage void __init unit_init(void)
27{
28 /* set up the external interrupts */
29 SET_XIRQ_TRIGGER(0, XIRQ_TRIGGER_HILEVEL);
30 SET_XIRQ_TRIGGER(2, XIRQ_TRIGGER_LOWLEVEL);
31 SET_XIRQ_TRIGGER(3, XIRQ_TRIGGER_HILEVEL);
32 SET_XIRQ_TRIGGER(4, XIRQ_TRIGGER_LOWLEVEL);
33 SET_XIRQ_TRIGGER(5, XIRQ_TRIGGER_LOWLEVEL);
34}
35
36/*
37 * initialise the rest of the unit hardware after gdbstub is ready
38 */
39void __init unit_setup(void)
40{
41}
42
43/*
44 * initialise the external interrupts used by a unit of this type
45 */
46void __init unit_init_IRQ(void)
47{
48 unsigned int extnum;
49
50 for (extnum = 0; extnum < NR_XIRQS; extnum++) {
51 switch (GET_XIRQ_TRIGGER(extnum)) {
52 case XIRQ_TRIGGER_HILEVEL:
53 case XIRQ_TRIGGER_LOWLEVEL:
54 set_irq_handler(XIRQ2IRQ(extnum), handle_level_irq);
55 break;
56 default:
57 break;
58 }
59 }
60}
diff --git a/arch/mn10300/unit-asb2305/Makefile b/arch/mn10300/unit-asb2305/Makefile
new file mode 100644
index 000000000000..0551022225b3
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/Makefile
@@ -0,0 +1,8 @@
1###############################################################################
2#
3# Makefile for the ASB2305 board
4#
5###############################################################################
6obj-y := unit-init.o leds.o
7
8obj-$(CONFIG_PCI) += pci.o pci-asb2305.o pci-irq.o pci-iomap.o
diff --git a/arch/mn10300/unit-asb2305/leds.c b/arch/mn10300/unit-asb2305/leds.c
new file mode 100644
index 000000000000..e99dcc9cee1a
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/leds.c
@@ -0,0 +1,124 @@
1/* ASB2305 Peripheral 7-segment LEDs x4 support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/init.h>
14#include <asm/io.h>
15#include <asm/processor.h>
16#include <asm/cpu/intctl-regs.h>
17#include <asm/cpu/rtc-regs.h>
18#include <asm/unit/leds.h>
19
20static const u8 asb2305_led_hex_tbl[16] = {
21 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0,
22 0x00, 0x20, 0x10, 0x06, 0x8c, 0x42, 0x0c, 0x1c
23};
24
25static const u32 asb2305_led_chase_tbl[6] = {
26 ~0x02020202, /* top - segA */
27 ~0x04040404, /* right top - segB */
28 ~0x08080808, /* right bottom - segC */
29 ~0x10101010, /* bottom - segD */
30 ~0x20202020, /* left bottom - segE */
31 ~0x40404040, /* left top - segF */
32};
33
34static unsigned asb2305_led_chase;
35
36void peripheral_leds7x4_display_dec(unsigned int val, unsigned int points)
37{
38 u32 leds;
39
40 leds = asb2305_led_hex_tbl[(val/1000) % 10];
41 leds <<= 8;
42 leds |= asb2305_led_hex_tbl[(val/100) % 10];
43 leds <<= 8;
44 leds |= asb2305_led_hex_tbl[(val/10) % 10];
45 leds <<= 8;
46 leds |= asb2305_led_hex_tbl[val % 10];
47 leds |= points^0x01010101;
48
49 ASB2305_7SEGLEDS = leds;
50}
51
52void peripheral_leds7x4_display_hex(unsigned int val, unsigned int points)
53{
54 u32 leds;
55
56 leds = asb2305_led_hex_tbl[(val/1000) % 10];
57 leds <<= 8;
58 leds |= asb2305_led_hex_tbl[(val/100) % 10];
59 leds <<= 8;
60 leds |= asb2305_led_hex_tbl[(val/10) % 10];
61 leds <<= 8;
62 leds |= asb2305_led_hex_tbl[val % 10];
63 leds |= points^0x01010101;
64
65 ASB2305_7SEGLEDS = leds;
66}
67
68void peripheral_leds_display_exception(enum exception_code code)
69{
70 u32 leds;
71
72 leds = asb2305_led_hex_tbl[(code/0x100) % 0x10];
73 leds <<= 8;
74 leds |= asb2305_led_hex_tbl[(code/0x10) % 0x10];
75 leds <<= 8;
76 leds |= asb2305_led_hex_tbl[code % 0x10];
77 leds |= 0x6d010101;
78
79 ASB2305_7SEGLEDS = leds;
80}
81
82void peripheral_leds7x4_display_minssecs(unsigned int time, unsigned int points)
83{
84 u32 leds;
85
86 leds = asb2305_led_hex_tbl[(time/600) % 6];
87 leds <<= 8;
88 leds |= asb2305_led_hex_tbl[(time/60) % 10];
89 leds <<= 8;
90 leds |= asb2305_led_hex_tbl[(time/10) % 6];
91 leds <<= 8;
92 leds |= asb2305_led_hex_tbl[time % 10];
93 leds |= points^0x01010101;
94
95 ASB2305_7SEGLEDS = leds;
96}
97
98void peripheral_leds7x4_display_rtc(void)
99{
100 unsigned int clock;
101 u8 mins, secs;
102
103 mins = RTMCR;
104 secs = RTSCR;
105
106 clock = ((mins & 0xf0) >> 4);
107 clock *= 10;
108 clock += (mins & 0x0f);
109 clock *= 6;
110
111 clock += ((secs & 0xf0) >> 4);
112 clock *= 10;
113 clock += (secs & 0x0f);
114
115 peripheral_leds7x4_display_minssecs(clock, 0);
116}
117
118void peripheral_leds_led_chase(void)
119{
120 ASB2305_7SEGLEDS = asb2305_led_chase_tbl[asb2305_led_chase];
121 asb2305_led_chase++;
122 if (asb2305_led_chase >= 6)
123 asb2305_led_chase = 0;
124}
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.c b/arch/mn10300/unit-asb2305/pci-asb2305.c
new file mode 100644
index 000000000000..d100ca788468
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.c
@@ -0,0 +1,303 @@
1/* ASB2305 PCI resource stuff
2 *
3 * Copyright (C) 2001 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * - Derived from arch/i386/pci-i386.c
6 * - Copyright 1997--2000 Martin Mares <mj@suse.cz>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public Licence
10 * as published by the Free Software Foundation; either version
11 * 2 of the Licence, or (at your option) any later version.
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/pci.h>
16#include <linux/init.h>
17#include <linux/ioport.h>
18#include <linux/errno.h>
19#include "pci-asb2305.h"
20
21/*
22 * We need to avoid collisions with `mirrored' VGA ports
23 * and other strange ISA hardware, so we always want the
24 * addresses to be allocated in the 0x000-0x0ff region
25 * modulo 0x400.
26 *
27 * Why? Because some silly external IO cards only decode
28 * the low 10 bits of the IO address. The 0x00-0xff region
29 * is reserved for motherboard devices that decode all 16
30 * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
31 * but we want to try to avoid allocating at 0x2900-0x2bff
32 * which might have be mirrored at 0x0100-0x03ff..
33 */
34void pcibios_align_resource(void *data, struct resource *res,
35 resource_size_t size, resource_size_t align)
36{
37#if 0
38 struct pci_dev *dev = data;
39
40 printk(KERN_DEBUG
41 "### PCIBIOS_ALIGN_RESOURCE(%s,,{%08lx-%08lx,%08lx},%lx)\n",
42 pci_name(dev),
43 res->start,
44 res->end,
45 res->flags,
46 size
47 );
48#endif
49
50 if (res->flags & IORESOURCE_IO) {
51 unsigned long start = res->start;
52
53 if (start & 0x300) {
54 start = (start + 0x3ff) & ~0x3ff;
55 res->start = start;
56 }
57 }
58}
59
60
61/*
62 * Handle resources of PCI devices. If the world were perfect, we could
63 * just allocate all the resource regions and do nothing more. It isn't.
64 * On the other hand, we cannot just re-allocate all devices, as it would
65 * require us to know lots of host bridge internals. So we attempt to
66 * keep as much of the original configuration as possible, but tweak it
67 * when it's found to be wrong.
68 *
69 * Known BIOS problems we have to work around:
70 * - I/O or memory regions not configured
71 * - regions configured, but not enabled in the command register
72 * - bogus I/O addresses above 64K used
73 * - expansion ROMs left enabled (this may sound harmless, but given
74 * the fact the PCI specs explicitly allow address decoders to be
75 * shared between expansion ROMs and other resource regions, it's
76 * at least dangerous)
77 *
78 * Our solution:
79 * (1) Allocate resources for all buses behind PCI-to-PCI bridges.
80 * This gives us fixed barriers on where we can allocate.
81 * (2) Allocate resources for all enabled devices. If there is
82 * a collision, just mark the resource as unallocated. Also
83 * disable expansion ROMs during this step.
84 * (3) Try to allocate resources for disabled devices. If the
85 * resources were assigned correctly, everything goes well,
86 * if they weren't, they won't disturb allocation of other
87 * resources.
88 * (4) Assign new addresses to resources which were either
89 * not configured at all or misconfigured. If explicitly
90 * requested by the user, configure expansion ROM address
91 * as well.
92 */
93static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
94{
95 struct pci_bus *bus;
96 struct pci_dev *dev;
97 int idx;
98 struct resource *r, *pr;
99
100 /* Depth-First Search on bus tree */
101 list_for_each_entry(bus, bus_list, node) {
102 dev = bus->self;
103 if (dev) {
104 for (idx = PCI_BRIDGE_RESOURCES;
105 idx < PCI_NUM_RESOURCES;
106 idx++) {
107 r = &dev->resource[idx];
108 if (!r->flags)
109 continue;
110 pr = pci_find_parent_resource(dev, r);
111 if (!r->start ||
112 !pr ||
113 request_resource(pr, r) < 0) {
114 printk(KERN_ERR "PCI:"
115 " Cannot allocate resource"
116 " region %d of bridge %s\n",
117 idx, pci_name(dev));
118 /* Something is wrong with the region.
119 * Invalidate the resource to prevent
120 * child resource allocations in this
121 * range. */
122 r->flags = 0;
123 }
124 }
125 }
126 pcibios_allocate_bus_resources(&bus->children);
127 }
128}
129
130static void __init pcibios_allocate_resources(int pass)
131{
132 struct pci_dev *dev = NULL;
133 int idx, disabled;
134 u16 command;
135 struct resource *r, *pr;
136
137 for_each_pci_dev(dev) {
138 pci_read_config_word(dev, PCI_COMMAND, &command);
139 for (idx = 0; idx < 6; idx++) {
140 r = &dev->resource[idx];
141 if (r->parent) /* Already allocated */
142 continue;
143 if (!r->start) /* Address not assigned */
144 continue;
145 if (r->flags & IORESOURCE_IO)
146 disabled = !(command & PCI_COMMAND_IO);
147 else
148 disabled = !(command & PCI_COMMAND_MEMORY);
149 if (pass == disabled) {
150 DBG("PCI[%s]: Resource %08lx-%08lx"
151 " (f=%lx, d=%d, p=%d)\n",
152 pci_name(dev), r->start, r->end, r->flags,
153 disabled, pass);
154 pr = pci_find_parent_resource(dev, r);
155 if (!pr || request_resource(pr, r) < 0) {
156 printk(KERN_ERR "PCI:"
157 " Cannot allocate resource"
158 " region %d of device %s\n",
159 idx, pci_name(dev));
160 /* We'll assign a new address later */
161 r->end -= r->start;
162 r->start = 0;
163 }
164 }
165 }
166 if (!pass) {
167 r = &dev->resource[PCI_ROM_RESOURCE];
168 if (r->flags & IORESOURCE_ROM_ENABLE) {
169 /* Turn the ROM off, leave the resource region,
170 * but keep it unregistered. */
171 u32 reg;
172 DBG("PCI: Switching off ROM of %s\n",
173 pci_name(dev));
174 r->flags &= ~IORESOURCE_ROM_ENABLE;
175 pci_read_config_dword(
176 dev, dev->rom_base_reg, &reg);
177 pci_write_config_dword(
178 dev, dev->rom_base_reg,
179 reg & ~PCI_ROM_ADDRESS_ENABLE);
180 }
181 }
182 }
183}
184
185static int __init pcibios_assign_resources(void)
186{
187 struct pci_dev *dev = NULL;
188 struct resource *r, *pr;
189
190 if (!(pci_probe & PCI_ASSIGN_ROMS)) {
191 /* Try to use BIOS settings for ROMs, otherwise let
192 pci_assign_unassigned_resources() allocate the new
193 addresses. */
194 for_each_pci_dev(dev) {
195 r = &dev->resource[PCI_ROM_RESOURCE];
196 if (!r->flags || !r->start)
197 continue;
198 pr = pci_find_parent_resource(dev, r);
199 if (!pr || request_resource(pr, r) < 0) {
200 r->end -= r->start;
201 r->start = 0;
202 }
203 }
204 }
205
206 pci_assign_unassigned_resources();
207
208 return 0;
209}
210
211fs_initcall(pcibios_assign_resources);
212
213void __init pcibios_resource_survey(void)
214{
215 DBG("PCI: Allocating resources\n");
216 pcibios_allocate_bus_resources(&pci_root_buses);
217 pcibios_allocate_resources(0);
218 pcibios_allocate_resources(1);
219}
220
221int pcibios_enable_resources(struct pci_dev *dev, int mask)
222{
223 u16 cmd, old_cmd;
224 int idx;
225 struct resource *r;
226
227 pci_read_config_word(dev, PCI_COMMAND, &cmd);
228 old_cmd = cmd;
229
230 for (idx = 0; idx < 6; idx++) {
231 /* Only set up the requested stuff */
232 if (!(mask & (1 << idx)))
233 continue;
234
235 r = &dev->resource[idx];
236
237 if (!r->start && r->end) {
238 printk(KERN_ERR
239 "PCI: Device %s not available because of"
240 " resource collisions\n",
241 pci_name(dev));
242 return -EINVAL;
243 }
244
245 if (r->flags & IORESOURCE_IO)
246 cmd |= PCI_COMMAND_IO;
247 if (r->flags & IORESOURCE_MEM)
248 cmd |= PCI_COMMAND_MEMORY;
249 }
250
251 if (dev->resource[PCI_ROM_RESOURCE].start)
252 cmd |= PCI_COMMAND_MEMORY;
253
254 if (cmd != old_cmd)
255 pci_write_config_word(dev, PCI_COMMAND, cmd);
256
257 return 0;
258}
259
260/*
261 * If we set up a device for bus mastering, we need to check the latency
262 * timer as certain crappy BIOSes forget to set it properly.
263 */
264unsigned int pcibios_max_latency = 255;
265
266void pcibios_set_master(struct pci_dev *dev)
267{
268 u8 lat;
269
270 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
271
272 if (lat < 16)
273 lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
274 else if (lat > pcibios_max_latency)
275 lat = pcibios_max_latency;
276 else
277 return;
278
279 pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
280}
281
282int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
283 enum pci_mmap_state mmap_state, int write_combine)
284{
285 unsigned long prot;
286
287 /* Leave vm_pgoff as-is, the PCI space address is the physical
288 * address on this platform.
289 */
290 vma->vm_flags |= VM_LOCKED | VM_IO;
291
292 prot = pgprot_val(vma->vm_page_prot);
293 prot &= ~_PAGE_CACHE;
294 vma->vm_page_prot = __pgprot(prot);
295
296 /* Write-combine setting is ignored */
297 if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
298 vma->vm_end - vma->vm_start,
299 vma->vm_page_prot))
300 return -EAGAIN;
301
302 return 0;
303}
diff --git a/arch/mn10300/unit-asb2305/pci-asb2305.h b/arch/mn10300/unit-asb2305/pci-asb2305.h
new file mode 100644
index 000000000000..84634fa3bce6
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-asb2305.h
@@ -0,0 +1,82 @@
1/* ASB2305 Arch-specific PCI declarations
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * Derived from: arch/i386/kernel/pci-i386.h: (c) 1999 Martin Mares <mj@ucw.cz>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public Licence
9 * as published by the Free Software Foundation; either version
10 * 2 of the Licence, or (at your option) any later version.
11 */
12#ifndef _PCI_ASB2305_H
13#define _PCI_ASB2305_H
14
15#undef DEBUG
16
17#ifdef DEBUG
18#define DBG(x...) printk(x)
19#else
20#define DBG(x...)
21#endif
22
23#define PCI_PROBE_BIOS 1
24#define PCI_PROBE_CONF1 2
25#define PCI_PROBE_CONF2 4
26#define PCI_NO_SORT 0x100
27#define PCI_BIOS_SORT 0x200
28#define PCI_NO_CHECKS 0x400
29#define PCI_ASSIGN_ROMS 0x1000
30#define PCI_BIOS_IRQ_SCAN 0x2000
31
32extern unsigned int pci_probe;
33
34/* pci-asb2305.c */
35
36extern unsigned int pcibios_max_latency;
37
38extern void pcibios_resource_survey(void);
39extern int pcibios_enable_resources(struct pci_dev *dev, int mask);
40
41/* pci.c */
42
43extern int pcibios_last_bus;
44extern struct pci_bus *pci_root_bus;
45extern struct pci_ops *pci_root_ops;
46
47extern struct irq_routing_table *pcibios_get_irq_routing_table(void);
48extern int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
49
50/* pci-irq.c */
51
52struct irq_info {
53 u8 bus, devfn; /* Bus, device and function */
54 struct {
55 u8 link; /* IRQ line ID, chipset dependent,
56 * 0=not routed */
57 u16 bitmap; /* Available IRQs */
58 } __attribute__((packed)) irq[4];
59 u8 slot; /* Slot number, 0=onboard */
60 u8 rfu;
61} __attribute__((packed));
62
63struct irq_routing_table {
64 u32 signature; /* PIRQ_SIGNATURE should be here */
65 u16 version; /* PIRQ_VERSION */
66 u16 size; /* Table size in bytes */
67 u8 rtr_bus, rtr_devfn; /* Where the interrupt router lies */
68 u16 exclusive_irqs; /* IRQs devoted exclusively to PCI usage */
69 u16 rtr_vendor, rtr_device; /* Vendor and device ID of interrupt router */
70 u32 miniport_data; /* Crap */
71 u8 rfu[11];
72 u8 checksum; /* Modulo 256 checksum must give zero */
73 struct irq_info slots[0];
74} __attribute__((packed));
75
76extern unsigned int pcibios_irq_mask;
77
78extern void pcibios_irq_init(void);
79extern void pcibios_fixup_irqs(void);
80extern void pcibios_enable_irq(struct pci_dev *dev);
81
82#endif /* PCI_ASB2305_H */
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c
new file mode 100644
index 000000000000..dbceae4307da
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-iomap.c
@@ -0,0 +1,31 @@
1/* ASB2305 PCI I/O mapping handler
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/pci.h>
12#include <linux/module.h>
13
14/*
15 * Create a virtual mapping cookie for a PCI BAR (memory or IO)
16 */
17void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
18{
19 unsigned long start = pci_resource_start(dev, bar);
20 unsigned long len = pci_resource_len(dev, bar);
21 unsigned long flags = pci_resource_flags(dev, bar);
22
23 if (!len || !start)
24 return NULL;
25
26 if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM))
27 return (void __iomem *) start;
28
29 return NULL;
30}
31EXPORT_SYMBOL(pci_iomap);
diff --git a/arch/mn10300/unit-asb2305/pci-irq.c b/arch/mn10300/unit-asb2305/pci-irq.c
new file mode 100644
index 000000000000..58cfb44f0acf
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci-irq.c
@@ -0,0 +1,51 @@
1/* PCI IRQ routing on the MN103E010 based ASB2305
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 *
11 * This is simple: All PCI interrupts route through the CPU's XIRQ1 pin [IRQ 35]
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/pci.h>
16#include <linux/init.h>
17#include <linux/slab.h>
18#include <linux/interrupt.h>
19#include <linux/irq.h>
20#include <asm/io.h>
21#include <asm/smp.h>
22#include "pci-asb2305.h"
23
24void __init pcibios_irq_init(void)
25{
26}
27
28void __init pcibios_fixup_irqs(void)
29{
30 struct pci_dev *dev = NULL;
31 u8 line, pin;
32
33 while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
34 pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
35 if (pin) {
36 dev->irq = XIRQ1;
37 pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
38 dev->irq);
39 }
40 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
41 }
42}
43
44void __init pcibios_penalize_isa_irq(int irq)
45{
46}
47
48void pcibios_enable_irq(struct pci_dev *dev)
49{
50 pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
51}
diff --git a/arch/mn10300/unit-asb2305/pci.c b/arch/mn10300/unit-asb2305/pci.c
new file mode 100644
index 000000000000..1a86425fec42
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/pci.c
@@ -0,0 +1,545 @@
1/* ASB2305 PCI support
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 * Derived from arch/i386/kernel/pci-pc.c
6 * (c) 1999--2000 Martin Mares <mj@suse.cz>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public Licence
10 * as published by the Free Software Foundation; either version
11 * 2 of the Licence, or (at your option) any later version.
12 */
13#include <linux/types.h>
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <linux/pci.h>
17#include <linux/init.h>
18#include <linux/ioport.h>
19#include <linux/delay.h>
20#include <asm/io.h>
21#include "pci-asb2305.h"
22
23unsigned int pci_probe = 1;
24
25int pcibios_last_bus = -1;
26struct pci_bus *pci_root_bus;
27struct pci_ops *pci_root_ops;
28
29/*
30 * Functions for accessing PCI configuration space
31 */
32
33#define CONFIG_CMD(bus, devfn, where) \
34 (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
35
36#define MEM_PAGING_REG (*(volatile __u32 *) 0xBFFFFFF4)
37#define CONFIG_ADDRESS (*(volatile __u32 *) 0xBFFFFFF8)
38#define CONFIG_DATAL(X) (*(volatile __u32 *) 0xBFFFFFFC)
39#define CONFIG_DATAW(X) (*(volatile __u16 *) (0xBFFFFFFC + ((X) & 2)))
40#define CONFIG_DATAB(X) (*(volatile __u8 *) (0xBFFFFFFC + ((X) & 3)))
41
42#define BRIDGEREGB(X) (*(volatile __u8 *) (0xBE040000 + (X)))
43#define BRIDGEREGW(X) (*(volatile __u16 *) (0xBE040000 + (X)))
44#define BRIDGEREGL(X) (*(volatile __u32 *) (0xBE040000 + (X)))
45
46static inline int __query(const struct pci_bus *bus, unsigned int devfn)
47{
48#if 0
49 return bus->number == 0 && (devfn == PCI_DEVFN(0, 0));
50 return bus->number == 1;
51 return bus->number == 0 &&
52 (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(3, 0));
53#endif
54 return 1;
55}
56
57/*
58 * translate Linuxcentric addresses to PCI bus addresses
59 */
60void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
61 struct resource *res)
62{
63 if (res->flags & IORESOURCE_IO) {
64 region->start = (res->start & 0x00ffffff);
65 region->end = (res->end & 0x00ffffff);
66 }
67
68 if (res->flags & IORESOURCE_MEM) {
69 region->start = (res->start & 0x03ffffff) | MEM_PAGING_REG;
70 region->end = (res->end & 0x03ffffff) | MEM_PAGING_REG;
71 }
72
73#if 0
74 printk(KERN_DEBUG "RES->BUS: %lx-%lx => %lx-%lx\n",
75 res->start, res->end, region->start, region->end);
76#endif
77}
78EXPORT_SYMBOL(pcibios_resource_to_bus);
79
80/*
81 * translate PCI bus addresses to Linuxcentric addresses
82 */
83void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
84 struct pci_bus_region *region)
85{
86 if (res->flags & IORESOURCE_IO) {
87 res->start = (region->start & 0x00ffffff) | 0xbe000000;
88 res->end = (region->end & 0x00ffffff) | 0xbe000000;
89 }
90
91 if (res->flags & IORESOURCE_MEM) {
92 res->start = (region->start & 0x03ffffff) | 0xb8000000;
93 res->end = (region->end & 0x03ffffff) | 0xb8000000;
94 }
95
96#if 0
97 printk(KERN_INFO "BUS->RES: %lx-%lx => %lx-%lx\n",
98 region->start, region->end, res->start, res->end);
99#endif
100}
101EXPORT_SYMBOL(pcibios_bus_to_resource);
102
103/*
104 *
105 */
106static int pci_ampci_read_config_byte(struct pci_bus *bus, unsigned int devfn,
107 int where, u32 *_value)
108{
109 u32 rawval, value;
110
111 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
112 value = BRIDGEREGB(where);
113 __pcbdebug("=> %02hx", &BRIDGEREGL(where), value);
114 } else {
115 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
116 rawval = CONFIG_ADDRESS;
117 value = CONFIG_DATAB(where);
118 if (__query(bus, devfn))
119 __pcidebug("=> %02hx", bus, devfn, where, value);
120 }
121
122 *_value = value;
123 return PCIBIOS_SUCCESSFUL;
124}
125
126static int pci_ampci_read_config_word(struct pci_bus *bus, unsigned int devfn,
127 int where, u32 *_value)
128{
129 u32 rawval, value;
130
131 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
132 value = BRIDGEREGW(where);
133 __pcbdebug("=> %04hx", &BRIDGEREGL(where), value);
134 } else {
135 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
136 rawval = CONFIG_ADDRESS;
137 value = CONFIG_DATAW(where);
138 if (__query(bus, devfn))
139 __pcidebug("=> %04hx", bus, devfn, where, value);
140 }
141
142 *_value = value;
143 return PCIBIOS_SUCCESSFUL;
144}
145
146static int pci_ampci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
147 int where, u32 *_value)
148{
149 u32 rawval, value;
150
151 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
152 value = BRIDGEREGL(where);
153 __pcbdebug("=> %08x", &BRIDGEREGL(where), value);
154 } else {
155 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
156 rawval = CONFIG_ADDRESS;
157 value = CONFIG_DATAL(where);
158 if (__query(bus, devfn))
159 __pcidebug("=> %08x", bus, devfn, where, value);
160 }
161
162 *_value = value;
163 return PCIBIOS_SUCCESSFUL;
164}
165
166static int pci_ampci_write_config_byte(struct pci_bus *bus, unsigned int devfn,
167 int where, u8 value)
168{
169 u32 rawval;
170
171 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
172 __pcbdebug("<= %02x", &BRIDGEREGB(where), value);
173 BRIDGEREGB(where) = value;
174 } else {
175 if (bus->number == 0 &&
176 (devfn == PCI_DEVFN(2, 0) && devfn == PCI_DEVFN(3, 0))
177 )
178 __pcidebug("<= %02x", bus, devfn, where, value);
179 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
180 rawval = CONFIG_ADDRESS;
181 CONFIG_DATAB(where) = value;
182 }
183 return PCIBIOS_SUCCESSFUL;
184}
185
186static int pci_ampci_write_config_word(struct pci_bus *bus, unsigned int devfn,
187 int where, u16 value)
188{
189 u32 rawval;
190
191 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
192 __pcbdebug("<= %04hx", &BRIDGEREGW(where), value);
193 BRIDGEREGW(where) = value;
194 } else {
195 if (__query(bus, devfn))
196 __pcidebug("<= %04hx", bus, devfn, where, value);
197 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
198 rawval = CONFIG_ADDRESS;
199 CONFIG_DATAW(where) = value;
200 }
201 return PCIBIOS_SUCCESSFUL;
202}
203
204static int pci_ampci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
205 int where, u32 value)
206{
207 u32 rawval;
208
209 if (bus->number == 0 && devfn == PCI_DEVFN(0, 0)) {
210 __pcbdebug("<= %08x", &BRIDGEREGL(where), value);
211 BRIDGEREGL(where) = value;
212 } else {
213 if (__query(bus, devfn))
214 __pcidebug("<= %08x", bus, devfn, where, value);
215 CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
216 rawval = CONFIG_ADDRESS;
217 CONFIG_DATAL(where) = value;
218 }
219 return PCIBIOS_SUCCESSFUL;
220}
221
222static int pci_ampci_read_config(struct pci_bus *bus, unsigned int devfn,
223 int where, int size, u32 *val)
224{
225 switch (size) {
226 case 1:
227 return pci_ampci_read_config_byte(bus, devfn, where, val);
228 case 2:
229 return pci_ampci_read_config_word(bus, devfn, where, val);
230 case 4:
231 return pci_ampci_read_config_dword(bus, devfn, where, val);
232 default:
233 BUG();
234 return -EOPNOTSUPP;
235 }
236}
237
238static int pci_ampci_write_config(struct pci_bus *bus, unsigned int devfn,
239 int where, int size, u32 val)
240{
241 switch (size) {
242 case 1:
243 return pci_ampci_write_config_byte(bus, devfn, where, val);
244 case 2:
245 return pci_ampci_write_config_word(bus, devfn, where, val);
246 case 4:
247 return pci_ampci_write_config_dword(bus, devfn, where, val);
248 default:
249 BUG();
250 return -EOPNOTSUPP;
251 }
252}
253
254static struct pci_ops pci_direct_ampci = {
255 pci_ampci_read_config,
256 pci_ampci_write_config,
257};
258
259/*
260 * Before we decide to use direct hardware access mechanisms, we try to do some
261 * trivial checks to ensure it at least _seems_ to be working -- we just test
262 * whether bus 00 contains a host bridge (this is similar to checking
263 * techniques used in XFree86, but ours should be more reliable since we
264 * attempt to make use of direct access hints provided by the PCI BIOS).
265 *
266 * This should be close to trivial, but it isn't, because there are buggy
267 * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID.
268 */
269static int __init pci_sanity_check(struct pci_ops *o)
270{
271 struct pci_bus bus; /* Fake bus and device */
272 u32 x;
273
274 bus.number = 0;
275
276 if ((!o->read(&bus, 0, PCI_CLASS_DEVICE, 2, &x) &&
277 (x == PCI_CLASS_BRIDGE_HOST || x == PCI_CLASS_DISPLAY_VGA)) ||
278 (!o->read(&bus, 0, PCI_VENDOR_ID, 2, &x) &&
279 (x == PCI_VENDOR_ID_INTEL || x == PCI_VENDOR_ID_COMPAQ)))
280 return 1;
281
282 printk(KERN_ERROR "PCI: Sanity check failed\n");
283 return 0;
284}
285
286static int __init pci_check_direct(void)
287{
288 unsigned long flags;
289
290 local_irq_save(flags);
291
292 /*
293 * Check if access works.
294 */
295 if (pci_sanity_check(&pci_direct_ampci)) {
296 local_irq_restore(flags);
297 printk(KERN_INFO "PCI: Using configuration ampci\n");
298 request_mem_region(0xBE040000, 256, "AMPCI bridge");
299 request_mem_region(0xBFFFFFF4, 12, "PCI ampci");
300 return 0;
301 }
302
303 local_irq_restore(flags);
304 return -ENODEV;
305}
306
307static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
308{
309 unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
310 struct resource *devr = &dev->resource[idx];
311
312 if (dev->bus) {
313 for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
314 struct resource *busr = dev->bus->resource[i];
315
316 if (!busr || (busr->flags ^ devr->flags) & type_mask)
317 continue;
318
319 if (devr->start &&
320 devr->start >= busr->start &&
321 devr->end <= busr->end)
322 return 1;
323 }
324 }
325
326 return 0;
327}
328
329static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
330{
331 struct pci_bus_region region;
332 int i;
333 int limit;
334
335 if (dev->bus->number != 0)
336 return;
337
338 limit = (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) ?
339 PCI_BRIDGE_RESOURCES : PCI_NUM_RESOURCES;
340
341 for (i = 0; i < limit; i++) {
342 if (!dev->resource[i].flags)
343 continue;
344
345 region.start = dev->resource[i].start;
346 region.end = dev->resource[i].end;
347 pcibios_bus_to_resource(dev, &dev->resource[i], &region);
348 if (is_valid_resource(dev, i))
349 pci_claim_resource(dev, i);
350 }
351}
352
353/*
354 * Called after each bus is probed, but before its children
355 * are examined.
356 */
357void __devinit pcibios_fixup_bus(struct pci_bus *bus)
358{
359 struct pci_dev *dev;
360
361 if (bus->self) {
362 pci_read_bridge_bases(bus);
363 pcibios_fixup_device_resources(bus->self);
364 }
365
366 list_for_each_entry(dev, &bus->devices, bus_list)
367 pcibios_fixup_device_resources(dev);
368}
369
370/*
371 * Initialization. Try all known PCI access methods. Note that we support
372 * using both PCI BIOS and direct access: in such cases, we use I/O ports
373 * to access config space, but we still keep BIOS order of cards to be
374 * compatible with 2.0.X. This should go away some day.
375 */
376static int __init pcibios_init(void)
377{
378 ioport_resource.start = 0xA0000000;
379 ioport_resource.end = 0xDFFFFFFF;
380 iomem_resource.start = 0xA0000000;
381 iomem_resource.end = 0xDFFFFFFF;
382
383 if (!pci_probe)
384 return 0;
385
386 if (pci_check_direct() < 0) {
387 printk(KERN_WARNING "PCI: No PCI bus detected\n");
388 return 0;
389 }
390
391 printk(KERN_INFO "PCI: Probing PCI hardware [mempage %08x]\n",
392 MEM_PAGING_REG);
393
394 {
395#if 0
396 static struct pci_bus am33_root_bus = {
397 .children = LIST_HEAD_INIT(am33_root_bus.children),
398 .devices = LIST_HEAD_INIT(am33_root_bus.devices),
399 .number = 0,
400 .secondary = 0,
401 .resource = { &ioport_resource, &iomem_resource },
402 };
403
404 am33_root_bus.ops = pci_root_ops;
405 list_add_tail(&am33_root_bus.node, &pci_root_buses);
406
407 am33_root_bus.subordinate = pci_do_scan_bus(0);
408
409 pci_root_bus = &am33_root_bus;
410#else
411 pci_root_bus = pci_scan_bus(0, &pci_direct_ampci, NULL);
412#endif
413 }
414
415 pcibios_irq_init();
416 pcibios_fixup_irqs();
417#if 0
418 pcibios_resource_survey();
419#endif
420 return 0;
421}
422
423arch_initcall(pcibios_init);
424
425char *__init pcibios_setup(char *str)
426{
427 if (!strcmp(str, "off")) {
428 pci_probe = 0;
429 return NULL;
430
431 } else if (!strncmp(str, "lastbus=", 8)) {
432 pcibios_last_bus = simple_strtol(str+8, NULL, 0);
433 return NULL;
434 }
435
436 return str;
437}
438
439int pcibios_enable_device(struct pci_dev *dev, int mask)
440{
441 int err;
442
443 err = pcibios_enable_resources(dev, mask);
444 if (err == 0)
445 pcibios_enable_irq(dev);
446 return err;
447}
448
449/*
450 * disable the ethernet chipset
451 */
452static void __init unit_disable_pcnet(struct pci_bus *bus, struct pci_ops *o)
453{
454 u32 x;
455
456 bus->number = 0;
457
458 o->read (bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, &x);
459 x |= PCI_COMMAND_MASTER |
460 PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
461 PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
462 o->write(bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, x);
463 o->read (bus, PCI_DEVFN(2, 0), PCI_COMMAND, 2, &x);
464 o->write(bus, PCI_DEVFN(2, 0), PCI_BASE_ADDRESS_0, 4, 0x00030001);
465 o->read (bus, PCI_DEVFN(2, 0), PCI_BASE_ADDRESS_0, 4, &x);
466
467#define RDP (*(volatile u32 *) 0xBE030010)
468#define RAP (*(volatile u32 *) 0xBE030014)
469#define __set_RAP(X) do { RAP = (X); x = RAP; } while (0)
470#define __set_RDP(X) do { RDP = (X); x = RDP; } while (0)
471#define __get_RDP() ({ RDP & 0xffff; })
472
473 __set_RAP(0);
474 __set_RDP(0x0004); /* CSR0 = STOP */
475
476 __set_RAP(88); /* check CSR88 indicates an Am79C973 */
477 BUG_ON(__get_RDP() != 0x5003);
478
479 for (x = 0; x < 100; x++)
480 asm volatile("nop");
481
482 __set_RDP(0x0004); /* CSR0 = STOP */
483}
484
485/*
486 * initialise the unit hardware
487 */
488asmlinkage void __init unit_pci_init(void)
489{
490 struct pci_bus bus; /* Fake bus and device */
491 struct pci_ops *o = &pci_direct_ampci;
492 u32 x;
493
494 set_intr_level(XIRQ1, GxICR_LEVEL_3);
495
496 memset(&bus, 0, sizeof(bus));
497
498 MEM_PAGING_REG = 0xE8000000;
499
500 /* we need to set up the bridge _now_ or we won't be able to access the
501 * PCI config registers
502 */
503 BRIDGEREGW(PCI_COMMAND) |=
504 PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
505 PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_MASTER;
506 BRIDGEREGW(PCI_STATUS) = 0xF800;
507 BRIDGEREGB(PCI_LATENCY_TIMER) = 0x10;
508 BRIDGEREGL(PCI_BASE_ADDRESS_0) = 0x80000000;
509 BRIDGEREGB(PCI_INTERRUPT_LINE) = 1;
510 BRIDGEREGL(0x48) = 0x98000000; /* AMPCI base addr */
511 BRIDGEREGB(0x41) = 0x00; /* secondary bus
512 * number */
513 BRIDGEREGB(0x42) = 0x01; /* subordinate bus
514 * number */
515 BRIDGEREGB(0x44) = 0x01;
516 BRIDGEREGL(0x50) = 0x00000001;
517 BRIDGEREGL(0x58) = 0x00001002;
518 BRIDGEREGL(0x5C) = 0x00000011;
519
520 /* we also need to set up the PCI-PCI bridge */
521 bus.number = 0;
522
523 /* IO: 0x00000000-0x00020000 */
524 o->read (&bus, PCI_DEVFN(3, 0), PCI_COMMAND, 2, &x);
525 x |= PCI_COMMAND_MASTER |
526 PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
527 PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
528 o->write(&bus, PCI_DEVFN(3, 0), PCI_COMMAND, 2, x);
529
530 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, &x);
531 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, &x);
532 o->read (&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, &x);
533 o->read (&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, &x);
534
535 o->write(&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, 0x01);
536 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE, 1, &x);
537 o->write(&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, 0x00020000);
538 o->read (&bus, PCI_DEVFN(3, 0), PCI_IO_BASE_UPPER16, 4, &x);
539 o->write(&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, 0xEBB0EA00);
540 o->read (&bus, PCI_DEVFN(3, 0), PCI_MEMORY_BASE, 4, &x);
541 o->write(&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, 0xE9F0E800);
542 o->read (&bus, PCI_DEVFN(3, 0), PCI_PREF_MEMORY_BASE, 4, &x);
543
544 unit_disable_pcnet(&bus, o);
545}
diff --git a/arch/mn10300/unit-asb2305/unit-init.c b/arch/mn10300/unit-asb2305/unit-init.c
new file mode 100644
index 000000000000..6a352414a358
--- /dev/null
+++ b/arch/mn10300/unit-asb2305/unit-init.c
@@ -0,0 +1,61 @@
1/* ASB2305 Initialisation
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/param.h>
13#include <linux/init.h>
14#include <linux/pci.h>
15#include <asm/io.h>
16#include <asm/setup.h>
17#include <asm/processor.h>
18#include <asm/cpu/intctl-regs.h>
19#include <asm/cpu/rtc-regs.h>
20#include <asm/cpu/serial-regs.h>
21#include <asm/unit/serial.h>
22
23/*
24 * initialise some of the unit hardware before gdbstub is set up
25 */
26asmlinkage void __init unit_init(void)
27{
28#ifndef CONFIG_GDBSTUB_ON_TTYSx
29 /* set the 16550 interrupt line to level 3 if not being used for GDB */
30 set_intr_level(XIRQ0, GxICR_LEVEL_3);
31#endif
32}
33
34/*
35 * initialise the rest of the unit hardware after gdbstub is ready
36 */
37void __init unit_setup(void)
38{
39#ifdef CONFIG_PCI
40 unit_pci_init();
41#endif
42}
43
44/*
45 * initialise the external interrupts used by a unit of this type
46 */
47void __init unit_init_IRQ(void)
48{
49 unsigned int extnum;
50
51 for (extnum = 0; extnum < NR_XIRQS; extnum++) {
52 switch (GET_XIRQ_TRIGGER(extnum)) {
53 case XIRQ_TRIGGER_HILEVEL:
54 case XIRQ_TRIGGER_LOWLEVEL:
55 set_irq_handler(XIRQ2IRQ(extnum), handle_level_irq);
56 break;
57 default:
58 break;
59 }
60 }
61}