diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/cris |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/cris')
77 files changed, 20877 insertions, 0 deletions
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig new file mode 100644 index 000000000000..4332ca348d51 --- /dev/null +++ b/arch/cris/Kconfig | |||
@@ -0,0 +1,180 @@ | |||
1 | # | ||
2 | # For a description of the syntax of this configuration file, | ||
3 | # see the Configure script. | ||
4 | # | ||
5 | |||
6 | mainmenu "Linux/CRIS Kernel Configuration" | ||
7 | |||
8 | config MMU | ||
9 | bool | ||
10 | default y | ||
11 | |||
12 | config UID16 | ||
13 | bool | ||
14 | default y | ||
15 | |||
16 | config RWSEM_GENERIC_SPINLOCK | ||
17 | bool | ||
18 | default y | ||
19 | |||
20 | config RWSEM_XCHGADD_ALGORITHM | ||
21 | bool | ||
22 | |||
23 | config GENERIC_CALIBRATE_DELAY | ||
24 | bool | ||
25 | default y | ||
26 | |||
27 | config CRIS | ||
28 | bool | ||
29 | default y | ||
30 | |||
31 | source "init/Kconfig" | ||
32 | |||
33 | menu "General setup" | ||
34 | |||
35 | source "fs/Kconfig.binfmt" | ||
36 | |||
37 | config ETRAX_CMDLINE | ||
38 | string "Kernel command line" | ||
39 | default "root=/dev/mtdblock3" | ||
40 | help | ||
41 | Pass additional commands to the kernel. | ||
42 | |||
43 | config ETRAX_WATCHDOG | ||
44 | bool "Enable ETRAX watchdog" | ||
45 | help | ||
46 | Enable the built-in watchdog timer support on ETRAX based embedded | ||
47 | network computers. | ||
48 | |||
49 | config ETRAX_WATCHDOG_NICE_DOGGY | ||
50 | bool "Disable watchdog during Oops printouts" | ||
51 | depends on ETRAX_WATCHDOG | ||
52 | help | ||
53 | By enabling this you make sure that the watchdog does not bite while | ||
54 | printing oopses. Recommended for development systems but not for | ||
55 | production releases. | ||
56 | |||
57 | config ETRAX_FAST_TIMER | ||
58 | bool "Enable ETRAX fast timer API" | ||
59 | help | ||
60 | This options enables the API to a fast timer implementation using | ||
61 | timer1 to get sub jiffie resolution timers (primarily one-shot | ||
62 | timers). | ||
63 | This is needed if CONFIG_ETRAX_SERIAL_FAST_TIMER is enabled. | ||
64 | |||
65 | config PREEMPT | ||
66 | bool "Preemptible Kernel" | ||
67 | help | ||
68 | This option reduces the latency of the kernel when reacting to | ||
69 | real-time or interactive events by allowing a low priority process to | ||
70 | be preempted even if it is in kernel mode executing a system call. | ||
71 | This allows applications to run more reliably even when the system is | ||
72 | under load. | ||
73 | |||
74 | Say Y here if you are building a kernel for a desktop, embedded | ||
75 | or real-time system. Say N if you are unsure. | ||
76 | |||
77 | endmenu | ||
78 | |||
79 | menu "Hardware setup" | ||
80 | |||
81 | choice | ||
82 | prompt "Processor type" | ||
83 | default ETRAX100LX | ||
84 | |||
85 | config ETRAX100LX | ||
86 | bool "ETRAX-100LX-v1" | ||
87 | help | ||
88 | Support version 1 of the ETRAX 100LX. | ||
89 | |||
90 | config ETRAX100LX_V2 | ||
91 | bool "ETRAX-100LX-v2" | ||
92 | help | ||
93 | Support version 2 of the ETRAX 100LX. | ||
94 | |||
95 | config SVINTO_SIM | ||
96 | bool "ETRAX-100LX-for-xsim-simulator" | ||
97 | help | ||
98 | Support the xsim ETRAX Simulator. | ||
99 | |||
100 | endchoice | ||
101 | |||
102 | config ETRAX_ARCH_V10 | ||
103 | bool | ||
104 | default y if ETRAX100LX || ETRAX100LX_V2 | ||
105 | default n if !(ETRAX100LX || ETRAX100LX_V2) | ||
106 | |||
107 | config ETRAX_DRAM_SIZE | ||
108 | int "DRAM size (dec, in MB)" | ||
109 | default "8" | ||
110 | help | ||
111 | Size of DRAM (decimal in MB) typically 2, 8 or 16. | ||
112 | |||
113 | config ETRAX_FLASH_BUSWIDTH | ||
114 | int "Buswidth of flash in bytes" | ||
115 | default "2" | ||
116 | help | ||
117 | Width in bytes of the Flash bus (1, 2 or 4). Is usually 2. | ||
118 | |||
119 | source arch/cris/arch-v10/Kconfig | ||
120 | |||
121 | endmenu | ||
122 | |||
123 | # bring in ETRAX built-in drivers | ||
124 | menu "Drivers for built-in interfaces" | ||
125 | source arch/cris/arch-v10/drivers/Kconfig | ||
126 | |||
127 | endmenu | ||
128 | |||
129 | source "drivers/base/Kconfig" | ||
130 | |||
131 | # standard linux drivers | ||
132 | source "drivers/mtd/Kconfig" | ||
133 | |||
134 | source "drivers/parport/Kconfig" | ||
135 | |||
136 | source "drivers/pnp/Kconfig" | ||
137 | |||
138 | source "drivers/block/Kconfig" | ||
139 | |||
140 | source "drivers/md/Kconfig" | ||
141 | |||
142 | source "drivers/ide/Kconfig" | ||
143 | |||
144 | source "drivers/scsi/Kconfig" | ||
145 | |||
146 | source "drivers/ieee1394/Kconfig" | ||
147 | |||
148 | source "drivers/message/i2o/Kconfig" | ||
149 | |||
150 | source "net/Kconfig" | ||
151 | |||
152 | source "drivers/isdn/Kconfig" | ||
153 | |||
154 | source "drivers/telephony/Kconfig" | ||
155 | |||
156 | source "drivers/cdrom/Kconfig" | ||
157 | |||
158 | # | ||
159 | # input before char - char/joystick depends on it. As does USB. | ||
160 | # | ||
161 | source "drivers/input/Kconfig" | ||
162 | |||
163 | source "drivers/char/Kconfig" | ||
164 | |||
165 | #source drivers/misc/Config.in | ||
166 | source "drivers/media/Kconfig" | ||
167 | |||
168 | source "fs/Kconfig" | ||
169 | |||
170 | source "sound/Kconfig" | ||
171 | |||
172 | source "drivers/usb/Kconfig" | ||
173 | |||
174 | source "arch/cris/Kconfig.debug" | ||
175 | |||
176 | source "security/Kconfig" | ||
177 | |||
178 | source "crypto/Kconfig" | ||
179 | |||
180 | source "lib/Kconfig" | ||
diff --git a/arch/cris/Kconfig.debug b/arch/cris/Kconfig.debug new file mode 100644 index 000000000000..f42918bf22a9 --- /dev/null +++ b/arch/cris/Kconfig.debug | |||
@@ -0,0 +1,41 @@ | |||
1 | menu "Kernel hacking" | ||
2 | |||
3 | #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC | ||
4 | config PROFILING | ||
5 | bool "Kernel profiling support" | ||
6 | |||
7 | config SYSTEM_PROFILER | ||
8 | bool "System profiling support" | ||
9 | |||
10 | config ETRAX_KGDB | ||
11 | bool "Use kernel GDB debugger" | ||
12 | ---help--- | ||
13 | The CRIS version of gdb can be used to remotely debug a running | ||
14 | Linux kernel via the serial debug port. Provided you have gdb-cris | ||
15 | installed, run gdb-cris vmlinux, then type | ||
16 | |||
17 | (gdb) set remotebaud 115200 <- kgdb uses 115200 as default | ||
18 | (gdb) target remote /dev/ttyS0 <- maybe you use another port | ||
19 | |||
20 | This should connect you to your booted kernel (or boot it now if you | ||
21 | didn't before). The kernel halts when it boots, waiting for gdb if | ||
22 | this option is turned on! | ||
23 | |||
24 | |||
25 | config DEBUG_INFO | ||
26 | bool "Compile the kernel with debug info" | ||
27 | help | ||
28 | If you say Y here the resulting kernel image will include | ||
29 | debugging info resulting in a larger kernel image. | ||
30 | Say Y here only if you plan to use gdb to debug the kernel. | ||
31 | If you don't debug the kernel, you can say N. | ||
32 | |||
33 | config FRAME_POINTER | ||
34 | bool "Compile the kernel with frame pointers" | ||
35 | help | ||
36 | If you say Y here the resulting kernel image will be slightly larger | ||
37 | and slower, but it will give very useful debugging information. | ||
38 | If you don't debug the kernel, you can say N, but we may not be able | ||
39 | to solve problems without frame pointers. | ||
40 | |||
41 | endmenu | ||
diff --git a/arch/cris/Makefile b/arch/cris/Makefile new file mode 100644 index 000000000000..9d28fa8563cc --- /dev/null +++ b/arch/cris/Makefile | |||
@@ -0,0 +1,112 @@ | |||
1 | # $Id: Makefile,v 1.23 2004/10/19 13:07:34 starvik Exp $ | ||
2 | # cris/Makefile | ||
3 | # | ||
4 | # This file is included by the global makefile so that you can add your own | ||
5 | # architecture-specific flags and dependencies. Remember to do have actions | ||
6 | # for "archclean" and "archdep" for cleaning up and making dependencies for | ||
7 | # this architecture | ||
8 | # | ||
9 | # This file is subject to the terms and conditions of the GNU General Public | ||
10 | # License. See the file "COPYING" in the main directory of this archive | ||
11 | # for more details. | ||
12 | |||
13 | # A bug in ld prevents us from having a (constant-value) symbol in a | ||
14 | # "ORIGIN =" or "LENGTH =" expression. | ||
15 | |||
16 | arch-y := v10 | ||
17 | arch-$(CONFIG_ETRAX_ARCH_V10) := v10 | ||
18 | |||
19 | # No config avaiable for make clean etc | ||
20 | ifneq ($(arch-y),) | ||
21 | SARCH := arch-$(arch-y) | ||
22 | else | ||
23 | SARCH := | ||
24 | endif | ||
25 | |||
26 | LD = $(CROSS_COMPILE)ld -mcrislinux | ||
27 | |||
28 | OBJCOPYFLAGS := -O binary -R .note -R .comment -S | ||
29 | |||
30 | CPPFLAGS_vmlinux.lds = -DDRAM_VIRTUAL_BASE=0x$(CONFIG_ETRAX_DRAM_VIRTUAL_BASE) | ||
31 | AFLAGS += -mlinux | ||
32 | |||
33 | CFLAGS := $(CFLAGS) -mlinux -march=$(arch-y) -pipe | ||
34 | |||
35 | ifdef CONFIG_FRAME_POINTER | ||
36 | CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) -g | ||
37 | CFLAGS += -fno-omit-frame-pointer | ||
38 | endif | ||
39 | |||
40 | head-y := arch/$(ARCH)/$(SARCH)/kernel/head.o | ||
41 | |||
42 | LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) | ||
43 | |||
44 | core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/ | ||
45 | core-y += arch/$(ARCH)/$(SARCH)/kernel/ arch/$(ARCH)/$(SARCH)/mm/ | ||
46 | drivers-y += arch/$(ARCH)/$(SARCH)/drivers/ | ||
47 | libs-y += arch/$(ARCH)/$(SARCH)/lib/ $(LIBGCC) | ||
48 | |||
49 | vmlinux.bin: vmlinux | ||
50 | $(OBJCOPY) $(OBJCOPYFLAGS) vmlinux vmlinux.bin | ||
51 | |||
52 | timage: vmlinux.bin | ||
53 | cat vmlinux.bin cramfs.img >timage | ||
54 | |||
55 | simimage: timage | ||
56 | cp vmlinux.bin simvmlinux.bin | ||
57 | |||
58 | # the following will remake timage without compiling the kernel | ||
59 | # it does of course require that all object files exist... | ||
60 | |||
61 | cramfs: | ||
62 | ## cramfs - Creates a cramfs image | ||
63 | mkcramfs -b 8192 -m romfs_meta.txt root cramfs.img | ||
64 | cat vmlinux.bin cramfs.img >timage | ||
65 | |||
66 | clinux: vmlinux.bin decompress.bin rescue.bin | ||
67 | |||
68 | decompress.bin: FORCE | ||
69 | @make -C arch/$(ARCH)/boot/compressed decompress.bin | ||
70 | |||
71 | rescue.bin: FORCE | ||
72 | @make -C arch/$(ARCH)/boot/rescue rescue.bin | ||
73 | |||
74 | zImage: vmlinux.bin rescue.bin | ||
75 | ## zImage - Compressed kernel (gzip) | ||
76 | @make -C arch/$(ARCH)/boot/ zImage | ||
77 | |||
78 | compressed: zImage | ||
79 | |||
80 | archmrproper: | ||
81 | archclean: | ||
82 | $(Q)$(MAKE) $(clean)=arch/$(ARCH)/boot | ||
83 | rm -f timage vmlinux.bin decompress.bin rescue.bin cramfs.img | ||
84 | rm -rf $(LD_SCRIPT).tmp | ||
85 | |||
86 | prepare: arch/$(ARCH)/.links include/asm-$(ARCH)/.arch \ | ||
87 | include/asm-$(ARCH)/$(SARCH)/offset.h | ||
88 | |||
89 | # Create some links to make all tools happy | ||
90 | arch/$(ARCH)/.links: | ||
91 | @rm -rf arch/$(ARCH)/drivers | ||
92 | @ln -sfn $(SARCH)/drivers arch/$(ARCH)/drivers | ||
93 | @rm -rf arch/$(ARCH)/boot | ||
94 | @ln -sfn $(SARCH)/boot arch/$(ARCH)/boot | ||
95 | @rm -rf arch/$(ARCH)/lib | ||
96 | @ln -sfn $(SARCH)/lib arch/$(ARCH)/lib | ||
97 | @ln -sfn $(SARCH) arch/$(ARCH)/arch | ||
98 | @ln -sfn ../$(SARCH)/vmlinux.lds.S arch/$(ARCH)/kernel/vmlinux.lds.S | ||
99 | @touch $@ | ||
100 | |||
101 | # Create link to sub arch includes | ||
102 | include/asm-$(ARCH)/.arch: $(wildcard include/config/arch/*.h) | ||
103 | @echo ' Making asm-$(ARCH)/arch -> asm-$(ARCH)/$(SARCH) symlink' | ||
104 | @rm -f include/asm-$(ARCH)/arch | ||
105 | @ln -sf $(SARCH) include/asm-$(ARCH)/arch | ||
106 | @touch $@ | ||
107 | |||
108 | arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ | ||
109 | include/config/MARKER | ||
110 | |||
111 | include/asm-$(ARCH)/$(SARCH)/offset.h: arch/$(ARCH)/$(SARCH)/kernel/asm-offsets.s | ||
112 | $(call filechk,gen-asm-offsets) | ||
diff --git a/arch/cris/arch-v10/Kconfig b/arch/cris/arch-v10/Kconfig new file mode 100644 index 000000000000..2ca64cc40c63 --- /dev/null +++ b/arch/cris/arch-v10/Kconfig | |||
@@ -0,0 +1,422 @@ | |||
1 | # ETRAX 100LX v1 has a MMU "feature" requiring a low mapping | ||
2 | config CRIS_LOW_MAP | ||
3 | bool | ||
4 | depends on ETRAX_ARCH_V10 && ETRAX100LX | ||
5 | default y | ||
6 | |||
7 | config ETRAX_DRAM_VIRTUAL_BASE | ||
8 | hex | ||
9 | depends on ETRAX_ARCH_V10 | ||
10 | default "c0000000" if !ETRAX100LX | ||
11 | default "60000000" if ETRAX100LX | ||
12 | |||
13 | choice | ||
14 | prompt "Product LED port" | ||
15 | depends on ETRAX_ARCH_V10 | ||
16 | default ETRAX_PA_LEDS | ||
17 | |||
18 | config ETRAX_PA_LEDS | ||
19 | bool "Port-PA-LEDs" | ||
20 | help | ||
21 | The ETRAX network driver is responsible for flashing LED's when | ||
22 | packets arrive and are sent. It uses macros defined in | ||
23 | <file:include/asm-cris/io.h>, and those macros are defined after what | ||
24 | YOU choose in this option. The actual bits used are configured | ||
25 | separately. Select this if the LEDs are on port PA. Some products | ||
26 | put the leds on PB or a memory-mapped latch (CSP0) instead. | ||
27 | |||
28 | config ETRAX_PB_LEDS | ||
29 | bool "Port-PB-LEDs" | ||
30 | help | ||
31 | The ETRAX network driver is responsible for flashing LED's when | ||
32 | packets arrive and are sent. It uses macros defined in | ||
33 | <file:include/asm-cris/io.h>, and those macros are defined after what | ||
34 | YOU choose in this option. The actual bits used are configured | ||
35 | separately. Select this if the LEDs are on port PB. Some products | ||
36 | put the leds on PA or a memory-mapped latch (CSP0) instead. | ||
37 | |||
38 | config ETRAX_CSP0_LEDS | ||
39 | bool "Port-CSP0-LEDs" | ||
40 | help | ||
41 | The ETRAX network driver is responsible for flashing LED's when | ||
42 | packets arrive and are sent. It uses macros defined in | ||
43 | <file:include/asm-cris/io.h>, and those macros are defined after what | ||
44 | YOU choose in this option. The actual bits used are configured | ||
45 | separately. Select this if the LEDs are on a memory-mapped latch | ||
46 | using chip select CSP0, this is mapped at 0x90000000. | ||
47 | Some products put the leds on PA or PB instead. | ||
48 | |||
49 | config ETRAX_NO_LEDS | ||
50 | bool "None" | ||
51 | help | ||
52 | Select this option if you don't have any LED at all. | ||
53 | |||
54 | endchoice | ||
55 | |||
56 | config ETRAX_LED1G | ||
57 | int "First green LED bit" | ||
58 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
59 | default "2" | ||
60 | help | ||
61 | Bit to use for the first green LED. | ||
62 | Most Axis products use bit 2 here. | ||
63 | |||
64 | config ETRAX_LED1R | ||
65 | int "First red LED bit" | ||
66 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
67 | default "3" | ||
68 | help | ||
69 | Bit to use for the first red LED. | ||
70 | Most Axis products use bit 3 here. | ||
71 | For products with only one controllable LED, | ||
72 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
73 | |||
74 | config ETRAX_LED2G | ||
75 | int "Second green LED bit" | ||
76 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
77 | default "4" | ||
78 | help | ||
79 | Bit to use for the second green LED. The "Active" LED. | ||
80 | Most Axis products use bit 4 here. | ||
81 | For products with only one controllable LED, | ||
82 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
83 | |||
84 | config ETRAX_LED2R | ||
85 | int "Second red LED bit" | ||
86 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
87 | default "5" | ||
88 | help | ||
89 | Bit to use for the second red LED. | ||
90 | Most Axis products use bit 5 here. | ||
91 | For products with only one controllable LED, | ||
92 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
93 | |||
94 | config ETRAX_LED3G | ||
95 | int "Third green LED bit" | ||
96 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
97 | default "2" | ||
98 | help | ||
99 | Bit to use for the third green LED. The "Drive" LED. | ||
100 | For products with only one or two controllable LEDs, | ||
101 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
102 | |||
103 | config ETRAX_LED3R | ||
104 | int "Third red LED bit" | ||
105 | depends on ETRAX_ARCH_V10 && !ETRAX_NO_LEDS | ||
106 | default "2" | ||
107 | help | ||
108 | Bit to use for the third red LED. | ||
109 | For products with only one or two controllable LEDs, | ||
110 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
111 | |||
112 | config ETRAX_LED4R | ||
113 | int "Fourth red LED bit" | ||
114 | depends on ETRAX_CSP0_LEDS | ||
115 | default "2" | ||
116 | help | ||
117 | Bit to use for the fourth red LED. | ||
118 | For products with only one or two controllable LEDs, | ||
119 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
120 | |||
121 | config ETRAX_LED4G | ||
122 | int "Fourth green LED bit" | ||
123 | depends on ETRAX_CSP0_LEDS | ||
124 | default "2" | ||
125 | help | ||
126 | Bit to use for the fourth green LED. | ||
127 | For products with only one or two controllable LEDs, | ||
128 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
129 | |||
130 | config ETRAX_LED5R | ||
131 | int "Fifth red LED bit" | ||
132 | depends on ETRAX_CSP0_LEDS | ||
133 | default "2" | ||
134 | help | ||
135 | Bit to use for the fifth red LED. | ||
136 | For products with only one or two controllable LEDs, | ||
137 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
138 | |||
139 | config ETRAX_LED5G | ||
140 | int "Fifth green LED bit" | ||
141 | depends on ETRAX_CSP0_LEDS | ||
142 | default "2" | ||
143 | help | ||
144 | Bit to use for the fifth green LED. | ||
145 | For products with only one or two controllable LEDs, | ||
146 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
147 | |||
148 | config ETRAX_LED6R | ||
149 | int "Sixth red LED bit" | ||
150 | depends on ETRAX_CSP0_LEDS | ||
151 | default "2" | ||
152 | help | ||
153 | Bit to use for the sixth red LED. | ||
154 | For products with only one or two controllable LEDs, | ||
155 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
156 | |||
157 | config ETRAX_LED6G | ||
158 | int "Sixth green LED bit" | ||
159 | depends on ETRAX_CSP0_LEDS | ||
160 | default "2" | ||
161 | help | ||
162 | Bit to use for the sixth green LED. The "Drive" LED. | ||
163 | For products with only one or two controllable LEDs, | ||
164 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
165 | |||
166 | config ETRAX_LED7R | ||
167 | int "Seventh red LED bit" | ||
168 | depends on ETRAX_CSP0_LEDS | ||
169 | default "2" | ||
170 | help | ||
171 | Bit to use for the seventh red LED. | ||
172 | For products with only one or two controllable LEDs, | ||
173 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
174 | |||
175 | config ETRAX_LED7G | ||
176 | int "Seventh green LED bit" | ||
177 | depends on ETRAX_CSP0_LEDS | ||
178 | default "2" | ||
179 | help | ||
180 | Bit to use for the seventh green LED. | ||
181 | For products with only one or two controllable LEDs, | ||
182 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
183 | |||
184 | config ETRAX_LED8Y | ||
185 | int "Eigth yellow LED bit" | ||
186 | depends on ETRAX_CSP0_LEDS | ||
187 | default "2" | ||
188 | help | ||
189 | Bit to use for the eighth yellow LED. The "Drive" LED. | ||
190 | For products with only one or two controllable LEDs, | ||
191 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
192 | |||
193 | config ETRAX_LED9Y | ||
194 | int "Ninth yellow LED bit" | ||
195 | depends on ETRAX_CSP0_LEDS | ||
196 | default "2" | ||
197 | help | ||
198 | Bit to use for the ninth yellow LED. | ||
199 | For products with only one or two controllable LEDs, | ||
200 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
201 | |||
202 | config ETRAX_LED10Y | ||
203 | int "Tenth yellow LED bit" | ||
204 | depends on ETRAX_CSP0_LEDS | ||
205 | default "2" | ||
206 | help | ||
207 | Bit to use for the tenth yellow LED. | ||
208 | For products with only one or two controllable LEDs, | ||
209 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
210 | |||
211 | config ETRAX_LED11Y | ||
212 | int "Eleventh yellow LED bit" | ||
213 | depends on ETRAX_CSP0_LEDS | ||
214 | default "2" | ||
215 | help | ||
216 | Bit to use for the eleventh yellow LED. | ||
217 | For products with only one or two controllable LEDs, | ||
218 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
219 | |||
220 | config ETRAX_LED12R | ||
221 | int "Twelfth red LED bit" | ||
222 | depends on ETRAX_CSP0_LEDS | ||
223 | default "2" | ||
224 | help | ||
225 | Bit to use for the twelfth red LED. | ||
226 | For products with only one or two controllable LEDs, | ||
227 | set this to same as CONFIG_ETRAX_LED1G (normally 2). | ||
228 | |||
229 | choice | ||
230 | prompt "Product debug-port" | ||
231 | depends on ETRAX_ARCH_V10 | ||
232 | default ETRAX_DEBUG_PORT0 | ||
233 | |||
234 | config ETRAX_DEBUG_PORT0 | ||
235 | bool "Serial-0" | ||
236 | help | ||
237 | Choose a serial port for the ETRAX debug console. Default to | ||
238 | port 0. | ||
239 | |||
240 | config ETRAX_DEBUG_PORT1 | ||
241 | bool "Serial-1" | ||
242 | help | ||
243 | Use serial port 1 for the console. | ||
244 | |||
245 | config ETRAX_DEBUG_PORT2 | ||
246 | bool "Serial-2" | ||
247 | help | ||
248 | Use serial port 2 for the console. | ||
249 | |||
250 | config ETRAX_DEBUG_PORT3 | ||
251 | bool "Serial-3" | ||
252 | help | ||
253 | Use serial port 3 for the console. | ||
254 | |||
255 | config ETRAX_DEBUG_PORT_NULL | ||
256 | bool "disabled" | ||
257 | help | ||
258 | Disable serial-port debugging. | ||
259 | |||
260 | endchoice | ||
261 | |||
262 | choice | ||
263 | prompt "Product rescue-port" | ||
264 | depends on ETRAX_ARCH_V10 | ||
265 | default ETRAX_RESCUE_SER0 | ||
266 | |||
267 | config ETRAX_RESCUE_SER0 | ||
268 | bool "Serial-0" | ||
269 | help | ||
270 | Select one of the four serial ports as a rescue port. The default | ||
271 | is port 0. | ||
272 | |||
273 | config ETRAX_RESCUE_SER1 | ||
274 | bool "Serial-1" | ||
275 | help | ||
276 | Use serial port 1 as the rescue port. | ||
277 | |||
278 | config ETRAX_RESCUE_SER2 | ||
279 | bool "Serial-2" | ||
280 | help | ||
281 | Use serial port 2 as the rescue port. | ||
282 | |||
283 | config ETRAX_RESCUE_SER3 | ||
284 | bool "Serial-3" | ||
285 | help | ||
286 | Use serial port 3 as the rescue port. | ||
287 | |||
288 | endchoice | ||
289 | |||
290 | config ETRAX_DEF_R_WAITSTATES | ||
291 | hex "R_WAITSTATES" | ||
292 | depends on ETRAX_ARCH_V10 | ||
293 | default "95a6" | ||
294 | help | ||
295 | Waitstates for SRAM, Flash and peripherials (not DRAM). 95f8 is a | ||
296 | good choice for most Axis products... | ||
297 | |||
298 | config ETRAX_DEF_R_BUS_CONFIG | ||
299 | hex "R_BUS_CONFIG" | ||
300 | depends on ETRAX_ARCH_V10 | ||
301 | default "104" | ||
302 | help | ||
303 | Assorted bits controlling write mode, DMA burst length etc. 104 is | ||
304 | a good choice for most Axis products... | ||
305 | |||
306 | config ETRAX_SDRAM | ||
307 | bool "SDRAM support" | ||
308 | depends on ETRAX_ARCH_V10 | ||
309 | help | ||
310 | Enable this if you use SDRAM chips and configure | ||
311 | R_SDRAM_CONFIG and R_SDRAM_TIMING as well. | ||
312 | |||
313 | config ETRAX_DEF_R_DRAM_CONFIG | ||
314 | hex "R_DRAM_CONFIG" | ||
315 | depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM | ||
316 | default "1a200040" | ||
317 | help | ||
318 | The R_DRAM_CONFIG register specifies everything on how the DRAM | ||
319 | chips in the system are connected to the ETRAX CPU. This is | ||
320 | different depending on the manufacturer, chip type and number of | ||
321 | chips. So this value often needs to be different for each Axis | ||
322 | product. | ||
323 | |||
324 | config ETRAX_DEF_R_DRAM_TIMING | ||
325 | hex "R_DRAM_TIMING" | ||
326 | depends on ETRAX_ARCH_V10 && !ETRAX_SDRAM | ||
327 | default "5611" | ||
328 | help | ||
329 | Different DRAM chips have different speeds. Current Axis products | ||
330 | use 50ns DRAM chips which can use the timing: 5611. | ||
331 | |||
332 | config ETRAX_DEF_R_SDRAM_CONFIG | ||
333 | hex "R_SDRAM_CONFIG" | ||
334 | depends on ETRAX_ARCH_V10 && ETRAX_SDRAM | ||
335 | default "d2fa7878" | ||
336 | help | ||
337 | The R_SDRAM_CONFIG register specifies everything on how the SDRAM | ||
338 | chips in the system are connected to the ETRAX CPU. This is | ||
339 | different depending on the manufacturer, chip type and number of | ||
340 | chips. So this value often needs to be different for each Axis | ||
341 | product. | ||
342 | |||
343 | config ETRAX_DEF_R_SDRAM_TIMING | ||
344 | hex "R_SDRAM_TIMING" | ||
345 | depends on ETRAX_ARCH_V10 && ETRAX_SDRAM | ||
346 | default "80004801" | ||
347 | help | ||
348 | Different SDRAM chips have different timing. | ||
349 | |||
350 | config ETRAX_DEF_R_PORT_PA_DIR | ||
351 | hex "R_PORT_PA_DIR" | ||
352 | depends on ETRAX_ARCH_V10 | ||
353 | default "1c" | ||
354 | help | ||
355 | Configures the direction of general port A bits. 1 is out, 0 is in. | ||
356 | This is often totally different depending on the product used. | ||
357 | There are some guidelines though - if you know that only LED's are | ||
358 | connected to port PA, then they are usually connected to bits 2-4 | ||
359 | and you can therefore use 1c. On other boards which don't have the | ||
360 | LED's at the general ports, these bits are used for all kinds of | ||
361 | stuff. If you don't know what to use, it is always safe to put all | ||
362 | as inputs, although floating inputs isn't good. | ||
363 | |||
364 | config ETRAX_DEF_R_PORT_PA_DATA | ||
365 | hex "R_PORT_PA_DATA" | ||
366 | depends on ETRAX_ARCH_V10 | ||
367 | default "00" | ||
368 | help | ||
369 | Configures the initial data for the general port A bits. Most | ||
370 | products should use 00 here. | ||
371 | |||
372 | config ETRAX_DEF_R_PORT_PB_CONFIG | ||
373 | hex "R_PORT_PB_CONFIG" | ||
374 | depends on ETRAX_ARCH_V10 | ||
375 | default "00" | ||
376 | help | ||
377 | Configures the type of the general port B bits. 1 is chip select, | ||
378 | 0 is port. Most products should use 00 here. | ||
379 | |||
380 | config ETRAX_DEF_R_PORT_PB_DIR | ||
381 | hex "R_PORT_PB_DIR" | ||
382 | depends on ETRAX_ARCH_V10 | ||
383 | default "00" | ||
384 | help | ||
385 | Configures the direction of general port B bits. 1 is out, 0 is in. | ||
386 | This is often totally different depending on the product used. Bits | ||
387 | 0 and 1 on port PB are usually used for I2C communication, but the | ||
388 | kernel I2C driver sets the appropriate directions itself so you | ||
389 | don't need to take that into consideration when setting this option. | ||
390 | If you don't know what to use, it is always safe to put all as | ||
391 | inputs. | ||
392 | |||
393 | config ETRAX_DEF_R_PORT_PB_DATA | ||
394 | hex "R_PORT_PB_DATA" | ||
395 | depends on ETRAX_ARCH_V10 | ||
396 | default "ff" | ||
397 | help | ||
398 | Configures the initial data for the general port A bits. Most | ||
399 | products should use FF here. | ||
400 | |||
401 | config ETRAX_SOFT_SHUTDOWN | ||
402 | bool "Software Shutdown Support" | ||
403 | depends on ETRAX_ARCH_V10 | ||
404 | help | ||
405 | Enable this if ETRAX is used with a power-supply that can be turned | ||
406 | off and on with PS_ON signal. Gives the possibility to detect | ||
407 | powerbutton and then do a power off after unmounting disks. | ||
408 | |||
409 | config ETRAX_SHUTDOWN_BIT | ||
410 | int "Shutdown bit on port CSP0" | ||
411 | depends on ETRAX_SOFT_SHUTDOWN | ||
412 | default "12" | ||
413 | help | ||
414 | Configure what pin on CSPO-port that is used for controlling power | ||
415 | supply. | ||
416 | |||
417 | config ETRAX_POWERBUTTON_BIT | ||
418 | int "Power button bit on port G" | ||
419 | depends on ETRAX_SOFT_SHUTDOWN | ||
420 | default "25" | ||
421 | help | ||
422 | Configure where power button is connected. | ||
diff --git a/arch/cris/arch-v10/README.mm b/arch/cris/arch-v10/README.mm new file mode 100644 index 000000000000..6f08903f3139 --- /dev/null +++ b/arch/cris/arch-v10/README.mm | |||
@@ -0,0 +1,244 @@ | |||
1 | Memory management for CRIS/MMU | ||
2 | ------------------------------ | ||
3 | HISTORY: | ||
4 | |||
5 | $Log: README.mm,v $ | ||
6 | Revision 1.1 2001/12/17 13:59:27 bjornw | ||
7 | Initial revision | ||
8 | |||
9 | Revision 1.1 2000/07/10 16:25:21 bjornw | ||
10 | Initial revision | ||
11 | |||
12 | Revision 1.4 2000/01/17 02:31:59 bjornw | ||
13 | Added discussion of paging and VM. | ||
14 | |||
15 | Revision 1.3 1999/12/03 16:43:23 hp | ||
16 | Blurb about that the 3.5G-limitation is not a MMU limitation | ||
17 | |||
18 | Revision 1.2 1999/12/03 16:04:21 hp | ||
19 | Picky comment about not mapping the first page | ||
20 | |||
21 | Revision 1.1 1999/12/03 15:41:30 bjornw | ||
22 | First version of CRIS/MMU memory layout specification. | ||
23 | |||
24 | |||
25 | |||
26 | |||
27 | |||
28 | ------------------------------ | ||
29 | |||
30 | See the ETRAX-NG HSDD for reference. | ||
31 | |||
32 | We use the page-size of 8 kbytes, as opposed to the i386 page-size of 4 kbytes. | ||
33 | |||
34 | The MMU can, apart from the normal mapping of pages, also do a top-level | ||
35 | segmentation of the kernel memory space. We use this feature to avoid having | ||
36 | to use page-tables to map the physical memory into the kernel's address | ||
37 | space. We also use it to keep the user-mode virtual mapping in the same | ||
38 | map during kernel-mode, so that the kernel easily can access the corresponding | ||
39 | user-mode process' data. | ||
40 | |||
41 | As a comparision, the Linux/i386 2.0 puts the kernel and physical RAM at | ||
42 | address 0, overlapping with the user-mode virtual space, so that descriptor | ||
43 | registers are needed for each memory access to specify which MMU space to | ||
44 | map through. That changed in 2.2, putting the kernel/physical RAM at | ||
45 | 0xc0000000, to co-exist with the user-mode mapping. We will do something | ||
46 | quite similar, but with the additional complexity of having to map the | ||
47 | internal chip I/O registers and the flash memory area (including SRAM | ||
48 | and peripherial chip-selets). | ||
49 | |||
50 | The kernel-mode segmentation map: | ||
51 | |||
52 | ------------------------ ------------------------ | ||
53 | FFFFFFFF| | => cached | | | ||
54 | | kernel seg_f | flash | | | ||
55 | F0000000|______________________| | | | ||
56 | EFFFFFFF| | => uncached | | | ||
57 | | kernel seg_e | flash | | | ||
58 | E0000000|______________________| | DRAM | | ||
59 | DFFFFFFF| | paged to any | Un-cached | | ||
60 | | kernel seg_d | =======> | | | ||
61 | D0000000|______________________| | | | ||
62 | CFFFFFFF| | | | | ||
63 | | kernel seg_c |==\ | | | ||
64 | C0000000|______________________| \ |______________________| | ||
65 | BFFFFFFF| | uncached | | | ||
66 | | kernel seg_b |=====\=========>| Registers | | ||
67 | B0000000|______________________| \c |______________________| | ||
68 | AFFFFFFF| | \a | | | ||
69 | | | \c | FLASH/SRAM/Peripheral| | ||
70 | | | \h |______________________| | ||
71 | | | \e | | | ||
72 | | | \d | | | ||
73 | | kernel seg_0 - seg_a | \==>| DRAM | | ||
74 | | | | Cached | | ||
75 | | | paged to any | | | ||
76 | | | =======> |______________________| | ||
77 | | | | | | ||
78 | | | | Illegal | | ||
79 | | | |______________________| | ||
80 | | | | | | ||
81 | | | | FLASH/SRAM/Peripheral| | ||
82 | 00000000|______________________| |______________________| | ||
83 | |||
84 | In user-mode it looks the same except that only the space 0-AFFFFFFF is | ||
85 | available. Therefore, in this model, the virtual address space per process | ||
86 | is limited to 0xb0000000 bytes (minus 8192 bytes, since the first page, | ||
87 | 0..8191, is never mapped, in order to trap NULL references). | ||
88 | |||
89 | It also means that the total physical RAM that can be mapped is 256 MB | ||
90 | (kseg_c above). More RAM can be mapped by choosing a different segmentation | ||
91 | and shrinking the user-mode memory space. | ||
92 | |||
93 | The MMU can map all 4 GB in user mode, but doing that would mean that a | ||
94 | few extra instructions would be needed for each access to user mode | ||
95 | memory. | ||
96 | |||
97 | The kernel needs access to both cached and uncached flash. Uncached is | ||
98 | necessary because of the special write/erase sequences. Also, the | ||
99 | peripherial chip-selects are decoded from that region. | ||
100 | |||
101 | The kernel also needs its own virtual memory space. That is kseg_d. It | ||
102 | is used by the vmalloc() kernel function to allocate virtual contiguous | ||
103 | chunks of memory not possible using the normal kmalloc physical RAM | ||
104 | allocator. | ||
105 | |||
106 | The setting of the actual MMU control registers to use this layout would | ||
107 | be something like this: | ||
108 | |||
109 | R_MMU_KSEG = ( ( seg_f, seg ) | // Flash cached | ||
110 | ( seg_e, seg ) | // Flash uncached | ||
111 | ( seg_d, page ) | // kernel vmalloc area | ||
112 | ( seg_c, seg ) | // kernel linear segment | ||
113 | ( seg_b, seg ) | // kernel linear segment | ||
114 | ( seg_a, page ) | | ||
115 | ( seg_9, page ) | | ||
116 | ( seg_8, page ) | | ||
117 | ( seg_7, page ) | | ||
118 | ( seg_6, page ) | | ||
119 | ( seg_5, page ) | | ||
120 | ( seg_4, page ) | | ||
121 | ( seg_3, page ) | | ||
122 | ( seg_2, page ) | | ||
123 | ( seg_1, page ) | | ||
124 | ( seg_0, page ) ); | ||
125 | |||
126 | R_MMU_KBASE_HI = ( ( base_f, 0x0 ) | // flash/sram/periph cached | ||
127 | ( base_e, 0x8 ) | // flash/sram/periph uncached | ||
128 | ( base_d, 0x0 ) | // don't care | ||
129 | ( base_c, 0x4 ) | // physical RAM cached area | ||
130 | ( base_b, 0xb ) | // uncached on-chip registers | ||
131 | ( base_a, 0x0 ) | // don't care | ||
132 | ( base_9, 0x0 ) | // don't care | ||
133 | ( base_8, 0x0 ) ); // don't care | ||
134 | |||
135 | R_MMU_KBASE_LO = ( ( base_7, 0x0 ) | // don't care | ||
136 | ( base_6, 0x0 ) | // don't care | ||
137 | ( base_5, 0x0 ) | // don't care | ||
138 | ( base_4, 0x0 ) | // don't care | ||
139 | ( base_3, 0x0 ) | // don't care | ||
140 | ( base_2, 0x0 ) | // don't care | ||
141 | ( base_1, 0x0 ) | // don't care | ||
142 | ( base_0, 0x0 ) ); // don't care | ||
143 | |||
144 | NOTE: while setting up the MMU, we run in a non-mapped mode in the DRAM (0x40 | ||
145 | segment) and need to setup the seg_4 to a unity mapping, so that we don't get | ||
146 | a fault before we have had time to jump into the real kernel segment (0xc0). This | ||
147 | is done in head.S temporarily, but fixed by the kernel later in paging_init. | ||
148 | |||
149 | |||
150 | Paging - PTE's, PMD's and PGD's | ||
151 | ------------------------------- | ||
152 | |||
153 | [ References: asm/pgtable.h, asm/page.h, asm/mmu.h ] | ||
154 | |||
155 | The paging mechanism uses virtual addresses to split a process memory-space into | ||
156 | pages, a page being the smallest unit that can be freely remapped in memory. On | ||
157 | Linux/CRIS, a page is 8192 bytes (for technical reasons not equal to 4096 as in | ||
158 | most other 32-bit architectures). It would be inefficient to let a virtual memory | ||
159 | mapping be controlled by a long table of page mappings, so it is broken down into | ||
160 | a 2-level structure with a Page Directory containing pointers to Page Tables which | ||
161 | each have maps of up to 2048 pages (8192 / sizeof(void *)). Linux can actually | ||
162 | handle 3-level structures as well, with a Page Middle Directory in between, but | ||
163 | in many cases, this is folded into a two-level structure by excluding the Middle | ||
164 | Directory. | ||
165 | |||
166 | We'll take a look at how an address is translated while we discuss how it's handled | ||
167 | in the Linux kernel. | ||
168 | |||
169 | The example address is 0xd004000c; in binary this is: | ||
170 | |||
171 | 31 23 15 7 0 | ||
172 | 11010000 00000100 00000000 00001100 | ||
173 | |||
174 | |______| |__________||____________| | ||
175 | PGD PTE page offset | ||
176 | |||
177 | Given the top-level Page Directory, the offset in that directory is calculated | ||
178 | using the upper 8 bits: | ||
179 | |||
180 | extern inline pgd_t * pgd_offset(struct mm_struct * mm, unsigned long address) | ||
181 | { | ||
182 | return mm->pgd + (address >> PGDIR_SHIFT); | ||
183 | } | ||
184 | |||
185 | PGDIR_SHIFT is the log2 of the amount of memory an entry in the PGD can map; in our | ||
186 | case it is 24, corresponding to 16 MB. This means that each entry in the PGD | ||
187 | corresponds to 16 MB of virtual memory. | ||
188 | |||
189 | The pgd_t from our example will therefore be the 208'th (0xd0) entry in mm->pgd. | ||
190 | |||
191 | Since the Middle Directory does not exist, it is a unity mapping: | ||
192 | |||
193 | extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) | ||
194 | { | ||
195 | return (pmd_t *) dir; | ||
196 | } | ||
197 | |||
198 | The Page Table provides the final lookup by using bits 13 to 23 as index: | ||
199 | |||
200 | extern inline pte_t * pte_offset(pmd_t * dir, unsigned long address) | ||
201 | { | ||
202 | return (pte_t *) pmd_page(*dir) + ((address >> PAGE_SHIFT) & | ||
203 | (PTRS_PER_PTE - 1)); | ||
204 | } | ||
205 | |||
206 | PAGE_SHIFT is the log2 of the size of a page; 13 in our case. PTRS_PER_PTE is | ||
207 | the number of pointers that fit in a Page Table and is used to mask off the | ||
208 | PGD-part of the address. | ||
209 | |||
210 | The so-far unused bits 0 to 12 are used to index inside a page linearily. | ||
211 | |||
212 | The VM system | ||
213 | ------------- | ||
214 | |||
215 | The kernels own page-directory is the swapper_pg_dir, cleared in paging_init, | ||
216 | and contains the kernels virtual mappings (the kernel itself is not paged - it | ||
217 | is mapped linearily using kseg_c as described above). Architectures without | ||
218 | kernel segments like the i386, need to setup swapper_pg_dir directly in head.S | ||
219 | to map the kernel itself. swapper_pg_dir is pointed to by init_mm.pgd as the | ||
220 | init-task's PGD. | ||
221 | |||
222 | To see what support functions are used to setup a page-table, let's look at the | ||
223 | kernel's internal paged memory system, vmalloc/vfree. | ||
224 | |||
225 | void * vmalloc(unsigned long size) | ||
226 | |||
227 | The vmalloc-system keeps a paged segment in kernel-space at 0xd0000000. What | ||
228 | happens first is that a virtual address chunk is allocated to the request using | ||
229 | get_vm_area(size). After that, physical RAM pages are allocated and put into | ||
230 | the kernel's page-table using alloc_area_pages(addr, size). | ||
231 | |||
232 | static int alloc_area_pages(unsigned long address, unsigned long size) | ||
233 | |||
234 | First the PGD entry is found using init_mm.pgd. This is passed to | ||
235 | alloc_area_pmd (remember the 3->2 folding). It uses pte_alloc_kernel to | ||
236 | check if the PGD entry points anywhere - if not, a page table page is | ||
237 | allocated and the PGD entry updated. Then the alloc_area_pte function is | ||
238 | used just like alloc_area_pmd to check which page table entry is desired, | ||
239 | and a physical page is allocated and the table entry updated. All of this | ||
240 | is repeated at the top-level until the entire address range specified has | ||
241 | been mapped. | ||
242 | |||
243 | |||
244 | |||
diff --git a/arch/cris/arch-v10/boot/Makefile b/arch/cris/arch-v10/boot/Makefile new file mode 100644 index 000000000000..fe6650368e6a --- /dev/null +++ b/arch/cris/arch-v10/boot/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # arch/cris/boot/Makefile | ||
3 | # | ||
4 | |||
5 | zImage: compressed/vmlinuz | ||
6 | |||
7 | compressed/vmlinuz: $(TOPDIR)/vmlinux | ||
8 | @$(MAKE) -C compressed vmlinuz | ||
9 | |||
10 | clean: | ||
11 | rm -f zImage tools/build compressed/vmlinux.out | ||
12 | @$(MAKE) -C compressed clean | ||
diff --git a/arch/cris/arch-v10/boot/compressed/Makefile b/arch/cris/arch-v10/boot/compressed/Makefile new file mode 100644 index 000000000000..5f71c2c819e6 --- /dev/null +++ b/arch/cris/arch-v10/boot/compressed/Makefile | |||
@@ -0,0 +1,40 @@ | |||
1 | # | ||
2 | # linux/arch/etrax100/boot/compressed/Makefile | ||
3 | # | ||
4 | # create a compressed vmlinux image from the original vmlinux files and romfs | ||
5 | # | ||
6 | |||
7 | CC = gcc-cris -melf -I $(TOPDIR)/include | ||
8 | CFLAGS = -O2 | ||
9 | LD = ld-cris | ||
10 | OBJCOPY = objcopy-cris | ||
11 | OBJCOPYFLAGS = -O binary --remove-section=.bss | ||
12 | OBJECTS = head.o misc.o | ||
13 | |||
14 | # files to compress | ||
15 | SYSTEM = $(TOPDIR)/vmlinux.bin | ||
16 | |||
17 | all: vmlinuz | ||
18 | |||
19 | decompress.bin: $(OBJECTS) | ||
20 | $(LD) -T decompress.ld -o decompress.o $(OBJECTS) | ||
21 | $(OBJCOPY) $(OBJCOPYFLAGS) decompress.o decompress.bin | ||
22 | # save it for mkprod in the topdir. | ||
23 | cp decompress.bin $(TOPDIR) | ||
24 | |||
25 | |||
26 | vmlinuz: piggy.img decompress.bin | ||
27 | cat decompress.bin piggy.img > vmlinuz | ||
28 | rm -f piggy.img | ||
29 | |||
30 | head.o: head.S | ||
31 | $(CC) -D__ASSEMBLY__ -traditional -c head.S -o head.o | ||
32 | |||
33 | # gzip the kernel image | ||
34 | |||
35 | piggy.img: $(SYSTEM) | ||
36 | cat $(SYSTEM) | gzip -f -9 > piggy.img | ||
37 | |||
38 | clean: | ||
39 | rm -f piggy.img vmlinuz vmlinuz.o | ||
40 | |||
diff --git a/arch/cris/arch-v10/boot/compressed/README b/arch/cris/arch-v10/boot/compressed/README new file mode 100644 index 000000000000..48b3db9924b9 --- /dev/null +++ b/arch/cris/arch-v10/boot/compressed/README | |||
@@ -0,0 +1,25 @@ | |||
1 | Creation of the self-extracting compressed kernel image (vmlinuz) | ||
2 | ----------------------------------------------------------------- | ||
3 | $Id: README,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
4 | |||
5 | This can be slightly confusing because it's a process with many steps. | ||
6 | |||
7 | The kernel object built by the arch/etrax100/Makefile, vmlinux, is split | ||
8 | by that makefile into text and data binary files, vmlinux.text and | ||
9 | vmlinux.data. | ||
10 | |||
11 | Those files together with a ROM filesystem can be catted together and | ||
12 | burned into a flash or executed directly at the DRAM origin. | ||
13 | |||
14 | They can also be catted together and compressed with gzip, which is what | ||
15 | happens in this makefile. Together they make up piggy.img. | ||
16 | |||
17 | The decompressor is built into the file decompress.o. It is turned into | ||
18 | the binary file decompress.bin, which is catted together with piggy.img | ||
19 | into the file vmlinuz. It can be executed in an arbitrary place in flash. | ||
20 | |||
21 | Be careful - it assumes some things about free locations in DRAM. It | ||
22 | assumes the DRAM starts at 0x40000000 and that it is at least 8 MB, | ||
23 | so it puts its code at 0x40700000, and initial stack at 0x40800000. | ||
24 | |||
25 | -Bjorn | ||
diff --git a/arch/cris/arch-v10/boot/compressed/decompress.ld b/arch/cris/arch-v10/boot/compressed/decompress.ld new file mode 100644 index 000000000000..0b0a14fe6177 --- /dev/null +++ b/arch/cris/arch-v10/boot/compressed/decompress.ld | |||
@@ -0,0 +1,29 @@ | |||
1 | OUTPUT_FORMAT(elf32-us-cris) | ||
2 | |||
3 | MEMORY | ||
4 | { | ||
5 | dram : ORIGIN = 0x40700000, | ||
6 | LENGTH = 0x00100000 | ||
7 | } | ||
8 | |||
9 | SECTIONS | ||
10 | { | ||
11 | .text : | ||
12 | { | ||
13 | _stext = . ; | ||
14 | *(.text) | ||
15 | *(.rodata) | ||
16 | *(.rodata.*) | ||
17 | _etext = . ; | ||
18 | } > dram | ||
19 | .data : | ||
20 | { | ||
21 | *(.data) | ||
22 | _edata = . ; | ||
23 | } > dram | ||
24 | .bss : | ||
25 | { | ||
26 | *(.bss) | ||
27 | _end = ALIGN( 0x10 ) ; | ||
28 | } > dram | ||
29 | } | ||
diff --git a/arch/cris/arch-v10/boot/compressed/head.S b/arch/cris/arch-v10/boot/compressed/head.S new file mode 100644 index 000000000000..4cbdd4b1d9d6 --- /dev/null +++ b/arch/cris/arch-v10/boot/compressed/head.S | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * arch/cris/boot/compressed/head.S | ||
3 | * | ||
4 | * Copyright (C) 1999, 2001 Axis Communications AB | ||
5 | * | ||
6 | * Code that sets up the DRAM registers, calls the | ||
7 | * decompressor to unpack the piggybacked kernel, and jumps. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #define ASSEMBLER_MACROS_ONLY | ||
13 | #include <asm/arch/sv_addr_ag.h> | ||
14 | |||
15 | #define RAM_INIT_MAGIC 0x56902387 | ||
16 | |||
17 | ;; Exported symbols | ||
18 | |||
19 | .globl _input_data | ||
20 | |||
21 | |||
22 | .text | ||
23 | |||
24 | nop | ||
25 | di | ||
26 | |||
27 | ;; We need to initialze DRAM registers before we start using the DRAM | ||
28 | |||
29 | cmp.d RAM_INIT_MAGIC, r8 ; Already initialized? | ||
30 | beq dram_init_finished | ||
31 | nop | ||
32 | |||
33 | #include "../../lib/dram_init.S" | ||
34 | |||
35 | dram_init_finished: | ||
36 | |||
37 | ;; Initiate the PA and PB ports | ||
38 | |||
39 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, r0 | ||
40 | move.b r0, [R_PORT_PA_DATA] | ||
41 | |||
42 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, r0 | ||
43 | move.b r0, [R_PORT_PA_DIR] | ||
44 | |||
45 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, r0 | ||
46 | move.b r0, [R_PORT_PB_DATA] | ||
47 | |||
48 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, r0 | ||
49 | move.b r0, [R_PORT_PB_DIR] | ||
50 | |||
51 | ;; Setup the stack to a suitably high address. | ||
52 | ;; We assume 8 MB is the minimum DRAM in an eLinux | ||
53 | ;; product and put the sp at the top for now. | ||
54 | |||
55 | move.d 0x40800000, sp | ||
56 | |||
57 | ;; Figure out where the compressed piggyback image is | ||
58 | ;; in the flash (since we wont try to copy it to DRAM | ||
59 | ;; before unpacking). It is at _edata, but in flash. | ||
60 | ;; Use (_edata - basse) as offset to the current PC. | ||
61 | |||
62 | basse: move.d pc, r5 | ||
63 | and.d 0x7fffffff, r5 ; strip any non-cache bit | ||
64 | subq 2, r5 ; compensate for the move.d pc instr | ||
65 | move.d r5, r0 ; save for later - flash address of 'basse' | ||
66 | add.d _edata, r5 | ||
67 | sub.d basse, r5 ; r5 = flash address of '_edata' | ||
68 | |||
69 | ;; Copy text+data to DRAM | ||
70 | |||
71 | move.d basse, r1 ; destination | ||
72 | move.d _edata, r2 ; end destination | ||
73 | 1: move.w [r0+], r3 | ||
74 | move.w r3, [r1+] | ||
75 | cmp.d r2, r1 | ||
76 | bcs 1b | ||
77 | nop | ||
78 | |||
79 | move.d r5, [_input_data] ; for the decompressor | ||
80 | |||
81 | |||
82 | ;; Clear the decompressors BSS (between _edata and _end) | ||
83 | |||
84 | moveq 0, r0 | ||
85 | move.d _edata, r1 | ||
86 | move.d _end, r2 | ||
87 | 1: move.w r0, [r1+] | ||
88 | cmp.d r2, r1 | ||
89 | bcs 1b | ||
90 | nop | ||
91 | |||
92 | ;; Do the decompression and save compressed size in _inptr | ||
93 | |||
94 | jsr _decompress_kernel | ||
95 | |||
96 | ;; Put start address of root partition in r9 so the kernel can use it | ||
97 | ;; when mounting from flash | ||
98 | |||
99 | move.d [_input_data], r9 ; flash address of compressed kernel | ||
100 | add.d [_inptr], r9 ; size of compressed kernel | ||
101 | |||
102 | ;; Enter the decompressed kernel | ||
103 | move.d RAM_INIT_MAGIC, r8 ; Tell kernel that DRAM is initialized | ||
104 | jump 0x40004000 ; kernel is linked to this address | ||
105 | |||
106 | .data | ||
107 | |||
108 | _input_data: | ||
109 | .dword 0 ; used by the decompressor | ||
110 | |||
111 | #include "../../lib/hw_settings.S" | ||
diff --git a/arch/cris/arch-v10/boot/compressed/misc.c b/arch/cris/arch-v10/boot/compressed/misc.c new file mode 100644 index 000000000000..1b5e83f1f846 --- /dev/null +++ b/arch/cris/arch-v10/boot/compressed/misc.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * misc.c | ||
3 | * | ||
4 | * $Id: misc.c,v 1.6 2003/10/27 08:04:31 starvik Exp $ | ||
5 | * | ||
6 | * This is a collection of several routines from gzip-1.0.3 | ||
7 | * adapted for Linux. | ||
8 | * | ||
9 | * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 | ||
10 | * puts by Nick Holloway 1993, better puts by Martin Mares 1995 | ||
11 | * adoptation for Linux/CRIS Axis Communications AB, 1999 | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | /* where the piggybacked kernel image expects itself to live. | ||
16 | * it is the same address we use when we network load an uncompressed | ||
17 | * image into DRAM, and it is the address the kernel is linked to live | ||
18 | * at by vmlinux.lds.S | ||
19 | */ | ||
20 | |||
21 | #define KERNEL_LOAD_ADR 0x40004000 | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | |||
25 | #include <linux/types.h> | ||
26 | #include <asm/arch/svinto.h> | ||
27 | |||
28 | /* | ||
29 | * gzip declarations | ||
30 | */ | ||
31 | |||
32 | #define OF(args) args | ||
33 | #define STATIC static | ||
34 | |||
35 | void* memset(void* s, int c, size_t n); | ||
36 | void* memcpy(void* __dest, __const void* __src, | ||
37 | size_t __n); | ||
38 | |||
39 | #define memzero(s, n) memset ((s), 0, (n)) | ||
40 | |||
41 | |||
42 | typedef unsigned char uch; | ||
43 | typedef unsigned short ush; | ||
44 | typedef unsigned long ulg; | ||
45 | |||
46 | #define WSIZE 0x8000 /* Window size must be at least 32k, */ | ||
47 | /* and a power of two */ | ||
48 | |||
49 | static uch *inbuf; /* input buffer */ | ||
50 | static uch window[WSIZE]; /* Sliding window buffer */ | ||
51 | |||
52 | unsigned inptr = 0; /* index of next byte to be processed in inbuf | ||
53 | * After decompression it will contain the | ||
54 | * compressed size, and head.S will read it. | ||
55 | */ | ||
56 | |||
57 | static unsigned outcnt = 0; /* bytes in output buffer */ | ||
58 | |||
59 | /* gzip flag byte */ | ||
60 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ | ||
61 | #define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ | ||
62 | #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ | ||
63 | #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ | ||
64 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | ||
65 | #define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ | ||
66 | #define RESERVED 0xC0 /* bit 6,7: reserved */ | ||
67 | |||
68 | #define get_byte() inbuf[inptr++] | ||
69 | |||
70 | /* Diagnostic functions */ | ||
71 | #ifdef DEBUG | ||
72 | # define Assert(cond,msg) {if(!(cond)) error(msg);} | ||
73 | # define Trace(x) fprintf x | ||
74 | # define Tracev(x) {if (verbose) fprintf x ;} | ||
75 | # define Tracevv(x) {if (verbose>1) fprintf x ;} | ||
76 | # define Tracec(c,x) {if (verbose && (c)) fprintf x ;} | ||
77 | # define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} | ||
78 | #else | ||
79 | # define Assert(cond,msg) | ||
80 | # define Trace(x) | ||
81 | # define Tracev(x) | ||
82 | # define Tracevv(x) | ||
83 | # define Tracec(c,x) | ||
84 | # define Tracecv(c,x) | ||
85 | #endif | ||
86 | |||
87 | static int fill_inbuf(void); | ||
88 | static void flush_window(void); | ||
89 | static void error(char *m); | ||
90 | static void gzip_mark(void **); | ||
91 | static void gzip_release(void **); | ||
92 | |||
93 | extern char *input_data; /* lives in head.S */ | ||
94 | |||
95 | static long bytes_out = 0; | ||
96 | static uch *output_data; | ||
97 | static unsigned long output_ptr = 0; | ||
98 | |||
99 | static void *malloc(int size); | ||
100 | static void free(void *where); | ||
101 | static void error(char *m); | ||
102 | static void gzip_mark(void **); | ||
103 | static void gzip_release(void **); | ||
104 | |||
105 | static void puts(const char *); | ||
106 | |||
107 | /* the "heap" is put directly after the BSS ends, at end */ | ||
108 | |||
109 | extern int end; | ||
110 | static long free_mem_ptr = (long)&end; | ||
111 | |||
112 | #include "../../../../../lib/inflate.c" | ||
113 | |||
114 | static void *malloc(int size) | ||
115 | { | ||
116 | void *p; | ||
117 | |||
118 | if (size <0) error("Malloc error"); | ||
119 | |||
120 | free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ | ||
121 | |||
122 | p = (void *)free_mem_ptr; | ||
123 | free_mem_ptr += size; | ||
124 | |||
125 | return p; | ||
126 | } | ||
127 | |||
128 | static void free(void *where) | ||
129 | { /* Don't care */ | ||
130 | } | ||
131 | |||
132 | static void gzip_mark(void **ptr) | ||
133 | { | ||
134 | *ptr = (void *) free_mem_ptr; | ||
135 | } | ||
136 | |||
137 | static void gzip_release(void **ptr) | ||
138 | { | ||
139 | free_mem_ptr = (long) *ptr; | ||
140 | } | ||
141 | |||
142 | /* decompressor info and error messages to serial console */ | ||
143 | |||
144 | static void | ||
145 | puts(const char *s) | ||
146 | { | ||
147 | #ifndef CONFIG_ETRAX_DEBUG_PORT_NULL | ||
148 | while(*s) { | ||
149 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | ||
150 | while(!(*R_SERIAL0_STATUS & (1 << 5))) ; | ||
151 | *R_SERIAL0_TR_DATA = *s++; | ||
152 | #endif | ||
153 | #ifdef CONFIG_ETRAX_DEBUG_PORT1 | ||
154 | while(!(*R_SERIAL1_STATUS & (1 << 5))) ; | ||
155 | *R_SERIAL1_TR_DATA = *s++; | ||
156 | #endif | ||
157 | #ifdef CONFIG_ETRAX_DEBUG_PORT2 | ||
158 | while(!(*R_SERIAL2_STATUS & (1 << 5))) ; | ||
159 | *R_SERIAL2_TR_DATA = *s++; | ||
160 | #endif | ||
161 | #ifdef CONFIG_ETRAX_DEBUG_PORT3 | ||
162 | while(!(*R_SERIAL3_STATUS & (1 << 5))) ; | ||
163 | *R_SERIAL3_TR_DATA = *s++; | ||
164 | #endif | ||
165 | } | ||
166 | #endif | ||
167 | } | ||
168 | |||
169 | void* | ||
170 | memset(void* s, int c, size_t n) | ||
171 | { | ||
172 | int i; | ||
173 | char *ss = (char*)s; | ||
174 | |||
175 | for (i=0;i<n;i++) ss[i] = c; | ||
176 | } | ||
177 | |||
178 | void* | ||
179 | memcpy(void* __dest, __const void* __src, | ||
180 | size_t __n) | ||
181 | { | ||
182 | int i; | ||
183 | char *d = (char *)__dest, *s = (char *)__src; | ||
184 | |||
185 | for (i=0;i<__n;i++) d[i] = s[i]; | ||
186 | } | ||
187 | |||
188 | /* =========================================================================== | ||
189 | * Write the output window window[0..outcnt-1] and update crc and bytes_out. | ||
190 | * (Used for the decompressed data only.) | ||
191 | */ | ||
192 | |||
193 | static void | ||
194 | flush_window() | ||
195 | { | ||
196 | ulg c = crc; /* temporary variable */ | ||
197 | unsigned n; | ||
198 | uch *in, *out, ch; | ||
199 | |||
200 | in = window; | ||
201 | out = &output_data[output_ptr]; | ||
202 | for (n = 0; n < outcnt; n++) { | ||
203 | ch = *out++ = *in++; | ||
204 | c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); | ||
205 | } | ||
206 | crc = c; | ||
207 | bytes_out += (ulg)outcnt; | ||
208 | output_ptr += (ulg)outcnt; | ||
209 | outcnt = 0; | ||
210 | } | ||
211 | |||
212 | static void | ||
213 | error(char *x) | ||
214 | { | ||
215 | puts("\n\n"); | ||
216 | puts(x); | ||
217 | puts("\n\n -- System halted\n"); | ||
218 | |||
219 | while(1); /* Halt */ | ||
220 | } | ||
221 | |||
222 | void | ||
223 | setup_normal_output_buffer() | ||
224 | { | ||
225 | output_data = (char *)KERNEL_LOAD_ADR; | ||
226 | } | ||
227 | |||
228 | void | ||
229 | decompress_kernel() | ||
230 | { | ||
231 | char revision; | ||
232 | |||
233 | /* input_data is set in head.S */ | ||
234 | inbuf = input_data; | ||
235 | |||
236 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | ||
237 | *R_SERIAL0_XOFF = 0; | ||
238 | *R_SERIAL0_BAUD = 0x99; | ||
239 | *R_SERIAL0_TR_CTRL = 0x40; | ||
240 | #endif | ||
241 | #ifdef CONFIG_ETRAX_DEBUG_PORT1 | ||
242 | *R_SERIAL1_XOFF = 0; | ||
243 | *R_SERIAL1_BAUD = 0x99; | ||
244 | *R_SERIAL1_TR_CTRL = 0x40; | ||
245 | #endif | ||
246 | #ifdef CONFIG_ETRAX_DEBUG_PORT2 | ||
247 | *R_GEN_CONFIG = 0x08; | ||
248 | *R_SERIAL2_XOFF = 0; | ||
249 | *R_SERIAL2_BAUD = 0x99; | ||
250 | *R_SERIAL2_TR_CTRL = 0x40; | ||
251 | #endif | ||
252 | #ifdef CONFIG_ETRAX_DEBUG_PORT3 | ||
253 | *R_GEN_CONFIG = 0x100; | ||
254 | *R_SERIAL3_XOFF = 0; | ||
255 | *R_SERIAL3_BAUD = 0x99; | ||
256 | *R_SERIAL3_TR_CTRL = 0x40; | ||
257 | #endif | ||
258 | |||
259 | setup_normal_output_buffer(); | ||
260 | |||
261 | makecrc(); | ||
262 | |||
263 | __asm__ volatile ("move vr,%0" : "=rm" (revision)); | ||
264 | if (revision < 10) | ||
265 | { | ||
266 | puts("You need an ETRAX 100LX to run linux 2.6\n"); | ||
267 | while(1); | ||
268 | } | ||
269 | |||
270 | puts("Uncompressing Linux...\n"); | ||
271 | gunzip(); | ||
272 | puts("Done. Now booting the kernel.\n"); | ||
273 | } | ||
diff --git a/arch/cris/arch-v10/boot/rescue/Makefile b/arch/cris/arch-v10/boot/rescue/Makefile new file mode 100644 index 000000000000..e9f2ba2ad02c --- /dev/null +++ b/arch/cris/arch-v10/boot/rescue/Makefile | |||
@@ -0,0 +1,55 @@ | |||
1 | # | ||
2 | # Makefile for rescue code | ||
3 | # | ||
4 | ifndef TOPDIR | ||
5 | TOPDIR = ../../../.. | ||
6 | endif | ||
7 | CC = gcc-cris -mlinux -I $(TOPDIR)/include | ||
8 | CFLAGS = -O2 | ||
9 | LD = gcc-cris -mlinux -nostdlib | ||
10 | OBJCOPY = objcopy-cris | ||
11 | OBJCOPYFLAGS = -O binary --remove-section=.bss | ||
12 | |||
13 | all: rescue.bin testrescue.bin kimagerescue.bin | ||
14 | |||
15 | rescue: rescue.bin | ||
16 | # do nothing | ||
17 | |||
18 | rescue.bin: head.o | ||
19 | $(LD) -T rescue.ld -o rescue.o head.o | ||
20 | $(OBJCOPY) $(OBJCOPYFLAGS) rescue.o rescue.bin | ||
21 | cp rescue.bin $(TOPDIR) | ||
22 | |||
23 | testrescue.bin: testrescue.o | ||
24 | $(OBJCOPY) $(OBJCOPYFLAGS) testrescue.o tr.bin | ||
25 | # Pad it to 784 bytes | ||
26 | dd if=/dev/zero of=tmp2423 bs=1 count=784 | ||
27 | cat tr.bin tmp2423 >testrescue_tmp.bin | ||
28 | dd if=testrescue_tmp.bin of=testrescue.bin bs=1 count=784 | ||
29 | rm tr.bin tmp2423 testrescue_tmp.bin | ||
30 | |||
31 | kimagerescue.bin: kimagerescue.o | ||
32 | $(OBJCOPY) $(OBJCOPYFLAGS) kimagerescue.o ktr.bin | ||
33 | # Pad it to 784 bytes, that's what the rescue loader expects | ||
34 | dd if=/dev/zero of=tmp2423 bs=1 count=784 | ||
35 | cat ktr.bin tmp2423 >kimagerescue_tmp.bin | ||
36 | dd if=kimagerescue_tmp.bin of=kimagerescue.bin bs=1 count=784 | ||
37 | rm ktr.bin tmp2423 kimagerescue_tmp.bin | ||
38 | |||
39 | head.o: head.S | ||
40 | $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o | ||
41 | |||
42 | testrescue.o: testrescue.S | ||
43 | $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o | ||
44 | |||
45 | kimagerescue.o: kimagerescue.S | ||
46 | $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o | ||
47 | |||
48 | clean: | ||
49 | rm -f *.o *.bin | ||
50 | |||
51 | fastdep: | ||
52 | |||
53 | modules: | ||
54 | |||
55 | modules-install: | ||
diff --git a/arch/cris/arch-v10/boot/rescue/head.S b/arch/cris/arch-v10/boot/rescue/head.S new file mode 100644 index 000000000000..8689ea972c46 --- /dev/null +++ b/arch/cris/arch-v10/boot/rescue/head.S | |||
@@ -0,0 +1,333 @@ | |||
1 | /* $Id: head.S,v 1.6 2003/04/09 08:12:43 pkj Exp $ | ||
2 | * | ||
3 | * Rescue code, made to reside at the beginning of the | ||
4 | * flash-memory. when it starts, it checks a partition | ||
5 | * table at the first sector after the rescue sector. | ||
6 | * the partition table was generated by the product builder | ||
7 | * script and contains offsets, lengths, types and checksums | ||
8 | * for each partition that this code should check. | ||
9 | * | ||
10 | * If any of the checksums fail, we assume the flash is so | ||
11 | * corrupt that we cant use it to boot into the ftp flash | ||
12 | * loader, and instead we initialize the serial port to | ||
13 | * receive a flash-loader and new flash image. we dont include | ||
14 | * any flash code here, but just accept a certain amount of | ||
15 | * bytes from the serial port and jump into it. the downloaded | ||
16 | * code is put in the cache. | ||
17 | * | ||
18 | * The partitiontable is designed so that it is transparent to | ||
19 | * code execution - it has a relative branch opcode in the | ||
20 | * beginning that jumps over it. each entry contains extra | ||
21 | * data so we can add stuff later. | ||
22 | * | ||
23 | * Partition table format: | ||
24 | * | ||
25 | * Code transparency: | ||
26 | * | ||
27 | * 2 bytes [opcode 'nop'] | ||
28 | * 2 bytes [opcode 'di'] | ||
29 | * 4 bytes [opcode 'ba <offset>', 8-bit or 16-bit version] | ||
30 | * 2 bytes [opcode 'nop', delay slot] | ||
31 | * | ||
32 | * Table validation (at +10): | ||
33 | * | ||
34 | * 2 bytes [magic/version word for partitiontable - 0xef, 0xbe] | ||
35 | * 2 bytes [length of all entries plus the end marker] | ||
36 | * 4 bytes [checksum for the partitiontable itself] | ||
37 | * | ||
38 | * Entries, each with the following format, last has offset -1: | ||
39 | * | ||
40 | * 4 bytes [offset in bytes, from start of flash] | ||
41 | * 4 bytes [length in bytes of partition] | ||
42 | * 4 bytes [checksum, simple longword sum] | ||
43 | * 2 bytes [partition type] | ||
44 | * 2 bytes [flags, only bit 0 used, ro/rw = 1/0] | ||
45 | * 16 bytes [reserved for future use] | ||
46 | * | ||
47 | * End marker | ||
48 | * | ||
49 | * 4 bytes [-1] | ||
50 | * | ||
51 | * 10 bytes [0, padding] | ||
52 | * | ||
53 | * Bit 0 in flags signifies RW or RO. The rescue code only bothers | ||
54 | * to check the checksum for RO partitions, since the others will | ||
55 | * change their data without updating the checksums. A 1 in bit 0 | ||
56 | * means RO, 0 means RW. That way, it is possible to set a partition | ||
57 | * in RO mode initially, and later mark it as RW, since you can always | ||
58 | * write 0's to the flash. | ||
59 | * | ||
60 | * During the wait for serial input, the status LED will flash so the | ||
61 | * user knows something went wrong. | ||
62 | * | ||
63 | * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB | ||
64 | */ | ||
65 | |||
66 | #include <linux/config.h> | ||
67 | #define ASSEMBLER_MACROS_ONLY | ||
68 | #include <asm/arch/sv_addr_ag.h> | ||
69 | |||
70 | ;; The partitiontable is looked for at the first sector after the boot | ||
71 | ;; sector. Sector size is 65536 bytes in all flashes we use. | ||
72 | |||
73 | #define PTABLE_START CONFIG_ETRAX_PTABLE_SECTOR | ||
74 | #define PTABLE_MAGIC 0xbeef | ||
75 | |||
76 | ;; The normal Etrax100 on-chip boot ROM does serial boot at 0x380000f0. | ||
77 | ;; That is not where we put our downloaded serial boot-code. The length is | ||
78 | ;; enough for downloading code that loads the rest of itself (after | ||
79 | ;; having setup the DRAM etc). It is the same length as the on-chip | ||
80 | ;; ROM loads, so the same host loader can be used to load a rescued | ||
81 | ;; product as well as one booted through the Etrax serial boot code. | ||
82 | |||
83 | #define CODE_START 0x40000000 | ||
84 | #define CODE_LENGTH 784 | ||
85 | |||
86 | #ifdef CONFIG_ETRAX_RESCUE_SER0 | ||
87 | #define SERXOFF R_SERIAL0_XOFF | ||
88 | #define SERBAUD R_SERIAL0_BAUD | ||
89 | #define SERRECC R_SERIAL0_REC_CTRL | ||
90 | #define SERRDAT R_SERIAL0_REC_DATA | ||
91 | #define SERSTAT R_SERIAL0_STATUS | ||
92 | #endif | ||
93 | #ifdef CONFIG_ETRAX_RESCUE_SER1 | ||
94 | #define SERXOFF R_SERIAL1_XOFF | ||
95 | #define SERBAUD R_SERIAL1_BAUD | ||
96 | #define SERRECC R_SERIAL1_REC_CTRL | ||
97 | #define SERRDAT R_SERIAL1_REC_DATA | ||
98 | #define SERSTAT R_SERIAL1_STATUS | ||
99 | #endif | ||
100 | #ifdef CONFIG_ETRAX_RESCUE_SER2 | ||
101 | #define SERXOFF R_SERIAL2_XOFF | ||
102 | #define SERBAUD R_SERIAL2_BAUD | ||
103 | #define SERRECC R_SERIAL2_REC_CTRL | ||
104 | #define SERRDAT R_SERIAL2_REC_DATA | ||
105 | #define SERSTAT R_SERIAL2_STATUS | ||
106 | #endif | ||
107 | #ifdef CONFIG_ETRAX_RESCUE_SER3 | ||
108 | #define SERXOFF R_SERIAL3_XOFF | ||
109 | #define SERBAUD R_SERIAL3_BAUD | ||
110 | #define SERRECC R_SERIAL3_REC_CTRL | ||
111 | #define SERRDAT R_SERIAL3_REC_DATA | ||
112 | #define SERSTAT R_SERIAL3_STATUS | ||
113 | #endif | ||
114 | |||
115 | #define NOP_DI 0xf025050f | ||
116 | #define RAM_INIT_MAGIC 0x56902387 | ||
117 | |||
118 | .text | ||
119 | |||
120 | ;; This is the entry point of the rescue code | ||
121 | ;; 0x80000000 if loaded in flash (as it should be) | ||
122 | ;; since etrax actually starts at address 2 when booting from flash, we | ||
123 | ;; put a nop (2 bytes) here first so we dont accidentally skip the di | ||
124 | |||
125 | nop | ||
126 | di | ||
127 | |||
128 | jump in_cache ; enter cached area instead | ||
129 | in_cache: | ||
130 | |||
131 | ;; first put a jump test to give a possibility of upgrading the rescue code | ||
132 | ;; without erasing/reflashing the sector. we put a longword of -1 here and if | ||
133 | ;; it is not -1, we jump using the value as jump target. since we can always | ||
134 | ;; change 1's to 0's without erasing the sector, it is possible to add new | ||
135 | ;; code after this and altering the jumptarget in an upgrade. | ||
136 | |||
137 | jtcd: move.d [jumptarget], $r0 | ||
138 | cmp.d 0xffffffff, $r0 | ||
139 | beq no_newjump | ||
140 | nop | ||
141 | |||
142 | jump [$r0] | ||
143 | |||
144 | jumptarget: | ||
145 | .dword 0xffffffff ; can be overwritten later to insert new code | ||
146 | |||
147 | no_newjump: | ||
148 | #ifdef CONFIG_ETRAX_ETHERNET | ||
149 | ;; Start MII clock to make sure it is running when tranceiver is reset | ||
150 | move.d 0x3, $r0 ; enable = on, phy = mii_clk | ||
151 | move.d $r0, [R_NETWORK_GEN_CONFIG] | ||
152 | #endif | ||
153 | |||
154 | ;; We need to setup the bus registers before we start using the DRAM | ||
155 | #include "../../lib/dram_init.S" | ||
156 | |||
157 | ;; we now should go through the checksum-table and check the listed | ||
158 | ;; partitions for errors. | ||
159 | |||
160 | move.d PTABLE_START, $r3 | ||
161 | move.d [$r3], $r0 | ||
162 | cmp.d NOP_DI, $r0 ; make sure the nop/di is there... | ||
163 | bne do_rescue | ||
164 | nop | ||
165 | |||
166 | ;; skip the code transparency block (10 bytes). | ||
167 | |||
168 | addq 10, $r3 | ||
169 | |||
170 | ;; check for correct magic | ||
171 | |||
172 | move.w [$r3+], $r0 | ||
173 | cmp.w PTABLE_MAGIC, $r0 | ||
174 | bne do_rescue ; didn't recognize - trig rescue | ||
175 | nop | ||
176 | |||
177 | ;; check for correct ptable checksum | ||
178 | |||
179 | movu.w [$r3+], $r2 ; ptable length | ||
180 | move.d $r2, $r8 ; save for later, length of total ptable | ||
181 | addq 28, $r8 ; account for the rest | ||
182 | move.d [$r3+], $r4 ; ptable checksum | ||
183 | move.d $r3, $r1 | ||
184 | jsr checksum ; r1 source, r2 length, returns in r0 | ||
185 | |||
186 | cmp.d $r0, $r4 | ||
187 | bne do_rescue ; didn't match - trig rescue | ||
188 | nop | ||
189 | |||
190 | ;; ptable is ok. validate each entry. | ||
191 | |||
192 | moveq -1, $r7 | ||
193 | |||
194 | ploop: move.d [$r3+], $r1 ; partition offset (from ptable start) | ||
195 | bne notfirst ; check if it is the partition containing ptable | ||
196 | nop ; yes.. | ||
197 | move.d $r8, $r1 ; for its checksum check, skip the ptable | ||
198 | move.d [$r3+], $r2 ; partition length | ||
199 | sub.d $r8, $r2 ; minus the ptable length | ||
200 | ba bosse | ||
201 | nop | ||
202 | notfirst: | ||
203 | cmp.d -1, $r1 ; the end of the ptable ? | ||
204 | beq flash_ok ; if so, the flash is validated | ||
205 | move.d [$r3+], $r2 ; partition length | ||
206 | bosse: move.d [$r3+], $r5 ; checksum | ||
207 | move.d [$r3+], $r4 ; type and flags | ||
208 | addq 16, $r3 ; skip the reserved bytes | ||
209 | btstq 16, $r4 ; check ro flag | ||
210 | bpl ploop ; rw partition, skip validation | ||
211 | nop | ||
212 | btstq 17, $r4 ; check bootable flag | ||
213 | bpl 1f | ||
214 | nop | ||
215 | move.d $r1, $r7 ; remember boot partition offset | ||
216 | 1: | ||
217 | |||
218 | add.d PTABLE_START, $r1 | ||
219 | |||
220 | jsr checksum ; checksum the partition | ||
221 | |||
222 | cmp.d $r0, $r5 | ||
223 | beq ploop ; checksums matched, go to next entry | ||
224 | nop | ||
225 | |||
226 | ;; otherwise fall through to the rescue code. | ||
227 | |||
228 | do_rescue: | ||
229 | ;; setup port PA and PB default initial directions and data | ||
230 | ;; (so we can flash LEDs, and so that DTR and others are set) | ||
231 | |||
232 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0 | ||
233 | move.b $r0, [R_PORT_PA_DIR] | ||
234 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0 | ||
235 | move.b $r0, [R_PORT_PA_DATA] | ||
236 | |||
237 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0 | ||
238 | move.b $r0, [R_PORT_PB_DIR] | ||
239 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0 | ||
240 | move.b $r0, [R_PORT_PB_DATA] | ||
241 | |||
242 | ;; setup the serial port at 115200 baud | ||
243 | |||
244 | moveq 0, $r0 | ||
245 | move.d $r0, [SERXOFF] | ||
246 | |||
247 | move.b 0x99, $r0 | ||
248 | move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit and receive | ||
249 | |||
250 | move.b 0x40, $r0 ; rec enable | ||
251 | move.b $r0, [SERRECC] | ||
252 | |||
253 | moveq 0, $r1 ; "timer" to clock out a LED red flash | ||
254 | move.d CODE_START, $r3 ; destination counter | ||
255 | movu.w CODE_LENGTH, $r4; length | ||
256 | |||
257 | wait_ser: | ||
258 | addq 1, $r1 | ||
259 | #ifndef CONFIG_ETRAX_NO_LEDS | ||
260 | #ifdef CONFIG_ETRAX_PA_LEDS | ||
261 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2 | ||
262 | #endif | ||
263 | #ifdef CONFIG_ETRAX_PB_LEDS | ||
264 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2 | ||
265 | #endif | ||
266 | move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0 | ||
267 | btstq 16, $r1 | ||
268 | bpl 1f | ||
269 | nop | ||
270 | or.d $r0, $r2 ; set bit | ||
271 | ba 2f | ||
272 | nop | ||
273 | 1: not $r0 ; clear bit | ||
274 | and.d $r0, $r2 | ||
275 | 2: | ||
276 | #ifdef CONFIG_ETRAX_PA_LEDS | ||
277 | move.b $r2, [R_PORT_PA_DATA] | ||
278 | #endif | ||
279 | #ifdef CONFIG_ETRAX_PB_LEDS | ||
280 | move.b $r2, [R_PORT_PB_DATA] | ||
281 | #endif | ||
282 | #ifdef CONFIG_ETRAX_90000000_LEDS | ||
283 | move.b $r2, [0x90000000] | ||
284 | #endif | ||
285 | #endif | ||
286 | |||
287 | ;; check if we got something on the serial port | ||
288 | |||
289 | move.b [SERSTAT], $r0 | ||
290 | btstq 0, $r0 ; data_avail | ||
291 | bpl wait_ser | ||
292 | nop | ||
293 | |||
294 | ;; got something - copy the byte and loop | ||
295 | |||
296 | move.b [SERRDAT], $r0 | ||
297 | move.b $r0, [$r3+] | ||
298 | |||
299 | subq 1, $r4 ; decrease length | ||
300 | bne wait_ser | ||
301 | nop | ||
302 | |||
303 | ;; jump into downloaded code | ||
304 | |||
305 | move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is initialized | ||
306 | jump CODE_START | ||
307 | |||
308 | flash_ok: | ||
309 | ;; check r7, which contains either -1 or the partition to boot from | ||
310 | |||
311 | cmp.d -1, $r7 | ||
312 | bne 1f | ||
313 | nop | ||
314 | move.d PTABLE_START, $r7; otherwise use the ptable start | ||
315 | 1: | ||
316 | move.d RAM_INIT_MAGIC, $r8 ; Tell next product that DRAM is initialized | ||
317 | jump $r7 ; boot! | ||
318 | |||
319 | |||
320 | ;; Helper subroutines | ||
321 | |||
322 | ;; Will checksum by simple addition | ||
323 | ;; r1 - source | ||
324 | ;; r2 - length in bytes | ||
325 | ;; result will be in r0 | ||
326 | checksum: | ||
327 | moveq 0, $r0 | ||
328 | 1: addu.b [$r1+], $r0 | ||
329 | subq 1, $r2 | ||
330 | bne 1b | ||
331 | nop | ||
332 | ret | ||
333 | nop | ||
diff --git a/arch/cris/arch-v10/boot/rescue/kimagerescue.S b/arch/cris/arch-v10/boot/rescue/kimagerescue.S new file mode 100644 index 000000000000..264bf7afc9ad --- /dev/null +++ b/arch/cris/arch-v10/boot/rescue/kimagerescue.S | |||
@@ -0,0 +1,144 @@ | |||
1 | /* $Id: kimagerescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * | ||
3 | * Rescue code to be prepended on a kimage and copied to the | ||
4 | * rescue serial port. | ||
5 | * This is called from the rescue code, it will copy received data to | ||
6 | * 4004000 and after a timeout jump to it. | ||
7 | */ | ||
8 | |||
9 | #include <linux/config.h> | ||
10 | #define ASSEMBLER_MACROS_ONLY | ||
11 | #include <asm/sv_addr_ag.h> | ||
12 | |||
13 | #define CODE_START 0x40004000 | ||
14 | #define CODE_LENGTH 784 | ||
15 | #define TIMEOUT_VALUE 1000 | ||
16 | |||
17 | |||
18 | #ifdef CONFIG_ETRAX_RESCUE_SER0 | ||
19 | #define SERXOFF R_SERIAL0_XOFF | ||
20 | #define SERBAUD R_SERIAL0_BAUD | ||
21 | #define SERRECC R_SERIAL0_REC_CTRL | ||
22 | #define SERRDAT R_SERIAL0_REC_DATA | ||
23 | #define SERSTAT R_SERIAL0_STATUS | ||
24 | #endif | ||
25 | #ifdef CONFIG_ETRAX_RESCUE_SER1 | ||
26 | #define SERXOFF R_SERIAL1_XOFF | ||
27 | #define SERBAUD R_SERIAL1_BAUD | ||
28 | #define SERRECC R_SERIAL1_REC_CTRL | ||
29 | #define SERRDAT R_SERIAL1_REC_DATA | ||
30 | #define SERSTAT R_SERIAL1_STATUS | ||
31 | #endif | ||
32 | #ifdef CONFIG_ETRAX_RESCUE_SER2 | ||
33 | #define SERXOFF R_SERIAL2_XOFF | ||
34 | #define SERBAUD R_SERIAL2_BAUD | ||
35 | #define SERRECC R_SERIAL2_REC_CTRL | ||
36 | #define SERRDAT R_SERIAL2_REC_DATA | ||
37 | #define SERSTAT R_SERIAL2_STATUS | ||
38 | #endif | ||
39 | #ifdef CONFIG_ETRAX_RESCUE_SER3 | ||
40 | #define SERXOFF R_SERIAL3_XOFF | ||
41 | #define SERBAUD R_SERIAL3_BAUD | ||
42 | #define SERRECC R_SERIAL3_REC_CTRL | ||
43 | #define SERRDAT R_SERIAL3_REC_DATA | ||
44 | #define SERSTAT R_SERIAL3_STATUS | ||
45 | #endif | ||
46 | |||
47 | .text | ||
48 | ;; This is the entry point of the rescue code | ||
49 | ;; 0x80000000 if loaded in flash (as it should be) | ||
50 | ;; since etrax actually starts at address 2 when booting from flash, we | ||
51 | ;; put a nop (2 bytes) here first so we dont accidentally skip the di | ||
52 | |||
53 | nop | ||
54 | di | ||
55 | #ifndef CONFIG_SVINTO_SIM | ||
56 | ;; setup port PA and PB default initial directions and data | ||
57 | ;; (so we can flash LEDs, and so that DTR and others are set) | ||
58 | |||
59 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR, $r0 | ||
60 | move.b $r0, [R_PORT_PA_DIR] | ||
61 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r0 | ||
62 | move.b $r0, [R_PORT_PA_DATA] | ||
63 | |||
64 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR, $r0 | ||
65 | move.b $r0, [R_PORT_PB_DIR] | ||
66 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r0 | ||
67 | move.b $r0, [R_PORT_PB_DATA] | ||
68 | |||
69 | ;; We need to setup the bus registers before we start using the DRAM | ||
70 | #include "../../lib/dram_init.S" | ||
71 | |||
72 | #endif | ||
73 | ;; Setup the stack to a suitably high address. | ||
74 | ;; We assume 8 MB is the minimum DRAM in an eLinux | ||
75 | ;; product and put the sp at the top for now. | ||
76 | |||
77 | move.d 0x40800000, $sp | ||
78 | |||
79 | ;; setup the serial port at 115200 baud | ||
80 | |||
81 | moveq 0, $r0 | ||
82 | move.d $r0, [SERXOFF] | ||
83 | |||
84 | move.b 0x99, $r0 | ||
85 | move.b $r0, [SERBAUD] ; 115.2kbaud for both transmit and receive | ||
86 | |||
87 | move.b 0x40, $r0 ; rec enable | ||
88 | move.b $r0, [SERRECC] | ||
89 | |||
90 | |||
91 | moveq 0, $r1 ; "timer" to clock out a LED red flash | ||
92 | move.d CODE_START, $r3 ; destination counter | ||
93 | move.d CODE_LENGTH, $r4 ; length | ||
94 | move.d TIMEOUT_VALUE, $r5 ; "timeout" until jump | ||
95 | |||
96 | wait_ser: | ||
97 | addq 1, $r1 | ||
98 | subq 1, $r5 ; decrease timeout | ||
99 | beq jump_start ; timed out | ||
100 | nop | ||
101 | #ifndef CONFIG_ETRAX_NO_LEDS | ||
102 | #ifdef CONFIG_ETRAX_PA_LEDS | ||
103 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA, $r2 | ||
104 | #endif | ||
105 | #ifdef CONFIG_ETRAX_PB_LEDS | ||
106 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA, $r2 | ||
107 | #endif | ||
108 | move.d (1 << CONFIG_ETRAX_LED1R) | (1 << CONFIG_ETRAX_LED2R), $r0 | ||
109 | btstq 16, $r1 | ||
110 | bpl 1f | ||
111 | nop | ||
112 | or.d $r0, $r2 ; set bit | ||
113 | ba 2f | ||
114 | nop | ||
115 | 1: not $r0 ; clear bit | ||
116 | and.d $r0, $r2 | ||
117 | 2: | ||
118 | #ifdef CONFIG_ETRAX_PA_LEDS | ||
119 | move.b $r2, [R_PORT_PA_DATA] | ||
120 | #endif | ||
121 | #ifdef CONFIG_ETRAX_PB_LEDS | ||
122 | move.b $r2, [R_PORT_PB_DATA] | ||
123 | #endif | ||
124 | #endif | ||
125 | |||
126 | ;; check if we got something on the serial port | ||
127 | |||
128 | move.b [SERSTAT], $r0 | ||
129 | btstq 0, $r0 ; data_avail | ||
130 | bpl wait_ser | ||
131 | nop | ||
132 | |||
133 | ;; got something - copy the byte and loop | ||
134 | |||
135 | move.b [SERRDAT], $r0 | ||
136 | move.b $r0, [$r3+] | ||
137 | move.d TIMEOUT_VALUE, $r5 ; reset "timeout" | ||
138 | subq 1, $r4 ; decrease length | ||
139 | bne wait_ser | ||
140 | nop | ||
141 | jump_start: | ||
142 | ;; jump into downloaded code | ||
143 | |||
144 | jump CODE_START | ||
diff --git a/arch/cris/arch-v10/boot/rescue/rescue.ld b/arch/cris/arch-v10/boot/rescue/rescue.ld new file mode 100644 index 000000000000..0b52a9490db6 --- /dev/null +++ b/arch/cris/arch-v10/boot/rescue/rescue.ld | |||
@@ -0,0 +1,20 @@ | |||
1 | MEMORY | ||
2 | { | ||
3 | flash : ORIGIN = 0x00000000, | ||
4 | LENGTH = 0x00100000 | ||
5 | } | ||
6 | |||
7 | SECTIONS | ||
8 | { | ||
9 | .text : | ||
10 | { | ||
11 | stext = . ; | ||
12 | *(.text) | ||
13 | etext = . ; | ||
14 | } > flash | ||
15 | .data : | ||
16 | { | ||
17 | *(.data) | ||
18 | edata = . ; | ||
19 | } > flash | ||
20 | } | ||
diff --git a/arch/cris/arch-v10/boot/rescue/testrescue.S b/arch/cris/arch-v10/boot/rescue/testrescue.S new file mode 100644 index 000000000000..566a9f341254 --- /dev/null +++ b/arch/cris/arch-v10/boot/rescue/testrescue.S | |||
@@ -0,0 +1,26 @@ | |||
1 | /* $Id: testrescue.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * | ||
3 | * Simple testcode to download by the rescue block. | ||
4 | * Just lits some LEDs to show it was downloaded correctly. | ||
5 | * | ||
6 | * Copyright (C) 1999 Axis Communications AB | ||
7 | */ | ||
8 | |||
9 | #define ASSEMBLER_MACROS_ONLY | ||
10 | #include <asm/sv_addr_ag.h> | ||
11 | |||
12 | .text | ||
13 | |||
14 | nop | ||
15 | nop | ||
16 | moveq -1, $r2 | ||
17 | move.b $r2, [R_PORT_PA_DIR] | ||
18 | moveq 0, $r2 | ||
19 | move.b $r2, [R_PORT_PA_DATA] | ||
20 | |||
21 | endless: | ||
22 | nop | ||
23 | ba endless | ||
24 | nop | ||
25 | |||
26 | |||
diff --git a/arch/cris/arch-v10/boot/tools/build.c b/arch/cris/arch-v10/boot/tools/build.c new file mode 100644 index 000000000000..2f9bbb26d603 --- /dev/null +++ b/arch/cris/arch-v10/boot/tools/build.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * linux/tools/build.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This file builds a disk-image from three different files: | ||
9 | * | ||
10 | * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest | ||
11 | * - setup: 8086 machine code, sets up system parm | ||
12 | * - system: 80386 code for actual system | ||
13 | * | ||
14 | * It does some checking that all files are of the correct type, and | ||
15 | * just writes the result to stdout, removing headers and padding to | ||
16 | * the right amount. It also writes some system data to stderr. | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * Changes by tytso to allow root device specification | ||
21 | * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 | ||
22 | * Cross compiling fixes by Gertjan van Wingerde, July 1996 | ||
23 | */ | ||
24 | |||
25 | #include <stdio.h> /* fprintf */ | ||
26 | #include <string.h> | ||
27 | #include <stdlib.h> /* contains exit */ | ||
28 | #include <sys/types.h> /* unistd.h needs this */ | ||
29 | #include <sys/stat.h> | ||
30 | #include <sys/sysmacros.h> | ||
31 | #include <unistd.h> /* contains read/write */ | ||
32 | #include <fcntl.h> | ||
33 | #include <linux/a.out.h> | ||
34 | #include <errno.h> | ||
35 | |||
36 | #define MINIX_HEADER 32 | ||
37 | |||
38 | #define N_MAGIC_OFFSET 1024 | ||
39 | #ifndef __BFD__ | ||
40 | static int GCC_HEADER = sizeof(struct exec); | ||
41 | #endif | ||
42 | |||
43 | #ifdef __BIG_KERNEL__ | ||
44 | #define SYS_SIZE 0xffff | ||
45 | #else | ||
46 | #define SYS_SIZE DEF_SYSSIZE | ||
47 | #endif | ||
48 | |||
49 | #define DEFAULT_MAJOR_ROOT 0 | ||
50 | #define DEFAULT_MINOR_ROOT 0 | ||
51 | |||
52 | /* max nr of sectors of setup: don't change unless you also change | ||
53 | * bootsect etc */ | ||
54 | #define SETUP_SECTS 4 | ||
55 | |||
56 | #define STRINGIFY(x) #x | ||
57 | |||
58 | typedef union { | ||
59 | int i; | ||
60 | long l; | ||
61 | short s[2]; | ||
62 | char b[4]; | ||
63 | } conv; | ||
64 | |||
65 | long intel_long(long l) | ||
66 | { | ||
67 | conv t; | ||
68 | |||
69 | t.b[0] = l & 0xff; l >>= 8; | ||
70 | t.b[1] = l & 0xff; l >>= 8; | ||
71 | t.b[2] = l & 0xff; l >>= 8; | ||
72 | t.b[3] = l & 0xff; l >>= 8; | ||
73 | return t.l; | ||
74 | } | ||
75 | |||
76 | int intel_int(int i) | ||
77 | { | ||
78 | conv t; | ||
79 | |||
80 | t.b[0] = i & 0xff; i >>= 8; | ||
81 | t.b[1] = i & 0xff; i >>= 8; | ||
82 | t.b[2] = i & 0xff; i >>= 8; | ||
83 | t.b[3] = i & 0xff; i >>= 8; | ||
84 | return t.i; | ||
85 | } | ||
86 | |||
87 | short intel_short(short l) | ||
88 | { | ||
89 | conv t; | ||
90 | |||
91 | t.b[0] = l & 0xff; l >>= 8; | ||
92 | t.b[1] = l & 0xff; l >>= 8; | ||
93 | return t.s[0]; | ||
94 | } | ||
95 | |||
96 | void die(const char * str) | ||
97 | { | ||
98 | fprintf(stderr,"%s\n",str); | ||
99 | exit(1); | ||
100 | } | ||
101 | |||
102 | void usage(void) | ||
103 | { | ||
104 | die("Usage: build bootsect setup system [rootdev] [> image]"); | ||
105 | } | ||
106 | |||
107 | int main(int argc, char ** argv) | ||
108 | { | ||
109 | int i,c,id,sz,tmp_int; | ||
110 | unsigned long sys_size, tmp_long; | ||
111 | char buf[1024]; | ||
112 | #ifndef __BFD__ | ||
113 | struct exec *ex = (struct exec *)buf; | ||
114 | #endif | ||
115 | char major_root, minor_root; | ||
116 | struct stat sb; | ||
117 | unsigned char setup_sectors; | ||
118 | |||
119 | if ((argc < 4) || (argc > 5)) | ||
120 | usage(); | ||
121 | if (argc > 4) { | ||
122 | if (!strcmp(argv[4], "CURRENT")) { | ||
123 | if (stat("/", &sb)) { | ||
124 | perror("/"); | ||
125 | die("Couldn't stat /"); | ||
126 | } | ||
127 | major_root = major(sb.st_dev); | ||
128 | minor_root = minor(sb.st_dev); | ||
129 | } else if (strcmp(argv[4], "FLOPPY")) { | ||
130 | if (stat(argv[4], &sb)) { | ||
131 | perror(argv[4]); | ||
132 | die("Couldn't stat root device."); | ||
133 | } | ||
134 | major_root = major(sb.st_rdev); | ||
135 | minor_root = minor(sb.st_rdev); | ||
136 | } else { | ||
137 | major_root = 0; | ||
138 | minor_root = 0; | ||
139 | } | ||
140 | } else { | ||
141 | major_root = DEFAULT_MAJOR_ROOT; | ||
142 | minor_root = DEFAULT_MINOR_ROOT; | ||
143 | } | ||
144 | fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); | ||
145 | for (i=0;i<sizeof buf; i++) buf[i]=0; | ||
146 | if ((id=open(argv[1],O_RDONLY,0))<0) | ||
147 | die("Unable to open 'boot'"); | ||
148 | if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) | ||
149 | die("Unable to read header of 'boot'"); | ||
150 | if (((long *) buf)[0]!=intel_long(0x04100301)) | ||
151 | die("Non-Minix header of 'boot'"); | ||
152 | if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) | ||
153 | die("Non-Minix header of 'boot'"); | ||
154 | if (((long *) buf)[3] != 0) | ||
155 | die("Illegal data segment in 'boot'"); | ||
156 | if (((long *) buf)[4] != 0) | ||
157 | die("Illegal bss in 'boot'"); | ||
158 | if (((long *) buf)[5] != 0) | ||
159 | die("Non-Minix header of 'boot'"); | ||
160 | if (((long *) buf)[7] != 0) | ||
161 | die("Illegal symbol table in 'boot'"); | ||
162 | i=read(id,buf,sizeof buf); | ||
163 | fprintf(stderr,"Boot sector %d bytes.\n",i); | ||
164 | if (i != 512) | ||
165 | die("Boot block must be exactly 512 bytes"); | ||
166 | if ((*(unsigned short *)(buf+510)) != (unsigned short)intel_short(0xAA55)) | ||
167 | die("Boot block hasn't got boot flag (0xAA55)"); | ||
168 | buf[508] = (char) minor_root; | ||
169 | buf[509] = (char) major_root; | ||
170 | i=write(1,buf,512); | ||
171 | if (i!=512) | ||
172 | die("Write call failed"); | ||
173 | close (id); | ||
174 | |||
175 | if ((id=open(argv[2],O_RDONLY,0))<0) | ||
176 | die("Unable to open 'setup'"); | ||
177 | if (read(id,buf,MINIX_HEADER) != MINIX_HEADER) | ||
178 | die("Unable to read header of 'setup'"); | ||
179 | if (((long *) buf)[0]!=intel_long(0x04100301)) | ||
180 | die("Non-Minix header of 'setup'"); | ||
181 | if (((long *) buf)[1]!=intel_long(MINIX_HEADER)) | ||
182 | die("Non-Minix header of 'setup'"); | ||
183 | if (((long *) buf)[3] != 0) | ||
184 | die("Illegal data segment in 'setup'"); | ||
185 | if (((long *) buf)[4] != 0) | ||
186 | die("Illegal bss in 'setup'"); | ||
187 | if (((long *) buf)[5] != 0) | ||
188 | die("Non-Minix header of 'setup'"); | ||
189 | if (((long *) buf)[7] != 0) | ||
190 | die("Illegal symbol table in 'setup'"); | ||
191 | for (i=0 ; (c=read(id,buf,sizeof buf))>0 ; i+=c ) | ||
192 | #ifdef __BIG_KERNEL__ | ||
193 | { | ||
194 | if (!i) { | ||
195 | /* Working with memcpy because of alignment constraints | ||
196 | on Sparc - Gertjan */ | ||
197 | memcpy(&tmp_long, &buf[2], sizeof(long)); | ||
198 | if (tmp_long != intel_long(0x53726448) ) | ||
199 | die("Wrong magic in loader header of 'setup'"); | ||
200 | memcpy(&tmp_int, &buf[6], sizeof(int)); | ||
201 | if (tmp_int < intel_int(0x200)) | ||
202 | die("Wrong version of loader header of 'setup'"); | ||
203 | buf[0x11] = 1; /* LOADED_HIGH */ | ||
204 | tmp_long = intel_long(0x100000); | ||
205 | memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */ | ||
206 | } | ||
207 | #endif | ||
208 | if (write(1,buf,c)!=c) | ||
209 | die("Write call failed"); | ||
210 | #ifdef __BIG_KERNEL__ | ||
211 | } | ||
212 | #endif | ||
213 | if (c != 0) | ||
214 | die("read-error on 'setup'"); | ||
215 | close (id); | ||
216 | setup_sectors = (unsigned char)((i + 511) / 512); | ||
217 | /* for compatibility with LILO */ | ||
218 | if (setup_sectors < SETUP_SECTS) | ||
219 | setup_sectors = SETUP_SECTS; | ||
220 | fprintf(stderr,"Setup is %d bytes.\n",i); | ||
221 | for (c=0 ; c<sizeof(buf) ; c++) | ||
222 | buf[c] = '\0'; | ||
223 | while (i < setup_sectors * 512) { | ||
224 | c = setup_sectors * 512 - i; | ||
225 | if (c > sizeof(buf)) | ||
226 | c = sizeof(buf); | ||
227 | if (write(1,buf,c) != c) | ||
228 | die("Write call failed"); | ||
229 | i += c; | ||
230 | } | ||
231 | |||
232 | if ((id=open(argv[3],O_RDONLY,0))<0) | ||
233 | die("Unable to open 'system'"); | ||
234 | #ifndef __BFD__ | ||
235 | if (read(id,buf,GCC_HEADER) != GCC_HEADER) | ||
236 | die("Unable to read header of 'system'"); | ||
237 | if (N_MAGIC(*ex) == ZMAGIC) { | ||
238 | GCC_HEADER = N_MAGIC_OFFSET; | ||
239 | lseek(id, GCC_HEADER, SEEK_SET); | ||
240 | } else if (N_MAGIC(*ex) != QMAGIC) | ||
241 | die("Non-GCC header of 'system'"); | ||
242 | fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n", | ||
243 | (ex->a_text+ex->a_data+ex->a_bss)/1024, | ||
244 | ex->a_text /1024, | ||
245 | ex->a_data /1024, | ||
246 | ex->a_bss /1024); | ||
247 | sz = N_SYMOFF(*ex) - GCC_HEADER + 4; | ||
248 | #else | ||
249 | if (fstat (id, &sb)) { | ||
250 | perror ("fstat"); | ||
251 | die ("Unable to stat 'system'"); | ||
252 | } | ||
253 | sz = sb.st_size; | ||
254 | fprintf (stderr, "System is %d kB\n", sz/1024); | ||
255 | #endif | ||
256 | sys_size = (sz + 15) / 16; | ||
257 | if (sys_size > SYS_SIZE) | ||
258 | die("System is too big"); | ||
259 | while (sz > 0) { | ||
260 | int l, n; | ||
261 | |||
262 | l = sz; | ||
263 | if (l > sizeof(buf)) | ||
264 | l = sizeof(buf); | ||
265 | if ((n=read(id, buf, l)) != l) { | ||
266 | if (n == -1) | ||
267 | perror(argv[1]); | ||
268 | else | ||
269 | fprintf(stderr, "Unexpected EOF\n"); | ||
270 | die("Can't read 'system'"); | ||
271 | } | ||
272 | if (write(1, buf, l) != l) | ||
273 | die("Write failed"); | ||
274 | sz -= l; | ||
275 | } | ||
276 | close(id); | ||
277 | if (lseek(1, 497, 0) == 497) { | ||
278 | if (write(1, &setup_sectors, 1) != 1) | ||
279 | die("Write of setup sectors failed"); | ||
280 | } | ||
281 | if (lseek(1,500,0) == 500) { | ||
282 | buf[0] = (sys_size & 0xff); | ||
283 | buf[1] = ((sys_size >> 8) & 0xff); | ||
284 | if (write(1, buf, 2) != 2) | ||
285 | die("Write failed"); | ||
286 | } | ||
287 | return(0); | ||
288 | } | ||
diff --git a/arch/cris/arch-v10/defconfig b/arch/cris/arch-v10/defconfig new file mode 100644 index 000000000000..2a3411eaace9 --- /dev/null +++ b/arch/cris/arch-v10/defconfig | |||
@@ -0,0 +1,505 @@ | |||
1 | # | ||
2 | # Automatically generated make config: don't edit | ||
3 | # | ||
4 | CONFIG_UID16=y | ||
5 | CONFIG_RWSEM_GENERIC_SPINLOCK=y | ||
6 | # CONFIG_RWSEM_XCHGADD_ALGORITHM is not set | ||
7 | |||
8 | # | ||
9 | # Code maturity level options | ||
10 | # | ||
11 | CONFIG_EXPERIMENTAL=y | ||
12 | |||
13 | # | ||
14 | # General setup | ||
15 | # | ||
16 | CONFIG_NET=y | ||
17 | CONFIG_SYSVIPC=y | ||
18 | # CONFIG_BSD_PROCESS_ACCT is not set | ||
19 | # CONFIG_SYSCTL is not set | ||
20 | CONFIG_BINFMT_ELF=y | ||
21 | # CONFIG_ETRAX_KGDB is not set | ||
22 | # CONFIG_ETRAX_WATCHDOG is not set | ||
23 | |||
24 | # | ||
25 | # Hardware setup | ||
26 | # | ||
27 | CONFIG_ETRAX100LX=y | ||
28 | # CONFIG_ETRAX100LX_V2 is not set | ||
29 | # CONFIG_SVINTO_SIM is not set | ||
30 | CONFIG_CRIS_LOW_MAP=y | ||
31 | CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 | ||
32 | CONFIG_ETRAX_DRAM_SIZE=8 | ||
33 | CONFIG_ETRAX_FLASH_BUSWIDTH=2 | ||
34 | CONFIG_ETRAX_ROOT_DEVICE="/dev/mtdblock3" | ||
35 | CONFIG_ETRAX_PA_LEDS=y | ||
36 | # CONFIG_ETRAX_PB_LEDS is not set | ||
37 | # CONFIG_ETRAX_CSP0_LEDS is not set | ||
38 | # CONFIG_ETRAX_NO_LEDS is not set | ||
39 | CONFIG_ETRAX_LED1G=2 | ||
40 | CONFIG_ETRAX_LED1R=2 | ||
41 | CONFIG_ETRAX_LED2G=2 | ||
42 | CONFIG_ETRAX_LED2R=2 | ||
43 | CONFIG_ETRAX_LED3R=2 | ||
44 | CONFIG_ETRAX_LED3G=2 | ||
45 | CONFIG_ETRAX_LED4R=2 | ||
46 | CONFIG_ETRAX_LED4G=2 | ||
47 | CONFIG_ETRAX_LED5R=2 | ||
48 | CONFIG_ETRAX_LED5G=2 | ||
49 | CONFIG_ETRAX_LED6R=2 | ||
50 | CONFIG_ETRAX_LED6G=2 | ||
51 | CONFIG_ETRAX_LED7R=2 | ||
52 | CONFIG_ETRAX_LED7G=2 | ||
53 | CONFIG_ETRAX_LED8Y=2 | ||
54 | CONFIG_ETRAX_LED9Y=2 | ||
55 | CONFIG_ETRAX_LED10Y=2 | ||
56 | CONFIG_ETRAX_LED11Y=2 | ||
57 | CONFIG_ETRAX_LED12R=2 | ||
58 | CONFIG_ETRAX_DEBUG_PORT0=y | ||
59 | # CONFIG_ETRAX_DEBUG_PORT1 is not set | ||
60 | # CONFIG_ETRAX_DEBUG_PORT2 is not set | ||
61 | # CONFIG_ETRAX_DEBUG_PORT3 is not set | ||
62 | CONFIG_ETRAX_RESCUE_SER0=y | ||
63 | # CONFIG_ETRAX_RESCUE_SER1 is not set | ||
64 | # CONFIG_ETRAX_RESCUE_SER2 is not set | ||
65 | # CONFIG_ETRAX_RESCUE_SER3 is not set | ||
66 | CONFIG_ETRAX_DEF_R_WAITSTATES=95a6 | ||
67 | CONFIG_ETRAX_DEF_R_BUS_CONFIG=104 | ||
68 | # CONFIG_ETRAX_SDRAM is not set | ||
69 | CONFIG_ETRAX_DEF_R_DRAM_CONFIG=1a200040 | ||
70 | CONFIG_ETRAX_DEF_R_DRAM_TIMING=5611 | ||
71 | CONFIG_ETRAX_DEF_R_PORT_PA_DIR=1d | ||
72 | CONFIG_ETRAX_DEF_R_PORT_PA_DATA=f0 | ||
73 | CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=00 | ||
74 | CONFIG_ETRAX_DEF_R_PORT_PB_DIR=1e | ||
75 | CONFIG_ETRAX_DEF_R_PORT_PB_DATA=f3 | ||
76 | # CONFIG_ETRAX_SOFT_SHUTDOWN is not set | ||
77 | |||
78 | # | ||
79 | # Drivers for ETRAX 100LX built-in interfaces | ||
80 | # | ||
81 | CONFIG_ETRAX_ETHERNET=y | ||
82 | CONFIG_NET_ETHERNET=y | ||
83 | # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set | ||
84 | CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y | ||
85 | # CONFIG_ETRAX_ETHERNET_LPSLAVE is not set | ||
86 | CONFIG_ETRAX_SERIAL=y | ||
87 | CONFIG_ETRAX_SERIAL_PORT0=y | ||
88 | # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set | ||
89 | CONFIG_ETRAX_SERIAL_PORT1=y | ||
90 | # CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_ON_PB is not set | ||
91 | # CONFIG_ETRAX_SERIAL_PORT2 is not set | ||
92 | # CONFIG_ETRAX_SERIAL_PORT3 is not set | ||
93 | # CONFIG_ETRAX_RS485 is not set | ||
94 | # CONFIG_ETRAX_SYNCHRONOUS_SERIAL is not set | ||
95 | # CONFIG_ETRAX_IDE is not set | ||
96 | CONFIG_ETRAX_AXISFLASHMAP=y | ||
97 | CONFIG_ETRAX_PTABLE_SECTOR=65536 | ||
98 | CONFIG_MTD=y | ||
99 | CONFIG_MTD_CFI=y | ||
100 | # CONFIG_MTD_CFI_INTELEXT is not set | ||
101 | CONFIG_MTD_CFI_AMDSTD=y | ||
102 | CONFIG_MTD_AMDSTD=y | ||
103 | CONFIG_MTD_CHAR=y | ||
104 | CONFIG_MTD_BLOCK=y | ||
105 | CONFIG_ETRAX_I2C=y | ||
106 | CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C=y | ||
107 | # CONFIG_ETRAX_I2C_EEPROM is not set | ||
108 | CONFIG_ETRAX_GPIO=y | ||
109 | CONFIG_ETRAX_PA_BUTTON_BITMASK=02 | ||
110 | CONFIG_ETRAX_PA_CHANGEABLE_DIR=00 | ||
111 | CONFIG_ETRAX_PA_CHANGEABLE_BITS=FF | ||
112 | CONFIG_ETRAX_PB_CHANGEABLE_DIR=00 | ||
113 | CONFIG_ETRAX_PB_CHANGEABLE_BITS=FF | ||
114 | # CONFIG_ETRAX_USB_HOST is not set | ||
115 | # CONFIG_USB is not set | ||
116 | # CONFIG_ETRAX_DS1302 is not set | ||
117 | |||
118 | # | ||
119 | # Memory Technology Devices (MTD) | ||
120 | # | ||
121 | CONFIG_MTD=y | ||
122 | # CONFIG_MTD_DEBUG is not set | ||
123 | |||
124 | # | ||
125 | # Disk-On-Chip Device Drivers | ||
126 | # | ||
127 | # CONFIG_MTD_DOC1000 is not set | ||
128 | # CONFIG_MTD_DOC2000 is not set | ||
129 | # CONFIG_MTD_DOC2001 is not set | ||
130 | # CONFIG_MTD_DOCPROBE is not set | ||
131 | |||
132 | # | ||
133 | # RAM/ROM Device Drivers | ||
134 | # | ||
135 | # CONFIG_MTD_PMC551 is not set | ||
136 | # CONFIG_MTD_SLRAM is not set | ||
137 | # CONFIG_MTD_RAM is not set | ||
138 | # CONFIG_MTD_ROM is not set | ||
139 | # CONFIG_MTD_MTDRAM is not set | ||
140 | |||
141 | # | ||
142 | # Linearly Mapped Flash Device Drivers | ||
143 | # | ||
144 | CONFIG_MTD_CFI=y | ||
145 | # CONFIG_MTD_CFI_GEOMETRY is not set | ||
146 | # CONFIG_MTD_CFI_INTELEXT is not set | ||
147 | CONFIG_MTD_CFI_AMDSTD=y | ||
148 | CONFIG_MTD_AMDSTD=y | ||
149 | # CONFIG_MTD_SHARP is not set | ||
150 | # CONFIG_MTD_PHYSMAP is not set | ||
151 | # CONFIG_MTD_NORA is not set | ||
152 | # CONFIG_MTD_PNC2000 is not set | ||
153 | # CONFIG_MTD_RPXLITE is not set | ||
154 | # CONFIG_MTD_SC520CDP is not set | ||
155 | # CONFIG_MTD_SBC_MEDIAGX is not set | ||
156 | # CONFIG_MTD_ELAN_104NC is not set | ||
157 | # CONFIG_MTD_SA1100 is not set | ||
158 | # CONFIG_MTD_DC21285 is not set | ||
159 | # CONFIG_MTD_CSTM_CFI_JEDEC is not set | ||
160 | # CONFIG_MTD_JEDEC is not set | ||
161 | # CONFIG_MTD_MIXMEM is not set | ||
162 | # CONFIG_MTD_OCTAGON is not set | ||
163 | # CONFIG_MTD_VMAX is not set | ||
164 | |||
165 | # | ||
166 | # NAND Flash Device Drivers | ||
167 | # | ||
168 | # CONFIG_MTD_NAND is not set | ||
169 | # CONFIG_MTD_NAND_SPIA is not set | ||
170 | |||
171 | # | ||
172 | # User Modules And Translation Layers | ||
173 | # | ||
174 | CONFIG_MTD_CHAR=y | ||
175 | CONFIG_MTD_BLOCK=y | ||
176 | # CONFIG_FTL is not set | ||
177 | # CONFIG_NFTL is not set | ||
178 | |||
179 | # | ||
180 | # Parallel port support | ||
181 | # | ||
182 | # CONFIG_PARPORT is not set | ||
183 | |||
184 | # | ||
185 | # Plug and Play configuration | ||
186 | # | ||
187 | # CONFIG_PNP is not set | ||
188 | # CONFIG_ISAPNP is not set | ||
189 | |||
190 | # | ||
191 | # Block devices | ||
192 | # | ||
193 | # CONFIG_BLK_DEV_FD is not set | ||
194 | # CONFIG_BLK_DEV_XD is not set | ||
195 | # CONFIG_PARIDE is not set | ||
196 | # CONFIG_BLK_CPQ_DA is not set | ||
197 | # CONFIG_BLK_CPQ_CISS_DA is not set | ||
198 | # CONFIG_BLK_DEV_DAC960 is not set | ||
199 | # CONFIG_BLK_DEV_LOOP is not set | ||
200 | # CONFIG_BLK_DEV_NBD is not set | ||
201 | # CONFIG_BLK_DEV_RAM is not set | ||
202 | # CONFIG_BLK_DEV_INITRD is not set | ||
203 | |||
204 | # | ||
205 | # Networking options | ||
206 | # | ||
207 | # CONFIG_PACKET is not set | ||
208 | # CONFIG_NETLINK is not set | ||
209 | # CONFIG_NETFILTER is not set | ||
210 | # CONFIG_FILTER is not set | ||
211 | CONFIG_UNIX=y | ||
212 | CONFIG_INET=y | ||
213 | # CONFIG_IP_MULTICAST is not set | ||
214 | # CONFIG_IP_ADVANCED_ROUTER is not set | ||
215 | # CONFIG_IP_PNP is not set | ||
216 | # CONFIG_NET_IPIP is not set | ||
217 | # CONFIG_NET_IPGRE is not set | ||
218 | # CONFIG_INET_ECN is not set | ||
219 | # CONFIG_SYN_COOKIES is not set | ||
220 | # CONFIG_IPV6 is not set | ||
221 | # CONFIG_KHTTPD is not set | ||
222 | # CONFIG_ATM is not set | ||
223 | # CONFIG_IPX is not set | ||
224 | # CONFIG_ATALK is not set | ||
225 | # CONFIG_DECNET is not set | ||
226 | # CONFIG_BRIDGE is not set | ||
227 | # CONFIG_X25 is not set | ||
228 | # CONFIG_LAPB is not set | ||
229 | # CONFIG_LLC is not set | ||
230 | # CONFIG_NET_DIVERT is not set | ||
231 | # CONFIG_ECONET is not set | ||
232 | # CONFIG_WAN_ROUTER is not set | ||
233 | # CONFIG_NET_HW_FLOWCONTROL is not set | ||
234 | |||
235 | # | ||
236 | # QoS and/or fair queueing | ||
237 | # | ||
238 | # CONFIG_NET_SCHED is not set | ||
239 | |||
240 | # | ||
241 | # Telephony Support | ||
242 | # | ||
243 | # CONFIG_PHONE is not set | ||
244 | # CONFIG_PHONE_IXJ is not set | ||
245 | |||
246 | # | ||
247 | # ATA/IDE/MFM/RLL support | ||
248 | # | ||
249 | # CONFIG_IDE is not set | ||
250 | |||
251 | # | ||
252 | # IDE, ATA and ATAPI Block devices | ||
253 | # | ||
254 | # CONFIG_BLK_DEV_IDE is not set | ||
255 | # CONFIG_BLK_DEV_HD_IDE is not set | ||
256 | # CONFIG_BLK_DEV_HD is not set | ||
257 | # CONFIG_BLK_DEV_IDEDISK is not set | ||
258 | # CONFIG_IDEDISK_MULTI_MODE is not set | ||
259 | # CONFIG_BLK_DEV_IDECS is not set | ||
260 | # CONFIG_BLK_DEV_IDECD is not set | ||
261 | # CONFIG_BLK_DEV_IDETAPE is not set | ||
262 | # CONFIG_BLK_DEV_IDEFLOPPY is not set | ||
263 | # CONFIG_BLK_DEV_IDESCSI is not set | ||
264 | # CONFIG_BLK_DEV_CMD640 is not set | ||
265 | # CONFIG_BLK_DEV_CMD640_ENHANCED is not set | ||
266 | # CONFIG_BLK_DEV_ISAPNP is not set | ||
267 | # CONFIG_IDE_CHIPSETS is not set | ||
268 | # CONFIG_IDEDMA_AUTO is not set | ||
269 | # CONFIG_BLK_DEV_IDE_MODES is not set | ||
270 | |||
271 | # | ||
272 | # SCSI support | ||
273 | # | ||
274 | # CONFIG_SCSI is not set | ||
275 | |||
276 | # | ||
277 | # I2O device support | ||
278 | # | ||
279 | # CONFIG_I2O is not set | ||
280 | # CONFIG_I2O_BLOCK is not set | ||
281 | # CONFIG_I2O_LAN is not set | ||
282 | # CONFIG_I2O_SCSI is not set | ||
283 | # CONFIG_I2O_PROC is not set | ||
284 | |||
285 | # | ||
286 | # Network device support | ||
287 | # | ||
288 | CONFIG_NETDEVICES=y | ||
289 | |||
290 | # | ||
291 | # ARCnet devices | ||
292 | # | ||
293 | # CONFIG_ARCNET is not set | ||
294 | # CONFIG_DUMMY is not set | ||
295 | # CONFIG_BONDING is not set | ||
296 | # CONFIG_EQUALIZER is not set | ||
297 | # CONFIG_TUN is not set | ||
298 | # CONFIG_NET_SB1000 is not set | ||
299 | |||
300 | # | ||
301 | # Ethernet (10 or 100Mbit) | ||
302 | # | ||
303 | CONFIG_NET_ETHERNET=y | ||
304 | # CONFIG_NET_VENDOR_3COM is not set | ||
305 | # CONFIG_LANCE is not set | ||
306 | # CONFIG_NET_VENDOR_SMC is not set | ||
307 | # CONFIG_NET_VENDOR_RACAL is not set | ||
308 | # CONFIG_AT1700 is not set | ||
309 | # CONFIG_DEPCA is not set | ||
310 | # CONFIG_NET_ISA is not set | ||
311 | # CONFIG_NET_PCI is not set | ||
312 | # CONFIG_NET_POCKET is not set | ||
313 | |||
314 | # | ||
315 | # Ethernet (1000 Mbit) | ||
316 | # | ||
317 | # CONFIG_ACENIC is not set | ||
318 | # CONFIG_HAMACHI is not set | ||
319 | # CONFIG_YELLOWFIN is not set | ||
320 | # CONFIG_SK98LIN is not set | ||
321 | # CONFIG_FDDI is not set | ||
322 | # CONFIG_HIPPI is not set | ||
323 | # CONFIG_PLIP is not set | ||
324 | # CONFIG_PPP is not set | ||
325 | # CONFIG_SLIP is not set | ||
326 | |||
327 | # | ||
328 | # Wireless LAN (non-hamradio) | ||
329 | # | ||
330 | # CONFIG_NET_RADIO is not set | ||
331 | |||
332 | # | ||
333 | # Token Ring devices | ||
334 | # | ||
335 | # CONFIG_TR is not set | ||
336 | # CONFIG_NET_FC is not set | ||
337 | # CONFIG_RCPCI is not set | ||
338 | # CONFIG_SHAPER is not set | ||
339 | |||
340 | # | ||
341 | # Wan interfaces | ||
342 | # | ||
343 | # CONFIG_WAN is not set | ||
344 | |||
345 | # | ||
346 | # Amateur Radio support | ||
347 | # | ||
348 | # CONFIG_HAMRADIO is not set | ||
349 | |||
350 | # | ||
351 | # IrDA (infrared) support | ||
352 | # | ||
353 | # CONFIG_IRDA is not set | ||
354 | |||
355 | # | ||
356 | # ISDN subsystem | ||
357 | # | ||
358 | # CONFIG_ISDN is not set | ||
359 | |||
360 | # | ||
361 | # CD-ROM drivers (not for SCSI or IDE/ATAPI drives) | ||
362 | # | ||
363 | # CONFIG_CD_NO_IDESCSI is not set | ||
364 | |||
365 | # | ||
366 | # Input core support | ||
367 | # | ||
368 | # CONFIG_INPUT is not set | ||
369 | |||
370 | # | ||
371 | # Character devices | ||
372 | # | ||
373 | # CONFIG_VT is not set | ||
374 | # CONFIG_SERIAL is not set | ||
375 | # CONFIG_SERIAL_EXTENDED is not set | ||
376 | # CONFIG_SERIAL_NONSTANDARD is not set | ||
377 | # CONFIG_UNIX98_PTYS is not set | ||
378 | |||
379 | # | ||
380 | # I2C support | ||
381 | # | ||
382 | # CONFIG_I2C is not set | ||
383 | |||
384 | # | ||
385 | # Mice | ||
386 | # | ||
387 | # CONFIG_BUSMOUSE is not set | ||
388 | # CONFIG_MOUSE is not set | ||
389 | |||
390 | # | ||
391 | # Joysticks | ||
392 | # | ||
393 | # CONFIG_JOYSTICK is not set | ||
394 | # CONFIG_QIC02_TAPE is not set | ||
395 | |||
396 | # | ||
397 | # Watchdog Cards | ||
398 | # | ||
399 | # CONFIG_WATCHDOG is not set | ||
400 | # CONFIG_INTEL_RNG is not set | ||
401 | # CONFIG_NVRAM is not set | ||
402 | # CONFIG_RTC is not set | ||
403 | # CONFIG_DTLK is not set | ||
404 | # CONFIG_R3964 is not set | ||
405 | # CONFIG_APPLICOM is not set | ||
406 | |||
407 | # | ||
408 | # Ftape, the floppy tape device driver | ||
409 | # | ||
410 | # CONFIG_FTAPE is not set | ||
411 | # CONFIG_AGP is not set | ||
412 | # CONFIG_DRM is not set | ||
413 | |||
414 | # | ||
415 | # Multimedia devices | ||
416 | # | ||
417 | # CONFIG_VIDEO_DEV is not set | ||
418 | |||
419 | # | ||
420 | # File systems | ||
421 | # | ||
422 | # CONFIG_QUOTA is not set | ||
423 | # CONFIG_AUTOFS_FS is not set | ||
424 | # CONFIG_AUTOFS4_FS is not set | ||
425 | # CONFIG_ADFS_FS is not set | ||
426 | # CONFIG_ADFS_FS_RW is not set | ||
427 | # CONFIG_AFFS_FS is not set | ||
428 | # CONFIG_HFS_FS is not set | ||
429 | # CONFIG_BFS_FS is not set | ||
430 | # CONFIG_FAT_FS is not set | ||
431 | # CONFIG_MSDOS_FS is not set | ||
432 | # CONFIG_UMSDOS_FS is not set | ||
433 | # CONFIG_VFAT_FS is not set | ||
434 | # CONFIG_EFS_FS is not set | ||
435 | # CONFIG_JFFS_FS is not set | ||
436 | CONFIG_CRAMFS=y | ||
437 | CONFIG_RAMFS=y | ||
438 | # CONFIG_ISO9660_FS is not set | ||
439 | # CONFIG_JOLIET is not set | ||
440 | # CONFIG_MINIX_FS is not set | ||
441 | # CONFIG_NTFS_FS is not set | ||
442 | # CONFIG_NTFS_DEBUG is not set | ||
443 | # CONFIG_NTFS_RW is not set | ||
444 | # CONFIG_HPFS_FS is not set | ||
445 | CONFIG_PROC_FS=y | ||
446 | # CONFIG_DEVFS_FS is not set | ||
447 | # CONFIG_DEVFS_MOUNT is not set | ||
448 | # CONFIG_DEVFS_DEBUG is not set | ||
449 | # CONFIG_DEVPTS_FS is not set | ||
450 | # CONFIG_QNX4FS_FS is not set | ||
451 | # CONFIG_QNX4FS_RW is not set | ||
452 | # CONFIG_ROMFS_FS is not set | ||
453 | # CONFIG_EXT2_FS is not set | ||
454 | # CONFIG_SYSV_FS is not set | ||
455 | # CONFIG_SYSV_FS_WRITE is not set | ||
456 | # CONFIG_UDF_FS is not set | ||
457 | # CONFIG_UDF_RW is not set | ||
458 | # CONFIG_UFS_FS is not set | ||
459 | # CONFIG_UFS_FS_WRITE is not set | ||
460 | |||
461 | # | ||
462 | # Network File Systems | ||
463 | # | ||
464 | # CONFIG_CODA_FS is not set | ||
465 | # CONFIG_NFS_FS is not set | ||
466 | # CONFIG_NFS_V3 is not set | ||
467 | # CONFIG_ROOT_NFS is not set | ||
468 | # CONFIG_NFSD is not set | ||
469 | # CONFIG_NFSD_V3 is not set | ||
470 | # CONFIG_SUNRPC is not set | ||
471 | # CONFIG_LOCKD is not set | ||
472 | # CONFIG_SMB_FS is not set | ||
473 | # CONFIG_NCP_FS is not set | ||
474 | # CONFIG_NCPFS_PACKET_SIGNING is not set | ||
475 | # CONFIG_NCPFS_IOCTL_LOCKING is not set | ||
476 | # CONFIG_NCPFS_STRONG is not set | ||
477 | # CONFIG_NCPFS_NFS_NS is not set | ||
478 | # CONFIG_NCPFS_OS2_NS is not set | ||
479 | # CONFIG_NCPFS_SMALLDOS is not set | ||
480 | # CONFIG_NCPFS_MOUNT_SUBDIR is not set | ||
481 | # CONFIG_NCPFS_NDS_DOMAINS is not set | ||
482 | # CONFIG_NCPFS_NLS is not set | ||
483 | # CONFIG_NCPFS_EXTRAS is not set | ||
484 | |||
485 | # | ||
486 | # Partition Types | ||
487 | # | ||
488 | # CONFIG_PARTITION_ADVANCED is not set | ||
489 | CONFIG_MSDOS_PARTITION=y | ||
490 | # CONFIG_NLS is not set | ||
491 | |||
492 | # | ||
493 | # Sound | ||
494 | # | ||
495 | # CONFIG_SOUND is not set | ||
496 | |||
497 | # | ||
498 | # USB support | ||
499 | # | ||
500 | # CONFIG_USB is not set | ||
501 | |||
502 | # | ||
503 | # Kernel hacking | ||
504 | # | ||
505 | # CONFIG_PROFILE is not set | ||
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig new file mode 100644 index 000000000000..748374f25b87 --- /dev/null +++ b/arch/cris/arch-v10/drivers/Kconfig | |||
@@ -0,0 +1,963 @@ | |||
1 | config ETRAX_ETHERNET | ||
2 | bool "Ethernet support" | ||
3 | depends on ETRAX_ARCH_V10 | ||
4 | help | ||
5 | This option enables the ETRAX 100LX built-in 10/100Mbit Ethernet | ||
6 | controller. | ||
7 | |||
8 | # this is just so that the user does not have to go into the | ||
9 | # normal ethernet driver section just to enable ethernetworking | ||
10 | config NET_ETHERNET | ||
11 | bool | ||
12 | depends on ETRAX_ETHERNET | ||
13 | default y | ||
14 | |||
15 | choice | ||
16 | prompt "Network LED behavior" | ||
17 | depends on ETRAX_ETHERNET | ||
18 | default ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY | ||
19 | |||
20 | config ETRAX_NETWORK_LED_ON_WHEN_LINK | ||
21 | bool "LED_on_when_link" | ||
22 | help | ||
23 | Selecting LED_on_when_link will light the LED when there is a | ||
24 | connection and will flash off when there is activity. | ||
25 | |||
26 | Selecting LED_on_when_activity will light the LED only when | ||
27 | there is activity. | ||
28 | |||
29 | This setting will also affect the behaviour of other activity LEDs | ||
30 | e.g. Bluetooth. | ||
31 | |||
32 | config ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY | ||
33 | bool "LED_on_when_activity" | ||
34 | help | ||
35 | Selecting LED_on_when_link will light the LED when there is a | ||
36 | connection and will flash off when there is activity. | ||
37 | |||
38 | Selecting LED_on_when_activity will light the LED only when | ||
39 | there is activity. | ||
40 | |||
41 | This setting will also affect the behaviour of other activity LEDs | ||
42 | e.g. Bluetooth. | ||
43 | |||
44 | endchoice | ||
45 | |||
46 | config ETRAX_SERIAL | ||
47 | bool "Serial-port support" | ||
48 | depends on ETRAX_ARCH_V10 | ||
49 | help | ||
50 | Enables the ETRAX 100 serial driver for ser0 (ttyS0) | ||
51 | You probably want this enabled. | ||
52 | |||
53 | config ETRAX_SERIAL_FAST_TIMER | ||
54 | bool "Use fast timers for serial DMA flush (experimental)" | ||
55 | depends on ETRAX_SERIAL | ||
56 | help | ||
57 | Select this to have the serial DMAs flushed at a higher rate than | ||
58 | normally, possible by using the fast timer API, the timeout is | ||
59 | approx. 4 character times. | ||
60 | If unsure, say N. | ||
61 | |||
62 | config ETRAX_SERIAL_FLUSH_DMA_FAST | ||
63 | bool "Fast serial port DMA flush" | ||
64 | depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER | ||
65 | help | ||
66 | Select this to have the serial DMAs flushed at a higher rate than | ||
67 | normally possible through a fast timer interrupt (currently at | ||
68 | 15360 Hz). | ||
69 | If unsure, say N. | ||
70 | |||
71 | config ETRAX_SERIAL_RX_TIMEOUT_TICKS | ||
72 | int "Receive flush timeout (ticks) " | ||
73 | depends on ETRAX_SERIAL && !ETRAX_SERIAL_FAST_TIMER && !ETRAX_SERIAL_FLUSH_DMA_FAST | ||
74 | default "5" | ||
75 | help | ||
76 | Number of timer ticks between flush of receive fifo (1 tick = 10ms). | ||
77 | Try 0-3 for low latency applications. Approx 5 for high load | ||
78 | applications (e.g. PPP). Maybe this should be more adaptive some | ||
79 | day... | ||
80 | |||
81 | config ETRAX_SERIAL_PORT0 | ||
82 | bool "Serial port 0 enabled" | ||
83 | depends on ETRAX_SERIAL | ||
84 | help | ||
85 | Enables the ETRAX 100 serial driver for ser0 (ttyS0) | ||
86 | Normally you want this on, unless you use external DMA 1 that uses | ||
87 | the same DMA channels. | ||
88 | |||
89 | choice | ||
90 | prompt "Ser0 DMA out assignment" | ||
91 | depends on ETRAX_SERIAL_PORT0 | ||
92 | default ETRAX_SERIAL_PORT0_DMA6_OUT | ||
93 | |||
94 | config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT | ||
95 | bool "No DMA out" | ||
96 | |||
97 | config CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT | ||
98 | bool "DMA 6" | ||
99 | |||
100 | endchoice | ||
101 | |||
102 | choice | ||
103 | prompt "Ser0 DMA in assignment" | ||
104 | depends on ETRAX_SERIAL_PORT0 | ||
105 | default ETRAX_SERIAL_PORT0_DMA7_IN | ||
106 | |||
107 | config CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN | ||
108 | bool "No DMA in" | ||
109 | |||
110 | config CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN | ||
111 | bool "DMA 7" | ||
112 | |||
113 | endchoice | ||
114 | |||
115 | choice | ||
116 | prompt "Ser0 DTR, RI, DSR and CD assignment" | ||
117 | depends on ETRAX_SERIAL_PORT0 | ||
118 | default ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE | ||
119 | |||
120 | config ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE | ||
121 | bool "No_DTR_RI_DSR_CD" | ||
122 | |||
123 | config ETRAX_SER0_DTR_RI_DSR_CD_ON_PA | ||
124 | bool "DTR_RI_DSR_CD_on_PA" | ||
125 | |||
126 | config ETRAX_SER0_DTR_RI_DSR_CD_ON_PB | ||
127 | bool "DTR_RI_DSR_CD_on_PB" | ||
128 | help | ||
129 | Enables the status and control signals DTR, RI, DSR and CD on PB for | ||
130 | ser0. | ||
131 | |||
132 | config ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
133 | bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" | ||
134 | |||
135 | endchoice | ||
136 | |||
137 | config ETRAX_SER0_DTR_ON_PA_BIT | ||
138 | int "Ser0 DTR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
139 | depends on ETRAX_SERIAL_PORT0 | ||
140 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
141 | default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
142 | |||
143 | config ETRAX_SER0_RI_ON_PA_BIT | ||
144 | int "Ser0 RI on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
145 | depends on ETRAX_SERIAL_PORT0 | ||
146 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
147 | default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
148 | |||
149 | config ETRAX_SER0_DSR_ON_PA_BIT | ||
150 | int "Ser0 DSR on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
151 | depends on ETRAX_SERIAL_PORT0 | ||
152 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
153 | default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
154 | |||
155 | config ETRAX_SER0_CD_ON_PA_BIT | ||
156 | int "Ser0 CD on PA bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
157 | depends on ETRAX_SERIAL_PORT0 | ||
158 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
159 | default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PA || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
160 | |||
161 | config ETRAX_SER0_DTR_ON_PB_BIT | ||
162 | int "Ser0 DTR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
163 | depends on ETRAX_SERIAL_PORT0 | ||
164 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
165 | default "4" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
166 | help | ||
167 | Specify the pin of the PB port to carry the DTR signal for serial | ||
168 | port 0. | ||
169 | |||
170 | config ETRAX_SER0_RI_ON_PB_BIT | ||
171 | int "Ser0 RI on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
172 | depends on ETRAX_SERIAL_PORT0 | ||
173 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
174 | default "5" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
175 | help | ||
176 | Specify the pin of the PB port to carry the RI signal for serial | ||
177 | port 0. | ||
178 | |||
179 | config ETRAX_SER0_DSR_ON_PB_BIT | ||
180 | int "Ser0 DSR on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
181 | depends on ETRAX_SERIAL_PORT0 | ||
182 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
183 | default "6" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
184 | help | ||
185 | Specify the pin of the PB port to carry the DSR signal for serial | ||
186 | port 0. | ||
187 | |||
188 | config ETRAX_SER0_CD_ON_PB_BIT | ||
189 | int "Ser0 CD on PB bit (-1 = not used)" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
190 | depends on ETRAX_SERIAL_PORT0 | ||
191 | default "-1" if !ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
192 | default "7" if ETRAX_SER0_DTR_RI_DSR_CD_ON_PB || ETRAX_SER0_DTR_RI_DSR_CD_MIXED | ||
193 | help | ||
194 | Specify the pin of the PB port to carry the CD signal for serial | ||
195 | port 0. | ||
196 | |||
197 | config ETRAX_SERIAL_PORT1 | ||
198 | bool "Serial port 1 enabled" | ||
199 | depends on ETRAX_SERIAL | ||
200 | help | ||
201 | Enables the ETRAX 100 serial driver for ser1 (ttyS1). | ||
202 | |||
203 | choice | ||
204 | prompt "Ser1 DMA out assignment" | ||
205 | depends on ETRAX_SERIAL_PORT1 | ||
206 | default ETRAX_SERIAL_PORT1_DMA8_OUT | ||
207 | |||
208 | config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_OUT | ||
209 | bool "No DMA out" | ||
210 | |||
211 | config CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT | ||
212 | bool "DMA 8" | ||
213 | |||
214 | endchoice | ||
215 | |||
216 | choice | ||
217 | prompt "Ser1 DMA in assignment" | ||
218 | depends on ETRAX_SERIAL_PORT1 | ||
219 | default ETRAX_SERIAL_PORT1_DMA9_IN | ||
220 | |||
221 | config CONFIG_ETRAX_SERIAL_PORT1_NO_DMA_IN | ||
222 | bool "No DMA in" | ||
223 | |||
224 | config CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN | ||
225 | bool "DMA 9" | ||
226 | |||
227 | endchoice | ||
228 | |||
229 | choice | ||
230 | prompt "Ser1 DTR, RI, DSR and CD assignment" | ||
231 | depends on ETRAX_SERIAL_PORT1 | ||
232 | default ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE | ||
233 | |||
234 | config ETRAX_SER1_DTR_RI_DSR_CD_ON_NONE | ||
235 | bool "No_DTR_RI_DSR_CD" | ||
236 | |||
237 | config ETRAX_SER1_DTR_RI_DSR_CD_ON_PA | ||
238 | bool "DTR_RI_DSR_CD_on_PA" | ||
239 | |||
240 | config ETRAX_SER1_DTR_RI_DSR_CD_ON_PB | ||
241 | bool "DTR_RI_DSR_CD_on_PB" | ||
242 | help | ||
243 | Enables the status and control signals DTR, RI, DSR and CD on PB for | ||
244 | ser1. | ||
245 | |||
246 | config ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
247 | bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" | ||
248 | |||
249 | endchoice | ||
250 | |||
251 | config ETRAX_SER1_DTR_ON_PA_BIT | ||
252 | int "Ser1 DTR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
253 | depends on ETRAX_SERIAL_PORT1 | ||
254 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
255 | default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
256 | |||
257 | config ETRAX_SER1_RI_ON_PA_BIT | ||
258 | int "Ser1 RI on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
259 | depends on ETRAX_SERIAL_PORT1 | ||
260 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
261 | default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
262 | |||
263 | config ETRAX_SER1_DSR_ON_PA_BIT | ||
264 | int "Ser1 DSR on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
265 | depends on ETRAX_SERIAL_PORT1 | ||
266 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
267 | default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
268 | |||
269 | config ETRAX_SER1_CD_ON_PA_BIT | ||
270 | int "Ser1 CD on PA bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
271 | depends on ETRAX_SERIAL_PORT1 | ||
272 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
273 | default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PA || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
274 | |||
275 | config ETRAX_SER1_DTR_ON_PB_BIT | ||
276 | int "Ser1 DTR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
277 | depends on ETRAX_SERIAL_PORT1 | ||
278 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
279 | default "4" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
280 | help | ||
281 | Specify the pin of the PB port to carry the DTR signal for serial | ||
282 | port 1. | ||
283 | |||
284 | config ETRAX_SER1_RI_ON_PB_BIT | ||
285 | int "Ser1 RI on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
286 | depends on ETRAX_SERIAL_PORT1 | ||
287 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
288 | default "5" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
289 | help | ||
290 | Specify the pin of the PB port to carry the RI signal for serial | ||
291 | port 1. | ||
292 | |||
293 | config ETRAX_SER1_DSR_ON_PB_BIT | ||
294 | int "Ser1 DSR on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
295 | depends on ETRAX_SERIAL_PORT1 | ||
296 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
297 | default "6" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
298 | help | ||
299 | Specify the pin of the PB port to carry the DSR signal for serial | ||
300 | port 1. | ||
301 | |||
302 | config ETRAX_SER1_CD_ON_PB_BIT | ||
303 | int "Ser1 CD on PB bit (-1 = not used)" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
304 | depends on ETRAX_SERIAL_PORT1 | ||
305 | default "-1" if !ETRAX_SER1_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
306 | default "7" if ETRAX_SER1_DTR_RI_DSR_CD_ON_PB || ETRAX_SER1_DTR_RI_DSR_CD_MIXED | ||
307 | help | ||
308 | Specify the pin of the PB port to carry the CD signal for serial | ||
309 | port 1. | ||
310 | |||
311 | comment "Make sure you dont have the same PB bits more than once!" | ||
312 | depends on ETRAX_SERIAL && ETRAX_SER0_DTR_RI_DSR_CD_ON_PB && ETRAX_SER1_DTR_RI_DSR_CD_ON_PB | ||
313 | |||
314 | config ETRAX_SERIAL_PORT2 | ||
315 | bool "Serial port 2 enabled" | ||
316 | depends on ETRAX_SERIAL | ||
317 | help | ||
318 | Enables the ETRAX 100 serial driver for ser2 (ttyS2). | ||
319 | |||
320 | choice | ||
321 | prompt "Ser2 DMA out assignment" | ||
322 | depends on ETRAX_SERIAL_PORT2 | ||
323 | default ETRAX_SERIAL_PORT2_DMA2_OUT | ||
324 | |||
325 | config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT | ||
326 | bool "No DMA out" | ||
327 | |||
328 | config CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT | ||
329 | bool "DMA 2" | ||
330 | |||
331 | endchoice | ||
332 | |||
333 | choice | ||
334 | prompt "Ser2 DMA in assignment" | ||
335 | depends on ETRAX_SERIAL_PORT2 | ||
336 | default ETRAX_SERIAL_PORT2_DMA3_IN | ||
337 | |||
338 | config CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN | ||
339 | bool "No DMA in" | ||
340 | |||
341 | config CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN | ||
342 | bool "DMA 3" | ||
343 | |||
344 | endchoice | ||
345 | |||
346 | choice | ||
347 | prompt "Ser2 DTR, RI, DSR and CD assignment" | ||
348 | depends on ETRAX_SERIAL_PORT2 | ||
349 | default ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE | ||
350 | |||
351 | config ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE | ||
352 | bool "No_DTR_RI_DSR_CD" | ||
353 | |||
354 | config ETRAX_SER2_DTR_RI_DSR_CD_ON_PA | ||
355 | bool "DTR_RI_DSR_CD_on_PA" | ||
356 | help | ||
357 | Enables the status and control signals DTR, RI, DSR and CD on PA for | ||
358 | ser2. | ||
359 | |||
360 | config ETRAX_SER2_DTR_RI_DSR_CD_ON_PB | ||
361 | bool "DTR_RI_DSR_CD_on_PB" | ||
362 | |||
363 | config ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
364 | bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" | ||
365 | |||
366 | endchoice | ||
367 | |||
368 | config ETRAX_SER2_DTR_ON_PA_BIT | ||
369 | int "Ser2 DTR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
370 | depends on ETRAX_SERIAL_PORT2 | ||
371 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
372 | default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
373 | help | ||
374 | Specify the pin of the PA port to carry the DTR signal for serial | ||
375 | port 2. | ||
376 | |||
377 | config ETRAX_SER2_RI_ON_PA_BIT | ||
378 | int "Ser2 RI on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
379 | depends on ETRAX_SERIAL_PORT2 | ||
380 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
381 | default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
382 | help | ||
383 | Specify the pin of the PA port to carry the RI signal for serial | ||
384 | port 2. | ||
385 | |||
386 | config ETRAX_SER2_DSR_ON_PA_BIT | ||
387 | int "Ser2 DSR on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
388 | depends on ETRAX_SERIAL_PORT2 | ||
389 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
390 | default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
391 | help | ||
392 | Specify the pin of the PA port to carry the DTR signal for serial | ||
393 | port 2. | ||
394 | |||
395 | config ETRAX_SER2_CD_ON_PA_BIT | ||
396 | int "Ser2 CD on PA bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
397 | depends on ETRAX_SERIAL_PORT2 | ||
398 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PA && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
399 | default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PA || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
400 | help | ||
401 | Specify the pin of the PA port to carry the CD signal for serial | ||
402 | port 2. | ||
403 | |||
404 | config ETRAX_SER2_DTR_ON_PB_BIT | ||
405 | int "Ser2 DTR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
406 | depends on ETRAX_SERIAL_PORT2 | ||
407 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
408 | default "4" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
409 | |||
410 | config ETRAX_SER2_RI_ON_PB_BIT | ||
411 | int "Ser2 RI on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
412 | depends on ETRAX_SERIAL_PORT2 | ||
413 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
414 | default "5" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
415 | |||
416 | config ETRAX_SER2_DSR_ON_PB_BIT | ||
417 | int "Ser2 DSR on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
418 | depends on ETRAX_SERIAL_PORT2 | ||
419 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
420 | default "6" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
421 | |||
422 | config ETRAX_SER2_CD_ON_PB_BIT | ||
423 | int "Ser2 CD on PB bit (-1 = not used)" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
424 | depends on ETRAX_SERIAL_PORT2 | ||
425 | default "-1" if !ETRAX_SER2_DTR_RI_DSR_CD_ON_PB && !ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
426 | default "7" if ETRAX_SER2_DTR_RI_DSR_CD_ON_PB || ETRAX_SER2_DTR_RI_DSR_CD_MIXED | ||
427 | |||
428 | config ETRAX_SERIAL_PORT3 | ||
429 | bool "Serial port 3 enabled" | ||
430 | depends on ETRAX_SERIAL | ||
431 | help | ||
432 | Enables the ETRAX 100 serial driver for ser3 (ttyS3). | ||
433 | |||
434 | choice | ||
435 | prompt "Ser3 DMA out assignment" | ||
436 | depends on ETRAX_SERIAL_PORT3 | ||
437 | default ETRAX_SERIAL_PORT3_DMA4_OUT | ||
438 | |||
439 | config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_OUT | ||
440 | bool "No DMA out" | ||
441 | |||
442 | config CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT | ||
443 | bool "DMA 4" | ||
444 | |||
445 | endchoice | ||
446 | |||
447 | choice | ||
448 | prompt "Ser3 DMA in assignment" | ||
449 | depends on ETRAX_SERIAL_PORT3 | ||
450 | default ETRAX_SERIAL_PORT3_DMA5_IN | ||
451 | |||
452 | config CONFIG_ETRAX_SERIAL_PORT3_NO_DMA_IN | ||
453 | bool "No DMA in" | ||
454 | |||
455 | config CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN | ||
456 | bool "DMA 5" | ||
457 | |||
458 | endchoice | ||
459 | |||
460 | choice | ||
461 | prompt "Ser3 DTR, RI, DSR and CD assignment" | ||
462 | depends on ETRAX_SERIAL_PORT3 | ||
463 | default ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE | ||
464 | |||
465 | config ETRAX_SER3_DTR_RI_DSR_CD_ON_NONE | ||
466 | bool "No_DTR_RI_DSR_CD" | ||
467 | |||
468 | config ETRAX_SER3_DTR_RI_DSR_CD_ON_PA | ||
469 | bool "DTR_RI_DSR_CD_on_PA" | ||
470 | |||
471 | config ETRAX_SER3_DTR_RI_DSR_CD_ON_PB | ||
472 | bool "DTR_RI_DSR_CD_on_PB" | ||
473 | |||
474 | config ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
475 | bool "DTR_RI_DSR_CD_mixed_on_PA_and_PB" | ||
476 | |||
477 | endchoice | ||
478 | |||
479 | config ETRAX_SER3_DTR_ON_PA_BIT | ||
480 | int "Ser3 DTR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
481 | depends on ETRAX_SERIAL_PORT3 | ||
482 | default "-1" | ||
483 | |||
484 | config ETRAX_SER3_RI_ON_PA_BIT | ||
485 | int "Ser3 RI on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
486 | depends on ETRAX_SERIAL_PORT3 | ||
487 | default "-1" | ||
488 | |||
489 | config ETRAX_SER3_DSR_ON_PA_BIT | ||
490 | int "Ser3 DSR on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
491 | depends on ETRAX_SERIAL_PORT3 | ||
492 | default "-1" | ||
493 | |||
494 | config ETRAX_SER3_CD_ON_PA_BIT | ||
495 | int "Ser3 CD on PA bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PA || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
496 | depends on ETRAX_SERIAL_PORT3 | ||
497 | default "-1" | ||
498 | |||
499 | config ETRAX_SER3_DTR_ON_PB_BIT | ||
500 | int "Ser3 DTR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
501 | depends on ETRAX_SERIAL_PORT3 | ||
502 | default "-1" | ||
503 | |||
504 | config ETRAX_SER3_RI_ON_PB_BIT | ||
505 | int "Ser3 RI on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
506 | depends on ETRAX_SERIAL_PORT3 | ||
507 | default "-1" | ||
508 | |||
509 | config ETRAX_SER3_DSR_ON_PB_BIT | ||
510 | int "Ser3 DSR on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
511 | depends on ETRAX_SERIAL_PORT3 | ||
512 | default "-1" | ||
513 | |||
514 | config ETRAX_SER3_CD_ON_PB_BIT | ||
515 | int "Ser3 CD on PB bit (-1 = not used)" if ETRAX_SER3_DTR_RI_DSR_CD_ON_PB || ETRAX_SER3_DTR_RI_DSR_CD_MIXED | ||
516 | depends on ETRAX_SERIAL_PORT3 | ||
517 | default "-1" | ||
518 | |||
519 | config ETRAX_RS485 | ||
520 | bool "RS-485 support" | ||
521 | depends on ETRAX_SERIAL | ||
522 | help | ||
523 | Enables support for RS-485 serial communication. For a primer on | ||
524 | RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>. | ||
525 | |||
526 | config ETRAX_RS485_ON_PA | ||
527 | bool "RS-485 mode on PA" | ||
528 | depends on ETRAX_RS485 | ||
529 | help | ||
530 | Control Driver Output Enable on RS485 transceiver using a pin on PA | ||
531 | port: | ||
532 | Axis 2400/2401 uses PA 3. | ||
533 | |||
534 | config ETRAX_RS485_ON_PA_BIT | ||
535 | int "RS-485 mode on PA bit" | ||
536 | depends on ETRAX_RS485_ON_PA | ||
537 | default "3" | ||
538 | help | ||
539 | Control Driver Output Enable on RS485 transceiver using a this bit | ||
540 | on PA port. | ||
541 | |||
542 | config ETRAX_RS485_DISABLE_RECEIVER | ||
543 | bool "Disable serial receiver" | ||
544 | depends on ETRAX_RS485 | ||
545 | help | ||
546 | It's necessary to disable the serial receiver to avoid serial | ||
547 | loopback. Not all products are able to do this in software only. | ||
548 | Axis 2400/2401 must disable receiver. | ||
549 | |||
550 | config ETRAX_IDE | ||
551 | bool "ATA/IDE support" | ||
552 | select IDE | ||
553 | select BLK_DEV_IDE | ||
554 | select BLK_DEV_IDEDISK | ||
555 | select BLK_DEV_IDECD | ||
556 | select BLK_DEV_IDEDMA | ||
557 | select DMA_NONPCI | ||
558 | help | ||
559 | Enable this to get support for ATA/IDE. | ||
560 | You can't use paralell ports or SCSI ports | ||
561 | at the same time. | ||
562 | |||
563 | |||
564 | config ETRAX_IDE_DELAY | ||
565 | int "Delay for drives to regain consciousness" | ||
566 | depends on ETRAX_IDE | ||
567 | default 15 | ||
568 | help | ||
569 | Number of seconds to wait for IDE drives to spin up after an IDE | ||
570 | reset. | ||
571 | choice | ||
572 | prompt "IDE reset pin" | ||
573 | depends on ETRAX_IDE | ||
574 | default ETRAX_IDE_PB7_RESET | ||
575 | |||
576 | config ETRAX_IDE_PB7_RESET | ||
577 | bool "Port_PB_Bit_7" | ||
578 | help | ||
579 | IDE reset on pin 7 on port B | ||
580 | |||
581 | config ETRAX_IDE_G27_RESET | ||
582 | bool "Port_G_Bit_27" | ||
583 | help | ||
584 | IDE reset on pin 27 on port G | ||
585 | |||
586 | endchoice | ||
587 | |||
588 | |||
589 | config ETRAX_USB_HOST | ||
590 | bool "USB host" | ||
591 | help | ||
592 | This option enables the host functionality of the ETRAX 100LX | ||
593 | built-in USB controller. In host mode the controller is designed | ||
594 | for CTRL and BULK traffic only, INTR traffic may work as well | ||
595 | however (depending on the requirements of timeliness). | ||
596 | |||
597 | config USB | ||
598 | tristate | ||
599 | depends on ETRAX_USB_HOST | ||
600 | default y | ||
601 | |||
602 | config ETRAX_USB_HOST_PORT1 | ||
603 | bool " USB port 1 enabled" | ||
604 | depends on ETRAX_USB_HOST | ||
605 | default n | ||
606 | |||
607 | config ETRAX_USB_HOST_PORT2 | ||
608 | bool " USB port 2 enabled" | ||
609 | depends on ETRAX_USB_HOST | ||
610 | default n | ||
611 | |||
612 | config ETRAX_AXISFLASHMAP | ||
613 | bool "Axis flash-map support" | ||
614 | depends on ETRAX_ARCH_V10 | ||
615 | help | ||
616 | This option enables MTD mapping of flash devices. Needed to use | ||
617 | flash memories. If unsure, say Y. | ||
618 | |||
619 | config ETRAX_PTABLE_SECTOR | ||
620 | int "Byte-offset of partition table sector" | ||
621 | depends on ETRAX_AXISFLASHMAP | ||
622 | default "65536" | ||
623 | help | ||
624 | Byte-offset of the partition table in the first flash chip. | ||
625 | The default value is 64kB and should not be changed unless | ||
626 | you know exactly what you are doing. The only valid reason | ||
627 | for changing this is when the flash block size is bigger | ||
628 | than 64kB (e.g. when using two parallel 16 bit flashes). | ||
629 | |||
630 | # here we define the CONFIG_'s necessary to enable MTD support | ||
631 | # for the flash | ||
632 | config MTD | ||
633 | tristate | ||
634 | depends on ETRAX_AXISFLASHMAP | ||
635 | default y | ||
636 | help | ||
637 | Memory Technology Devices are flash, RAM and similar chips, often | ||
638 | used for solid state file systems on embedded devices. This option | ||
639 | will provide the generic support for MTD drivers to register | ||
640 | themselves with the kernel and for potential users of MTD devices | ||
641 | to enumerate the devices which are present and obtain a handle on | ||
642 | them. It will also allow you to select individual drivers for | ||
643 | particular hardware and users of MTD devices. If unsure, say N. | ||
644 | |||
645 | config MTD_CFI | ||
646 | tristate | ||
647 | depends on ETRAX_AXISFLASHMAP | ||
648 | default y | ||
649 | help | ||
650 | The Common Flash Interface specification was developed by Intel, | ||
651 | AMD and other flash manufactures that provides a universal method | ||
652 | for probing the capabilities of flash devices. If you wish to | ||
653 | support any device that is CFI-compliant, you need to enable this | ||
654 | option. Visit <http://www.amd.com/products/nvd/overview/cfi.html> | ||
655 | for more information on CFI. | ||
656 | |||
657 | config MTD_CFI_AMDSTD | ||
658 | tristate | ||
659 | depends on ETRAX_AXISFLASHMAP | ||
660 | default y | ||
661 | help | ||
662 | The Common Flash Interface defines a number of different command | ||
663 | sets which a CFI-compliant chip may claim to implement. This code | ||
664 | provides support for one of those command sets, used on chips | ||
665 | chips including the AMD Am29LV320. | ||
666 | |||
667 | config MTD_OBSOLETE_CHIPS | ||
668 | bool | ||
669 | depends on ETRAX_AXISFLASHMAP | ||
670 | default y | ||
671 | help | ||
672 | This option does not enable any code directly, but will allow you to | ||
673 | select some other chip drivers which are now considered obsolete, | ||
674 | because the generic CONFIG_JEDEC_PROBE code above should now detect | ||
675 | the chips which are supported by these drivers, and allow the generic | ||
676 | CFI-compatible drivers to drive the chips. Say 'N' here unless you have | ||
677 | already tried the CONFIG_JEDEC_PROBE method and reported its failure | ||
678 | to the MTD mailing list at <linux-mtd@lists.infradead.org> | ||
679 | |||
680 | config MTD_AMDSTD | ||
681 | tristate | ||
682 | depends on ETRAX_AXISFLASHMAP | ||
683 | default y | ||
684 | help | ||
685 | This option enables support for flash chips using AMD-compatible | ||
686 | commands, including some which are not CFI-compatible and hence | ||
687 | cannot be used with the CONFIG_MTD_CFI_AMDSTD option. | ||
688 | |||
689 | It also works on AMD compatible chips that do conform to CFI. | ||
690 | |||
691 | config MTD_CHAR | ||
692 | tristate | ||
693 | depends on ETRAX_AXISFLASHMAP | ||
694 | default y | ||
695 | help | ||
696 | This provides a character device for each MTD device present in | ||
697 | the system, allowing the user to read and write directly to the | ||
698 | memory chips, and also use ioctl() to obtain information about | ||
699 | the device, or to erase parts of it. | ||
700 | |||
701 | config MTD_BLOCK | ||
702 | tristate | ||
703 | depends on ETRAX_AXISFLASHMAP | ||
704 | default y | ||
705 | ---help--- | ||
706 | Although most flash chips have an erase size too large to be useful | ||
707 | as block devices, it is possible to use MTD devices which are based | ||
708 | on RAM chips in this manner. This block device is a user of MTD | ||
709 | devices performing that function. | ||
710 | |||
711 | At the moment, it is also required for the Journalling Flash File | ||
712 | System(s) to obtain a handle on the MTD device when it's mounted | ||
713 | (although JFFS and JFFS2 don't actually use any of the functionality | ||
714 | of the mtdblock device). | ||
715 | |||
716 | Later, it may be extended to perform read/erase/modify/write cycles | ||
717 | on flash chips to emulate a smaller block size. Needless to say, | ||
718 | this is very unsafe, but could be useful for file systems which are | ||
719 | almost never written to. | ||
720 | |||
721 | You do not need this option for use with the DiskOnChip devices. For | ||
722 | those, enable NFTL support (CONFIG_NFTL) instead. | ||
723 | |||
724 | config MTD_PARTITIONS | ||
725 | tristate | ||
726 | depends on ETRAX_AXISFLASHMAP | ||
727 | default y | ||
728 | help | ||
729 | If you have a device which needs to divide its flash chip(s) up | ||
730 | into multiple 'partitions', each of which appears to the user as | ||
731 | a separate MTD device, you require this option to be enabled. If | ||
732 | unsure, say 'Y'. | ||
733 | |||
734 | Note, however, that you don't need this option for the DiskOnChip | ||
735 | devices. Partitioning on NFTL 'devices' is a different - that's the | ||
736 | 'normal' form of partitioning used on a block device. | ||
737 | |||
738 | config MTD_CONCAT | ||
739 | tristate | ||
740 | depends on ETRAX_AXISFLASHMAP | ||
741 | default y | ||
742 | |||
743 | config ETRAX_I2C | ||
744 | bool "I2C support" | ||
745 | depends on ETRAX_ARCH_V10 | ||
746 | help | ||
747 | Enables an I2C driver on ETRAX100. | ||
748 | EXAMPLE usage: | ||
749 | i2c_arg = I2C_WRITEARG(STA013_WRITE_ADDR, reg, val); | ||
750 | ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_WRITEREG), i2c_arg); | ||
751 | i2c_arg = I2C_READARG(STA013_READ_ADDR, reg); | ||
752 | val = ioctl(fd, _IO(ETRAXI2C_IOCTYPE, I2C_READREG), i2c_arg); | ||
753 | |||
754 | # this is true for most products since PB-I2C seems to be somewhat | ||
755 | # flawed.. | ||
756 | config ETRAX_I2C_USES_PB_NOT_PB_I2C | ||
757 | bool "I2C uses PB not PB-I2C" | ||
758 | depends on ETRAX_I2C | ||
759 | help | ||
760 | Select whether to use the special I2C mode in the PB I/O register or | ||
761 | not. This option needs to be selected in order to use some drivers | ||
762 | that access the I2C I/O pins directly instead of going through the | ||
763 | I2C driver, like the DS1302 realtime-clock driver. If you are | ||
764 | uncertain, choose Y here. | ||
765 | |||
766 | config ETRAX_I2C_DATA_PORT | ||
767 | int "I2C SDA bit number" | ||
768 | depends on ETRAX_I2C_USES_PB_NOT_PB_I2C | ||
769 | default "0" | ||
770 | help | ||
771 | Selects the pin on Port B where the data pin is connected | ||
772 | |||
773 | config ETRAX_I2C_CLK_PORT | ||
774 | int "I2C SCL bit number" | ||
775 | depends on ETRAX_I2C_USES_PB_NOT_PB_I2C | ||
776 | default "1" | ||
777 | help | ||
778 | Select the pin on Port B where the clock pin is connected | ||
779 | |||
780 | config ETRAX_I2C_EEPROM | ||
781 | bool "I2C EEPROM (non-volatile RAM) support" | ||
782 | depends on ETRAX_I2C | ||
783 | help | ||
784 | Enables I2C EEPROM (non-volatile RAM) on PB0 and PB1 using the I2C | ||
785 | driver. Select size option: Probed, 2k, 8k, 16k. | ||
786 | (Probing works for 2k and 8k but not that well for 16k) | ||
787 | |||
788 | choice | ||
789 | prompt "EEPROM size" | ||
790 | depends on ETRAX_I2C_EEPROM | ||
791 | default ETRAX_I2C_EEPROM_PROBE | ||
792 | |||
793 | config ETRAX_I2C_EEPROM_PROBE | ||
794 | bool "Probed" | ||
795 | help | ||
796 | Specifies size or auto probe of the EEPROM size. | ||
797 | Options: Probed, 2k, 8k, 16k. | ||
798 | (Probing works for 2k and 8k but not that well for 16k) | ||
799 | |||
800 | config ETRAX_I2C_EEPROM_2KB | ||
801 | bool "2kB" | ||
802 | help | ||
803 | Use a 2kB EEPROM. | ||
804 | |||
805 | config ETRAX_I2C_EEPROM_8KB | ||
806 | bool "8kB" | ||
807 | help | ||
808 | Use a 8kB EEPROM. | ||
809 | |||
810 | config ETRAX_I2C_EEPROM_16KB | ||
811 | bool "16kB" | ||
812 | help | ||
813 | Use a 16kB EEPROM. | ||
814 | |||
815 | endchoice | ||
816 | |||
817 | config ETRAX_GPIO | ||
818 | bool "GPIO support" | ||
819 | depends on ETRAX_ARCH_V10 | ||
820 | ---help--- | ||
821 | Enables the ETRAX general port device (major 120, minors 0 and 1). | ||
822 | You can use this driver to access the general port bits. It supports | ||
823 | these ioctl's: | ||
824 | #include <linux/etraxgpio.h> | ||
825 | fd = open("/dev/gpioa", O_RDWR); // or /dev/gpiob | ||
826 | ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_SETBITS), bits_to_set); | ||
827 | ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_CLRBITS), bits_to_clear); | ||
828 | val = ioctl(fd, _IO(ETRAXGPIO_IOCTYPE, IO_READBITS), NULL); | ||
829 | Remember that you need to setup the port directions appropriately in | ||
830 | the General configuration. | ||
831 | |||
832 | config ETRAX_PA_BUTTON_BITMASK | ||
833 | hex "PA-buttons bitmask" | ||
834 | depends on ETRAX_GPIO | ||
835 | default "02" | ||
836 | help | ||
837 | This is a bitmask with information about what bits on PA that | ||
838 | are used for buttons. | ||
839 | Most products has a so called TEST button on PA1, if that's true | ||
840 | use 02 here. | ||
841 | Use 00 if there are no buttons on PA. | ||
842 | If the bitmask is <> 00 a button driver will be included in the gpio | ||
843 | driver. ETRAX general I/O support must be enabled. | ||
844 | |||
845 | config ETRAX_PA_CHANGEABLE_DIR | ||
846 | hex "PA user changeable dir mask" | ||
847 | depends on ETRAX_GPIO | ||
848 | default "00" | ||
849 | help | ||
850 | This is a bitmask with information of what bits in PA that a user | ||
851 | can change direction on using ioctl's. | ||
852 | Bit set = changeable. | ||
853 | You probably want 00 here. | ||
854 | |||
855 | config ETRAX_PA_CHANGEABLE_BITS | ||
856 | hex "PA user changeable bits mask" | ||
857 | depends on ETRAX_GPIO | ||
858 | default "FF" | ||
859 | help | ||
860 | This is a bitmask with information of what bits in PA that a user | ||
861 | can change change the value on using ioctl's. | ||
862 | Bit set = changeable. | ||
863 | You probably want 00 here. | ||
864 | |||
865 | config ETRAX_PB_CHANGEABLE_DIR | ||
866 | hex "PB user changeable dir mask" | ||
867 | depends on ETRAX_GPIO | ||
868 | default "00" | ||
869 | help | ||
870 | This is a bitmask with information of what bits in PB that a user | ||
871 | can change direction on using ioctl's. | ||
872 | Bit set = changeable. | ||
873 | You probably want 00 here. | ||
874 | |||
875 | config ETRAX_PB_CHANGEABLE_BITS | ||
876 | hex "PB user changeable bits mask" | ||
877 | depends on ETRAX_GPIO | ||
878 | default "FF" | ||
879 | help | ||
880 | This is a bitmask with information of what bits in PB that a user | ||
881 | can change the value on using ioctl's. | ||
882 | Bit set = changeable. | ||
883 | You probably want 00 here. | ||
884 | |||
885 | config ETRAX_RTC | ||
886 | bool "Real Time Clock support" | ||
887 | depends on ETRAX_ARCH_V10 | ||
888 | help | ||
889 | Enables drivers for the Real-Time Clock battery-backed chips on | ||
890 | some products. The kernel reads the time when booting, and | ||
891 | the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a | ||
892 | rtc_time struct (see <file:include/asm-cris/rtc.h>) on the /dev/rtc | ||
893 | device, major 121. You can check the time with cat /proc/rtc, but | ||
894 | normal time reading should be done using libc function time and | ||
895 | friends. | ||
896 | |||
897 | choice | ||
898 | prompt "RTC chip" | ||
899 | depends on ETRAX_RTC | ||
900 | default ETRAX_DS1302 | ||
901 | |||
902 | config ETRAX_DS1302 | ||
903 | bool "DS1302" | ||
904 | help | ||
905 | Enables the driver for the DS1302 Real-Time Clock battery-backed | ||
906 | chip on some products. | ||
907 | |||
908 | config ETRAX_PCF8563 | ||
909 | bool "PCF8563" | ||
910 | help | ||
911 | Enables the driver for the PCF8563 Real-Time Clock battery-backed | ||
912 | chip on some products. | ||
913 | |||
914 | endchoice | ||
915 | |||
916 | config ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
917 | bool "DS1302 RST on Generic Port" | ||
918 | depends on ETRAX_DS1302 | ||
919 | help | ||
920 | If your product has the RST signal line for the DS1302 RTC on the | ||
921 | Generic Port then say Y here, otherwise leave it as N in which | ||
922 | case the RST signal line is assumed to be connected to Port PB | ||
923 | (just like the SCL and SDA lines). | ||
924 | |||
925 | config ETRAX_DS1302_RSTBIT | ||
926 | int "DS1302 RST bit number" | ||
927 | depends on ETRAX_DS1302 | ||
928 | default "2" | ||
929 | help | ||
930 | This is the bit number for the RST signal line of the DS1302 RTC on | ||
931 | the selected port. If you have selected the generic port then it | ||
932 | should be bit 27, otherwise your best bet is bit 5. | ||
933 | |||
934 | config ETRAX_DS1302_SCLBIT | ||
935 | int "DS1302 SCL bit number" | ||
936 | depends on ETRAX_DS1302 | ||
937 | default "1" | ||
938 | help | ||
939 | This is the bit number for the SCL signal line of the DS1302 RTC on | ||
940 | Port PB. This is probably best left at 3. | ||
941 | |||
942 | config ETRAX_DS1302_SDABIT | ||
943 | int "DS1302 SDA bit number" | ||
944 | depends on ETRAX_DS1302 | ||
945 | default "0" | ||
946 | help | ||
947 | This is the bit number for the SDA signal line of the DS1302 RTC on | ||
948 | Port PB. This is probably best left at 2. | ||
949 | |||
950 | config ETRAX_DS1302_TRICKLE_CHARGE | ||
951 | int "DS1302 Trickle charger value" | ||
952 | depends on ETRAX_DS1302 | ||
953 | default "0" | ||
954 | help | ||
955 | This controls the initial value of the trickle charge register. | ||
956 | 0 = disabled (use this if you are unsure or have a non rechargable battery) | ||
957 | Otherwise the following values can be OR:ed together to control the | ||
958 | charge current: | ||
959 | 1 = 2kohm, 2 = 4kohm, 3 = 4kohm | ||
960 | 4 = 1 diode, 8 = 2 diodes | ||
961 | Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5 | ||
962 | |||
963 | |||
diff --git a/arch/cris/arch-v10/drivers/Makefile b/arch/cris/arch-v10/drivers/Makefile new file mode 100644 index 000000000000..20258e36f384 --- /dev/null +++ b/arch/cris/arch-v10/drivers/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for Etrax-specific drivers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_ETRAX_AXISFLASHMAP) += axisflashmap.o | ||
6 | obj-$(CONFIG_ETRAX_I2C) += i2c.o | ||
7 | obj-$(CONFIG_ETRAX_I2C_EEPROM) += eeprom.o | ||
8 | obj-$(CONFIG_ETRAX_GPIO) += gpio.o | ||
9 | obj-$(CONFIG_ETRAX_DS1302) += ds1302.o | ||
10 | obj-$(CONFIG_ETRAX_PCF8563) += pcf8563.o | ||
11 | |||
12 | |||
diff --git a/arch/cris/arch-v10/drivers/axisflashmap.c b/arch/cris/arch-v10/drivers/axisflashmap.c new file mode 100644 index 000000000000..fb7d4855ea62 --- /dev/null +++ b/arch/cris/arch-v10/drivers/axisflashmap.c | |||
@@ -0,0 +1,541 @@ | |||
1 | /* | ||
2 | * Physical mapping layer for MTD using the Axis partitiontable format | ||
3 | * | ||
4 | * Copyright (c) 2001, 2002 Axis Communications AB | ||
5 | * | ||
6 | * This file is under the GPL. | ||
7 | * | ||
8 | * First partition is always sector 0 regardless of if we find a partitiontable | ||
9 | * or not. In the start of the next sector, there can be a partitiontable that | ||
10 | * tells us what other partitions to define. If there isn't, we use a default | ||
11 | * partition split defined below. | ||
12 | * | ||
13 | * $Log: axisflashmap.c,v $ | ||
14 | * Revision 1.10 2004/08/16 12:37:22 starvik | ||
15 | * Merge of Linux 2.6.8 | ||
16 | * | ||
17 | * Revision 1.8 2004/05/14 07:58:03 starvik | ||
18 | * Merge of changes from 2.4 | ||
19 | * | ||
20 | * Revision 1.6 2003/07/04 08:27:37 starvik | ||
21 | * Merge of Linux 2.5.74 | ||
22 | * | ||
23 | * Revision 1.5 2002/12/11 13:13:57 starvik | ||
24 | * Added arch/ to v10 specific includes | ||
25 | * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
26 | * | ||
27 | * Revision 1.4 2002/11/20 11:56:10 starvik | ||
28 | * Merge of Linux 2.5.48 | ||
29 | * | ||
30 | * Revision 1.3 2002/11/13 14:54:13 starvik | ||
31 | * Copied from linux 2.4 | ||
32 | * | ||
33 | * Revision 1.28 2002/10/01 08:08:43 jonashg | ||
34 | * The first partition ends at the start of the partition table. | ||
35 | * | ||
36 | * Revision 1.27 2002/08/21 09:23:13 jonashg | ||
37 | * Speling. | ||
38 | * | ||
39 | * Revision 1.26 2002/08/21 08:35:20 jonashg | ||
40 | * Cosmetic change to printouts. | ||
41 | * | ||
42 | * Revision 1.25 2002/08/21 08:15:42 jonashg | ||
43 | * Made it compile even without CONFIG_MTD_CONCAT defined. | ||
44 | * | ||
45 | * Revision 1.24 2002/08/20 13:12:35 jonashg | ||
46 | * * New approach to probing. Probe cse0 and cse1 separately and (mtd)concat | ||
47 | * the results. | ||
48 | * * Removed compile time tests concerning how the mtdram driver has been | ||
49 | * configured. The user will know about the misconfiguration at runtime | ||
50 | * instead. (The old approach made it impossible to use mtdram for anything | ||
51 | * else than RAM boot). | ||
52 | * | ||
53 | * Revision 1.23 2002/05/13 12:12:28 johana | ||
54 | * Allow compile without CONFIG_MTD_MTDRAM but warn at compiletime and | ||
55 | * be informative at runtime. | ||
56 | * | ||
57 | * Revision 1.22 2002/05/13 10:24:44 johana | ||
58 | * Added #if checks on MTDRAM CONFIG | ||
59 | * | ||
60 | * Revision 1.21 2002/05/06 16:05:20 johana | ||
61 | * Removed debug printout. | ||
62 | * | ||
63 | * Revision 1.20 2002/05/06 16:03:00 johana | ||
64 | * No more cramfs as root hack in generic code. | ||
65 | * It's handled by axisflashmap using mtdram. | ||
66 | * | ||
67 | * Revision 1.19 2002/03/15 17:10:28 bjornw | ||
68 | * Changed comment about cached access since we changed this before | ||
69 | * | ||
70 | * Revision 1.18 2002/03/05 17:06:15 jonashg | ||
71 | * Try amd_flash probe before cfi_probe since amd_flash driver can handle two | ||
72 | * (or more) flash chips of different model and the cfi driver cannot. | ||
73 | * | ||
74 | * Revision 1.17 2001/11/12 19:42:38 pkj | ||
75 | * Fixed compiler warnings. | ||
76 | * | ||
77 | * Revision 1.16 2001/11/08 11:18:58 jonashg | ||
78 | * Always read from uncached address to avoid problems with flushing | ||
79 | * cachelines after write and MTD-erase. No performance loss have been | ||
80 | * seen yet. | ||
81 | * | ||
82 | * Revision 1.15 2001/10/19 12:41:04 jonashg | ||
83 | * Name of probe has changed in MTD. | ||
84 | * | ||
85 | * Revision 1.14 2001/09/21 07:14:10 jonashg | ||
86 | * Made root filesystem (cramfs) use mtdblock driver when booting from flash. | ||
87 | * | ||
88 | * Revision 1.13 2001/08/15 13:57:35 jonashg | ||
89 | * Entire MTD updated to the linux 2.4.7 version. | ||
90 | * | ||
91 | * Revision 1.12 2001/06/11 09:50:30 jonashg | ||
92 | * Oops, 2MB is 0x200000 bytes. | ||
93 | * | ||
94 | * Revision 1.11 2001/06/08 11:39:44 jonashg | ||
95 | * Changed sizes and offsets in axis_default_partitions to use | ||
96 | * CONFIG_ETRAX_PTABLE_SECTOR. | ||
97 | * | ||
98 | * Revision 1.10 2001/05/29 09:42:03 jonashg | ||
99 | * Use macro for end marker length instead of sizeof. | ||
100 | * | ||
101 | * Revision 1.9 2001/05/29 08:52:52 jonashg | ||
102 | * Gave names to the magic fours (size of the ptable end marker). | ||
103 | * | ||
104 | * Revision 1.8 2001/05/28 15:36:20 jonashg | ||
105 | * * Removed old comment about ptable location in flash (it's a CONFIG_ option). | ||
106 | * * Variable ptable was initialized twice to the same value. | ||
107 | * | ||
108 | * Revision 1.7 2001/04/05 13:41:46 markusl | ||
109 | * Updated according to review remarks | ||
110 | * | ||
111 | * Revision 1.6 2001/03/07 09:21:21 bjornw | ||
112 | * No need to waste .data | ||
113 | * | ||
114 | * Revision 1.5 2001/03/06 16:27:01 jonashg | ||
115 | * Probe the entire flash area for flash devices. | ||
116 | * | ||
117 | * Revision 1.4 2001/02/23 12:47:15 bjornw | ||
118 | * Uncached flash in LOW_MAP moved from 0xe to 0x8 | ||
119 | * | ||
120 | * Revision 1.3 2001/02/16 12:11:45 jonashg | ||
121 | * MTD driver amd_flash is now included in MTD CVS repository. | ||
122 | * (It's now in drivers/mtd). | ||
123 | * | ||
124 | * Revision 1.2 2001/02/09 11:12:22 jonashg | ||
125 | * Support for AMD compatible non-CFI flash chips. | ||
126 | * Only tested with Toshiba TC58FVT160 so far. | ||
127 | * | ||
128 | * Revision 1.1 2001/01/12 17:01:18 bjornw | ||
129 | * * Added axisflashmap.c, a physical mapping for MTD that reads and understands | ||
130 | * Axis partition-table format. | ||
131 | * | ||
132 | * | ||
133 | */ | ||
134 | |||
135 | #include <linux/module.h> | ||
136 | #include <linux/types.h> | ||
137 | #include <linux/kernel.h> | ||
138 | #include <linux/config.h> | ||
139 | #include <linux/init.h> | ||
140 | |||
141 | #include <linux/mtd/concat.h> | ||
142 | #include <linux/mtd/map.h> | ||
143 | #include <linux/mtd/mtd.h> | ||
144 | #include <linux/mtd/mtdram.h> | ||
145 | #include <linux/mtd/partitions.h> | ||
146 | |||
147 | #include <asm/axisflashmap.h> | ||
148 | #include <asm/mmu.h> | ||
149 | #include <asm/arch/sv_addr_ag.h> | ||
150 | |||
151 | #ifdef CONFIG_CRIS_LOW_MAP | ||
152 | #define FLASH_UNCACHED_ADDR KSEG_8 | ||
153 | #define FLASH_CACHED_ADDR KSEG_5 | ||
154 | #else | ||
155 | #define FLASH_UNCACHED_ADDR KSEG_E | ||
156 | #define FLASH_CACHED_ADDR KSEG_F | ||
157 | #endif | ||
158 | |||
159 | #if CONFIG_ETRAX_FLASH_BUSWIDTH==1 | ||
160 | #define flash_data __u8 | ||
161 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==2 | ||
162 | #define flash_data __u16 | ||
163 | #elif CONFIG_ETRAX_FLASH_BUSWIDTH==4 | ||
164 | #define flash_data __u16 | ||
165 | #endif | ||
166 | |||
167 | /* From head.S */ | ||
168 | extern unsigned long romfs_start, romfs_length, romfs_in_flash; | ||
169 | |||
170 | /* The master mtd for the entire flash. */ | ||
171 | struct mtd_info* axisflash_mtd = NULL; | ||
172 | |||
173 | /* Map driver functions. */ | ||
174 | |||
175 | static map_word flash_read(struct map_info *map, unsigned long ofs) | ||
176 | { | ||
177 | map_word tmp; | ||
178 | tmp.x[0] = *(flash_data *)(map->map_priv_1 + ofs); | ||
179 | return tmp; | ||
180 | } | ||
181 | |||
182 | static void flash_copy_from(struct map_info *map, void *to, | ||
183 | unsigned long from, ssize_t len) | ||
184 | { | ||
185 | memcpy(to, (void *)(map->map_priv_1 + from), len); | ||
186 | } | ||
187 | |||
188 | static void flash_write(struct map_info *map, map_word d, unsigned long adr) | ||
189 | { | ||
190 | *(flash_data *)(map->map_priv_1 + adr) = (flash_data)d.x[0]; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * The map for chip select e0. | ||
195 | * | ||
196 | * We run into tricky coherence situations if we mix cached with uncached | ||
197 | * accesses to we only use the uncached version here. | ||
198 | * | ||
199 | * The size field is the total size where the flash chips may be mapped on the | ||
200 | * chip select. MTD probes should find all devices there and it does not matter | ||
201 | * if there are unmapped gaps or aliases (mirrors of flash devices). The MTD | ||
202 | * probes will ignore them. | ||
203 | * | ||
204 | * The start address in map_priv_1 is in virtual memory so we cannot use | ||
205 | * MEM_CSE0_START but must rely on that FLASH_UNCACHED_ADDR is the start | ||
206 | * address of cse0. | ||
207 | */ | ||
208 | static struct map_info map_cse0 = { | ||
209 | .name = "cse0", | ||
210 | .size = MEM_CSE0_SIZE, | ||
211 | .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, | ||
212 | .read = flash_read, | ||
213 | .copy_from = flash_copy_from, | ||
214 | .write = flash_write, | ||
215 | .map_priv_1 = FLASH_UNCACHED_ADDR | ||
216 | }; | ||
217 | |||
218 | /* | ||
219 | * The map for chip select e1. | ||
220 | * | ||
221 | * If there was a gap between cse0 and cse1, map_priv_1 would get the wrong | ||
222 | * address, but there isn't. | ||
223 | */ | ||
224 | static struct map_info map_cse1 = { | ||
225 | .name = "cse1", | ||
226 | .size = MEM_CSE1_SIZE, | ||
227 | .bankwidth = CONFIG_ETRAX_FLASH_BUSWIDTH, | ||
228 | .read = flash_read, | ||
229 | .copy_from = flash_copy_from, | ||
230 | .write = flash_write, | ||
231 | .map_priv_1 = FLASH_UNCACHED_ADDR + MEM_CSE0_SIZE | ||
232 | }; | ||
233 | |||
234 | /* If no partition-table was found, we use this default-set. */ | ||
235 | #define MAX_PARTITIONS 7 | ||
236 | #define NUM_DEFAULT_PARTITIONS 3 | ||
237 | |||
238 | /* | ||
239 | * Default flash size is 2MB. CONFIG_ETRAX_PTABLE_SECTOR is most likely the | ||
240 | * size of one flash block and "filesystem"-partition needs 5 blocks to be able | ||
241 | * to use JFFS. | ||
242 | */ | ||
243 | static struct mtd_partition axis_default_partitions[NUM_DEFAULT_PARTITIONS] = { | ||
244 | { | ||
245 | .name = "boot firmware", | ||
246 | .size = CONFIG_ETRAX_PTABLE_SECTOR, | ||
247 | .offset = 0 | ||
248 | }, | ||
249 | { | ||
250 | .name = "kernel", | ||
251 | .size = 0x200000 - (6 * CONFIG_ETRAX_PTABLE_SECTOR), | ||
252 | .offset = CONFIG_ETRAX_PTABLE_SECTOR | ||
253 | }, | ||
254 | { | ||
255 | .name = "filesystem", | ||
256 | .size = 5 * CONFIG_ETRAX_PTABLE_SECTOR, | ||
257 | .offset = 0x200000 - (5 * CONFIG_ETRAX_PTABLE_SECTOR) | ||
258 | } | ||
259 | }; | ||
260 | |||
261 | /* Initialize the ones normally used. */ | ||
262 | static struct mtd_partition axis_partitions[MAX_PARTITIONS] = { | ||
263 | { | ||
264 | .name = "part0", | ||
265 | .size = CONFIG_ETRAX_PTABLE_SECTOR, | ||
266 | .offset = 0 | ||
267 | }, | ||
268 | { | ||
269 | .name = "part1", | ||
270 | .size = 0, | ||
271 | .offset = 0 | ||
272 | }, | ||
273 | { | ||
274 | .name = "part2", | ||
275 | .size = 0, | ||
276 | .offset = 0 | ||
277 | }, | ||
278 | { | ||
279 | .name = "part3", | ||
280 | .size = 0, | ||
281 | .offset = 0 | ||
282 | }, | ||
283 | { | ||
284 | .name = "part4", | ||
285 | .size = 0, | ||
286 | .offset = 0 | ||
287 | }, | ||
288 | { | ||
289 | .name = "part5", | ||
290 | .size = 0, | ||
291 | .offset = 0 | ||
292 | }, | ||
293 | { | ||
294 | .name = "part6", | ||
295 | .size = 0, | ||
296 | .offset = 0 | ||
297 | }, | ||
298 | }; | ||
299 | |||
300 | /* | ||
301 | * Probe a chip select for AMD-compatible (JEDEC) or CFI-compatible flash | ||
302 | * chips in that order (because the amd_flash-driver is faster). | ||
303 | */ | ||
304 | static struct mtd_info *probe_cs(struct map_info *map_cs) | ||
305 | { | ||
306 | struct mtd_info *mtd_cs = NULL; | ||
307 | |||
308 | printk(KERN_INFO | ||
309 | "%s: Probing a 0x%08lx bytes large window at 0x%08lx.\n", | ||
310 | map_cs->name, map_cs->size, map_cs->map_priv_1); | ||
311 | |||
312 | #ifdef CONFIG_MTD_AMDSTD | ||
313 | mtd_cs = do_map_probe("amd_flash", map_cs); | ||
314 | #endif | ||
315 | #ifdef CONFIG_MTD_CFI | ||
316 | if (!mtd_cs) { | ||
317 | mtd_cs = do_map_probe("cfi_probe", map_cs); | ||
318 | } | ||
319 | #endif | ||
320 | |||
321 | return mtd_cs; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Probe each chip select individually for flash chips. If there are chips on | ||
326 | * both cse0 and cse1, the mtd_info structs will be concatenated to one struct | ||
327 | * so that MTD partitions can cross chip boundries. | ||
328 | * | ||
329 | * The only known restriction to how you can mount your chips is that each | ||
330 | * chip select must hold similar flash chips. But you need external hardware | ||
331 | * to do that anyway and you can put totally different chips on cse0 and cse1 | ||
332 | * so it isn't really much of a restriction. | ||
333 | */ | ||
334 | static struct mtd_info *flash_probe(void) | ||
335 | { | ||
336 | struct mtd_info *mtd_cse0; | ||
337 | struct mtd_info *mtd_cse1; | ||
338 | struct mtd_info *mtd_cse; | ||
339 | |||
340 | mtd_cse0 = probe_cs(&map_cse0); | ||
341 | mtd_cse1 = probe_cs(&map_cse1); | ||
342 | |||
343 | if (!mtd_cse0 && !mtd_cse1) { | ||
344 | /* No chip found. */ | ||
345 | return NULL; | ||
346 | } | ||
347 | |||
348 | if (mtd_cse0 && mtd_cse1) { | ||
349 | #ifdef CONFIG_MTD_CONCAT | ||
350 | struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 }; | ||
351 | |||
352 | /* Since the concatenation layer adds a small overhead we | ||
353 | * could try to figure out if the chips in cse0 and cse1 are | ||
354 | * identical and reprobe the whole cse0+cse1 window. But since | ||
355 | * flash chips are slow, the overhead is relatively small. | ||
356 | * So we use the MTD concatenation layer instead of further | ||
357 | * complicating the probing procedure. | ||
358 | */ | ||
359 | mtd_cse = mtd_concat_create(mtds, | ||
360 | sizeof(mtds) / sizeof(mtds[0]), | ||
361 | "cse0+cse1"); | ||
362 | #else | ||
363 | printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel " | ||
364 | "(mis)configuration!\n", map_cse0.name, map_cse1.name); | ||
365 | mtd_cse = NULL; | ||
366 | #endif | ||
367 | if (!mtd_cse) { | ||
368 | printk(KERN_ERR "%s and %s: Concatenation failed!\n", | ||
369 | map_cse0.name, map_cse1.name); | ||
370 | |||
371 | /* The best we can do now is to only use what we found | ||
372 | * at cse0. | ||
373 | */ | ||
374 | mtd_cse = mtd_cse0; | ||
375 | map_destroy(mtd_cse1); | ||
376 | } | ||
377 | } else { | ||
378 | mtd_cse = mtd_cse0? mtd_cse0 : mtd_cse1; | ||
379 | } | ||
380 | |||
381 | return mtd_cse; | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * Probe the flash chip(s) and, if it succeeds, read the partition-table | ||
386 | * and register the partitions with MTD. | ||
387 | */ | ||
388 | static int __init init_axis_flash(void) | ||
389 | { | ||
390 | struct mtd_info *mymtd; | ||
391 | int err = 0; | ||
392 | int pidx = 0; | ||
393 | struct partitiontable_head *ptable_head = NULL; | ||
394 | struct partitiontable_entry *ptable; | ||
395 | int use_default_ptable = 1; /* Until proven otherwise. */ | ||
396 | const char *pmsg = " /dev/flash%d at 0x%08x, size 0x%08x\n"; | ||
397 | |||
398 | if (!(mymtd = flash_probe())) { | ||
399 | /* There's no reason to use this module if no flash chip can | ||
400 | * be identified. Make sure that's understood. | ||
401 | */ | ||
402 | printk(KERN_INFO "axisflashmap: Found no flash chip.\n"); | ||
403 | } else { | ||
404 | printk(KERN_INFO "%s: 0x%08x bytes of flash memory.\n", | ||
405 | mymtd->name, mymtd->size); | ||
406 | axisflash_mtd = mymtd; | ||
407 | } | ||
408 | |||
409 | if (mymtd) { | ||
410 | mymtd->owner = THIS_MODULE; | ||
411 | ptable_head = (struct partitiontable_head *)(FLASH_CACHED_ADDR + | ||
412 | CONFIG_ETRAX_PTABLE_SECTOR + | ||
413 | PARTITION_TABLE_OFFSET); | ||
414 | } | ||
415 | pidx++; /* First partition is always set to the default. */ | ||
416 | |||
417 | if (ptable_head && (ptable_head->magic == PARTITION_TABLE_MAGIC) | ||
418 | && (ptable_head->size < | ||
419 | (MAX_PARTITIONS * sizeof(struct partitiontable_entry) + | ||
420 | PARTITIONTABLE_END_MARKER_SIZE)) | ||
421 | && (*(unsigned long*)((void*)ptable_head + sizeof(*ptable_head) + | ||
422 | ptable_head->size - | ||
423 | PARTITIONTABLE_END_MARKER_SIZE) | ||
424 | == PARTITIONTABLE_END_MARKER)) { | ||
425 | /* Looks like a start, sane length and end of a | ||
426 | * partition table, lets check csum etc. | ||
427 | */ | ||
428 | int ptable_ok = 0; | ||
429 | struct partitiontable_entry *max_addr = | ||
430 | (struct partitiontable_entry *) | ||
431 | ((unsigned long)ptable_head + sizeof(*ptable_head) + | ||
432 | ptable_head->size); | ||
433 | unsigned long offset = CONFIG_ETRAX_PTABLE_SECTOR; | ||
434 | unsigned char *p; | ||
435 | unsigned long csum = 0; | ||
436 | |||
437 | ptable = (struct partitiontable_entry *) | ||
438 | ((unsigned long)ptable_head + sizeof(*ptable_head)); | ||
439 | |||
440 | /* Lets be PARANOID, and check the checksum. */ | ||
441 | p = (unsigned char*) ptable; | ||
442 | |||
443 | while (p <= (unsigned char*)max_addr) { | ||
444 | csum += *p++; | ||
445 | csum += *p++; | ||
446 | csum += *p++; | ||
447 | csum += *p++; | ||
448 | } | ||
449 | ptable_ok = (csum == ptable_head->checksum); | ||
450 | |||
451 | /* Read the entries and use/show the info. */ | ||
452 | printk(KERN_INFO " Found a%s partition table at 0x%p-0x%p.\n", | ||
453 | (ptable_ok ? " valid" : "n invalid"), ptable_head, | ||
454 | max_addr); | ||
455 | |||
456 | /* We have found a working bootblock. Now read the | ||
457 | * partition table. Scan the table. It ends when | ||
458 | * there is 0xffffffff, that is, empty flash. | ||
459 | */ | ||
460 | while (ptable_ok | ||
461 | && ptable->offset != 0xffffffff | ||
462 | && ptable < max_addr | ||
463 | && pidx < MAX_PARTITIONS) { | ||
464 | |||
465 | axis_partitions[pidx].offset = offset + ptable->offset; | ||
466 | axis_partitions[pidx].size = ptable->size; | ||
467 | |||
468 | printk(pmsg, pidx, axis_partitions[pidx].offset, | ||
469 | axis_partitions[pidx].size); | ||
470 | pidx++; | ||
471 | ptable++; | ||
472 | } | ||
473 | use_default_ptable = !ptable_ok; | ||
474 | } | ||
475 | |||
476 | if (romfs_in_flash) { | ||
477 | /* Add an overlapping device for the root partition (romfs). */ | ||
478 | |||
479 | axis_partitions[pidx].name = "romfs"; | ||
480 | axis_partitions[pidx].size = romfs_length; | ||
481 | axis_partitions[pidx].offset = romfs_start - FLASH_CACHED_ADDR; | ||
482 | axis_partitions[pidx].mask_flags |= MTD_WRITEABLE; | ||
483 | |||
484 | printk(KERN_INFO | ||
485 | " Adding readonly flash partition for romfs image:\n"); | ||
486 | printk(pmsg, pidx, axis_partitions[pidx].offset, | ||
487 | axis_partitions[pidx].size); | ||
488 | pidx++; | ||
489 | } | ||
490 | |||
491 | if (mymtd) { | ||
492 | if (use_default_ptable) { | ||
493 | printk(KERN_INFO " Using default partition table.\n"); | ||
494 | err = add_mtd_partitions(mymtd, axis_default_partitions, | ||
495 | NUM_DEFAULT_PARTITIONS); | ||
496 | } else { | ||
497 | err = add_mtd_partitions(mymtd, axis_partitions, pidx); | ||
498 | } | ||
499 | |||
500 | if (err) { | ||
501 | panic("axisflashmap could not add MTD partitions!\n"); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | if (!romfs_in_flash) { | ||
506 | /* Create an RAM device for the root partition (romfs). */ | ||
507 | |||
508 | #if !defined(CONFIG_MTD_MTDRAM) || (CONFIG_MTDRAM_TOTAL_SIZE != 0) || (CONFIG_MTDRAM_ABS_POS != 0) | ||
509 | /* No use trying to boot this kernel from RAM. Panic! */ | ||
510 | printk(KERN_EMERG "axisflashmap: Cannot create an MTD RAM " | ||
511 | "device due to kernel (mis)configuration!\n"); | ||
512 | panic("This kernel cannot boot from RAM!\n"); | ||
513 | #else | ||
514 | struct mtd_info *mtd_ram; | ||
515 | |||
516 | mtd_ram = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), | ||
517 | GFP_KERNEL); | ||
518 | if (!mtd_ram) { | ||
519 | panic("axisflashmap couldn't allocate memory for " | ||
520 | "mtd_info!\n"); | ||
521 | } | ||
522 | |||
523 | printk(KERN_INFO " Adding RAM partition for romfs image:\n"); | ||
524 | printk(pmsg, pidx, romfs_start, romfs_length); | ||
525 | |||
526 | err = mtdram_init_device(mtd_ram, (void*)romfs_start, | ||
527 | romfs_length, "romfs"); | ||
528 | if (err) { | ||
529 | panic("axisflashmap could not initialize MTD RAM " | ||
530 | "device!\n"); | ||
531 | } | ||
532 | #endif | ||
533 | } | ||
534 | |||
535 | return err; | ||
536 | } | ||
537 | |||
538 | /* This adds the above to the kernels init-call chain. */ | ||
539 | module_init(init_axis_flash); | ||
540 | |||
541 | EXPORT_SYMBOL(axisflash_mtd); | ||
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c new file mode 100644 index 000000000000..fba530fcfaeb --- /dev/null +++ b/arch/cris/arch-v10/drivers/ds1302.c | |||
@@ -0,0 +1,602 @@ | |||
1 | /*!*************************************************************************** | ||
2 | *! | ||
3 | *! FILE NAME : ds1302.c | ||
4 | *! | ||
5 | *! DESCRIPTION: Implements an interface for the DS1302 RTC through Etrax I/O | ||
6 | *! | ||
7 | *! Functions exported: ds1302_readreg, ds1302_writereg, ds1302_init | ||
8 | *! | ||
9 | *! $Log: ds1302.c,v $ | ||
10 | *! Revision 1.14 2004/08/24 06:48:43 starvik | ||
11 | *! Whitespace cleanup | ||
12 | *! | ||
13 | *! Revision 1.13 2004/05/28 09:26:59 starvik | ||
14 | *! Modified I2C initialization to work in 2.6. | ||
15 | *! | ||
16 | *! Revision 1.12 2004/05/14 07:58:03 starvik | ||
17 | *! Merge of changes from 2.4 | ||
18 | *! | ||
19 | *! Revision 1.10 2004/02/04 09:25:12 starvik | ||
20 | *! Merge of Linux 2.6.2 | ||
21 | *! | ||
22 | *! Revision 1.9 2003/07/04 08:27:37 starvik | ||
23 | *! Merge of Linux 2.5.74 | ||
24 | *! | ||
25 | *! Revision 1.8 2003/04/09 05:20:47 starvik | ||
26 | *! Merge of Linux 2.5.67 | ||
27 | *! | ||
28 | *! Revision 1.6 2003/01/09 14:42:51 starvik | ||
29 | *! Merge of Linux 2.5.55 | ||
30 | *! | ||
31 | *! Revision 1.4 2002/12/11 13:13:57 starvik | ||
32 | *! Added arch/ to v10 specific includes | ||
33 | *! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
34 | *! | ||
35 | *! Revision 1.3 2002/11/20 11:56:10 starvik | ||
36 | *! Merge of Linux 2.5.48 | ||
37 | *! | ||
38 | *! Revision 1.2 2002/11/18 13:16:06 starvik | ||
39 | *! Linux 2.5 port of latest 2.4 drivers | ||
40 | *! | ||
41 | *! Revision 1.15 2002/10/11 16:14:33 johana | ||
42 | *! Added CONFIG_ETRAX_DS1302_TRICKLE_CHARGE and initial setting of the | ||
43 | *! trcklecharge register. | ||
44 | *! | ||
45 | *! Revision 1.14 2002/10/10 12:15:38 magnusmn | ||
46 | *! Added support for having the RST signal on bit g0 | ||
47 | *! | ||
48 | *! Revision 1.13 2002/05/29 15:16:08 johana | ||
49 | *! Removed unused variables. | ||
50 | *! | ||
51 | *! Revision 1.12 2002/04/10 15:35:25 johana | ||
52 | *! Moved probe function closer to init function and marked it __init. | ||
53 | *! | ||
54 | *! Revision 1.11 2001/06/14 12:35:52 jonashg | ||
55 | *! The ATA hack is back. It is unfortunately the only way to set g27 to output. | ||
56 | *! | ||
57 | *! Revision 1.9 2001/06/14 10:00:14 jonashg | ||
58 | *! No need for tempudelay to be inline anymore (had to adjust the usec to | ||
59 | *! loops conversion because of this to make it slow enough to be a udelay). | ||
60 | *! | ||
61 | *! Revision 1.8 2001/06/14 08:06:32 jonashg | ||
62 | *! Made tempudelay delay usecs (well, just a tad more). | ||
63 | *! | ||
64 | *! Revision 1.7 2001/06/13 14:18:11 jonashg | ||
65 | *! Only allow processes with SYS_TIME capability to set time and charge. | ||
66 | *! | ||
67 | *! Revision 1.6 2001/06/12 15:22:07 jonashg | ||
68 | *! * Made init function __init. | ||
69 | *! * Parameter to out_byte() is unsigned char. | ||
70 | *! * The magic number 42 has got a name. | ||
71 | *! * Removed comment about /proc (nothing is exported there). | ||
72 | *! | ||
73 | *! Revision 1.5 2001/06/12 14:35:13 jonashg | ||
74 | *! Gave the module a name and added it to printk's. | ||
75 | *! | ||
76 | *! Revision 1.4 2001/05/31 14:53:40 jonashg | ||
77 | *! Made tempudelay() inline so that the watchdog doesn't reset (see | ||
78 | *! function comment). | ||
79 | *! | ||
80 | *! Revision 1.3 2001/03/26 16:03:06 bjornw | ||
81 | *! Needs linux/config.h | ||
82 | *! | ||
83 | *! Revision 1.2 2001/03/20 19:42:00 bjornw | ||
84 | *! Use the ETRAX prefix on the DS1302 options | ||
85 | *! | ||
86 | *! Revision 1.1 2001/03/20 09:13:50 magnusmn | ||
87 | *! Linux 2.4 port | ||
88 | *! | ||
89 | *! Revision 1.10 2000/07/05 15:38:23 bjornw | ||
90 | *! Dont update kernel time when a RTC_SET_TIME is done | ||
91 | *! | ||
92 | *! Revision 1.9 2000/03/02 15:42:59 macce | ||
93 | *! * Hack to make RTC work on all 2100/2400 | ||
94 | *! | ||
95 | *! Revision 1.8 2000/02/23 16:59:18 torbjore | ||
96 | *! added setup of R_GEN_CONFIG when RTC is connected to the generic port. | ||
97 | *! | ||
98 | *! Revision 1.7 2000/01/17 15:51:43 johana | ||
99 | *! Added RTC_SET_CHARGE ioctl to enable trickle charger. | ||
100 | *! | ||
101 | *! Revision 1.6 1999/10/27 13:19:47 bjornw | ||
102 | *! Added update_xtime_from_cmos which reads back the updated RTC into the kernel. | ||
103 | *! /dev/rtc calls it now. | ||
104 | *! | ||
105 | *! Revision 1.5 1999/10/27 12:39:37 bjornw | ||
106 | *! Disabled superuser check. Anyone can now set the time. | ||
107 | *! | ||
108 | *! Revision 1.4 1999/09/02 13:27:46 pkj | ||
109 | *! Added shadow for R_PORT_PB_CONFIG. | ||
110 | *! Renamed port_g_shadow to port_g_data_shadow. | ||
111 | *! | ||
112 | *! Revision 1.3 1999/09/02 08:28:06 pkj | ||
113 | *! Made it possible to select either port PB or the generic port for the RST | ||
114 | *! signal line to the DS1302 RTC. | ||
115 | *! Also make sure the RST bit is configured as output on Port PB (if used). | ||
116 | *! | ||
117 | *! Revision 1.2 1999/09/01 14:47:20 bjornw | ||
118 | *! Added support for /dev/rtc operations with ioctl RD_TIME and SET_TIME to read | ||
119 | *! and set the date. Register as major 121. | ||
120 | *! | ||
121 | *! Revision 1.1 1999/09/01 09:45:29 bjornw | ||
122 | *! Implemented a DS1302 RTC driver. | ||
123 | *! | ||
124 | *! | ||
125 | *! --------------------------------------------------------------------------- | ||
126 | *! | ||
127 | *! (C) Copyright 1999, 2000, 2001 Axis Communications AB, LUND, SWEDEN | ||
128 | *! | ||
129 | *! $Id: ds1302.c,v 1.14 2004/08/24 06:48:43 starvik Exp $ | ||
130 | *! | ||
131 | *!***************************************************************************/ | ||
132 | |||
133 | #include <linux/config.h> | ||
134 | |||
135 | #include <linux/fs.h> | ||
136 | #include <linux/init.h> | ||
137 | #include <linux/mm.h> | ||
138 | #include <linux/module.h> | ||
139 | #include <linux/miscdevice.h> | ||
140 | #include <linux/delay.h> | ||
141 | #include <linux/bcd.h> | ||
142 | |||
143 | #include <asm/uaccess.h> | ||
144 | #include <asm/system.h> | ||
145 | #include <asm/arch/svinto.h> | ||
146 | #include <asm/io.h> | ||
147 | #include <asm/rtc.h> | ||
148 | |||
149 | #define RTC_MAJOR_NR 121 /* local major, change later */ | ||
150 | |||
151 | static const char ds1302_name[] = "ds1302"; | ||
152 | |||
153 | /* The DS1302 might be connected to different bits on different products. | ||
154 | * It has three signals - SDA, SCL and RST. RST and SCL are always outputs, | ||
155 | * but SDA can have a selected direction. | ||
156 | * For now, only PORT_PB is hardcoded. | ||
157 | */ | ||
158 | |||
159 | /* The RST bit may be on either the Generic Port or Port PB. */ | ||
160 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
161 | #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
162 | #define TK_RST_DIR(x) | ||
163 | #else | ||
164 | #define TK_RST_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
165 | #define TK_RST_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_RSTBIT, x) | ||
166 | #endif | ||
167 | |||
168 | |||
169 | #define TK_SDA_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) | ||
170 | #define TK_SCL_OUT(x) REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) | ||
171 | |||
172 | #define TK_SDA_IN() ((*R_PORT_PB_READ >> CONFIG_ETRAX_DS1302_SDABIT) & 1) | ||
173 | /* 1 is out, 0 is in */ | ||
174 | #define TK_SDA_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SDABIT, x) | ||
175 | #define TK_SCL_DIR(x) REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, CONFIG_ETRAX_DS1302_SCLBIT, x) | ||
176 | |||
177 | |||
178 | /* | ||
179 | * The reason for tempudelay and not udelay is that loops_per_usec | ||
180 | * (used in udelay) is not set when functions here are called from time.c | ||
181 | */ | ||
182 | |||
183 | static void tempudelay(int usecs) | ||
184 | { | ||
185 | volatile int loops; | ||
186 | |||
187 | for(loops = usecs * 12; loops > 0; loops--) | ||
188 | /* nothing */; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* Send 8 bits. */ | ||
193 | static void | ||
194 | out_byte(unsigned char x) | ||
195 | { | ||
196 | int i; | ||
197 | TK_SDA_DIR(1); | ||
198 | for (i = 8; i--;) { | ||
199 | /* The chip latches incoming bits on the rising edge of SCL. */ | ||
200 | TK_SCL_OUT(0); | ||
201 | TK_SDA_OUT(x & 1); | ||
202 | tempudelay(1); | ||
203 | TK_SCL_OUT(1); | ||
204 | tempudelay(1); | ||
205 | x >>= 1; | ||
206 | } | ||
207 | TK_SDA_DIR(0); | ||
208 | } | ||
209 | |||
210 | static unsigned char | ||
211 | in_byte(void) | ||
212 | { | ||
213 | unsigned char x = 0; | ||
214 | int i; | ||
215 | |||
216 | /* Read byte. Bits come LSB first, on the falling edge of SCL. | ||
217 | * Assume SDA is in input direction already. | ||
218 | */ | ||
219 | TK_SDA_DIR(0); | ||
220 | |||
221 | for (i = 8; i--;) { | ||
222 | TK_SCL_OUT(0); | ||
223 | tempudelay(1); | ||
224 | x >>= 1; | ||
225 | x |= (TK_SDA_IN() << 7); | ||
226 | TK_SCL_OUT(1); | ||
227 | tempudelay(1); | ||
228 | } | ||
229 | |||
230 | return x; | ||
231 | } | ||
232 | |||
233 | /* Prepares for a transaction by de-activating RST (active-low). */ | ||
234 | |||
235 | static void | ||
236 | start(void) | ||
237 | { | ||
238 | TK_SCL_OUT(0); | ||
239 | tempudelay(1); | ||
240 | TK_RST_OUT(0); | ||
241 | tempudelay(5); | ||
242 | TK_RST_OUT(1); | ||
243 | } | ||
244 | |||
245 | /* Ends a transaction by taking RST active again. */ | ||
246 | |||
247 | static void | ||
248 | stop(void) | ||
249 | { | ||
250 | tempudelay(2); | ||
251 | TK_RST_OUT(0); | ||
252 | } | ||
253 | |||
254 | /* Enable writing. */ | ||
255 | |||
256 | static void | ||
257 | ds1302_wenable(void) | ||
258 | { | ||
259 | start(); | ||
260 | out_byte(0x8e); /* Write control register */ | ||
261 | out_byte(0x00); /* Disable write protect bit 7 = 0 */ | ||
262 | stop(); | ||
263 | } | ||
264 | |||
265 | /* Disable writing. */ | ||
266 | |||
267 | static void | ||
268 | ds1302_wdisable(void) | ||
269 | { | ||
270 | start(); | ||
271 | out_byte(0x8e); /* Write control register */ | ||
272 | out_byte(0x80); /* Disable write protect bit 7 = 0 */ | ||
273 | stop(); | ||
274 | } | ||
275 | |||
276 | |||
277 | |||
278 | /* Read a byte from the selected register in the DS1302. */ | ||
279 | |||
280 | unsigned char | ||
281 | ds1302_readreg(int reg) | ||
282 | { | ||
283 | unsigned char x; | ||
284 | |||
285 | start(); | ||
286 | out_byte(0x81 | (reg << 1)); /* read register */ | ||
287 | x = in_byte(); | ||
288 | stop(); | ||
289 | |||
290 | return x; | ||
291 | } | ||
292 | |||
293 | /* Write a byte to the selected register. */ | ||
294 | |||
295 | void | ||
296 | ds1302_writereg(int reg, unsigned char val) | ||
297 | { | ||
298 | #ifndef CONFIG_ETRAX_RTC_READONLY | ||
299 | int do_writereg = 1; | ||
300 | #else | ||
301 | int do_writereg = 0; | ||
302 | |||
303 | if (reg == RTC_TRICKLECHARGER) | ||
304 | do_writereg = 1; | ||
305 | #endif | ||
306 | |||
307 | if (do_writereg) { | ||
308 | ds1302_wenable(); | ||
309 | start(); | ||
310 | out_byte(0x80 | (reg << 1)); /* write register */ | ||
311 | out_byte(val); | ||
312 | stop(); | ||
313 | ds1302_wdisable(); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | void | ||
318 | get_rtc_time(struct rtc_time *rtc_tm) | ||
319 | { | ||
320 | unsigned long flags; | ||
321 | |||
322 | local_irq_save(flags); | ||
323 | local_irq_disable(); | ||
324 | |||
325 | rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS); | ||
326 | rtc_tm->tm_min = CMOS_READ(RTC_MINUTES); | ||
327 | rtc_tm->tm_hour = CMOS_READ(RTC_HOURS); | ||
328 | rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); | ||
329 | rtc_tm->tm_mon = CMOS_READ(RTC_MONTH); | ||
330 | rtc_tm->tm_year = CMOS_READ(RTC_YEAR); | ||
331 | |||
332 | local_irq_restore(flags); | ||
333 | |||
334 | BCD_TO_BIN(rtc_tm->tm_sec); | ||
335 | BCD_TO_BIN(rtc_tm->tm_min); | ||
336 | BCD_TO_BIN(rtc_tm->tm_hour); | ||
337 | BCD_TO_BIN(rtc_tm->tm_mday); | ||
338 | BCD_TO_BIN(rtc_tm->tm_mon); | ||
339 | BCD_TO_BIN(rtc_tm->tm_year); | ||
340 | |||
341 | /* | ||
342 | * Account for differences between how the RTC uses the values | ||
343 | * and how they are defined in a struct rtc_time; | ||
344 | */ | ||
345 | |||
346 | if (rtc_tm->tm_year <= 69) | ||
347 | rtc_tm->tm_year += 100; | ||
348 | |||
349 | rtc_tm->tm_mon--; | ||
350 | } | ||
351 | |||
352 | static unsigned char days_in_mo[] = | ||
353 | {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
354 | |||
355 | /* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */ | ||
356 | |||
357 | static int | ||
358 | rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
359 | unsigned long arg) | ||
360 | { | ||
361 | unsigned long flags; | ||
362 | |||
363 | switch(cmd) { | ||
364 | case RTC_RD_TIME: /* read the time/date from RTC */ | ||
365 | { | ||
366 | struct rtc_time rtc_tm; | ||
367 | |||
368 | memset(&rtc_tm, 0, sizeof (struct rtc_time)); | ||
369 | get_rtc_time(&rtc_tm); | ||
370 | if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) | ||
371 | return -EFAULT; | ||
372 | return 0; | ||
373 | } | ||
374 | |||
375 | case RTC_SET_TIME: /* set the RTC */ | ||
376 | { | ||
377 | struct rtc_time rtc_tm; | ||
378 | unsigned char mon, day, hrs, min, sec, leap_yr; | ||
379 | unsigned int yrs; | ||
380 | |||
381 | if (!capable(CAP_SYS_TIME)) | ||
382 | return -EPERM; | ||
383 | |||
384 | if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) | ||
385 | return -EFAULT; | ||
386 | |||
387 | yrs = rtc_tm.tm_year + 1900; | ||
388 | mon = rtc_tm.tm_mon + 1; /* tm_mon starts at zero */ | ||
389 | day = rtc_tm.tm_mday; | ||
390 | hrs = rtc_tm.tm_hour; | ||
391 | min = rtc_tm.tm_min; | ||
392 | sec = rtc_tm.tm_sec; | ||
393 | |||
394 | |||
395 | if ((yrs < 1970) || (yrs > 2069)) | ||
396 | return -EINVAL; | ||
397 | |||
398 | leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400)); | ||
399 | |||
400 | if ((mon > 12) || (day == 0)) | ||
401 | return -EINVAL; | ||
402 | |||
403 | if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) | ||
404 | return -EINVAL; | ||
405 | |||
406 | if ((hrs >= 24) || (min >= 60) || (sec >= 60)) | ||
407 | return -EINVAL; | ||
408 | |||
409 | if (yrs >= 2000) | ||
410 | yrs -= 2000; /* RTC (0, 1, ... 69) */ | ||
411 | else | ||
412 | yrs -= 1900; /* RTC (70, 71, ... 99) */ | ||
413 | |||
414 | BIN_TO_BCD(sec); | ||
415 | BIN_TO_BCD(min); | ||
416 | BIN_TO_BCD(hrs); | ||
417 | BIN_TO_BCD(day); | ||
418 | BIN_TO_BCD(mon); | ||
419 | BIN_TO_BCD(yrs); | ||
420 | |||
421 | local_irq_save(flags); | ||
422 | local_irq_disable(); | ||
423 | CMOS_WRITE(yrs, RTC_YEAR); | ||
424 | CMOS_WRITE(mon, RTC_MONTH); | ||
425 | CMOS_WRITE(day, RTC_DAY_OF_MONTH); | ||
426 | CMOS_WRITE(hrs, RTC_HOURS); | ||
427 | CMOS_WRITE(min, RTC_MINUTES); | ||
428 | CMOS_WRITE(sec, RTC_SECONDS); | ||
429 | local_irq_restore(flags); | ||
430 | |||
431 | /* Notice that at this point, the RTC is updated but | ||
432 | * the kernel is still running with the old time. | ||
433 | * You need to set that separately with settimeofday | ||
434 | * or adjtimex. | ||
435 | */ | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | case RTC_SET_CHARGE: /* set the RTC TRICKLE CHARGE register */ | ||
440 | { | ||
441 | int tcs_val; | ||
442 | |||
443 | if (!capable(CAP_SYS_TIME)) | ||
444 | return -EPERM; | ||
445 | |||
446 | if(copy_from_user(&tcs_val, (int*)arg, sizeof(int))) | ||
447 | return -EFAULT; | ||
448 | |||
449 | tcs_val = RTC_TCR_PATTERN | (tcs_val & 0x0F); | ||
450 | ds1302_writereg(RTC_TRICKLECHARGER, tcs_val); | ||
451 | return 0; | ||
452 | } | ||
453 | case RTC_VLOW_RD: | ||
454 | { | ||
455 | /* TODO: | ||
456 | * Implement voltage low detection support | ||
457 | */ | ||
458 | printk(KERN_WARNING "DS1302: RTC Voltage Low detection" | ||
459 | " is not supported\n"); | ||
460 | return 0; | ||
461 | } | ||
462 | case RTC_VLOW_SET: | ||
463 | { | ||
464 | /* TODO: | ||
465 | * Nothing to do since Voltage Low detection is not supported | ||
466 | */ | ||
467 | return 0; | ||
468 | } | ||
469 | default: | ||
470 | return -ENOIOCTLCMD; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | static void | ||
475 | print_rtc_status(void) | ||
476 | { | ||
477 | struct rtc_time tm; | ||
478 | |||
479 | get_rtc_time(&tm); | ||
480 | |||
481 | /* | ||
482 | * There is no way to tell if the luser has the RTC set for local | ||
483 | * time or for Universal Standard Time (GMT). Probably local though. | ||
484 | */ | ||
485 | |||
486 | printk(KERN_INFO "rtc_time\t: %02d:%02d:%02d\n", | ||
487 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
488 | printk(KERN_INFO "rtc_date\t: %04d-%02d-%02d\n", | ||
489 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); | ||
490 | } | ||
491 | |||
492 | /* The various file operations we support. */ | ||
493 | |||
494 | static struct file_operations rtc_fops = { | ||
495 | .owner = THIS_MODULE, | ||
496 | .ioctl = rtc_ioctl, | ||
497 | }; | ||
498 | |||
499 | /* Probe for the chip by writing something to its RAM and try reading it back. */ | ||
500 | |||
501 | #define MAGIC_PATTERN 0x42 | ||
502 | |||
503 | static int __init | ||
504 | ds1302_probe(void) | ||
505 | { | ||
506 | int retval, res; | ||
507 | |||
508 | TK_RST_DIR(1); | ||
509 | TK_SCL_DIR(1); | ||
510 | TK_SDA_DIR(0); | ||
511 | |||
512 | /* Try to talk to timekeeper. */ | ||
513 | |||
514 | ds1302_wenable(); | ||
515 | start(); | ||
516 | out_byte(0xc0); /* write RAM byte 0 */ | ||
517 | out_byte(MAGIC_PATTERN); /* write something magic */ | ||
518 | start(); | ||
519 | out_byte(0xc1); /* read RAM byte 0 */ | ||
520 | |||
521 | if((res = in_byte()) == MAGIC_PATTERN) { | ||
522 | stop(); | ||
523 | ds1302_wdisable(); | ||
524 | printk(KERN_INFO "%s: RTC found.\n", ds1302_name); | ||
525 | printk(KERN_INFO "%s: SDA, SCL, RST on PB%i, PB%i, %s%i\n", | ||
526 | ds1302_name, | ||
527 | CONFIG_ETRAX_DS1302_SDABIT, | ||
528 | CONFIG_ETRAX_DS1302_SCLBIT, | ||
529 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
530 | "GENIO", | ||
531 | #else | ||
532 | "PB", | ||
533 | #endif | ||
534 | CONFIG_ETRAX_DS1302_RSTBIT); | ||
535 | print_rtc_status(); | ||
536 | retval = 1; | ||
537 | } else { | ||
538 | stop(); | ||
539 | retval = 0; | ||
540 | } | ||
541 | |||
542 | return retval; | ||
543 | } | ||
544 | |||
545 | |||
546 | /* Just probe for the RTC and register the device to handle the ioctl needed. */ | ||
547 | |||
548 | int __init | ||
549 | ds1302_init(void) | ||
550 | { | ||
551 | i2c_init(); | ||
552 | |||
553 | if (!ds1302_probe()) { | ||
554 | #ifdef CONFIG_ETRAX_DS1302_RST_ON_GENERIC_PORT | ||
555 | #if CONFIG_ETRAX_DS1302_RSTBIT == 27 | ||
556 | /* | ||
557 | * The only way to set g27 to output is to enable ATA. | ||
558 | * | ||
559 | * Make sure that R_GEN_CONFIG is setup correct. | ||
560 | */ | ||
561 | genconfig_shadow = ((genconfig_shadow & | ||
562 | ~IO_MASK(R_GEN_CONFIG, ata)) | | ||
563 | (IO_STATE(R_GEN_CONFIG, ata, select))); | ||
564 | *R_GEN_CONFIG = genconfig_shadow; | ||
565 | #elif CONFIG_ETRAX_DS1302_RSTBIT == 0 | ||
566 | |||
567 | /* Set the direction of this bit to out. */ | ||
568 | genconfig_shadow = ((genconfig_shadow & | ||
569 | ~IO_MASK(R_GEN_CONFIG, g0dir)) | | ||
570 | (IO_STATE(R_GEN_CONFIG, g0dir, out))); | ||
571 | *R_GEN_CONFIG = genconfig_shadow; | ||
572 | #endif | ||
573 | if (!ds1302_probe()) { | ||
574 | printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); | ||
575 | return -1; | ||
576 | } | ||
577 | #else | ||
578 | printk(KERN_WARNING "%s: RTC not found.\n", ds1302_name); | ||
579 | return -1; | ||
580 | #endif | ||
581 | } | ||
582 | /* Initialise trickle charger */ | ||
583 | ds1302_writereg(RTC_TRICKLECHARGER, | ||
584 | RTC_TCR_PATTERN |(CONFIG_ETRAX_DS1302_TRICKLE_CHARGE & 0x0F)); | ||
585 | /* Start clock by resetting CLOCK_HALT */ | ||
586 | ds1302_writereg(RTC_SECONDS, (ds1302_readreg(RTC_SECONDS) & 0x7F)); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int __init ds1302_register(void) | ||
591 | { | ||
592 | ds1302_init(); | ||
593 | if (register_chrdev(RTC_MAJOR_NR, ds1302_name, &rtc_fops)) { | ||
594 | printk(KERN_INFO "%s: unable to get major %d for rtc\n", | ||
595 | ds1302_name, RTC_MAJOR_NR); | ||
596 | return -1; | ||
597 | } | ||
598 | return 0; | ||
599 | |||
600 | } | ||
601 | |||
602 | module_init(ds1302_register); | ||
diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c new file mode 100644 index 000000000000..316ca15d6802 --- /dev/null +++ b/arch/cris/arch-v10/drivers/eeprom.c | |||
@@ -0,0 +1,945 @@ | |||
1 | /*!***************************************************************************** | ||
2 | *! | ||
3 | *! Implements an interface for i2c compatible eeproms to run under linux. | ||
4 | *! Supports 2k, 8k(?) and 16k. Uses adaptive timing adjustents by | ||
5 | *! Johan.Adolfsson@axis.com | ||
6 | *! | ||
7 | *! Probing results: | ||
8 | *! 8k or not is detected (the assumes 2k or 16k) | ||
9 | *! 2k or 16k detected using test reads and writes. | ||
10 | *! | ||
11 | *!------------------------------------------------------------------------ | ||
12 | *! HISTORY | ||
13 | *! | ||
14 | *! DATE NAME CHANGES | ||
15 | *! ---- ---- ------- | ||
16 | *! Aug 28 1999 Edgar Iglesias Initial Version | ||
17 | *! Aug 31 1999 Edgar Iglesias Allow simultaneous users. | ||
18 | *! Sep 03 1999 Edgar Iglesias Updated probe. | ||
19 | *! Sep 03 1999 Edgar Iglesias Added bail-out stuff if we get interrupted | ||
20 | *! in the spin-lock. | ||
21 | *! | ||
22 | *! $Log: eeprom.c,v $ | ||
23 | *! Revision 1.10 2003/09/11 07:29:48 starvik | ||
24 | *! Merge of Linux 2.6.0-test5 | ||
25 | *! | ||
26 | *! Revision 1.9 2003/07/04 08:27:37 starvik | ||
27 | *! Merge of Linux 2.5.74 | ||
28 | *! | ||
29 | *! Revision 1.8 2003/04/09 05:20:47 starvik | ||
30 | *! Merge of Linux 2.5.67 | ||
31 | *! | ||
32 | *! Revision 1.6 2003/02/10 07:19:28 starvik | ||
33 | *! Removed misplaced ; | ||
34 | *! | ||
35 | *! Revision 1.5 2002/12/11 13:13:57 starvik | ||
36 | *! Added arch/ to v10 specific includes | ||
37 | *! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
38 | *! | ||
39 | *! Revision 1.4 2002/11/20 11:56:10 starvik | ||
40 | *! Merge of Linux 2.5.48 | ||
41 | *! | ||
42 | *! Revision 1.3 2002/11/18 13:16:06 starvik | ||
43 | *! Linux 2.5 port of latest 2.4 drivers | ||
44 | *! | ||
45 | *! Revision 1.8 2001/06/15 13:24:29 jonashg | ||
46 | *! * Added verification of pointers from userspace in read and write. | ||
47 | *! * Made busy counter volatile. | ||
48 | *! * Added define for inital write delay. | ||
49 | *! * Removed warnings by using loff_t instead of unsigned long. | ||
50 | *! | ||
51 | *! Revision 1.7 2001/06/14 15:26:54 jonashg | ||
52 | *! Removed test because condition is always true. | ||
53 | *! | ||
54 | *! Revision 1.6 2001/06/14 15:18:20 jonashg | ||
55 | *! Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k). | ||
56 | *! | ||
57 | *! Revision 1.5 2001/06/14 14:39:51 jonashg | ||
58 | *! Forgot to use name when registering the driver. | ||
59 | *! | ||
60 | *! Revision 1.4 2001/06/14 14:35:47 jonashg | ||
61 | *! * Gave driver a name and used it in printk's. | ||
62 | *! * Cleanup. | ||
63 | *! | ||
64 | *! Revision 1.3 2001/03/19 16:04:46 markusl | ||
65 | *! Fixed init of fops struct | ||
66 | *! | ||
67 | *! Revision 1.2 2001/03/19 10:35:07 markusl | ||
68 | *! 2.4 port of eeprom driver | ||
69 | *! | ||
70 | *! Revision 1.8 2000/05/18 10:42:25 edgar | ||
71 | *! Make sure to end write cycle on _every_ write | ||
72 | *! | ||
73 | *! Revision 1.7 2000/01/17 17:41:01 johana | ||
74 | *! Adjusted probing and return -ENOSPC when writing outside EEPROM | ||
75 | *! | ||
76 | *! Revision 1.6 2000/01/17 15:50:36 johana | ||
77 | *! Added adaptive timing adjustments and fixed autoprobing for 2k and 16k(?) | ||
78 | *! EEPROMs | ||
79 | *! | ||
80 | *! Revision 1.5 1999/09/03 15:07:37 edgar | ||
81 | *! Added bail-out check to the spinlock | ||
82 | *! | ||
83 | *! Revision 1.4 1999/09/03 12:11:17 bjornw | ||
84 | *! Proper atomicity (need to use spinlocks, not if's). users -> busy. | ||
85 | *! | ||
86 | *! | ||
87 | *! (c) 1999 Axis Communications AB, Lund, Sweden | ||
88 | *!*****************************************************************************/ | ||
89 | |||
90 | #include <linux/config.h> | ||
91 | #include <linux/kernel.h> | ||
92 | #include <linux/sched.h> | ||
93 | #include <linux/fs.h> | ||
94 | #include <linux/init.h> | ||
95 | #include <linux/delay.h> | ||
96 | #include <linux/interrupt.h> | ||
97 | #include <asm/uaccess.h> | ||
98 | #include "i2c.h" | ||
99 | |||
100 | #define D(x) | ||
101 | |||
102 | /* If we should use adaptive timing or not: */ | ||
103 | //#define EEPROM_ADAPTIVE_TIMING | ||
104 | |||
105 | #define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */ | ||
106 | #define EEPROM_MINOR_NR 0 | ||
107 | |||
108 | /* Empirical sane initial value of the delay, the value will be adapted to | ||
109 | * what the chip needs when using EEPROM_ADAPTIVE_TIMING. | ||
110 | */ | ||
111 | #define INITIAL_WRITEDELAY_US 4000 | ||
112 | #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ | ||
113 | |||
114 | /* This one defines how many times to try when eeprom fails. */ | ||
115 | #define EEPROM_RETRIES 10 | ||
116 | |||
117 | #define EEPROM_2KB (2 * 1024) | ||
118 | /*#define EEPROM_4KB (4 * 1024)*/ /* Exists but not used in Axis products */ | ||
119 | #define EEPROM_8KB (8 * 1024 - 1 ) /* Last byte has write protection bit */ | ||
120 | #define EEPROM_16KB (16 * 1024) | ||
121 | |||
122 | #define i2c_delay(x) udelay(x) | ||
123 | |||
124 | /* | ||
125 | * This structure describes the attached eeprom chip. | ||
126 | * The values are probed for. | ||
127 | */ | ||
128 | |||
129 | struct eeprom_type | ||
130 | { | ||
131 | unsigned long size; | ||
132 | unsigned long sequential_write_pagesize; | ||
133 | unsigned char select_cmd; | ||
134 | unsigned long usec_delay_writecycles; /* Min time between write cycles | ||
135 | (up to 10ms for some models) */ | ||
136 | unsigned long usec_delay_step; /* For adaptive algorithm */ | ||
137 | int adapt_state; /* 1 = To high , 0 = Even, -1 = To low */ | ||
138 | |||
139 | /* this one is to keep the read/write operations atomic */ | ||
140 | wait_queue_head_t wait_q; | ||
141 | volatile int busy; | ||
142 | int retry_cnt_addr; /* Used to keep track of number of retries for | ||
143 | adaptive timing adjustments */ | ||
144 | int retry_cnt_read; | ||
145 | }; | ||
146 | |||
147 | static int eeprom_open(struct inode * inode, struct file * file); | ||
148 | static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig); | ||
149 | static ssize_t eeprom_read(struct file * file, char * buf, size_t count, | ||
150 | loff_t *off); | ||
151 | static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, | ||
152 | loff_t *off); | ||
153 | static int eeprom_close(struct inode * inode, struct file * file); | ||
154 | |||
155 | static int eeprom_address(unsigned long addr); | ||
156 | static int read_from_eeprom(char * buf, int count); | ||
157 | static int eeprom_write_buf(loff_t addr, const char * buf, int count); | ||
158 | static int eeprom_read_buf(loff_t addr, char * buf, int count); | ||
159 | |||
160 | static void eeprom_disable_write_protect(void); | ||
161 | |||
162 | |||
163 | static const char eeprom_name[] = "eeprom"; | ||
164 | |||
165 | /* chip description */ | ||
166 | static struct eeprom_type eeprom; | ||
167 | |||
168 | /* This is the exported file-operations structure for this device. */ | ||
169 | struct file_operations eeprom_fops = | ||
170 | { | ||
171 | .llseek = eeprom_lseek, | ||
172 | .read = eeprom_read, | ||
173 | .write = eeprom_write, | ||
174 | .open = eeprom_open, | ||
175 | .release = eeprom_close | ||
176 | }; | ||
177 | |||
178 | /* eeprom init call. Probes for different eeprom models. */ | ||
179 | |||
180 | int __init eeprom_init(void) | ||
181 | { | ||
182 | init_waitqueue_head(&eeprom.wait_q); | ||
183 | eeprom.busy = 0; | ||
184 | |||
185 | #ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE | ||
186 | #define EETEXT "Found" | ||
187 | #else | ||
188 | #define EETEXT "Assuming" | ||
189 | #endif | ||
190 | if (register_chrdev(EEPROM_MAJOR_NR, eeprom_name, &eeprom_fops)) | ||
191 | { | ||
192 | printk(KERN_INFO "%s: unable to get major %d for eeprom device\n", | ||
193 | eeprom_name, EEPROM_MAJOR_NR); | ||
194 | return -1; | ||
195 | } | ||
196 | |||
197 | printk("EEPROM char device v0.3, (c) 2000 Axis Communications AB\n"); | ||
198 | |||
199 | /* | ||
200 | * Note: Most of this probing method was taken from the printserver (5470e) | ||
201 | * codebase. It did not contain a way of finding the 16kB chips | ||
202 | * (M24128 or variants). The method used here might not work | ||
203 | * for all models. If you encounter problems the easiest way | ||
204 | * is probably to define your model within #ifdef's, and hard- | ||
205 | * code it. | ||
206 | */ | ||
207 | |||
208 | eeprom.size = 0; | ||
209 | eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US; | ||
210 | eeprom.usec_delay_step = 128; | ||
211 | eeprom.adapt_state = 0; | ||
212 | |||
213 | #ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE | ||
214 | i2c_start(); | ||
215 | i2c_outbyte(0x80); | ||
216 | if(!i2c_getack()) | ||
217 | { | ||
218 | /* It's not 8k.. */ | ||
219 | int success = 0; | ||
220 | unsigned char buf_2k_start[16]; | ||
221 | |||
222 | /* Im not sure this will work... :) */ | ||
223 | /* assume 2kB, if failure go for 16kB */ | ||
224 | /* Test with 16kB settings.. */ | ||
225 | /* If it's a 2kB EEPROM and we address it outside it's range | ||
226 | * it will mirror the address space: | ||
227 | * 1. We read two locations (that are mirrored), | ||
228 | * if the content differs * it's a 16kB EEPROM. | ||
229 | * 2. if it doesn't differ - write different value to one of the locations, | ||
230 | * check the other - if content still is the same it's a 2k EEPROM, | ||
231 | * restore original data. | ||
232 | */ | ||
233 | #define LOC1 8 | ||
234 | #define LOC2 (0x1fb) /*1fb, 3ed, 5df, 7d1 */ | ||
235 | |||
236 | /* 2k settings */ | ||
237 | i2c_stop(); | ||
238 | eeprom.size = EEPROM_2KB; | ||
239 | eeprom.select_cmd = 0xA0; | ||
240 | eeprom.sequential_write_pagesize = 16; | ||
241 | if( eeprom_read_buf( 0, buf_2k_start, 16 ) == 16 ) | ||
242 | { | ||
243 | D(printk("2k start: '%16.16s'\n", buf_2k_start)); | ||
244 | } | ||
245 | else | ||
246 | { | ||
247 | printk(KERN_INFO "%s: Failed to read in 2k mode!\n", eeprom_name); | ||
248 | } | ||
249 | |||
250 | /* 16k settings */ | ||
251 | eeprom.size = EEPROM_16KB; | ||
252 | eeprom.select_cmd = 0xA0; | ||
253 | eeprom.sequential_write_pagesize = 64; | ||
254 | |||
255 | { | ||
256 | unsigned char loc1[4], loc2[4], tmp[4]; | ||
257 | if( eeprom_read_buf(LOC2, loc2, 4) == 4) | ||
258 | { | ||
259 | if( eeprom_read_buf(LOC1, loc1, 4) == 4) | ||
260 | { | ||
261 | D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", | ||
262 | LOC1, loc1, LOC2, loc2)); | ||
263 | #if 0 | ||
264 | if (memcmp(loc1, loc2, 4) != 0 ) | ||
265 | { | ||
266 | /* It's 16k */ | ||
267 | printk(KERN_INFO "%s: 16k detected in step 1\n", eeprom_name); | ||
268 | eeprom.size = EEPROM_16KB; | ||
269 | success = 1; | ||
270 | } | ||
271 | else | ||
272 | #endif | ||
273 | { | ||
274 | /* Do step 2 check */ | ||
275 | /* Invert value */ | ||
276 | loc1[0] = ~loc1[0]; | ||
277 | if (eeprom_write_buf(LOC1, loc1, 1) == 1) | ||
278 | { | ||
279 | /* If 2k EEPROM this write will actually write 10 bytes | ||
280 | * from pos 0 | ||
281 | */ | ||
282 | D(printk("1 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", | ||
283 | LOC1, loc1, LOC2, loc2)); | ||
284 | if( eeprom_read_buf(LOC1, tmp, 4) == 4) | ||
285 | { | ||
286 | D(printk("2 loc1: (%i) '%4.4s' tmp '%4.4s'\n", | ||
287 | LOC1, loc1, tmp)); | ||
288 | if (memcmp(loc1, tmp, 4) != 0 ) | ||
289 | { | ||
290 | printk(KERN_INFO "%s: read and write differs! Not 16kB\n", | ||
291 | eeprom_name); | ||
292 | loc1[0] = ~loc1[0]; | ||
293 | |||
294 | if (eeprom_write_buf(LOC1, loc1, 1) == 1) | ||
295 | { | ||
296 | success = 1; | ||
297 | } | ||
298 | else | ||
299 | { | ||
300 | printk(KERN_INFO "%s: Restore 2k failed during probe," | ||
301 | " EEPROM might be corrupt!\n", eeprom_name); | ||
302 | |||
303 | } | ||
304 | i2c_stop(); | ||
305 | /* Go to 2k mode and write original data */ | ||
306 | eeprom.size = EEPROM_2KB; | ||
307 | eeprom.select_cmd = 0xA0; | ||
308 | eeprom.sequential_write_pagesize = 16; | ||
309 | if( eeprom_write_buf(0, buf_2k_start, 16) == 16) | ||
310 | { | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | printk(KERN_INFO "%s: Failed to write back 2k start!\n", | ||
315 | eeprom_name); | ||
316 | } | ||
317 | |||
318 | eeprom.size = EEPROM_2KB; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | if(!success) | ||
323 | { | ||
324 | if( eeprom_read_buf(LOC2, loc2, 1) == 1) | ||
325 | { | ||
326 | D(printk("0 loc1: (%i) '%4.4s' loc2 (%i) '%4.4s'\n", | ||
327 | LOC1, loc1, LOC2, loc2)); | ||
328 | if (memcmp(loc1, loc2, 4) == 0 ) | ||
329 | { | ||
330 | /* Data the same, must be mirrored -> 2k */ | ||
331 | /* Restore data */ | ||
332 | printk(KERN_INFO "%s: 2k detected in step 2\n", eeprom_name); | ||
333 | loc1[0] = ~loc1[0]; | ||
334 | if (eeprom_write_buf(LOC1, loc1, 1) == 1) | ||
335 | { | ||
336 | success = 1; | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | printk(KERN_INFO "%s: Restore 2k failed during probe," | ||
341 | " EEPROM might be corrupt!\n", eeprom_name); | ||
342 | |||
343 | } | ||
344 | |||
345 | eeprom.size = EEPROM_2KB; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | printk(KERN_INFO "%s: 16k detected in step 2\n", | ||
350 | eeprom_name); | ||
351 | loc1[0] = ~loc1[0]; | ||
352 | /* Data differs, assume 16k */ | ||
353 | /* Restore data */ | ||
354 | if (eeprom_write_buf(LOC1, loc1, 1) == 1) | ||
355 | { | ||
356 | success = 1; | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | printk(KERN_INFO "%s: Restore 16k failed during probe," | ||
361 | " EEPROM might be corrupt!\n", eeprom_name); | ||
362 | } | ||
363 | |||
364 | eeprom.size = EEPROM_16KB; | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | } /* read LOC1 */ | ||
370 | } /* address LOC1 */ | ||
371 | if (!success) | ||
372 | { | ||
373 | printk(KERN_INFO "%s: Probing failed!, using 2KB!\n", eeprom_name); | ||
374 | eeprom.size = EEPROM_2KB; | ||
375 | } | ||
376 | } /* read */ | ||
377 | } | ||
378 | } | ||
379 | else | ||
380 | { | ||
381 | i2c_outbyte(0x00); | ||
382 | if(!i2c_getack()) | ||
383 | { | ||
384 | /* No 8k */ | ||
385 | eeprom.size = EEPROM_2KB; | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | i2c_start(); | ||
390 | i2c_outbyte(0x81); | ||
391 | if (!i2c_getack()) | ||
392 | { | ||
393 | eeprom.size = EEPROM_2KB; | ||
394 | } | ||
395 | else | ||
396 | { | ||
397 | /* It's a 8kB */ | ||
398 | i2c_inbyte(); | ||
399 | eeprom.size = EEPROM_8KB; | ||
400 | } | ||
401 | } | ||
402 | } | ||
403 | i2c_stop(); | ||
404 | #elif defined(CONFIG_ETRAX_I2C_EEPROM_16KB) | ||
405 | eeprom.size = EEPROM_16KB; | ||
406 | #elif defined(CONFIG_ETRAX_I2C_EEPROM_8KB) | ||
407 | eeprom.size = EEPROM_8KB; | ||
408 | #elif defined(CONFIG_ETRAX_I2C_EEPROM_2KB) | ||
409 | eeprom.size = EEPROM_2KB; | ||
410 | #endif | ||
411 | |||
412 | switch(eeprom.size) | ||
413 | { | ||
414 | case (EEPROM_2KB): | ||
415 | printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name); | ||
416 | eeprom.sequential_write_pagesize = 16; | ||
417 | eeprom.select_cmd = 0xA0; | ||
418 | break; | ||
419 | case (EEPROM_8KB): | ||
420 | printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name); | ||
421 | eeprom.sequential_write_pagesize = 16; | ||
422 | eeprom.select_cmd = 0x80; | ||
423 | break; | ||
424 | case (EEPROM_16KB): | ||
425 | printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name); | ||
426 | eeprom.sequential_write_pagesize = 64; | ||
427 | eeprom.select_cmd = 0xA0; | ||
428 | break; | ||
429 | default: | ||
430 | eeprom.size = 0; | ||
431 | printk("%s: Did not find a supported eeprom\n", eeprom_name); | ||
432 | break; | ||
433 | } | ||
434 | |||
435 | |||
436 | |||
437 | eeprom_disable_write_protect(); | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* Opens the device. */ | ||
443 | |||
444 | static int eeprom_open(struct inode * inode, struct file * file) | ||
445 | { | ||
446 | |||
447 | if(MINOR(inode->i_rdev) != EEPROM_MINOR_NR) | ||
448 | return -ENXIO; | ||
449 | if(MAJOR(inode->i_rdev) != EEPROM_MAJOR_NR) | ||
450 | return -ENXIO; | ||
451 | |||
452 | if( eeprom.size > 0 ) | ||
453 | { | ||
454 | /* OK */ | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | /* No EEprom found */ | ||
459 | return -EFAULT; | ||
460 | } | ||
461 | |||
462 | /* Changes the current file position. */ | ||
463 | |||
464 | static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig) | ||
465 | { | ||
466 | /* | ||
467 | * orig 0: position from begning of eeprom | ||
468 | * orig 1: relative from current position | ||
469 | * orig 2: position from last eeprom address | ||
470 | */ | ||
471 | |||
472 | switch (orig) | ||
473 | { | ||
474 | case 0: | ||
475 | file->f_pos = offset; | ||
476 | break; | ||
477 | case 1: | ||
478 | file->f_pos += offset; | ||
479 | break; | ||
480 | case 2: | ||
481 | file->f_pos = eeprom.size - offset; | ||
482 | break; | ||
483 | default: | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | /* truncate position */ | ||
488 | if (file->f_pos < 0) | ||
489 | { | ||
490 | file->f_pos = 0; | ||
491 | return(-EOVERFLOW); | ||
492 | } | ||
493 | |||
494 | if (file->f_pos >= eeprom.size) | ||
495 | { | ||
496 | file->f_pos = eeprom.size - 1; | ||
497 | return(-EOVERFLOW); | ||
498 | } | ||
499 | |||
500 | return ( file->f_pos ); | ||
501 | } | ||
502 | |||
503 | /* Reads data from eeprom. */ | ||
504 | |||
505 | static int eeprom_read_buf(loff_t addr, char * buf, int count) | ||
506 | { | ||
507 | struct file f; | ||
508 | |||
509 | f.f_pos = addr; | ||
510 | return eeprom_read(&f, buf, count, &addr); | ||
511 | } | ||
512 | |||
513 | |||
514 | |||
515 | /* Reads data from eeprom. */ | ||
516 | |||
517 | static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t *off) | ||
518 | { | ||
519 | int read=0; | ||
520 | unsigned long p = file->f_pos; | ||
521 | |||
522 | unsigned char page; | ||
523 | |||
524 | if(p >= eeprom.size) /* Address i 0 - (size-1) */ | ||
525 | { | ||
526 | return -EFAULT; | ||
527 | } | ||
528 | |||
529 | while(eeprom.busy) | ||
530 | { | ||
531 | interruptible_sleep_on(&eeprom.wait_q); | ||
532 | |||
533 | /* bail out if we get interrupted */ | ||
534 | if (signal_pending(current)) | ||
535 | return -EINTR; | ||
536 | |||
537 | } | ||
538 | eeprom.busy++; | ||
539 | |||
540 | page = (unsigned char) (p >> 8); | ||
541 | |||
542 | if(!eeprom_address(p)) | ||
543 | { | ||
544 | printk(KERN_INFO "%s: Read failed to address the eeprom: " | ||
545 | "0x%08X (%i) page: %i\n", eeprom_name, (int)p, (int)p, page); | ||
546 | i2c_stop(); | ||
547 | |||
548 | /* don't forget to wake them up */ | ||
549 | eeprom.busy--; | ||
550 | wake_up_interruptible(&eeprom.wait_q); | ||
551 | return -EFAULT; | ||
552 | } | ||
553 | |||
554 | if( (p + count) > eeprom.size) | ||
555 | { | ||
556 | /* truncate count */ | ||
557 | count = eeprom.size - p; | ||
558 | } | ||
559 | |||
560 | /* stop dummy write op and initiate the read op */ | ||
561 | i2c_start(); | ||
562 | |||
563 | /* special case for small eeproms */ | ||
564 | if(eeprom.size < EEPROM_16KB) | ||
565 | { | ||
566 | i2c_outbyte( eeprom.select_cmd | 1 | (page << 1) ); | ||
567 | } | ||
568 | |||
569 | /* go on with the actual read */ | ||
570 | read = read_from_eeprom( buf, count); | ||
571 | |||
572 | if(read > 0) | ||
573 | { | ||
574 | file->f_pos += read; | ||
575 | } | ||
576 | |||
577 | eeprom.busy--; | ||
578 | wake_up_interruptible(&eeprom.wait_q); | ||
579 | return read; | ||
580 | } | ||
581 | |||
582 | /* Writes data to eeprom. */ | ||
583 | |||
584 | static int eeprom_write_buf(loff_t addr, const char * buf, int count) | ||
585 | { | ||
586 | struct file f; | ||
587 | |||
588 | f.f_pos = addr; | ||
589 | |||
590 | return eeprom_write(&f, buf, count, &addr); | ||
591 | } | ||
592 | |||
593 | |||
594 | /* Writes data to eeprom. */ | ||
595 | |||
596 | static ssize_t eeprom_write(struct file * file, const char * buf, size_t count, | ||
597 | loff_t *off) | ||
598 | { | ||
599 | int i, written, restart=1; | ||
600 | unsigned long p; | ||
601 | |||
602 | if (!access_ok(VERIFY_READ, buf, count)) | ||
603 | { | ||
604 | return -EFAULT; | ||
605 | } | ||
606 | |||
607 | while(eeprom.busy) | ||
608 | { | ||
609 | interruptible_sleep_on(&eeprom.wait_q); | ||
610 | /* bail out if we get interrupted */ | ||
611 | if (signal_pending(current)) | ||
612 | return -EINTR; | ||
613 | } | ||
614 | eeprom.busy++; | ||
615 | for(i = 0; (i < EEPROM_RETRIES) && (restart > 0); i++) | ||
616 | { | ||
617 | restart = 0; | ||
618 | written = 0; | ||
619 | p = file->f_pos; | ||
620 | |||
621 | |||
622 | while( (written < count) && (p < eeprom.size)) | ||
623 | { | ||
624 | /* address the eeprom */ | ||
625 | if(!eeprom_address(p)) | ||
626 | { | ||
627 | printk(KERN_INFO "%s: Write failed to address the eeprom: " | ||
628 | "0x%08X (%i) \n", eeprom_name, (int)p, (int)p); | ||
629 | i2c_stop(); | ||
630 | |||
631 | /* don't forget to wake them up */ | ||
632 | eeprom.busy--; | ||
633 | wake_up_interruptible(&eeprom.wait_q); | ||
634 | return -EFAULT; | ||
635 | } | ||
636 | #ifdef EEPROM_ADAPTIVE_TIMING | ||
637 | /* Adaptive algorithm to adjust timing */ | ||
638 | if (eeprom.retry_cnt_addr > 0) | ||
639 | { | ||
640 | /* To Low now */ | ||
641 | D(printk(">D=%i d=%i\n", | ||
642 | eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); | ||
643 | |||
644 | if (eeprom.usec_delay_step < 4) | ||
645 | { | ||
646 | eeprom.usec_delay_step++; | ||
647 | eeprom.usec_delay_writecycles += eeprom.usec_delay_step; | ||
648 | } | ||
649 | else | ||
650 | { | ||
651 | |||
652 | if (eeprom.adapt_state > 0) | ||
653 | { | ||
654 | /* To Low before */ | ||
655 | eeprom.usec_delay_step *= 2; | ||
656 | if (eeprom.usec_delay_step > 2) | ||
657 | { | ||
658 | eeprom.usec_delay_step--; | ||
659 | } | ||
660 | eeprom.usec_delay_writecycles += eeprom.usec_delay_step; | ||
661 | } | ||
662 | else if (eeprom.adapt_state < 0) | ||
663 | { | ||
664 | /* To High before (toggle dir) */ | ||
665 | eeprom.usec_delay_writecycles += eeprom.usec_delay_step; | ||
666 | if (eeprom.usec_delay_step > 1) | ||
667 | { | ||
668 | eeprom.usec_delay_step /= 2; | ||
669 | eeprom.usec_delay_step--; | ||
670 | } | ||
671 | } | ||
672 | } | ||
673 | |||
674 | eeprom.adapt_state = 1; | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | /* To High (or good) now */ | ||
679 | D(printk("<D=%i d=%i\n", | ||
680 | eeprom.usec_delay_writecycles, eeprom.usec_delay_step)); | ||
681 | |||
682 | if (eeprom.adapt_state < 0) | ||
683 | { | ||
684 | /* To High before */ | ||
685 | if (eeprom.usec_delay_step > 1) | ||
686 | { | ||
687 | eeprom.usec_delay_step *= 2; | ||
688 | eeprom.usec_delay_step--; | ||
689 | |||
690 | if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) | ||
691 | { | ||
692 | eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; | ||
693 | } | ||
694 | } | ||
695 | } | ||
696 | else if (eeprom.adapt_state > 0) | ||
697 | { | ||
698 | /* To Low before (toggle dir) */ | ||
699 | if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) | ||
700 | { | ||
701 | eeprom.usec_delay_writecycles -= eeprom.usec_delay_step; | ||
702 | } | ||
703 | if (eeprom.usec_delay_step > 1) | ||
704 | { | ||
705 | eeprom.usec_delay_step /= 2; | ||
706 | eeprom.usec_delay_step--; | ||
707 | } | ||
708 | |||
709 | eeprom.adapt_state = -1; | ||
710 | } | ||
711 | |||
712 | if (eeprom.adapt_state > -100) | ||
713 | { | ||
714 | eeprom.adapt_state--; | ||
715 | } | ||
716 | else | ||
717 | { | ||
718 | /* Restart adaption */ | ||
719 | D(printk("#Restart\n")); | ||
720 | eeprom.usec_delay_step++; | ||
721 | } | ||
722 | } | ||
723 | #endif /* EEPROM_ADAPTIVE_TIMING */ | ||
724 | /* write until we hit a page boundary or count */ | ||
725 | do | ||
726 | { | ||
727 | i2c_outbyte(buf[written]); | ||
728 | if(!i2c_getack()) | ||
729 | { | ||
730 | restart=1; | ||
731 | printk(KERN_INFO "%s: write error, retrying. %d\n", eeprom_name, i); | ||
732 | i2c_stop(); | ||
733 | break; | ||
734 | } | ||
735 | written++; | ||
736 | p++; | ||
737 | } while( written < count && ( p % eeprom.sequential_write_pagesize )); | ||
738 | |||
739 | /* end write cycle */ | ||
740 | i2c_stop(); | ||
741 | i2c_delay(eeprom.usec_delay_writecycles); | ||
742 | } /* while */ | ||
743 | } /* for */ | ||
744 | |||
745 | eeprom.busy--; | ||
746 | wake_up_interruptible(&eeprom.wait_q); | ||
747 | if (written == 0 && file->f_pos >= eeprom.size){ | ||
748 | return -ENOSPC; | ||
749 | } | ||
750 | file->f_pos += written; | ||
751 | return written; | ||
752 | } | ||
753 | |||
754 | /* Closes the device. */ | ||
755 | |||
756 | static int eeprom_close(struct inode * inode, struct file * file) | ||
757 | { | ||
758 | /* do nothing for now */ | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | /* Sets the current address of the eeprom. */ | ||
763 | |||
764 | static int eeprom_address(unsigned long addr) | ||
765 | { | ||
766 | int i; | ||
767 | unsigned char page, offset; | ||
768 | |||
769 | page = (unsigned char) (addr >> 8); | ||
770 | offset = (unsigned char) addr; | ||
771 | |||
772 | for(i = 0; i < EEPROM_RETRIES; i++) | ||
773 | { | ||
774 | /* start a dummy write for addressing */ | ||
775 | i2c_start(); | ||
776 | |||
777 | if(eeprom.size == EEPROM_16KB) | ||
778 | { | ||
779 | i2c_outbyte( eeprom.select_cmd ); | ||
780 | i2c_getack(); | ||
781 | i2c_outbyte(page); | ||
782 | } | ||
783 | else | ||
784 | { | ||
785 | i2c_outbyte( eeprom.select_cmd | (page << 1) ); | ||
786 | } | ||
787 | if(!i2c_getack()) | ||
788 | { | ||
789 | /* retry */ | ||
790 | i2c_stop(); | ||
791 | /* Must have a delay here.. 500 works, >50, 100->works 5th time*/ | ||
792 | i2c_delay(MAX_WRITEDELAY_US / EEPROM_RETRIES * i); | ||
793 | /* The chip needs up to 10 ms from write stop to next start */ | ||
794 | |||
795 | } | ||
796 | else | ||
797 | { | ||
798 | i2c_outbyte(offset); | ||
799 | |||
800 | if(!i2c_getack()) | ||
801 | { | ||
802 | /* retry */ | ||
803 | i2c_stop(); | ||
804 | } | ||
805 | else | ||
806 | break; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | |||
811 | eeprom.retry_cnt_addr = i; | ||
812 | D(printk("%i\n", eeprom.retry_cnt_addr)); | ||
813 | if(eeprom.retry_cnt_addr == EEPROM_RETRIES) | ||
814 | { | ||
815 | /* failed */ | ||
816 | return 0; | ||
817 | } | ||
818 | return 1; | ||
819 | } | ||
820 | |||
821 | /* Reads from current address. */ | ||
822 | |||
823 | static int read_from_eeprom(char * buf, int count) | ||
824 | { | ||
825 | int i, read=0; | ||
826 | |||
827 | for(i = 0; i < EEPROM_RETRIES; i++) | ||
828 | { | ||
829 | if(eeprom.size == EEPROM_16KB) | ||
830 | { | ||
831 | i2c_outbyte( eeprom.select_cmd | 1 ); | ||
832 | } | ||
833 | |||
834 | if(i2c_getack()) | ||
835 | { | ||
836 | break; | ||
837 | } | ||
838 | } | ||
839 | |||
840 | if(i == EEPROM_RETRIES) | ||
841 | { | ||
842 | printk(KERN_INFO "%s: failed to read from eeprom\n", eeprom_name); | ||
843 | i2c_stop(); | ||
844 | |||
845 | return -EFAULT; | ||
846 | } | ||
847 | |||
848 | while( (read < count)) | ||
849 | { | ||
850 | if (put_user(i2c_inbyte(), &buf[read++])) | ||
851 | { | ||
852 | i2c_stop(); | ||
853 | |||
854 | return -EFAULT; | ||
855 | } | ||
856 | |||
857 | /* | ||
858 | * make sure we don't ack last byte or you will get very strange | ||
859 | * results! | ||
860 | */ | ||
861 | if(read < count) | ||
862 | { | ||
863 | i2c_sendack(); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | /* stop the operation */ | ||
868 | i2c_stop(); | ||
869 | |||
870 | return read; | ||
871 | } | ||
872 | |||
873 | /* Disables write protection if applicable. */ | ||
874 | |||
875 | #define DBP_SAVE(x) | ||
876 | #define ax_printf printk | ||
877 | static void eeprom_disable_write_protect(void) | ||
878 | { | ||
879 | /* Disable write protect */ | ||
880 | if (eeprom.size == EEPROM_8KB) | ||
881 | { | ||
882 | /* Step 1 Set WEL = 1 (write 00000010 to address 1FFFh */ | ||
883 | i2c_start(); | ||
884 | i2c_outbyte(0xbe); | ||
885 | if(!i2c_getack()) | ||
886 | { | ||
887 | DBP_SAVE(ax_printf("Get ack returns false\n")); | ||
888 | } | ||
889 | i2c_outbyte(0xFF); | ||
890 | if(!i2c_getack()) | ||
891 | { | ||
892 | DBP_SAVE(ax_printf("Get ack returns false 2\n")); | ||
893 | } | ||
894 | i2c_outbyte(0x02); | ||
895 | if(!i2c_getack()) | ||
896 | { | ||
897 | DBP_SAVE(ax_printf("Get ack returns false 3\n")); | ||
898 | } | ||
899 | i2c_stop(); | ||
900 | |||
901 | i2c_delay(1000); | ||
902 | |||
903 | /* Step 2 Set RWEL = 1 (write 00000110 to address 1FFFh */ | ||
904 | i2c_start(); | ||
905 | i2c_outbyte(0xbe); | ||
906 | if(!i2c_getack()) | ||
907 | { | ||
908 | DBP_SAVE(ax_printf("Get ack returns false 55\n")); | ||
909 | } | ||
910 | i2c_outbyte(0xFF); | ||
911 | if(!i2c_getack()) | ||
912 | { | ||
913 | DBP_SAVE(ax_printf("Get ack returns false 52\n")); | ||
914 | } | ||
915 | i2c_outbyte(0x06); | ||
916 | if(!i2c_getack()) | ||
917 | { | ||
918 | DBP_SAVE(ax_printf("Get ack returns false 53\n")); | ||
919 | } | ||
920 | i2c_stop(); | ||
921 | |||
922 | /* Step 3 Set BP1, BP0, and/or WPEN bits (write 00000110 to address 1FFFh */ | ||
923 | i2c_start(); | ||
924 | i2c_outbyte(0xbe); | ||
925 | if(!i2c_getack()) | ||
926 | { | ||
927 | DBP_SAVE(ax_printf("Get ack returns false 56\n")); | ||
928 | } | ||
929 | i2c_outbyte(0xFF); | ||
930 | if(!i2c_getack()) | ||
931 | { | ||
932 | DBP_SAVE(ax_printf("Get ack returns false 57\n")); | ||
933 | } | ||
934 | i2c_outbyte(0x06); | ||
935 | if(!i2c_getack()) | ||
936 | { | ||
937 | DBP_SAVE(ax_printf("Get ack returns false 58\n")); | ||
938 | } | ||
939 | i2c_stop(); | ||
940 | |||
941 | /* Write protect disabled */ | ||
942 | } | ||
943 | } | ||
944 | |||
945 | module_init(eeprom_init); | ||
diff --git a/arch/cris/arch-v10/drivers/gpio.c b/arch/cris/arch-v10/drivers/gpio.c new file mode 100644 index 000000000000..c095de82a0da --- /dev/null +++ b/arch/cris/arch-v10/drivers/gpio.c | |||
@@ -0,0 +1,944 @@ | |||
1 | /* $Id: gpio.c,v 1.12 2004/08/24 07:19:59 starvik Exp $ | ||
2 | * | ||
3 | * Etrax general port I/O device | ||
4 | * | ||
5 | * Copyright (c) 1999, 2000, 2001, 2002 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (initial version) | ||
8 | * Ola Knutsson (LED handling) | ||
9 | * Johan Adolfsson (read/set directions, write, port G) | ||
10 | * | ||
11 | * $Log: gpio.c,v $ | ||
12 | * Revision 1.12 2004/08/24 07:19:59 starvik | ||
13 | * Whitespace cleanup | ||
14 | * | ||
15 | * Revision 1.11 2004/05/14 07:58:03 starvik | ||
16 | * Merge of changes from 2.4 | ||
17 | * | ||
18 | * Revision 1.9 2003/09/11 07:29:48 starvik | ||
19 | * Merge of Linux 2.6.0-test5 | ||
20 | * | ||
21 | * Revision 1.8 2003/07/04 08:27:37 starvik | ||
22 | * Merge of Linux 2.5.74 | ||
23 | * | ||
24 | * Revision 1.7 2003/01/10 07:44:07 starvik | ||
25 | * init_ioremap is now called by kernel before drivers are initialized | ||
26 | * | ||
27 | * Revision 1.6 2002/12/11 13:13:57 starvik | ||
28 | * Added arch/ to v10 specific includes | ||
29 | * Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
30 | * | ||
31 | * Revision 1.5 2002/11/20 11:56:11 starvik | ||
32 | * Merge of Linux 2.5.48 | ||
33 | * | ||
34 | * Revision 1.4 2002/11/18 10:10:05 starvik | ||
35 | * Linux 2.5 port of latest gpio.c from Linux 2.4 | ||
36 | * | ||
37 | * Revision 1.20 2002/10/16 21:16:24 johana | ||
38 | * Added support for PA high level interrupt. | ||
39 | * That gives 2ms response time with iodtest for high levels and 2-12 ms | ||
40 | * response time on low levels if the check is not made in | ||
41 | * process.c:cpu_idle() as well. | ||
42 | * | ||
43 | * Revision 1.19 2002/10/14 18:27:33 johana | ||
44 | * Implemented alarm handling so select() now works. | ||
45 | * Latency is around 6-9 ms with a etrax_gpio_wake_up_check() in | ||
46 | * cpu_idle(). | ||
47 | * Otherwise I get 15-18 ms (same as doing the poll in userspace - | ||
48 | * but less overhead). | ||
49 | * TODO? Perhaps we should add the check in IMMEDIATE_BH (or whatever it | ||
50 | * is in 2.4) as well? | ||
51 | * TODO? Perhaps call request_irq()/free_irq() only when needed? | ||
52 | * Increased version to 2.5 | ||
53 | * | ||
54 | * Revision 1.18 2002/10/11 15:02:00 johana | ||
55 | * Mask inverted 8 bit value in setget_input(). | ||
56 | * | ||
57 | * Revision 1.17 2002/06/17 15:53:01 johana | ||
58 | * Added IO_READ_INBITS, IO_READ_OUTBITS, IO_SETGET_INPUT and IO_SETGET_OUTPUT | ||
59 | * that take a pointer as argument and thus can handle 32 bit ports (G) | ||
60 | * correctly. | ||
61 | * These should be used instead of IO_READBITS, IO_SETINPUT and IO_SETOUTPUT. | ||
62 | * (especially if Port G bit 31 is used) | ||
63 | * | ||
64 | * Revision 1.16 2002/06/17 09:59:51 johana | ||
65 | * Returning 32 bit values in the ioctl return value doesn't work if bit | ||
66 | * 31 is set (could happen for port G), so mask it of with 0x7FFFFFFF. | ||
67 | * A new set of ioctl's will be added. | ||
68 | * | ||
69 | * Revision 1.15 2002/05/06 13:19:13 johana | ||
70 | * IO_SETINPUT returns mask with bit set = inputs for PA and PB as well. | ||
71 | * | ||
72 | * Revision 1.14 2002/04/12 12:01:53 johana | ||
73 | * Use global r_port_g_data_shadow. | ||
74 | * Moved gpio_init_port_g() closer to gpio_init() and marked it __init. | ||
75 | * | ||
76 | * Revision 1.13 2002/04/10 12:03:55 johana | ||
77 | * Added support for port G /dev/gpiog (minor 3). | ||
78 | * Changed indentation on switch cases. | ||
79 | * Fixed other spaces to tabs. | ||
80 | * | ||
81 | * Revision 1.12 2001/11/12 19:42:15 pkj | ||
82 | * * Corrected return values from gpio_leds_ioctl(). | ||
83 | * * Fixed compiler warnings. | ||
84 | * | ||
85 | * Revision 1.11 2001/10/30 14:39:12 johana | ||
86 | * Added D() around gpio_write printk. | ||
87 | * | ||
88 | * Revision 1.10 2001/10/25 10:24:42 johana | ||
89 | * Added IO_CFG_WRITE_MODE ioctl and write method that can do fast | ||
90 | * bittoggling in the kernel. (This speeds up programming an FPGA with 450kB | ||
91 | * from ~60 seconds to 4 seconds). | ||
92 | * Added save_flags/cli/restore_flags in ioctl. | ||
93 | * | ||
94 | * Revision 1.9 2001/05/04 14:16:07 matsfg | ||
95 | * Corrected spelling error | ||
96 | * | ||
97 | * Revision 1.8 2001/04/27 13:55:26 matsfg | ||
98 | * Moved initioremap. | ||
99 | * Turns off all LEDS on init. | ||
100 | * Added support for shutdown and powerbutton. | ||
101 | * | ||
102 | * Revision 1.7 2001/04/04 13:30:08 matsfg | ||
103 | * Added bitset and bitclear for leds. Calls init_ioremap to set up memmapping | ||
104 | * | ||
105 | * Revision 1.6 2001/03/26 16:03:06 bjornw | ||
106 | * Needs linux/config.h | ||
107 | * | ||
108 | * Revision 1.5 2001/03/26 14:22:03 bjornw | ||
109 | * Namechange of some config options | ||
110 | * | ||
111 | * Revision 1.4 2001/02/27 13:52:48 bjornw | ||
112 | * malloc.h -> slab.h | ||
113 | * | ||
114 | * Revision 1.3 2001/01/24 15:06:48 bjornw | ||
115 | * gpio_wq correct type | ||
116 | * | ||
117 | * Revision 1.2 2001/01/18 16:07:30 bjornw | ||
118 | * 2.4 port | ||
119 | * | ||
120 | * Revision 1.1 2001/01/18 15:55:16 bjornw | ||
121 | * Verbatim copy of etraxgpio.c from elinux 2.0 added | ||
122 | * | ||
123 | * | ||
124 | */ | ||
125 | |||
126 | #include <linux/config.h> | ||
127 | |||
128 | #include <linux/module.h> | ||
129 | #include <linux/sched.h> | ||
130 | #include <linux/slab.h> | ||
131 | #include <linux/ioport.h> | ||
132 | #include <linux/errno.h> | ||
133 | #include <linux/kernel.h> | ||
134 | #include <linux/fs.h> | ||
135 | #include <linux/string.h> | ||
136 | #include <linux/poll.h> | ||
137 | #include <linux/init.h> | ||
138 | #include <linux/interrupt.h> | ||
139 | |||
140 | #include <asm/etraxgpio.h> | ||
141 | #include <asm/arch/svinto.h> | ||
142 | #include <asm/io.h> | ||
143 | #include <asm/system.h> | ||
144 | #include <asm/irq.h> | ||
145 | |||
146 | #define GPIO_MAJOR 120 /* experimental MAJOR number */ | ||
147 | |||
148 | #define D(x) | ||
149 | |||
150 | #if 0 | ||
151 | static int dp_cnt; | ||
152 | #define DP(x) do { dp_cnt++; if (dp_cnt % 1000 == 0) x; }while(0) | ||
153 | #else | ||
154 | #define DP(x) | ||
155 | #endif | ||
156 | |||
157 | static char gpio_name[] = "etrax gpio"; | ||
158 | |||
159 | #if 0 | ||
160 | static wait_queue_head_t *gpio_wq; | ||
161 | #endif | ||
162 | |||
163 | static int gpio_ioctl(struct inode *inode, struct file *file, | ||
164 | unsigned int cmd, unsigned long arg); | ||
165 | static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | ||
166 | loff_t *off); | ||
167 | static int gpio_open(struct inode *inode, struct file *filp); | ||
168 | static int gpio_release(struct inode *inode, struct file *filp); | ||
169 | static unsigned int gpio_poll(struct file *filp, struct poll_table_struct *wait); | ||
170 | |||
171 | /* private data per open() of this driver */ | ||
172 | |||
173 | struct gpio_private { | ||
174 | struct gpio_private *next; | ||
175 | /* These fields are for PA and PB only */ | ||
176 | volatile unsigned char *port, *shadow; | ||
177 | volatile unsigned char *dir, *dir_shadow; | ||
178 | unsigned char changeable_dir; | ||
179 | unsigned char changeable_bits; | ||
180 | unsigned char clk_mask; | ||
181 | unsigned char data_mask; | ||
182 | unsigned char write_msb; | ||
183 | unsigned char pad1, pad2, pad3; | ||
184 | /* These fields are generic */ | ||
185 | unsigned long highalarm, lowalarm; | ||
186 | wait_queue_head_t alarm_wq; | ||
187 | int minor; | ||
188 | }; | ||
189 | |||
190 | /* linked list of alarms to check for */ | ||
191 | |||
192 | static struct gpio_private *alarmlist = 0; | ||
193 | |||
194 | static int gpio_some_alarms = 0; /* Set if someone uses alarm */ | ||
195 | static unsigned long gpio_pa_irq_enabled_mask = 0; | ||
196 | |||
197 | /* Port A and B use 8 bit access, but Port G is 32 bit */ | ||
198 | #define NUM_PORTS (GPIO_MINOR_B+1) | ||
199 | |||
200 | static volatile unsigned char *ports[NUM_PORTS] = { | ||
201 | R_PORT_PA_DATA, | ||
202 | R_PORT_PB_DATA, | ||
203 | }; | ||
204 | static volatile unsigned char *shads[NUM_PORTS] = { | ||
205 | &port_pa_data_shadow, | ||
206 | &port_pb_data_shadow | ||
207 | }; | ||
208 | |||
209 | /* What direction bits that are user changeable 1=changeable*/ | ||
210 | #ifndef CONFIG_ETRAX_PA_CHANGEABLE_DIR | ||
211 | #define CONFIG_ETRAX_PA_CHANGEABLE_DIR 0x00 | ||
212 | #endif | ||
213 | #ifndef CONFIG_ETRAX_PB_CHANGEABLE_DIR | ||
214 | #define CONFIG_ETRAX_PB_CHANGEABLE_DIR 0x00 | ||
215 | #endif | ||
216 | |||
217 | #ifndef CONFIG_ETRAX_PA_CHANGEABLE_BITS | ||
218 | #define CONFIG_ETRAX_PA_CHANGEABLE_BITS 0xFF | ||
219 | #endif | ||
220 | #ifndef CONFIG_ETRAX_PB_CHANGEABLE_BITS | ||
221 | #define CONFIG_ETRAX_PB_CHANGEABLE_BITS 0xFF | ||
222 | #endif | ||
223 | |||
224 | |||
225 | static unsigned char changeable_dir[NUM_PORTS] = { | ||
226 | CONFIG_ETRAX_PA_CHANGEABLE_DIR, | ||
227 | CONFIG_ETRAX_PB_CHANGEABLE_DIR | ||
228 | }; | ||
229 | static unsigned char changeable_bits[NUM_PORTS] = { | ||
230 | CONFIG_ETRAX_PA_CHANGEABLE_BITS, | ||
231 | CONFIG_ETRAX_PB_CHANGEABLE_BITS | ||
232 | }; | ||
233 | |||
234 | static volatile unsigned char *dir[NUM_PORTS] = { | ||
235 | R_PORT_PA_DIR, | ||
236 | R_PORT_PB_DIR | ||
237 | }; | ||
238 | |||
239 | static volatile unsigned char *dir_shadow[NUM_PORTS] = { | ||
240 | &port_pa_dir_shadow, | ||
241 | &port_pb_dir_shadow | ||
242 | }; | ||
243 | |||
244 | /* Port G is 32 bit, handle it special, some bits are both inputs | ||
245 | and outputs at the same time, only some of the bits can change direction | ||
246 | and some of them in groups of 8 bit. */ | ||
247 | static unsigned long changeable_dir_g; | ||
248 | static unsigned long dir_g_in_bits; | ||
249 | static unsigned long dir_g_out_bits; | ||
250 | static unsigned long dir_g_shadow; /* 1=output */ | ||
251 | |||
252 | #define USE_PORTS(priv) ((priv)->minor <= GPIO_MINOR_B) | ||
253 | |||
254 | |||
255 | |||
256 | static unsigned int | ||
257 | gpio_poll(struct file *file, | ||
258 | poll_table *wait) | ||
259 | { | ||
260 | unsigned int mask = 0; | ||
261 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | ||
262 | unsigned long data; | ||
263 | poll_wait(file, &priv->alarm_wq, wait); | ||
264 | if (priv->minor == GPIO_MINOR_A) { | ||
265 | unsigned long flags; | ||
266 | unsigned long tmp; | ||
267 | data = *R_PORT_PA_DATA; | ||
268 | /* PA has support for high level interrupt - | ||
269 | * lets activate for those low and with highalarm set | ||
270 | */ | ||
271 | tmp = ~data & priv->highalarm & 0xFF; | ||
272 | tmp = (tmp << R_IRQ_MASK1_SET__pa0__BITNR); | ||
273 | save_flags(flags); cli(); | ||
274 | gpio_pa_irq_enabled_mask |= tmp; | ||
275 | *R_IRQ_MASK1_SET = tmp; | ||
276 | restore_flags(flags); | ||
277 | |||
278 | } else if (priv->minor == GPIO_MINOR_B) | ||
279 | data = *R_PORT_PB_DATA; | ||
280 | else if (priv->minor == GPIO_MINOR_G) | ||
281 | data = *R_PORT_G_DATA; | ||
282 | else | ||
283 | return 0; | ||
284 | |||
285 | if ((data & priv->highalarm) || | ||
286 | (~data & priv->lowalarm)) { | ||
287 | mask = POLLIN|POLLRDNORM; | ||
288 | } | ||
289 | |||
290 | DP(printk("gpio_poll ready: mask 0x%08X\n", mask)); | ||
291 | return mask; | ||
292 | } | ||
293 | |||
294 | int etrax_gpio_wake_up_check(void) | ||
295 | { | ||
296 | struct gpio_private *priv = alarmlist; | ||
297 | unsigned long data = 0; | ||
298 | int ret = 0; | ||
299 | while (priv) { | ||
300 | if (USE_PORTS(priv)) { | ||
301 | data = *priv->port; | ||
302 | } else if (priv->minor == GPIO_MINOR_G) { | ||
303 | data = *R_PORT_G_DATA; | ||
304 | } | ||
305 | if ((data & priv->highalarm) || | ||
306 | (~data & priv->lowalarm)) { | ||
307 | DP(printk("etrax_gpio_wake_up_check %i\n",priv->minor)); | ||
308 | wake_up_interruptible(&priv->alarm_wq); | ||
309 | ret = 1; | ||
310 | } | ||
311 | priv = priv->next; | ||
312 | } | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | static irqreturn_t | ||
317 | gpio_poll_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
318 | { | ||
319 | if (gpio_some_alarms) { | ||
320 | etrax_gpio_wake_up_check(); | ||
321 | return IRQ_HANDLED; | ||
322 | } | ||
323 | return IRQ_NONE; | ||
324 | } | ||
325 | |||
326 | static irqreturn_t | ||
327 | gpio_pa_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
328 | { | ||
329 | unsigned long tmp; | ||
330 | /* Find what PA interrupts are active */ | ||
331 | tmp = (*R_IRQ_READ1); | ||
332 | |||
333 | /* Find those that we have enabled */ | ||
334 | tmp &= gpio_pa_irq_enabled_mask; | ||
335 | |||
336 | /* Clear them.. */ | ||
337 | *R_IRQ_MASK1_CLR = tmp; | ||
338 | gpio_pa_irq_enabled_mask &= ~tmp; | ||
339 | |||
340 | if (gpio_some_alarms) { | ||
341 | return IRQ_RETVAL(etrax_gpio_wake_up_check()); | ||
342 | } | ||
343 | return IRQ_NONE; | ||
344 | } | ||
345 | |||
346 | |||
347 | static ssize_t gpio_write(struct file * file, const char * buf, size_t count, | ||
348 | loff_t *off) | ||
349 | { | ||
350 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | ||
351 | unsigned char data, clk_mask, data_mask, write_msb; | ||
352 | unsigned long flags; | ||
353 | ssize_t retval = count; | ||
354 | if (priv->minor !=GPIO_MINOR_A && priv->minor != GPIO_MINOR_B) { | ||
355 | return -EFAULT; | ||
356 | } | ||
357 | |||
358 | if (!access_ok(VERIFY_READ, buf, count)) { | ||
359 | return -EFAULT; | ||
360 | } | ||
361 | clk_mask = priv->clk_mask; | ||
362 | data_mask = priv->data_mask; | ||
363 | /* It must have been configured using the IO_CFG_WRITE_MODE */ | ||
364 | /* Perhaps a better error code? */ | ||
365 | if (clk_mask == 0 || data_mask == 0) { | ||
366 | return -EPERM; | ||
367 | } | ||
368 | write_msb = priv->write_msb; | ||
369 | D(printk("gpio_write: %lu to data 0x%02X clk 0x%02X msb: %i\n",count, data_mask, clk_mask, write_msb)); | ||
370 | while (count--) { | ||
371 | int i; | ||
372 | data = *buf++; | ||
373 | if (priv->write_msb) { | ||
374 | for (i = 7; i >= 0;i--) { | ||
375 | local_irq_save(flags); local_irq_disable(); | ||
376 | *priv->port = *priv->shadow &= ~clk_mask; | ||
377 | if (data & 1<<i) | ||
378 | *priv->port = *priv->shadow |= data_mask; | ||
379 | else | ||
380 | *priv->port = *priv->shadow &= ~data_mask; | ||
381 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
382 | *priv->port = *priv->shadow |= clk_mask; | ||
383 | local_irq_restore(flags); | ||
384 | } | ||
385 | } else { | ||
386 | for (i = 0; i <= 7;i++) { | ||
387 | local_irq_save(flags); local_irq_disable(); | ||
388 | *priv->port = *priv->shadow &= ~clk_mask; | ||
389 | if (data & 1<<i) | ||
390 | *priv->port = *priv->shadow |= data_mask; | ||
391 | else | ||
392 | *priv->port = *priv->shadow &= ~data_mask; | ||
393 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | ||
394 | *priv->port = *priv->shadow |= clk_mask; | ||
395 | local_irq_restore(flags); | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | return retval; | ||
400 | } | ||
401 | |||
402 | |||
403 | |||
404 | static int | ||
405 | gpio_open(struct inode *inode, struct file *filp) | ||
406 | { | ||
407 | struct gpio_private *priv; | ||
408 | int p = MINOR(inode->i_rdev); | ||
409 | |||
410 | if (p > GPIO_MINOR_LAST) | ||
411 | return -EINVAL; | ||
412 | |||
413 | priv = (struct gpio_private *)kmalloc(sizeof(struct gpio_private), | ||
414 | GFP_KERNEL); | ||
415 | |||
416 | if (!priv) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | priv->minor = p; | ||
420 | |||
421 | /* initialize the io/alarm struct and link it into our alarmlist */ | ||
422 | |||
423 | priv->next = alarmlist; | ||
424 | alarmlist = priv; | ||
425 | if (USE_PORTS(priv)) { /* A and B */ | ||
426 | priv->port = ports[p]; | ||
427 | priv->shadow = shads[p]; | ||
428 | priv->dir = dir[p]; | ||
429 | priv->dir_shadow = dir_shadow[p]; | ||
430 | priv->changeable_dir = changeable_dir[p]; | ||
431 | priv->changeable_bits = changeable_bits[p]; | ||
432 | } else { | ||
433 | priv->port = NULL; | ||
434 | priv->shadow = NULL; | ||
435 | priv->dir = NULL; | ||
436 | priv->dir_shadow = NULL; | ||
437 | priv->changeable_dir = 0; | ||
438 | priv->changeable_bits = 0; | ||
439 | } | ||
440 | |||
441 | priv->highalarm = 0; | ||
442 | priv->lowalarm = 0; | ||
443 | priv->clk_mask = 0; | ||
444 | priv->data_mask = 0; | ||
445 | init_waitqueue_head(&priv->alarm_wq); | ||
446 | |||
447 | filp->private_data = (void *)priv; | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int | ||
453 | gpio_release(struct inode *inode, struct file *filp) | ||
454 | { | ||
455 | struct gpio_private *p = alarmlist; | ||
456 | struct gpio_private *todel = (struct gpio_private *)filp->private_data; | ||
457 | |||
458 | /* unlink from alarmlist and free the private structure */ | ||
459 | |||
460 | if (p == todel) { | ||
461 | alarmlist = todel->next; | ||
462 | } else { | ||
463 | while (p->next != todel) | ||
464 | p = p->next; | ||
465 | p->next = todel->next; | ||
466 | } | ||
467 | |||
468 | kfree(todel); | ||
469 | /* Check if there are still any alarms set */ | ||
470 | p = alarmlist; | ||
471 | while (p) { | ||
472 | if (p->highalarm | p->lowalarm) { | ||
473 | gpio_some_alarms = 1; | ||
474 | return 0; | ||
475 | } | ||
476 | p = p->next; | ||
477 | } | ||
478 | gpio_some_alarms = 0; | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* Main device API. ioctl's to read/set/clear bits, as well as to | ||
484 | * set alarms to wait for using a subsequent select(). | ||
485 | */ | ||
486 | |||
487 | unsigned long inline setget_input(struct gpio_private *priv, unsigned long arg) | ||
488 | { | ||
489 | /* Set direction 0=unchanged 1=input, | ||
490 | * return mask with 1=input | ||
491 | */ | ||
492 | unsigned long flags; | ||
493 | if (USE_PORTS(priv)) { | ||
494 | local_irq_save(flags); local_irq_disable(); | ||
495 | *priv->dir = *priv->dir_shadow &= | ||
496 | ~((unsigned char)arg & priv->changeable_dir); | ||
497 | local_irq_restore(flags); | ||
498 | return ~(*priv->dir_shadow) & 0xFF; /* Only 8 bits */ | ||
499 | } else if (priv->minor == GPIO_MINOR_G) { | ||
500 | /* We must fiddle with R_GEN_CONFIG to change dir */ | ||
501 | save_flags(flags); cli(); | ||
502 | if (((arg & dir_g_in_bits) != arg) && | ||
503 | (arg & changeable_dir_g)) { | ||
504 | arg &= changeable_dir_g; | ||
505 | /* Clear bits in genconfig to set to input */ | ||
506 | if (arg & (1<<0)) { | ||
507 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g0dir); | ||
508 | dir_g_in_bits |= (1<<0); | ||
509 | dir_g_out_bits &= ~(1<<0); | ||
510 | } | ||
511 | if ((arg & 0x0000FF00) == 0x0000FF00) { | ||
512 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g8_15dir); | ||
513 | dir_g_in_bits |= 0x0000FF00; | ||
514 | dir_g_out_bits &= ~0x0000FF00; | ||
515 | } | ||
516 | if ((arg & 0x00FF0000) == 0x00FF0000) { | ||
517 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g16_23dir); | ||
518 | dir_g_in_bits |= 0x00FF0000; | ||
519 | dir_g_out_bits &= ~0x00FF0000; | ||
520 | } | ||
521 | if (arg & (1<<24)) { | ||
522 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG,g24dir); | ||
523 | dir_g_in_bits |= (1<<24); | ||
524 | dir_g_out_bits &= ~(1<<24); | ||
525 | } | ||
526 | D(printk(KERN_INFO "gpio: SETINPUT on port G set " | ||
527 | "genconfig to 0x%08lX " | ||
528 | "in_bits: 0x%08lX " | ||
529 | "out_bits: 0x%08lX\n", | ||
530 | (unsigned long)genconfig_shadow, | ||
531 | dir_g_in_bits, dir_g_out_bits)); | ||
532 | *R_GEN_CONFIG = genconfig_shadow; | ||
533 | /* Must be a >120 ns delay before writing this again */ | ||
534 | |||
535 | } | ||
536 | restore_flags(flags); | ||
537 | return dir_g_in_bits; | ||
538 | } | ||
539 | return 0; | ||
540 | } /* setget_input */ | ||
541 | |||
542 | unsigned long inline setget_output(struct gpio_private *priv, unsigned long arg) | ||
543 | { | ||
544 | unsigned long flags; | ||
545 | if (USE_PORTS(priv)) { | ||
546 | local_irq_save(flags); local_irq_disable(); | ||
547 | *priv->dir = *priv->dir_shadow |= | ||
548 | ((unsigned char)arg & priv->changeable_dir); | ||
549 | local_irq_restore(flags); | ||
550 | return *priv->dir_shadow; | ||
551 | } else if (priv->minor == GPIO_MINOR_G) { | ||
552 | /* We must fiddle with R_GEN_CONFIG to change dir */ | ||
553 | save_flags(flags); cli(); | ||
554 | if (((arg & dir_g_out_bits) != arg) && | ||
555 | (arg & changeable_dir_g)) { | ||
556 | /* Set bits in genconfig to set to output */ | ||
557 | if (arg & (1<<0)) { | ||
558 | genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g0dir); | ||
559 | dir_g_out_bits |= (1<<0); | ||
560 | dir_g_in_bits &= ~(1<<0); | ||
561 | } | ||
562 | if ((arg & 0x0000FF00) == 0x0000FF00) { | ||
563 | genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g8_15dir); | ||
564 | dir_g_out_bits |= 0x0000FF00; | ||
565 | dir_g_in_bits &= ~0x0000FF00; | ||
566 | } | ||
567 | if ((arg & 0x00FF0000) == 0x00FF0000) { | ||
568 | genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g16_23dir); | ||
569 | dir_g_out_bits |= 0x00FF0000; | ||
570 | dir_g_in_bits &= ~0x00FF0000; | ||
571 | } | ||
572 | if (arg & (1<<24)) { | ||
573 | genconfig_shadow |= IO_MASK(R_GEN_CONFIG,g24dir); | ||
574 | dir_g_out_bits |= (1<<24); | ||
575 | dir_g_in_bits &= ~(1<<24); | ||
576 | } | ||
577 | D(printk(KERN_INFO "gpio: SETOUTPUT on port G set " | ||
578 | "genconfig to 0x%08lX " | ||
579 | "in_bits: 0x%08lX " | ||
580 | "out_bits: 0x%08lX\n", | ||
581 | (unsigned long)genconfig_shadow, | ||
582 | dir_g_in_bits, dir_g_out_bits)); | ||
583 | *R_GEN_CONFIG = genconfig_shadow; | ||
584 | /* Must be a >120 ns delay before writing this again */ | ||
585 | } | ||
586 | restore_flags(flags); | ||
587 | return dir_g_out_bits & 0x7FFFFFFF; | ||
588 | } | ||
589 | return 0; | ||
590 | } /* setget_output */ | ||
591 | |||
592 | static int | ||
593 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg); | ||
594 | |||
595 | static int | ||
596 | gpio_ioctl(struct inode *inode, struct file *file, | ||
597 | unsigned int cmd, unsigned long arg) | ||
598 | { | ||
599 | unsigned long flags; | ||
600 | unsigned long val; | ||
601 | struct gpio_private *priv = (struct gpio_private *)file->private_data; | ||
602 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) { | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | switch (_IOC_NR(cmd)) { | ||
607 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | ||
608 | // read the port | ||
609 | if (USE_PORTS(priv)) { | ||
610 | return *priv->port; | ||
611 | } else if (priv->minor == GPIO_MINOR_G) { | ||
612 | return (*R_PORT_G_DATA) & 0x7FFFFFFF; | ||
613 | } | ||
614 | break; | ||
615 | case IO_SETBITS: | ||
616 | local_irq_save(flags); local_irq_disable(); | ||
617 | // set changeable bits with a 1 in arg | ||
618 | if (USE_PORTS(priv)) { | ||
619 | *priv->port = *priv->shadow |= | ||
620 | ((unsigned char)arg & priv->changeable_bits); | ||
621 | } else if (priv->minor == GPIO_MINOR_G) { | ||
622 | *R_PORT_G_DATA = port_g_data_shadow |= (arg & dir_g_out_bits); | ||
623 | } | ||
624 | local_irq_restore(flags); | ||
625 | break; | ||
626 | case IO_CLRBITS: | ||
627 | local_irq_save(flags); local_irq_disable(); | ||
628 | // clear changeable bits with a 1 in arg | ||
629 | if (USE_PORTS(priv)) { | ||
630 | *priv->port = *priv->shadow &= | ||
631 | ~((unsigned char)arg & priv->changeable_bits); | ||
632 | } else if (priv->minor == GPIO_MINOR_G) { | ||
633 | *R_PORT_G_DATA = port_g_data_shadow &= ~((unsigned long)arg & dir_g_out_bits); | ||
634 | } | ||
635 | local_irq_restore(flags); | ||
636 | break; | ||
637 | case IO_HIGHALARM: | ||
638 | // set alarm when bits with 1 in arg go high | ||
639 | priv->highalarm |= arg; | ||
640 | gpio_some_alarms = 1; | ||
641 | break; | ||
642 | case IO_LOWALARM: | ||
643 | // set alarm when bits with 1 in arg go low | ||
644 | priv->lowalarm |= arg; | ||
645 | gpio_some_alarms = 1; | ||
646 | break; | ||
647 | case IO_CLRALARM: | ||
648 | // clear alarm for bits with 1 in arg | ||
649 | priv->highalarm &= ~arg; | ||
650 | priv->lowalarm &= ~arg; | ||
651 | { | ||
652 | /* Must update gpio_some_alarms */ | ||
653 | struct gpio_private *p = alarmlist; | ||
654 | int some_alarms; | ||
655 | some_alarms = 0; | ||
656 | while (p) { | ||
657 | if (p->highalarm | p->lowalarm) { | ||
658 | some_alarms = 1; | ||
659 | break; | ||
660 | } | ||
661 | p = p->next; | ||
662 | } | ||
663 | gpio_some_alarms = some_alarms; | ||
664 | } | ||
665 | break; | ||
666 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | ||
667 | /* Read direction 0=input 1=output */ | ||
668 | if (USE_PORTS(priv)) { | ||
669 | return *priv->dir_shadow; | ||
670 | } else if (priv->minor == GPIO_MINOR_G) { | ||
671 | /* Note: Some bits are both in and out, | ||
672 | * Those that are dual is set here as well. | ||
673 | */ | ||
674 | return (dir_g_shadow | dir_g_out_bits) & 0x7FFFFFFF; | ||
675 | } | ||
676 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ | ||
677 | /* Set direction 0=unchanged 1=input, | ||
678 | * return mask with 1=input | ||
679 | */ | ||
680 | return setget_input(priv, arg) & 0x7FFFFFFF; | ||
681 | break; | ||
682 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ | ||
683 | /* Set direction 0=unchanged 1=output, | ||
684 | * return mask with 1=output | ||
685 | */ | ||
686 | return setget_output(priv, arg) & 0x7FFFFFFF; | ||
687 | |||
688 | case IO_SHUTDOWN: | ||
689 | SOFT_SHUTDOWN(); | ||
690 | break; | ||
691 | case IO_GET_PWR_BT: | ||
692 | #if defined (CONFIG_ETRAX_SOFT_SHUTDOWN) | ||
693 | return (*R_PORT_G_DATA & ( 1 << CONFIG_ETRAX_POWERBUTTON_BIT)); | ||
694 | #else | ||
695 | return 0; | ||
696 | #endif | ||
697 | break; | ||
698 | case IO_CFG_WRITE_MODE: | ||
699 | priv->clk_mask = arg & 0xFF; | ||
700 | priv->data_mask = (arg >> 8) & 0xFF; | ||
701 | priv->write_msb = (arg >> 16) & 0x01; | ||
702 | /* Check if we're allowed to change the bits and | ||
703 | * the direction is correct | ||
704 | */ | ||
705 | if (!((priv->clk_mask & priv->changeable_bits) && | ||
706 | (priv->data_mask & priv->changeable_bits) && | ||
707 | (priv->clk_mask & *priv->dir_shadow) && | ||
708 | (priv->data_mask & *priv->dir_shadow))) | ||
709 | { | ||
710 | priv->clk_mask = 0; | ||
711 | priv->data_mask = 0; | ||
712 | return -EPERM; | ||
713 | } | ||
714 | break; | ||
715 | case IO_READ_INBITS: | ||
716 | /* *arg is result of reading the input pins */ | ||
717 | if (USE_PORTS(priv)) { | ||
718 | val = *priv->port; | ||
719 | } else if (priv->minor == GPIO_MINOR_G) { | ||
720 | val = *R_PORT_G_DATA; | ||
721 | } | ||
722 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | ||
723 | return -EFAULT; | ||
724 | return 0; | ||
725 | break; | ||
726 | case IO_READ_OUTBITS: | ||
727 | /* *arg is result of reading the output shadow */ | ||
728 | if (USE_PORTS(priv)) { | ||
729 | val = *priv->shadow; | ||
730 | } else if (priv->minor == GPIO_MINOR_G) { | ||
731 | val = port_g_data_shadow; | ||
732 | } | ||
733 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | ||
734 | return -EFAULT; | ||
735 | break; | ||
736 | case IO_SETGET_INPUT: | ||
737 | /* bits set in *arg is set to input, | ||
738 | * *arg updated with current input pins. | ||
739 | */ | ||
740 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | ||
741 | return -EFAULT; | ||
742 | val = setget_input(priv, val); | ||
743 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | ||
744 | return -EFAULT; | ||
745 | break; | ||
746 | case IO_SETGET_OUTPUT: | ||
747 | /* bits set in *arg is set to output, | ||
748 | * *arg updated with current output pins. | ||
749 | */ | ||
750 | if (copy_from_user(&val, (unsigned long*)arg, sizeof(val))) | ||
751 | return -EFAULT; | ||
752 | val = setget_output(priv, val); | ||
753 | if (copy_to_user((unsigned long*)arg, &val, sizeof(val))) | ||
754 | return -EFAULT; | ||
755 | break; | ||
756 | default: | ||
757 | if (priv->minor == GPIO_MINOR_LEDS) | ||
758 | return gpio_leds_ioctl(cmd, arg); | ||
759 | else | ||
760 | return -EINVAL; | ||
761 | } /* switch */ | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static int | ||
767 | gpio_leds_ioctl(unsigned int cmd, unsigned long arg) | ||
768 | { | ||
769 | unsigned char green; | ||
770 | unsigned char red; | ||
771 | |||
772 | switch (_IOC_NR(cmd)) { | ||
773 | case IO_LEDACTIVE_SET: | ||
774 | green = ((unsigned char) arg) & 1; | ||
775 | red = (((unsigned char) arg) >> 1) & 1; | ||
776 | LED_ACTIVE_SET_G(green); | ||
777 | LED_ACTIVE_SET_R(red); | ||
778 | break; | ||
779 | |||
780 | case IO_LED_SETBIT: | ||
781 | LED_BIT_SET(arg); | ||
782 | break; | ||
783 | |||
784 | case IO_LED_CLRBIT: | ||
785 | LED_BIT_CLR(arg); | ||
786 | break; | ||
787 | |||
788 | default: | ||
789 | return -EINVAL; | ||
790 | } /* switch */ | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | struct file_operations gpio_fops = { | ||
796 | .owner = THIS_MODULE, | ||
797 | .poll = gpio_poll, | ||
798 | .ioctl = gpio_ioctl, | ||
799 | .write = gpio_write, | ||
800 | .open = gpio_open, | ||
801 | .release = gpio_release, | ||
802 | }; | ||
803 | |||
804 | |||
805 | static void __init gpio_init_port_g(void) | ||
806 | { | ||
807 | #define GROUPA (0x0000FF3F) | ||
808 | #define GROUPB (1<<6 | 1<<7) | ||
809 | #define GROUPC (1<<30 | 1<<31) | ||
810 | #define GROUPD (0x3FFF0000) | ||
811 | #define GROUPD_LOW (0x00FF0000) | ||
812 | unsigned long used_in_bits = 0; | ||
813 | unsigned long used_out_bits = 0; | ||
814 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0, select)){ | ||
815 | used_in_bits |= GROUPA | GROUPB | 0 | 0; | ||
816 | used_out_bits |= GROUPA | GROUPB | 0 | 0; | ||
817 | } | ||
818 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ata, select)) { | ||
819 | used_in_bits |= GROUPA | GROUPB | GROUPC | (GROUPD & ~(1<<25|1<<26)); | ||
820 | used_out_bits |= GROUPA | GROUPB | GROUPC | GROUPD; | ||
821 | } | ||
822 | |||
823 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par0, select)) { | ||
824 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; | ||
825 | used_out_bits |= (GROUPA & ~(1<<0)) | 0 | 0 | 0; | ||
826 | } | ||
827 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser2, select)) { | ||
828 | used_in_bits |= 0 | GROUPB | 0 | 0; | ||
829 | used_out_bits |= 0 | GROUPB | 0 | 0; | ||
830 | } | ||
831 | /* mio same as shared RAM ? */ | ||
832 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio, select)) { | ||
833 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 |0 |GROUPD_LOW; | ||
834 | used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 |0 |GROUPD_LOW; | ||
835 | } | ||
836 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi1, select)) { | ||
837 | used_in_bits |= 0 | 0 | GROUPC | GROUPD; | ||
838 | used_out_bits |= 0 | 0 | GROUPC | GROUPD; | ||
839 | } | ||
840 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, scsi0w, select)) { | ||
841 | used_in_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24); | ||
842 | used_out_bits |= GROUPA | GROUPB | 0 | (GROUPD_LOW | 1<<24 | 1<<25|1<<26); | ||
843 | } | ||
844 | |||
845 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, par1, select)) { | ||
846 | used_in_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); | ||
847 | used_out_bits |= 0 | 0 | 0 | (GROUPD & ~(1<<24)); | ||
848 | } | ||
849 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, ser3, select)) { | ||
850 | used_in_bits |= 0 | 0 | GROUPC | 0; | ||
851 | used_out_bits |= 0 | 0 | GROUPC | 0; | ||
852 | } | ||
853 | /* mio same as shared RAM-W? */ | ||
854 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, mio_w, select)) { | ||
855 | used_in_bits |= (GROUPA & ~(1<<0)) | 0 | 0 |GROUPD_LOW; | ||
856 | used_out_bits |= (GROUPA & ~(1<<0|1<<1|1<<2)) | 0 | 0 |GROUPD_LOW; | ||
857 | } | ||
858 | /* TODO: USB p2, parw, sync ser3? */ | ||
859 | |||
860 | /* Initialise the dir_g_shadow etc. depending on genconfig */ | ||
861 | /* 0=input 1=output */ | ||
862 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g0dir, out)) | ||
863 | dir_g_shadow |= (1 << 0); | ||
864 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g8_15dir, out)) | ||
865 | dir_g_shadow |= 0x0000FF00; | ||
866 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g16_23dir, out)) | ||
867 | dir_g_shadow |= 0x00FF0000; | ||
868 | if (genconfig_shadow & IO_STATE(R_GEN_CONFIG, g24dir, out)) | ||
869 | dir_g_shadow |= (1 << 24); | ||
870 | |||
871 | dir_g_in_bits = ~used_in_bits; | ||
872 | dir_g_out_bits = ~used_out_bits; | ||
873 | |||
874 | changeable_dir_g = 0x01FFFF01; /* all that can change dir */ | ||
875 | changeable_dir_g &= dir_g_out_bits; | ||
876 | changeable_dir_g &= dir_g_in_bits; | ||
877 | /* Correct the bits that can change direction */ | ||
878 | dir_g_out_bits &= ~changeable_dir_g; | ||
879 | dir_g_out_bits |= dir_g_shadow; | ||
880 | dir_g_in_bits &= ~changeable_dir_g; | ||
881 | dir_g_in_bits |= (~dir_g_shadow & changeable_dir_g); | ||
882 | |||
883 | |||
884 | printk(KERN_INFO "GPIO port G: in_bits: 0x%08lX out_bits: 0x%08lX val: %08lX\n", | ||
885 | dir_g_in_bits, dir_g_out_bits, (unsigned long)*R_PORT_G_DATA); | ||
886 | printk(KERN_INFO "GPIO port G: dir: %08lX changeable: %08lX\n", | ||
887 | dir_g_shadow, changeable_dir_g); | ||
888 | } | ||
889 | |||
890 | /* main driver initialization routine, called from mem.c */ | ||
891 | |||
892 | static __init int | ||
893 | gpio_init(void) | ||
894 | { | ||
895 | int res; | ||
896 | #if defined (CONFIG_ETRAX_CSP0_LEDS) | ||
897 | int i; | ||
898 | #endif | ||
899 | |||
900 | /* do the formalities */ | ||
901 | |||
902 | res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); | ||
903 | if (res < 0) { | ||
904 | printk(KERN_ERR "gpio: couldn't get a major number.\n"); | ||
905 | return res; | ||
906 | } | ||
907 | |||
908 | /* Clear all leds */ | ||
909 | #if defined (CONFIG_ETRAX_CSP0_LEDS) || defined (CONFIG_ETRAX_PA_LEDS) || defined (CONFIG_ETRAX_PB_LEDS) | ||
910 | LED_NETWORK_SET(0); | ||
911 | LED_ACTIVE_SET(0); | ||
912 | LED_DISK_READ(0); | ||
913 | LED_DISK_WRITE(0); | ||
914 | |||
915 | #if defined (CONFIG_ETRAX_CSP0_LEDS) | ||
916 | for (i = 0; i < 32; i++) { | ||
917 | LED_BIT_SET(i); | ||
918 | } | ||
919 | #endif | ||
920 | |||
921 | #endif | ||
922 | gpio_init_port_g(); | ||
923 | printk(KERN_INFO "ETRAX 100LX GPIO driver v2.5, (c) 2001, 2002 Axis Communications AB\n"); | ||
924 | /* We call etrax_gpio_wake_up_check() from timer interrupt and | ||
925 | * from cpu_idle() in kernel/process.c | ||
926 | * The check in cpu_idle() reduces latency from ~15 ms to ~6 ms | ||
927 | * in some tests. | ||
928 | */ | ||
929 | if (request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt, | ||
930 | SA_SHIRQ | SA_INTERRUPT,"gpio poll", NULL)) { | ||
931 | printk(KERN_CRIT "err: timer0 irq for gpio\n"); | ||
932 | } | ||
933 | if (request_irq(PA_IRQ_NBR, gpio_pa_interrupt, | ||
934 | SA_SHIRQ | SA_INTERRUPT,"gpio PA", NULL)) { | ||
935 | printk(KERN_CRIT "err: PA irq for gpio\n"); | ||
936 | } | ||
937 | |||
938 | |||
939 | return res; | ||
940 | } | ||
941 | |||
942 | /* this makes sure that gpio_init is called during kernel boot */ | ||
943 | |||
944 | module_init(gpio_init); | ||
diff --git a/arch/cris/arch-v10/drivers/i2c.c b/arch/cris/arch-v10/drivers/i2c.c new file mode 100644 index 000000000000..8bbe233ba7b1 --- /dev/null +++ b/arch/cris/arch-v10/drivers/i2c.c | |||
@@ -0,0 +1,730 @@ | |||
1 | /*!*************************************************************************** | ||
2 | *! | ||
3 | *! FILE NAME : i2c.c | ||
4 | *! | ||
5 | *! DESCRIPTION: implements an interface for IIC/I2C, both directly from other | ||
6 | *! kernel modules (i2c_writereg/readreg) and from userspace using | ||
7 | *! ioctl()'s | ||
8 | *! | ||
9 | *! Nov 30 1998 Torbjorn Eliasson Initial version. | ||
10 | *! Bjorn Wesen Elinux kernel version. | ||
11 | *! Jan 14 2000 Johan Adolfsson Fixed PB shadow register stuff - | ||
12 | *! don't use PB_I2C if DS1302 uses same bits, | ||
13 | *! use PB. | ||
14 | *! $Log: i2c.c,v $ | ||
15 | *! Revision 1.9 2004/08/24 06:49:14 starvik | ||
16 | *! Whitespace cleanup | ||
17 | *! | ||
18 | *! Revision 1.8 2004/06/08 08:48:26 starvik | ||
19 | *! Removed unused code | ||
20 | *! | ||
21 | *! Revision 1.7 2004/05/28 09:26:59 starvik | ||
22 | *! Modified I2C initialization to work in 2.6. | ||
23 | *! | ||
24 | *! Revision 1.6 2004/05/14 07:58:03 starvik | ||
25 | *! Merge of changes from 2.4 | ||
26 | *! | ||
27 | *! Revision 1.4 2002/12/11 13:13:57 starvik | ||
28 | *! Added arch/ to v10 specific includes | ||
29 | *! Added fix from Linux 2.4 in serial.c (flush_to_flip_buffer) | ||
30 | *! | ||
31 | *! Revision 1.3 2002/11/20 11:56:11 starvik | ||
32 | *! Merge of Linux 2.5.48 | ||
33 | *! | ||
34 | *! Revision 1.2 2002/11/18 13:16:06 starvik | ||
35 | *! Linux 2.5 port of latest 2.4 drivers | ||
36 | *! | ||
37 | *! Revision 1.9 2002/10/31 15:32:26 starvik | ||
38 | *! Update Port B register and shadow even when running with hardware support | ||
39 | *! to avoid glitches when reading bits | ||
40 | *! Never set direction to out in i2c_inbyte | ||
41 | *! Removed incorrect clock togling at end of i2c_inbyte | ||
42 | *! | ||
43 | *! Revision 1.8 2002/08/13 06:31:53 starvik | ||
44 | *! Made SDA and SCL line configurable | ||
45 | *! Modified i2c_inbyte to work with PCF8563 | ||
46 | *! | ||
47 | *! Revision 1.7 2001/04/04 13:11:36 markusl | ||
48 | *! Updated according to review remarks | ||
49 | *! | ||
50 | *! Revision 1.6 2001/03/19 12:43:00 markusl | ||
51 | *! Made some symbols unstatic (used by the eeprom driver) | ||
52 | *! | ||
53 | *! Revision 1.5 2001/02/27 13:52:48 bjornw | ||
54 | *! malloc.h -> slab.h | ||
55 | *! | ||
56 | *! Revision 1.4 2001/02/15 07:17:40 starvik | ||
57 | *! Corrected usage if port_pb_i2c_shadow | ||
58 | *! | ||
59 | *! Revision 1.3 2001/01/26 17:55:13 bjornw | ||
60 | *! * Made I2C_USES_PB_NOT_PB_I2C a CONFIG option instead of assigning it | ||
61 | *! magically. Config.in needs to set it for the options that need it, like | ||
62 | *! Dallas 1302 support. Actually, it should be default since it screws up | ||
63 | *! the PB bits even if you don't use I2C.. | ||
64 | *! * Include linux/config.h to get the above | ||
65 | *! | ||
66 | *! Revision 1.2 2001/01/18 15:49:30 bjornw | ||
67 | *! 2.4 port of I2C including some cleanups (untested of course) | ||
68 | *! | ||
69 | *! Revision 1.1 2001/01/18 15:35:25 bjornw | ||
70 | *! Verbatim copy of the Etrax i2c driver, 2.0 elinux version | ||
71 | *! | ||
72 | *! | ||
73 | *! --------------------------------------------------------------------------- | ||
74 | *! | ||
75 | *! (C) Copyright 1999-2002 Axis Communications AB, LUND, SWEDEN | ||
76 | *! | ||
77 | *!***************************************************************************/ | ||
78 | /* $Id: i2c.c,v 1.9 2004/08/24 06:49:14 starvik Exp $ */ | ||
79 | |||
80 | /****************** INCLUDE FILES SECTION ***********************************/ | ||
81 | |||
82 | #include <linux/module.h> | ||
83 | #include <linux/sched.h> | ||
84 | #include <linux/slab.h> | ||
85 | #include <linux/errno.h> | ||
86 | #include <linux/kernel.h> | ||
87 | #include <linux/fs.h> | ||
88 | #include <linux/string.h> | ||
89 | #include <linux/init.h> | ||
90 | #include <linux/config.h> | ||
91 | |||
92 | #include <asm/etraxi2c.h> | ||
93 | |||
94 | #include <asm/system.h> | ||
95 | #include <asm/arch/svinto.h> | ||
96 | #include <asm/io.h> | ||
97 | #include <asm/delay.h> | ||
98 | |||
99 | #include "i2c.h" | ||
100 | |||
101 | /****************** I2C DEFINITION SECTION *************************/ | ||
102 | |||
103 | #define D(x) | ||
104 | |||
105 | #define I2C_MAJOR 123 /* LOCAL/EXPERIMENTAL */ | ||
106 | static const char i2c_name[] = "i2c"; | ||
107 | |||
108 | #define CLOCK_LOW_TIME 8 | ||
109 | #define CLOCK_HIGH_TIME 8 | ||
110 | #define START_CONDITION_HOLD_TIME 8 | ||
111 | #define STOP_CONDITION_HOLD_TIME 8 | ||
112 | #define ENABLE_OUTPUT 0x01 | ||
113 | #define ENABLE_INPUT 0x00 | ||
114 | #define I2C_CLOCK_HIGH 1 | ||
115 | #define I2C_CLOCK_LOW 0 | ||
116 | #define I2C_DATA_HIGH 1 | ||
117 | #define I2C_DATA_LOW 0 | ||
118 | |||
119 | #ifdef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C | ||
120 | /* Use PB and not PB_I2C */ | ||
121 | #ifndef CONFIG_ETRAX_I2C_DATA_PORT | ||
122 | #define CONFIG_ETRAX_I2C_DATA_PORT 0 | ||
123 | #endif | ||
124 | #ifndef CONFIG_ETRAX_I2C_CLK_PORT | ||
125 | #define CONFIG_ETRAX_I2C_CLK_PORT 1 | ||
126 | #endif | ||
127 | |||
128 | #define SDABIT CONFIG_ETRAX_I2C_DATA_PORT | ||
129 | #define SCLBIT CONFIG_ETRAX_I2C_CLK_PORT | ||
130 | #define i2c_enable() | ||
131 | #define i2c_disable() | ||
132 | |||
133 | /* enable or disable output-enable, to select output or input on the i2c bus */ | ||
134 | |||
135 | #define i2c_dir_out() \ | ||
136 | REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 1) | ||
137 | #define i2c_dir_in() \ | ||
138 | REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, SDABIT, 0) | ||
139 | |||
140 | /* control the i2c clock and data signals */ | ||
141 | |||
142 | #define i2c_clk(x) \ | ||
143 | REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SCLBIT, x) | ||
144 | #define i2c_data(x) \ | ||
145 | REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, SDABIT, x) | ||
146 | |||
147 | /* read a bit from the i2c interface */ | ||
148 | |||
149 | #define i2c_getbit() (((*R_PORT_PB_READ & (1 << SDABIT))) >> SDABIT) | ||
150 | |||
151 | #else | ||
152 | /* enable or disable the i2c interface */ | ||
153 | |||
154 | #define i2c_enable() *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_en)) | ||
155 | #define i2c_disable() *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_en)) | ||
156 | |||
157 | /* enable or disable output-enable, to select output or input on the i2c bus */ | ||
158 | |||
159 | #define i2c_dir_out() \ | ||
160 | *R_PORT_PB_I2C = (port_pb_i2c_shadow &= ~IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ | ||
161 | REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 1); | ||
162 | #define i2c_dir_in() \ | ||
163 | *R_PORT_PB_I2C = (port_pb_i2c_shadow |= IO_MASK(R_PORT_PB_I2C, i2c_oe_)); \ | ||
164 | REG_SHADOW_SET(R_PORT_PB_DIR, port_pb_dir_shadow, 0, 0); | ||
165 | |||
166 | /* control the i2c clock and data signals */ | ||
167 | |||
168 | #define i2c_clk(x) \ | ||
169 | *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ | ||
170 | ~IO_MASK(R_PORT_PB_I2C, i2c_clk)) | IO_FIELD(R_PORT_PB_I2C, i2c_clk, (x))); \ | ||
171 | REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 1, x); | ||
172 | |||
173 | #define i2c_data(x) \ | ||
174 | *R_PORT_PB_I2C = (port_pb_i2c_shadow = (port_pb_i2c_shadow & \ | ||
175 | ~IO_MASK(R_PORT_PB_I2C, i2c_d)) | IO_FIELD(R_PORT_PB_I2C, i2c_d, (x))); \ | ||
176 | REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, 0, x); | ||
177 | |||
178 | /* read a bit from the i2c interface */ | ||
179 | |||
180 | #define i2c_getbit() (*R_PORT_PB_READ & 0x1) | ||
181 | #endif | ||
182 | |||
183 | /* use the kernels delay routine */ | ||
184 | |||
185 | #define i2c_delay(usecs) udelay(usecs) | ||
186 | |||
187 | |||
188 | /****************** FUNCTION DEFINITION SECTION *************************/ | ||
189 | |||
190 | |||
191 | /* generate i2c start condition */ | ||
192 | |||
193 | void | ||
194 | i2c_start(void) | ||
195 | { | ||
196 | /* | ||
197 | * SCL=1 SDA=1 | ||
198 | */ | ||
199 | i2c_dir_out(); | ||
200 | i2c_delay(CLOCK_HIGH_TIME/6); | ||
201 | i2c_data(I2C_DATA_HIGH); | ||
202 | i2c_clk(I2C_CLOCK_HIGH); | ||
203 | i2c_delay(CLOCK_HIGH_TIME); | ||
204 | /* | ||
205 | * SCL=1 SDA=0 | ||
206 | */ | ||
207 | i2c_data(I2C_DATA_LOW); | ||
208 | i2c_delay(START_CONDITION_HOLD_TIME); | ||
209 | /* | ||
210 | * SCL=0 SDA=0 | ||
211 | */ | ||
212 | i2c_clk(I2C_CLOCK_LOW); | ||
213 | i2c_delay(CLOCK_LOW_TIME); | ||
214 | } | ||
215 | |||
216 | /* generate i2c stop condition */ | ||
217 | |||
218 | void | ||
219 | i2c_stop(void) | ||
220 | { | ||
221 | i2c_dir_out(); | ||
222 | |||
223 | /* | ||
224 | * SCL=0 SDA=0 | ||
225 | */ | ||
226 | i2c_clk(I2C_CLOCK_LOW); | ||
227 | i2c_data(I2C_DATA_LOW); | ||
228 | i2c_delay(CLOCK_LOW_TIME*2); | ||
229 | /* | ||
230 | * SCL=1 SDA=0 | ||
231 | */ | ||
232 | i2c_clk(I2C_CLOCK_HIGH); | ||
233 | i2c_delay(CLOCK_HIGH_TIME*2); | ||
234 | /* | ||
235 | * SCL=1 SDA=1 | ||
236 | */ | ||
237 | i2c_data(I2C_DATA_HIGH); | ||
238 | i2c_delay(STOP_CONDITION_HOLD_TIME); | ||
239 | |||
240 | i2c_dir_in(); | ||
241 | } | ||
242 | |||
243 | /* write a byte to the i2c interface */ | ||
244 | |||
245 | void | ||
246 | i2c_outbyte(unsigned char x) | ||
247 | { | ||
248 | int i; | ||
249 | |||
250 | i2c_dir_out(); | ||
251 | |||
252 | for (i = 0; i < 8; i++) { | ||
253 | if (x & 0x80) { | ||
254 | i2c_data(I2C_DATA_HIGH); | ||
255 | } else { | ||
256 | i2c_data(I2C_DATA_LOW); | ||
257 | } | ||
258 | |||
259 | i2c_delay(CLOCK_LOW_TIME/2); | ||
260 | i2c_clk(I2C_CLOCK_HIGH); | ||
261 | i2c_delay(CLOCK_HIGH_TIME); | ||
262 | i2c_clk(I2C_CLOCK_LOW); | ||
263 | i2c_delay(CLOCK_LOW_TIME/2); | ||
264 | x <<= 1; | ||
265 | } | ||
266 | i2c_data(I2C_DATA_LOW); | ||
267 | i2c_delay(CLOCK_LOW_TIME/2); | ||
268 | |||
269 | /* | ||
270 | * enable input | ||
271 | */ | ||
272 | i2c_dir_in(); | ||
273 | } | ||
274 | |||
275 | /* read a byte from the i2c interface */ | ||
276 | |||
277 | unsigned char | ||
278 | i2c_inbyte(void) | ||
279 | { | ||
280 | unsigned char aBitByte = 0; | ||
281 | int i; | ||
282 | |||
283 | /* Switch off I2C to get bit */ | ||
284 | i2c_disable(); | ||
285 | i2c_dir_in(); | ||
286 | i2c_delay(CLOCK_HIGH_TIME/2); | ||
287 | |||
288 | /* Get bit */ | ||
289 | aBitByte |= i2c_getbit(); | ||
290 | |||
291 | /* Enable I2C */ | ||
292 | i2c_enable(); | ||
293 | i2c_delay(CLOCK_LOW_TIME/2); | ||
294 | |||
295 | for (i = 1; i < 8; i++) { | ||
296 | aBitByte <<= 1; | ||
297 | /* Clock pulse */ | ||
298 | i2c_clk(I2C_CLOCK_HIGH); | ||
299 | i2c_delay(CLOCK_HIGH_TIME); | ||
300 | i2c_clk(I2C_CLOCK_LOW); | ||
301 | i2c_delay(CLOCK_LOW_TIME); | ||
302 | |||
303 | /* Switch off I2C to get bit */ | ||
304 | i2c_disable(); | ||
305 | i2c_dir_in(); | ||
306 | i2c_delay(CLOCK_HIGH_TIME/2); | ||
307 | |||
308 | /* Get bit */ | ||
309 | aBitByte |= i2c_getbit(); | ||
310 | |||
311 | /* Enable I2C */ | ||
312 | i2c_enable(); | ||
313 | i2c_delay(CLOCK_LOW_TIME/2); | ||
314 | } | ||
315 | i2c_clk(I2C_CLOCK_HIGH); | ||
316 | i2c_delay(CLOCK_HIGH_TIME); | ||
317 | |||
318 | /* | ||
319 | * we leave the clock low, getbyte is usually followed | ||
320 | * by sendack/nack, they assume the clock to be low | ||
321 | */ | ||
322 | i2c_clk(I2C_CLOCK_LOW); | ||
323 | return aBitByte; | ||
324 | } | ||
325 | |||
326 | /*#--------------------------------------------------------------------------- | ||
327 | *# | ||
328 | *# FUNCTION NAME: i2c_getack | ||
329 | *# | ||
330 | *# DESCRIPTION : checks if ack was received from ic2 | ||
331 | *# | ||
332 | *#--------------------------------------------------------------------------*/ | ||
333 | |||
334 | int | ||
335 | i2c_getack(void) | ||
336 | { | ||
337 | int ack = 1; | ||
338 | /* | ||
339 | * enable output | ||
340 | */ | ||
341 | i2c_dir_out(); | ||
342 | /* | ||
343 | * Release data bus by setting | ||
344 | * data high | ||
345 | */ | ||
346 | i2c_data(I2C_DATA_HIGH); | ||
347 | /* | ||
348 | * enable input | ||
349 | */ | ||
350 | i2c_dir_in(); | ||
351 | i2c_delay(CLOCK_HIGH_TIME/4); | ||
352 | /* | ||
353 | * generate ACK clock pulse | ||
354 | */ | ||
355 | i2c_clk(I2C_CLOCK_HIGH); | ||
356 | /* | ||
357 | * Use PORT PB instead of I2C | ||
358 | * for input. (I2C not working) | ||
359 | */ | ||
360 | i2c_clk(1); | ||
361 | i2c_data(1); | ||
362 | /* | ||
363 | * switch off I2C | ||
364 | */ | ||
365 | i2c_data(1); | ||
366 | i2c_disable(); | ||
367 | i2c_dir_in(); | ||
368 | /* | ||
369 | * now wait for ack | ||
370 | */ | ||
371 | i2c_delay(CLOCK_HIGH_TIME/2); | ||
372 | /* | ||
373 | * check for ack | ||
374 | */ | ||
375 | if(i2c_getbit()) | ||
376 | ack = 0; | ||
377 | i2c_delay(CLOCK_HIGH_TIME/2); | ||
378 | if(!ack){ | ||
379 | if(!i2c_getbit()) /* receiver pulld SDA low */ | ||
380 | ack = 1; | ||
381 | i2c_delay(CLOCK_HIGH_TIME/2); | ||
382 | } | ||
383 | |||
384 | /* | ||
385 | * our clock is high now, make sure data is low | ||
386 | * before we enable our output. If we keep data high | ||
387 | * and enable output, we would generate a stop condition. | ||
388 | */ | ||
389 | i2c_data(I2C_DATA_LOW); | ||
390 | |||
391 | /* | ||
392 | * end clock pulse | ||
393 | */ | ||
394 | i2c_enable(); | ||
395 | i2c_dir_out(); | ||
396 | i2c_clk(I2C_CLOCK_LOW); | ||
397 | i2c_delay(CLOCK_HIGH_TIME/4); | ||
398 | /* | ||
399 | * enable output | ||
400 | */ | ||
401 | i2c_dir_out(); | ||
402 | /* | ||
403 | * remove ACK clock pulse | ||
404 | */ | ||
405 | i2c_data(I2C_DATA_HIGH); | ||
406 | i2c_delay(CLOCK_LOW_TIME/2); | ||
407 | return ack; | ||
408 | } | ||
409 | |||
410 | /*#--------------------------------------------------------------------------- | ||
411 | *# | ||
412 | *# FUNCTION NAME: I2C::sendAck | ||
413 | *# | ||
414 | *# DESCRIPTION : Send ACK on received data | ||
415 | *# | ||
416 | *#--------------------------------------------------------------------------*/ | ||
417 | void | ||
418 | i2c_sendack(void) | ||
419 | { | ||
420 | /* | ||
421 | * enable output | ||
422 | */ | ||
423 | i2c_delay(CLOCK_LOW_TIME); | ||
424 | i2c_dir_out(); | ||
425 | /* | ||
426 | * set ack pulse high | ||
427 | */ | ||
428 | i2c_data(I2C_DATA_LOW); | ||
429 | /* | ||
430 | * generate clock pulse | ||
431 | */ | ||
432 | i2c_delay(CLOCK_HIGH_TIME/6); | ||
433 | i2c_clk(I2C_CLOCK_HIGH); | ||
434 | i2c_delay(CLOCK_HIGH_TIME); | ||
435 | i2c_clk(I2C_CLOCK_LOW); | ||
436 | i2c_delay(CLOCK_LOW_TIME/6); | ||
437 | /* | ||
438 | * reset data out | ||
439 | */ | ||
440 | i2c_data(I2C_DATA_HIGH); | ||
441 | i2c_delay(CLOCK_LOW_TIME); | ||
442 | |||
443 | i2c_dir_in(); | ||
444 | } | ||
445 | |||
446 | /*#--------------------------------------------------------------------------- | ||
447 | *# | ||
448 | *# FUNCTION NAME: i2c_sendnack | ||
449 | *# | ||
450 | *# DESCRIPTION : Sends NACK on received data | ||
451 | *# | ||
452 | *#--------------------------------------------------------------------------*/ | ||
453 | void | ||
454 | i2c_sendnack(void) | ||
455 | { | ||
456 | /* | ||
457 | * enable output | ||
458 | */ | ||
459 | i2c_delay(CLOCK_LOW_TIME); | ||
460 | i2c_dir_out(); | ||
461 | /* | ||
462 | * set data high | ||
463 | */ | ||
464 | i2c_data(I2C_DATA_HIGH); | ||
465 | /* | ||
466 | * generate clock pulse | ||
467 | */ | ||
468 | i2c_delay(CLOCK_HIGH_TIME/6); | ||
469 | i2c_clk(I2C_CLOCK_HIGH); | ||
470 | i2c_delay(CLOCK_HIGH_TIME); | ||
471 | i2c_clk(I2C_CLOCK_LOW); | ||
472 | i2c_delay(CLOCK_LOW_TIME); | ||
473 | |||
474 | i2c_dir_in(); | ||
475 | } | ||
476 | |||
477 | /*#--------------------------------------------------------------------------- | ||
478 | *# | ||
479 | *# FUNCTION NAME: i2c_writereg | ||
480 | *# | ||
481 | *# DESCRIPTION : Writes a value to an I2C device | ||
482 | *# | ||
483 | *#--------------------------------------------------------------------------*/ | ||
484 | int | ||
485 | i2c_writereg(unsigned char theSlave, unsigned char theReg, | ||
486 | unsigned char theValue) | ||
487 | { | ||
488 | int error, cntr = 3; | ||
489 | unsigned long flags; | ||
490 | |||
491 | do { | ||
492 | error = 0; | ||
493 | /* | ||
494 | * we don't like to be interrupted | ||
495 | */ | ||
496 | local_irq_save(flags); | ||
497 | local_irq_disable(); | ||
498 | |||
499 | i2c_start(); | ||
500 | /* | ||
501 | * send slave address | ||
502 | */ | ||
503 | i2c_outbyte((theSlave & 0xfe)); | ||
504 | /* | ||
505 | * wait for ack | ||
506 | */ | ||
507 | if(!i2c_getack()) | ||
508 | error = 1; | ||
509 | /* | ||
510 | * now select register | ||
511 | */ | ||
512 | i2c_dir_out(); | ||
513 | i2c_outbyte(theReg); | ||
514 | /* | ||
515 | * now it's time to wait for ack | ||
516 | */ | ||
517 | if(!i2c_getack()) | ||
518 | error |= 2; | ||
519 | /* | ||
520 | * send register register data | ||
521 | */ | ||
522 | i2c_outbyte(theValue); | ||
523 | /* | ||
524 | * now it's time to wait for ack | ||
525 | */ | ||
526 | if(!i2c_getack()) | ||
527 | error |= 4; | ||
528 | /* | ||
529 | * end byte stream | ||
530 | */ | ||
531 | i2c_stop(); | ||
532 | /* | ||
533 | * enable interrupt again | ||
534 | */ | ||
535 | local_irq_restore(flags); | ||
536 | |||
537 | } while(error && cntr--); | ||
538 | |||
539 | i2c_delay(CLOCK_LOW_TIME); | ||
540 | |||
541 | return -error; | ||
542 | } | ||
543 | |||
544 | /*#--------------------------------------------------------------------------- | ||
545 | *# | ||
546 | *# FUNCTION NAME: i2c_readreg | ||
547 | *# | ||
548 | *# DESCRIPTION : Reads a value from the decoder registers. | ||
549 | *# | ||
550 | *#--------------------------------------------------------------------------*/ | ||
551 | unsigned char | ||
552 | i2c_readreg(unsigned char theSlave, unsigned char theReg) | ||
553 | { | ||
554 | unsigned char b = 0; | ||
555 | int error, cntr = 3; | ||
556 | unsigned long flags; | ||
557 | |||
558 | do { | ||
559 | error = 0; | ||
560 | /* | ||
561 | * we don't like to be interrupted | ||
562 | */ | ||
563 | local_irq_save(flags); | ||
564 | local_irq_disable(); | ||
565 | /* | ||
566 | * generate start condition | ||
567 | */ | ||
568 | i2c_start(); | ||
569 | |||
570 | /* | ||
571 | * send slave address | ||
572 | */ | ||
573 | i2c_outbyte((theSlave & 0xfe)); | ||
574 | /* | ||
575 | * wait for ack | ||
576 | */ | ||
577 | if(!i2c_getack()) | ||
578 | error = 1; | ||
579 | /* | ||
580 | * now select register | ||
581 | */ | ||
582 | i2c_dir_out(); | ||
583 | i2c_outbyte(theReg); | ||
584 | /* | ||
585 | * now it's time to wait for ack | ||
586 | */ | ||
587 | if(!i2c_getack()) | ||
588 | error = 1; | ||
589 | /* | ||
590 | * repeat start condition | ||
591 | */ | ||
592 | i2c_delay(CLOCK_LOW_TIME); | ||
593 | i2c_start(); | ||
594 | /* | ||
595 | * send slave address | ||
596 | */ | ||
597 | i2c_outbyte(theSlave | 0x01); | ||
598 | /* | ||
599 | * wait for ack | ||
600 | */ | ||
601 | if(!i2c_getack()) | ||
602 | error = 1; | ||
603 | /* | ||
604 | * fetch register | ||
605 | */ | ||
606 | b = i2c_inbyte(); | ||
607 | /* | ||
608 | * last received byte needs to be nacked | ||
609 | * instead of acked | ||
610 | */ | ||
611 | i2c_sendack(); | ||
612 | /* | ||
613 | * end sequence | ||
614 | */ | ||
615 | i2c_stop(); | ||
616 | /* | ||
617 | * enable interrupt again | ||
618 | */ | ||
619 | local_irq_restore(flags); | ||
620 | |||
621 | } while(error && cntr--); | ||
622 | |||
623 | return b; | ||
624 | } | ||
625 | |||
626 | static int | ||
627 | i2c_open(struct inode *inode, struct file *filp) | ||
628 | { | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int | ||
633 | i2c_release(struct inode *inode, struct file *filp) | ||
634 | { | ||
635 | return 0; | ||
636 | } | ||
637 | |||
638 | /* Main device API. ioctl's to write or read to/from i2c registers. | ||
639 | */ | ||
640 | |||
641 | static int | ||
642 | i2c_ioctl(struct inode *inode, struct file *file, | ||
643 | unsigned int cmd, unsigned long arg) | ||
644 | { | ||
645 | if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) { | ||
646 | return -EINVAL; | ||
647 | } | ||
648 | |||
649 | switch (_IOC_NR(cmd)) { | ||
650 | case I2C_WRITEREG: | ||
651 | /* write to an i2c slave */ | ||
652 | D(printk("i2cw %d %d %d\n", | ||
653 | I2C_ARGSLAVE(arg), | ||
654 | I2C_ARGREG(arg), | ||
655 | I2C_ARGVALUE(arg))); | ||
656 | |||
657 | return i2c_writereg(I2C_ARGSLAVE(arg), | ||
658 | I2C_ARGREG(arg), | ||
659 | I2C_ARGVALUE(arg)); | ||
660 | case I2C_READREG: | ||
661 | { | ||
662 | unsigned char val; | ||
663 | /* read from an i2c slave */ | ||
664 | D(printk("i2cr %d %d ", | ||
665 | I2C_ARGSLAVE(arg), | ||
666 | I2C_ARGREG(arg))); | ||
667 | val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg)); | ||
668 | D(printk("= %d\n", val)); | ||
669 | return val; | ||
670 | } | ||
671 | default: | ||
672 | return -EINVAL; | ||
673 | |||
674 | } | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static struct file_operations i2c_fops = { | ||
680 | .owner = THIS_MODULE, | ||
681 | .ioctl = i2c_ioctl, | ||
682 | .open = i2c_open, | ||
683 | .release = i2c_release, | ||
684 | }; | ||
685 | |||
686 | int __init | ||
687 | i2c_init(void) | ||
688 | { | ||
689 | /* Setup and enable the Port B I2C interface */ | ||
690 | |||
691 | #ifndef CONFIG_ETRAX_I2C_USES_PB_NOT_PB_I2C | ||
692 | *R_PORT_PB_I2C = port_pb_i2c_shadow |= | ||
693 | IO_STATE(R_PORT_PB_I2C, i2c_en, on) | | ||
694 | IO_FIELD(R_PORT_PB_I2C, i2c_d, 1) | | ||
695 | IO_FIELD(R_PORT_PB_I2C, i2c_clk, 1) | | ||
696 | IO_STATE(R_PORT_PB_I2C, i2c_oe_, enable); | ||
697 | #endif | ||
698 | |||
699 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir0); | ||
700 | port_pb_dir_shadow &= ~IO_MASK(R_PORT_PB_DIR, dir1); | ||
701 | |||
702 | *R_PORT_PB_DIR = (port_pb_dir_shadow |= | ||
703 | IO_STATE(R_PORT_PB_DIR, dir0, input) | | ||
704 | IO_STATE(R_PORT_PB_DIR, dir1, output)); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int __init | ||
710 | i2c_register(void) | ||
711 | { | ||
712 | int res; | ||
713 | |||
714 | i2c_init(); | ||
715 | res = register_chrdev(I2C_MAJOR, i2c_name, &i2c_fops); | ||
716 | if(res < 0) { | ||
717 | printk(KERN_ERR "i2c: couldn't get a major number.\n"); | ||
718 | return res; | ||
719 | } | ||
720 | |||
721 | printk(KERN_INFO "I2C driver v2.2, (c) 1999-2001 Axis Communications AB\n"); | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | /* this makes sure that i2c_register is called during boot */ | ||
727 | |||
728 | module_init(i2c_register); | ||
729 | |||
730 | /****************** END OF FILE i2c.c ********************************/ | ||
diff --git a/arch/cris/arch-v10/drivers/i2c.h b/arch/cris/arch-v10/drivers/i2c.h new file mode 100644 index 000000000000..4ee91426bd40 --- /dev/null +++ b/arch/cris/arch-v10/drivers/i2c.h | |||
@@ -0,0 +1,18 @@ | |||
1 | /* $Id: i2c.h,v 1.3 2004/05/28 09:26:59 starvik Exp $ */ | ||
2 | |||
3 | int i2c_init(void); | ||
4 | |||
5 | /* High level I2C actions */ | ||
6 | int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); | ||
7 | unsigned char i2c_readreg(unsigned char theSlave, unsigned char theReg); | ||
8 | |||
9 | /* Low level I2C */ | ||
10 | void i2c_start(void); | ||
11 | void i2c_stop(void); | ||
12 | void i2c_outbyte(unsigned char x); | ||
13 | unsigned char i2c_inbyte(void); | ||
14 | int i2c_getack(void); | ||
15 | void i2c_sendack(void); | ||
16 | |||
17 | |||
18 | |||
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c new file mode 100644 index 000000000000..b3dfdf7b8fc5 --- /dev/null +++ b/arch/cris/arch-v10/drivers/pcf8563.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * PCF8563 RTC | ||
3 | * | ||
4 | * From Phillips' datasheet: | ||
5 | * | ||
6 | * The PCF8563 is a CMOS real-time clock/calendar optimized for low power | ||
7 | * consumption. A programmable clock output, interupt output and voltage | ||
8 | * low detector are also provided. All address and data are transferred | ||
9 | * serially via two-line bidirectional I2C-bus. Maximum bus speed is | ||
10 | * 400 kbits/s. The built-in word address register is incremented | ||
11 | * automatically after each written or read bute. | ||
12 | * | ||
13 | * Copyright (c) 2002, Axis Communications AB | ||
14 | * All rights reserved. | ||
15 | * | ||
16 | * Author: Tobias Anderberg <tobiasa@axis.com>. | ||
17 | * | ||
18 | * $Id: pcf8563.c,v 1.8 2004/08/24 06:42:51 starvik Exp $ | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/version.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/ioctl.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/bcd.h> | ||
32 | |||
33 | #include <asm/uaccess.h> | ||
34 | #include <asm/system.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/arch/svinto.h> | ||
37 | #include <asm/rtc.h> | ||
38 | #include "i2c.h" | ||
39 | |||
40 | #define PCF8563_MAJOR 121 /* Local major number. */ | ||
41 | #define DEVICE_NAME "rtc" /* Name which is registered in /proc/devices. */ | ||
42 | #define PCF8563_NAME "PCF8563" | ||
43 | #define DRIVER_VERSION "$Revision: 1.8 $" | ||
44 | |||
45 | /* I2C bus slave registers. */ | ||
46 | #define RTC_I2C_READ 0xa3 | ||
47 | #define RTC_I2C_WRITE 0xa2 | ||
48 | |||
49 | /* Two simple wrapper macros, saves a few keystrokes. */ | ||
50 | #define rtc_read(x) i2c_readreg(RTC_I2C_READ, x) | ||
51 | #define rtc_write(x,y) i2c_writereg(RTC_I2C_WRITE, x, y) | ||
52 | |||
53 | static const unsigned char days_in_month[] = | ||
54 | { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; | ||
55 | |||
56 | int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | ||
57 | |||
58 | static struct file_operations pcf8563_fops = { | ||
59 | .owner = THIS_MODULE, | ||
60 | .ioctl = pcf8563_ioctl, | ||
61 | }; | ||
62 | |||
63 | unsigned char | ||
64 | pcf8563_readreg(int reg) | ||
65 | { | ||
66 | unsigned char res = i2c_readreg(RTC_I2C_READ, reg); | ||
67 | |||
68 | /* The PCF8563 does not return 0 for unimplemented bits */ | ||
69 | switch(reg) | ||
70 | { | ||
71 | case RTC_SECONDS: | ||
72 | case RTC_MINUTES: | ||
73 | res &= 0x7f; | ||
74 | break; | ||
75 | case RTC_HOURS: | ||
76 | case RTC_DAY_OF_MONTH: | ||
77 | res &= 0x3f; | ||
78 | break; | ||
79 | case RTC_MONTH: | ||
80 | res = (res & 0x1f) - 1; /* PCF8563 returns month in range 1-12 */ | ||
81 | break; | ||
82 | } | ||
83 | return res; | ||
84 | } | ||
85 | |||
86 | void | ||
87 | pcf8563_writereg(int reg, unsigned char val) | ||
88 | { | ||
89 | #ifdef CONFIG_ETRAX_RTC_READONLY | ||
90 | if (reg == RTC_CONTROL1 || (reg >= RTC_SECONDS && reg <= RTC_YEAR)) | ||
91 | return; | ||
92 | #endif | ||
93 | |||
94 | rtc_write(reg, val); | ||
95 | } | ||
96 | |||
97 | void | ||
98 | get_rtc_time(struct rtc_time *tm) | ||
99 | { | ||
100 | tm->tm_sec = rtc_read(RTC_SECONDS); | ||
101 | tm->tm_min = rtc_read(RTC_MINUTES); | ||
102 | tm->tm_hour = rtc_read(RTC_HOURS); | ||
103 | tm->tm_mday = rtc_read(RTC_DAY_OF_MONTH); | ||
104 | tm->tm_mon = rtc_read(RTC_MONTH); | ||
105 | tm->tm_year = rtc_read(RTC_YEAR); | ||
106 | |||
107 | if (tm->tm_sec & 0x80) | ||
108 | printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); | ||
109 | |||
110 | tm->tm_year = BCD_TO_BIN(tm->tm_year) + ((tm->tm_mon & 0x80) ? 100 : 0); | ||
111 | tm->tm_sec &= 0x7f; | ||
112 | tm->tm_min &= 0x7f; | ||
113 | tm->tm_hour &= 0x3f; | ||
114 | tm->tm_mday &= 0x3f; | ||
115 | tm->tm_mon &= 0x1f; | ||
116 | |||
117 | BCD_TO_BIN(tm->tm_sec); | ||
118 | BCD_TO_BIN(tm->tm_min); | ||
119 | BCD_TO_BIN(tm->tm_hour); | ||
120 | BCD_TO_BIN(tm->tm_mday); | ||
121 | BCD_TO_BIN(tm->tm_mon); | ||
122 | tm->tm_mon--; /* Month is 1..12 in RTC but 0..11 in linux */ | ||
123 | } | ||
124 | |||
125 | int __init | ||
126 | pcf8563_init(void) | ||
127 | { | ||
128 | unsigned char ret; | ||
129 | |||
130 | i2c_init(); | ||
131 | |||
132 | /* | ||
133 | * First of all we need to reset the chip. This is done by | ||
134 | * clearing control1, control2 and clk freq, clear the | ||
135 | * Voltage Low bit, and resetting all alarms. | ||
136 | */ | ||
137 | if (rtc_write(RTC_CONTROL1, 0x00) < 0) | ||
138 | goto err; | ||
139 | |||
140 | if (rtc_write(RTC_CONTROL2, 0x00) < 0) | ||
141 | goto err; | ||
142 | |||
143 | if (rtc_write(RTC_CLOCKOUT_FREQ, 0x00) < 0) | ||
144 | goto err; | ||
145 | |||
146 | /* Clear the VL bit in the seconds register. */ | ||
147 | ret = rtc_read(RTC_SECONDS); | ||
148 | |||
149 | if (rtc_write(RTC_SECONDS, (ret & 0x7f)) < 0) | ||
150 | goto err; | ||
151 | |||
152 | /* Reset the alarms. */ | ||
153 | if (rtc_write(RTC_MINUTE_ALARM, 0x00) < 0) | ||
154 | goto err; | ||
155 | |||
156 | if (rtc_write(RTC_HOUR_ALARM, 0x00) < 0) | ||
157 | goto err; | ||
158 | |||
159 | if (rtc_write(RTC_DAY_ALARM, 0x00) < 0) | ||
160 | goto err; | ||
161 | |||
162 | if (rtc_write(RTC_WEEKDAY_ALARM, 0x00) < 0) | ||
163 | goto err; | ||
164 | |||
165 | /* Check for low voltage, and warn about it.. */ | ||
166 | if (rtc_read(RTC_SECONDS) & 0x80) | ||
167 | printk(KERN_WARNING "%s: RTC Low Voltage - date/time is not reliable!\n", PCF8563_NAME); | ||
168 | |||
169 | return 0; | ||
170 | |||
171 | err: | ||
172 | printk(KERN_INFO "%s: Error initializing chip.\n", PCF8563_NAME); | ||
173 | return -1; | ||
174 | } | ||
175 | |||
176 | void __exit | ||
177 | pcf8563_exit(void) | ||
178 | { | ||
179 | if (unregister_chrdev(PCF8563_MAJOR, DEVICE_NAME) < 0) { | ||
180 | printk(KERN_INFO "%s: Unable to unregister device.\n", PCF8563_NAME); | ||
181 | } | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * ioctl calls for this driver. Why return -ENOTTY upon error? Because | ||
186 | * POSIX says so! | ||
187 | */ | ||
188 | int | ||
189 | pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) | ||
190 | { | ||
191 | /* Some sanity checks. */ | ||
192 | if (_IOC_TYPE(cmd) != RTC_MAGIC) | ||
193 | return -ENOTTY; | ||
194 | |||
195 | if (_IOC_NR(cmd) > RTC_MAX_IOCTL) | ||
196 | return -ENOTTY; | ||
197 | |||
198 | switch (cmd) { | ||
199 | case RTC_RD_TIME: | ||
200 | { | ||
201 | struct rtc_time tm; | ||
202 | |||
203 | get_rtc_time(&tm); | ||
204 | |||
205 | if (copy_to_user((struct rtc_time *) arg, &tm, sizeof(struct rtc_time))) { | ||
206 | return -EFAULT; | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | break; | ||
212 | case RTC_SET_TIME: | ||
213 | { | ||
214 | #ifdef CONFIG_ETRAX_RTC_READONLY | ||
215 | return -EPERM; | ||
216 | #else | ||
217 | int leap; | ||
218 | int century; | ||
219 | struct rtc_time tm; | ||
220 | |||
221 | memset(&tm, 0, sizeof (struct rtc_time)); | ||
222 | if (!capable(CAP_SYS_TIME)) | ||
223 | return -EPERM; | ||
224 | |||
225 | if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) | ||
226 | return -EFAULT; | ||
227 | |||
228 | /* Convert from struct tm to struct rtc_time. */ | ||
229 | tm.tm_year += 1900; | ||
230 | tm.tm_mon += 1; | ||
231 | |||
232 | leap = ((tm.tm_mon == 2) && ((tm.tm_year % 4) == 0)) ? 1 : 0; | ||
233 | |||
234 | /* Perform some sanity checks. */ | ||
235 | if ((tm.tm_year < 1970) || | ||
236 | (tm.tm_mon > 12) || | ||
237 | (tm.tm_mday == 0) || | ||
238 | (tm.tm_mday > days_in_month[tm.tm_mon] + leap) || | ||
239 | (tm.tm_hour >= 24) || | ||
240 | (tm.tm_min >= 60) || | ||
241 | (tm.tm_sec >= 60)) | ||
242 | return -EINVAL; | ||
243 | |||
244 | century = (tm.tm_year >= 2000) ? 0x80 : 0; | ||
245 | tm.tm_year = tm.tm_year % 100; | ||
246 | |||
247 | BIN_TO_BCD(tm.tm_year); | ||
248 | BIN_TO_BCD(tm.tm_mday); | ||
249 | BIN_TO_BCD(tm.tm_hour); | ||
250 | BIN_TO_BCD(tm.tm_min); | ||
251 | BIN_TO_BCD(tm.tm_sec); | ||
252 | tm.tm_mon |= century; | ||
253 | |||
254 | rtc_write(RTC_YEAR, tm.tm_year); | ||
255 | rtc_write(RTC_MONTH, tm.tm_mon); | ||
256 | rtc_write(RTC_DAY_OF_MONTH, tm.tm_mday); | ||
257 | rtc_write(RTC_HOURS, tm.tm_hour); | ||
258 | rtc_write(RTC_MINUTES, tm.tm_min); | ||
259 | rtc_write(RTC_SECONDS, tm.tm_sec); | ||
260 | |||
261 | return 0; | ||
262 | #endif /* !CONFIG_ETRAX_RTC_READONLY */ | ||
263 | } | ||
264 | |||
265 | case RTC_VLOW_RD: | ||
266 | { | ||
267 | int vl_bit = 0; | ||
268 | |||
269 | if (rtc_read(RTC_SECONDS) & 0x80) { | ||
270 | vl_bit = 1; | ||
271 | printk(KERN_WARNING "%s: RTC Voltage Low - reliable " | ||
272 | "date/time information is no longer guaranteed!\n", | ||
273 | PCF8563_NAME); | ||
274 | } | ||
275 | if (copy_to_user((int *) arg, &vl_bit, sizeof(int))) | ||
276 | return -EFAULT; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | case RTC_VLOW_SET: | ||
282 | { | ||
283 | /* Clear the VL bit in the seconds register */ | ||
284 | int ret = rtc_read(RTC_SECONDS); | ||
285 | |||
286 | rtc_write(RTC_SECONDS, (ret & 0x7F)); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | default: | ||
292 | return -ENOTTY; | ||
293 | } | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int __init | ||
299 | pcf8563_register(void) | ||
300 | { | ||
301 | pcf8563_init(); | ||
302 | if (register_chrdev(PCF8563_MAJOR, DEVICE_NAME, &pcf8563_fops) < 0) { | ||
303 | printk(KERN_INFO "%s: Unable to get major numer %d for RTC device.\n", | ||
304 | PCF8563_NAME, PCF8563_MAJOR); | ||
305 | return -1; | ||
306 | } | ||
307 | |||
308 | printk(KERN_INFO "%s Real-Time Clock Driver, %s\n", PCF8563_NAME, DRIVER_VERSION); | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | module_init(pcf8563_register); | ||
313 | module_exit(pcf8563_exit); | ||
diff --git a/arch/cris/arch-v10/kernel/Makefile b/arch/cris/arch-v10/kernel/Makefile new file mode 100644 index 000000000000..52761603b6a5 --- /dev/null +++ b/arch/cris/arch-v10/kernel/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | # $Id: Makefile,v 1.5 2004/06/02 08:24:38 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | extra-y := head.o | ||
7 | |||
8 | |||
9 | obj-y := entry.o traps.o shadows.o debugport.o irq.o \ | ||
10 | process.o setup.o signal.o traps.o time.o ptrace.o | ||
11 | |||
12 | obj-$(CONFIG_ETRAX_KGDB) += kgdb.o | ||
13 | obj-$(CONFIG_ETRAX_FAST_TIMER) += fasttimer.o | ||
14 | obj-$(CONFIG_MODULES) += crisksyms.o | ||
15 | |||
16 | clean: | ||
17 | |||
diff --git a/arch/cris/arch-v10/kernel/asm-offsets.c b/arch/cris/arch-v10/kernel/asm-offsets.c new file mode 100644 index 000000000000..1aa3cc4e7107 --- /dev/null +++ b/arch/cris/arch-v10/kernel/asm-offsets.c | |||
@@ -0,0 +1,47 @@ | |||
1 | #include <linux/sched.h> | ||
2 | #include <asm/thread_info.h> | ||
3 | |||
4 | /* | ||
5 | * Generate definitions needed by assembly language modules. | ||
6 | * This code generates raw asm output which is post-processed to extract | ||
7 | * and format the required data. | ||
8 | */ | ||
9 | |||
10 | #define DEFINE(sym, val) \ | ||
11 | asm volatile("\n->" #sym " %0 " #val : : "i" (val)) | ||
12 | |||
13 | #define BLANK() asm volatile("\n->" : : ) | ||
14 | |||
15 | int main(void) | ||
16 | { | ||
17 | #define ENTRY(entry) DEFINE(PT_ ## entry, offsetof(struct pt_regs, entry)) | ||
18 | ENTRY(orig_r10); | ||
19 | ENTRY(r13); | ||
20 | ENTRY(r12); | ||
21 | ENTRY(r11); | ||
22 | ENTRY(r10); | ||
23 | ENTRY(r9); | ||
24 | ENTRY(mof); | ||
25 | ENTRY(dccr); | ||
26 | ENTRY(srp); | ||
27 | BLANK(); | ||
28 | #undef ENTRY | ||
29 | #define ENTRY(entry) DEFINE(TI_ ## entry, offsetof(struct thread_info, entry)) | ||
30 | ENTRY(task); | ||
31 | ENTRY(flags); | ||
32 | ENTRY(preempt_count); | ||
33 | BLANK(); | ||
34 | #undef ENTRY | ||
35 | #define ENTRY(entry) DEFINE(THREAD_ ## entry, offsetof(struct thread_struct, entry)) | ||
36 | ENTRY(ksp); | ||
37 | ENTRY(usp); | ||
38 | ENTRY(dccr); | ||
39 | BLANK(); | ||
40 | #undef ENTRY | ||
41 | #define ENTRY(entry) DEFINE(TASK_ ## entry, offsetof(struct task_struct, entry)) | ||
42 | ENTRY(pid); | ||
43 | BLANK(); | ||
44 | DEFINE(LCLONE_VM, CLONE_VM); | ||
45 | DEFINE(LCLONE_UNTRACED, CLONE_UNTRACED); | ||
46 | return 0; | ||
47 | } | ||
diff --git a/arch/cris/arch-v10/kernel/crisksyms.c b/arch/cris/arch-v10/kernel/crisksyms.c new file mode 100644 index 000000000000..b332bf9b312b --- /dev/null +++ b/arch/cris/arch-v10/kernel/crisksyms.c | |||
@@ -0,0 +1,17 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <asm/io.h> | ||
4 | #include <asm/arch/svinto.h> | ||
5 | |||
6 | /* Export shadow registers for the CPU I/O pins */ | ||
7 | EXPORT_SYMBOL(genconfig_shadow); | ||
8 | EXPORT_SYMBOL(port_pa_data_shadow); | ||
9 | EXPORT_SYMBOL(port_pa_dir_shadow); | ||
10 | EXPORT_SYMBOL(port_pb_data_shadow); | ||
11 | EXPORT_SYMBOL(port_pb_dir_shadow); | ||
12 | EXPORT_SYMBOL(port_pb_config_shadow); | ||
13 | EXPORT_SYMBOL(port_g_data_shadow); | ||
14 | |||
15 | /* Cache flush functions */ | ||
16 | EXPORT_SYMBOL(flush_etrax_cache); | ||
17 | EXPORT_SYMBOL(prepare_rx_descriptor); | ||
diff --git a/arch/cris/arch-v10/kernel/debugport.c b/arch/cris/arch-v10/kernel/debugport.c new file mode 100644 index 000000000000..6cf069e5e7b6 --- /dev/null +++ b/arch/cris/arch-v10/kernel/debugport.c | |||
@@ -0,0 +1,531 @@ | |||
1 | /* Serialport functions for debugging | ||
2 | * | ||
3 | * Copyright (c) 2000 Axis Communications AB | ||
4 | * | ||
5 | * Authors: Bjorn Wesen | ||
6 | * | ||
7 | * Exports: | ||
8 | * console_print_etrax(char *buf) | ||
9 | * int getDebugChar() | ||
10 | * putDebugChar(int) | ||
11 | * enableDebugIRQ() | ||
12 | * init_etrax_debug() | ||
13 | * | ||
14 | * $Log: debugport.c,v $ | ||
15 | * Revision 1.19 2004/10/21 07:26:16 starvik | ||
16 | * Made it possible to specify console settings on kernel command line. | ||
17 | * | ||
18 | * Revision 1.18 2004/10/19 13:07:37 starvik | ||
19 | * Merge of Linux 2.6.9 | ||
20 | * | ||
21 | * Revision 1.17 2004/09/29 10:33:46 starvik | ||
22 | * Resolved a dealock when printing debug from kernel. | ||
23 | * | ||
24 | * Revision 1.16 2004/08/24 06:12:19 starvik | ||
25 | * Whitespace cleanup | ||
26 | * | ||
27 | * Revision 1.15 2004/08/16 12:37:19 starvik | ||
28 | * Merge of Linux 2.6.8 | ||
29 | * | ||
30 | * Revision 1.14 2004/05/17 13:11:29 starvik | ||
31 | * Disable DMA until real serial driver is up | ||
32 | * | ||
33 | * Revision 1.13 2004/05/14 07:58:01 starvik | ||
34 | * Merge of changes from 2.4 | ||
35 | * | ||
36 | * Revision 1.12 2003/09/11 07:29:49 starvik | ||
37 | * Merge of Linux 2.6.0-test5 | ||
38 | * | ||
39 | * Revision 1.11 2003/07/07 09:53:36 starvik | ||
40 | * Revert all the 2.5.74 merge changes to make the console work again | ||
41 | * | ||
42 | * Revision 1.9 2003/02/17 17:07:23 starvik | ||
43 | * Solved the problem with corrupted debug output (from Linux 2.4) | ||
44 | * * Wait until DMA, FIFO and pipe is empty before and after transmissions | ||
45 | * * Buffer data until a FIFO flush can be triggered. | ||
46 | * | ||
47 | * Revision 1.8 2003/01/22 06:48:36 starvik | ||
48 | * Fixed warnings issued by GCC 3.2.1 | ||
49 | * | ||
50 | * Revision 1.7 2002/12/12 08:26:32 starvik | ||
51 | * Don't use C-comments inside CVS comments | ||
52 | * | ||
53 | * Revision 1.6 2002/12/11 15:42:02 starvik | ||
54 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
55 | * | ||
56 | * Revision 1.5 2002/11/20 06:58:03 starvik | ||
57 | * Compiles with kgdb | ||
58 | * | ||
59 | * Revision 1.4 2002/11/19 14:35:24 starvik | ||
60 | * Changes from linux 2.4 | ||
61 | * Changed struct initializer syntax to the currently prefered notation | ||
62 | * | ||
63 | * Revision 1.3 2002/11/06 09:47:03 starvik | ||
64 | * Modified for new interrupt macros | ||
65 | * | ||
66 | * Revision 1.2 2002/01/21 15:21:50 bjornw | ||
67 | * Update for kdev_t changes | ||
68 | * | ||
69 | * Revision 1.6 2001/04/17 13:58:39 orjanf | ||
70 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
71 | * | ||
72 | * Revision 1.5 2001/03/26 14:22:05 bjornw | ||
73 | * Namechange of some config options | ||
74 | * | ||
75 | * Revision 1.4 2000/10/06 12:37:26 bjornw | ||
76 | * Use physical addresses when talking to DMA | ||
77 | * | ||
78 | * | ||
79 | */ | ||
80 | |||
81 | #include <linux/config.h> | ||
82 | #include <linux/console.h> | ||
83 | #include <linux/init.h> | ||
84 | #include <linux/major.h> | ||
85 | #include <linux/delay.h> | ||
86 | #include <linux/tty.h> | ||
87 | #include <asm/system.h> | ||
88 | #include <asm/arch/svinto.h> | ||
89 | #include <asm/io.h> /* Get SIMCOUT. */ | ||
90 | |||
91 | struct dbg_port | ||
92 | { | ||
93 | unsigned int index; | ||
94 | const volatile unsigned* read; | ||
95 | volatile char* write; | ||
96 | volatile unsigned* xoff; | ||
97 | volatile char* baud; | ||
98 | volatile char* tr_ctrl; | ||
99 | volatile char* rec_ctrl; | ||
100 | unsigned long irq; | ||
101 | unsigned int started; | ||
102 | unsigned long baudrate; | ||
103 | unsigned char parity; | ||
104 | unsigned int bits; | ||
105 | }; | ||
106 | |||
107 | struct dbg_port ports[]= | ||
108 | { | ||
109 | { | ||
110 | 0, | ||
111 | R_SERIAL0_READ, | ||
112 | R_SERIAL0_TR_DATA, | ||
113 | R_SERIAL0_XOFF, | ||
114 | R_SERIAL0_BAUD, | ||
115 | R_SERIAL0_TR_CTRL, | ||
116 | R_SERIAL0_REC_CTRL, | ||
117 | IO_STATE(R_IRQ_MASK1_SET, ser0_data, set) | ||
118 | }, | ||
119 | { | ||
120 | 1, | ||
121 | R_SERIAL1_READ, | ||
122 | R_SERIAL1_TR_DATA, | ||
123 | R_SERIAL1_XOFF, | ||
124 | R_SERIAL1_BAUD, | ||
125 | R_SERIAL1_TR_CTRL, | ||
126 | R_SERIAL1_REC_CTRL, | ||
127 | IO_STATE(R_IRQ_MASK1_SET, ser1_data, set) | ||
128 | }, | ||
129 | { | ||
130 | 2, | ||
131 | R_SERIAL2_READ, | ||
132 | R_SERIAL2_TR_DATA, | ||
133 | R_SERIAL2_XOFF, | ||
134 | R_SERIAL2_BAUD, | ||
135 | R_SERIAL2_TR_CTRL, | ||
136 | R_SERIAL2_REC_CTRL, | ||
137 | IO_STATE(R_IRQ_MASK1_SET, ser2_data, set) | ||
138 | }, | ||
139 | { | ||
140 | 3, | ||
141 | R_SERIAL3_READ, | ||
142 | R_SERIAL3_TR_DATA, | ||
143 | R_SERIAL3_XOFF, | ||
144 | R_SERIAL3_BAUD, | ||
145 | R_SERIAL3_TR_CTRL, | ||
146 | R_SERIAL3_REC_CTRL, | ||
147 | IO_STATE(R_IRQ_MASK1_SET, ser3_data, set) | ||
148 | } | ||
149 | }; | ||
150 | |||
151 | static struct tty_driver *serial_driver; | ||
152 | |||
153 | struct dbg_port* port = | ||
154 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) | ||
155 | &ports[0]; | ||
156 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
157 | &ports[1]; | ||
158 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
159 | &ports[2]; | ||
160 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
161 | &ports[3]; | ||
162 | #else | ||
163 | NULL; | ||
164 | #endif | ||
165 | /* Used by serial.c to register a debug_write_function so that the normal | ||
166 | * serial driver is used for kernel debug output | ||
167 | */ | ||
168 | typedef int (*debugport_write_function)(int i, const char *buf, unsigned int len); | ||
169 | |||
170 | debugport_write_function debug_write_function = NULL; | ||
171 | |||
172 | static void | ||
173 | start_port(void) | ||
174 | { | ||
175 | unsigned long rec_ctrl = 0; | ||
176 | unsigned long tr_ctrl = 0; | ||
177 | |||
178 | if (!port) | ||
179 | return; | ||
180 | |||
181 | if (port->started) | ||
182 | return; | ||
183 | port->started = 1; | ||
184 | |||
185 | if (port->index == 0) | ||
186 | { | ||
187 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma6); | ||
188 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma6, unused); | ||
189 | } | ||
190 | else if (port->index == 1) | ||
191 | { | ||
192 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma8); | ||
193 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma8, usb); | ||
194 | } | ||
195 | else if (port->index == 2) | ||
196 | { | ||
197 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma2); | ||
198 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma2, par0); | ||
199 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma3); | ||
200 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma3, par0); | ||
201 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser2, select); | ||
202 | } | ||
203 | else | ||
204 | { | ||
205 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma4); | ||
206 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma4, par1); | ||
207 | genconfig_shadow &= ~IO_MASK(R_GEN_CONFIG, dma5); | ||
208 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, dma5, par1); | ||
209 | genconfig_shadow |= IO_STATE(R_GEN_CONFIG, ser3, select); | ||
210 | } | ||
211 | |||
212 | *R_GEN_CONFIG = genconfig_shadow; | ||
213 | |||
214 | *port->xoff = | ||
215 | IO_STATE(R_SERIAL0_XOFF, tx_stop, enable) | | ||
216 | IO_STATE(R_SERIAL0_XOFF, auto_xoff, disable) | | ||
217 | IO_FIELD(R_SERIAL0_XOFF, xoff_char, 0); | ||
218 | |||
219 | switch (port->baudrate) | ||
220 | { | ||
221 | case 0: | ||
222 | case 115200: | ||
223 | *port->baud = | ||
224 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | | ||
225 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); | ||
226 | break; | ||
227 | case 1200: | ||
228 | *port->baud = | ||
229 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c1200Hz) | | ||
230 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c1200Hz); | ||
231 | break; | ||
232 | case 2400: | ||
233 | *port->baud = | ||
234 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c2400Hz) | | ||
235 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c2400Hz); | ||
236 | break; | ||
237 | case 4800: | ||
238 | *port->baud = | ||
239 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c4800Hz) | | ||
240 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c4800Hz); | ||
241 | break; | ||
242 | case 9600: | ||
243 | *port->baud = | ||
244 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c9600Hz) | | ||
245 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c9600Hz); | ||
246 | break; | ||
247 | case 19200: | ||
248 | *port->baud = | ||
249 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c19k2Hz) | | ||
250 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c19k2Hz); | ||
251 | break; | ||
252 | case 38400: | ||
253 | *port->baud = | ||
254 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c38k4Hz) | | ||
255 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c38k4Hz); | ||
256 | break; | ||
257 | case 57600: | ||
258 | *port->baud = | ||
259 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c57k6Hz) | | ||
260 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c57k6Hz); | ||
261 | break; | ||
262 | default: | ||
263 | *port->baud = | ||
264 | IO_STATE(R_SERIAL0_BAUD, tr_baud, c115k2Hz) | | ||
265 | IO_STATE(R_SERIAL0_BAUD, rec_baud, c115k2Hz); | ||
266 | break; | ||
267 | } | ||
268 | |||
269 | if (port->parity == 'E') { | ||
270 | rec_ctrl = | ||
271 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | | ||
272 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); | ||
273 | tr_ctrl = | ||
274 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | | ||
275 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); | ||
276 | } else if (port->parity == 'O') { | ||
277 | rec_ctrl = | ||
278 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, odd) | | ||
279 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, enable); | ||
280 | tr_ctrl = | ||
281 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, odd) | | ||
282 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, enable); | ||
283 | } else { | ||
284 | rec_ctrl = | ||
285 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par, even) | | ||
286 | IO_STATE(R_SERIAL0_REC_CTRL, rec_par_en, disable); | ||
287 | tr_ctrl = | ||
288 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par, even) | | ||
289 | IO_STATE(R_SERIAL0_TR_CTRL, tr_par_en, disable); | ||
290 | } | ||
291 | |||
292 | if (port->bits == 7) | ||
293 | { | ||
294 | rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_7bit); | ||
295 | tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_7bit); | ||
296 | } | ||
297 | else | ||
298 | { | ||
299 | rec_ctrl |= IO_STATE(R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit); | ||
300 | tr_ctrl |= IO_STATE(R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit); | ||
301 | } | ||
302 | |||
303 | *port->rec_ctrl = | ||
304 | IO_STATE(R_SERIAL0_REC_CTRL, dma_err, stop) | | ||
305 | IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable) | | ||
306 | IO_STATE(R_SERIAL0_REC_CTRL, rts_, active) | | ||
307 | IO_STATE(R_SERIAL0_REC_CTRL, sampling, middle) | | ||
308 | IO_STATE(R_SERIAL0_REC_CTRL, rec_stick_par, normal) | | ||
309 | rec_ctrl; | ||
310 | |||
311 | *port->tr_ctrl = | ||
312 | IO_FIELD(R_SERIAL0_TR_CTRL, txd, 0) | | ||
313 | IO_STATE(R_SERIAL0_TR_CTRL, tr_enable, enable) | | ||
314 | IO_STATE(R_SERIAL0_TR_CTRL, auto_cts, disabled) | | ||
315 | IO_STATE(R_SERIAL0_TR_CTRL, stop_bits, one_bit) | | ||
316 | IO_STATE(R_SERIAL0_TR_CTRL, tr_stick_par, normal) | | ||
317 | tr_ctrl; | ||
318 | } | ||
319 | |||
320 | static void | ||
321 | console_write_direct(struct console *co, const char *buf, unsigned int len) | ||
322 | { | ||
323 | int i; | ||
324 | unsigned long flags; | ||
325 | local_irq_save(flags); | ||
326 | /* Send data */ | ||
327 | for (i = 0; i < len; i++) { | ||
328 | /* Wait until transmitter is ready and send.*/ | ||
329 | while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) | ||
330 | ; | ||
331 | *port->write = buf[i]; | ||
332 | } | ||
333 | local_irq_restore(flags); | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | console_write(struct console *co, const char *buf, unsigned int len) | ||
338 | { | ||
339 | if (!port) | ||
340 | return; | ||
341 | |||
342 | #ifdef CONFIG_SVINTO_SIM | ||
343 | /* no use to simulate the serial debug output */ | ||
344 | SIMCOUT(buf, len); | ||
345 | return; | ||
346 | #endif | ||
347 | |||
348 | start_port(); | ||
349 | |||
350 | #ifdef CONFIG_ETRAX_KGDB | ||
351 | /* kgdb needs to output debug info using the gdb protocol */ | ||
352 | putDebugString(buf, len); | ||
353 | return; | ||
354 | #endif | ||
355 | |||
356 | if (debug_write_function) | ||
357 | debug_write_function(co->index, buf, len); | ||
358 | else | ||
359 | console_write_direct(co, buf, len); | ||
360 | } | ||
361 | |||
362 | /* legacy function */ | ||
363 | |||
364 | void | ||
365 | console_print_etrax(const char *buf) | ||
366 | { | ||
367 | console_write(NULL, buf, strlen(buf)); | ||
368 | } | ||
369 | |||
370 | /* Use polling to get a single character FROM the debug port */ | ||
371 | |||
372 | int | ||
373 | getDebugChar(void) | ||
374 | { | ||
375 | unsigned long readval; | ||
376 | |||
377 | do { | ||
378 | readval = *port->read; | ||
379 | } while (!(readval & IO_MASK(R_SERIAL0_READ, data_avail))); | ||
380 | |||
381 | return (readval & IO_MASK(R_SERIAL0_READ, data_in)); | ||
382 | } | ||
383 | |||
384 | /* Use polling to put a single character to the debug port */ | ||
385 | |||
386 | void | ||
387 | putDebugChar(int val) | ||
388 | { | ||
389 | while (!(*port->read & IO_MASK(R_SERIAL0_READ, tr_ready))) | ||
390 | ; | ||
391 | *port->write = val; | ||
392 | } | ||
393 | |||
394 | /* Enable irq for receiving chars on the debug port, used by kgdb */ | ||
395 | |||
396 | void | ||
397 | enableDebugIRQ(void) | ||
398 | { | ||
399 | *R_IRQ_MASK1_SET = port->irq; | ||
400 | /* use R_VECT_MASK directly, since we really bypass Linux normal | ||
401 | * IRQ handling in kgdb anyway, we don't need to use enable_irq | ||
402 | */ | ||
403 | *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, serial, set); | ||
404 | |||
405 | *port->rec_ctrl = IO_STATE(R_SERIAL0_REC_CTRL, rec_enable, enable); | ||
406 | } | ||
407 | |||
408 | static struct tty_driver* | ||
409 | etrax_console_device(struct console* co, int *index) | ||
410 | { | ||
411 | return serial_driver; | ||
412 | } | ||
413 | |||
414 | static int __init | ||
415 | console_setup(struct console *co, char *options) | ||
416 | { | ||
417 | char* s; | ||
418 | |||
419 | if (options) { | ||
420 | port = &ports[co->index]; | ||
421 | port->baudrate = 115200; | ||
422 | port->parity = 'N'; | ||
423 | port->bits = 8; | ||
424 | port->baudrate = simple_strtoul(options, NULL, 10); | ||
425 | s = options; | ||
426 | while(*s >= '0' && *s <= '9') | ||
427 | s++; | ||
428 | if (*s) port->parity = *s++; | ||
429 | if (*s) port->bits = *s++ - '0'; | ||
430 | port->started = 0; | ||
431 | start_port(); | ||
432 | } | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static struct console sercons = { | ||
437 | name : "ttyS", | ||
438 | write: console_write, | ||
439 | read : NULL, | ||
440 | device : etrax_console_device, | ||
441 | unblank : NULL, | ||
442 | setup : console_setup, | ||
443 | flags : CON_PRINTBUFFER, | ||
444 | index : -1, | ||
445 | cflag : 0, | ||
446 | next : NULL | ||
447 | }; | ||
448 | static struct console sercons0 = { | ||
449 | name : "ttyS", | ||
450 | write: console_write, | ||
451 | read : NULL, | ||
452 | device : etrax_console_device, | ||
453 | unblank : NULL, | ||
454 | setup : console_setup, | ||
455 | flags : CON_PRINTBUFFER, | ||
456 | index : 0, | ||
457 | cflag : 0, | ||
458 | next : NULL | ||
459 | }; | ||
460 | |||
461 | static struct console sercons1 = { | ||
462 | name : "ttyS", | ||
463 | write: console_write, | ||
464 | read : NULL, | ||
465 | device : etrax_console_device, | ||
466 | unblank : NULL, | ||
467 | setup : console_setup, | ||
468 | flags : CON_PRINTBUFFER, | ||
469 | index : 1, | ||
470 | cflag : 0, | ||
471 | next : NULL | ||
472 | }; | ||
473 | static struct console sercons2 = { | ||
474 | name : "ttyS", | ||
475 | write: console_write, | ||
476 | read : NULL, | ||
477 | device : etrax_console_device, | ||
478 | unblank : NULL, | ||
479 | setup : console_setup, | ||
480 | flags : CON_PRINTBUFFER, | ||
481 | index : 2, | ||
482 | cflag : 0, | ||
483 | next : NULL | ||
484 | }; | ||
485 | static struct console sercons3 = { | ||
486 | name : "ttyS", | ||
487 | write: console_write, | ||
488 | read : NULL, | ||
489 | device : etrax_console_device, | ||
490 | unblank : NULL, | ||
491 | setup : console_setup, | ||
492 | flags : CON_PRINTBUFFER, | ||
493 | index : 3, | ||
494 | cflag : 0, | ||
495 | next : NULL | ||
496 | }; | ||
497 | /* | ||
498 | * Register console (for printk's etc) | ||
499 | */ | ||
500 | |||
501 | int __init | ||
502 | init_etrax_debug(void) | ||
503 | { | ||
504 | static int first = 1; | ||
505 | |||
506 | if (!first) { | ||
507 | if (!port) { | ||
508 | register_console(&sercons0); | ||
509 | register_console(&sercons1); | ||
510 | register_console(&sercons2); | ||
511 | register_console(&sercons3); | ||
512 | unregister_console(&sercons); | ||
513 | } | ||
514 | return 0; | ||
515 | } | ||
516 | first = 0; | ||
517 | if (port) | ||
518 | register_console(&sercons); | ||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | int __init | ||
523 | init_console(void) | ||
524 | { | ||
525 | serial_driver = alloc_tty_driver(1); | ||
526 | if (!serial_driver) | ||
527 | return -ENOMEM; | ||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | __initcall(init_etrax_debug); | ||
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S new file mode 100644 index 000000000000..1bc44f481c34 --- /dev/null +++ b/arch/cris/arch-v10/kernel/entry.S | |||
@@ -0,0 +1,1132 @@ | |||
1 | /* $Id: entry.S,v 1.23 2004/10/19 13:07:37 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/entry.S | ||
4 | * | ||
5 | * Copyright (C) 2000, 2001, 2002 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * $Log: entry.S,v $ | ||
10 | * Revision 1.23 2004/10/19 13:07:37 starvik | ||
11 | * Merge of Linux 2.6.9 | ||
12 | * | ||
13 | * Revision 1.22 2004/06/21 10:29:55 starvik | ||
14 | * Merge of Linux 2.6.7 | ||
15 | * | ||
16 | * Revision 1.21 2004/06/09 05:30:27 starvik | ||
17 | * Clean up multiple interrupt handling. | ||
18 | * Prevent interrupts from interrupting each other. | ||
19 | * Handle all active interrupts. | ||
20 | * | ||
21 | * Revision 1.20 2004/06/08 08:55:32 starvik | ||
22 | * Removed unused code | ||
23 | * | ||
24 | * Revision 1.19 2004/06/04 11:56:15 starvik | ||
25 | * Implemented page table lookup for refills in assembler for improved performance. | ||
26 | * | ||
27 | * Revision 1.18 2004/05/11 12:28:25 starvik | ||
28 | * Merge of Linux 2.6.6 | ||
29 | * | ||
30 | * Revision 1.17 2003/09/11 07:29:49 starvik | ||
31 | * Merge of Linux 2.6.0-test5 | ||
32 | * | ||
33 | * Revision 1.16 2003/07/04 08:27:41 starvik | ||
34 | * Merge of Linux 2.5.74 | ||
35 | * | ||
36 | * Revision 1.15 2003/04/09 07:32:55 starvik | ||
37 | * resume should return task_struct, not thread_info | ||
38 | * | ||
39 | * Revision 1.14 2003/04/09 05:20:44 starvik | ||
40 | * Merge of Linux 2.5.67 | ||
41 | * | ||
42 | * Revision 1.13 2002/12/11 15:42:02 starvik | ||
43 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c | ||
44 | * | ||
45 | * Revision 1.12 2002/12/10 09:00:10 starvik | ||
46 | * Merge of Linux 2.5.51 | ||
47 | * | ||
48 | * Revision 1.11 2002/12/05 07:53:10 starvik | ||
49 | * Corrected constants used with btstq | ||
50 | * | ||
51 | * Revision 1.10 2002/11/27 08:45:10 starvik | ||
52 | * pid is in task_struct, not thread_info | ||
53 | * | ||
54 | * Revision 1.9 2002/11/26 09:52:05 starvik | ||
55 | * Added preemptive kernel scheduling (if CONFIG_PREEMPT) | ||
56 | * | ||
57 | * Revision 1.8 2002/11/20 11:56:11 starvik | ||
58 | * Merge of Linux 2.5.48 | ||
59 | * | ||
60 | * Revision 1.7 2002/11/18 13:02:42 starvik | ||
61 | * Added fourth parameter to do_notify_resume | ||
62 | * Minor cleanup | ||
63 | * | ||
64 | * Revision 1.6 2002/11/11 10:37:50 starvik | ||
65 | * Use new asm-offset defines | ||
66 | * Modified for new location of current->work etc | ||
67 | * Removed SYMBOL_NAME from syscalls | ||
68 | * Added some new syscalls | ||
69 | * | ||
70 | * Revision 1.5 2002/11/05 06:45:11 starvik | ||
71 | * Merge of Linux 2.5.45 | ||
72 | * | ||
73 | * Revision 1.4 2002/02/05 15:41:31 bjornw | ||
74 | * Rewritten to conform better to current 2.5 code (similar to arch/i386) | ||
75 | * | ||
76 | * Revision 1.3 2002/01/21 15:22:20 bjornw | ||
77 | * NICE_DOGGY fix from 2.4 arch/cris | ||
78 | * | ||
79 | * Revision 1.37 2001/12/07 17:03:55 bjornw | ||
80 | * Call a c-hook called watchdog_bite_hook instead of show_registers directly | ||
81 | * | ||
82 | * Revision 1.36 2001/11/22 13:36:36 bjornw | ||
83 | * * In ret_from_intr, check regs->dccr for usermode reentrance instead of | ||
84 | * DCCR explicitely (because the latter might not reflect current reality) | ||
85 | * * In mmu_bus_fault, set $r9 _after_ calling the C-code instead of before | ||
86 | * since $r9 is call-clobbered and is potentially needed afterwards | ||
87 | * | ||
88 | * Revision 1.35 2001/10/30 17:10:15 bjornw | ||
89 | * Add some syscalls | ||
90 | * | ||
91 | * Revision 1.34 2001/10/01 14:45:03 bjornw | ||
92 | * Removed underscores and added register prefixes | ||
93 | * | ||
94 | * Revision 1.33 2001/08/21 13:48:01 jonashg | ||
95 | * Added fix by HP to avoid oops when doing a hard_reset_now. | ||
96 | * | ||
97 | * Revision 1.32 2001/08/14 04:32:02 hp | ||
98 | * In _resume, add comment why R9 is saved; don't sound like it's call-saved. | ||
99 | * | ||
100 | * Revision 1.31 2001/07/25 16:07:42 bjornw | ||
101 | * softirq_active/mask -> softirq_pending only | ||
102 | * | ||
103 | * Revision 1.30 2001/07/05 01:03:32 hp | ||
104 | * - include asm/errno.h to get ENOSYS. | ||
105 | * - Use ENOSYS, not local constant LENOSYS; tweak comments. | ||
106 | * - Explain why .include, not #include is used. | ||
107 | * - Make oops-register-dump if watchdog bits and it's not expected. | ||
108 | * - Don't jsr, use jump _hard_reset_now, and skip spurious nop. | ||
109 | * - Use correct section attribute for section .rodata. | ||
110 | * - Adjust sys_ni_syscall fill number. | ||
111 | * | ||
112 | * Revision 1.29 2001/06/25 14:07:00 hp | ||
113 | * Fix review comment. | ||
114 | * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of | ||
115 | * magic numbers. Add comment that -traditional must not be used. | ||
116 | * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. | ||
117 | * Correct and update comment. | ||
118 | * * Makefile (.S.o): Don't use -traditional. Add comment why the | ||
119 | * toplevel rule can't be used (now that there's a reason). | ||
120 | * | ||
121 | * Revision 1.28 2001/06/21 02:00:40 hp | ||
122 | * * entry.S: Include asm/unistd.h. | ||
123 | * (_sys_call_table): Use section .rodata, not .data. | ||
124 | * (_kernel_thread): Move from... | ||
125 | * * process.c: ... here. | ||
126 | * * entryoffsets.c (VAL): Break out from... | ||
127 | * (OF): Use VAL. | ||
128 | * (LCLONE_VM): New asmified value from CLONE_VM. | ||
129 | * | ||
130 | * Revision 1.27 2001/05/29 11:25:27 markusl | ||
131 | * In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop... | ||
132 | * | ||
133 | * Revision 1.26 2001/05/15 15:46:03 bjornw | ||
134 | * Include config.h now that we use some CONFIG_ options | ||
135 | * | ||
136 | * Revision 1.25 2001/05/15 05:38:47 hp | ||
137 | * Tweaked code in _ret_from_sys_call | ||
138 | * | ||
139 | * Revision 1.24 2001/05/15 05:27:49 hp | ||
140 | * Save r9 in r1 over function call rather than on stack. | ||
141 | * | ||
142 | * Revision 1.23 2001/05/15 05:10:00 hp | ||
143 | * Generate entry.S structure offsets from C | ||
144 | * | ||
145 | * Revision 1.22 2001/04/17 13:58:39 orjanf | ||
146 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
147 | * | ||
148 | * Revision 1.21 2001/04/17 11:33:29 orjanf | ||
149 | * Updated according to review: | ||
150 | * * Included asm/sv_addr_ag.h to get macro for internal register. | ||
151 | * * Corrected comment regarding system call argument passing. | ||
152 | * * Removed comment about instruction being in a delay slot. | ||
153 | * * Added comment about SYMBOL_NAME macro. | ||
154 | * | ||
155 | * Revision 1.20 2001/04/12 08:51:07 hp | ||
156 | * - Add entry for sys_fcntl64. In fact copy last piece from i386 including ... | ||
157 | * - .rept to fill table to safe state with sys_ni_syscall. | ||
158 | * | ||
159 | * Revision 1.19 2001/04/04 09:43:32 orjanf | ||
160 | * * Moved do_sigtrap from traps.c to entry.S. | ||
161 | * * LTASK_PID need not be global anymore. | ||
162 | * | ||
163 | * Revision 1.18 2001/03/26 09:25:02 markusl | ||
164 | * Updated after review, should now handle USB interrupts correctly. | ||
165 | * | ||
166 | * Revision 1.17 2001/03/21 16:12:55 bjornw | ||
167 | * * Always make room for the cpu status record in the frame, in order to | ||
168 | * use the same framelength and layout for both mmu busfaults and normal | ||
169 | * irqs. No need to check for the explicit CRIS_FRAME_FIXUP type anymore. | ||
170 | * * Fixed bug with using addq for popping the stack in the epilogue - it | ||
171 | * destroyed the flag register. Use instructions that don't affect the | ||
172 | * flag register instead. | ||
173 | * * Removed write to R_PORT_PA_DATA during spurious_interrupt | ||
174 | * | ||
175 | * Revision 1.16 2001/03/20 19:43:02 bjornw | ||
176 | * * Get rid of esp0 setting | ||
177 | * * Give a 7th argument to a systemcall - the stackframe | ||
178 | * | ||
179 | * Revision 1.15 2001/03/05 13:14:30 bjornw | ||
180 | * Spelling fix | ||
181 | * | ||
182 | * Revision 1.14 2001/02/23 08:36:36 perf | ||
183 | * New ABI; syscallnr=r9, arg5=mof, arg6=srp. | ||
184 | * Corrected tracesys call check. | ||
185 | * | ||
186 | * Revision 1.13 2001/02/15 08:40:55 perf | ||
187 | * H-P by way of perf; | ||
188 | * - (_system_call): Don't read system call function address into r1. | ||
189 | * - (RBFExit): There is no such thing as a null pop. Adjust sp by addq. | ||
190 | * - (_system_call): Don't use r10 and don't save and restore it. | ||
191 | * - (THREAD_ESP0): New constant. | ||
192 | * - (_system_call): Inline set_esp0. | ||
193 | * | ||
194 | * Revision 1.12 2001/01/31 17:56:25 orjanf | ||
195 | * Added definition of LTASK_PID and made it global. | ||
196 | * | ||
197 | * Revision 1.11 2001/01/10 21:13:29 bjornw | ||
198 | * SYMBOL_NAME is defined incorrectly for the compiler options we currently use | ||
199 | * | ||
200 | * Revision 1.10 2000/12/18 23:47:56 bjornw | ||
201 | * * Added syscall trace support (ptrace), completely untested of course | ||
202 | * * Removed redundant check for NULL entries in syscall_table | ||
203 | * | ||
204 | * Revision 1.9 2000/11/21 16:40:51 bjornw | ||
205 | * * New frame type used when an SBFS frame needs to be popped without | ||
206 | * actually restarting the instruction | ||
207 | * * Enable interrupts in signal_return (they did so in x86, I hope it's a good | ||
208 | * idea) | ||
209 | * | ||
210 | * Revision 1.8 2000/11/17 16:53:35 bjornw | ||
211 | * Added detection of frame-type in Rexit, so that mmu_bus_fault can | ||
212 | * use ret_from_intr in the return-path to check for signals (like SEGV) | ||
213 | * and other foul things that might have occurred during the fault. | ||
214 | * | ||
215 | * Revision 1.7 2000/10/06 15:04:28 bjornw | ||
216 | * Include mof in register savings | ||
217 | * | ||
218 | * Revision 1.6 2000/09/12 16:02:44 bjornw | ||
219 | * Linux-2.4.0-test7 derived updates | ||
220 | * | ||
221 | * Revision 1.5 2000/08/17 15:35:15 bjornw | ||
222 | * 2.4.0-test6 changed local_irq_count and friends API | ||
223 | * | ||
224 | * Revision 1.4 2000/08/02 13:59:30 bjornw | ||
225 | * Removed olduname and uname from the syscall list | ||
226 | * | ||
227 | * Revision 1.3 2000/07/31 13:32:58 bjornw | ||
228 | * * Export ret_from_intr | ||
229 | * * _resume updated (prev/last tjohejsan) | ||
230 | * * timer_interrupt obsolete | ||
231 | * * SIGSEGV detection in mmu_bus_fault temporarily disabled | ||
232 | * | ||
233 | * | ||
234 | */ | ||
235 | |||
236 | /* | ||
237 | * entry.S contains the system-call and fault low-level handling routines. | ||
238 | * | ||
239 | * NOTE: This code handles signal-recognition, which happens every time | ||
240 | * after a timer-interrupt and after each system call. | ||
241 | * | ||
242 | * Stack layout in 'ret_from_system_call': | ||
243 | * ptrace needs to have all regs on the stack. | ||
244 | * if the order here is changed, it needs to be | ||
245 | * updated in fork.c:copy_process, signal.c:do_signal, | ||
246 | * ptrace.c and ptrace.h | ||
247 | * | ||
248 | */ | ||
249 | |||
250 | #include <linux/config.h> | ||
251 | #include <linux/linkage.h> | ||
252 | #include <linux/sys.h> | ||
253 | #include <asm/unistd.h> | ||
254 | #include <asm/arch/sv_addr_ag.h> | ||
255 | #include <asm/errno.h> | ||
256 | #include <asm/thread_info.h> | ||
257 | #include <asm/arch/offset.h> | ||
258 | #include <asm/page.h> | ||
259 | #include <asm/pgtable.h> | ||
260 | |||
261 | ;; functions exported from this file | ||
262 | |||
263 | .globl system_call | ||
264 | .globl ret_from_intr | ||
265 | .globl ret_from_fork | ||
266 | .globl resume | ||
267 | .globl multiple_interrupt | ||
268 | .globl hwbreakpoint | ||
269 | .globl IRQ1_interrupt | ||
270 | .globl spurious_interrupt | ||
271 | .globl hw_bp_trigs | ||
272 | .globl mmu_bus_fault | ||
273 | .globl do_sigtrap | ||
274 | .globl gdb_handle_breakpoint | ||
275 | .globl sys_call_table | ||
276 | |||
277 | ;; below are various parts of system_call which are not in the fast-path | ||
278 | |||
279 | #ifdef CONFIG_PREEMPT | ||
280 | ; Check if preemptive kernel scheduling should be done | ||
281 | _resume_kernel: | ||
282 | ; Load current task struct | ||
283 | movs.w -8192, $r0 ; THREAD_SIZE = 8192 | ||
284 | and.d $sp, $r0 | ||
285 | move.d [$r0+TI_preempt_count], $r10 ; Preemption disabled? | ||
286 | bne _Rexit | ||
287 | nop | ||
288 | _need_resched: | ||
289 | move.d [$r0+TI_flags], $r10 | ||
290 | btstq TIF_NEED_RESCHED, $r10 ; Check if need_resched is set | ||
291 | bpl _Rexit | ||
292 | nop | ||
293 | ; Ok, lets's do some preemptive kernel scheduling | ||
294 | move.d PREEMPT_ACTIVE, $r10 | ||
295 | move.d $r10, [$r0+TI_preempt_count] ; Mark as active | ||
296 | ei | ||
297 | jsr schedule | ||
298 | clear.d [$r0+TI_preempt_count] ; Mark as inactive | ||
299 | di | ||
300 | ; Load new task struct | ||
301 | movs.w -8192, $r0 ; THREAD_SIZE = 8192 | ||
302 | and.d $sp, $r0 | ||
303 | ; One more time (with new task) | ||
304 | ba _need_resched | ||
305 | nop | ||
306 | #else | ||
307 | #define _resume_kernel _Rexit | ||
308 | #endif | ||
309 | |||
310 | ; Called at exit from fork. schedule_tail must be called to drop | ||
311 | ; spinlock if CONFIG_PREEMPT | ||
312 | ret_from_fork: | ||
313 | jsr schedule_tail | ||
314 | ba ret_from_sys_call | ||
315 | nop | ||
316 | |||
317 | ret_from_intr: | ||
318 | ;; check for resched if preemptive kernel or if we're going back to user-mode | ||
319 | ;; this test matches the user_regs(regs) macro | ||
320 | ;; we cannot simply test $dccr, because that does not necessarily | ||
321 | ;; reflect what mode we'll return into. | ||
322 | |||
323 | move.d [$sp + PT_dccr], $r0; regs->dccr | ||
324 | btstq 8, $r0 ; U-flag | ||
325 | bpl _resume_kernel | ||
326 | ; Note that di below is in delay slot | ||
327 | |||
328 | _resume_userspace: | ||
329 | di ; so need_resched and sigpending don't change | ||
330 | |||
331 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
332 | and.d $sp, $r0 | ||
333 | |||
334 | move.d [$r0+TI_flags], $r10 ; current->work | ||
335 | and.d _TIF_WORK_MASK, $r10 ; is there any work to be done on return | ||
336 | bne _work_pending | ||
337 | nop | ||
338 | ba _Rexit | ||
339 | nop | ||
340 | |||
341 | ;; The system_call is called by a BREAK instruction, which works like | ||
342 | ;; an interrupt call but it stores the return PC in BRP instead of IRP. | ||
343 | ;; Since we dont really want to have two epilogues (one for system calls | ||
344 | ;; and one for interrupts) we push the contents of BRP instead of IRP in the | ||
345 | ;; system call prologue, to make it look like an ordinary interrupt on the | ||
346 | ;; stackframe. | ||
347 | ;; | ||
348 | ;; Since we can't have system calls inside interrupts, it should not matter | ||
349 | ;; that we don't stack IRP. | ||
350 | ;; | ||
351 | ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp | ||
352 | ;; | ||
353 | ;; This function looks on the _surface_ like spaghetti programming, but it's | ||
354 | ;; really designed so that the fast-path does not force cache-loading of non-used | ||
355 | ;; instructions. Only the non-common cases cause the outlined code to run.. | ||
356 | |||
357 | system_call: | ||
358 | ;; stack-frame similar to the irq heads, which is reversed in ret_from_sys_call | ||
359 | move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
360 | push $srp | ||
361 | push $dccr | ||
362 | push $mof | ||
363 | subq 14*4, $sp ; make room for r0-r13 | ||
364 | movem $r13, [$sp] ; push r0-r13 | ||
365 | push $r10 ; push orig_r10 | ||
366 | clear.d [$sp=$sp-4] ; frametype == 0, normal stackframe | ||
367 | |||
368 | movs.w -ENOSYS, $r0 | ||
369 | move.d $r0, [$sp+PT_r10] ; put the default return value in r10 in the frame | ||
370 | |||
371 | ;; check if this process is syscall-traced | ||
372 | |||
373 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
374 | and.d $sp, $r0 | ||
375 | |||
376 | move.d [$r0+TI_flags], $r0 | ||
377 | btstq TIF_SYSCALL_TRACE, $r0 | ||
378 | bmi _syscall_trace_entry | ||
379 | nop | ||
380 | |||
381 | _syscall_traced: | ||
382 | |||
383 | ;; check for sanity in the requested syscall number | ||
384 | |||
385 | cmpu.w NR_syscalls, $r9 | ||
386 | bcc ret_from_sys_call | ||
387 | lslq 2, $r9 ; multiply by 4, in the delay slot | ||
388 | |||
389 | ;; as a bonus 7th parameter, we give the location on the stack | ||
390 | ;; of the register structure itself. some syscalls need this. | ||
391 | |||
392 | push $sp | ||
393 | |||
394 | ;; the parameter carrying registers r10, r11, r12 and 13 are intact. | ||
395 | ;; the fifth and sixth parameters (if any) was in mof and srp | ||
396 | ;; respectively, and we need to put them on the stack. | ||
397 | |||
398 | push $srp | ||
399 | push $mof | ||
400 | |||
401 | jsr [$r9+sys_call_table] ; actually do the system call | ||
402 | addq 3*4, $sp ; pop the mof, srp and regs parameters | ||
403 | move.d $r10, [$sp+PT_r10] ; save the return value | ||
404 | |||
405 | moveq 1, $r9 ; "parameter" to ret_from_sys_call to show it was a sys call | ||
406 | |||
407 | ;; fall through into ret_from_sys_call to return | ||
408 | |||
409 | ret_from_sys_call: | ||
410 | ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq | ||
411 | |||
412 | ;; get the current task-struct pointer (see top for defs) | ||
413 | |||
414 | movs.w -8192, $r0 ; THREAD_SIZE == 8192 | ||
415 | and.d $sp, $r0 | ||
416 | |||
417 | di ; make sure need_resched and sigpending don't change | ||
418 | move.d [$r0+TI_flags],$r1 | ||
419 | and.d _TIF_ALLWORK_MASK, $r1 | ||
420 | bne _syscall_exit_work | ||
421 | nop | ||
422 | |||
423 | _Rexit: | ||
424 | ;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h | ||
425 | pop $r10 ; frametype | ||
426 | bne _RBFexit ; was not CRIS_FRAME_NORMAL, handle otherwise | ||
427 | addq 4, $sp ; skip orig_r10, in delayslot | ||
428 | movem [$sp+], $r13 ; registers r0-r13 | ||
429 | pop $mof ; multiply overflow register | ||
430 | pop $dccr ; condition codes | ||
431 | pop $srp ; subroutine return pointer | ||
432 | ;; now we have a 4-word SBFS frame which we do not want to restore | ||
433 | ;; using RBF since it was not stacked with SBFS. instead we would like to | ||
434 | ;; just get the PC value to restart it with, and skip the rest of | ||
435 | ;; the frame. | ||
436 | ;; Also notice that it's important to use instructions here that | ||
437 | ;; keep the interrupts disabled (since we've already popped DCCR) | ||
438 | move [$sp=$sp+16], $p8; pop the SBFS frame from the sp | ||
439 | jmpu [$sp-16] ; return through the irp field in the sbfs frame | ||
440 | |||
441 | _RBFexit: | ||
442 | movem [$sp+], $r13 ; registers r0-r13, in delay slot | ||
443 | pop $mof ; multiply overflow register | ||
444 | pop $dccr ; condition codes | ||
445 | pop $srp ; subroutine return pointer | ||
446 | rbf [$sp+] ; return by popping the CPU status | ||
447 | |||
448 | ;; We get here after doing a syscall if extra work might need to be done | ||
449 | ;; perform syscall exit tracing if needed | ||
450 | |||
451 | _syscall_exit_work: | ||
452 | ;; $r0 contains current at this point and irq's are disabled | ||
453 | |||
454 | move.d [$r0+TI_flags], $r1 | ||
455 | btstq TIF_SYSCALL_TRACE, $r1 | ||
456 | bpl _work_pending | ||
457 | nop | ||
458 | |||
459 | ei | ||
460 | |||
461 | move.d $r9, $r1 ; preserve r9 | ||
462 | jsr do_syscall_trace | ||
463 | move.d $r1, $r9 | ||
464 | |||
465 | ba _resume_userspace | ||
466 | nop | ||
467 | |||
468 | _work_pending: | ||
469 | move.d [$r0+TI_flags], $r1 | ||
470 | btstq TIF_NEED_RESCHED, $r1 | ||
471 | bpl _work_notifysig ; was neither trace nor sched, must be signal/notify | ||
472 | nop | ||
473 | |||
474 | _work_resched: | ||
475 | move.d $r9, $r1 ; preserve r9 | ||
476 | jsr schedule | ||
477 | move.d $r1, $r9 | ||
478 | di | ||
479 | |||
480 | move.d [$r0+TI_flags], $r1 | ||
481 | and.d _TIF_WORK_MASK, $r1; ignore the syscall trace counter | ||
482 | beq _Rexit | ||
483 | nop | ||
484 | btstq TIF_NEED_RESCHED, $r1 | ||
485 | bmi _work_resched ; current->work.need_resched | ||
486 | nop | ||
487 | |||
488 | _work_notifysig: | ||
489 | ;; deal with pending signals and notify-resume requests | ||
490 | |||
491 | move.d $r9, $r10 ; do_notify_resume syscall/irq param | ||
492 | moveq 0, $r11 ; oldset param - 0 in this case | ||
493 | move.d $sp, $r12 ; the regs param | ||
494 | move.d $r1, $r13 ; the thread_info_flags parameter | ||
495 | jsr do_notify_resume | ||
496 | |||
497 | ba _Rexit | ||
498 | nop | ||
499 | |||
500 | ;; We get here as a sidetrack when we've entered a syscall with the | ||
501 | ;; trace-bit set. We need to call do_syscall_trace and then continue | ||
502 | ;; with the call. | ||
503 | |||
504 | _syscall_trace_entry: | ||
505 | ;; PT_r10 in the frame contains -ENOSYS as required, at this point | ||
506 | |||
507 | jsr do_syscall_trace | ||
508 | |||
509 | ;; now re-enter the syscall code to do the syscall itself | ||
510 | ;; we need to restore $r9 here to contain the wanted syscall, and | ||
511 | ;; the other parameter-bearing registers | ||
512 | |||
513 | move.d [$sp+PT_r9], $r9 | ||
514 | move.d [$sp+PT_orig_r10], $r10 ; PT_r10 is already filled with -ENOSYS. | ||
515 | move.d [$sp+PT_r11], $r11 | ||
516 | move.d [$sp+PT_r12], $r12 | ||
517 | move.d [$sp+PT_r13], $r13 | ||
518 | move [$sp+PT_mof], $mof | ||
519 | move [$sp+PT_srp], $srp | ||
520 | |||
521 | ba _syscall_traced | ||
522 | nop | ||
523 | |||
524 | ;; resume performs the actual task-switching, by switching stack pointers | ||
525 | ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct | ||
526 | ;; returns old current in r10 | ||
527 | ;; | ||
528 | ;; TODO: see the i386 version. The switch_to which calls resume in our version | ||
529 | ;; could really be an inline asm of this. | ||
530 | |||
531 | resume: | ||
532 | push $srp ; we keep the old/new PC on the stack | ||
533 | add.d $r12, $r10 ; r10 = current tasks tss | ||
534 | move $dccr, [$r10+THREAD_dccr]; save irq enable state | ||
535 | di | ||
536 | |||
537 | move $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer | ||
538 | |||
539 | ;; See copy_thread for the reason why register R9 is saved. | ||
540 | subq 10*4, $sp | ||
541 | movem $r9, [$sp] ; save non-scratch registers and R9. | ||
542 | |||
543 | move.d $sp, [$r10+THREAD_ksp] ; save the kernel stack pointer for the old task | ||
544 | move.d $sp, $r10 ; return last running task in r10 | ||
545 | and.d -8192, $r10 ; get thread_info from stackpointer | ||
546 | move.d [$r10+TI_task], $r10 ; get task | ||
547 | add.d $r12, $r11 ; find the new tasks tss | ||
548 | move.d [$r11+THREAD_ksp], $sp ; switch into the new stackframe by restoring kernel sp | ||
549 | |||
550 | movem [$sp+], $r9 ; restore non-scratch registers and R9. | ||
551 | |||
552 | move [$r11+THREAD_usp], $usp ; restore user-mode stackpointer | ||
553 | |||
554 | move [$r11+THREAD_dccr], $dccr ; restore irq enable status | ||
555 | jump [$sp+] ; restore PC | ||
556 | |||
557 | ;; This is the MMU bus fault handler. | ||
558 | ;; It needs to stack the CPU status and overall is different | ||
559 | ;; from the other interrupt handlers. | ||
560 | |||
561 | mmu_bus_fault: | ||
562 | ;; For refills we try to do a quick page table lookup. If it is | ||
563 | ;; a real fault we let the mm subsystem handle it. | ||
564 | |||
565 | ;; the first longword in the sbfs frame was the interrupted PC | ||
566 | ;; which fits nicely with the "IRP" slot in pt_regs normally used to | ||
567 | ;; contain the return address. used by Oops to print kernel errors. | ||
568 | sbfs [$sp=$sp-16] ; push the internal CPU status | ||
569 | push $dccr | ||
570 | di | ||
571 | subq 2*4, $sp | ||
572 | movem $r1, [$sp] | ||
573 | move.d [R_MMU_CAUSE], $r1 | ||
574 | ;; ETRAX 100LX TR89 bugfix: if the second half of an unaligned | ||
575 | ;; write causes a MMU-fault, it will not be restarted correctly. | ||
576 | ;; This could happen if a write crosses a page-boundary and the | ||
577 | ;; second page is not yet COW'ed or even loaded. The workaround | ||
578 | ;; is to clear the unaligned bit in the CPU status record, so | ||
579 | ;; that the CPU will rerun both the first and second halves of | ||
580 | ;; the instruction. This will not have any sideeffects unless | ||
581 | ;; the first half goes to any device or memory that can't be | ||
582 | ;; written twice, and which is mapped through the MMU. | ||
583 | ;; | ||
584 | ;; We only need to do this for writes. | ||
585 | btstq 8, $r1 ; Write access? | ||
586 | bpl 1f | ||
587 | nop | ||
588 | move.d [$sp+16], $r0 ; Clear unaligned bit in csrinstr | ||
589 | and.d ~(1<<5), $r0 | ||
590 | move.d $r0, [$sp+16] | ||
591 | 1: btstq 12, $r1 ; Refill? | ||
592 | bpl 2f | ||
593 | lsrq PMD_SHIFT, $r1 ; Get PMD index into PGD (bit 24-31) | ||
594 | move.d [current_pgd], $r0 ; PGD for the current process | ||
595 | move.d [$r0+$r1.d], $r0 ; Get PMD | ||
596 | beq 2f | ||
597 | nop | ||
598 | and.w PAGE_MASK, $r0 ; Remove PMD flags | ||
599 | move.d [R_MMU_CAUSE], $r1 | ||
600 | lsrq PAGE_SHIFT, $r1 | ||
601 | and.d 0x7ff, $r1 ; Get PTE index into PMD (bit 13-24) | ||
602 | move.d [$r0+$r1.d], $r1 ; Get PTE | ||
603 | beq 2f | ||
604 | nop | ||
605 | ;; Store in TLB | ||
606 | move.d $r1, [R_TLB_LO] | ||
607 | ;; Return | ||
608 | movem [$sp+], $r1 | ||
609 | pop $dccr | ||
610 | rbf [$sp+] ; return by popping the CPU status | ||
611 | |||
612 | 2: ; PMD or PTE missing, let the mm subsystem fix it up. | ||
613 | movem [$sp+], $r1 | ||
614 | pop $dccr | ||
615 | |||
616 | ; Ok, not that easy, pass it on to the mm subsystem | ||
617 | ; The MMU status record is now on the stack | ||
618 | push $srp ; make a stackframe similar to pt_regs | ||
619 | push $dccr | ||
620 | push $mof | ||
621 | di | ||
622 | subq 14*4, $sp | ||
623 | movem $r13, [$sp] | ||
624 | push $r10 ; dummy orig_r10 | ||
625 | moveq 1, $r10 | ||
626 | push $r10 ; frametype == 1, BUSFAULT frame type | ||
627 | |||
628 | move.d $sp, $r10 ; pt_regs argument to handle_mmu_bus_fault | ||
629 | |||
630 | jsr handle_mmu_bus_fault ; in arch/cris/arch-v10/mm/fault.c | ||
631 | |||
632 | ;; now we need to return through the normal path, we cannot just | ||
633 | ;; do the RBFexit since we might have killed off the running | ||
634 | ;; process due to a SEGV, scheduled due to a page blocking or | ||
635 | ;; whatever. | ||
636 | |||
637 | moveq 0, $r9 ; busfault is equivalent to an irq | ||
638 | |||
639 | ba ret_from_intr | ||
640 | nop | ||
641 | |||
642 | ;; special handlers for breakpoint and NMI | ||
643 | hwbreakpoint: | ||
644 | push $dccr | ||
645 | di | ||
646 | push $r10 | ||
647 | push $r11 | ||
648 | move.d [hw_bp_trig_ptr],$r10 | ||
649 | move $brp,$r11 | ||
650 | move.d $r11,[$r10+] | ||
651 | move.d $r10,[hw_bp_trig_ptr] | ||
652 | 1: pop $r11 | ||
653 | pop $r10 | ||
654 | pop $dccr | ||
655 | retb | ||
656 | nop | ||
657 | |||
658 | IRQ1_interrupt: | ||
659 | |||
660 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
661 | ;; If we receive a watchdog interrupt while it is not expected, then set | ||
662 | ;; up a canonical frame and dump register contents before dying. | ||
663 | |||
664 | ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! | ||
665 | move $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
666 | push $srp | ||
667 | push $dccr | ||
668 | push $mof | ||
669 | di | ||
670 | subq 14*4, $sp | ||
671 | movem $r13, [$sp] | ||
672 | push $r10 ; push orig_r10 | ||
673 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | ||
674 | |||
675 | ;; We don't check that we actually were bit by the watchdog as opposed to | ||
676 | ;; an external NMI, since there is currently no handler for external NMI. | ||
677 | |||
678 | ;; Check if we're waiting for reset to happen, as signalled by | ||
679 | ;; hard_reset_now setting cause_of_death to a magic value. If so, just | ||
680 | ;; get stuck until reset happens. | ||
681 | .comm cause_of_death, 4 ;; Don't declare this anywhere. | ||
682 | move.d [cause_of_death], $r10 | ||
683 | cmp.d 0xbedead, $r10 | ||
684 | _killed_by_death: | ||
685 | beq _killed_by_death | ||
686 | nop | ||
687 | |||
688 | ;; We'll see this in ksymoops dumps. | ||
689 | Watchdog_bite: | ||
690 | |||
691 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
692 | ;; We just restart the watchdog here to be sure we dont get | ||
693 | ;; hit while printing the watchdogmsg below | ||
694 | ;; This restart is compatible with the rest of the C-code, so | ||
695 | ;; the C-code can keep restarting the watchdog after this point. | ||
696 | ;; The non-NICE_DOGGY code below though, disables the possibility | ||
697 | ;; to restart since it changes the watchdog key, to avoid any | ||
698 | ;; buggy loops etc. keeping the watchdog alive after this. | ||
699 | jsr reset_watchdog | ||
700 | #else | ||
701 | |||
702 | ;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have | ||
703 | ;; time for an oops-dump over a 115k2 serial wire. Another 100ms should do. | ||
704 | |||
705 | ;; Change the watchdog key to an arbitrary 3-bit value and restart the | ||
706 | ;; watchdog. | ||
707 | #define WD_INIT 2 | ||
708 | moveq IO_FIELD (R_WATCHDOG, key, WD_INIT), $r10 | ||
709 | move.d R_WATCHDOG, $r11 | ||
710 | |||
711 | move.d $r10, [$r11] | ||
712 | moveq IO_FIELD (R_WATCHDOG, key, \ | ||
713 | IO_EXTRACT (R_WATCHDOG, key, \ | ||
714 | IO_MASK (R_WATCHDOG, key)) \ | ||
715 | ^ WD_INIT) \ | ||
716 | | IO_STATE (R_WATCHDOG, enable, start), $r10 | ||
717 | move.d $r10, [$r11] | ||
718 | |||
719 | #endif | ||
720 | |||
721 | ;; Note that we don't do "setf m" here (or after two necessary NOPs), | ||
722 | ;; since *not* doing that saves us from re-entrancy checks. We don't want | ||
723 | ;; to get here again due to possible subsequent NMIs; we want the watchdog | ||
724 | ;; to reset us. | ||
725 | |||
726 | move.d _watchdogmsg,$r10 | ||
727 | jsr printk | ||
728 | |||
729 | move.d $sp, $r10 | ||
730 | jsr watchdog_bite_hook | ||
731 | |||
732 | ;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps | ||
733 | ;; rather than "spurious_interrupt". | ||
734 | nop | ||
735 | ;; At this point we drop down into spurious_interrupt, which will do a | ||
736 | ;; hard reset. | ||
737 | |||
738 | .section .rodata,"a" | ||
739 | _watchdogmsg: | ||
740 | .ascii "Oops: bitten by watchdog\n\0" | ||
741 | .previous | ||
742 | |||
743 | #endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */ | ||
744 | |||
745 | spurious_interrupt: | ||
746 | di | ||
747 | jump hard_reset_now | ||
748 | |||
749 | ;; this handles the case when multiple interrupts arrive at the same time | ||
750 | ;; we jump to the first set interrupt bit in a priority fashion | ||
751 | ;; the hardware will call the unserved interrupts after the handler finishes | ||
752 | |||
753 | multiple_interrupt: | ||
754 | ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! | ||
755 | move $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame | ||
756 | push $srp | ||
757 | push $dccr | ||
758 | push $mof | ||
759 | di | ||
760 | subq 14*4, $sp | ||
761 | movem $r13, [$sp] | ||
762 | push $r10 ; push orig_r10 | ||
763 | clear.d [$sp=$sp-4] ; frametype == 0, normal frame | ||
764 | |||
765 | moveq 2, $r2 ; first bit we care about is the timer0 irq | ||
766 | move.d [R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq | ||
767 | move.d $r0, [R_VECT_MASK_CLR] ; Block all active IRQs | ||
768 | 1: | ||
769 | btst $r2, $r0 ; check for the irq given by bit r2 | ||
770 | bpl 2f | ||
771 | move.d $r2, $r10 ; First argument to do_IRQ | ||
772 | move.d $sp, $r11 ; second argument to do_IRQ | ||
773 | jsr do_IRQ | ||
774 | 2: | ||
775 | addq 1, $r2 ; next vector bit | ||
776 | cmp.b 32, $r2 | ||
777 | bne 1b ; process all irq's up to and including number 31 | ||
778 | moveq 0, $r9 ; make ret_from_intr realise we came from an ir | ||
779 | |||
780 | move.d $r0, [R_VECT_MASK_SET] ; Unblock all the IRQs | ||
781 | jump ret_from_intr | ||
782 | |||
783 | do_sigtrap: | ||
784 | ;; | ||
785 | ;; SIGTRAP the process that executed the break instruction. | ||
786 | ;; Make a frame that Rexit in entry.S expects. | ||
787 | ;; | ||
788 | move $brp, [$sp=$sp-16] ; Push BRP while faking a cpu status record. | ||
789 | push $srp ; Push subroutine return pointer. | ||
790 | push $dccr ; Push condition codes. | ||
791 | push $mof ; Push multiply overflow reg. | ||
792 | di ; Need to disable irq's at this point. | ||
793 | subq 14*4, $sp ; Make room for r0-r13. | ||
794 | movem $r13, [$sp] ; Push the r0-r13 registers. | ||
795 | push $r10 ; Push orig_r10. | ||
796 | clear.d [$sp=$sp-4] ; Frametype - this is a normal stackframe. | ||
797 | |||
798 | movs.w -8192,$r9 ; THREAD_SIZE == 8192 | ||
799 | and.d $sp, $r9 | ||
800 | move.d [$r9+TI_task], $r10 | ||
801 | move.d [$r10+TASK_pid], $r10 ; current->pid as arg1. | ||
802 | moveq 5, $r11 ; SIGTRAP as arg2. | ||
803 | jsr sys_kill | ||
804 | jump ret_from_intr ; Use the return routine for interrupts. | ||
805 | |||
806 | gdb_handle_breakpoint: | ||
807 | push $dccr | ||
808 | push $r0 | ||
809 | #ifdef CONFIG_ETRAX_KGDB | ||
810 | move $dccr, $r0 ; U-flag not affected by previous insns. | ||
811 | btstq 8, $r0 ; Test the U-flag. | ||
812 | bmi _ugdb_handle_breakpoint ; Go to user mode debugging. | ||
813 | nop ; Empty delay slot (cannot pop r0 here). | ||
814 | pop $r0 ; Restore r0. | ||
815 | ba kgdb_handle_breakpoint ; Go to kernel debugging. | ||
816 | pop $dccr ; Restore dccr in delay slot. | ||
817 | #endif | ||
818 | |||
819 | _ugdb_handle_breakpoint: | ||
820 | move $brp, $r0 ; Use r0 temporarily for calculation. | ||
821 | subq 2, $r0 ; Set to address of previous instruction. | ||
822 | move $r0, $brp | ||
823 | pop $r0 ; Restore r0. | ||
824 | ba do_sigtrap ; SIGTRAP the offending process. | ||
825 | pop $dccr ; Restore dccr in delay slot. | ||
826 | |||
827 | .data | ||
828 | |||
829 | hw_bp_trigs: | ||
830 | .space 64*4 | ||
831 | hw_bp_trig_ptr: | ||
832 | .dword hw_bp_trigs | ||
833 | |||
834 | .section .rodata,"a" | ||
835 | sys_call_table: | ||
836 | .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ | ||
837 | .long sys_exit | ||
838 | .long sys_fork | ||
839 | .long sys_read | ||
840 | .long sys_write | ||
841 | .long sys_open /* 5 */ | ||
842 | .long sys_close | ||
843 | .long sys_waitpid | ||
844 | .long sys_creat | ||
845 | .long sys_link | ||
846 | .long sys_unlink /* 10 */ | ||
847 | .long sys_execve | ||
848 | .long sys_chdir | ||
849 | .long sys_time | ||
850 | .long sys_mknod | ||
851 | .long sys_chmod /* 15 */ | ||
852 | .long sys_lchown16 | ||
853 | .long sys_ni_syscall /* old break syscall holder */ | ||
854 | .long sys_stat | ||
855 | .long sys_lseek | ||
856 | .long sys_getpid /* 20 */ | ||
857 | .long sys_mount | ||
858 | .long sys_oldumount | ||
859 | .long sys_setuid16 | ||
860 | .long sys_getuid16 | ||
861 | .long sys_stime /* 25 */ | ||
862 | .long sys_ptrace | ||
863 | .long sys_alarm | ||
864 | .long sys_fstat | ||
865 | .long sys_pause | ||
866 | .long sys_utime /* 30 */ | ||
867 | .long sys_ni_syscall /* old stty syscall holder */ | ||
868 | .long sys_ni_syscall /* old gtty syscall holder */ | ||
869 | .long sys_access | ||
870 | .long sys_nice | ||
871 | .long sys_ni_syscall /* 35 old ftime syscall holder */ | ||
872 | .long sys_sync | ||
873 | .long sys_kill | ||
874 | .long sys_rename | ||
875 | .long sys_mkdir | ||
876 | .long sys_rmdir /* 40 */ | ||
877 | .long sys_dup | ||
878 | .long sys_pipe | ||
879 | .long sys_times | ||
880 | .long sys_ni_syscall /* old prof syscall holder */ | ||
881 | .long sys_brk /* 45 */ | ||
882 | .long sys_setgid16 | ||
883 | .long sys_getgid16 | ||
884 | .long sys_signal | ||
885 | .long sys_geteuid16 | ||
886 | .long sys_getegid16 /* 50 */ | ||
887 | .long sys_acct | ||
888 | .long sys_umount /* recycled never used phys( */ | ||
889 | .long sys_ni_syscall /* old lock syscall holder */ | ||
890 | .long sys_ioctl | ||
891 | .long sys_fcntl /* 55 */ | ||
892 | .long sys_ni_syscall /* old mpx syscall holder */ | ||
893 | .long sys_setpgid | ||
894 | .long sys_ni_syscall /* old ulimit syscall holder */ | ||
895 | .long sys_ni_syscall /* old sys_olduname holder */ | ||
896 | .long sys_umask /* 60 */ | ||
897 | .long sys_chroot | ||
898 | .long sys_ustat | ||
899 | .long sys_dup2 | ||
900 | .long sys_getppid | ||
901 | .long sys_getpgrp /* 65 */ | ||
902 | .long sys_setsid | ||
903 | .long sys_sigaction | ||
904 | .long sys_sgetmask | ||
905 | .long sys_ssetmask | ||
906 | .long sys_setreuid16 /* 70 */ | ||
907 | .long sys_setregid16 | ||
908 | .long sys_sigsuspend | ||
909 | .long sys_sigpending | ||
910 | .long sys_sethostname | ||
911 | .long sys_setrlimit /* 75 */ | ||
912 | .long sys_old_getrlimit | ||
913 | .long sys_getrusage | ||
914 | .long sys_gettimeofday | ||
915 | .long sys_settimeofday | ||
916 | .long sys_getgroups16 /* 80 */ | ||
917 | .long sys_setgroups16 | ||
918 | .long sys_select /* was old_select in Linux/E100 */ | ||
919 | .long sys_symlink | ||
920 | .long sys_lstat | ||
921 | .long sys_readlink /* 85 */ | ||
922 | .long sys_uselib | ||
923 | .long sys_swapon | ||
924 | .long sys_reboot | ||
925 | .long old_readdir | ||
926 | .long old_mmap /* 90 */ | ||
927 | .long sys_munmap | ||
928 | .long sys_truncate | ||
929 | .long sys_ftruncate | ||
930 | .long sys_fchmod | ||
931 | .long sys_fchown16 /* 95 */ | ||
932 | .long sys_getpriority | ||
933 | .long sys_setpriority | ||
934 | .long sys_ni_syscall /* old profil syscall holder */ | ||
935 | .long sys_statfs | ||
936 | .long sys_fstatfs /* 100 */ | ||
937 | .long sys_ni_syscall /* sys_ioperm in i386 */ | ||
938 | .long sys_socketcall | ||
939 | .long sys_syslog | ||
940 | .long sys_setitimer | ||
941 | .long sys_getitimer /* 105 */ | ||
942 | .long sys_newstat | ||
943 | .long sys_newlstat | ||
944 | .long sys_newfstat | ||
945 | .long sys_ni_syscall /* old sys_uname holder */ | ||
946 | .long sys_ni_syscall /* sys_iopl in i386 */ | ||
947 | .long sys_vhangup | ||
948 | .long sys_ni_syscall /* old "idle" system call */ | ||
949 | .long sys_ni_syscall /* vm86old in i386 */ | ||
950 | .long sys_wait4 | ||
951 | .long sys_swapoff /* 115 */ | ||
952 | .long sys_sysinfo | ||
953 | .long sys_ipc | ||
954 | .long sys_fsync | ||
955 | .long sys_sigreturn | ||
956 | .long sys_clone /* 120 */ | ||
957 | .long sys_setdomainname | ||
958 | .long sys_newuname | ||
959 | .long sys_ni_syscall /* sys_modify_ldt */ | ||
960 | .long sys_adjtimex | ||
961 | .long sys_mprotect /* 125 */ | ||
962 | .long sys_sigprocmask | ||
963 | .long sys_ni_syscall /* old "create_module" */ | ||
964 | .long sys_init_module | ||
965 | .long sys_delete_module | ||
966 | .long sys_ni_syscall /* 130: old "get_kernel_syms" */ | ||
967 | .long sys_quotactl | ||
968 | .long sys_getpgid | ||
969 | .long sys_fchdir | ||
970 | .long sys_bdflush | ||
971 | .long sys_sysfs /* 135 */ | ||
972 | .long sys_personality | ||
973 | .long sys_ni_syscall /* for afs_syscall */ | ||
974 | .long sys_setfsuid16 | ||
975 | .long sys_setfsgid16 | ||
976 | .long sys_llseek /* 140 */ | ||
977 | .long sys_getdents | ||
978 | .long sys_select | ||
979 | .long sys_flock | ||
980 | .long sys_msync | ||
981 | .long sys_readv /* 145 */ | ||
982 | .long sys_writev | ||
983 | .long sys_getsid | ||
984 | .long sys_fdatasync | ||
985 | .long sys_sysctl | ||
986 | .long sys_mlock /* 150 */ | ||
987 | .long sys_munlock | ||
988 | .long sys_mlockall | ||
989 | .long sys_munlockall | ||
990 | .long sys_sched_setparam | ||
991 | .long sys_sched_getparam /* 155 */ | ||
992 | .long sys_sched_setscheduler | ||
993 | .long sys_sched_getscheduler | ||
994 | .long sys_sched_yield | ||
995 | .long sys_sched_get_priority_max | ||
996 | .long sys_sched_get_priority_min /* 160 */ | ||
997 | .long sys_sched_rr_get_interval | ||
998 | .long sys_nanosleep | ||
999 | .long sys_mremap | ||
1000 | .long sys_setresuid16 | ||
1001 | .long sys_getresuid16 /* 165 */ | ||
1002 | .long sys_ni_syscall /* sys_vm86 */ | ||
1003 | .long sys_ni_syscall /* Old sys_query_module */ | ||
1004 | .long sys_poll | ||
1005 | .long sys_nfsservctl | ||
1006 | .long sys_setresgid16 /* 170 */ | ||
1007 | .long sys_getresgid16 | ||
1008 | .long sys_prctl | ||
1009 | .long sys_rt_sigreturn | ||
1010 | .long sys_rt_sigaction | ||
1011 | .long sys_rt_sigprocmask /* 175 */ | ||
1012 | .long sys_rt_sigpending | ||
1013 | .long sys_rt_sigtimedwait | ||
1014 | .long sys_rt_sigqueueinfo | ||
1015 | .long sys_rt_sigsuspend | ||
1016 | .long sys_pread64 /* 180 */ | ||
1017 | .long sys_pwrite64 | ||
1018 | .long sys_chown16 | ||
1019 | .long sys_getcwd | ||
1020 | .long sys_capget | ||
1021 | .long sys_capset /* 185 */ | ||
1022 | .long sys_sigaltstack | ||
1023 | .long sys_sendfile | ||
1024 | .long sys_ni_syscall /* streams1 */ | ||
1025 | .long sys_ni_syscall /* streams2 */ | ||
1026 | .long sys_vfork /* 190 */ | ||
1027 | .long sys_getrlimit | ||
1028 | .long sys_mmap2 | ||
1029 | .long sys_truncate64 | ||
1030 | .long sys_ftruncate64 | ||
1031 | .long sys_stat64 /* 195 */ | ||
1032 | .long sys_lstat64 | ||
1033 | .long sys_fstat64 | ||
1034 | .long sys_lchown | ||
1035 | .long sys_getuid | ||
1036 | .long sys_getgid /* 200 */ | ||
1037 | .long sys_geteuid | ||
1038 | .long sys_getegid | ||
1039 | .long sys_setreuid | ||
1040 | .long sys_setregid | ||
1041 | .long sys_getgroups /* 205 */ | ||
1042 | .long sys_setgroups | ||
1043 | .long sys_fchown | ||
1044 | .long sys_setresuid | ||
1045 | .long sys_getresuid | ||
1046 | .long sys_setresgid /* 210 */ | ||
1047 | .long sys_getresgid | ||
1048 | .long sys_chown | ||
1049 | .long sys_setuid | ||
1050 | .long sys_setgid | ||
1051 | .long sys_setfsuid /* 215 */ | ||
1052 | .long sys_setfsgid | ||
1053 | .long sys_pivot_root | ||
1054 | .long sys_mincore | ||
1055 | .long sys_madvise | ||
1056 | .long sys_getdents64 /* 220 */ | ||
1057 | .long sys_fcntl64 | ||
1058 | .long sys_ni_syscall /* reserved for TUX */ | ||
1059 | .long sys_ni_syscall | ||
1060 | .long sys_gettid | ||
1061 | .long sys_readahead /* 225 */ | ||
1062 | .long sys_setxattr | ||
1063 | .long sys_lsetxattr | ||
1064 | .long sys_fsetxattr | ||
1065 | .long sys_getxattr | ||
1066 | .long sys_lgetxattr /* 230 */ | ||
1067 | .long sys_fgetxattr | ||
1068 | .long sys_listxattr | ||
1069 | .long sys_llistxattr | ||
1070 | .long sys_flistxattr | ||
1071 | .long sys_removexattr /* 235 */ | ||
1072 | .long sys_lremovexattr | ||
1073 | .long sys_fremovexattr | ||
1074 | .long sys_tkill | ||
1075 | .long sys_sendfile64 | ||
1076 | .long sys_futex /* 240 */ | ||
1077 | .long sys_sched_setaffinity | ||
1078 | .long sys_sched_getaffinity | ||
1079 | .long sys_ni_syscall /* sys_set_thread_area */ | ||
1080 | .long sys_ni_syscall /* sys_get_thread_area */ | ||
1081 | .long sys_io_setup /* 245 */ | ||
1082 | .long sys_io_destroy | ||
1083 | .long sys_io_getevents | ||
1084 | .long sys_io_submit | ||
1085 | .long sys_io_cancel | ||
1086 | .long sys_fadvise64 /* 250 */ | ||
1087 | .long sys_ni_syscall | ||
1088 | .long sys_exit_group | ||
1089 | .long sys_lookup_dcookie | ||
1090 | .long sys_epoll_create | ||
1091 | .long sys_epoll_ctl /* 255 */ | ||
1092 | .long sys_epoll_wait | ||
1093 | .long sys_remap_file_pages | ||
1094 | .long sys_set_tid_address | ||
1095 | .long sys_timer_create | ||
1096 | .long sys_timer_settime /* 260 */ | ||
1097 | .long sys_timer_gettime | ||
1098 | .long sys_timer_getoverrun | ||
1099 | .long sys_timer_delete | ||
1100 | .long sys_clock_settime | ||
1101 | .long sys_clock_gettime /* 265 */ | ||
1102 | .long sys_clock_getres | ||
1103 | .long sys_clock_nanosleep | ||
1104 | .long sys_statfs64 | ||
1105 | .long sys_fstatfs64 | ||
1106 | .long sys_tgkill /* 270 */ | ||
1107 | .long sys_utimes | ||
1108 | .long sys_fadvise64_64 | ||
1109 | .long sys_ni_syscall /* sys_vserver */ | ||
1110 | .long sys_ni_syscall /* sys_mbind */ | ||
1111 | .long sys_ni_syscall /* 275 sys_get_mempolicy */ | ||
1112 | .long sys_ni_syscall /* sys_set_mempolicy */ | ||
1113 | .long sys_mq_open | ||
1114 | .long sys_mq_unlink | ||
1115 | .long sys_mq_timedsend | ||
1116 | .long sys_mq_timedreceive /* 280 */ | ||
1117 | .long sys_mq_notify | ||
1118 | .long sys_mq_getsetattr | ||
1119 | .long sys_ni_syscall /* reserved for kexec */ | ||
1120 | .long sys_waitid | ||
1121 | |||
1122 | /* | ||
1123 | * NOTE!! This doesn't have to be exact - we just have | ||
1124 | * to make sure we have _enough_ of the "sys_ni_syscall" | ||
1125 | * entries. Don't panic if you notice that this hasn't | ||
1126 | * been shrunk every time we add a new system call. | ||
1127 | */ | ||
1128 | |||
1129 | .rept NR_syscalls-(.-sys_call_table)/4 | ||
1130 | .long sys_ni_syscall | ||
1131 | .endr | ||
1132 | |||
diff --git a/arch/cris/arch-v10/kernel/fasttimer.c b/arch/cris/arch-v10/kernel/fasttimer.c new file mode 100644 index 000000000000..4717f7ae8e51 --- /dev/null +++ b/arch/cris/arch-v10/kernel/fasttimer.c | |||
@@ -0,0 +1,977 @@ | |||
1 | /* $Id: fasttimer.c,v 1.6 2004/05/14 10:18:39 starvik Exp $ | ||
2 | * linux/arch/cris/kernel/fasttimer.c | ||
3 | * | ||
4 | * Fast timers for ETRAX100/ETRAX100LX | ||
5 | * This may be useful in other OS than Linux so use 2 space indentation... | ||
6 | * | ||
7 | * $Log: fasttimer.c,v $ | ||
8 | * Revision 1.6 2004/05/14 10:18:39 starvik | ||
9 | * Export fast_timer_list | ||
10 | * | ||
11 | * Revision 1.5 2004/05/14 07:58:01 starvik | ||
12 | * Merge of changes from 2.4 | ||
13 | * | ||
14 | * Revision 1.4 2003/07/04 08:27:41 starvik | ||
15 | * Merge of Linux 2.5.74 | ||
16 | * | ||
17 | * Revision 1.3 2002/12/12 08:26:32 starvik | ||
18 | * Don't use C-comments inside CVS comments | ||
19 | * | ||
20 | * Revision 1.2 2002/12/11 15:42:02 starvik | ||
21 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/ | ||
22 | * | ||
23 | * Revision 1.1 2002/11/18 07:58:06 starvik | ||
24 | * Fast timers (from Linux 2.4) | ||
25 | * | ||
26 | * Revision 1.5 2002/10/15 06:21:39 starvik | ||
27 | * Added call to init_waitqueue_head | ||
28 | * | ||
29 | * Revision 1.4 2002/05/28 17:47:59 johana | ||
30 | * Added del_fast_timer() | ||
31 | * | ||
32 | * Revision 1.3 2002/05/28 16:16:07 johana | ||
33 | * Handle empty fast_timer_list | ||
34 | * | ||
35 | * Revision 1.2 2002/05/27 15:38:42 johana | ||
36 | * Made it compile without warnings on Linux 2.4. | ||
37 | * (includes, wait_queue, PROC_FS and snprintf) | ||
38 | * | ||
39 | * Revision 1.1 2002/05/27 15:32:25 johana | ||
40 | * arch/etrax100/kernel/fasttimer.c v1.8 from the elinux tree. | ||
41 | * | ||
42 | * Revision 1.8 2001/11/27 13:50:40 pkj | ||
43 | * Disable interrupts while stopping the timer and while modifying the | ||
44 | * list of active timers in timer1_handler() as it may be interrupted | ||
45 | * by other interrupts (e.g., the serial interrupt) which may add fast | ||
46 | * timers. | ||
47 | * | ||
48 | * Revision 1.7 2001/11/22 11:50:32 pkj | ||
49 | * * Only store information about the last 16 timers. | ||
50 | * * proc_fasttimer_read() now uses an allocated buffer, since it | ||
51 | * requires more space than just a page even for only writing the | ||
52 | * last 16 timers. The buffer is only allocated on request, so | ||
53 | * unless /proc/fasttimer is read, it is never allocated. | ||
54 | * * Renamed fast_timer_started to fast_timers_started to match | ||
55 | * fast_timers_added and fast_timers_expired. | ||
56 | * * Some clean-up. | ||
57 | * | ||
58 | * Revision 1.6 2000/12/13 14:02:08 johana | ||
59 | * Removed volatile for fast_timer_list | ||
60 | * | ||
61 | * Revision 1.5 2000/12/13 13:55:35 johana | ||
62 | * Added DEBUG_LOG, added som cli() and cleanup | ||
63 | * | ||
64 | * Revision 1.4 2000/12/05 13:48:50 johana | ||
65 | * Added range check when writing proc file, modified timer int handling | ||
66 | * | ||
67 | * Revision 1.3 2000/11/23 10:10:20 johana | ||
68 | * More debug/logging possibilities. | ||
69 | * Moved GET_JIFFIES_USEC() to timex.h and time.c | ||
70 | * | ||
71 | * Revision 1.2 2000/11/01 13:41:04 johana | ||
72 | * Clean up and bugfixes. | ||
73 | * Created new do_gettimeofday_fast() that gets a timeval struct | ||
74 | * with time based on jiffies and *R_TIMER0_DATA, uses a table | ||
75 | * for fast conversion of timer value to microseconds. | ||
76 | * (Much faster the standard do_gettimeofday() and we don't really | ||
77 | * wan't to use the true time - we wan't the "uptime" so timers don't screw up | ||
78 | * when we change the time. | ||
79 | * TODO: Add efficient support for continuous timers as well. | ||
80 | * | ||
81 | * Revision 1.1 2000/10/26 15:49:16 johana | ||
82 | * Added fasttimer, highresolution timers. | ||
83 | * | ||
84 | * Copyright (C) 2000,2001 2002 Axis Communications AB, Lund, Sweden | ||
85 | */ | ||
86 | |||
87 | #include <linux/errno.h> | ||
88 | #include <linux/sched.h> | ||
89 | #include <linux/kernel.h> | ||
90 | #include <linux/param.h> | ||
91 | #include <linux/string.h> | ||
92 | #include <linux/mm.h> | ||
93 | #include <linux/vmalloc.h> | ||
94 | #include <linux/interrupt.h> | ||
95 | #include <linux/time.h> | ||
96 | #include <linux/delay.h> | ||
97 | |||
98 | #include <asm/segment.h> | ||
99 | #include <asm/io.h> | ||
100 | #include <asm/irq.h> | ||
101 | #include <asm/delay.h> | ||
102 | #include <asm/rtc.h> | ||
103 | |||
104 | #include <linux/config.h> | ||
105 | #include <linux/version.h> | ||
106 | |||
107 | #include <asm/arch/svinto.h> | ||
108 | #include <asm/fasttimer.h> | ||
109 | #include <linux/proc_fs.h> | ||
110 | |||
111 | |||
112 | #define DEBUG_LOG_INCLUDED | ||
113 | #define FAST_TIMER_LOG | ||
114 | //#define FAST_TIMER_TEST | ||
115 | |||
116 | #define FAST_TIMER_SANITY_CHECKS | ||
117 | |||
118 | #ifdef FAST_TIMER_SANITY_CHECKS | ||
119 | #define SANITYCHECK(x) x | ||
120 | static int sanity_failed = 0; | ||
121 | #else | ||
122 | #define SANITYCHECK(x) | ||
123 | #endif | ||
124 | |||
125 | #define D1(x) | ||
126 | #define D2(x) | ||
127 | #define DP(x) | ||
128 | |||
129 | #define __INLINE__ inline | ||
130 | |||
131 | static int fast_timer_running = 0; | ||
132 | static int fast_timers_added = 0; | ||
133 | static int fast_timers_started = 0; | ||
134 | static int fast_timers_expired = 0; | ||
135 | static int fast_timers_deleted = 0; | ||
136 | static int fast_timer_is_init = 0; | ||
137 | static int fast_timer_ints = 0; | ||
138 | |||
139 | struct fast_timer *fast_timer_list = NULL; | ||
140 | |||
141 | #ifdef DEBUG_LOG_INCLUDED | ||
142 | #define DEBUG_LOG_MAX 128 | ||
143 | static const char * debug_log_string[DEBUG_LOG_MAX]; | ||
144 | static unsigned long debug_log_value[DEBUG_LOG_MAX]; | ||
145 | static int debug_log_cnt = 0; | ||
146 | static int debug_log_cnt_wrapped = 0; | ||
147 | |||
148 | #define DEBUG_LOG(string, value) \ | ||
149 | { \ | ||
150 | unsigned long log_flags; \ | ||
151 | save_flags(log_flags); \ | ||
152 | cli(); \ | ||
153 | debug_log_string[debug_log_cnt] = (string); \ | ||
154 | debug_log_value[debug_log_cnt] = (unsigned long)(value); \ | ||
155 | if (++debug_log_cnt >= DEBUG_LOG_MAX) \ | ||
156 | { \ | ||
157 | debug_log_cnt = debug_log_cnt % DEBUG_LOG_MAX; \ | ||
158 | debug_log_cnt_wrapped = 1; \ | ||
159 | } \ | ||
160 | restore_flags(log_flags); \ | ||
161 | } | ||
162 | #else | ||
163 | #define DEBUG_LOG(string, value) | ||
164 | #endif | ||
165 | |||
166 | |||
167 | /* The frequencies for index = clkselx number in R_TIMER_CTRL */ | ||
168 | #define NUM_TIMER_FREQ 15 | ||
169 | #define MAX_USABLE_TIMER_FREQ 7 | ||
170 | #define MAX_DELAY_US 853333L | ||
171 | const unsigned long timer_freq_100[NUM_TIMER_FREQ] = | ||
172 | { | ||
173 | 3, /* 0 3333 - 853333 us */ | ||
174 | 6, /* 1 1666 - 426666 us */ | ||
175 | 12, /* 2 833 - 213333 us */ | ||
176 | 24, /* 3 416 - 106666 us */ | ||
177 | 48, /* 4 208 - 53333 us */ | ||
178 | 96, /* 5 104 - 26666 us */ | ||
179 | 192, /* 6 52 - 13333 us */ | ||
180 | 384, /* 7 26 - 6666 us */ | ||
181 | 576, | ||
182 | 1152, | ||
183 | 2304, | ||
184 | 4608, | ||
185 | 9216, | ||
186 | 18432, | ||
187 | 62500, | ||
188 | /* 15 = cascade */ | ||
189 | }; | ||
190 | #define NUM_TIMER_STATS 16 | ||
191 | #ifdef FAST_TIMER_LOG | ||
192 | struct fast_timer timer_added_log[NUM_TIMER_STATS]; | ||
193 | struct fast_timer timer_started_log[NUM_TIMER_STATS]; | ||
194 | struct fast_timer timer_expired_log[NUM_TIMER_STATS]; | ||
195 | #endif | ||
196 | |||
197 | int timer_div_settings[NUM_TIMER_STATS]; | ||
198 | int timer_freq_settings[NUM_TIMER_STATS]; | ||
199 | int timer_delay_settings[NUM_TIMER_STATS]; | ||
200 | |||
201 | /* Not true gettimeofday, only checks the jiffies (uptime) + useconds */ | ||
202 | void __INLINE__ do_gettimeofday_fast(struct timeval *tv) | ||
203 | { | ||
204 | unsigned long sec = jiffies; | ||
205 | unsigned long usec = GET_JIFFIES_USEC(); | ||
206 | |||
207 | usec += (sec % HZ) * (1000000 / HZ); | ||
208 | sec = sec / HZ; | ||
209 | |||
210 | if (usec > 1000000) | ||
211 | { | ||
212 | usec -= 1000000; | ||
213 | sec++; | ||
214 | } | ||
215 | tv->tv_sec = sec; | ||
216 | tv->tv_usec = usec; | ||
217 | } | ||
218 | |||
219 | int __INLINE__ timeval_cmp(struct timeval *t0, struct timeval *t1) | ||
220 | { | ||
221 | if (t0->tv_sec < t1->tv_sec) | ||
222 | { | ||
223 | return -1; | ||
224 | } | ||
225 | else if (t0->tv_sec > t1->tv_sec) | ||
226 | { | ||
227 | return 1; | ||
228 | } | ||
229 | if (t0->tv_usec < t1->tv_usec) | ||
230 | { | ||
231 | return -1; | ||
232 | } | ||
233 | else if (t0->tv_usec > t1->tv_usec) | ||
234 | { | ||
235 | return 1; | ||
236 | } | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | void __INLINE__ start_timer1(unsigned long delay_us) | ||
241 | { | ||
242 | int freq_index = 0; /* This is the lowest resolution */ | ||
243 | unsigned long upper_limit = MAX_DELAY_US; | ||
244 | |||
245 | unsigned long div; | ||
246 | /* Start/Restart the timer to the new shorter value */ | ||
247 | /* t = 1/freq = 1/19200 = 53us | ||
248 | * T=div*t, div = T/t = delay_us*freq/1000000 | ||
249 | */ | ||
250 | #if 1 /* Adaptive timer settings */ | ||
251 | while (delay_us < upper_limit && freq_index < MAX_USABLE_TIMER_FREQ) | ||
252 | { | ||
253 | freq_index++; | ||
254 | upper_limit >>= 1; /* Divide by 2 using shift */ | ||
255 | } | ||
256 | if (freq_index > 0) | ||
257 | { | ||
258 | freq_index--; | ||
259 | } | ||
260 | #else | ||
261 | freq_index = 6; | ||
262 | #endif | ||
263 | div = delay_us * timer_freq_100[freq_index]/10000; | ||
264 | if (div < 2) | ||
265 | { | ||
266 | /* Maybe increase timer freq? */ | ||
267 | div = 2; | ||
268 | } | ||
269 | if (div > 255) | ||
270 | { | ||
271 | div = 0; /* This means 256, the max the timer takes */ | ||
272 | /* If a longer timeout than the timer can handle is used, | ||
273 | * then we must restart it when it goes off. | ||
274 | */ | ||
275 | } | ||
276 | |||
277 | timer_div_settings[fast_timers_started % NUM_TIMER_STATS] = div; | ||
278 | timer_freq_settings[fast_timers_started % NUM_TIMER_STATS] = freq_index; | ||
279 | timer_delay_settings[fast_timers_started % NUM_TIMER_STATS] = delay_us; | ||
280 | |||
281 | D1(printk("start_timer1 : %d us freq: %i div: %i\n", | ||
282 | delay_us, freq_index, div)); | ||
283 | /* Clear timer1 irq */ | ||
284 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); | ||
285 | |||
286 | /* Set timer values */ | ||
287 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
288 | (r_timer_ctrl_shadow & | ||
289 | ~IO_MASK(R_TIMER_CTRL, timerdiv1) & | ||
290 | ~IO_MASK(R_TIMER_CTRL, tm1) & | ||
291 | ~IO_MASK(R_TIMER_CTRL, clksel1)) | | ||
292 | IO_FIELD(R_TIMER_CTRL, timerdiv1, div) | | ||
293 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | | ||
294 | IO_FIELD(R_TIMER_CTRL, clksel1, freq_index ); /* 6=c19k2Hz */ | ||
295 | |||
296 | /* Ack interrupt */ | ||
297 | *R_TIMER_CTRL = r_timer_ctrl_shadow | | ||
298 | IO_STATE(R_TIMER_CTRL, i1, clr); | ||
299 | |||
300 | /* Start timer */ | ||
301 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
302 | (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | | ||
303 | IO_STATE(R_TIMER_CTRL, tm1, run); | ||
304 | |||
305 | /* Enable timer1 irq */ | ||
306 | *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer1, set); | ||
307 | fast_timers_started++; | ||
308 | fast_timer_running = 1; | ||
309 | } | ||
310 | |||
311 | /* In version 1.4 this function takes 27 - 50 us */ | ||
312 | void start_one_shot_timer(struct fast_timer *t, | ||
313 | fast_timer_function_type *function, | ||
314 | unsigned long data, | ||
315 | unsigned long delay_us, | ||
316 | const char *name) | ||
317 | { | ||
318 | unsigned long flags; | ||
319 | struct fast_timer *tmp; | ||
320 | |||
321 | D1(printk("sft %s %d us\n", name, delay_us)); | ||
322 | |||
323 | save_flags(flags); | ||
324 | cli(); | ||
325 | |||
326 | do_gettimeofday_fast(&t->tv_set); | ||
327 | tmp = fast_timer_list; | ||
328 | |||
329 | SANITYCHECK({ /* Check so this is not in the list already... */ | ||
330 | while (tmp != NULL) | ||
331 | { | ||
332 | if (tmp == t) | ||
333 | { | ||
334 | printk(KERN_WARNING | ||
335 | "timer name: %s data: 0x%08lX already in list!\n", name, data); | ||
336 | sanity_failed++; | ||
337 | return; | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | tmp = tmp->next; | ||
342 | } | ||
343 | } | ||
344 | tmp = fast_timer_list; | ||
345 | }); | ||
346 | |||
347 | t->delay_us = delay_us; | ||
348 | t->function = function; | ||
349 | t->data = data; | ||
350 | t->name = name; | ||
351 | |||
352 | t->tv_expires.tv_usec = t->tv_set.tv_usec + delay_us % 1000000; | ||
353 | t->tv_expires.tv_sec = t->tv_set.tv_sec + delay_us / 1000000; | ||
354 | if (t->tv_expires.tv_usec > 1000000) | ||
355 | { | ||
356 | t->tv_expires.tv_usec -= 1000000; | ||
357 | t->tv_expires.tv_sec++; | ||
358 | } | ||
359 | #ifdef FAST_TIMER_LOG | ||
360 | timer_added_log[fast_timers_added % NUM_TIMER_STATS] = *t; | ||
361 | #endif | ||
362 | fast_timers_added++; | ||
363 | |||
364 | /* Check if this should timeout before anything else */ | ||
365 | if (tmp == NULL || timeval_cmp(&t->tv_expires, &tmp->tv_expires) < 0) | ||
366 | { | ||
367 | /* Put first in list and modify the timer value */ | ||
368 | t->prev = NULL; | ||
369 | t->next = fast_timer_list; | ||
370 | if (fast_timer_list) | ||
371 | { | ||
372 | fast_timer_list->prev = t; | ||
373 | } | ||
374 | fast_timer_list = t; | ||
375 | #ifdef FAST_TIMER_LOG | ||
376 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | ||
377 | #endif | ||
378 | start_timer1(delay_us); | ||
379 | } else { | ||
380 | /* Put in correct place in list */ | ||
381 | while (tmp->next && | ||
382 | timeval_cmp(&t->tv_expires, &tmp->next->tv_expires) > 0) | ||
383 | { | ||
384 | tmp = tmp->next; | ||
385 | } | ||
386 | /* Insert t after tmp */ | ||
387 | t->prev = tmp; | ||
388 | t->next = tmp->next; | ||
389 | if (tmp->next) | ||
390 | { | ||
391 | tmp->next->prev = t; | ||
392 | } | ||
393 | tmp->next = t; | ||
394 | } | ||
395 | |||
396 | D2(printk("start_one_shot_timer: %d us done\n", delay_us)); | ||
397 | |||
398 | restore_flags(flags); | ||
399 | } /* start_one_shot_timer */ | ||
400 | |||
401 | static inline int fast_timer_pending (const struct fast_timer * t) | ||
402 | { | ||
403 | return (t->next != NULL) || (t->prev != NULL) || (t == fast_timer_list); | ||
404 | } | ||
405 | |||
406 | static inline int detach_fast_timer (struct fast_timer *t) | ||
407 | { | ||
408 | struct fast_timer *next, *prev; | ||
409 | if (!fast_timer_pending(t)) | ||
410 | return 0; | ||
411 | next = t->next; | ||
412 | prev = t->prev; | ||
413 | if (next) | ||
414 | next->prev = prev; | ||
415 | if (prev) | ||
416 | prev->next = next; | ||
417 | else | ||
418 | fast_timer_list = next; | ||
419 | fast_timers_deleted++; | ||
420 | return 1; | ||
421 | } | ||
422 | |||
423 | int del_fast_timer(struct fast_timer * t) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | int ret; | ||
427 | |||
428 | save_flags(flags); | ||
429 | cli(); | ||
430 | ret = detach_fast_timer(t); | ||
431 | t->next = t->prev = NULL; | ||
432 | restore_flags(flags); | ||
433 | return ret; | ||
434 | } /* del_fast_timer */ | ||
435 | |||
436 | |||
437 | /* Interrupt routines or functions called in interrupt context */ | ||
438 | |||
439 | /* Timer 1 interrupt handler */ | ||
440 | |||
441 | static irqreturn_t | ||
442 | timer1_handler(int irq, void *dev_id, struct pt_regs *regs) | ||
443 | { | ||
444 | struct fast_timer *t; | ||
445 | unsigned long flags; | ||
446 | |||
447 | save_flags(flags); | ||
448 | cli(); | ||
449 | |||
450 | /* Clear timer1 irq */ | ||
451 | *R_IRQ_MASK0_CLR = IO_STATE(R_IRQ_MASK0_CLR, timer1, clr); | ||
452 | |||
453 | /* First stop timer, then ack interrupt */ | ||
454 | /* Stop timer */ | ||
455 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
456 | (r_timer_ctrl_shadow & ~IO_MASK(R_TIMER_CTRL, tm1)) | | ||
457 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld); | ||
458 | |||
459 | /* Ack interrupt */ | ||
460 | *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i1, clr); | ||
461 | |||
462 | fast_timer_running = 0; | ||
463 | fast_timer_ints++; | ||
464 | |||
465 | restore_flags(flags); | ||
466 | |||
467 | t = fast_timer_list; | ||
468 | while (t) | ||
469 | { | ||
470 | struct timeval tv; | ||
471 | |||
472 | /* Has it really expired? */ | ||
473 | do_gettimeofday_fast(&tv); | ||
474 | D1(printk("t: %is %06ius\n", tv.tv_sec, tv.tv_usec)); | ||
475 | |||
476 | if (timeval_cmp(&t->tv_expires, &tv) <= 0) | ||
477 | { | ||
478 | /* Yes it has expired */ | ||
479 | #ifdef FAST_TIMER_LOG | ||
480 | timer_expired_log[fast_timers_expired % NUM_TIMER_STATS] = *t; | ||
481 | #endif | ||
482 | fast_timers_expired++; | ||
483 | |||
484 | /* Remove this timer before call, since it may reuse the timer */ | ||
485 | save_flags(flags); | ||
486 | cli(); | ||
487 | if (t->prev) | ||
488 | { | ||
489 | t->prev->next = t->next; | ||
490 | } | ||
491 | else | ||
492 | { | ||
493 | fast_timer_list = t->next; | ||
494 | } | ||
495 | if (t->next) | ||
496 | { | ||
497 | t->next->prev = t->prev; | ||
498 | } | ||
499 | t->prev = NULL; | ||
500 | t->next = NULL; | ||
501 | restore_flags(flags); | ||
502 | |||
503 | if (t->function != NULL) | ||
504 | { | ||
505 | t->function(t->data); | ||
506 | } | ||
507 | else | ||
508 | { | ||
509 | DEBUG_LOG("!timer1 %i function==NULL!\n", fast_timer_ints); | ||
510 | } | ||
511 | } | ||
512 | else | ||
513 | { | ||
514 | /* Timer is to early, let's set it again using the normal routines */ | ||
515 | D1(printk(".\n")); | ||
516 | } | ||
517 | |||
518 | save_flags(flags); | ||
519 | cli(); | ||
520 | if ((t = fast_timer_list) != NULL) | ||
521 | { | ||
522 | /* Start next timer.. */ | ||
523 | long us; | ||
524 | struct timeval tv; | ||
525 | |||
526 | do_gettimeofday_fast(&tv); | ||
527 | us = ((t->tv_expires.tv_sec - tv.tv_sec) * 1000000 + | ||
528 | t->tv_expires.tv_usec - tv.tv_usec); | ||
529 | if (us > 0) | ||
530 | { | ||
531 | if (!fast_timer_running) | ||
532 | { | ||
533 | #ifdef FAST_TIMER_LOG | ||
534 | timer_started_log[fast_timers_started % NUM_TIMER_STATS] = *t; | ||
535 | #endif | ||
536 | start_timer1(us); | ||
537 | } | ||
538 | restore_flags(flags); | ||
539 | break; | ||
540 | } | ||
541 | else | ||
542 | { | ||
543 | /* Timer already expired, let's handle it better late than never. | ||
544 | * The normal loop handles it | ||
545 | */ | ||
546 | D1(printk("e! %d\n", us)); | ||
547 | } | ||
548 | } | ||
549 | restore_flags(flags); | ||
550 | } | ||
551 | |||
552 | if (!t) | ||
553 | { | ||
554 | D1(printk("t1 stop!\n")); | ||
555 | } | ||
556 | |||
557 | return IRQ_HANDLED; | ||
558 | } | ||
559 | |||
560 | static void wake_up_func(unsigned long data) | ||
561 | { | ||
562 | #ifdef DECLARE_WAITQUEUE | ||
563 | wait_queue_head_t *sleep_wait_p = (wait_queue_head_t*)data; | ||
564 | #else | ||
565 | struct wait_queue **sleep_wait_p = (struct wait_queue **)data; | ||
566 | #endif | ||
567 | wake_up(sleep_wait_p); | ||
568 | } | ||
569 | |||
570 | |||
571 | /* Useful API */ | ||
572 | |||
573 | void schedule_usleep(unsigned long us) | ||
574 | { | ||
575 | struct fast_timer t; | ||
576 | #ifdef DECLARE_WAITQUEUE | ||
577 | wait_queue_head_t sleep_wait; | ||
578 | init_waitqueue_head(&sleep_wait); | ||
579 | { | ||
580 | DECLARE_WAITQUEUE(wait, current); | ||
581 | #else | ||
582 | struct wait_queue *sleep_wait = NULL; | ||
583 | struct wait_queue wait = { current, NULL }; | ||
584 | #endif | ||
585 | |||
586 | D1(printk("schedule_usleep(%d)\n", us)); | ||
587 | add_wait_queue(&sleep_wait, &wait); | ||
588 | set_current_state(TASK_INTERRUPTIBLE); | ||
589 | start_one_shot_timer(&t, wake_up_func, (unsigned long)&sleep_wait, us, | ||
590 | "usleep"); | ||
591 | schedule(); | ||
592 | set_current_state(TASK_RUNNING); | ||
593 | remove_wait_queue(&sleep_wait, &wait); | ||
594 | D1(printk("done schedule_usleep(%d)\n", us)); | ||
595 | #ifdef DECLARE_WAITQUEUE | ||
596 | } | ||
597 | #endif | ||
598 | } | ||
599 | |||
600 | #ifdef CONFIG_PROC_FS | ||
601 | static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | ||
602 | ,int *eof, void *data_unused); | ||
603 | static struct proc_dir_entry *fasttimer_proc_entry; | ||
604 | #endif /* CONFIG_PROC_FS */ | ||
605 | |||
606 | #ifdef CONFIG_PROC_FS | ||
607 | |||
608 | /* This value is very much based on testing */ | ||
609 | #define BIG_BUF_SIZE (500 + NUM_TIMER_STATS * 300) | ||
610 | |||
611 | static int proc_fasttimer_read(char *buf, char **start, off_t offset, int len | ||
612 | ,int *eof, void *data_unused) | ||
613 | { | ||
614 | unsigned long flags; | ||
615 | int i = 0; | ||
616 | int num_to_show; | ||
617 | struct timeval tv; | ||
618 | struct fast_timer *t, *nextt; | ||
619 | static char *bigbuf = NULL; | ||
620 | static unsigned long used; | ||
621 | |||
622 | if (!bigbuf && !(bigbuf = vmalloc(BIG_BUF_SIZE))) | ||
623 | { | ||
624 | used = 0; | ||
625 | bigbuf[0] = '\0'; | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | if (!offset || !used) | ||
630 | { | ||
631 | do_gettimeofday_fast(&tv); | ||
632 | |||
633 | used = 0; | ||
634 | used += sprintf(bigbuf + used, "Fast timers added: %i\n", | ||
635 | fast_timers_added); | ||
636 | used += sprintf(bigbuf + used, "Fast timers started: %i\n", | ||
637 | fast_timers_started); | ||
638 | used += sprintf(bigbuf + used, "Fast timer interrupts: %i\n", | ||
639 | fast_timer_ints); | ||
640 | used += sprintf(bigbuf + used, "Fast timers expired: %i\n", | ||
641 | fast_timers_expired); | ||
642 | used += sprintf(bigbuf + used, "Fast timers deleted: %i\n", | ||
643 | fast_timers_deleted); | ||
644 | used += sprintf(bigbuf + used, "Fast timer running: %s\n", | ||
645 | fast_timer_running ? "yes" : "no"); | ||
646 | used += sprintf(bigbuf + used, "Current time: %lu.%06lu\n", | ||
647 | (unsigned long)tv.tv_sec, | ||
648 | (unsigned long)tv.tv_usec); | ||
649 | #ifdef FAST_TIMER_SANITY_CHECKS | ||
650 | used += sprintf(bigbuf + used, "Sanity failed: %i\n", | ||
651 | sanity_failed); | ||
652 | #endif | ||
653 | used += sprintf(bigbuf + used, "\n"); | ||
654 | |||
655 | #ifdef DEBUG_LOG_INCLUDED | ||
656 | { | ||
657 | int end_i = debug_log_cnt; | ||
658 | i = 0; | ||
659 | |||
660 | if (debug_log_cnt_wrapped) | ||
661 | { | ||
662 | i = debug_log_cnt; | ||
663 | } | ||
664 | |||
665 | while ((i != end_i || (debug_log_cnt_wrapped && !used)) && | ||
666 | used+100 < BIG_BUF_SIZE) | ||
667 | { | ||
668 | used += sprintf(bigbuf + used, debug_log_string[i], | ||
669 | debug_log_value[i]); | ||
670 | i = (i+1) % DEBUG_LOG_MAX; | ||
671 | } | ||
672 | } | ||
673 | used += sprintf(bigbuf + used, "\n"); | ||
674 | #endif | ||
675 | |||
676 | num_to_show = (fast_timers_started < NUM_TIMER_STATS ? fast_timers_started: | ||
677 | NUM_TIMER_STATS); | ||
678 | used += sprintf(bigbuf + used, "Timers started: %i\n", fast_timers_started); | ||
679 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE) ; i++) | ||
680 | { | ||
681 | int cur = (fast_timers_started - i - 1) % NUM_TIMER_STATS; | ||
682 | |||
683 | #if 1 //ndef FAST_TIMER_LOG | ||
684 | used += sprintf(bigbuf + used, "div: %i freq: %i delay: %i" | ||
685 | "\n", | ||
686 | timer_div_settings[cur], | ||
687 | timer_freq_settings[cur], | ||
688 | timer_delay_settings[cur] | ||
689 | ); | ||
690 | #endif | ||
691 | #ifdef FAST_TIMER_LOG | ||
692 | t = &timer_started_log[cur]; | ||
693 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
694 | "d: %6li us data: 0x%08lX" | ||
695 | "\n", | ||
696 | t->name, | ||
697 | (unsigned long)t->tv_set.tv_sec, | ||
698 | (unsigned long)t->tv_set.tv_usec, | ||
699 | (unsigned long)t->tv_expires.tv_sec, | ||
700 | (unsigned long)t->tv_expires.tv_usec, | ||
701 | t->delay_us, | ||
702 | t->data | ||
703 | ); | ||
704 | #endif | ||
705 | } | ||
706 | used += sprintf(bigbuf + used, "\n"); | ||
707 | |||
708 | #ifdef FAST_TIMER_LOG | ||
709 | num_to_show = (fast_timers_added < NUM_TIMER_STATS ? fast_timers_added: | ||
710 | NUM_TIMER_STATS); | ||
711 | used += sprintf(bigbuf + used, "Timers added: %i\n", fast_timers_added); | ||
712 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) | ||
713 | { | ||
714 | t = &timer_added_log[(fast_timers_added - i - 1) % NUM_TIMER_STATS]; | ||
715 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
716 | "d: %6li us data: 0x%08lX" | ||
717 | "\n", | ||
718 | t->name, | ||
719 | (unsigned long)t->tv_set.tv_sec, | ||
720 | (unsigned long)t->tv_set.tv_usec, | ||
721 | (unsigned long)t->tv_expires.tv_sec, | ||
722 | (unsigned long)t->tv_expires.tv_usec, | ||
723 | t->delay_us, | ||
724 | t->data | ||
725 | ); | ||
726 | } | ||
727 | used += sprintf(bigbuf + used, "\n"); | ||
728 | |||
729 | num_to_show = (fast_timers_expired < NUM_TIMER_STATS ? fast_timers_expired: | ||
730 | NUM_TIMER_STATS); | ||
731 | used += sprintf(bigbuf + used, "Timers expired: %i\n", fast_timers_expired); | ||
732 | for (i = 0; i < num_to_show && (used+100 < BIG_BUF_SIZE); i++) | ||
733 | { | ||
734 | t = &timer_expired_log[(fast_timers_expired - i - 1) % NUM_TIMER_STATS]; | ||
735 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
736 | "d: %6li us data: 0x%08lX" | ||
737 | "\n", | ||
738 | t->name, | ||
739 | (unsigned long)t->tv_set.tv_sec, | ||
740 | (unsigned long)t->tv_set.tv_usec, | ||
741 | (unsigned long)t->tv_expires.tv_sec, | ||
742 | (unsigned long)t->tv_expires.tv_usec, | ||
743 | t->delay_us, | ||
744 | t->data | ||
745 | ); | ||
746 | } | ||
747 | used += sprintf(bigbuf + used, "\n"); | ||
748 | #endif | ||
749 | |||
750 | used += sprintf(bigbuf + used, "Active timers:\n"); | ||
751 | save_flags(flags); | ||
752 | cli(); | ||
753 | t = fast_timer_list; | ||
754 | while (t != NULL && (used+100 < BIG_BUF_SIZE)) | ||
755 | { | ||
756 | nextt = t->next; | ||
757 | restore_flags(flags); | ||
758 | used += sprintf(bigbuf + used, "%-14s s: %6lu.%06lu e: %6lu.%06lu " | ||
759 | "d: %6li us data: 0x%08lX" | ||
760 | /* " func: 0x%08lX" */ | ||
761 | "\n", | ||
762 | t->name, | ||
763 | (unsigned long)t->tv_set.tv_sec, | ||
764 | (unsigned long)t->tv_set.tv_usec, | ||
765 | (unsigned long)t->tv_expires.tv_sec, | ||
766 | (unsigned long)t->tv_expires.tv_usec, | ||
767 | t->delay_us, | ||
768 | t->data | ||
769 | /* , t->function */ | ||
770 | ); | ||
771 | cli(); | ||
772 | if (t->next != nextt) | ||
773 | { | ||
774 | printk(KERN_WARNING "timer removed!\n"); | ||
775 | } | ||
776 | t = nextt; | ||
777 | } | ||
778 | restore_flags(flags); | ||
779 | } | ||
780 | |||
781 | if (used - offset < len) | ||
782 | { | ||
783 | len = used - offset; | ||
784 | } | ||
785 | |||
786 | memcpy(buf, bigbuf + offset, len); | ||
787 | *start = buf; | ||
788 | *eof = 1; | ||
789 | |||
790 | return len; | ||
791 | } | ||
792 | #endif /* PROC_FS */ | ||
793 | |||
794 | #ifdef FAST_TIMER_TEST | ||
795 | static volatile unsigned long i = 0; | ||
796 | static volatile int num_test_timeout = 0; | ||
797 | static struct fast_timer tr[10]; | ||
798 | static int exp_num[10]; | ||
799 | |||
800 | static struct timeval tv_exp[100]; | ||
801 | |||
802 | static void test_timeout(unsigned long data) | ||
803 | { | ||
804 | do_gettimeofday_fast(&tv_exp[data]); | ||
805 | exp_num[data] = num_test_timeout; | ||
806 | |||
807 | num_test_timeout++; | ||
808 | } | ||
809 | |||
810 | static void test_timeout1(unsigned long data) | ||
811 | { | ||
812 | do_gettimeofday_fast(&tv_exp[data]); | ||
813 | exp_num[data] = num_test_timeout; | ||
814 | if (data < 7) | ||
815 | { | ||
816 | start_one_shot_timer(&tr[i], test_timeout1, i, 1000, "timeout1"); | ||
817 | i++; | ||
818 | } | ||
819 | num_test_timeout++; | ||
820 | } | ||
821 | |||
822 | DP( | ||
823 | static char buf0[2000]; | ||
824 | static char buf1[2000]; | ||
825 | static char buf2[2000]; | ||
826 | static char buf3[2000]; | ||
827 | static char buf4[2000]; | ||
828 | ); | ||
829 | |||
830 | static char buf5[6000]; | ||
831 | static int j_u[1000]; | ||
832 | |||
833 | static void fast_timer_test(void) | ||
834 | { | ||
835 | int prev_num; | ||
836 | int j; | ||
837 | |||
838 | struct timeval tv, tv0, tv1, tv2; | ||
839 | |||
840 | printk("fast_timer_test() start\n"); | ||
841 | do_gettimeofday_fast(&tv); | ||
842 | |||
843 | for (j = 0; j < 1000; j++) | ||
844 | { | ||
845 | j_u[j] = GET_JIFFIES_USEC(); | ||
846 | } | ||
847 | for (j = 0; j < 100; j++) | ||
848 | { | ||
849 | do_gettimeofday_fast(&tv_exp[j]); | ||
850 | } | ||
851 | printk("fast_timer_test() %is %06i\n", tv.tv_sec, tv.tv_usec); | ||
852 | |||
853 | for (j = 0; j < 1000; j++) | ||
854 | { | ||
855 | printk("%i %i %i %i %i\n",j_u[j], j_u[j+1], j_u[j+2], j_u[j+3], j_u[j+4]); | ||
856 | j += 4; | ||
857 | } | ||
858 | for (j = 0; j < 100; j++) | ||
859 | { | ||
860 | printk("%i.%i %i.%i %i.%i %i.%i %i.%i\n", | ||
861 | tv_exp[j].tv_sec,tv_exp[j].tv_usec, | ||
862 | tv_exp[j+1].tv_sec,tv_exp[j+1].tv_usec, | ||
863 | tv_exp[j+2].tv_sec,tv_exp[j+2].tv_usec, | ||
864 | tv_exp[j+3].tv_sec,tv_exp[j+3].tv_usec, | ||
865 | tv_exp[j+4].tv_sec,tv_exp[j+4].tv_usec); | ||
866 | j += 4; | ||
867 | } | ||
868 | do_gettimeofday_fast(&tv0); | ||
869 | start_one_shot_timer(&tr[i], test_timeout, i, 50000, "test0"); | ||
870 | DP(proc_fasttimer_read(buf0, NULL, 0, 0, 0)); | ||
871 | i++; | ||
872 | start_one_shot_timer(&tr[i], test_timeout, i, 70000, "test1"); | ||
873 | DP(proc_fasttimer_read(buf1, NULL, 0, 0, 0)); | ||
874 | i++; | ||
875 | start_one_shot_timer(&tr[i], test_timeout, i, 40000, "test2"); | ||
876 | DP(proc_fasttimer_read(buf2, NULL, 0, 0, 0)); | ||
877 | i++; | ||
878 | start_one_shot_timer(&tr[i], test_timeout, i, 60000, "test3"); | ||
879 | DP(proc_fasttimer_read(buf3, NULL, 0, 0, 0)); | ||
880 | i++; | ||
881 | start_one_shot_timer(&tr[i], test_timeout1, i, 55000, "test4xx"); | ||
882 | DP(proc_fasttimer_read(buf4, NULL, 0, 0, 0)); | ||
883 | i++; | ||
884 | do_gettimeofday_fast(&tv1); | ||
885 | |||
886 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | ||
887 | |||
888 | prev_num = num_test_timeout; | ||
889 | while (num_test_timeout < i) | ||
890 | { | ||
891 | if (num_test_timeout != prev_num) | ||
892 | { | ||
893 | prev_num = num_test_timeout; | ||
894 | } | ||
895 | } | ||
896 | do_gettimeofday_fast(&tv2); | ||
897 | printk("Timers started %is %06i\n", tv0.tv_sec, tv0.tv_usec); | ||
898 | printk("Timers started at %is %06i\n", tv1.tv_sec, tv1.tv_usec); | ||
899 | printk("Timers done %is %06i\n", tv2.tv_sec, tv2.tv_usec); | ||
900 | DP(printk("buf0:\n"); | ||
901 | printk(buf0); | ||
902 | printk("buf1:\n"); | ||
903 | printk(buf1); | ||
904 | printk("buf2:\n"); | ||
905 | printk(buf2); | ||
906 | printk("buf3:\n"); | ||
907 | printk(buf3); | ||
908 | printk("buf4:\n"); | ||
909 | printk(buf4); | ||
910 | ); | ||
911 | printk("buf5:\n"); | ||
912 | printk(buf5); | ||
913 | |||
914 | printk("timers set:\n"); | ||
915 | for(j = 0; j<i; j++) | ||
916 | { | ||
917 | struct fast_timer *t = &tr[j]; | ||
918 | printk("%-10s set: %6is %06ius exp: %6is %06ius " | ||
919 | "data: 0x%08X func: 0x%08X\n", | ||
920 | t->name, | ||
921 | t->tv_set.tv_sec, | ||
922 | t->tv_set.tv_usec, | ||
923 | t->tv_expires.tv_sec, | ||
924 | t->tv_expires.tv_usec, | ||
925 | t->data, | ||
926 | t->function | ||
927 | ); | ||
928 | |||
929 | printk(" del: %6ius did exp: %6is %06ius as #%i error: %6li\n", | ||
930 | t->delay_us, | ||
931 | tv_exp[j].tv_sec, | ||
932 | tv_exp[j].tv_usec, | ||
933 | exp_num[j], | ||
934 | (tv_exp[j].tv_sec - t->tv_expires.tv_sec)*1000000 + tv_exp[j].tv_usec - t->tv_expires.tv_usec); | ||
935 | } | ||
936 | proc_fasttimer_read(buf5, NULL, 0, 0, 0); | ||
937 | printk("buf5 after all done:\n"); | ||
938 | printk(buf5); | ||
939 | printk("fast_timer_test() done\n"); | ||
940 | } | ||
941 | #endif | ||
942 | |||
943 | |||
944 | void fast_timer_init(void) | ||
945 | { | ||
946 | /* For some reason, request_irq() hangs when called froom time_init() */ | ||
947 | if (!fast_timer_is_init) | ||
948 | { | ||
949 | #if 0 && defined(FAST_TIMER_TEST) | ||
950 | int i; | ||
951 | #endif | ||
952 | |||
953 | printk(KERN_INFO "fast_timer_init()\n"); | ||
954 | |||
955 | #if 0 && defined(FAST_TIMER_TEST) | ||
956 | for (i = 0; i <= TIMER0_DIV; i++) | ||
957 | { | ||
958 | /* We must be careful not to get overflow... */ | ||
959 | printk("%3i %6u\n", i, timer0_value_us[i]); | ||
960 | } | ||
961 | #endif | ||
962 | #ifdef CONFIG_PROC_FS | ||
963 | if ((fasttimer_proc_entry = create_proc_entry( "fasttimer", 0, 0 ))) | ||
964 | fasttimer_proc_entry->read_proc = proc_fasttimer_read; | ||
965 | #endif /* PROC_FS */ | ||
966 | if(request_irq(TIMER1_IRQ_NBR, timer1_handler, SA_SHIRQ, | ||
967 | "fast timer int", NULL)) | ||
968 | { | ||
969 | printk("err: timer1 irq\n"); | ||
970 | } | ||
971 | fast_timer_is_init = 1; | ||
972 | #ifdef FAST_TIMER_TEST | ||
973 | printk("do test\n"); | ||
974 | fast_timer_test(); | ||
975 | #endif | ||
976 | } | ||
977 | } | ||
diff --git a/arch/cris/arch-v10/kernel/head.S b/arch/cris/arch-v10/kernel/head.S new file mode 100644 index 000000000000..2c1dd1184a8f --- /dev/null +++ b/arch/cris/arch-v10/kernel/head.S | |||
@@ -0,0 +1,882 @@ | |||
1 | /* $Id: head.S,v 1.7 2004/05/14 07:58:01 starvik Exp $ | ||
2 | * | ||
3 | * Head of the kernel - alter with care | ||
4 | * | ||
5 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * $Log: head.S,v $ | ||
10 | * Revision 1.7 2004/05/14 07:58:01 starvik | ||
11 | * Merge of changes from 2.4 | ||
12 | * | ||
13 | * Revision 1.6 2003/04/28 05:31:46 starvik | ||
14 | * Added section attributes | ||
15 | * | ||
16 | * Revision 1.5 2002/12/11 15:42:02 starvik | ||
17 | * Extracted v10 (ETRAX 100LX) specific stuff from arch/cris/kernel/*.c | ||
18 | * | ||
19 | * Revision 1.4 2002/11/07 09:00:44 starvik | ||
20 | * Names changed for init sections | ||
21 | * init_task_union -> init_thread_union | ||
22 | * | ||
23 | * Revision 1.3 2002/02/05 15:38:23 bjornw | ||
24 | * Oops.. non-CRAMFS_MAGIC should jump over the copying, not into it... | ||
25 | * | ||
26 | * Revision 1.2 2001/12/18 13:35:19 bjornw | ||
27 | * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). | ||
28 | * | ||
29 | * Revision 1.43 2001/11/08 15:09:43 starvik | ||
30 | * Only start MII clock if Ethernet is configured | ||
31 | * | ||
32 | * Revision 1.42 2001/11/08 14:37:34 starvik | ||
33 | * Start MII clock early to make sure that it is running at tranceiver reset | ||
34 | * | ||
35 | * Revision 1.41 2001/10/29 14:55:58 pkj | ||
36 | * Corrected pa$r0 to par0. | ||
37 | * | ||
38 | * Revision 1.40 2001/10/03 14:59:57 pkj | ||
39 | * Added support for resetting the Bluetooth hardware. | ||
40 | * | ||
41 | * Revision 1.39 2001/10/01 14:45:03 bjornw | ||
42 | * Removed underscores and added register prefixes | ||
43 | * | ||
44 | * Revision 1.38 2001/09/21 07:14:11 jonashg | ||
45 | * Made root filesystem (cramfs) use mtdblock driver when booting from flash. | ||
46 | * | ||
47 | * Revision 1.37 2001/09/11 13:44:29 orjanf | ||
48 | * Decouple usage of serial ports for debug and kgdb. | ||
49 | * | ||
50 | * Revision 1.36 2001/06/29 12:39:31 pkj | ||
51 | * Added support for mirroring the first flash to just below the | ||
52 | * second one, to make them look consecutive to cramfs. | ||
53 | * | ||
54 | * Revision 1.35 2001/06/25 14:07:00 hp | ||
55 | * Fix review comment. | ||
56 | * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of | ||
57 | * magic numbers. Add comment that -traditional must not be used. | ||
58 | * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. | ||
59 | * Correct and update comment. | ||
60 | * * Makefile (.S.o): Don't use -traditional. Add comment why the | ||
61 | * toplevel rule can't be used (now that there's a reason). | ||
62 | * | ||
63 | * Revision 1.34 2001/05/15 07:08:14 hp | ||
64 | * Tweak "notice" to reflect that both r8 r9 are used | ||
65 | * | ||
66 | * Revision 1.33 2001/05/15 06:40:05 hp | ||
67 | * Put bulk of code in .text.init, data in .data.init | ||
68 | * | ||
69 | * Revision 1.32 2001/05/15 06:18:56 hp | ||
70 | * Execute review comment: s/bcc/bhs/g; s/bcs/blo/g | ||
71 | * | ||
72 | * Revision 1.31 2001/05/15 06:08:40 hp | ||
73 | * Add sentence about autodetecting the bit31-MMU-bug | ||
74 | * | ||
75 | * Revision 1.30 2001/05/15 06:00:05 hp | ||
76 | * Update comment: LOW_MAP is not forced on xsim anymore. | ||
77 | * | ||
78 | * Revision 1.29 2001/04/18 12:51:59 orjanf | ||
79 | * * Reverted review change regarding the use of bcs/bcc. | ||
80 | * * Removed non-working LED-clearing code. | ||
81 | * | ||
82 | * Revision 1.28 2001/04/17 13:58:39 orjanf | ||
83 | * * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
84 | * | ||
85 | * Revision 1.27 2001/04/17 11:42:35 orjanf | ||
86 | * Changed according to review: | ||
87 | * * Added comment explaining memory map bug. | ||
88 | * * Changed bcs and bcc to blo and bhs, respectively. | ||
89 | * * Removed mentioning of Stallone and Olga boards. | ||
90 | * | ||
91 | * Revision 1.26 2001/04/06 12:31:07 jonashg | ||
92 | * Check for cramfs in flash before RAM instead of RAM before flash. | ||
93 | * | ||
94 | * Revision 1.25 2001/04/04 06:23:53 starvik | ||
95 | * Initialize DRAM if not already initialized | ||
96 | * | ||
97 | * Revision 1.24 2001/04/03 11:12:00 starvik | ||
98 | * Removed dram init (done by rescue or etrax100boot | ||
99 | * Corrected include | ||
100 | * | ||
101 | * Revision 1.23 2001/04/03 09:53:03 starvik | ||
102 | * Include hw_settings.S | ||
103 | * | ||
104 | * Revision 1.22 2001/03/26 14:23:26 bjornw | ||
105 | * Namechange of some config options | ||
106 | * | ||
107 | * Revision 1.21 2001/03/08 12:14:41 bjornw | ||
108 | * * Config name for ETRAX IDE was renamed | ||
109 | * * Removed G27 auto-setting when JULIETTE is chosen (need to make this | ||
110 | * a new config option later) | ||
111 | * | ||
112 | * Revision 1.20 2001/02/23 12:47:56 bjornw | ||
113 | * MMU regs during LOW_MAP updated to reflect a newer reality | ||
114 | * | ||
115 | * Revision 1.19 2001/02/19 11:12:07 bjornw | ||
116 | * Changed comment header format | ||
117 | * | ||
118 | * Revision 1.18 2001/02/15 07:25:38 starvik | ||
119 | * Added support for synchronous serial ports | ||
120 | * | ||
121 | * Revision 1.17 2001/02/08 15:53:13 starvik | ||
122 | * Last commit removed some important ifdefs | ||
123 | * | ||
124 | * Revision 1.16 2001/02/08 15:20:38 starvik | ||
125 | * Include dram_init.S as inline | ||
126 | * | ||
127 | * Revision 1.15 2001/01/29 18:12:01 bjornw | ||
128 | * Corrected some comments | ||
129 | * | ||
130 | * Revision 1.14 2001/01/29 13:11:29 starvik | ||
131 | * Include dram_init.S (with DRAM/SDRAM initialization) | ||
132 | * | ||
133 | * Revision 1.13 2001/01/23 14:54:57 markusl | ||
134 | * Updated for USB | ||
135 | * i.e. added r_gen_config settings | ||
136 | * | ||
137 | * Revision 1.12 2001/01/19 16:16:29 perf | ||
138 | * Added temporary mapping of 0x0c->0x0c to avoid flash loading confusion. | ||
139 | * Renamed serial options from ETRAX100 to ETRAX. | ||
140 | * | ||
141 | * Revision 1.11 2001/01/16 16:31:38 bjornw | ||
142 | * * Changed name and semantics of running_from_flash to romfs_in_flash, | ||
143 | * set by head.S to indicate to setup.c whether there is a cramfs image | ||
144 | * after the kernels BSS or not. Should work for all three boot-cases | ||
145 | * (DRAM with cramfs in DRAM, DRAM with cramfs in flash (compressed boot), | ||
146 | * and flash with cramfs in flash) | ||
147 | * | ||
148 | * Revision 1.10 2001/01/16 14:12:21 bjornw | ||
149 | * * Check for cramfs start passed in r9 from the decompressor, if all other | ||
150 | * cramfs options fail (if we boot from DRAM but don't find a cramfs image | ||
151 | * after the kernel in DRAM, it is probably still in the flash) | ||
152 | * * Check magic in cramfs detection when booting from flash directly | ||
153 | * | ||
154 | * Revision 1.9 2001/01/15 17:17:02 bjornw | ||
155 | * * Corrected the code that detects the cramfs lengths | ||
156 | * * Added a comment saying that the above does not work due to other | ||
157 | * reasons.. | ||
158 | * | ||
159 | * Revision 1.8 2001/01/15 16:27:51 jonashg | ||
160 | * Made boot after flashing work. | ||
161 | * * end destination is __vmlinux_end in RAM. | ||
162 | * * _romfs_start moved because of virtual memory. | ||
163 | * | ||
164 | * Revision 1.7 2000/11/21 13:55:29 bjornw | ||
165 | * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type | ||
166 | * | ||
167 | * Revision 1.6 2000/10/06 12:36:55 bjornw | ||
168 | * Forgot swapper_pg_dir when changing memory map.. | ||
169 | * | ||
170 | * Revision 1.5 2000/10/04 16:49:30 bjornw | ||
171 | * * Fixed memory mapping in LX | ||
172 | * * Check for cramfs instead of romfs | ||
173 | * | ||
174 | */ | ||
175 | |||
176 | #include <linux/config.h> | ||
177 | #define ASSEMBLER_MACROS_ONLY | ||
178 | /* The IO_* macros use the ## token concatenation operator, so | ||
179 | -traditional must not be used when assembling this file. */ | ||
180 | #include <asm/arch/sv_addr_ag.h> | ||
181 | |||
182 | #define CRAMFS_MAGIC 0x28cd3d45 | ||
183 | #define RAM_INIT_MAGIC 0x56902387 | ||
184 | |||
185 | #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\ | ||
186 | IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk) | ||
187 | |||
188 | ;; exported symbols | ||
189 | |||
190 | .globl etrax_irv | ||
191 | .globl romfs_start | ||
192 | .globl romfs_length | ||
193 | .globl romfs_in_flash | ||
194 | .globl swapper_pg_dir | ||
195 | |||
196 | .text | ||
197 | |||
198 | ;; This is the entry point of the kernel. We are in supervisor mode. | ||
199 | ;; 0x00000000 if Flash, 0x40004000 if DRAM | ||
200 | ;; since etrax actually starts at address 2 when booting from flash, we | ||
201 | ;; put a nop (2 bytes) here first so we dont accidentally skip the di | ||
202 | ;; | ||
203 | ;; NOTICE! The registers r8 and r9 are used as parameters carrying | ||
204 | ;; information from the decompressor (if the kernel was compressed). | ||
205 | ;; They should not be used in the code below until read. | ||
206 | |||
207 | nop | ||
208 | di | ||
209 | |||
210 | ;; First setup the kseg_c mapping from where the kernel is linked | ||
211 | ;; to 0x40000000 (where the actual DRAM resides) otherwise | ||
212 | ;; we cannot do very much! See arch/cris/README.mm | ||
213 | ;; | ||
214 | ;; Notice that since we're potentially running at 0x00 or 0x40 right now, | ||
215 | ;; we will get a fault as soon as we enable the MMU if we dont | ||
216 | ;; temporarily map those segments linearily. | ||
217 | ;; | ||
218 | ;; Due to a bug in Etrax-100 LX version 1 we need to map the memory | ||
219 | ;; slightly different. The bug is that you can't remap bit 31 of | ||
220 | ;; an address. Though we can check the version register for | ||
221 | ;; whether the bug is present, some constants would then have to | ||
222 | ;; be variables, so we don't. The drawback is that you can "only" map | ||
223 | ;; 1G per process with CONFIG_CRIS_LOW_MAP. | ||
224 | |||
225 | #ifdef CONFIG_CRIS_LOW_MAP | ||
226 | ; kseg mappings, temporary map of 0xc0->0x40 | ||
227 | move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | ||
228 | | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \ | ||
229 | | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \ | ||
230 | | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0 | ||
231 | move.d $r0, [R_MMU_KBASE_HI] | ||
232 | |||
233 | ; temporary map of 0x40->0x40 and 0x60->0x40 | ||
234 | move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ | ||
235 | | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 | ||
236 | move.d $r0, [R_MMU_KBASE_LO] | ||
237 | |||
238 | ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped | ||
239 | move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | ||
240 | | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | ||
241 | | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | ||
242 | | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ | ||
243 | | IO_STATE (R_MMU_CONFIG, seg_f, page) \ | ||
244 | | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ | ||
245 | | IO_STATE (R_MMU_CONFIG, seg_d, page) \ | ||
246 | | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ | ||
247 | | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ | ||
248 | | IO_STATE (R_MMU_CONFIG, seg_a, seg) \ | ||
249 | | IO_STATE (R_MMU_CONFIG, seg_9, page) \ | ||
250 | | IO_STATE (R_MMU_CONFIG, seg_8, page) \ | ||
251 | | IO_STATE (R_MMU_CONFIG, seg_7, page) \ | ||
252 | | IO_STATE (R_MMU_CONFIG, seg_6, seg) \ | ||
253 | | IO_STATE (R_MMU_CONFIG, seg_5, seg) \ | ||
254 | | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ | ||
255 | | IO_STATE (R_MMU_CONFIG, seg_3, page) \ | ||
256 | | IO_STATE (R_MMU_CONFIG, seg_2, page) \ | ||
257 | | IO_STATE (R_MMU_CONFIG, seg_1, page) \ | ||
258 | | IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0 | ||
259 | move.d $r0, [R_MMU_CONFIG] | ||
260 | #else | ||
261 | ; kseg mappings | ||
262 | move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ | ||
263 | | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ | ||
264 | | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0 | ||
265 | move.d $r0, [R_MMU_KBASE_HI] | ||
266 | |||
267 | ; temporary map of 0x40->0x40 and 0x00->0x00 | ||
268 | move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0 | ||
269 | move.d $r0, [R_MMU_KBASE_LO] | ||
270 | |||
271 | ; mmu enable, segs f,e,c,b,4,0 segment mapped | ||
272 | move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ | ||
273 | | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ | ||
274 | | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ | ||
275 | | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ | ||
276 | | IO_STATE (R_MMU_CONFIG, seg_f, seg) \ | ||
277 | | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ | ||
278 | | IO_STATE (R_MMU_CONFIG, seg_d, page) \ | ||
279 | | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ | ||
280 | | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ | ||
281 | | IO_STATE (R_MMU_CONFIG, seg_a, page) \ | ||
282 | | IO_STATE (R_MMU_CONFIG, seg_9, page) \ | ||
283 | | IO_STATE (R_MMU_CONFIG, seg_8, page) \ | ||
284 | | IO_STATE (R_MMU_CONFIG, seg_7, page) \ | ||
285 | | IO_STATE (R_MMU_CONFIG, seg_6, page) \ | ||
286 | | IO_STATE (R_MMU_CONFIG, seg_5, page) \ | ||
287 | | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ | ||
288 | | IO_STATE (R_MMU_CONFIG, seg_3, page) \ | ||
289 | | IO_STATE (R_MMU_CONFIG, seg_2, page) \ | ||
290 | | IO_STATE (R_MMU_CONFIG, seg_1, page) \ | ||
291 | | IO_STATE (R_MMU_CONFIG, seg_0, seg), $r0 | ||
292 | move.d $r0, [R_MMU_CONFIG] | ||
293 | #endif | ||
294 | |||
295 | ;; Now we need to sort out the segments and their locations in RAM or | ||
296 | ;; Flash. The image in the Flash (or in DRAM) consists of 3 pieces: | ||
297 | ;; 1) kernel text, 2) kernel data, 3) ROM filesystem image | ||
298 | ;; But the linker has linked the kernel to expect this layout in | ||
299 | ;; DRAM memory: | ||
300 | ;; 1) kernel text, 2) kernel data, 3) kernel BSS | ||
301 | ;; (the location of the ROM filesystem is determined by the krom driver) | ||
302 | ;; If we boot this from Flash, we want to keep the ROM filesystem in | ||
303 | ;; the flash, we want to copy the text and need to copy the data to DRAM. | ||
304 | ;; But if we boot from DRAM, we need to move the ROMFS image | ||
305 | ;; from its position after kernel data, to after kernel BSS, BEFORE the | ||
306 | ;; kernel starts using the BSS area (since its "overlayed" with the ROMFS) | ||
307 | ;; | ||
308 | ;; In both cases, we start in un-cached mode, and need to jump into a | ||
309 | ;; cached PC after we're done fiddling around with the segments. | ||
310 | ;; | ||
311 | ;; arch/etrax100/etrax100.ld sets some symbols that define the start | ||
312 | ;; and end of each segment. | ||
313 | |||
314 | ;; Check if we start from DRAM or FLASH by testing PC | ||
315 | |||
316 | move.d $pc,$r0 | ||
317 | and.d 0x7fffffff,$r0 ; get rid of the non-cache bit | ||
318 | cmp.d 0x10000,$r0 ; arbitrary... just something above this code | ||
319 | blo _inflash0 | ||
320 | nop | ||
321 | |||
322 | jump _inram ; enter cached ram | ||
323 | |||
324 | ;; Jumpgate for branches. | ||
325 | _inflash0: | ||
326 | jump _inflash | ||
327 | |||
328 | ;; Put this in a suitable section where we can reclaim storage | ||
329 | ;; after init. | ||
330 | .section ".init.text", "ax" | ||
331 | _inflash: | ||
332 | #ifdef CONFIG_ETRAX_ETHERNET | ||
333 | ;; Start MII clock to make sure it is running when tranceiver is reset | ||
334 | move.d START_ETHERNET_CLOCK, $r0 | ||
335 | move.d $r0, [R_NETWORK_GEN_CONFIG] | ||
336 | #endif | ||
337 | |||
338 | ;; Set up waitstates etc according to kernel configuration. | ||
339 | #ifndef CONFIG_SVINTO_SIM | ||
340 | move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 | ||
341 | move.d $r0, [R_WAITSTATES] | ||
342 | |||
343 | move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 | ||
344 | move.d $r0, [R_BUS_CONFIG] | ||
345 | #endif | ||
346 | |||
347 | ;; We need to initialze DRAM registers before we start using the DRAM | ||
348 | |||
349 | cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? | ||
350 | beq _dram_init_finished | ||
351 | nop | ||
352 | |||
353 | #include "../lib/dram_init.S" | ||
354 | |||
355 | _dram_init_finished: | ||
356 | ;; Copy text+data to DRAM | ||
357 | ;; This is fragile - the calculation of r4 as the image size depends | ||
358 | ;; on that the labels below actually are the first and last positions | ||
359 | ;; in the linker-script. | ||
360 | ;; | ||
361 | ;; Then the locating of the cramfs image depends on the aforementioned | ||
362 | ;; image being located in the flash at 0. This is most often not true, | ||
363 | ;; thus the following does not work (normally there is a rescue-block | ||
364 | ;; between the physical start of the flash and the flash-image start, | ||
365 | ;; and when run with compression, the kernel is actually unpacked to | ||
366 | ;; DRAM and we never get here in the first place :)) | ||
367 | |||
368 | moveq 0, $r0 ; source | ||
369 | move.d text_start, $r1 ; destination | ||
370 | move.d __vmlinux_end, $r2 ; end destination | ||
371 | move.d $r2, $r4 | ||
372 | sub.d $r1, $r4 ; r4=__vmlinux_end in flash, used below | ||
373 | 1: move.w [$r0+], $r3 | ||
374 | move.w $r3, [$r1+] | ||
375 | cmp.d $r2, $r1 | ||
376 | blo 1b | ||
377 | nop | ||
378 | |||
379 | ;; We keep the cramfs in the flash. | ||
380 | ;; There might be none, but that does not matter because | ||
381 | ;; we don't do anything than read some bytes here. | ||
382 | |||
383 | moveq 0, $r0 | ||
384 | move.d $r0, [romfs_length] ; default if there is no cramfs | ||
385 | |||
386 | move.d [$r4], $r0 ; cramfs_super.magic | ||
387 | cmp.d CRAMFS_MAGIC, $r0 | ||
388 | bne 1f | ||
389 | nop | ||
390 | move.d [$r4 + 4], $r0 ; cramfs_super.size | ||
391 | move.d $r0, [romfs_length] | ||
392 | #ifdef CONFIG_CRIS_LOW_MAP | ||
393 | add.d 0x50000000, $r4 ; add flash start in virtual memory (cached) | ||
394 | #else | ||
395 | add.d 0xf0000000, $r4 ; add flash start in virtual memory (cached) | ||
396 | #endif | ||
397 | move.d $r4, [romfs_start] | ||
398 | 1: | ||
399 | moveq 1, $r0 | ||
400 | move.d $r0, [romfs_in_flash] | ||
401 | |||
402 | jump _start_it ; enter code, cached this time | ||
403 | |||
404 | _inram: | ||
405 | ;; Move the ROM fs to after BSS end. This assumes that the cramfs | ||
406 | ;; second longword contains the length of the cramfs | ||
407 | |||
408 | moveq 0, $r0 | ||
409 | move.d $r0, [romfs_length] ; default if there is no cramfs | ||
410 | |||
411 | ;; The kernel could have been unpacked to DRAM by the loader, but | ||
412 | ;; the cramfs image could still be in the Flash directly after the | ||
413 | ;; compressed kernel image. The loader passes the address of the | ||
414 | ;; byte succeeding the last compressed byte in the flash in the | ||
415 | ;; register r9 when starting the kernel. Check if r9 points to a | ||
416 | ;; decent cramfs image! | ||
417 | ;; (Notice that if this is not booted from the loader, r9 will be | ||
418 | ;; garbage but we do sanity checks on it, the chance that it points | ||
419 | ;; to a cramfs magic is small.. ) | ||
420 | |||
421 | cmp.d 0x0ffffff8, $r9 | ||
422 | bhs _no_romfs_in_flash ; r9 points outside the flash area | ||
423 | nop | ||
424 | move.d [$r9], $r0 ; cramfs_super.magic | ||
425 | cmp.d CRAMFS_MAGIC, $r0 | ||
426 | bne _no_romfs_in_flash | ||
427 | nop | ||
428 | move.d [$r9+4], $r0 ; cramfs_super.length | ||
429 | move.d $r0, [romfs_length] | ||
430 | #ifdef CONFIG_CRIS_LOW_MAP | ||
431 | add.d 0x50000000, $r9 ; add flash start in virtual memory (cached) | ||
432 | #else | ||
433 | add.d 0xf0000000, $r9 ; add flash start in virtual memory (cached) | ||
434 | #endif | ||
435 | move.d $r9, [romfs_start] | ||
436 | |||
437 | moveq 1, $r0 | ||
438 | move.d $r0, [romfs_in_flash] | ||
439 | |||
440 | jump _start_it ; enter code, cached this time | ||
441 | |||
442 | _no_romfs_in_flash: | ||
443 | |||
444 | ;; Check if there is a cramfs (magic value). | ||
445 | ;; Notice that we check for cramfs magic value - which is | ||
446 | ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does | ||
447 | ;; not need this mechanism anyway) | ||
448 | |||
449 | move.d __vmlinux_end, $r0; the image will be after the vmlinux end address | ||
450 | move.d [$r0], $r1 ; cramfs assumes same endian on host/target | ||
451 | cmp.d CRAMFS_MAGIC, $r1; magic value in cramfs superblock | ||
452 | bne 2f | ||
453 | nop | ||
454 | |||
455 | ;; Ok. What is its size ? | ||
456 | |||
457 | move.d [$r0 + 4], $r2 ; cramfs_super.size (again, no need to swapwb) | ||
458 | |||
459 | ;; We want to copy it to the end of the BSS | ||
460 | |||
461 | move.d _end, $r1 | ||
462 | |||
463 | ;; Remember values so cramfs and setup can find this info | ||
464 | |||
465 | move.d $r1, [romfs_start] ; new romfs location | ||
466 | move.d $r2, [romfs_length] | ||
467 | |||
468 | ;; We need to copy it backwards, since they can be overlapping | ||
469 | |||
470 | add.d $r2, $r0 | ||
471 | add.d $r2, $r1 | ||
472 | |||
473 | ;; Go ahead. Make my loop. | ||
474 | |||
475 | lsrq 1, $r2 ; size is in bytes, we copy words | ||
476 | |||
477 | 1: move.w [$r0=$r0-2],$r3 | ||
478 | move.w $r3,[$r1=$r1-2] | ||
479 | subq 1, $r2 | ||
480 | bne 1b | ||
481 | nop | ||
482 | |||
483 | 2: | ||
484 | ;; Dont worry that the BSS is tainted. It will be cleared later. | ||
485 | |||
486 | moveq 0, $r0 | ||
487 | move.d $r0, [romfs_in_flash] | ||
488 | |||
489 | jump _start_it ; better skip the additional cramfs check below | ||
490 | |||
491 | _start_it: | ||
492 | |||
493 | ;; the kernel stack is overlayed with the task structure for each | ||
494 | ;; task. thus the initial kernel stack is in the same page as the | ||
495 | ;; init_task (but starts in the top of the page, size 8192) | ||
496 | move.d init_thread_union + 8192, $sp | ||
497 | move.d ibr_start,$r0 ; this symbol is set by the linker script | ||
498 | move $r0,$ibr | ||
499 | move.d $r0,[etrax_irv] ; set the interrupt base register and pointer | ||
500 | |||
501 | ;; Clear BSS region, from _bss_start to _end | ||
502 | |||
503 | move.d __bss_start, $r0 | ||
504 | move.d _end, $r1 | ||
505 | 1: clear.d [$r0+] | ||
506 | cmp.d $r1, $r0 | ||
507 | blo 1b | ||
508 | nop | ||
509 | |||
510 | #ifdef CONFIG_BLK_DEV_ETRAXIDE | ||
511 | ;; disable ATA before enabling it in genconfig below | ||
512 | moveq 0,$r0 | ||
513 | move.d $r0,[R_ATA_CTRL_DATA] | ||
514 | move.d $r0,[R_ATA_TRANSFER_CNT] | ||
515 | move.d $r0,[R_ATA_CONFIG] | ||
516 | #if 0 | ||
517 | move.d R_PORT_G_DATA, $r1 | ||
518 | move.d $r0, [$r1]; assert ATA bus-reset | ||
519 | nop | ||
520 | nop | ||
521 | nop | ||
522 | nop | ||
523 | nop | ||
524 | nop | ||
525 | move.d 0x08000000,$r0 | ||
526 | move.d $r0,[$r1] | ||
527 | #endif | ||
528 | #endif | ||
529 | |||
530 | #ifdef CONFIG_JULIETTE | ||
531 | ;; configure external DMA channel 0 before enabling it in genconfig | ||
532 | |||
533 | moveq 0,$r0 | ||
534 | move.d $r0,[R_EXT_DMA_0_ADDR] | ||
535 | ; cnt enable, word size, output, stop, size 0 | ||
536 | move.d IO_STATE (R_EXT_DMA_0_CMD, cnt, enable) \ | ||
537 | | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh) \ | ||
538 | | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh) \ | ||
539 | | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst) \ | ||
540 | | IO_STATE (R_EXT_DMA_0_CMD, wid, word) \ | ||
541 | | IO_STATE (R_EXT_DMA_0_CMD, dir, output) \ | ||
542 | | IO_STATE (R_EXT_DMA_0_CMD, run, stop) \ | ||
543 | | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),$r0 | ||
544 | move.d $r0,[R_EXT_DMA_0_CMD] | ||
545 | |||
546 | ;; reset dma4 and wait for completion | ||
547 | |||
548 | moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 | ||
549 | move.b $r0,[R_DMA_CH4_CMD] | ||
550 | 1: move.b [R_DMA_CH4_CMD],$r0 | ||
551 | and.b IO_MASK (R_DMA_CH4_CMD, cmd),$r0 | ||
552 | cmp.b IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0 | ||
553 | beq 1b | ||
554 | nop | ||
555 | |||
556 | ;; reset dma5 and wait for completion | ||
557 | |||
558 | moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 | ||
559 | move.b $r0,[R_DMA_CH5_CMD] | ||
560 | 1: move.b [R_DMA_CH5_CMD],$r0 | ||
561 | and.b IO_MASK (R_DMA_CH5_CMD, cmd),$r0 | ||
562 | cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0 | ||
563 | beq 1b | ||
564 | nop | ||
565 | #endif | ||
566 | |||
567 | ;; Etrax product HW genconfig setup | ||
568 | |||
569 | moveq 0,$r0 | ||
570 | #if (!defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT0)) \ | ||
571 | && !defined(CONFIG_DMA_MEMCPY) | ||
572 | ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA | ||
573 | or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ | ||
574 | | IO_STATE (R_GEN_CONFIG, dma6, serial0),$r0 | ||
575 | #endif | ||
576 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
577 | ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA | ||
578 | or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ | ||
579 | | IO_STATE (R_GEN_CONFIG, dma8, serial1),$r0 | ||
580 | #endif | ||
581 | #ifdef CONFIG_DMA_MEMCPY | ||
582 | ; 6/7 memory-memory DMA | ||
583 | or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ | ||
584 | | IO_STATE (R_GEN_CONFIG, dma6, intdma7),$r0 | ||
585 | #endif | ||
586 | #ifdef CONFIG_ETRAX_SERIAL_PORT2 | ||
587 | ; Enable serial port 2 | ||
588 | or.w IO_STATE (R_GEN_CONFIG, ser2, select),$r0 | ||
589 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
590 | ; DMA channels 2 and 3 to ser2, kgdb doesnt want DMA | ||
591 | or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ | ||
592 | | IO_STATE (R_GEN_CONFIG, dma2, serial2),$r0 | ||
593 | #endif | ||
594 | #endif | ||
595 | #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) | ||
596 | ; Enable serial port 3 | ||
597 | or.w IO_STATE (R_GEN_CONFIG, ser3, select),$r0 | ||
598 | #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
599 | ; DMA channels 4 and 5 to ser3, kgdb doesnt want DMA | ||
600 | or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ | ||
601 | | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0 | ||
602 | #endif | ||
603 | #endif | ||
604 | #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
605 | ; parport 0 enabled using DMA 2/3 | ||
606 | or.w IO_STATE (R_GEN_CONFIG, par0, select),$r0 | ||
607 | #endif | ||
608 | #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) | ||
609 | ; parport 1 enabled using DMA 4/5 | ||
610 | or.w IO_STATE (R_GEN_CONFIG, par1, select),$r0 | ||
611 | #endif | ||
612 | #ifdef CONFIG_ETRAX_IDE | ||
613 | ; DMA channels 2 and 3 to ATA, ATA enabled | ||
614 | or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ | ||
615 | | IO_STATE (R_GEN_CONFIG, dma2, ata) \ | ||
616 | | IO_STATE (R_GEN_CONFIG, ata, select),$r0 | ||
617 | #endif | ||
618 | |||
619 | #ifdef CONFIG_ETRAX_USB_HOST_PORT1 | ||
620 | ; Set the USB port 1 enable bit | ||
621 | or.d IO_STATE (R_GEN_CONFIG, usb1, select),$r0 | ||
622 | #endif | ||
623 | #ifdef CONFIG_ETRAX_USB_HOST_PORT2 | ||
624 | ; Set the USB port 2 enable bit | ||
625 | or.d IO_STATE (R_GEN_CONFIG, usb2, select),$r0 | ||
626 | #endif | ||
627 | #ifdef CONFIG_ETRAX_USB_HOST | ||
628 | ; Connect DMA channels 8 and 9 to USB | ||
629 | and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ | ||
630 | | IO_MASK (R_GEN_CONFIG, dma8))) \ | ||
631 | | IO_STATE (R_GEN_CONFIG, dma9, usb) \ | ||
632 | | IO_STATE (R_GEN_CONFIG, dma8, usb),$r0 | ||
633 | #endif | ||
634 | |||
635 | #ifdef CONFIG_JULIETTE | ||
636 | ; DMA channels 4 and 5 to EXTDMA0, for Juliette | ||
637 | or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ | ||
638 | | IO_STATE (R_GEN_CONFIG, dma4, extdma0),$r0 | ||
639 | #endif | ||
640 | |||
641 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G0_DIR_OUT) | ||
642 | or.d IO_STATE (R_GEN_CONFIG, g0dir, out),$r0 | ||
643 | #endif | ||
644 | |||
645 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G8_15_DIR_OUT) | ||
646 | or.d IO_STATE (R_GEN_CONFIG, g8_15dir, out),$r0 | ||
647 | #endif | ||
648 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G16_23_DIR_OUT) | ||
649 | or.d IO_STATE (R_GEN_CONFIG, g16_23dir, out),$r0 | ||
650 | #endif | ||
651 | |||
652 | #if defined(CONFIG_ETRAX_DEF_R_PORT_G24_DIR_OUT) | ||
653 | or.d IO_STATE (R_GEN_CONFIG, g24dir, out),$r0 | ||
654 | #endif | ||
655 | |||
656 | move.d $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG | ||
657 | |||
658 | #ifndef CONFIG_SVINTO_SIM | ||
659 | move.d $r0,[R_GEN_CONFIG] | ||
660 | |||
661 | #if 0 | ||
662 | moveq 4,$r0 | ||
663 | move.b $r0,[R_DMA_CH6_CMD] ; reset (ser0 dma out) | ||
664 | move.b $r0,[R_DMA_CH7_CMD] ; reset (ser0 dma in) | ||
665 | 1: move.b [R_DMA_CH6_CMD],$r0 ; wait for reset cycle to finish | ||
666 | and.b 7,$r0 | ||
667 | cmp.b 4,$r0 | ||
668 | beq 1b | ||
669 | nop | ||
670 | 1: move.b [R_DMA_CH7_CMD],$r0 ; wait for reset cycle to finish | ||
671 | and.b 7,$r0 | ||
672 | cmp.b 4,$r0 | ||
673 | beq 1b | ||
674 | nop | ||
675 | #endif | ||
676 | |||
677 | moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 | ||
678 | move.b $r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) | ||
679 | move.b $r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) | ||
680 | 1: move.b [R_DMA_CH8_CMD],$r0 ; wait for reset cycle to finish | ||
681 | andq IO_MASK (R_DMA_CH8_CMD, cmd),$r0 | ||
682 | cmpq IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0 | ||
683 | beq 1b | ||
684 | nop | ||
685 | 1: move.b [R_DMA_CH9_CMD],$r0 ; wait for reset cycle to finish | ||
686 | andq IO_MASK (R_DMA_CH9_CMD, cmd),$r0 | ||
687 | cmpq IO_STATE (R_DMA_CH9_CMD, cmd, reset),$r0 | ||
688 | beq 1b | ||
689 | nop | ||
690 | |||
691 | ;; setup port PA and PB default initial directions and data | ||
692 | ;; including their shadow registers | ||
693 | |||
694 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0 | ||
695 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) | ||
696 | or.b IO_STATE (R_PORT_PA_DIR, dir7, output),$r0 | ||
697 | #endif | ||
698 | move.b $r0,[port_pa_dir_shadow] | ||
699 | move.b $r0,[R_PORT_PA_DIR] | ||
700 | move.b CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0 | ||
701 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7) | ||
702 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
703 | and.b ~(1 << 7),$r0 | ||
704 | #else | ||
705 | or.b (1 << 7),$r0 | ||
706 | #endif | ||
707 | #endif | ||
708 | move.b $r0,[port_pa_data_shadow] | ||
709 | move.b $r0,[R_PORT_PA_DATA] | ||
710 | |||
711 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0 | ||
712 | move.b $r0,[port_pb_config_shadow] | ||
713 | move.b $r0,[R_PORT_PB_CONFIG] | ||
714 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0 | ||
715 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) | ||
716 | or.b IO_STATE (R_PORT_PB_DIR, dir5, output),$r0 | ||
717 | #endif | ||
718 | move.b $r0,[port_pb_dir_shadow] | ||
719 | move.b $r0,[R_PORT_PB_DIR] | ||
720 | move.b CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0 | ||
721 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PB5) | ||
722 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
723 | and.b ~(1 << 5),$r0 | ||
724 | #else | ||
725 | or.b (1 << 5),$r0 | ||
726 | #endif | ||
727 | #endif | ||
728 | move.b $r0,[port_pb_data_shadow] | ||
729 | move.b $r0,[R_PORT_PB_DATA] | ||
730 | |||
731 | moveq 0, $r0 | ||
732 | move.d $r0,[port_pb_i2c_shadow] | ||
733 | move.d $r0, [R_PORT_PB_I2C] | ||
734 | |||
735 | moveq 0,$r0 | ||
736 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G10) | ||
737 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
738 | and.d ~(1 << 10),$r0 | ||
739 | #else | ||
740 | or.d (1 << 10),$r0 | ||
741 | #endif | ||
742 | #endif | ||
743 | #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_G11) | ||
744 | #if defined(CONFIG_BLUETOOTH_RESET_ACTIVE_HIGH) | ||
745 | and.d ~(1 << 11),$r0 | ||
746 | #else | ||
747 | or.d (1 << 11),$r0 | ||
748 | #endif | ||
749 | #endif | ||
750 | move.d $r0,[port_g_data_shadow] | ||
751 | move.d $r0,[R_PORT_G_DATA] | ||
752 | |||
753 | ;; setup the serial port 0 at 115200 baud for debug purposes | ||
754 | |||
755 | moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \ | ||
756 | | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \ | ||
757 | | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0 | ||
758 | move.d $r0,[R_SERIAL0_XOFF] | ||
759 | |||
760 | ; 115.2kbaud for both transmit and receive | ||
761 | move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \ | ||
762 | | IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),$r0 | ||
763 | move.b $r0,[R_SERIAL0_BAUD] | ||
764 | |||
765 | ; Set up and enable the serial0 receiver. | ||
766 | move.b IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop) \ | ||
767 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable) \ | ||
768 | | IO_STATE (R_SERIAL0_REC_CTRL, rts_, active) \ | ||
769 | | IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle) \ | ||
770 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal) \ | ||
771 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \ | ||
772 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \ | ||
773 | | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
774 | move.b $r0,[R_SERIAL0_REC_CTRL] | ||
775 | |||
776 | ; Set up and enable the serial0 transmitter. | ||
777 | move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \ | ||
778 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \ | ||
779 | | IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled) \ | ||
780 | | IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit) \ | ||
781 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal) \ | ||
782 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even) \ | ||
783 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable) \ | ||
784 | | IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
785 | move.b $r0,[R_SERIAL0_TR_CTRL] | ||
786 | |||
787 | ;; setup the serial port 1 at 115200 baud for debug purposes | ||
788 | |||
789 | moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \ | ||
790 | | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \ | ||
791 | | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0 | ||
792 | move.d $r0,[R_SERIAL1_XOFF] | ||
793 | |||
794 | ; 115.2kbaud for both transmit and receive | ||
795 | move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \ | ||
796 | | IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),$r0 | ||
797 | move.b $r0,[R_SERIAL1_BAUD] | ||
798 | |||
799 | ; Set up and enable the serial1 receiver. | ||
800 | move.b IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop) \ | ||
801 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable) \ | ||
802 | | IO_STATE (R_SERIAL1_REC_CTRL, rts_, active) \ | ||
803 | | IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle) \ | ||
804 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal) \ | ||
805 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \ | ||
806 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \ | ||
807 | | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
808 | move.b $r0,[R_SERIAL1_REC_CTRL] | ||
809 | |||
810 | ; Set up and enable the serial1 transmitter. | ||
811 | move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \ | ||
812 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \ | ||
813 | | IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled) \ | ||
814 | | IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit) \ | ||
815 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal) \ | ||
816 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even) \ | ||
817 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable) \ | ||
818 | | IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
819 | move.b $r0,[R_SERIAL1_TR_CTRL] | ||
820 | |||
821 | |||
822 | #ifdef CONFIG_ETRAX_SERIAL_PORT3 | ||
823 | ;; setup the serial port 3 at 115200 baud for debug purposes | ||
824 | |||
825 | moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \ | ||
826 | | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \ | ||
827 | | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0 | ||
828 | move.d $r0,[R_SERIAL3_XOFF] | ||
829 | |||
830 | ; 115.2kbaud for both transmit and receive | ||
831 | move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \ | ||
832 | | IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),$r0 | ||
833 | move.b $r0,[R_SERIAL3_BAUD] | ||
834 | |||
835 | ; Set up and enable the serial3 receiver. | ||
836 | move.b IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop) \ | ||
837 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable) \ | ||
838 | | IO_STATE (R_SERIAL3_REC_CTRL, rts_, active) \ | ||
839 | | IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle) \ | ||
840 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal) \ | ||
841 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \ | ||
842 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \ | ||
843 | | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0 | ||
844 | move.b $r0,[R_SERIAL3_REC_CTRL] | ||
845 | |||
846 | ; Set up and enable the serial3 transmitter. | ||
847 | move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \ | ||
848 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \ | ||
849 | | IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled) \ | ||
850 | | IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit) \ | ||
851 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal) \ | ||
852 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even) \ | ||
853 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable) \ | ||
854 | | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0 | ||
855 | move.b $r0,[R_SERIAL3_TR_CTRL] | ||
856 | #endif | ||
857 | |||
858 | #endif /* CONFIG_SVINTO_SIM */ | ||
859 | |||
860 | jump start_kernel ; jump into the C-function start_kernel in init/main.c | ||
861 | |||
862 | .data | ||
863 | etrax_irv: | ||
864 | .dword 0 | ||
865 | romfs_start: | ||
866 | .dword 0 | ||
867 | romfs_length: | ||
868 | .dword 0 | ||
869 | romfs_in_flash: | ||
870 | .dword 0 | ||
871 | |||
872 | ;; put some special pages at the beginning of the kernel aligned | ||
873 | ;; to page boundaries - the kernel cannot start until after this | ||
874 | |||
875 | #ifdef CONFIG_CRIS_LOW_MAP | ||
876 | swapper_pg_dir = 0x60002000 | ||
877 | #else | ||
878 | swapper_pg_dir = 0xc0002000 | ||
879 | #endif | ||
880 | |||
881 | .section ".init.data", "aw" | ||
882 | #include "../lib/hw_settings.S" | ||
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c new file mode 100644 index 000000000000..b2f16d6fc871 --- /dev/null +++ b/arch/cris/arch-v10/kernel/irq.c | |||
@@ -0,0 +1,204 @@ | |||
1 | /* $Id: irq.c,v 1.2 2004/06/09 05:30:27 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/irq.c | ||
4 | * | ||
5 | * Copyright (c) 2000-2002 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * This file contains the interrupt vectors and some | ||
10 | * helper functions | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <asm/irq.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/config.h> | ||
18 | |||
19 | irqvectptr irq_shortcuts[NR_IRQS]; /* vector of shortcut jumps after the irq prologue */ | ||
20 | |||
21 | /* don't use set_int_vector, it bypasses the linux interrupt handlers. it is | ||
22 | * global just so that the kernel gdb can use it. | ||
23 | */ | ||
24 | |||
25 | void | ||
26 | set_int_vector(int n, irqvectptr addr) | ||
27 | { | ||
28 | etrax_irv->v[n + 0x20] = (irqvectptr)addr; | ||
29 | } | ||
30 | |||
31 | /* the breakpoint vector is obviously not made just like the normal irq handlers | ||
32 | * but needs to contain _code_ to jump to addr. | ||
33 | * | ||
34 | * the BREAK n instruction jumps to IBR + n * 8 | ||
35 | */ | ||
36 | |||
37 | void | ||
38 | set_break_vector(int n, irqvectptr addr) | ||
39 | { | ||
40 | unsigned short *jinstr = (unsigned short *)&etrax_irv->v[n*2]; | ||
41 | unsigned long *jaddr = (unsigned long *)(jinstr + 1); | ||
42 | |||
43 | /* if you don't know what this does, do not touch it! */ | ||
44 | |||
45 | *jinstr = 0x0d3f; | ||
46 | *jaddr = (unsigned long)addr; | ||
47 | |||
48 | /* 00000026 <clrlop+1a> 3f0d82000000 jump 0x82 */ | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * This builds up the IRQ handler stubs using some ugly macros in irq.h | ||
53 | * | ||
54 | * These macros create the low-level assembly IRQ routines that do all | ||
55 | * the operations that are needed. They are also written to be fast - and to | ||
56 | * disable interrupts as little as humanly possible. | ||
57 | * | ||
58 | */ | ||
59 | |||
60 | /* IRQ0 and 1 are special traps */ | ||
61 | void hwbreakpoint(void); | ||
62 | void IRQ1_interrupt(void); | ||
63 | BUILD_TIMER_IRQ(2, 0x04) /* the timer interrupt is somewhat special */ | ||
64 | BUILD_IRQ(3, 0x08) | ||
65 | BUILD_IRQ(4, 0x10) | ||
66 | BUILD_IRQ(5, 0x20) | ||
67 | BUILD_IRQ(6, 0x40) | ||
68 | BUILD_IRQ(7, 0x80) | ||
69 | BUILD_IRQ(8, 0x100) | ||
70 | BUILD_IRQ(9, 0x200) | ||
71 | BUILD_IRQ(10, 0x400) | ||
72 | BUILD_IRQ(11, 0x800) | ||
73 | BUILD_IRQ(12, 0x1000) | ||
74 | BUILD_IRQ(13, 0x2000) | ||
75 | void mmu_bus_fault(void); /* IRQ 14 is the bus fault interrupt */ | ||
76 | void multiple_interrupt(void); /* IRQ 15 is the multiple IRQ interrupt */ | ||
77 | BUILD_IRQ(16, 0x10000) | ||
78 | BUILD_IRQ(17, 0x20000) | ||
79 | BUILD_IRQ(18, 0x40000) | ||
80 | BUILD_IRQ(19, 0x80000) | ||
81 | BUILD_IRQ(20, 0x100000) | ||
82 | BUILD_IRQ(21, 0x200000) | ||
83 | BUILD_IRQ(22, 0x400000) | ||
84 | BUILD_IRQ(23, 0x800000) | ||
85 | BUILD_IRQ(24, 0x1000000) | ||
86 | BUILD_IRQ(25, 0x2000000) | ||
87 | /* IRQ 26-30 are reserved */ | ||
88 | BUILD_IRQ(31, 0x80000000) | ||
89 | |||
90 | /* | ||
91 | * Pointers to the low-level handlers | ||
92 | */ | ||
93 | |||
94 | static void (*interrupt[NR_IRQS])(void) = { | ||
95 | NULL, NULL, IRQ2_interrupt, IRQ3_interrupt, | ||
96 | IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, | ||
97 | IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, | ||
98 | IRQ12_interrupt, IRQ13_interrupt, NULL, NULL, | ||
99 | IRQ16_interrupt, IRQ17_interrupt, IRQ18_interrupt, IRQ19_interrupt, | ||
100 | IRQ20_interrupt, IRQ21_interrupt, IRQ22_interrupt, IRQ23_interrupt, | ||
101 | IRQ24_interrupt, IRQ25_interrupt, NULL, NULL, NULL, NULL, NULL, | ||
102 | IRQ31_interrupt | ||
103 | }; | ||
104 | |||
105 | static void (*bad_interrupt[NR_IRQS])(void) = { | ||
106 | NULL, NULL, | ||
107 | NULL, bad_IRQ3_interrupt, | ||
108 | bad_IRQ4_interrupt, bad_IRQ5_interrupt, | ||
109 | bad_IRQ6_interrupt, bad_IRQ7_interrupt, | ||
110 | bad_IRQ8_interrupt, bad_IRQ9_interrupt, | ||
111 | bad_IRQ10_interrupt, bad_IRQ11_interrupt, | ||
112 | bad_IRQ12_interrupt, bad_IRQ13_interrupt, | ||
113 | NULL, NULL, | ||
114 | bad_IRQ16_interrupt, bad_IRQ17_interrupt, | ||
115 | bad_IRQ18_interrupt, bad_IRQ19_interrupt, | ||
116 | bad_IRQ20_interrupt, bad_IRQ21_interrupt, | ||
117 | bad_IRQ22_interrupt, bad_IRQ23_interrupt, | ||
118 | bad_IRQ24_interrupt, bad_IRQ25_interrupt, | ||
119 | NULL, NULL, NULL, NULL, NULL, | ||
120 | bad_IRQ31_interrupt | ||
121 | }; | ||
122 | |||
123 | void arch_setup_irq(int irq) | ||
124 | { | ||
125 | set_int_vector(irq, interrupt[irq]); | ||
126 | } | ||
127 | |||
128 | void arch_free_irq(int irq) | ||
129 | { | ||
130 | set_int_vector(irq, bad_interrupt[irq]); | ||
131 | } | ||
132 | |||
133 | void weird_irq(void); | ||
134 | void system_call(void); /* from entry.S */ | ||
135 | void do_sigtrap(void); /* from entry.S */ | ||
136 | void gdb_handle_breakpoint(void); /* from entry.S */ | ||
137 | |||
138 | /* init_IRQ() is called by start_kernel and is responsible for fixing IRQ masks and | ||
139 | setting the irq vector table to point to bad_interrupt ptrs. | ||
140 | */ | ||
141 | |||
142 | void __init | ||
143 | init_IRQ(void) | ||
144 | { | ||
145 | int i; | ||
146 | |||
147 | /* clear all interrupt masks */ | ||
148 | |||
149 | #ifndef CONFIG_SVINTO_SIM | ||
150 | *R_IRQ_MASK0_CLR = 0xffffffff; | ||
151 | *R_IRQ_MASK1_CLR = 0xffffffff; | ||
152 | *R_IRQ_MASK2_CLR = 0xffffffff; | ||
153 | #endif | ||
154 | |||
155 | *R_VECT_MASK_CLR = 0xffffffff; | ||
156 | |||
157 | /* clear the shortcut entry points */ | ||
158 | |||
159 | for(i = 0; i < NR_IRQS; i++) | ||
160 | irq_shortcuts[i] = NULL; | ||
161 | |||
162 | for (i = 0; i < 256; i++) | ||
163 | etrax_irv->v[i] = weird_irq; | ||
164 | |||
165 | /* the entries in the break vector contain actual code to be | ||
166 | executed by the associated break handler, rather than just a jump | ||
167 | address. therefore we need to setup a default breakpoint handler | ||
168 | for all breakpoints */ | ||
169 | |||
170 | for (i = 0; i < 16; i++) | ||
171 | set_break_vector(i, do_sigtrap); | ||
172 | |||
173 | /* set all etrax irq's to the bad handlers */ | ||
174 | for (i = 2; i < NR_IRQS; i++) | ||
175 | set_int_vector(i, bad_interrupt[i]); | ||
176 | |||
177 | /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */ | ||
178 | |||
179 | set_int_vector(15, multiple_interrupt); | ||
180 | |||
181 | /* 0 and 1 which are special breakpoint/NMI traps */ | ||
182 | |||
183 | set_int_vector(0, hwbreakpoint); | ||
184 | set_int_vector(1, IRQ1_interrupt); | ||
185 | |||
186 | /* and irq 14 which is the mmu bus fault handler */ | ||
187 | |||
188 | set_int_vector(14, mmu_bus_fault); | ||
189 | |||
190 | /* setup the system-call trap, which is reached by BREAK 13 */ | ||
191 | |||
192 | set_break_vector(13, system_call); | ||
193 | |||
194 | /* setup a breakpoint handler for debugging used for both user and | ||
195 | kernel mode debugging (which is why it is not inside an ifdef | ||
196 | CONFIG_ETRAX_KGDB) */ | ||
197 | set_break_vector(8, gdb_handle_breakpoint); | ||
198 | |||
199 | #ifdef CONFIG_ETRAX_KGDB | ||
200 | /* setup kgdb if its enabled, and break into the debugger */ | ||
201 | kgdb_init(); | ||
202 | breakpoint(); | ||
203 | #endif | ||
204 | } | ||
diff --git a/arch/cris/arch-v10/kernel/kgdb.c b/arch/cris/arch-v10/kernel/kgdb.c new file mode 100644 index 000000000000..7d368c877ee9 --- /dev/null +++ b/arch/cris/arch-v10/kernel/kgdb.c | |||
@@ -0,0 +1,1568 @@ | |||
1 | /*!************************************************************************** | ||
2 | *! | ||
3 | *! FILE NAME : kgdb.c | ||
4 | *! | ||
5 | *! DESCRIPTION: Implementation of the gdb stub with respect to ETRAX 100. | ||
6 | *! It is a mix of arch/m68k/kernel/kgdb.c and cris_stub.c. | ||
7 | *! | ||
8 | *!--------------------------------------------------------------------------- | ||
9 | *! HISTORY | ||
10 | *! | ||
11 | *! DATE NAME CHANGES | ||
12 | *! ---- ---- ------- | ||
13 | *! Apr 26 1999 Hendrik Ruijter Initial version. | ||
14 | *! May 6 1999 Hendrik Ruijter Removed call to strlen in libc and removed | ||
15 | *! struct assignment as it generates calls to | ||
16 | *! memcpy in libc. | ||
17 | *! Jun 17 1999 Hendrik Ruijter Added gdb 4.18 support. 'X', 'qC' and 'qL'. | ||
18 | *! Jul 21 1999 Bjorn Wesen eLinux port | ||
19 | *! | ||
20 | *! $Log: kgdb.c,v $ | ||
21 | *! Revision 1.5 2004/10/07 13:59:08 starvik | ||
22 | *! Corrected call to set_int_vector | ||
23 | *! | ||
24 | *! Revision 1.4 2003/04/09 05:20:44 starvik | ||
25 | *! Merge of Linux 2.5.67 | ||
26 | *! | ||
27 | *! Revision 1.3 2003/01/21 19:11:08 starvik | ||
28 | *! Modified include path for new dir layout | ||
29 | *! | ||
30 | *! Revision 1.2 2002/11/19 14:35:24 starvik | ||
31 | *! Changes from linux 2.4 | ||
32 | *! Changed struct initializer syntax to the currently prefered notation | ||
33 | *! | ||
34 | *! Revision 1.1 2001/12/17 13:59:27 bjornw | ||
35 | *! Initial revision | ||
36 | *! | ||
37 | *! Revision 1.6 2001/10/09 13:10:03 matsfg | ||
38 | *! Added $ on registers and removed some underscores | ||
39 | *! | ||
40 | *! Revision 1.5 2001/04/17 13:58:39 orjanf | ||
41 | *! * Renamed CONFIG_KGDB to CONFIG_ETRAX_KGDB. | ||
42 | *! | ||
43 | *! Revision 1.4 2001/02/23 13:45:19 bjornw | ||
44 | *! config.h check | ||
45 | *! | ||
46 | *! Revision 1.3 2001/01/31 18:08:23 orjanf | ||
47 | *! Removed kgdb_handle_breakpoint from being the break 8 handler. | ||
48 | *! | ||
49 | *! Revision 1.2 2001/01/12 14:22:25 orjanf | ||
50 | *! Updated kernel debugging support to work with ETRAX 100LX. | ||
51 | *! | ||
52 | *! Revision 1.1 2000/07/10 16:25:21 bjornw | ||
53 | *! Initial revision | ||
54 | *! | ||
55 | *! Revision 1.1.1.1 1999/12/03 14:57:31 bjornw | ||
56 | *! * Initial version of arch/cris, the latest CRIS architecture with an MMU. | ||
57 | *! Mostly copied from arch/etrax100 with appropriate renames of files. | ||
58 | *! The mm/ subdir is copied from arch/i386. | ||
59 | *! This does not compile yet at all. | ||
60 | *! | ||
61 | *! | ||
62 | *! Revision 1.4 1999/07/22 17:25:25 bjornw | ||
63 | *! Dont wait for + in putpacket if we havent hit the initial breakpoint yet. Added a kgdb_init function which sets up the break and irq vectors. | ||
64 | *! | ||
65 | *! Revision 1.3 1999/07/21 19:51:18 bjornw | ||
66 | *! Check if the interrupting char is a ctrl-C, ignore otherwise. | ||
67 | *! | ||
68 | *! Revision 1.2 1999/07/21 18:09:39 bjornw | ||
69 | *! Ported to eLinux architecture, and added some kgdb documentation. | ||
70 | *! | ||
71 | *! | ||
72 | *!--------------------------------------------------------------------------- | ||
73 | *! | ||
74 | *! $Id: kgdb.c,v 1.5 2004/10/07 13:59:08 starvik Exp $ | ||
75 | *! | ||
76 | *! (C) Copyright 1999, Axis Communications AB, LUND, SWEDEN | ||
77 | *! | ||
78 | *!**************************************************************************/ | ||
79 | /* @(#) cris_stub.c 1.3 06/17/99 */ | ||
80 | |||
81 | /* | ||
82 | * kgdb usage notes: | ||
83 | * ----------------- | ||
84 | * | ||
85 | * If you select CONFIG_ETRAX_KGDB in the configuration, the kernel will be | ||
86 | * built with different gcc flags: "-g" is added to get debug infos, and | ||
87 | * "-fomit-frame-pointer" is omitted to make debugging easier. Since the | ||
88 | * resulting kernel will be quite big (approx. > 7 MB), it will be stripped | ||
89 | * before compresion. Such a kernel will behave just as usually, except if | ||
90 | * given a "debug=<device>" command line option. (Only serial devices are | ||
91 | * allowed for <device>, i.e. no printers or the like; possible values are | ||
92 | * machine depedend and are the same as for the usual debug device, the one | ||
93 | * for logging kernel messages.) If that option is given and the device can be | ||
94 | * initialized, the kernel will connect to the remote gdb in trap_init(). The | ||
95 | * serial parameters are fixed to 8N1 and 115200 bps, for easyness of | ||
96 | * implementation. | ||
97 | * | ||
98 | * To start a debugging session, start that gdb with the debugging kernel | ||
99 | * image (the one with the symbols, vmlinux.debug) named on the command line. | ||
100 | * This file will be used by gdb to get symbol and debugging infos about the | ||
101 | * kernel. Next, select remote debug mode by | ||
102 | * target remote <device> | ||
103 | * where <device> is the name of the serial device over which the debugged | ||
104 | * machine is connected. Maybe you have to adjust the baud rate by | ||
105 | * set remotebaud <rate> | ||
106 | * or also other parameters with stty: | ||
107 | * shell stty ... </dev/... | ||
108 | * If the kernel to debug has already booted, it waited for gdb and now | ||
109 | * connects, and you'll see a breakpoint being reported. If the kernel isn't | ||
110 | * running yet, start it now. The order of gdb and the kernel doesn't matter. | ||
111 | * Another thing worth knowing about in the getting-started phase is how to | ||
112 | * debug the remote protocol itself. This is activated with | ||
113 | * set remotedebug 1 | ||
114 | * gdb will then print out each packet sent or received. You'll also get some | ||
115 | * messages about the gdb stub on the console of the debugged machine. | ||
116 | * | ||
117 | * If all that works, you can use lots of the usual debugging techniques on | ||
118 | * the kernel, e.g. inspecting and changing variables/memory, setting | ||
119 | * breakpoints, single stepping and so on. It's also possible to interrupt the | ||
120 | * debugged kernel by pressing C-c in gdb. Have fun! :-) | ||
121 | * | ||
122 | * The gdb stub is entered (and thus the remote gdb gets control) in the | ||
123 | * following situations: | ||
124 | * | ||
125 | * - If breakpoint() is called. This is just after kgdb initialization, or if | ||
126 | * a breakpoint() call has been put somewhere into the kernel source. | ||
127 | * (Breakpoints can of course also be set the usual way in gdb.) | ||
128 | * In eLinux, we call breakpoint() in init/main.c after IRQ initialization. | ||
129 | * | ||
130 | * - If there is a kernel exception, i.e. bad_super_trap() or die_if_kernel() | ||
131 | * are entered. All the CPU exceptions are mapped to (more or less..., see | ||
132 | * the hard_trap_info array below) appropriate signal, which are reported | ||
133 | * to gdb. die_if_kernel() is usually called after some kind of access | ||
134 | * error and thus is reported as SIGSEGV. | ||
135 | * | ||
136 | * - When panic() is called. This is reported as SIGABRT. | ||
137 | * | ||
138 | * - If C-c is received over the serial line, which is treated as | ||
139 | * SIGINT. | ||
140 | * | ||
141 | * Of course, all these signals are just faked for gdb, since there is no | ||
142 | * signal concept as such for the kernel. It also isn't possible --obviously-- | ||
143 | * to set signal handlers from inside gdb, or restart the kernel with a | ||
144 | * signal. | ||
145 | * | ||
146 | * Current limitations: | ||
147 | * | ||
148 | * - While the kernel is stopped, interrupts are disabled for safety reasons | ||
149 | * (i.e., variables not changing magically or the like). But this also | ||
150 | * means that the clock isn't running anymore, and that interrupts from the | ||
151 | * hardware may get lost/not be served in time. This can cause some device | ||
152 | * errors... | ||
153 | * | ||
154 | * - When single-stepping, only one instruction of the current thread is | ||
155 | * executed, but interrupts are allowed for that time and will be serviced | ||
156 | * if pending. Be prepared for that. | ||
157 | * | ||
158 | * - All debugging happens in kernel virtual address space. There's no way to | ||
159 | * access physical memory not mapped in kernel space, or to access user | ||
160 | * space. A way to work around this is using get_user_long & Co. in gdb | ||
161 | * expressions, but only for the current process. | ||
162 | * | ||
163 | * - Interrupting the kernel only works if interrupts are currently allowed, | ||
164 | * and the interrupt of the serial line isn't blocked by some other means | ||
165 | * (IPL too high, disabled, ...) | ||
166 | * | ||
167 | * - The gdb stub is currently not reentrant, i.e. errors that happen therein | ||
168 | * (e.g. accessing invalid memory) may not be caught correctly. This could | ||
169 | * be removed in future by introducing a stack of struct registers. | ||
170 | * | ||
171 | */ | ||
172 | |||
173 | /* | ||
174 | * To enable debugger support, two things need to happen. One, a | ||
175 | * call to kgdb_init() is necessary in order to allow any breakpoints | ||
176 | * or error conditions to be properly intercepted and reported to gdb. | ||
177 | * Two, a breakpoint needs to be generated to begin communication. This | ||
178 | * is most easily accomplished by a call to breakpoint(). | ||
179 | * | ||
180 | * The following gdb commands are supported: | ||
181 | * | ||
182 | * command function Return value | ||
183 | * | ||
184 | * g return the value of the CPU registers hex data or ENN | ||
185 | * G set the value of the CPU registers OK or ENN | ||
186 | * | ||
187 | * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN | ||
188 | * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN | ||
189 | * | ||
190 | * c Resume at current address SNN ( signal NN) | ||
191 | * cAA..AA Continue at address AA..AA SNN | ||
192 | * | ||
193 | * s Step one instruction SNN | ||
194 | * sAA..AA Step one instruction from AA..AA SNN | ||
195 | * | ||
196 | * k kill | ||
197 | * | ||
198 | * ? What was the last sigval ? SNN (signal NN) | ||
199 | * | ||
200 | * bBB..BB Set baud rate to BB..BB OK or BNN, then sets | ||
201 | * baud rate | ||
202 | * | ||
203 | * All commands and responses are sent with a packet which includes a | ||
204 | * checksum. A packet consists of | ||
205 | * | ||
206 | * $<packet info>#<checksum>. | ||
207 | * | ||
208 | * where | ||
209 | * <packet info> :: <characters representing the command or response> | ||
210 | * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>> | ||
211 | * | ||
212 | * When a packet is received, it is first acknowledged with either '+' or '-'. | ||
213 | * '+' indicates a successful transfer. '-' indicates a failed transfer. | ||
214 | * | ||
215 | * Example: | ||
216 | * | ||
217 | * Host: Reply: | ||
218 | * $m0,10#2a +$00010203040506070809101112131415#42 | ||
219 | * | ||
220 | */ | ||
221 | |||
222 | |||
223 | #include <linux/string.h> | ||
224 | #include <linux/signal.h> | ||
225 | #include <linux/kernel.h> | ||
226 | #include <linux/delay.h> | ||
227 | #include <linux/linkage.h> | ||
228 | |||
229 | #include <asm/setup.h> | ||
230 | #include <asm/ptrace.h> | ||
231 | |||
232 | #include <asm/arch/svinto.h> | ||
233 | #include <asm/irq.h> | ||
234 | |||
235 | static int kgdb_started = 0; | ||
236 | |||
237 | /********************************* Register image ****************************/ | ||
238 | /* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's | ||
239 | Reference", p. 1-1, with the additional register definitions of the | ||
240 | ETRAX 100LX in cris-opc.h. | ||
241 | There are 16 general 32-bit registers, R0-R15, where R14 is the stack | ||
242 | pointer, SP, and R15 is the program counter, PC. | ||
243 | There are 16 special registers, P0-P15, where three of the unimplemented | ||
244 | registers, P0, P4 and P8, are reserved as zero-registers. A read from | ||
245 | any of these registers returns zero and a write has no effect. */ | ||
246 | |||
247 | typedef | ||
248 | struct register_image | ||
249 | { | ||
250 | /* Offset */ | ||
251 | unsigned int r0; /* 0x00 */ | ||
252 | unsigned int r1; /* 0x04 */ | ||
253 | unsigned int r2; /* 0x08 */ | ||
254 | unsigned int r3; /* 0x0C */ | ||
255 | unsigned int r4; /* 0x10 */ | ||
256 | unsigned int r5; /* 0x14 */ | ||
257 | unsigned int r6; /* 0x18 */ | ||
258 | unsigned int r7; /* 0x1C */ | ||
259 | unsigned int r8; /* 0x20 Frame pointer */ | ||
260 | unsigned int r9; /* 0x24 */ | ||
261 | unsigned int r10; /* 0x28 */ | ||
262 | unsigned int r11; /* 0x2C */ | ||
263 | unsigned int r12; /* 0x30 */ | ||
264 | unsigned int r13; /* 0x34 */ | ||
265 | unsigned int sp; /* 0x38 Stack pointer */ | ||
266 | unsigned int pc; /* 0x3C Program counter */ | ||
267 | |||
268 | unsigned char p0; /* 0x40 8-bit zero-register */ | ||
269 | unsigned char vr; /* 0x41 Version register */ | ||
270 | |||
271 | unsigned short p4; /* 0x42 16-bit zero-register */ | ||
272 | unsigned short ccr; /* 0x44 Condition code register */ | ||
273 | |||
274 | unsigned int mof; /* 0x46 Multiply overflow register */ | ||
275 | |||
276 | unsigned int p8; /* 0x4A 32-bit zero-register */ | ||
277 | unsigned int ibr; /* 0x4E Interrupt base register */ | ||
278 | unsigned int irp; /* 0x52 Interrupt return pointer */ | ||
279 | unsigned int srp; /* 0x56 Subroutine return pointer */ | ||
280 | unsigned int bar; /* 0x5A Breakpoint address register */ | ||
281 | unsigned int dccr; /* 0x5E Double condition code register */ | ||
282 | unsigned int brp; /* 0x62 Breakpoint return pointer (pc in caller) */ | ||
283 | unsigned int usp; /* 0x66 User mode stack pointer */ | ||
284 | } registers; | ||
285 | |||
286 | /************** Prototypes for local library functions ***********************/ | ||
287 | |||
288 | /* Copy of strcpy from libc. */ | ||
289 | static char *gdb_cris_strcpy (char *s1, const char *s2); | ||
290 | |||
291 | /* Copy of strlen from libc. */ | ||
292 | static int gdb_cris_strlen (const char *s); | ||
293 | |||
294 | /* Copy of memchr from libc. */ | ||
295 | static void *gdb_cris_memchr (const void *s, int c, int n); | ||
296 | |||
297 | /* Copy of strtol from libc. Does only support base 16. */ | ||
298 | static int gdb_cris_strtol (const char *s, char **endptr, int base); | ||
299 | |||
300 | /********************** Prototypes for local functions. **********************/ | ||
301 | /* Copy the content of a register image into another. The size n is | ||
302 | the size of the register image. Due to struct assignment generation of | ||
303 | memcpy in libc. */ | ||
304 | static void copy_registers (registers *dptr, registers *sptr, int n); | ||
305 | |||
306 | /* Copy the stored registers from the stack. Put the register contents | ||
307 | of thread thread_id in the struct reg. */ | ||
308 | static void copy_registers_from_stack (int thread_id, registers *reg); | ||
309 | |||
310 | /* Copy the registers to the stack. Put the register contents of thread | ||
311 | thread_id from struct reg to the stack. */ | ||
312 | static void copy_registers_to_stack (int thread_id, registers *reg); | ||
313 | |||
314 | /* Write a value to a specified register regno in the register image | ||
315 | of the current thread. */ | ||
316 | static int write_register (int regno, char *val); | ||
317 | |||
318 | /* Write a value to a specified register in the stack of a thread other | ||
319 | than the current thread. */ | ||
320 | static write_stack_register (int thread_id, int regno, char *valptr); | ||
321 | |||
322 | /* Read a value from a specified register in the register image. Returns the | ||
323 | status of the read operation. The register value is returned in valptr. */ | ||
324 | static int read_register (char regno, unsigned int *valptr); | ||
325 | |||
326 | /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */ | ||
327 | int getDebugChar (void); | ||
328 | |||
329 | /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */ | ||
330 | void putDebugChar (int val); | ||
331 | |||
332 | void enableDebugIRQ (void); | ||
333 | |||
334 | /* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, | ||
335 | represented by int x. */ | ||
336 | static char highhex (int x); | ||
337 | |||
338 | /* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, | ||
339 | represented by int x. */ | ||
340 | static char lowhex (int x); | ||
341 | |||
342 | /* Returns the integer equivalent of a hexadecimal character. */ | ||
343 | static int hex (char ch); | ||
344 | |||
345 | /* Convert the memory, pointed to by mem into hexadecimal representation. | ||
346 | Put the result in buf, and return a pointer to the last character | ||
347 | in buf (null). */ | ||
348 | static char *mem2hex (char *buf, unsigned char *mem, int count); | ||
349 | |||
350 | /* Convert the array, in hexadecimal representation, pointed to by buf into | ||
351 | binary representation. Put the result in mem, and return a pointer to | ||
352 | the character after the last byte written. */ | ||
353 | static unsigned char *hex2mem (unsigned char *mem, char *buf, int count); | ||
354 | |||
355 | /* Put the content of the array, in binary representation, pointed to by buf | ||
356 | into memory pointed to by mem, and return a pointer to | ||
357 | the character after the last byte written. */ | ||
358 | static unsigned char *bin2mem (unsigned char *mem, unsigned char *buf, int count); | ||
359 | |||
360 | /* Await the sequence $<data>#<checksum> and store <data> in the array buffer | ||
361 | returned. */ | ||
362 | static void getpacket (char *buffer); | ||
363 | |||
364 | /* Send $<data>#<checksum> from the <data> in the array buffer. */ | ||
365 | static void putpacket (char *buffer); | ||
366 | |||
367 | /* Build and send a response packet in order to inform the host the | ||
368 | stub is stopped. */ | ||
369 | static void stub_is_stopped (int sigval); | ||
370 | |||
371 | /* All expected commands are sent from remote.c. Send a response according | ||
372 | to the description in remote.c. */ | ||
373 | static void handle_exception (int sigval); | ||
374 | |||
375 | /* Performs a complete re-start from scratch. ETRAX specific. */ | ||
376 | static void kill_restart (void); | ||
377 | |||
378 | /******************** Prototypes for global functions. ***********************/ | ||
379 | |||
380 | /* The string str is prepended with the GDB printout token and sent. */ | ||
381 | void putDebugString (const unsigned char *str, int length); /* used by etrax100ser.c */ | ||
382 | |||
383 | /* The hook for both static (compiled) and dynamic breakpoints set by GDB. | ||
384 | ETRAX 100 specific. */ | ||
385 | void handle_breakpoint (void); /* used by irq.c */ | ||
386 | |||
387 | /* The hook for an interrupt generated by GDB. ETRAX 100 specific. */ | ||
388 | void handle_interrupt (void); /* used by irq.c */ | ||
389 | |||
390 | /* A static breakpoint to be used at startup. */ | ||
391 | void breakpoint (void); /* called by init/main.c */ | ||
392 | |||
393 | /* From osys_int.c, executing_task contains the number of the current | ||
394 | executing task in osys. Does not know of object-oriented threads. */ | ||
395 | extern unsigned char executing_task; | ||
396 | |||
397 | /* The number of characters used for a 64 bit thread identifier. */ | ||
398 | #define HEXCHARS_IN_THREAD_ID 16 | ||
399 | |||
400 | /* Avoid warning as the internal_stack is not used in the C-code. */ | ||
401 | #define USEDVAR(name) { if (name) { ; } } | ||
402 | #define USEDFUN(name) { void (*pf)(void) = (void *)name; USEDVAR(pf) } | ||
403 | |||
404 | /********************************** Packet I/O ******************************/ | ||
405 | /* BUFMAX defines the maximum number of characters in | ||
406 | inbound/outbound buffers */ | ||
407 | #define BUFMAX 512 | ||
408 | |||
409 | /* Run-length encoding maximum length. Send 64 at most. */ | ||
410 | #define RUNLENMAX 64 | ||
411 | |||
412 | /* Definition of all valid hexadecimal characters */ | ||
413 | static const char hexchars[] = "0123456789abcdef"; | ||
414 | |||
415 | /* The inbound/outbound buffers used in packet I/O */ | ||
416 | static char remcomInBuffer[BUFMAX]; | ||
417 | static char remcomOutBuffer[BUFMAX]; | ||
418 | |||
419 | /* Error and warning messages. */ | ||
420 | enum error_type | ||
421 | { | ||
422 | SUCCESS, E01, E02, E03, E04, E05, E06, E07 | ||
423 | }; | ||
424 | static char *error_message[] = | ||
425 | { | ||
426 | "", | ||
427 | "E01 Set current or general thread - H[c,g] - internal error.", | ||
428 | "E02 Change register content - P - cannot change read-only register.", | ||
429 | "E03 Thread is not alive.", /* T, not used. */ | ||
430 | "E04 The command is not supported - [s,C,S,!,R,d,r] - internal error.", | ||
431 | "E05 Change register content - P - the register is not implemented..", | ||
432 | "E06 Change memory content - M - internal error.", | ||
433 | "E07 Change register content - P - the register is not stored on the stack" | ||
434 | }; | ||
435 | /********************************* Register image ****************************/ | ||
436 | /* Use the order of registers as defined in "AXIS ETRAX CRIS Programmer's | ||
437 | Reference", p. 1-1, with the additional register definitions of the | ||
438 | ETRAX 100LX in cris-opc.h. | ||
439 | There are 16 general 32-bit registers, R0-R15, where R14 is the stack | ||
440 | pointer, SP, and R15 is the program counter, PC. | ||
441 | There are 16 special registers, P0-P15, where three of the unimplemented | ||
442 | registers, P0, P4 and P8, are reserved as zero-registers. A read from | ||
443 | any of these registers returns zero and a write has no effect. */ | ||
444 | enum register_name | ||
445 | { | ||
446 | R0, R1, R2, R3, | ||
447 | R4, R5, R6, R7, | ||
448 | R8, R9, R10, R11, | ||
449 | R12, R13, SP, PC, | ||
450 | P0, VR, P2, P3, | ||
451 | P4, CCR, P6, MOF, | ||
452 | P8, IBR, IRP, SRP, | ||
453 | BAR, DCCR, BRP, USP | ||
454 | }; | ||
455 | |||
456 | /* The register sizes of the registers in register_name. An unimplemented register | ||
457 | is designated by size 0 in this array. */ | ||
458 | static int register_size[] = | ||
459 | { | ||
460 | 4, 4, 4, 4, | ||
461 | 4, 4, 4, 4, | ||
462 | 4, 4, 4, 4, | ||
463 | 4, 4, 4, 4, | ||
464 | 1, 1, 0, 0, | ||
465 | 2, 2, 0, 4, | ||
466 | 4, 4, 4, 4, | ||
467 | 4, 4, 4, 4 | ||
468 | }; | ||
469 | |||
470 | /* Contains the register image of the executing thread in the assembler | ||
471 | part of the code in order to avoid horrible addressing modes. */ | ||
472 | static registers reg; | ||
473 | |||
474 | /* FIXME: Should this be used? Delete otherwise. */ | ||
475 | /* Contains the assumed consistency state of the register image. Uses the | ||
476 | enum error_type for state information. */ | ||
477 | static int consistency_status = SUCCESS; | ||
478 | |||
479 | /********************************** Handle exceptions ************************/ | ||
480 | /* The variable reg contains the register image associated with the | ||
481 | current_thread_c variable. It is a complete register image created at | ||
482 | entry. The reg_g contains a register image of a task where the general | ||
483 | registers are taken from the stack and all special registers are taken | ||
484 | from the executing task. It is associated with current_thread_g and used | ||
485 | in order to provide access mainly for 'g', 'G' and 'P'. | ||
486 | */ | ||
487 | |||
488 | /* Need two task id pointers in order to handle Hct and Hgt commands. */ | ||
489 | static int current_thread_c = 0; | ||
490 | static int current_thread_g = 0; | ||
491 | |||
492 | /* Need two register images in order to handle Hct and Hgt commands. The | ||
493 | variable reg_g is in addition to reg above. */ | ||
494 | static registers reg_g; | ||
495 | |||
496 | /********************************** Breakpoint *******************************/ | ||
497 | /* Use an internal stack in the breakpoint and interrupt response routines */ | ||
498 | #define INTERNAL_STACK_SIZE 1024 | ||
499 | static char internal_stack[INTERNAL_STACK_SIZE]; | ||
500 | |||
501 | /* Due to the breakpoint return pointer, a state variable is needed to keep | ||
502 | track of whether it is a static (compiled) or dynamic (gdb-invoked) | ||
503 | breakpoint to be handled. A static breakpoint uses the content of register | ||
504 | BRP as it is whereas a dynamic breakpoint requires subtraction with 2 | ||
505 | in order to execute the instruction. The first breakpoint is static. */ | ||
506 | static unsigned char is_dyn_brkp = 0; | ||
507 | |||
508 | /********************************* String library ****************************/ | ||
509 | /* Single-step over library functions creates trap loops. */ | ||
510 | |||
511 | /* Copy char s2[] to s1[]. */ | ||
512 | static char* | ||
513 | gdb_cris_strcpy (char *s1, const char *s2) | ||
514 | { | ||
515 | char *s = s1; | ||
516 | |||
517 | for (s = s1; (*s++ = *s2++) != '\0'; ) | ||
518 | ; | ||
519 | return (s1); | ||
520 | } | ||
521 | |||
522 | /* Find length of s[]. */ | ||
523 | static int | ||
524 | gdb_cris_strlen (const char *s) | ||
525 | { | ||
526 | const char *sc; | ||
527 | |||
528 | for (sc = s; *sc != '\0'; sc++) | ||
529 | ; | ||
530 | return (sc - s); | ||
531 | } | ||
532 | |||
533 | /* Find first occurrence of c in s[n]. */ | ||
534 | static void* | ||
535 | gdb_cris_memchr (const void *s, int c, int n) | ||
536 | { | ||
537 | const unsigned char uc = c; | ||
538 | const unsigned char *su; | ||
539 | |||
540 | for (su = s; 0 < n; ++su, --n) | ||
541 | if (*su == uc) | ||
542 | return ((void *)su); | ||
543 | return (NULL); | ||
544 | } | ||
545 | /******************************* Standard library ****************************/ | ||
546 | /* Single-step over library functions creates trap loops. */ | ||
547 | /* Convert string to long. */ | ||
548 | static int | ||
549 | gdb_cris_strtol (const char *s, char **endptr, int base) | ||
550 | { | ||
551 | char *s1; | ||
552 | char *sd; | ||
553 | int x = 0; | ||
554 | |||
555 | for (s1 = (char*)s; (sd = gdb_cris_memchr(hexchars, *s1, base)) != NULL; ++s1) | ||
556 | x = x * base + (sd - hexchars); | ||
557 | |||
558 | if (endptr) | ||
559 | { | ||
560 | /* Unconverted suffix is stored in endptr unless endptr is NULL. */ | ||
561 | *endptr = s1; | ||
562 | } | ||
563 | |||
564 | return x; | ||
565 | } | ||
566 | |||
567 | int | ||
568 | double_this(int x) | ||
569 | { | ||
570 | return 2 * x; | ||
571 | } | ||
572 | |||
573 | /********************************* Register image ****************************/ | ||
574 | /* Copy the content of a register image into another. The size n is | ||
575 | the size of the register image. Due to struct assignment generation of | ||
576 | memcpy in libc. */ | ||
577 | static void | ||
578 | copy_registers (registers *dptr, registers *sptr, int n) | ||
579 | { | ||
580 | unsigned char *dreg; | ||
581 | unsigned char *sreg; | ||
582 | |||
583 | for (dreg = (unsigned char*)dptr, sreg = (unsigned char*)sptr; n > 0; n--) | ||
584 | *dreg++ = *sreg++; | ||
585 | } | ||
586 | |||
587 | #ifdef PROCESS_SUPPORT | ||
588 | /* Copy the stored registers from the stack. Put the register contents | ||
589 | of thread thread_id in the struct reg. */ | ||
590 | static void | ||
591 | copy_registers_from_stack (int thread_id, registers *regptr) | ||
592 | { | ||
593 | int j; | ||
594 | stack_registers *s = (stack_registers *)stack_list[thread_id]; | ||
595 | unsigned int *d = (unsigned int *)regptr; | ||
596 | |||
597 | for (j = 13; j >= 0; j--) | ||
598 | *d++ = s->r[j]; | ||
599 | regptr->sp = (unsigned int)stack_list[thread_id]; | ||
600 | regptr->pc = s->pc; | ||
601 | regptr->dccr = s->dccr; | ||
602 | regptr->srp = s->srp; | ||
603 | } | ||
604 | |||
605 | /* Copy the registers to the stack. Put the register contents of thread | ||
606 | thread_id from struct reg to the stack. */ | ||
607 | static void | ||
608 | copy_registers_to_stack (int thread_id, registers *regptr) | ||
609 | { | ||
610 | int i; | ||
611 | stack_registers *d = (stack_registers *)stack_list[thread_id]; | ||
612 | unsigned int *s = (unsigned int *)regptr; | ||
613 | |||
614 | for (i = 0; i < 14; i++) { | ||
615 | d->r[i] = *s++; | ||
616 | } | ||
617 | d->pc = regptr->pc; | ||
618 | d->dccr = regptr->dccr; | ||
619 | d->srp = regptr->srp; | ||
620 | } | ||
621 | #endif | ||
622 | |||
623 | /* Write a value to a specified register in the register image of the current | ||
624 | thread. Returns status code SUCCESS, E02 or E05. */ | ||
625 | static int | ||
626 | write_register (int regno, char *val) | ||
627 | { | ||
628 | int status = SUCCESS; | ||
629 | registers *current_reg = ® | ||
630 | |||
631 | if (regno >= R0 && regno <= PC) { | ||
632 | /* 32-bit register with simple offset. */ | ||
633 | hex2mem ((unsigned char *)current_reg + regno * sizeof(unsigned int), | ||
634 | val, sizeof(unsigned int)); | ||
635 | } | ||
636 | else if (regno == P0 || regno == VR || regno == P4 || regno == P8) { | ||
637 | /* Do not support read-only registers. */ | ||
638 | status = E02; | ||
639 | } | ||
640 | else if (regno == CCR) { | ||
641 | /* 16 bit register with complex offset. (P4 is read-only, P6 is not implemented, | ||
642 | and P7 (MOF) is 32 bits in ETRAX 100LX. */ | ||
643 | hex2mem ((unsigned char *)&(current_reg->ccr) + (regno-CCR) * sizeof(unsigned short), | ||
644 | val, sizeof(unsigned short)); | ||
645 | } | ||
646 | else if (regno >= MOF && regno <= USP) { | ||
647 | /* 32 bit register with complex offset. (P8 has been taken care of.) */ | ||
648 | hex2mem ((unsigned char *)&(current_reg->ibr) + (regno-IBR) * sizeof(unsigned int), | ||
649 | val, sizeof(unsigned int)); | ||
650 | } | ||
651 | else { | ||
652 | /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ | ||
653 | status = E05; | ||
654 | } | ||
655 | return status; | ||
656 | } | ||
657 | |||
658 | #ifdef PROCESS_SUPPORT | ||
659 | /* Write a value to a specified register in the stack of a thread other | ||
660 | than the current thread. Returns status code SUCCESS or E07. */ | ||
661 | static int | ||
662 | write_stack_register (int thread_id, int regno, char *valptr) | ||
663 | { | ||
664 | int status = SUCCESS; | ||
665 | stack_registers *d = (stack_registers *)stack_list[thread_id]; | ||
666 | unsigned int val; | ||
667 | |||
668 | hex2mem ((unsigned char *)&val, valptr, sizeof(unsigned int)); | ||
669 | if (regno >= R0 && regno < SP) { | ||
670 | d->r[regno] = val; | ||
671 | } | ||
672 | else if (regno == SP) { | ||
673 | stack_list[thread_id] = val; | ||
674 | } | ||
675 | else if (regno == PC) { | ||
676 | d->pc = val; | ||
677 | } | ||
678 | else if (regno == SRP) { | ||
679 | d->srp = val; | ||
680 | } | ||
681 | else if (regno == DCCR) { | ||
682 | d->dccr = val; | ||
683 | } | ||
684 | else { | ||
685 | /* Do not support registers in the current thread. */ | ||
686 | status = E07; | ||
687 | } | ||
688 | return status; | ||
689 | } | ||
690 | #endif | ||
691 | |||
692 | /* Read a value from a specified register in the register image. Returns the | ||
693 | value in the register or -1 for non-implemented registers. | ||
694 | Should check consistency_status after a call which may be E05 after changes | ||
695 | in the implementation. */ | ||
696 | static int | ||
697 | read_register (char regno, unsigned int *valptr) | ||
698 | { | ||
699 | registers *current_reg = ® | ||
700 | |||
701 | if (regno >= R0 && regno <= PC) { | ||
702 | /* 32-bit register with simple offset. */ | ||
703 | *valptr = *(unsigned int *)((char *)current_reg + regno * sizeof(unsigned int)); | ||
704 | return SUCCESS; | ||
705 | } | ||
706 | else if (regno == P0 || regno == VR) { | ||
707 | /* 8 bit register with complex offset. */ | ||
708 | *valptr = (unsigned int)(*(unsigned char *) | ||
709 | ((char *)&(current_reg->p0) + (regno-P0) * sizeof(char))); | ||
710 | return SUCCESS; | ||
711 | } | ||
712 | else if (regno == P4 || regno == CCR) { | ||
713 | /* 16 bit register with complex offset. */ | ||
714 | *valptr = (unsigned int)(*(unsigned short *) | ||
715 | ((char *)&(current_reg->p4) + (regno-P4) * sizeof(unsigned short))); | ||
716 | return SUCCESS; | ||
717 | } | ||
718 | else if (regno >= MOF && regno <= USP) { | ||
719 | /* 32 bit register with complex offset. */ | ||
720 | *valptr = *(unsigned int *)((char *)&(current_reg->p8) | ||
721 | + (regno-P8) * sizeof(unsigned int)); | ||
722 | return SUCCESS; | ||
723 | } | ||
724 | else { | ||
725 | /* Do not support nonexisting or unimplemented registers (P2, P3, and P6). */ | ||
726 | consistency_status = E05; | ||
727 | return E05; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | /********************************** Packet I/O ******************************/ | ||
732 | /* Returns the character equivalent of a nibble, bit 7, 6, 5, and 4 of a byte, | ||
733 | represented by int x. */ | ||
734 | static inline char | ||
735 | highhex(int x) | ||
736 | { | ||
737 | return hexchars[(x >> 4) & 0xf]; | ||
738 | } | ||
739 | |||
740 | /* Returns the character equivalent of a nibble, bit 3, 2, 1, and 0 of a byte, | ||
741 | represented by int x. */ | ||
742 | static inline char | ||
743 | lowhex(int x) | ||
744 | { | ||
745 | return hexchars[x & 0xf]; | ||
746 | } | ||
747 | |||
748 | /* Returns the integer equivalent of a hexadecimal character. */ | ||
749 | static int | ||
750 | hex (char ch) | ||
751 | { | ||
752 | if ((ch >= 'a') && (ch <= 'f')) | ||
753 | return (ch - 'a' + 10); | ||
754 | if ((ch >= '0') && (ch <= '9')) | ||
755 | return (ch - '0'); | ||
756 | if ((ch >= 'A') && (ch <= 'F')) | ||
757 | return (ch - 'A' + 10); | ||
758 | return (-1); | ||
759 | } | ||
760 | |||
761 | /* Convert the memory, pointed to by mem into hexadecimal representation. | ||
762 | Put the result in buf, and return a pointer to the last character | ||
763 | in buf (null). */ | ||
764 | |||
765 | static int do_printk = 0; | ||
766 | |||
767 | static char * | ||
768 | mem2hex(char *buf, unsigned char *mem, int count) | ||
769 | { | ||
770 | int i; | ||
771 | int ch; | ||
772 | |||
773 | if (mem == NULL) { | ||
774 | /* Bogus read from m0. FIXME: What constitutes a valid address? */ | ||
775 | for (i = 0; i < count; i++) { | ||
776 | *buf++ = '0'; | ||
777 | *buf++ = '0'; | ||
778 | } | ||
779 | } else { | ||
780 | /* Valid mem address. */ | ||
781 | for (i = 0; i < count; i++) { | ||
782 | ch = *mem++; | ||
783 | *buf++ = highhex (ch); | ||
784 | *buf++ = lowhex (ch); | ||
785 | } | ||
786 | } | ||
787 | |||
788 | /* Terminate properly. */ | ||
789 | *buf = '\0'; | ||
790 | return (buf); | ||
791 | } | ||
792 | |||
793 | /* Convert the array, in hexadecimal representation, pointed to by buf into | ||
794 | binary representation. Put the result in mem, and return a pointer to | ||
795 | the character after the last byte written. */ | ||
796 | static unsigned char* | ||
797 | hex2mem (unsigned char *mem, char *buf, int count) | ||
798 | { | ||
799 | int i; | ||
800 | unsigned char ch; | ||
801 | for (i = 0; i < count; i++) { | ||
802 | ch = hex (*buf++) << 4; | ||
803 | ch = ch + hex (*buf++); | ||
804 | *mem++ = ch; | ||
805 | } | ||
806 | return (mem); | ||
807 | } | ||
808 | |||
809 | /* Put the content of the array, in binary representation, pointed to by buf | ||
810 | into memory pointed to by mem, and return a pointer to the character after | ||
811 | the last byte written. | ||
812 | Gdb will escape $, #, and the escape char (0x7d). */ | ||
813 | static unsigned char* | ||
814 | bin2mem (unsigned char *mem, unsigned char *buf, int count) | ||
815 | { | ||
816 | int i; | ||
817 | unsigned char *next; | ||
818 | for (i = 0; i < count; i++) { | ||
819 | /* Check for any escaped characters. Be paranoid and | ||
820 | only unescape chars that should be escaped. */ | ||
821 | if (*buf == 0x7d) { | ||
822 | next = buf + 1; | ||
823 | if (*next == 0x3 || *next == 0x4 || *next == 0x5D) /* #, $, ESC */ | ||
824 | { | ||
825 | buf++; | ||
826 | *buf += 0x20; | ||
827 | } | ||
828 | } | ||
829 | *mem++ = *buf++; | ||
830 | } | ||
831 | return (mem); | ||
832 | } | ||
833 | |||
834 | /* Await the sequence $<data>#<checksum> and store <data> in the array buffer | ||
835 | returned. */ | ||
836 | static void | ||
837 | getpacket (char *buffer) | ||
838 | { | ||
839 | unsigned char checksum; | ||
840 | unsigned char xmitcsum; | ||
841 | int i; | ||
842 | int count; | ||
843 | char ch; | ||
844 | do { | ||
845 | while ((ch = getDebugChar ()) != '$') | ||
846 | /* Wait for the start character $ and ignore all other characters */; | ||
847 | checksum = 0; | ||
848 | xmitcsum = -1; | ||
849 | count = 0; | ||
850 | /* Read until a # or the end of the buffer is reached */ | ||
851 | while (count < BUFMAX) { | ||
852 | ch = getDebugChar (); | ||
853 | if (ch == '#') | ||
854 | break; | ||
855 | checksum = checksum + ch; | ||
856 | buffer[count] = ch; | ||
857 | count = count + 1; | ||
858 | } | ||
859 | buffer[count] = '\0'; | ||
860 | |||
861 | if (ch == '#') { | ||
862 | xmitcsum = hex (getDebugChar ()) << 4; | ||
863 | xmitcsum += hex (getDebugChar ()); | ||
864 | if (checksum != xmitcsum) { | ||
865 | /* Wrong checksum */ | ||
866 | putDebugChar ('-'); | ||
867 | } | ||
868 | else { | ||
869 | /* Correct checksum */ | ||
870 | putDebugChar ('+'); | ||
871 | /* If sequence characters are received, reply with them */ | ||
872 | if (buffer[2] == ':') { | ||
873 | putDebugChar (buffer[0]); | ||
874 | putDebugChar (buffer[1]); | ||
875 | /* Remove the sequence characters from the buffer */ | ||
876 | count = gdb_cris_strlen (buffer); | ||
877 | for (i = 3; i <= count; i++) | ||
878 | buffer[i - 3] = buffer[i]; | ||
879 | } | ||
880 | } | ||
881 | } | ||
882 | } while (checksum != xmitcsum); | ||
883 | } | ||
884 | |||
885 | /* Send $<data>#<checksum> from the <data> in the array buffer. */ | ||
886 | |||
887 | static void | ||
888 | putpacket(char *buffer) | ||
889 | { | ||
890 | int checksum; | ||
891 | int runlen; | ||
892 | int encode; | ||
893 | |||
894 | do { | ||
895 | char *src = buffer; | ||
896 | putDebugChar ('$'); | ||
897 | checksum = 0; | ||
898 | while (*src) { | ||
899 | /* Do run length encoding */ | ||
900 | putDebugChar (*src); | ||
901 | checksum += *src; | ||
902 | runlen = 0; | ||
903 | while (runlen < RUNLENMAX && *src == src[runlen]) { | ||
904 | runlen++; | ||
905 | } | ||
906 | if (runlen > 3) { | ||
907 | /* Got a useful amount */ | ||
908 | putDebugChar ('*'); | ||
909 | checksum += '*'; | ||
910 | encode = runlen + ' ' - 4; | ||
911 | putDebugChar (encode); | ||
912 | checksum += encode; | ||
913 | src += runlen; | ||
914 | } | ||
915 | else { | ||
916 | src++; | ||
917 | } | ||
918 | } | ||
919 | putDebugChar ('#'); | ||
920 | putDebugChar (highhex (checksum)); | ||
921 | putDebugChar (lowhex (checksum)); | ||
922 | } while(kgdb_started && (getDebugChar() != '+')); | ||
923 | } | ||
924 | |||
925 | /* The string str is prepended with the GDB printout token and sent. Required | ||
926 | in traditional implementations. */ | ||
927 | void | ||
928 | putDebugString (const unsigned char *str, int length) | ||
929 | { | ||
930 | remcomOutBuffer[0] = 'O'; | ||
931 | mem2hex(&remcomOutBuffer[1], (unsigned char *)str, length); | ||
932 | putpacket(remcomOutBuffer); | ||
933 | } | ||
934 | |||
935 | /********************************** Handle exceptions ************************/ | ||
936 | /* Build and send a response packet in order to inform the host the | ||
937 | stub is stopped. TAAn...:r...;n...:r...;n...:r...; | ||
938 | AA = signal number | ||
939 | n... = register number (hex) | ||
940 | r... = register contents | ||
941 | n... = `thread' | ||
942 | r... = thread process ID. This is a hex integer. | ||
943 | n... = other string not starting with valid hex digit. | ||
944 | gdb should ignore this n,r pair and go on to the next. | ||
945 | This way we can extend the protocol. */ | ||
946 | static void | ||
947 | stub_is_stopped(int sigval) | ||
948 | { | ||
949 | char *ptr = remcomOutBuffer; | ||
950 | int regno; | ||
951 | |||
952 | unsigned int reg_cont; | ||
953 | int status; | ||
954 | |||
955 | /* Send trap type (converted to signal) */ | ||
956 | |||
957 | *ptr++ = 'T'; | ||
958 | *ptr++ = highhex (sigval); | ||
959 | *ptr++ = lowhex (sigval); | ||
960 | |||
961 | /* Send register contents. We probably only need to send the | ||
962 | * PC, frame pointer and stack pointer here. Other registers will be | ||
963 | * explicitely asked for. But for now, send all. | ||
964 | */ | ||
965 | |||
966 | for (regno = R0; regno <= USP; regno++) { | ||
967 | /* Store n...:r...; for the registers in the buffer. */ | ||
968 | |||
969 | status = read_register (regno, ®_cont); | ||
970 | |||
971 | if (status == SUCCESS) { | ||
972 | |||
973 | *ptr++ = highhex (regno); | ||
974 | *ptr++ = lowhex (regno); | ||
975 | *ptr++ = ':'; | ||
976 | |||
977 | ptr = mem2hex(ptr, (unsigned char *)®_cont, | ||
978 | register_size[regno]); | ||
979 | *ptr++ = ';'; | ||
980 | } | ||
981 | |||
982 | } | ||
983 | |||
984 | #ifdef PROCESS_SUPPORT | ||
985 | /* Store the registers of the executing thread. Assume that both step, | ||
986 | continue, and register content requests are with respect to this | ||
987 | thread. The executing task is from the operating system scheduler. */ | ||
988 | |||
989 | current_thread_c = executing_task; | ||
990 | current_thread_g = executing_task; | ||
991 | |||
992 | /* A struct assignment translates into a libc memcpy call. Avoid | ||
993 | all libc functions in order to prevent recursive break points. */ | ||
994 | copy_registers (®_g, ®, sizeof(registers)); | ||
995 | |||
996 | /* Store thread:r...; with the executing task TID. */ | ||
997 | gdb_cris_strcpy (&remcomOutBuffer[pos], "thread:"); | ||
998 | pos += gdb_cris_strlen ("thread:"); | ||
999 | remcomOutBuffer[pos++] = highhex (executing_task); | ||
1000 | remcomOutBuffer[pos++] = lowhex (executing_task); | ||
1001 | gdb_cris_strcpy (&remcomOutBuffer[pos], ";"); | ||
1002 | #endif | ||
1003 | |||
1004 | /* null-terminate and send it off */ | ||
1005 | |||
1006 | *ptr = 0; | ||
1007 | |||
1008 | putpacket (remcomOutBuffer); | ||
1009 | } | ||
1010 | |||
1011 | /* All expected commands are sent from remote.c. Send a response according | ||
1012 | to the description in remote.c. */ | ||
1013 | static void | ||
1014 | handle_exception (int sigval) | ||
1015 | { | ||
1016 | /* Avoid warning of not used. */ | ||
1017 | |||
1018 | USEDFUN(handle_exception); | ||
1019 | USEDVAR(internal_stack[0]); | ||
1020 | |||
1021 | /* Send response. */ | ||
1022 | |||
1023 | stub_is_stopped (sigval); | ||
1024 | |||
1025 | for (;;) { | ||
1026 | remcomOutBuffer[0] = '\0'; | ||
1027 | getpacket (remcomInBuffer); | ||
1028 | switch (remcomInBuffer[0]) { | ||
1029 | case 'g': | ||
1030 | /* Read registers: g | ||
1031 | Success: Each byte of register data is described by two hex digits. | ||
1032 | Registers are in the internal order for GDB, and the bytes | ||
1033 | in a register are in the same order the machine uses. | ||
1034 | Failure: void. */ | ||
1035 | |||
1036 | { | ||
1037 | #ifdef PROCESS_SUPPORT | ||
1038 | /* Use the special register content in the executing thread. */ | ||
1039 | copy_registers (®_g, ®, sizeof(registers)); | ||
1040 | /* Replace the content available on the stack. */ | ||
1041 | if (current_thread_g != executing_task) { | ||
1042 | copy_registers_from_stack (current_thread_g, ®_g); | ||
1043 | } | ||
1044 | mem2hex ((unsigned char *)remcomOutBuffer, (unsigned char *)®_g, sizeof(registers)); | ||
1045 | #else | ||
1046 | mem2hex(remcomOutBuffer, (char *)®, sizeof(registers)); | ||
1047 | #endif | ||
1048 | } | ||
1049 | break; | ||
1050 | |||
1051 | case 'G': | ||
1052 | /* Write registers. GXX..XX | ||
1053 | Each byte of register data is described by two hex digits. | ||
1054 | Success: OK | ||
1055 | Failure: void. */ | ||
1056 | #ifdef PROCESS_SUPPORT | ||
1057 | hex2mem ((unsigned char *)®_g, &remcomInBuffer[1], sizeof(registers)); | ||
1058 | if (current_thread_g == executing_task) { | ||
1059 | copy_registers (®, ®_g, sizeof(registers)); | ||
1060 | } | ||
1061 | else { | ||
1062 | copy_registers_to_stack(current_thread_g, ®_g); | ||
1063 | } | ||
1064 | #else | ||
1065 | hex2mem((char *)®, &remcomInBuffer[1], sizeof(registers)); | ||
1066 | #endif | ||
1067 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1068 | break; | ||
1069 | |||
1070 | case 'P': | ||
1071 | /* Write register. Pn...=r... | ||
1072 | Write register n..., hex value without 0x, with value r..., | ||
1073 | which contains a hex value without 0x and two hex digits | ||
1074 | for each byte in the register (target byte order). P1f=11223344 means | ||
1075 | set register 31 to 44332211. | ||
1076 | Success: OK | ||
1077 | Failure: E02, E05 */ | ||
1078 | { | ||
1079 | char *suffix; | ||
1080 | int regno = gdb_cris_strtol (&remcomInBuffer[1], &suffix, 16); | ||
1081 | int status; | ||
1082 | #ifdef PROCESS_SUPPORT | ||
1083 | if (current_thread_g != executing_task) | ||
1084 | status = write_stack_register (current_thread_g, regno, suffix+1); | ||
1085 | else | ||
1086 | #endif | ||
1087 | status = write_register (regno, suffix+1); | ||
1088 | |||
1089 | switch (status) { | ||
1090 | case E02: | ||
1091 | /* Do not support read-only registers. */ | ||
1092 | gdb_cris_strcpy (remcomOutBuffer, error_message[E02]); | ||
1093 | break; | ||
1094 | case E05: | ||
1095 | /* Do not support non-existing registers. */ | ||
1096 | gdb_cris_strcpy (remcomOutBuffer, error_message[E05]); | ||
1097 | break; | ||
1098 | case E07: | ||
1099 | /* Do not support non-existing registers on the stack. */ | ||
1100 | gdb_cris_strcpy (remcomOutBuffer, error_message[E07]); | ||
1101 | break; | ||
1102 | default: | ||
1103 | /* Valid register number. */ | ||
1104 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1105 | break; | ||
1106 | } | ||
1107 | } | ||
1108 | break; | ||
1109 | |||
1110 | case 'm': | ||
1111 | /* Read from memory. mAA..AA,LLLL | ||
1112 | AA..AA is the address and LLLL is the length. | ||
1113 | Success: XX..XX is the memory content. Can be fewer bytes than | ||
1114 | requested if only part of the data may be read. m6000120a,6c means | ||
1115 | retrieve 108 byte from base address 6000120a. | ||
1116 | Failure: void. */ | ||
1117 | { | ||
1118 | char *suffix; | ||
1119 | unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], | ||
1120 | &suffix, 16); int length = gdb_cris_strtol(suffix+1, 0, 16); | ||
1121 | |||
1122 | mem2hex(remcomOutBuffer, addr, length); | ||
1123 | } | ||
1124 | break; | ||
1125 | |||
1126 | case 'X': | ||
1127 | /* Write to memory. XAA..AA,LLLL:XX..XX | ||
1128 | AA..AA is the start address, LLLL is the number of bytes, and | ||
1129 | XX..XX is the binary data. | ||
1130 | Success: OK | ||
1131 | Failure: void. */ | ||
1132 | case 'M': | ||
1133 | /* Write to memory. MAA..AA,LLLL:XX..XX | ||
1134 | AA..AA is the start address, LLLL is the number of bytes, and | ||
1135 | XX..XX is the hexadecimal data. | ||
1136 | Success: OK | ||
1137 | Failure: void. */ | ||
1138 | { | ||
1139 | char *lenptr; | ||
1140 | char *dataptr; | ||
1141 | unsigned char *addr = (unsigned char *)gdb_cris_strtol(&remcomInBuffer[1], | ||
1142 | &lenptr, 16); | ||
1143 | int length = gdb_cris_strtol(lenptr+1, &dataptr, 16); | ||
1144 | if (*lenptr == ',' && *dataptr == ':') { | ||
1145 | if (remcomInBuffer[0] == 'M') { | ||
1146 | hex2mem(addr, dataptr + 1, length); | ||
1147 | } | ||
1148 | else /* X */ { | ||
1149 | bin2mem(addr, dataptr + 1, length); | ||
1150 | } | ||
1151 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1152 | } | ||
1153 | else { | ||
1154 | gdb_cris_strcpy (remcomOutBuffer, error_message[E06]); | ||
1155 | } | ||
1156 | } | ||
1157 | break; | ||
1158 | |||
1159 | case 'c': | ||
1160 | /* Continue execution. cAA..AA | ||
1161 | AA..AA is the address where execution is resumed. If AA..AA is | ||
1162 | omitted, resume at the present address. | ||
1163 | Success: return to the executing thread. | ||
1164 | Failure: will never know. */ | ||
1165 | if (remcomInBuffer[1] != '\0') { | ||
1166 | reg.pc = gdb_cris_strtol (&remcomInBuffer[1], 0, 16); | ||
1167 | } | ||
1168 | enableDebugIRQ(); | ||
1169 | return; | ||
1170 | |||
1171 | case 's': | ||
1172 | /* Step. sAA..AA | ||
1173 | AA..AA is the address where execution is resumed. If AA..AA is | ||
1174 | omitted, resume at the present address. Success: return to the | ||
1175 | executing thread. Failure: will never know. | ||
1176 | |||
1177 | Should never be invoked. The single-step is implemented on | ||
1178 | the host side. If ever invoked, it is an internal error E04. */ | ||
1179 | gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); | ||
1180 | putpacket (remcomOutBuffer); | ||
1181 | return; | ||
1182 | |||
1183 | case '?': | ||
1184 | /* The last signal which caused a stop. ? | ||
1185 | Success: SAA, where AA is the signal number. | ||
1186 | Failure: void. */ | ||
1187 | remcomOutBuffer[0] = 'S'; | ||
1188 | remcomOutBuffer[1] = highhex (sigval); | ||
1189 | remcomOutBuffer[2] = lowhex (sigval); | ||
1190 | remcomOutBuffer[3] = 0; | ||
1191 | break; | ||
1192 | |||
1193 | case 'D': | ||
1194 | /* Detach from host. D | ||
1195 | Success: OK, and return to the executing thread. | ||
1196 | Failure: will never know */ | ||
1197 | putpacket ("OK"); | ||
1198 | return; | ||
1199 | |||
1200 | case 'k': | ||
1201 | case 'r': | ||
1202 | /* kill request or reset request. | ||
1203 | Success: restart of target. | ||
1204 | Failure: will never know. */ | ||
1205 | kill_restart (); | ||
1206 | break; | ||
1207 | |||
1208 | case 'C': | ||
1209 | case 'S': | ||
1210 | case '!': | ||
1211 | case 'R': | ||
1212 | case 'd': | ||
1213 | /* Continue with signal sig. Csig;AA..AA | ||
1214 | Step with signal sig. Ssig;AA..AA | ||
1215 | Use the extended remote protocol. ! | ||
1216 | Restart the target system. R0 | ||
1217 | Toggle debug flag. d | ||
1218 | Search backwards. tAA:PP,MM | ||
1219 | Not supported: E04 */ | ||
1220 | gdb_cris_strcpy (remcomOutBuffer, error_message[E04]); | ||
1221 | break; | ||
1222 | #ifdef PROCESS_SUPPORT | ||
1223 | |||
1224 | case 'T': | ||
1225 | /* Thread alive. TXX | ||
1226 | Is thread XX alive? | ||
1227 | Success: OK, thread XX is alive. | ||
1228 | Failure: E03, thread XX is dead. */ | ||
1229 | { | ||
1230 | int thread_id = (int)gdb_cris_strtol (&remcomInBuffer[1], 0, 16); | ||
1231 | /* Cannot tell whether it is alive or not. */ | ||
1232 | if (thread_id >= 0 && thread_id < number_of_tasks) | ||
1233 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1234 | } | ||
1235 | break; | ||
1236 | |||
1237 | case 'H': | ||
1238 | /* Set thread for subsequent operations: Hct | ||
1239 | c = 'c' for thread used in step and continue; | ||
1240 | t can be -1 for all threads. | ||
1241 | c = 'g' for thread used in other operations. | ||
1242 | t = 0 means pick any thread. | ||
1243 | Success: OK | ||
1244 | Failure: E01 */ | ||
1245 | { | ||
1246 | int thread_id = gdb_cris_strtol (&remcomInBuffer[2], 0, 16); | ||
1247 | if (remcomInBuffer[1] == 'c') { | ||
1248 | /* c = 'c' for thread used in step and continue */ | ||
1249 | /* Do not change current_thread_c here. It would create a mess in | ||
1250 | the scheduler. */ | ||
1251 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1252 | } | ||
1253 | else if (remcomInBuffer[1] == 'g') { | ||
1254 | /* c = 'g' for thread used in other operations. | ||
1255 | t = 0 means pick any thread. Impossible since the scheduler does | ||
1256 | not allow that. */ | ||
1257 | if (thread_id >= 0 && thread_id < number_of_tasks) { | ||
1258 | current_thread_g = thread_id; | ||
1259 | gdb_cris_strcpy (remcomOutBuffer, "OK"); | ||
1260 | } | ||
1261 | else { | ||
1262 | /* Not expected - send an error message. */ | ||
1263 | gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); | ||
1264 | } | ||
1265 | } | ||
1266 | else { | ||
1267 | /* Not expected - send an error message. */ | ||
1268 | gdb_cris_strcpy (remcomOutBuffer, error_message[E01]); | ||
1269 | } | ||
1270 | } | ||
1271 | break; | ||
1272 | |||
1273 | case 'q': | ||
1274 | case 'Q': | ||
1275 | /* Query of general interest. qXXXX | ||
1276 | Set general value XXXX. QXXXX=yyyy */ | ||
1277 | { | ||
1278 | int pos; | ||
1279 | int nextpos; | ||
1280 | int thread_id; | ||
1281 | |||
1282 | switch (remcomInBuffer[1]) { | ||
1283 | case 'C': | ||
1284 | /* Identify the remote current thread. */ | ||
1285 | gdb_cris_strcpy (&remcomOutBuffer[0], "QC"); | ||
1286 | remcomOutBuffer[2] = highhex (current_thread_c); | ||
1287 | remcomOutBuffer[3] = lowhex (current_thread_c); | ||
1288 | remcomOutBuffer[4] = '\0'; | ||
1289 | break; | ||
1290 | case 'L': | ||
1291 | gdb_cris_strcpy (&remcomOutBuffer[0], "QM"); | ||
1292 | /* Reply with number of threads. */ | ||
1293 | if (os_is_started()) { | ||
1294 | remcomOutBuffer[2] = highhex (number_of_tasks); | ||
1295 | remcomOutBuffer[3] = lowhex (number_of_tasks); | ||
1296 | } | ||
1297 | else { | ||
1298 | remcomOutBuffer[2] = highhex (0); | ||
1299 | remcomOutBuffer[3] = lowhex (1); | ||
1300 | } | ||
1301 | /* Done with the reply. */ | ||
1302 | remcomOutBuffer[4] = lowhex (1); | ||
1303 | pos = 5; | ||
1304 | /* Expects the argument thread id. */ | ||
1305 | for (; pos < (5 + HEXCHARS_IN_THREAD_ID); pos++) | ||
1306 | remcomOutBuffer[pos] = remcomInBuffer[pos]; | ||
1307 | /* Reply with the thread identifiers. */ | ||
1308 | if (os_is_started()) { | ||
1309 | /* Store the thread identifiers of all tasks. */ | ||
1310 | for (thread_id = 0; thread_id < number_of_tasks; thread_id++) { | ||
1311 | nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; | ||
1312 | for (; pos < nextpos; pos ++) | ||
1313 | remcomOutBuffer[pos] = lowhex (0); | ||
1314 | remcomOutBuffer[pos++] = lowhex (thread_id); | ||
1315 | } | ||
1316 | } | ||
1317 | else { | ||
1318 | /* Store the thread identifier of the boot task. */ | ||
1319 | nextpos = pos + HEXCHARS_IN_THREAD_ID - 1; | ||
1320 | for (; pos < nextpos; pos ++) | ||
1321 | remcomOutBuffer[pos] = lowhex (0); | ||
1322 | remcomOutBuffer[pos++] = lowhex (current_thread_c); | ||
1323 | } | ||
1324 | remcomOutBuffer[pos] = '\0'; | ||
1325 | break; | ||
1326 | default: | ||
1327 | /* Not supported: "" */ | ||
1328 | /* Request information about section offsets: qOffsets. */ | ||
1329 | remcomOutBuffer[0] = 0; | ||
1330 | break; | ||
1331 | } | ||
1332 | } | ||
1333 | break; | ||
1334 | #endif /* PROCESS_SUPPORT */ | ||
1335 | |||
1336 | default: | ||
1337 | /* The stub should ignore other request and send an empty | ||
1338 | response ($#<checksum>). This way we can extend the protocol and GDB | ||
1339 | can tell whether the stub it is talking to uses the old or the new. */ | ||
1340 | remcomOutBuffer[0] = 0; | ||
1341 | break; | ||
1342 | } | ||
1343 | putpacket(remcomOutBuffer); | ||
1344 | } | ||
1345 | } | ||
1346 | |||
1347 | /* The jump is to the address 0x00000002. Performs a complete re-start | ||
1348 | from scratch. */ | ||
1349 | static void | ||
1350 | kill_restart () | ||
1351 | { | ||
1352 | __asm__ volatile ("jump 2"); | ||
1353 | } | ||
1354 | |||
1355 | /********************************** Breakpoint *******************************/ | ||
1356 | /* The hook for both a static (compiled) and a dynamic breakpoint set by GDB. | ||
1357 | An internal stack is used by the stub. The register image of the caller is | ||
1358 | stored in the structure register_image. | ||
1359 | Interactive communication with the host is handled by handle_exception and | ||
1360 | finally the register image is restored. */ | ||
1361 | |||
1362 | void kgdb_handle_breakpoint(void); | ||
1363 | |||
1364 | asm (" | ||
1365 | .global kgdb_handle_breakpoint | ||
1366 | kgdb_handle_breakpoint: | ||
1367 | ;; | ||
1368 | ;; Response to the break-instruction | ||
1369 | ;; | ||
1370 | ;; Create a register image of the caller | ||
1371 | ;; | ||
1372 | move $dccr,[reg+0x5E] ; Save the flags in DCCR before disable interrupts | ||
1373 | di ; Disable interrupts | ||
1374 | move.d $r0,[reg] ; Save R0 | ||
1375 | move.d $r1,[reg+0x04] ; Save R1 | ||
1376 | move.d $r2,[reg+0x08] ; Save R2 | ||
1377 | move.d $r3,[reg+0x0C] ; Save R3 | ||
1378 | move.d $r4,[reg+0x10] ; Save R4 | ||
1379 | move.d $r5,[reg+0x14] ; Save R5 | ||
1380 | move.d $r6,[reg+0x18] ; Save R6 | ||
1381 | move.d $r7,[reg+0x1C] ; Save R7 | ||
1382 | move.d $r8,[reg+0x20] ; Save R8 | ||
1383 | move.d $r9,[reg+0x24] ; Save R9 | ||
1384 | move.d $r10,[reg+0x28] ; Save R10 | ||
1385 | move.d $r11,[reg+0x2C] ; Save R11 | ||
1386 | move.d $r12,[reg+0x30] ; Save R12 | ||
1387 | move.d $r13,[reg+0x34] ; Save R13 | ||
1388 | move.d $sp,[reg+0x38] ; Save SP (R14) | ||
1389 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1390 | .word 0xE670 ; move brp,$r0 | ||
1391 | subq 2,$r0 ; Set to address of previous instruction. | ||
1392 | move.d $r0,[reg+0x3c] ; Save the address in PC (R15) | ||
1393 | clear.b [reg+0x40] ; Clear P0 | ||
1394 | move $vr,[reg+0x41] ; Save special register P1 | ||
1395 | clear.w [reg+0x42] ; Clear P4 | ||
1396 | move $ccr,[reg+0x44] ; Save special register CCR | ||
1397 | move $mof,[reg+0x46] ; P7 | ||
1398 | clear.d [reg+0x4A] ; Clear P8 | ||
1399 | move $ibr,[reg+0x4E] ; P9, | ||
1400 | move $irp,[reg+0x52] ; P10, | ||
1401 | move $srp,[reg+0x56] ; P11, | ||
1402 | move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR | ||
1403 | ; P13, register DCCR already saved | ||
1404 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1405 | .word 0xE670 ; move brp,r0 | ||
1406 | ;; Static (compiled) breakpoints must return to the next instruction in order | ||
1407 | ;; to avoid infinite loops. Dynamic (gdb-invoked) must restore the instruction | ||
1408 | ;; in order to execute it when execution is continued. | ||
1409 | test.b [is_dyn_brkp] ; Is this a dynamic breakpoint? | ||
1410 | beq is_static ; No, a static breakpoint | ||
1411 | nop | ||
1412 | subq 2,$r0 ; rerun the instruction the break replaced | ||
1413 | is_static: | ||
1414 | moveq 1,$r1 | ||
1415 | move.b $r1,[is_dyn_brkp] ; Set the state variable to dynamic breakpoint | ||
1416 | move.d $r0,[reg+0x62] ; Save the return address in BRP | ||
1417 | move $usp,[reg+0x66] ; USP | ||
1418 | ;; | ||
1419 | ;; Handle the communication | ||
1420 | ;; | ||
1421 | move.d internal_stack+1020,$sp ; Use the internal stack which grows upward | ||
1422 | moveq 5,$r10 ; SIGTRAP | ||
1423 | jsr handle_exception ; Interactive routine | ||
1424 | ;; | ||
1425 | ;; Return to the caller | ||
1426 | ;; | ||
1427 | move.d [reg],$r0 ; Restore R0 | ||
1428 | move.d [reg+0x04],$r1 ; Restore R1 | ||
1429 | move.d [reg+0x08],$r2 ; Restore R2 | ||
1430 | move.d [reg+0x0C],$r3 ; Restore R3 | ||
1431 | move.d [reg+0x10],$r4 ; Restore R4 | ||
1432 | move.d [reg+0x14],$r5 ; Restore R5 | ||
1433 | move.d [reg+0x18],$r6 ; Restore R6 | ||
1434 | move.d [reg+0x1C],$r7 ; Restore R7 | ||
1435 | move.d [reg+0x20],$r8 ; Restore R8 | ||
1436 | move.d [reg+0x24],$r9 ; Restore R9 | ||
1437 | move.d [reg+0x28],$r10 ; Restore R10 | ||
1438 | move.d [reg+0x2C],$r11 ; Restore R11 | ||
1439 | move.d [reg+0x30],$r12 ; Restore R12 | ||
1440 | move.d [reg+0x34],$r13 ; Restore R13 | ||
1441 | ;; | ||
1442 | ;; FIXME: Which registers should be restored? | ||
1443 | ;; | ||
1444 | move.d [reg+0x38],$sp ; Restore SP (R14) | ||
1445 | move [reg+0x56],$srp ; Restore the subroutine return pointer. | ||
1446 | move [reg+0x5E],$dccr ; Restore DCCR | ||
1447 | move [reg+0x66],$usp ; Restore USP | ||
1448 | jump [reg+0x62] ; A jump to the content in register BRP works. | ||
1449 | nop ; | ||
1450 | "); | ||
1451 | |||
1452 | /* The hook for an interrupt generated by GDB. An internal stack is used | ||
1453 | by the stub. The register image of the caller is stored in the structure | ||
1454 | register_image. Interactive communication with the host is handled by | ||
1455 | handle_exception and finally the register image is restored. Due to the | ||
1456 | old assembler which does not recognise the break instruction and the | ||
1457 | breakpoint return pointer hex-code is used. */ | ||
1458 | |||
1459 | void kgdb_handle_serial(void); | ||
1460 | |||
1461 | asm (" | ||
1462 | .global kgdb_handle_serial | ||
1463 | kgdb_handle_serial: | ||
1464 | ;; | ||
1465 | ;; Response to a serial interrupt | ||
1466 | ;; | ||
1467 | |||
1468 | move $dccr,[reg+0x5E] ; Save the flags in DCCR | ||
1469 | di ; Disable interrupts | ||
1470 | move.d $r0,[reg] ; Save R0 | ||
1471 | move.d $r1,[reg+0x04] ; Save R1 | ||
1472 | move.d $r2,[reg+0x08] ; Save R2 | ||
1473 | move.d $r3,[reg+0x0C] ; Save R3 | ||
1474 | move.d $r4,[reg+0x10] ; Save R4 | ||
1475 | move.d $r5,[reg+0x14] ; Save R5 | ||
1476 | move.d $r6,[reg+0x18] ; Save R6 | ||
1477 | move.d $r7,[reg+0x1C] ; Save R7 | ||
1478 | move.d $r8,[reg+0x20] ; Save R8 | ||
1479 | move.d $r9,[reg+0x24] ; Save R9 | ||
1480 | move.d $r10,[reg+0x28] ; Save R10 | ||
1481 | move.d $r11,[reg+0x2C] ; Save R11 | ||
1482 | move.d $r12,[reg+0x30] ; Save R12 | ||
1483 | move.d $r13,[reg+0x34] ; Save R13 | ||
1484 | move.d $sp,[reg+0x38] ; Save SP (R14) | ||
1485 | move $irp,[reg+0x3c] ; Save the address in PC (R15) | ||
1486 | clear.b [reg+0x40] ; Clear P0 | ||
1487 | move $vr,[reg+0x41] ; Save special register P1, | ||
1488 | clear.w [reg+0x42] ; Clear P4 | ||
1489 | move $ccr,[reg+0x44] ; Save special register CCR | ||
1490 | move $mof,[reg+0x46] ; P7 | ||
1491 | clear.d [reg+0x4A] ; Clear P8 | ||
1492 | move $ibr,[reg+0x4E] ; P9, | ||
1493 | move $irp,[reg+0x52] ; P10, | ||
1494 | move $srp,[reg+0x56] ; P11, | ||
1495 | move $dtp0,[reg+0x5A] ; P12, register BAR, assembler might not know BAR | ||
1496 | ; P13, register DCCR already saved | ||
1497 | ;; Due to the old assembler-versions BRP might not be recognized | ||
1498 | .word 0xE670 ; move brp,r0 | ||
1499 | move.d $r0,[reg+0x62] ; Save the return address in BRP | ||
1500 | move $usp,[reg+0x66] ; USP | ||
1501 | |||
1502 | ;; get the serial character (from debugport.c) and check if it is a ctrl-c | ||
1503 | |||
1504 | jsr getDebugChar | ||
1505 | cmp.b 3, $r10 | ||
1506 | bne goback | ||
1507 | nop | ||
1508 | |||
1509 | ;; | ||
1510 | ;; Handle the communication | ||
1511 | ;; | ||
1512 | move.d internal_stack+1020,$sp ; Use the internal stack | ||
1513 | moveq 2,$r10 ; SIGINT | ||
1514 | jsr handle_exception ; Interactive routine | ||
1515 | |||
1516 | goback: | ||
1517 | ;; | ||
1518 | ;; Return to the caller | ||
1519 | ;; | ||
1520 | move.d [reg],$r0 ; Restore R0 | ||
1521 | move.d [reg+0x04],$r1 ; Restore R1 | ||
1522 | move.d [reg+0x08],$r2 ; Restore R2 | ||
1523 | move.d [reg+0x0C],$r3 ; Restore R3 | ||
1524 | move.d [reg+0x10],$r4 ; Restore R4 | ||
1525 | move.d [reg+0x14],$r5 ; Restore R5 | ||
1526 | move.d [reg+0x18],$r6 ; Restore R6 | ||
1527 | move.d [reg+0x1C],$r7 ; Restore R7 | ||
1528 | move.d [reg+0x20],$r8 ; Restore R8 | ||
1529 | move.d [reg+0x24],$r9 ; Restore R9 | ||
1530 | move.d [reg+0x28],$r10 ; Restore R10 | ||
1531 | move.d [reg+0x2C],$r11 ; Restore R11 | ||
1532 | move.d [reg+0x30],$r12 ; Restore R12 | ||
1533 | move.d [reg+0x34],$r13 ; Restore R13 | ||
1534 | ;; | ||
1535 | ;; FIXME: Which registers should be restored? | ||
1536 | ;; | ||
1537 | move.d [reg+0x38],$sp ; Restore SP (R14) | ||
1538 | move [reg+0x56],$srp ; Restore the subroutine return pointer. | ||
1539 | move [reg+0x5E],$dccr ; Restore DCCR | ||
1540 | move [reg+0x66],$usp ; Restore USP | ||
1541 | reti ; Return from the interrupt routine | ||
1542 | nop | ||
1543 | "); | ||
1544 | |||
1545 | /* Use this static breakpoint in the start-up only. */ | ||
1546 | |||
1547 | void | ||
1548 | breakpoint(void) | ||
1549 | { | ||
1550 | kgdb_started = 1; | ||
1551 | is_dyn_brkp = 0; /* This is a static, not a dynamic breakpoint. */ | ||
1552 | __asm__ volatile ("break 8"); /* Jump to handle_breakpoint. */ | ||
1553 | } | ||
1554 | |||
1555 | /* initialize kgdb. doesn't break into the debugger, but sets up irq and ports */ | ||
1556 | |||
1557 | void | ||
1558 | kgdb_init(void) | ||
1559 | { | ||
1560 | /* could initialize debug port as well but it's done in head.S already... */ | ||
1561 | |||
1562 | /* breakpoint handler is now set in irq.c */ | ||
1563 | set_int_vector(8, kgdb_handle_serial); | ||
1564 | |||
1565 | enableDebugIRQ(); | ||
1566 | } | ||
1567 | |||
1568 | /****************************** End of file **********************************/ | ||
diff --git a/arch/cris/arch-v10/kernel/process.c b/arch/cris/arch-v10/kernel/process.c new file mode 100644 index 000000000000..87ff37790827 --- /dev/null +++ b/arch/cris/arch-v10/kernel/process.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* $Id: process.c,v 1.9 2004/10/19 13:07:37 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/process.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (C) 2000-2002 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
9 | * Mikael Starvik (starvik@axis.com) | ||
10 | * | ||
11 | * This file handles the architecture-dependent parts of process handling.. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/fs.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <asm/arch/svinto.h> | ||
20 | #include <linux/init.h> | ||
21 | |||
22 | #ifdef CONFIG_ETRAX_GPIO | ||
23 | void etrax_gpio_wake_up_check(void); /* drivers/gpio.c */ | ||
24 | #endif | ||
25 | |||
26 | /* | ||
27 | * We use this if we don't have any better | ||
28 | * idle routine.. | ||
29 | */ | ||
30 | void default_idle(void) | ||
31 | { | ||
32 | #ifdef CONFIG_ETRAX_GPIO | ||
33 | etrax_gpio_wake_up_check(); | ||
34 | #endif | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Free current thread data structures etc.. | ||
39 | */ | ||
40 | |||
41 | void exit_thread(void) | ||
42 | { | ||
43 | /* Nothing needs to be done. */ | ||
44 | } | ||
45 | |||
46 | /* if the watchdog is enabled, we can simply disable interrupts and go | ||
47 | * into an eternal loop, and the watchdog will reset the CPU after 0.1s | ||
48 | * if on the other hand the watchdog wasn't enabled, we just enable it and wait | ||
49 | */ | ||
50 | |||
51 | void hard_reset_now (void) | ||
52 | { | ||
53 | /* | ||
54 | * Don't declare this variable elsewhere. We don't want any other | ||
55 | * code to know about it than the watchdog handler in entry.S and | ||
56 | * this code, implementing hard reset through the watchdog. | ||
57 | */ | ||
58 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
59 | extern int cause_of_death; | ||
60 | #endif | ||
61 | |||
62 | printk("*** HARD RESET ***\n"); | ||
63 | local_irq_disable(); | ||
64 | |||
65 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
66 | cause_of_death = 0xbedead; | ||
67 | #else | ||
68 | /* Since we dont plan to keep on reseting the watchdog, | ||
69 | the key can be arbitrary hence three */ | ||
70 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, 3) | | ||
71 | IO_STATE(R_WATCHDOG, enable, start); | ||
72 | #endif | ||
73 | |||
74 | while(1) /* waiting for RETRIBUTION! */ ; | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Return saved PC of a blocked thread. | ||
79 | */ | ||
80 | unsigned long thread_saved_pc(struct task_struct *t) | ||
81 | { | ||
82 | return (unsigned long)user_regs(t->thread_info)->irp; | ||
83 | } | ||
84 | |||
85 | static void kernel_thread_helper(void* dummy, int (*fn)(void *), void * arg) | ||
86 | { | ||
87 | fn(arg); | ||
88 | do_exit(-1); /* Should never be called, return bad exit value */ | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Create a kernel thread | ||
93 | */ | ||
94 | int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | ||
95 | { | ||
96 | struct pt_regs regs; | ||
97 | |||
98 | memset(®s, 0, sizeof(regs)); | ||
99 | |||
100 | /* Don't use r10 since that is set to 0 in copy_thread */ | ||
101 | regs.r11 = (unsigned long)fn; | ||
102 | regs.r12 = (unsigned long)arg; | ||
103 | regs.irp = (unsigned long)kernel_thread_helper; | ||
104 | |||
105 | /* Ok, create the new process.. */ | ||
106 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
107 | } | ||
108 | |||
109 | /* setup the child's kernel stack with a pt_regs and switch_stack on it. | ||
110 | * it will be un-nested during _resume and _ret_from_sys_call when the | ||
111 | * new thread is scheduled. | ||
112 | * | ||
113 | * also setup the thread switching structure which is used to keep | ||
114 | * thread-specific data during _resumes. | ||
115 | * | ||
116 | */ | ||
117 | asmlinkage void ret_from_fork(void); | ||
118 | |||
119 | int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | ||
120 | unsigned long unused, | ||
121 | struct task_struct *p, struct pt_regs *regs) | ||
122 | { | ||
123 | struct pt_regs * childregs; | ||
124 | struct switch_stack *swstack; | ||
125 | |||
126 | /* put the pt_regs structure at the end of the new kernel stack page and fix it up | ||
127 | * remember that the task_struct doubles as the kernel stack for the task | ||
128 | */ | ||
129 | |||
130 | childregs = user_regs(p->thread_info); | ||
131 | |||
132 | *childregs = *regs; /* struct copy of pt_regs */ | ||
133 | |||
134 | p->set_child_tid = p->clear_child_tid = NULL; | ||
135 | |||
136 | childregs->r10 = 0; /* child returns 0 after a fork/clone */ | ||
137 | |||
138 | /* put the switch stack right below the pt_regs */ | ||
139 | |||
140 | swstack = ((struct switch_stack *)childregs) - 1; | ||
141 | |||
142 | swstack->r9 = 0; /* parameter to ret_from_sys_call, 0 == dont restart the syscall */ | ||
143 | |||
144 | /* we want to return into ret_from_sys_call after the _resume */ | ||
145 | |||
146 | swstack->return_ip = (unsigned long) ret_from_fork; /* Will call ret_from_sys_call */ | ||
147 | |||
148 | /* fix the user-mode stackpointer */ | ||
149 | |||
150 | p->thread.usp = usp; | ||
151 | |||
152 | /* and the kernel-mode one */ | ||
153 | |||
154 | p->thread.ksp = (unsigned long) swstack; | ||
155 | |||
156 | #ifdef DEBUG | ||
157 | printk("copy_thread: new regs at 0x%p, as shown below:\n", childregs); | ||
158 | show_registers(childregs); | ||
159 | #endif | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Be aware of the "magic" 7th argument in the four system-calls below. | ||
166 | * They need the latest stackframe, which is put as the 7th argument by | ||
167 | * entry.S. The previous arguments are dummies or actually used, but need | ||
168 | * to be defined to reach the 7th argument. | ||
169 | * | ||
170 | * N.B.: Another method to get the stackframe is to use current_regs(). But | ||
171 | * it returns the latest stack-frame stacked when going from _user mode_ and | ||
172 | * some of these (at least sys_clone) are called from kernel-mode sometimes | ||
173 | * (for example during kernel_thread, above) and thus cannot use it. Thus, | ||
174 | * to be sure not to get any surprises, we use the method for the other calls | ||
175 | * as well. | ||
176 | */ | ||
177 | |||
178 | asmlinkage int sys_fork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
179 | struct pt_regs *regs) | ||
180 | { | ||
181 | return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
182 | } | ||
183 | |||
184 | /* if newusp is 0, we just grab the old usp */ | ||
185 | /* FIXME: Is parent_tid/child_tid really third/fourth argument? Update lib? */ | ||
186 | asmlinkage int sys_clone(unsigned long newusp, unsigned long flags, | ||
187 | int* parent_tid, int* child_tid, long mof, long srp, | ||
188 | struct pt_regs *regs) | ||
189 | { | ||
190 | if (!newusp) | ||
191 | newusp = rdusp(); | ||
192 | return do_fork(flags, newusp, regs, 0, parent_tid, child_tid); | ||
193 | } | ||
194 | |||
195 | /* vfork is a system call in i386 because of register-pressure - maybe | ||
196 | * we can remove it and handle it in libc but we put it here until then. | ||
197 | */ | ||
198 | |||
199 | asmlinkage int sys_vfork(long r10, long r11, long r12, long r13, long mof, long srp, | ||
200 | struct pt_regs *regs) | ||
201 | { | ||
202 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * sys_execve() executes a new program. | ||
207 | */ | ||
208 | asmlinkage int sys_execve(const char *fname, char **argv, char **envp, | ||
209 | long r13, long mof, long srp, | ||
210 | struct pt_regs *regs) | ||
211 | { | ||
212 | int error; | ||
213 | char *filename; | ||
214 | |||
215 | filename = getname(fname); | ||
216 | error = PTR_ERR(filename); | ||
217 | |||
218 | if (IS_ERR(filename)) | ||
219 | goto out; | ||
220 | error = do_execve(filename, argv, envp, regs); | ||
221 | putname(filename); | ||
222 | out: | ||
223 | return error; | ||
224 | } | ||
225 | |||
226 | unsigned long get_wchan(struct task_struct *p) | ||
227 | { | ||
228 | #if 0 | ||
229 | /* YURGH. TODO. */ | ||
230 | |||
231 | unsigned long ebp, esp, eip; | ||
232 | unsigned long stack_page; | ||
233 | int count = 0; | ||
234 | if (!p || p == current || p->state == TASK_RUNNING) | ||
235 | return 0; | ||
236 | stack_page = (unsigned long)p; | ||
237 | esp = p->thread.esp; | ||
238 | if (!stack_page || esp < stack_page || esp > 8188+stack_page) | ||
239 | return 0; | ||
240 | /* include/asm-i386/system.h:switch_to() pushes ebp last. */ | ||
241 | ebp = *(unsigned long *) esp; | ||
242 | do { | ||
243 | if (ebp < stack_page || ebp > 8184+stack_page) | ||
244 | return 0; | ||
245 | eip = *(unsigned long *) (ebp+4); | ||
246 | if (!in_sched_functions(eip)) | ||
247 | return eip; | ||
248 | ebp = *(unsigned long *) ebp; | ||
249 | } while (count++ < 16); | ||
250 | #endif | ||
251 | return 0; | ||
252 | } | ||
253 | #undef last_sched | ||
254 | #undef first_sched | ||
255 | |||
256 | void show_regs(struct pt_regs * regs) | ||
257 | { | ||
258 | unsigned long usp = rdusp(); | ||
259 | printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", | ||
260 | regs->irp, regs->srp, regs->dccr, usp, regs->mof ); | ||
261 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", | ||
262 | regs->r0, regs->r1, regs->r2, regs->r3); | ||
263 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | ||
264 | regs->r4, regs->r5, regs->r6, regs->r7); | ||
265 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | ||
266 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
267 | printk("r12: %08lx r13: %08lx oR10: %08lx\n", | ||
268 | regs->r12, regs->r13, regs->orig_r10); | ||
269 | } | ||
270 | |||
diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c new file mode 100644 index 000000000000..da15db8ae482 --- /dev/null +++ b/arch/cris/arch-v10/kernel/ptrace.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000-2003, Axis Communications AB. | ||
3 | */ | ||
4 | |||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <linux/mm.h> | ||
8 | #include <linux/smp.h> | ||
9 | #include <linux/smp_lock.h> | ||
10 | #include <linux/errno.h> | ||
11 | #include <linux/ptrace.h> | ||
12 | #include <linux/user.h> | ||
13 | |||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/pgtable.h> | ||
17 | #include <asm/system.h> | ||
18 | #include <asm/processor.h> | ||
19 | |||
20 | /* | ||
21 | * Determines which bits in DCCR the user has access to. | ||
22 | * 1 = access, 0 = no access. | ||
23 | */ | ||
24 | #define DCCR_MASK 0x0000001f /* XNZVC */ | ||
25 | |||
26 | /* | ||
27 | * Get contents of register REGNO in task TASK. | ||
28 | */ | ||
29 | inline long get_reg(struct task_struct *task, unsigned int regno) | ||
30 | { | ||
31 | /* USP is a special case, it's not in the pt_regs struct but | ||
32 | * in the tasks thread struct | ||
33 | */ | ||
34 | |||
35 | if (regno == PT_USP) | ||
36 | return task->thread.usp; | ||
37 | else if (regno < PT_MAX) | ||
38 | return ((unsigned long *)user_regs(task->thread_info))[regno]; | ||
39 | else | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * Write contents of register REGNO in task TASK. | ||
45 | */ | ||
46 | inline int put_reg(struct task_struct *task, unsigned int regno, | ||
47 | unsigned long data) | ||
48 | { | ||
49 | if (regno == PT_USP) | ||
50 | task->thread.usp = data; | ||
51 | else if (regno < PT_MAX) | ||
52 | ((unsigned long *)user_regs(task->thread_info))[regno] = data; | ||
53 | else | ||
54 | return -1; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * Called by kernel/ptrace.c when detaching. | ||
60 | * | ||
61 | * Make sure the single step bit is not set. | ||
62 | */ | ||
63 | void | ||
64 | ptrace_disable(struct task_struct *child) | ||
65 | { | ||
66 | /* Todo - pending singlesteps? */ | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * Note that this implementation of ptrace behaves differently from vanilla | ||
71 | * ptrace. Contrary to what the man page says, in the PTRACE_PEEKTEXT, | ||
72 | * PTRACE_PEEKDATA, and PTRACE_PEEKUSER requests the data variable is not | ||
73 | * ignored. Instead, the data variable is expected to point at a location | ||
74 | * (in user space) where the result of the ptrace call is written (instead of | ||
75 | * being returned). | ||
76 | */ | ||
77 | asmlinkage int | ||
78 | sys_ptrace(long request, long pid, long addr, long data) | ||
79 | { | ||
80 | struct task_struct *child; | ||
81 | int ret; | ||
82 | unsigned long __user *datap = (unsigned long __user *)data; | ||
83 | |||
84 | lock_kernel(); | ||
85 | ret = -EPERM; | ||
86 | |||
87 | if (request == PTRACE_TRACEME) { | ||
88 | if (current->ptrace & PT_PTRACED) | ||
89 | goto out; | ||
90 | |||
91 | current->ptrace |= PT_PTRACED; | ||
92 | ret = 0; | ||
93 | goto out; | ||
94 | } | ||
95 | |||
96 | ret = -ESRCH; | ||
97 | read_lock(&tasklist_lock); | ||
98 | child = find_task_by_pid(pid); | ||
99 | |||
100 | if (child) | ||
101 | get_task_struct(child); | ||
102 | |||
103 | read_unlock(&tasklist_lock); | ||
104 | |||
105 | if (!child) | ||
106 | goto out; | ||
107 | |||
108 | ret = -EPERM; | ||
109 | |||
110 | if (pid == 1) /* Leave the init process alone! */ | ||
111 | goto out_tsk; | ||
112 | |||
113 | if (request == PTRACE_ATTACH) { | ||
114 | ret = ptrace_attach(child); | ||
115 | goto out_tsk; | ||
116 | } | ||
117 | |||
118 | ret = ptrace_check_attach(child, request == PTRACE_KILL); | ||
119 | if (ret < 0) | ||
120 | goto out_tsk; | ||
121 | |||
122 | switch (request) { | ||
123 | /* Read word at location address. */ | ||
124 | case PTRACE_PEEKTEXT: | ||
125 | case PTRACE_PEEKDATA: { | ||
126 | unsigned long tmp; | ||
127 | int copied; | ||
128 | |||
129 | copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); | ||
130 | ret = -EIO; | ||
131 | |||
132 | if (copied != sizeof(tmp)) | ||
133 | break; | ||
134 | |||
135 | ret = put_user(tmp,datap); | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | /* Read the word at location address in the USER area. */ | ||
140 | case PTRACE_PEEKUSR: { | ||
141 | unsigned long tmp; | ||
142 | |||
143 | ret = -EIO; | ||
144 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) | ||
145 | break; | ||
146 | |||
147 | tmp = get_reg(child, addr >> 2); | ||
148 | ret = put_user(tmp, datap); | ||
149 | break; | ||
150 | } | ||
151 | |||
152 | /* Write the word at location address. */ | ||
153 | case PTRACE_POKETEXT: | ||
154 | case PTRACE_POKEDATA: | ||
155 | ret = 0; | ||
156 | |||
157 | if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data)) | ||
158 | break; | ||
159 | |||
160 | ret = -EIO; | ||
161 | break; | ||
162 | |||
163 | /* Write the word at location address in the USER area. */ | ||
164 | case PTRACE_POKEUSR: | ||
165 | ret = -EIO; | ||
166 | if ((addr & 3) || addr < 0 || addr > PT_MAX << 2) | ||
167 | break; | ||
168 | |||
169 | addr >>= 2; | ||
170 | |||
171 | if (addr == PT_DCCR) { | ||
172 | /* don't allow the tracing process to change stuff like | ||
173 | * interrupt enable, kernel/user bit, dma enables etc. | ||
174 | */ | ||
175 | data &= DCCR_MASK; | ||
176 | data |= get_reg(child, PT_DCCR) & ~DCCR_MASK; | ||
177 | } | ||
178 | if (put_reg(child, addr, data)) | ||
179 | break; | ||
180 | ret = 0; | ||
181 | break; | ||
182 | |||
183 | case PTRACE_SYSCALL: | ||
184 | case PTRACE_CONT: | ||
185 | ret = -EIO; | ||
186 | |||
187 | if ((unsigned long) data > _NSIG) | ||
188 | break; | ||
189 | |||
190 | if (request == PTRACE_SYSCALL) { | ||
191 | set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
192 | } | ||
193 | else { | ||
194 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
195 | } | ||
196 | |||
197 | child->exit_code = data; | ||
198 | |||
199 | /* TODO: make sure any pending breakpoint is killed */ | ||
200 | wake_up_process(child); | ||
201 | ret = 0; | ||
202 | |||
203 | break; | ||
204 | |||
205 | /* Make the child exit by sending it a sigkill. */ | ||
206 | case PTRACE_KILL: | ||
207 | ret = 0; | ||
208 | |||
209 | if (child->state == TASK_ZOMBIE) | ||
210 | break; | ||
211 | |||
212 | child->exit_code = SIGKILL; | ||
213 | |||
214 | /* TODO: make sure any pending breakpoint is killed */ | ||
215 | wake_up_process(child); | ||
216 | break; | ||
217 | |||
218 | /* Set the trap flag. */ | ||
219 | case PTRACE_SINGLESTEP: | ||
220 | ret = -EIO; | ||
221 | |||
222 | if ((unsigned long) data > _NSIG) | ||
223 | break; | ||
224 | |||
225 | clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); | ||
226 | |||
227 | /* TODO: set some clever breakpoint mechanism... */ | ||
228 | |||
229 | child->exit_code = data; | ||
230 | wake_up_process(child); | ||
231 | ret = 0; | ||
232 | break; | ||
233 | |||
234 | case PTRACE_DETACH: | ||
235 | ret = ptrace_detach(child, data); | ||
236 | break; | ||
237 | |||
238 | /* Get all GP registers from the child. */ | ||
239 | case PTRACE_GETREGS: { | ||
240 | int i; | ||
241 | unsigned long tmp; | ||
242 | |||
243 | for (i = 0; i <= PT_MAX; i++) { | ||
244 | tmp = get_reg(child, i); | ||
245 | |||
246 | if (put_user(tmp, datap)) { | ||
247 | ret = -EFAULT; | ||
248 | goto out_tsk; | ||
249 | } | ||
250 | |||
251 | data += sizeof(long); | ||
252 | } | ||
253 | |||
254 | ret = 0; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | /* Set all GP registers in the child. */ | ||
259 | case PTRACE_SETREGS: { | ||
260 | int i; | ||
261 | unsigned long tmp; | ||
262 | |||
263 | for (i = 0; i <= PT_MAX; i++) { | ||
264 | if (get_user(tmp, datap)) { | ||
265 | ret = -EFAULT; | ||
266 | goto out_tsk; | ||
267 | } | ||
268 | |||
269 | if (i == PT_DCCR) { | ||
270 | tmp &= DCCR_MASK; | ||
271 | tmp |= get_reg(child, PT_DCCR) & ~DCCR_MASK; | ||
272 | } | ||
273 | |||
274 | put_reg(child, i, tmp); | ||
275 | data += sizeof(long); | ||
276 | } | ||
277 | |||
278 | ret = 0; | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | default: | ||
283 | ret = ptrace_request(child, request, addr, data); | ||
284 | break; | ||
285 | } | ||
286 | out_tsk: | ||
287 | put_task_struct(child); | ||
288 | out: | ||
289 | unlock_kernel(); | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | void do_syscall_trace(void) | ||
294 | { | ||
295 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
296 | return; | ||
297 | |||
298 | if (!(current->ptrace & PT_PTRACED)) | ||
299 | return; | ||
300 | |||
301 | /* the 0x80 provides a way for the tracing parent to distinguish | ||
302 | between a syscall stop and SIGTRAP delivery */ | ||
303 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) | ||
304 | ? 0x80 : 0)); | ||
305 | |||
306 | /* | ||
307 | * This isn't the same as continuing with a signal, but it will do for | ||
308 | * normal use. | ||
309 | */ | ||
310 | if (current->exit_code) { | ||
311 | send_sig(current->exit_code, current, 1); | ||
312 | current->exit_code = 0; | ||
313 | } | ||
314 | } | ||
diff --git a/arch/cris/arch-v10/kernel/setup.c b/arch/cris/arch-v10/kernel/setup.c new file mode 100644 index 000000000000..b668d7fb68ee --- /dev/null +++ b/arch/cris/arch-v10/kernel/setup.c | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/kernel/setup.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (c) 2001-2002 Axis Communications AB | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of initialization | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | #include <linux/delay.h> | ||
17 | |||
18 | #ifdef CONFIG_PROC_FS | ||
19 | #define HAS_FPU 0x0001 | ||
20 | #define HAS_MMU 0x0002 | ||
21 | #define HAS_ETHERNET100 0x0004 | ||
22 | #define HAS_TOKENRING 0x0008 | ||
23 | #define HAS_SCSI 0x0010 | ||
24 | #define HAS_ATA 0x0020 | ||
25 | #define HAS_USB 0x0040 | ||
26 | #define HAS_IRQ_BUG 0x0080 | ||
27 | #define HAS_MMU_BUG 0x0100 | ||
28 | |||
29 | static struct cpu_info { | ||
30 | char *model; | ||
31 | unsigned short cache; | ||
32 | unsigned short flags; | ||
33 | } cpu_info[] = { | ||
34 | /* The first four models will never ever run this code and are | ||
35 | only here for display. */ | ||
36 | { "ETRAX 1", 0, 0 }, | ||
37 | { "ETRAX 2", 0, 0 }, | ||
38 | { "ETRAX 3", 0, HAS_TOKENRING }, | ||
39 | { "ETRAX 4", 0, HAS_TOKENRING | HAS_SCSI }, | ||
40 | { "Unknown", 0, 0 }, | ||
41 | { "Unknown", 0, 0 }, | ||
42 | { "Unknown", 0, 0 }, | ||
43 | { "Simulator", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, | ||
44 | { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_IRQ_BUG }, | ||
45 | { "ETRAX 100", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA }, | ||
46 | { "ETRAX 100LX", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU | HAS_MMU_BUG }, | ||
47 | { "ETRAX 100LX v2", 8, HAS_ETHERNET100 | HAS_SCSI | HAS_ATA | HAS_USB | HAS_MMU }, | ||
48 | { "Unknown", 0, 0 } /* This entry MUST be the last */ | ||
49 | }; | ||
50 | |||
51 | int show_cpuinfo(struct seq_file *m, void *v) | ||
52 | { | ||
53 | unsigned long revision; | ||
54 | struct cpu_info *info; | ||
55 | |||
56 | /* read the version register in the CPU and print some stuff */ | ||
57 | |||
58 | revision = rdvr(); | ||
59 | |||
60 | if (revision >= sizeof cpu_info/sizeof *cpu_info) | ||
61 | info = &cpu_info[sizeof cpu_info/sizeof *cpu_info - 1]; | ||
62 | else | ||
63 | info = &cpu_info[revision]; | ||
64 | |||
65 | return seq_printf(m, | ||
66 | "processor\t: 0\n" | ||
67 | "cpu\t\t: CRIS\n" | ||
68 | "cpu revision\t: %lu\n" | ||
69 | "cpu model\t: %s\n" | ||
70 | "cache size\t: %d kB\n" | ||
71 | "fpu\t\t: %s\n" | ||
72 | "mmu\t\t: %s\n" | ||
73 | "mmu DMA bug\t: %s\n" | ||
74 | "ethernet\t: %s Mbps\n" | ||
75 | "token ring\t: %s\n" | ||
76 | "scsi\t\t: %s\n" | ||
77 | "ata\t\t: %s\n" | ||
78 | "usb\t\t: %s\n" | ||
79 | "bogomips\t: %lu.%02lu\n", | ||
80 | |||
81 | revision, | ||
82 | info->model, | ||
83 | info->cache, | ||
84 | info->flags & HAS_FPU ? "yes" : "no", | ||
85 | info->flags & HAS_MMU ? "yes" : "no", | ||
86 | info->flags & HAS_MMU_BUG ? "yes" : "no", | ||
87 | info->flags & HAS_ETHERNET100 ? "10/100" : "10", | ||
88 | info->flags & HAS_TOKENRING ? "4/16 Mbps" : "no", | ||
89 | info->flags & HAS_SCSI ? "yes" : "no", | ||
90 | info->flags & HAS_ATA ? "yes" : "no", | ||
91 | info->flags & HAS_USB ? "yes" : "no", | ||
92 | (loops_per_jiffy * HZ + 500) / 500000, | ||
93 | ((loops_per_jiffy * HZ + 500) / 5000) % 100); | ||
94 | } | ||
95 | |||
96 | #endif /* CONFIG_PROC_FS */ | ||
97 | |||
98 | void | ||
99 | show_etrax_copyright(void) | ||
100 | { | ||
101 | printk(KERN_INFO | ||
102 | "Linux/CRIS port on ETRAX 100LX (c) 2001 Axis Communications AB\n"); | ||
103 | } | ||
diff --git a/arch/cris/arch-v10/kernel/shadows.c b/arch/cris/arch-v10/kernel/shadows.c new file mode 100644 index 000000000000..561a890a8e4c --- /dev/null +++ b/arch/cris/arch-v10/kernel/shadows.c | |||
@@ -0,0 +1,36 @@ | |||
1 | /* $Id: shadows.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * | ||
3 | * Various shadow registers. Defines for these are in include/asm-etrax100/io.h | ||
4 | */ | ||
5 | |||
6 | /* Shadows for internal Etrax-registers */ | ||
7 | |||
8 | unsigned long genconfig_shadow; | ||
9 | unsigned long port_g_data_shadow; | ||
10 | unsigned char port_pa_dir_shadow; | ||
11 | unsigned char port_pa_data_shadow; | ||
12 | unsigned char port_pb_i2c_shadow; | ||
13 | unsigned char port_pb_config_shadow; | ||
14 | unsigned char port_pb_dir_shadow; | ||
15 | unsigned char port_pb_data_shadow; | ||
16 | unsigned long r_timer_ctrl_shadow; | ||
17 | |||
18 | /* Shadows for external I/O port registers. | ||
19 | * These are only usable if there actually IS a latch connected | ||
20 | * to the corresponding external chip-select pin. | ||
21 | * | ||
22 | * A common usage is that CSP0 controls LED's and CSP4 video chips. | ||
23 | */ | ||
24 | |||
25 | unsigned long port_cse1_shadow; | ||
26 | unsigned long port_csp0_shadow; | ||
27 | unsigned long port_csp4_shadow; | ||
28 | |||
29 | /* Corresponding addresses for the ports. | ||
30 | * These are initialized in arch/cris/mm/init.c using ioremap. | ||
31 | */ | ||
32 | |||
33 | volatile unsigned long *port_cse1_addr; | ||
34 | volatile unsigned long *port_csp0_addr; | ||
35 | volatile unsigned long *port_csp4_addr; | ||
36 | |||
diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c new file mode 100644 index 000000000000..85e0032e664f --- /dev/null +++ b/arch/cris/arch-v10/kernel/signal.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/kernel/signal.c | ||
3 | * | ||
4 | * Based on arch/i386/kernel/signal.c by | ||
5 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
6 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson * | ||
7 | * | ||
8 | * Ideas also taken from arch/arm. | ||
9 | * | ||
10 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
11 | * | ||
12 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/sched.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/unistd.h> | ||
26 | #include <linux/stddef.h> | ||
27 | |||
28 | #include <asm/processor.h> | ||
29 | #include <asm/ucontext.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | |||
32 | #define DEBUG_SIG 0 | ||
33 | |||
34 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
35 | |||
36 | /* a syscall in Linux/CRIS is a break 13 instruction which is 2 bytes */ | ||
37 | /* manipulate regs so that upon return, it will be re-executed */ | ||
38 | |||
39 | /* We rely on that pc points to the instruction after "break 13", so the | ||
40 | * library must never do strange things like putting it in a delay slot. | ||
41 | */ | ||
42 | #define RESTART_CRIS_SYS(regs) regs->r10 = regs->orig_r10; regs->irp -= 2; | ||
43 | |||
44 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); | ||
45 | |||
46 | /* | ||
47 | * Atomically swap in the new signal mask, and wait for a signal. Define | ||
48 | * dummy arguments to be able to reach the regs argument. (Note that this | ||
49 | * arrangement relies on old_sigset_t occupying one register.) | ||
50 | */ | ||
51 | int | ||
52 | sys_sigsuspend(old_sigset_t mask, long r11, long r12, long r13, long mof, | ||
53 | long srp, struct pt_regs *regs) | ||
54 | { | ||
55 | sigset_t saveset; | ||
56 | |||
57 | mask &= _BLOCKABLE; | ||
58 | spin_lock_irq(¤t->sighand->siglock); | ||
59 | saveset = current->blocked; | ||
60 | siginitset(¤t->blocked, mask); | ||
61 | recalc_sigpending(); | ||
62 | spin_unlock_irq(¤t->sighand->siglock); | ||
63 | |||
64 | regs->r10 = -EINTR; | ||
65 | while (1) { | ||
66 | current->state = TASK_INTERRUPTIBLE; | ||
67 | schedule(); | ||
68 | if (do_signal(0, &saveset, regs)) | ||
69 | /* We will get here twice: once to call the signal | ||
70 | handler, then again to return from the | ||
71 | sigsuspend system call. When calling the | ||
72 | signal handler, R10 holds the signal number as | ||
73 | set through do_signal. The sigsuspend call | ||
74 | will return with the restored value set above; | ||
75 | always -EINTR. */ | ||
76 | return regs->r10; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | /* Define dummy arguments to be able to reach the regs argument. (Note that | ||
81 | * this arrangement relies on size_t occupying one register.) | ||
82 | */ | ||
83 | int | ||
84 | sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, long r12, long r13, | ||
85 | long mof, long srp, struct pt_regs *regs) | ||
86 | { | ||
87 | sigset_t saveset, newset; | ||
88 | |||
89 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
90 | if (sigsetsize != sizeof(sigset_t)) | ||
91 | return -EINVAL; | ||
92 | |||
93 | if (copy_from_user(&newset, unewset, sizeof(newset))) | ||
94 | return -EFAULT; | ||
95 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
96 | |||
97 | spin_lock_irq(¤t->sighand->siglock); | ||
98 | saveset = current->blocked; | ||
99 | current->blocked = newset; | ||
100 | recalc_sigpending(); | ||
101 | spin_unlock_irq(¤t->sighand->siglock); | ||
102 | |||
103 | regs->r10 = -EINTR; | ||
104 | while (1) { | ||
105 | current->state = TASK_INTERRUPTIBLE; | ||
106 | schedule(); | ||
107 | if (do_signal(0, &saveset, regs)) | ||
108 | /* We will get here twice: once to call the signal | ||
109 | handler, then again to return from the | ||
110 | sigsuspend system call. When calling the | ||
111 | signal handler, R10 holds the signal number as | ||
112 | set through do_signal. The sigsuspend call | ||
113 | will return with the restored value set above; | ||
114 | always -EINTR. */ | ||
115 | return regs->r10; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | int | ||
120 | sys_sigaction(int sig, const struct old_sigaction __user *act, | ||
121 | struct old_sigaction *oact) | ||
122 | { | ||
123 | struct k_sigaction new_ka, old_ka; | ||
124 | int ret; | ||
125 | |||
126 | if (act) { | ||
127 | old_sigset_t mask; | ||
128 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
129 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | ||
130 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | ||
131 | return -EFAULT; | ||
132 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
133 | __get_user(mask, &act->sa_mask); | ||
134 | siginitset(&new_ka.sa.sa_mask, mask); | ||
135 | } | ||
136 | |||
137 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
138 | |||
139 | if (!ret && oact) { | ||
140 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
141 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | ||
142 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | ||
143 | return -EFAULT; | ||
144 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
145 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
146 | } | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | int | ||
152 | sys_sigaltstack(const stack_t *uss, stack_t __user *uoss) | ||
153 | { | ||
154 | return do_sigaltstack(uss, uoss, rdusp()); | ||
155 | } | ||
156 | |||
157 | |||
158 | /* | ||
159 | * Do a signal return; undo the signal stack. | ||
160 | */ | ||
161 | |||
162 | struct sigframe { | ||
163 | struct sigcontext sc; | ||
164 | unsigned long extramask[_NSIG_WORDS-1]; | ||
165 | unsigned char retcode[8]; /* trampoline code */ | ||
166 | }; | ||
167 | |||
168 | struct rt_sigframe { | ||
169 | struct siginfo *pinfo; | ||
170 | void *puc; | ||
171 | struct siginfo info; | ||
172 | struct ucontext uc; | ||
173 | unsigned char retcode[8]; /* trampoline code */ | ||
174 | }; | ||
175 | |||
176 | |||
177 | static int | ||
178 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
179 | { | ||
180 | unsigned int err = 0; | ||
181 | unsigned long old_usp; | ||
182 | |||
183 | /* Always make any pending restarted system calls return -EINTR */ | ||
184 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
185 | |||
186 | /* restore the regs from &sc->regs (same as sc, since regs is first) | ||
187 | * (sc is already checked for VERIFY_READ since the sigframe was | ||
188 | * checked in sys_sigreturn previously) | ||
189 | */ | ||
190 | |||
191 | if (__copy_from_user(regs, sc, sizeof(struct pt_regs))) | ||
192 | goto badframe; | ||
193 | |||
194 | /* make sure the U-flag is set so user-mode cannot fool us */ | ||
195 | |||
196 | regs->dccr |= 1 << 8; | ||
197 | |||
198 | /* restore the old USP as it was before we stacked the sc etc. | ||
199 | * (we cannot just pop the sigcontext since we aligned the sp and | ||
200 | * stuff after pushing it) | ||
201 | */ | ||
202 | |||
203 | err |= __get_user(old_usp, &sc->usp); | ||
204 | |||
205 | wrusp(old_usp); | ||
206 | |||
207 | /* TODO: the other ports use regs->orig_XX to disable syscall checks | ||
208 | * after this completes, but we don't use that mechanism. maybe we can | ||
209 | * use it now ? | ||
210 | */ | ||
211 | |||
212 | return err; | ||
213 | |||
214 | badframe: | ||
215 | return 1; | ||
216 | } | ||
217 | |||
218 | /* Define dummy arguments to be able to reach the regs argument. */ | ||
219 | |||
220 | asmlinkage int sys_sigreturn(long r10, long r11, long r12, long r13, long mof, | ||
221 | long srp, struct pt_regs *regs) | ||
222 | { | ||
223 | struct sigframe __user *frame = (struct sigframe *)rdusp(); | ||
224 | sigset_t set; | ||
225 | |||
226 | /* | ||
227 | * Since we stacked the signal on a dword boundary, | ||
228 | * then frame should be dword aligned here. If it's | ||
229 | * not, then the user is trying to mess with us. | ||
230 | */ | ||
231 | if (((long)frame) & 3) | ||
232 | goto badframe; | ||
233 | |||
234 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
235 | goto badframe; | ||
236 | if (__get_user(set.sig[0], &frame->sc.oldmask) | ||
237 | || (_NSIG_WORDS > 1 | ||
238 | && __copy_from_user(&set.sig[1], frame->extramask, | ||
239 | sizeof(frame->extramask)))) | ||
240 | goto badframe; | ||
241 | |||
242 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
243 | spin_lock_irq(¤t->sighand->siglock); | ||
244 | current->blocked = set; | ||
245 | recalc_sigpending(); | ||
246 | spin_unlock_irq(¤t->sighand->siglock); | ||
247 | |||
248 | if (restore_sigcontext(regs, &frame->sc)) | ||
249 | goto badframe; | ||
250 | |||
251 | /* TODO: SIGTRAP when single-stepping as in arm ? */ | ||
252 | |||
253 | return regs->r10; | ||
254 | |||
255 | badframe: | ||
256 | force_sig(SIGSEGV, current); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* Define dummy arguments to be able to reach the regs argument. */ | ||
261 | |||
262 | asmlinkage int sys_rt_sigreturn(long r10, long r11, long r12, long r13, | ||
263 | long mof, long srp, struct pt_regs *regs) | ||
264 | { | ||
265 | struct rt_sigframe __user *frame = (struct rt_sigframe *)rdusp(); | ||
266 | sigset_t set; | ||
267 | |||
268 | /* | ||
269 | * Since we stacked the signal on a dword boundary, | ||
270 | * then frame should be dword aligned here. If it's | ||
271 | * not, then the user is trying to mess with us. | ||
272 | */ | ||
273 | if (((long)frame) & 3) | ||
274 | goto badframe; | ||
275 | |||
276 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
277 | goto badframe; | ||
278 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
279 | goto badframe; | ||
280 | |||
281 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
282 | spin_lock_irq(¤t->sighand->siglock); | ||
283 | current->blocked = set; | ||
284 | recalc_sigpending(); | ||
285 | spin_unlock_irq(¤t->sighand->siglock); | ||
286 | |||
287 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | ||
288 | goto badframe; | ||
289 | |||
290 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, rdusp()) == -EFAULT) | ||
291 | goto badframe; | ||
292 | |||
293 | return regs->r10; | ||
294 | |||
295 | badframe: | ||
296 | force_sig(SIGSEGV, current); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | ||
301 | * Set up a signal frame. | ||
302 | */ | ||
303 | |||
304 | static int | ||
305 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, unsigned long mask) | ||
306 | { | ||
307 | int err = 0; | ||
308 | unsigned long usp = rdusp(); | ||
309 | |||
310 | /* copy the regs. they are first in sc so we can use sc directly */ | ||
311 | |||
312 | err |= __copy_to_user(sc, regs, sizeof(struct pt_regs)); | ||
313 | |||
314 | /* Set the frametype to CRIS_FRAME_NORMAL for the execution of | ||
315 | the signal handler. The frametype will be restored to its previous | ||
316 | value in restore_sigcontext. */ | ||
317 | regs->frametype = CRIS_FRAME_NORMAL; | ||
318 | |||
319 | /* then some other stuff */ | ||
320 | |||
321 | err |= __put_user(mask, &sc->oldmask); | ||
322 | |||
323 | err |= __put_user(usp, &sc->usp); | ||
324 | |||
325 | return err; | ||
326 | } | ||
327 | |||
328 | /* figure out where we want to put the new signal frame - usually on the stack */ | ||
329 | |||
330 | static inline void __user * | ||
331 | get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | ||
332 | { | ||
333 | unsigned long sp = rdusp(); | ||
334 | |||
335 | /* This is the X/Open sanctioned signal stack switching. */ | ||
336 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
337 | if (! on_sig_stack(sp)) | ||
338 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
339 | } | ||
340 | |||
341 | /* make sure the frame is dword-aligned */ | ||
342 | |||
343 | sp &= ~3; | ||
344 | |||
345 | return (void __user*)(sp - frame_size); | ||
346 | } | ||
347 | |||
348 | /* grab and setup a signal frame. | ||
349 | * | ||
350 | * basically we stack a lot of state info, and arrange for the | ||
351 | * user-mode program to return to the kernel using either a | ||
352 | * trampoline which performs the syscall sigreturn, or a provided | ||
353 | * user-mode trampoline. | ||
354 | */ | ||
355 | |||
356 | static void setup_frame(int sig, struct k_sigaction *ka, | ||
357 | sigset_t *set, struct pt_regs * regs) | ||
358 | { | ||
359 | struct sigframe __user *frame; | ||
360 | unsigned long return_ip; | ||
361 | int err = 0; | ||
362 | |||
363 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
364 | |||
365 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
366 | goto give_sigsegv; | ||
367 | |||
368 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | ||
369 | if (err) | ||
370 | goto give_sigsegv; | ||
371 | |||
372 | if (_NSIG_WORDS > 1) { | ||
373 | err |= __copy_to_user(frame->extramask, &set->sig[1], | ||
374 | sizeof(frame->extramask)); | ||
375 | } | ||
376 | if (err) | ||
377 | goto give_sigsegv; | ||
378 | |||
379 | /* Set up to return from userspace. If provided, use a stub | ||
380 | already in userspace. */ | ||
381 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
382 | return_ip = (unsigned long)ka->sa.sa_restorer; | ||
383 | } else { | ||
384 | /* trampoline - the desired return ip is the retcode itself */ | ||
385 | return_ip = (unsigned long)&frame->retcode; | ||
386 | /* This is movu.w __NR_sigreturn, r9; break 13; */ | ||
387 | err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); | ||
388 | err |= __put_user(__NR_sigreturn, (short __user*)(frame->retcode+2)); | ||
389 | err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); | ||
390 | } | ||
391 | |||
392 | if (err) | ||
393 | goto give_sigsegv; | ||
394 | |||
395 | /* Set up registers for signal handler */ | ||
396 | |||
397 | regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ | ||
398 | regs->srp = return_ip; /* what we enter LATER */ | ||
399 | regs->r10 = sig; /* first argument is signo */ | ||
400 | |||
401 | /* actually move the usp to reflect the stacked frame */ | ||
402 | |||
403 | wrusp((unsigned long)frame); | ||
404 | |||
405 | return; | ||
406 | |||
407 | give_sigsegv: | ||
408 | force_sigsegv(sig, current); | ||
409 | } | ||
410 | |||
411 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
412 | sigset_t *set, struct pt_regs * regs) | ||
413 | { | ||
414 | struct rt_sigframe __user *frame; | ||
415 | unsigned long return_ip; | ||
416 | int err = 0; | ||
417 | |||
418 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
419 | |||
420 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
421 | goto give_sigsegv; | ||
422 | |||
423 | err |= __put_user(&frame->info, &frame->pinfo); | ||
424 | err |= __put_user(&frame->uc, &frame->puc); | ||
425 | err |= copy_siginfo_to_user(&frame->info, info); | ||
426 | if (err) | ||
427 | goto give_sigsegv; | ||
428 | |||
429 | /* Clear all the bits of the ucontext we don't use. */ | ||
430 | err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); | ||
431 | |||
432 | err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); | ||
433 | |||
434 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
435 | |||
436 | if (err) | ||
437 | goto give_sigsegv; | ||
438 | |||
439 | /* Set up to return from userspace. If provided, use a stub | ||
440 | already in userspace. */ | ||
441 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
442 | return_ip = (unsigned long)ka->sa.sa_restorer; | ||
443 | } else { | ||
444 | /* trampoline - the desired return ip is the retcode itself */ | ||
445 | return_ip = (unsigned long)&frame->retcode; | ||
446 | /* This is movu.w __NR_rt_sigreturn, r9; break 13; */ | ||
447 | err |= __put_user(0x9c5f, (short __user*)(frame->retcode+0)); | ||
448 | err |= __put_user(__NR_rt_sigreturn, (short __user*)(frame->retcode+2)); | ||
449 | err |= __put_user(0xe93d, (short __user*)(frame->retcode+4)); | ||
450 | } | ||
451 | |||
452 | if (err) | ||
453 | goto give_sigsegv; | ||
454 | |||
455 | /* TODO what is the current->exec_domain stuff and invmap ? */ | ||
456 | |||
457 | /* Set up registers for signal handler */ | ||
458 | |||
459 | regs->irp = (unsigned long) ka->sa.sa_handler; /* what we enter NOW */ | ||
460 | regs->srp = return_ip; /* what we enter LATER */ | ||
461 | regs->r10 = sig; /* first argument is signo */ | ||
462 | regs->r11 = (unsigned long) &frame->info; /* second argument is (siginfo_t *) */ | ||
463 | regs->r12 = 0; /* third argument is unused */ | ||
464 | |||
465 | /* actually move the usp to reflect the stacked frame */ | ||
466 | |||
467 | wrusp((unsigned long)frame); | ||
468 | |||
469 | return; | ||
470 | |||
471 | give_sigsegv: | ||
472 | force_sigsegv(sig, current); | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * OK, we're invoking a handler | ||
477 | */ | ||
478 | |||
479 | extern inline void | ||
480 | handle_signal(int canrestart, unsigned long sig, | ||
481 | siginfo_t *info, struct k_sigaction *ka, | ||
482 | sigset_t *oldset, struct pt_regs * regs) | ||
483 | { | ||
484 | /* Are we from a system call? */ | ||
485 | if (canrestart) { | ||
486 | /* If so, check system call restarting.. */ | ||
487 | switch (regs->r10) { | ||
488 | case -ERESTART_RESTARTBLOCK: | ||
489 | case -ERESTARTNOHAND: | ||
490 | /* ERESTARTNOHAND means that the syscall should only be | ||
491 | restarted if there was no handler for the signal, and since | ||
492 | we only get here if there is a handler, we don't restart */ | ||
493 | regs->r10 = -EINTR; | ||
494 | break; | ||
495 | |||
496 | case -ERESTARTSYS: | ||
497 | /* ERESTARTSYS means to restart the syscall if there is no | ||
498 | handler or the handler was registered with SA_RESTART */ | ||
499 | if (!(ka->sa.sa_flags & SA_RESTART)) { | ||
500 | regs->r10 = -EINTR; | ||
501 | break; | ||
502 | } | ||
503 | /* fallthrough */ | ||
504 | case -ERESTARTNOINTR: | ||
505 | /* ERESTARTNOINTR means that the syscall should be called again | ||
506 | after the signal handler returns. */ | ||
507 | RESTART_CRIS_SYS(regs); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | /* Set up the stack frame */ | ||
512 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
513 | setup_rt_frame(sig, ka, info, oldset, regs); | ||
514 | else | ||
515 | setup_frame(sig, ka, oldset, regs); | ||
516 | |||
517 | if (ka->sa.sa_flags & SA_ONESHOT) | ||
518 | ka->sa.sa_handler = SIG_DFL; | ||
519 | |||
520 | if (!(ka->sa.sa_flags & SA_NODEFER)) { | ||
521 | spin_lock_irq(¤t->sighand->siglock); | ||
522 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
523 | sigaddset(¤t->blocked,sig); | ||
524 | recalc_sigpending(); | ||
525 | spin_unlock_irq(¤t->sighand->siglock); | ||
526 | } | ||
527 | } | ||
528 | |||
529 | /* | ||
530 | * Note that 'init' is a special process: it doesn't get signals it doesn't | ||
531 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
532 | * mistake. | ||
533 | * | ||
534 | * Also note that the regs structure given here as an argument, is the latest | ||
535 | * pushed pt_regs. It may or may not be the same as the first pushed registers | ||
536 | * when the initial usermode->kernelmode transition took place. Therefore | ||
537 | * we can use user_mode(regs) to see if we came directly from kernel or user | ||
538 | * mode below. | ||
539 | */ | ||
540 | |||
541 | int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs) | ||
542 | { | ||
543 | siginfo_t info; | ||
544 | int signr; | ||
545 | struct k_sigaction ka; | ||
546 | |||
547 | /* | ||
548 | * We want the common case to go fast, which | ||
549 | * is why we may in certain cases get here from | ||
550 | * kernel mode. Just return without doing anything | ||
551 | * if so. | ||
552 | */ | ||
553 | if (!user_mode(regs)) | ||
554 | return 1; | ||
555 | |||
556 | if (!oldset) | ||
557 | oldset = ¤t->blocked; | ||
558 | |||
559 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | ||
560 | if (signr > 0) { | ||
561 | /* Whee! Actually deliver the signal. */ | ||
562 | handle_signal(canrestart, signr, &info, &ka, oldset, regs); | ||
563 | return 1; | ||
564 | } | ||
565 | |||
566 | /* Did we come from a system call? */ | ||
567 | if (canrestart) { | ||
568 | /* Restart the system call - no handlers present */ | ||
569 | if (regs->r10 == -ERESTARTNOHAND || | ||
570 | regs->r10 == -ERESTARTSYS || | ||
571 | regs->r10 == -ERESTARTNOINTR) { | ||
572 | RESTART_CRIS_SYS(regs); | ||
573 | } | ||
574 | if (regs->r10 == -ERESTART_RESTARTBLOCK){ | ||
575 | regs->r10 = __NR_restart_syscall; | ||
576 | regs->irp -= 2; | ||
577 | } | ||
578 | } | ||
579 | return 0; | ||
580 | } | ||
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c new file mode 100644 index 000000000000..6b7b4e0802e3 --- /dev/null +++ b/arch/cris/arch-v10/kernel/time.c | |||
@@ -0,0 +1,369 @@ | |||
1 | /* $Id: time.c,v 1.5 2004/09/29 06:12:46 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/kernel/time.c | ||
4 | * | ||
5 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
6 | * Copyright (C) 1999-2002 Axis Communications AB | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/timex.h> | ||
12 | #include <linux/time.h> | ||
13 | #include <linux/jiffies.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/swap.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <asm/arch/svinto.h> | ||
19 | #include <asm/types.h> | ||
20 | #include <asm/signal.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/delay.h> | ||
23 | #include <asm/rtc.h> | ||
24 | |||
25 | /* define this if you need to use print_timestamp */ | ||
26 | /* it will make jiffies at 96 hz instead of 100 hz though */ | ||
27 | #undef USE_CASCADE_TIMERS | ||
28 | |||
29 | extern void update_xtime_from_cmos(void); | ||
30 | extern int set_rtc_mmss(unsigned long nowtime); | ||
31 | extern int setup_irq(int, struct irqaction *); | ||
32 | extern int have_rtc; | ||
33 | |||
34 | unsigned long get_ns_in_jiffie(void) | ||
35 | { | ||
36 | unsigned char timer_count, t1; | ||
37 | unsigned short presc_count; | ||
38 | unsigned long ns; | ||
39 | unsigned long flags; | ||
40 | |||
41 | local_irq_save(flags); | ||
42 | local_irq_disable(); | ||
43 | timer_count = *R_TIMER0_DATA; | ||
44 | presc_count = *R_TIM_PRESC_STATUS; | ||
45 | /* presc_count might be wrapped */ | ||
46 | t1 = *R_TIMER0_DATA; | ||
47 | |||
48 | if (timer_count != t1){ | ||
49 | /* it wrapped, read prescaler again... */ | ||
50 | presc_count = *R_TIM_PRESC_STATUS; | ||
51 | timer_count = t1; | ||
52 | } | ||
53 | local_irq_restore(flags); | ||
54 | if (presc_count >= PRESCALE_VALUE/2 ){ | ||
55 | presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; | ||
56 | } else { | ||
57 | presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; | ||
58 | } | ||
59 | |||
60 | ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + | ||
61 | ( (presc_count) * (1000000000/PRESCALE_FREQ)); | ||
62 | return ns; | ||
63 | } | ||
64 | |||
65 | unsigned long do_slow_gettimeoffset(void) | ||
66 | { | ||
67 | unsigned long count, t1; | ||
68 | unsigned long usec_count = 0; | ||
69 | unsigned short presc_count; | ||
70 | |||
71 | static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ | ||
72 | static unsigned long jiffies_p = 0; | ||
73 | |||
74 | /* | ||
75 | * cache volatile jiffies temporarily; we have IRQs turned off. | ||
76 | */ | ||
77 | unsigned long jiffies_t; | ||
78 | |||
79 | /* The timer interrupt comes from Etrax timer 0. In order to get | ||
80 | * better precision, we check the current value. It might have | ||
81 | * underflowed already though. | ||
82 | */ | ||
83 | |||
84 | #ifndef CONFIG_SVINTO_SIM | ||
85 | /* Not available in the xsim simulator. */ | ||
86 | count = *R_TIMER0_DATA; | ||
87 | presc_count = *R_TIM_PRESC_STATUS; | ||
88 | /* presc_count might be wrapped */ | ||
89 | t1 = *R_TIMER0_DATA; | ||
90 | if (count != t1){ | ||
91 | /* it wrapped, read prescaler again... */ | ||
92 | presc_count = *R_TIM_PRESC_STATUS; | ||
93 | count = t1; | ||
94 | } | ||
95 | #else | ||
96 | count = 0; | ||
97 | presc_count = 0; | ||
98 | #endif | ||
99 | |||
100 | jiffies_t = jiffies; | ||
101 | |||
102 | /* | ||
103 | * avoiding timer inconsistencies (they are rare, but they happen)... | ||
104 | * there are one problem that must be avoided here: | ||
105 | * 1. the timer counter underflows | ||
106 | */ | ||
107 | if( jiffies_t == jiffies_p ) { | ||
108 | if( count > count_p ) { | ||
109 | /* Timer wrapped, use new count and prescale | ||
110 | * increase the time corresponding to one jiffie | ||
111 | */ | ||
112 | usec_count = 1000000/HZ; | ||
113 | } | ||
114 | } else | ||
115 | jiffies_p = jiffies_t; | ||
116 | count_p = count; | ||
117 | if (presc_count >= PRESCALE_VALUE/2 ){ | ||
118 | presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; | ||
119 | } else { | ||
120 | presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; | ||
121 | } | ||
122 | /* Convert timer value to usec */ | ||
123 | usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + | ||
124 | (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000); | ||
125 | |||
126 | return usec_count; | ||
127 | } | ||
128 | |||
129 | /* Excerpt from the Etrax100 HSDD about the built-in watchdog: | ||
130 | * | ||
131 | * 3.10.4 Watchdog timer | ||
132 | |||
133 | * When the watchdog timer is started, it generates an NMI if the watchdog | ||
134 | * isn't restarted or stopped within 0.1 s. If it still isn't restarted or | ||
135 | * stopped after an additional 3.3 ms, the watchdog resets the chip. | ||
136 | * The watchdog timer is stopped after reset. The watchdog timer is controlled | ||
137 | * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit | ||
138 | * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is | ||
139 | * described in the table below: | ||
140 | * | ||
141 | * Watchdog Value written: | ||
142 | * state: To enable: To key: Operation: | ||
143 | * -------- ---------- ------- ---------- | ||
144 | * stopped 0 X No effect. | ||
145 | * stopped 1 key_val Start watchdog with key = key_val. | ||
146 | * started 0 ~key Stop watchdog | ||
147 | * started 1 ~key Restart watchdog with key = ~key. | ||
148 | * started X new_key_val Change key to new_key_val. | ||
149 | * | ||
150 | * Note: '~' is the bitwise NOT operator. | ||
151 | * | ||
152 | */ | ||
153 | |||
154 | /* right now, starting the watchdog is the same as resetting it */ | ||
155 | #define start_watchdog reset_watchdog | ||
156 | |||
157 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
158 | static int watchdog_key = 0; /* arbitrary number */ | ||
159 | #endif | ||
160 | |||
161 | /* number of pages to consider "out of memory". it is normal that the memory | ||
162 | * is used though, so put this really low. | ||
163 | */ | ||
164 | |||
165 | #define WATCHDOG_MIN_FREE_PAGES 8 | ||
166 | |||
167 | void | ||
168 | reset_watchdog(void) | ||
169 | { | ||
170 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
171 | /* only keep watchdog happy as long as we have memory left! */ | ||
172 | if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { | ||
173 | /* reset the watchdog with the inverse of the old key */ | ||
174 | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | ||
175 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | ||
176 | IO_STATE(R_WATCHDOG, enable, start); | ||
177 | } | ||
178 | #endif | ||
179 | } | ||
180 | |||
181 | /* stop the watchdog - we still need the correct key */ | ||
182 | |||
183 | void | ||
184 | stop_watchdog(void) | ||
185 | { | ||
186 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
187 | watchdog_key ^= 0x7; /* invert key, which is 3 bits */ | ||
188 | *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | | ||
189 | IO_STATE(R_WATCHDOG, enable, stop); | ||
190 | #endif | ||
191 | } | ||
192 | |||
193 | /* last time the cmos clock got updated */ | ||
194 | static long last_rtc_update = 0; | ||
195 | |||
196 | /* | ||
197 | * timer_interrupt() needs to keep up the real-time clock, | ||
198 | * as well as call the "do_timer()" routine every clocktick | ||
199 | */ | ||
200 | |||
201 | //static unsigned short myjiff; /* used by our debug routine print_timestamp */ | ||
202 | |||
203 | extern void cris_do_profile(struct pt_regs *regs); | ||
204 | |||
205 | static inline irqreturn_t | ||
206 | timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
207 | { | ||
208 | /* acknowledge the timer irq */ | ||
209 | |||
210 | #ifdef USE_CASCADE_TIMERS | ||
211 | *R_TIMER_CTRL = | ||
212 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
213 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
214 | IO_STATE( R_TIMER_CTRL, i1, clr) | | ||
215 | IO_STATE( R_TIMER_CTRL, tm1, run) | | ||
216 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
217 | IO_STATE( R_TIMER_CTRL, i0, clr) | | ||
218 | IO_STATE( R_TIMER_CTRL, tm0, run) | | ||
219 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
220 | #else | ||
221 | *R_TIMER_CTRL = r_timer_ctrl_shadow | | ||
222 | IO_STATE(R_TIMER_CTRL, i0, clr); | ||
223 | #endif | ||
224 | |||
225 | /* reset watchdog otherwise it resets us! */ | ||
226 | |||
227 | reset_watchdog(); | ||
228 | |||
229 | /* call the real timer interrupt handler */ | ||
230 | |||
231 | do_timer(regs); | ||
232 | |||
233 | cris_do_profile(regs); /* Save profiling information */ | ||
234 | |||
235 | /* | ||
236 | * If we have an externally synchronized Linux clock, then update | ||
237 | * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be | ||
238 | * called as close as possible to 500 ms before the new second starts. | ||
239 | * | ||
240 | * The division here is not time critical since it will run once in | ||
241 | * 11 minutes | ||
242 | */ | ||
243 | if ((time_status & STA_UNSYNC) == 0 && | ||
244 | xtime.tv_sec > last_rtc_update + 660 && | ||
245 | (xtime.tv_nsec / 1000) >= 500000 - (tick_nsec / 1000) / 2 && | ||
246 | (xtime.tv_nsec / 1000) <= 500000 + (tick_nsec / 1000) / 2) { | ||
247 | if (set_rtc_mmss(xtime.tv_sec) == 0) | ||
248 | last_rtc_update = xtime.tv_sec; | ||
249 | else | ||
250 | last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ | ||
251 | } | ||
252 | return IRQ_HANDLED; | ||
253 | } | ||
254 | |||
255 | /* timer is SA_SHIRQ so drivers can add stuff to the timer irq chain | ||
256 | * it needs to be SA_INTERRUPT to make the jiffies update work properly | ||
257 | */ | ||
258 | |||
259 | static struct irqaction irq2 = { timer_interrupt, SA_SHIRQ | SA_INTERRUPT, | ||
260 | CPU_MASK_NONE, "timer", NULL, NULL}; | ||
261 | |||
262 | void __init | ||
263 | time_init(void) | ||
264 | { | ||
265 | /* probe for the RTC and read it if it exists | ||
266 | * Before the RTC can be probed the loops_per_usec variable needs | ||
267 | * to be initialized to make usleep work. A better value for | ||
268 | * loops_per_usec is calculated by the kernel later once the | ||
269 | * clock has started. | ||
270 | */ | ||
271 | loops_per_usec = 50; | ||
272 | |||
273 | if(RTC_INIT() < 0) { | ||
274 | /* no RTC, start at 1980 */ | ||
275 | xtime.tv_sec = 0; | ||
276 | xtime.tv_nsec = 0; | ||
277 | have_rtc = 0; | ||
278 | } else { | ||
279 | /* get the current time */ | ||
280 | have_rtc = 1; | ||
281 | update_xtime_from_cmos(); | ||
282 | } | ||
283 | |||
284 | /* | ||
285 | * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the | ||
286 | * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC). | ||
287 | */ | ||
288 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); | ||
289 | |||
290 | /* Setup the etrax timers | ||
291 | * Base frequency is 25000 hz, divider 250 -> 100 HZ | ||
292 | * In normal mode, we use timer0, so timer1 is free. In cascade | ||
293 | * mode (which we sometimes use for debugging) both timers are used. | ||
294 | * Remember that linux/timex.h contains #defines that rely on the | ||
295 | * timer settings below (hz and divide factor) !!! | ||
296 | */ | ||
297 | |||
298 | #ifdef USE_CASCADE_TIMERS | ||
299 | *R_TIMER_CTRL = | ||
300 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
301 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
302 | IO_STATE( R_TIMER_CTRL, i1, nop) | | ||
303 | IO_STATE( R_TIMER_CTRL, tm1, stop_ld) | | ||
304 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
305 | IO_STATE( R_TIMER_CTRL, i0, nop) | | ||
306 | IO_STATE( R_TIMER_CTRL, tm0, stop_ld) | | ||
307 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
308 | |||
309 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
310 | IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) | | ||
311 | IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) | | ||
312 | IO_STATE( R_TIMER_CTRL, i1, nop) | | ||
313 | IO_STATE( R_TIMER_CTRL, tm1, run) | | ||
314 | IO_STATE( R_TIMER_CTRL, clksel1, cascade0) | | ||
315 | IO_STATE( R_TIMER_CTRL, i0, nop) | | ||
316 | IO_STATE( R_TIMER_CTRL, tm0, run) | | ||
317 | IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz); | ||
318 | #else | ||
319 | *R_TIMER_CTRL = | ||
320 | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | | ||
321 | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | | ||
322 | IO_STATE(R_TIMER_CTRL, i1, nop) | | ||
323 | IO_STATE(R_TIMER_CTRL, tm1, stop_ld) | | ||
324 | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | | ||
325 | IO_STATE(R_TIMER_CTRL, i0, nop) | | ||
326 | IO_STATE(R_TIMER_CTRL, tm0, stop_ld) | | ||
327 | IO_STATE(R_TIMER_CTRL, clksel0, flexible); | ||
328 | |||
329 | *R_TIMER_CTRL = r_timer_ctrl_shadow = | ||
330 | IO_FIELD(R_TIMER_CTRL, timerdiv1, 192) | | ||
331 | IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV) | | ||
332 | IO_STATE(R_TIMER_CTRL, i1, nop) | | ||
333 | IO_STATE(R_TIMER_CTRL, tm1, run) | | ||
334 | IO_STATE(R_TIMER_CTRL, clksel1, c19k2Hz) | | ||
335 | IO_STATE(R_TIMER_CTRL, i0, nop) | | ||
336 | IO_STATE(R_TIMER_CTRL, tm0, run) | | ||
337 | IO_STATE(R_TIMER_CTRL, clksel0, flexible); | ||
338 | |||
339 | *R_TIMER_PRESCALE = PRESCALE_VALUE; | ||
340 | #endif | ||
341 | |||
342 | *R_IRQ_MASK0_SET = | ||
343 | IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */ | ||
344 | |||
345 | /* now actually register the timer irq handler that calls timer_interrupt() */ | ||
346 | |||
347 | setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */ | ||
348 | |||
349 | /* enable watchdog if we should use one */ | ||
350 | |||
351 | #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) | ||
352 | printk("Enabling watchdog...\n"); | ||
353 | start_watchdog(); | ||
354 | |||
355 | /* If we use the hardware watchdog, we want to trap it as an NMI | ||
356 | and dump registers before it resets us. For this to happen, we | ||
357 | must set the "m" NMI enable flag (which once set, is unset only | ||
358 | when an NMI is taken). | ||
359 | |||
360 | The same goes for the external NMI, but that doesn't have any | ||
361 | driver or infrastructure support yet. */ | ||
362 | asm ("setf m"); | ||
363 | |||
364 | *R_IRQ_MASK0_SET = | ||
365 | IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); | ||
366 | *R_VECT_MASK_SET = | ||
367 | IO_STATE(R_VECT_MASK_SET, nmi, set); | ||
368 | #endif | ||
369 | } | ||
diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c new file mode 100644 index 000000000000..da491f438a6e --- /dev/null +++ b/arch/cris/arch-v10/kernel/traps.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* $Id: traps.c,v 1.2 2003/07/04 08:27:41 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/arch-v10/traps.c | ||
4 | * | ||
5 | * Heler functions for trap handlers | ||
6 | * | ||
7 | * Copyright (C) 2000-2002 Axis Communications AB | ||
8 | * | ||
9 | * Authors: Bjorn Wesen | ||
10 | * Hans-Peter Nilsson | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/ptrace.h> | ||
16 | #include <asm/uaccess.h> | ||
17 | #include <asm/arch/sv_addr_ag.h> | ||
18 | |||
19 | void | ||
20 | show_registers(struct pt_regs * regs) | ||
21 | { | ||
22 | /* We either use rdusp() - the USP register, which might not | ||
23 | correspond to the current process for all cases we're called, | ||
24 | or we use the current->thread.usp, which is not up to date for | ||
25 | the current process. Experience shows we want the USP | ||
26 | register. */ | ||
27 | unsigned long usp = rdusp(); | ||
28 | |||
29 | printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", | ||
30 | regs->irp, regs->srp, regs->dccr, usp, regs->mof ); | ||
31 | printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", | ||
32 | regs->r0, regs->r1, regs->r2, regs->r3); | ||
33 | printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", | ||
34 | regs->r4, regs->r5, regs->r6, regs->r7); | ||
35 | printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", | ||
36 | regs->r8, regs->r9, regs->r10, regs->r11); | ||
37 | printk("r12: %08lx r13: %08lx oR10: %08lx\n", | ||
38 | regs->r12, regs->r13, regs->orig_r10); | ||
39 | printk("R_MMU_CAUSE: %08lx\n", (unsigned long)*R_MMU_CAUSE); | ||
40 | printk("Process %s (pid: %d, stackpage=%08lx)\n", | ||
41 | current->comm, current->pid, (unsigned long)current); | ||
42 | |||
43 | /* | ||
44 | * When in-kernel, we also print out the stack and code at the | ||
45 | * time of the fault.. | ||
46 | */ | ||
47 | if (! user_mode(regs)) { | ||
48 | int i; | ||
49 | |||
50 | show_stack(NULL, (unsigned long*)usp); | ||
51 | |||
52 | /* Dump kernel stack if the previous dump wasn't one. */ | ||
53 | if (usp != 0) | ||
54 | show_stack (NULL, NULL); | ||
55 | |||
56 | printk("\nCode: "); | ||
57 | if(regs->irp < PAGE_OFFSET) | ||
58 | goto bad; | ||
59 | |||
60 | /* Often enough the value at regs->irp does not point to | ||
61 | the interesting instruction, which is most often the | ||
62 | _previous_ instruction. So we dump at an offset large | ||
63 | enough that instruction decoding should be in sync at | ||
64 | the interesting point, but small enough to fit on a row | ||
65 | (sort of). We point out the regs->irp location in a | ||
66 | ksymoops-friendly way by wrapping the byte for that | ||
67 | address in parentheses. */ | ||
68 | for(i = -12; i < 12; i++) | ||
69 | { | ||
70 | unsigned char c; | ||
71 | if(__get_user(c, &((unsigned char*)regs->irp)[i])) { | ||
72 | bad: | ||
73 | printk(" Bad IP value."); | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | if (i == 0) | ||
78 | printk("(%02x) ", c); | ||
79 | else | ||
80 | printk("%02x ", c); | ||
81 | } | ||
82 | printk("\n"); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | /* Called from entry.S when the watchdog has bitten | ||
87 | * We print out something resembling an oops dump, and if | ||
88 | * we have the nice doggy development flag set, we halt here | ||
89 | * instead of rebooting. | ||
90 | */ | ||
91 | |||
92 | extern void reset_watchdog(void); | ||
93 | extern void stop_watchdog(void); | ||
94 | |||
95 | |||
96 | void | ||
97 | watchdog_bite_hook(struct pt_regs *regs) | ||
98 | { | ||
99 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
100 | local_irq_disable(); | ||
101 | stop_watchdog(); | ||
102 | show_registers(regs); | ||
103 | while(1) /* nothing */; | ||
104 | #else | ||
105 | show_registers(regs); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | /* This is normally the 'Oops' routine */ | ||
110 | void | ||
111 | die_if_kernel(const char * str, struct pt_regs * regs, long err) | ||
112 | { | ||
113 | if(user_mode(regs)) | ||
114 | return; | ||
115 | |||
116 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
117 | /* This printout might take too long and trigger the | ||
118 | * watchdog normally. If we're in the nice doggy | ||
119 | * development mode, stop the watchdog during printout. | ||
120 | */ | ||
121 | stop_watchdog(); | ||
122 | #endif | ||
123 | |||
124 | printk("%s: %04lx\n", str, err & 0xffff); | ||
125 | |||
126 | show_registers(regs); | ||
127 | |||
128 | #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY | ||
129 | reset_watchdog(); | ||
130 | #endif | ||
131 | do_exit(SIGSEGV); | ||
132 | } | ||
diff --git a/arch/cris/arch-v10/lib/Makefile b/arch/cris/arch-v10/lib/Makefile new file mode 100644 index 000000000000..36e9a9c5239b --- /dev/null +++ b/arch/cris/arch-v10/lib/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for Etrax-specific library files.. | ||
3 | # | ||
4 | |||
5 | |||
6 | EXTRA_AFLAGS := -traditional | ||
7 | |||
8 | lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o | ||
9 | |||
diff --git a/arch/cris/arch-v10/lib/checksum.S b/arch/cris/arch-v10/lib/checksum.S new file mode 100644 index 000000000000..85c48f0a9ec2 --- /dev/null +++ b/arch/cris/arch-v10/lib/checksum.S | |||
@@ -0,0 +1,124 @@ | |||
1 | /* $Id: checksum.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * A fast checksum routine using movem | ||
3 | * Copyright (c) 1998-2001 Axis Communications AB | ||
4 | * | ||
5 | * csum_partial(const unsigned char * buff, int len, unsigned int sum) | ||
6 | */ | ||
7 | |||
8 | .globl csum_partial | ||
9 | csum_partial: | ||
10 | |||
11 | ;; r10 - src | ||
12 | ;; r11 - length | ||
13 | ;; r12 - checksum | ||
14 | |||
15 | ;; check for breakeven length between movem and normal word looping versions | ||
16 | ;; we also do _NOT_ want to compute a checksum over more than the | ||
17 | ;; actual length when length < 40 | ||
18 | |||
19 | cmpu.w 80,$r11 | ||
20 | blo _word_loop | ||
21 | nop | ||
22 | |||
23 | ;; need to save the registers we use below in the movem loop | ||
24 | ;; this overhead is why we have a check above for breakeven length | ||
25 | ;; only r0 - r8 have to be saved, the other ones are clobber-able | ||
26 | ;; according to the ABI | ||
27 | |||
28 | subq 9*4,$sp | ||
29 | movem $r8,[$sp] | ||
30 | |||
31 | ;; do a movem checksum | ||
32 | |||
33 | subq 10*4,$r11 ; update length for the first loop | ||
34 | |||
35 | _mloop: movem [$r10+],$r9 ; read 10 longwords | ||
36 | |||
37 | ;; perform dword checksumming on the 10 longwords | ||
38 | |||
39 | add.d $r0,$r12 | ||
40 | ax | ||
41 | add.d $r1,$r12 | ||
42 | ax | ||
43 | add.d $r2,$r12 | ||
44 | ax | ||
45 | add.d $r3,$r12 | ||
46 | ax | ||
47 | add.d $r4,$r12 | ||
48 | ax | ||
49 | add.d $r5,$r12 | ||
50 | ax | ||
51 | add.d $r6,$r12 | ||
52 | ax | ||
53 | add.d $r7,$r12 | ||
54 | ax | ||
55 | add.d $r8,$r12 | ||
56 | ax | ||
57 | add.d $r9,$r12 | ||
58 | |||
59 | ;; fold the carry into the checksum, to avoid having to loop the carry | ||
60 | ;; back into the top | ||
61 | |||
62 | ax | ||
63 | addq 0,$r12 | ||
64 | ax ; do it again, since we might have generated a carry | ||
65 | addq 0,$r12 | ||
66 | |||
67 | subq 10*4,$r11 | ||
68 | bge _mloop | ||
69 | nop | ||
70 | |||
71 | addq 10*4,$r11 ; compensate for last loop underflowing length | ||
72 | |||
73 | movem [$sp+],$r8 ; restore regs | ||
74 | |||
75 | _word_loop: | ||
76 | ;; only fold if there is anything to fold. | ||
77 | |||
78 | cmpq 0,$r12 | ||
79 | beq _no_fold | ||
80 | |||
81 | ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below. | ||
82 | ;; r9 and r13 can be used as temporaries. | ||
83 | |||
84 | moveq -1,$r9 ; put 0xffff in r9, faster than move.d 0xffff,r9 | ||
85 | lsrq 16,$r9 | ||
86 | |||
87 | move.d $r12,$r13 | ||
88 | lsrq 16,$r13 ; r13 = checksum >> 16 | ||
89 | and.d $r9,$r12 ; checksum = checksum & 0xffff | ||
90 | add.d $r13,$r12 ; checksum += r13 | ||
91 | move.d $r12,$r13 ; do the same again, maybe we got a carry last add | ||
92 | lsrq 16,$r13 | ||
93 | and.d $r9,$r12 | ||
94 | add.d $r13,$r12 | ||
95 | |||
96 | _no_fold: | ||
97 | cmpq 2,$r11 | ||
98 | blt _no_words | ||
99 | nop | ||
100 | |||
101 | ;; checksum the rest of the words | ||
102 | |||
103 | subq 2,$r11 | ||
104 | |||
105 | _wloop: subq 2,$r11 | ||
106 | bge _wloop | ||
107 | addu.w [$r10+],$r12 | ||
108 | |||
109 | addq 2,$r11 | ||
110 | |||
111 | _no_words: | ||
112 | ;; see if we have one odd byte more | ||
113 | cmpq 1,$r11 | ||
114 | beq _do_byte | ||
115 | nop | ||
116 | ret | ||
117 | move.d $r12, $r10 | ||
118 | |||
119 | _do_byte: | ||
120 | ;; copy and checksum the last byte | ||
121 | addu.b [$r10],$r12 | ||
122 | ret | ||
123 | move.d $r12, $r10 | ||
124 | |||
diff --git a/arch/cris/arch-v10/lib/checksumcopy.S b/arch/cris/arch-v10/lib/checksumcopy.S new file mode 100644 index 000000000000..35cbffb306fd --- /dev/null +++ b/arch/cris/arch-v10/lib/checksumcopy.S | |||
@@ -0,0 +1,132 @@ | |||
1 | /* $Id: checksumcopy.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * A fast checksum+copy routine using movem | ||
3 | * Copyright (c) 1998, 2001 Axis Communications AB | ||
4 | * | ||
5 | * Authors: Bjorn Wesen | ||
6 | * | ||
7 | * csum_partial_copy_nocheck(const char *src, char *dst, | ||
8 | * int len, unsigned int sum) | ||
9 | */ | ||
10 | |||
11 | .globl csum_partial_copy_nocheck | ||
12 | csum_partial_copy_nocheck: | ||
13 | |||
14 | ;; r10 - src | ||
15 | ;; r11 - dst | ||
16 | ;; r12 - length | ||
17 | ;; r13 - checksum | ||
18 | |||
19 | ;; check for breakeven length between movem and normal word looping versions | ||
20 | ;; we also do _NOT_ want to compute a checksum over more than the | ||
21 | ;; actual length when length < 40 | ||
22 | |||
23 | cmpu.w 80, $r12 | ||
24 | blo _word_loop | ||
25 | nop | ||
26 | |||
27 | ;; need to save the registers we use below in the movem loop | ||
28 | ;; this overhead is why we have a check above for breakeven length | ||
29 | ;; only r0 - r8 have to be saved, the other ones are clobber-able | ||
30 | ;; according to the ABI | ||
31 | |||
32 | subq 9*4, $sp | ||
33 | movem $r8, [$sp] | ||
34 | |||
35 | ;; do a movem copy and checksum | ||
36 | |||
37 | subq 10*4, $r12 ; update length for the first loop | ||
38 | |||
39 | _mloop: movem [$r10+],$r9 ; read 10 longwords | ||
40 | 1: ;; A failing userspace access will have this as PC. | ||
41 | movem $r9,[$r11+] ; write 10 longwords | ||
42 | |||
43 | ;; perform dword checksumming on the 10 longwords | ||
44 | |||
45 | add.d $r0,$r13 | ||
46 | ax | ||
47 | add.d $r1,$r13 | ||
48 | ax | ||
49 | add.d $r2,$r13 | ||
50 | ax | ||
51 | add.d $r3,$r13 | ||
52 | ax | ||
53 | add.d $r4,$r13 | ||
54 | ax | ||
55 | add.d $r5,$r13 | ||
56 | ax | ||
57 | add.d $r6,$r13 | ||
58 | ax | ||
59 | add.d $r7,$r13 | ||
60 | ax | ||
61 | add.d $r8,$r13 | ||
62 | ax | ||
63 | add.d $r9,$r13 | ||
64 | |||
65 | ;; fold the carry into the checksum, to avoid having to loop the carry | ||
66 | ;; back into the top | ||
67 | |||
68 | ax | ||
69 | addq 0,$r13 | ||
70 | ax ; do it again, since we might have generated a carry | ||
71 | addq 0,$r13 | ||
72 | |||
73 | subq 10*4,$r12 | ||
74 | bge _mloop | ||
75 | nop | ||
76 | |||
77 | addq 10*4,$r12 ; compensate for last loop underflowing length | ||
78 | |||
79 | movem [$sp+],$r8 ; restore regs | ||
80 | |||
81 | _word_loop: | ||
82 | ;; only fold if there is anything to fold. | ||
83 | |||
84 | cmpq 0,$r13 | ||
85 | beq _no_fold | ||
86 | |||
87 | ;; fold 32-bit checksum into a 16-bit checksum, to avoid carries below | ||
88 | ;; r9 can be used as temporary. | ||
89 | |||
90 | move.d $r13,$r9 | ||
91 | lsrq 16,$r9 ; r0 = checksum >> 16 | ||
92 | and.d 0xffff,$r13 ; checksum = checksum & 0xffff | ||
93 | add.d $r9,$r13 ; checksum += r0 | ||
94 | move.d $r13,$r9 ; do the same again, maybe we got a carry last add | ||
95 | lsrq 16,$r9 | ||
96 | and.d 0xffff,$r13 | ||
97 | add.d $r9,$r13 | ||
98 | |||
99 | _no_fold: | ||
100 | cmpq 2,$r12 | ||
101 | blt _no_words | ||
102 | nop | ||
103 | |||
104 | ;; copy and checksum the rest of the words | ||
105 | |||
106 | subq 2,$r12 | ||
107 | |||
108 | _wloop: move.w [$r10+],$r9 | ||
109 | 2: ;; A failing userspace access will have this as PC. | ||
110 | addu.w $r9,$r13 | ||
111 | subq 2,$r12 | ||
112 | bge _wloop | ||
113 | move.w $r9,[$r11+] | ||
114 | |||
115 | addq 2,$r12 | ||
116 | |||
117 | _no_words: | ||
118 | ;; see if we have one odd byte more | ||
119 | cmpq 1,$r12 | ||
120 | beq _do_byte | ||
121 | nop | ||
122 | ret | ||
123 | move.d $r13, $r10 | ||
124 | |||
125 | _do_byte: | ||
126 | ;; copy and checksum the last byte | ||
127 | move.b [$r10],$r9 | ||
128 | 3: ;; A failing userspace access will have this as PC. | ||
129 | addu.b $r9,$r13 | ||
130 | move.b $r9,[$r11] | ||
131 | ret | ||
132 | move.d $r13, $r10 | ||
diff --git a/arch/cris/arch-v10/lib/csumcpfruser.S b/arch/cris/arch-v10/lib/csumcpfruser.S new file mode 100644 index 000000000000..5f41ccd62754 --- /dev/null +++ b/arch/cris/arch-v10/lib/csumcpfruser.S | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into | ||
3 | * csum_partial_copy_from_user by adding exception records. | ||
4 | * | ||
5 | * Copyright (C) 2001 Axis Communications AB. | ||
6 | * | ||
7 | * Author: Hans-Peter Nilsson. | ||
8 | */ | ||
9 | |||
10 | #include <asm/errno.h> | ||
11 | |||
12 | /* Same function body, but a different name. If we just added exception | ||
13 | records to _csum_partial_copy_nocheck and made it generic, we wouldn't | ||
14 | know a user fault from a kernel fault and we would have overhead in | ||
15 | each kernel caller for the error-pointer argument. | ||
16 | |||
17 | unsigned int csum_partial_copy_from_user | ||
18 | (const char *src, char *dst, int len, unsigned int sum, int *errptr); | ||
19 | |||
20 | Note that the errptr argument is only set if we encounter an error. | ||
21 | It is conveniently located on the stack, so the normal function body | ||
22 | does not have to handle it. */ | ||
23 | |||
24 | #define csum_partial_copy_nocheck csum_partial_copy_from_user | ||
25 | |||
26 | /* There are local labels numbered 1, 2 and 3 present to mark the | ||
27 | different from-user accesses. */ | ||
28 | #include "checksumcopy.S" | ||
29 | |||
30 | .section .fixup,"ax" | ||
31 | |||
32 | ;; Here from the movem loop; restore stack. | ||
33 | 4: | ||
34 | movem [$sp+],$r8 | ||
35 | ;; r12 is already decremented. Add back chunk_size-2. | ||
36 | addq 40-2,$r12 | ||
37 | |||
38 | ;; Here from the word loop; r12 is off by 2; add it back. | ||
39 | 5: | ||
40 | addq 2,$r12 | ||
41 | |||
42 | ;; Here from a failing single byte. | ||
43 | 6: | ||
44 | |||
45 | ;; Signal in *errptr that we had a failing access. | ||
46 | moveq -EFAULT,$r9 | ||
47 | move.d $r9,[[$sp]] | ||
48 | |||
49 | ;; Clear the rest of the destination area using memset. Preserve the | ||
50 | ;; checksum for the readable bytes. | ||
51 | push $srp | ||
52 | push $r13 | ||
53 | move.d $r11,$r10 | ||
54 | clear.d $r11 | ||
55 | jsr memset | ||
56 | pop $r10 | ||
57 | jump [$sp+] | ||
58 | |||
59 | .previous | ||
60 | .section __ex_table,"a" | ||
61 | .dword 1b,4b | ||
62 | .dword 2b,5b | ||
63 | .dword 3b,6b | ||
64 | .previous | ||
diff --git a/arch/cris/arch-v10/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c new file mode 100644 index 000000000000..e5fb44f505c5 --- /dev/null +++ b/arch/cris/arch-v10/lib/dmacopy.c | |||
@@ -0,0 +1,43 @@ | |||
1 | /* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
2 | * | ||
3 | * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax | ||
4 | */ | ||
5 | |||
6 | #include <asm/svinto.h> | ||
7 | #include <asm/io.h> | ||
8 | |||
9 | #define D(x) | ||
10 | |||
11 | void *dma_memcpy(void *pdst, | ||
12 | const void *psrc, | ||
13 | unsigned int pn) | ||
14 | { | ||
15 | static etrax_dma_descr indma, outdma; | ||
16 | |||
17 | D(printk("dma_memcpy %d bytes... ", pn)); | ||
18 | |||
19 | #if 0 | ||
20 | *R_GEN_CONFIG = genconfig_shadow = | ||
21 | (genconfig_shadow & ~0x3c0000) | | ||
22 | IO_STATE(R_GEN_CONFIG, dma6, intdma7) | | ||
23 | IO_STATE(R_GEN_CONFIG, dma7, intdma6); | ||
24 | #endif | ||
25 | indma.sw_len = outdma.sw_len = pn; | ||
26 | indma.ctrl = d_eol | d_eop; | ||
27 | outdma.ctrl = d_eol; | ||
28 | indma.buf = psrc; | ||
29 | outdma.buf = pdst; | ||
30 | |||
31 | *R_DMA_CH6_FIRST = &indma; | ||
32 | *R_DMA_CH7_FIRST = &outdma; | ||
33 | *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start); | ||
34 | *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start); | ||
35 | |||
36 | while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ; | ||
37 | |||
38 | D(printk("done\n")); | ||
39 | |||
40 | } | ||
41 | |||
42 | |||
43 | |||
diff --git a/arch/cris/arch-v10/lib/dram_init.S b/arch/cris/arch-v10/lib/dram_init.S new file mode 100644 index 000000000000..2ef4ad5706ef --- /dev/null +++ b/arch/cris/arch-v10/lib/dram_init.S | |||
@@ -0,0 +1,205 @@ | |||
1 | /* $Id: dram_init.S,v 1.4 2003/09/22 09:21:59 starvik Exp $ | ||
2 | * | ||
3 | * DRAM/SDRAM initialization - alter with care | ||
4 | * This file is intended to be included from other assembler files | ||
5 | * | ||
6 | * Note: This file may not modify r9 because r9 is used to carry | ||
7 | * information from the decompresser to the kernel | ||
8 | * | ||
9 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
10 | * | ||
11 | * Authors: Mikael Starvik (starvik@axis.com) | ||
12 | * | ||
13 | * $Log: dram_init.S,v $ | ||
14 | * Revision 1.4 2003/09/22 09:21:59 starvik | ||
15 | * Decompresser is linked to 0x407xxxxx and sdram commands are at 0x000xxxxx | ||
16 | * so we need to mask off 12 bits. | ||
17 | * | ||
18 | * Revision 1.3 2003/03/31 09:38:37 starvik | ||
19 | * Corrected calculation of end of sdram init commands | ||
20 | * | ||
21 | * Revision 1.2 2002/11/19 13:33:29 starvik | ||
22 | * Changes from Linux 2.4 | ||
23 | * | ||
24 | * Revision 1.13 2002/10/30 07:42:28 starvik | ||
25 | * Always read SDRAM command sequence from flash | ||
26 | * | ||
27 | * Revision 1.12 2002/08/09 11:37:37 orjanf | ||
28 | * Added double initialization work-around for Samsung SDRAMs. | ||
29 | * | ||
30 | * Revision 1.11 2002/06/04 11:43:21 starvik | ||
31 | * Check if mrs_data is specified in kernelconfig (necessary for MCM) | ||
32 | * | ||
33 | * Revision 1.10 2001/10/04 12:00:21 martinnn | ||
34 | * Added missing underscores. | ||
35 | * | ||
36 | * Revision 1.9 2001/10/01 14:47:35 bjornw | ||
37 | * Added register prefixes and removed underscores | ||
38 | * | ||
39 | * Revision 1.8 2001/05/15 07:12:45 hp | ||
40 | * Copy warning from head.S about r8 and r9 | ||
41 | * | ||
42 | * Revision 1.7 2001/04/18 12:05:39 bjornw | ||
43 | * Fixed comments, and explicitely include config.h to be sure its there | ||
44 | * | ||
45 | * Revision 1.6 2001/04/10 06:20:16 starvik | ||
46 | * Delay should be 200us, not 200ns | ||
47 | * | ||
48 | * Revision 1.5 2001/04/09 06:01:13 starvik | ||
49 | * Added support for 100 MHz SDRAMs | ||
50 | * | ||
51 | * Revision 1.4 2001/03/26 14:24:01 bjornw | ||
52 | * Namechange of some config options | ||
53 | * | ||
54 | * Revision 1.3 2001/03/23 08:29:41 starvik | ||
55 | * Corrected calculation of mrs_data | ||
56 | * | ||
57 | * Revision 1.2 2001/02/08 15:20:00 starvik | ||
58 | * Corrected SDRAM initialization | ||
59 | * Should now be included as inline | ||
60 | * | ||
61 | * Revision 1.1 2001/01/29 13:08:02 starvik | ||
62 | * Initial version | ||
63 | * This file should be included from all assembler files that needs to | ||
64 | * initialize DRAM/SDRAM. | ||
65 | * | ||
66 | */ | ||
67 | |||
68 | /* Just to be certain the config file is included, we include it here | ||
69 | * explicitely instead of depending on it being included in the file that | ||
70 | * uses this code. | ||
71 | */ | ||
72 | |||
73 | #include <linux/config.h> | ||
74 | |||
75 | ;; WARNING! The registers r8 and r9 are used as parameters carrying | ||
76 | ;; information from the decompressor (if the kernel was compressed). | ||
77 | ;; They should not be used in the code below. | ||
78 | |||
79 | #ifndef CONFIG_SVINTO_SIM | ||
80 | move.d CONFIG_ETRAX_DEF_R_WAITSTATES, $r0 | ||
81 | move.d $r0, [R_WAITSTATES] | ||
82 | |||
83 | move.d CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0 | ||
84 | move.d $r0, [R_BUS_CONFIG] | ||
85 | |||
86 | #ifndef CONFIG_ETRAX_SDRAM | ||
87 | move.d CONFIG_ETRAX_DEF_R_DRAM_CONFIG, $r0 | ||
88 | move.d $r0, [R_DRAM_CONFIG] | ||
89 | |||
90 | move.d CONFIG_ETRAX_DEF_R_DRAM_TIMING, $r0 | ||
91 | move.d $r0, [R_DRAM_TIMING] | ||
92 | #else | ||
93 | ;; Samsung SDRAMs seem to require to be initialized twice to work properly. | ||
94 | moveq 2, $r6 | ||
95 | _sdram_init: | ||
96 | |||
97 | ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization | ||
98 | |||
99 | ; Bank configuration | ||
100 | move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r0 | ||
101 | move.d $r0, [R_SDRAM_CONFIG] | ||
102 | |||
103 | ; Calculate value of mrs_data | ||
104 | ; CAS latency = 2 && bus_width = 32 => 0x40 | ||
105 | ; CAS latency = 3 && bus_width = 32 => 0x60 | ||
106 | ; CAS latency = 2 && bus_width = 16 => 0x20 | ||
107 | ; CAS latency = 3 && bus_width = 16 => 0x30 | ||
108 | |||
109 | ; Check if value is already supplied in kernel config | ||
110 | move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r2 | ||
111 | and.d 0x00ff0000, $r2 | ||
112 | bne _set_timing | ||
113 | lsrq 16, $r2 | ||
114 | |||
115 | move.d 0x40, $r2 ; Assume 32 bits and CAS latency = 2 | ||
116 | move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 | ||
117 | move.d $r1, $r3 | ||
118 | and.d 0x03, $r1 ; Get CAS latency | ||
119 | and.d 0x1000, $r3 ; 50 or 100 MHz? | ||
120 | beq _speed_50 | ||
121 | nop | ||
122 | _speed_100: | ||
123 | cmp.d 0x00, $r1 ; CAS latency = 2? | ||
124 | beq _bw_check | ||
125 | nop | ||
126 | or.d 0x20, $r2 ; CAS latency = 3 | ||
127 | ba _bw_check | ||
128 | nop | ||
129 | _speed_50: | ||
130 | cmp.d 0x01, $r1 ; CAS latency = 2? | ||
131 | beq _bw_check | ||
132 | nop | ||
133 | or.d 0x20, $r2 ; CAS latency = 3 | ||
134 | _bw_check: | ||
135 | move.d CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r1 | ||
136 | and.d 0x800000, $r1 ; DRAM width is bit 23 | ||
137 | bne _set_timing | ||
138 | nop | ||
139 | lsrq 1, $r2 ; 16 bits. Shift down value. | ||
140 | |||
141 | ; Set timing parameters. Starts master clock | ||
142 | _set_timing: | ||
143 | move.d CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1 | ||
144 | and.d 0x8000f9ff, $r1 ; Make sure mrs data and command is 0 | ||
145 | or.d 0x80000000, $r1 ; Make sure sdram enable bit is set | ||
146 | move.d $r1, $r5 | ||
147 | or.d 0x0000c000, $r1 ; ref = disable | ||
148 | lslq 16, $r2 ; mrs data starts at bit 16 | ||
149 | or.d $r2, $r1 | ||
150 | move.d $r1, [R_SDRAM_TIMING] | ||
151 | |||
152 | ; Wait 200us | ||
153 | move.d 10000, $r2 | ||
154 | 1: bne 1b | ||
155 | subq 1, $r2 | ||
156 | |||
157 | ; Issue initialization command sequence | ||
158 | move.d _sdram_commands_start, $r2 | ||
159 | and.d 0x000fffff, $r2 ; Make sure commands are read from flash | ||
160 | move.d _sdram_commands_end, $r3 | ||
161 | and.d 0x000fffff, $r3 | ||
162 | 1: clear.d $r4 | ||
163 | move.b [$r2+], $r4 | ||
164 | lslq 9, $r4 ; Command starts at bit 9 | ||
165 | or.d $r1, $r4 | ||
166 | move.d $r4, [R_SDRAM_TIMING] | ||
167 | nop ; Wait five nop cycles between each command | ||
168 | nop | ||
169 | nop | ||
170 | nop | ||
171 | nop | ||
172 | cmp.d $r2, $r3 | ||
173 | bne 1b | ||
174 | nop | ||
175 | move.d $r5, [R_SDRAM_TIMING] | ||
176 | subq 1, $r6 | ||
177 | bne _sdram_init | ||
178 | nop | ||
179 | ba _sdram_commands_end | ||
180 | nop | ||
181 | |||
182 | _sdram_commands_start: | ||
183 | .byte 3 ; Precharge | ||
184 | .byte 0 ; nop | ||
185 | .byte 2 ; refresh | ||
186 | .byte 0 ; nop | ||
187 | .byte 2 ; refresh | ||
188 | .byte 0 ; nop | ||
189 | .byte 2 ; refresh | ||
190 | .byte 0 ; nop | ||
191 | .byte 2 ; refresh | ||
192 | .byte 0 ; nop | ||
193 | .byte 2 ; refresh | ||
194 | .byte 0 ; nop | ||
195 | .byte 2 ; refresh | ||
196 | .byte 0 ; nop | ||
197 | .byte 2 ; refresh | ||
198 | .byte 0 ; nop | ||
199 | .byte 2 ; refresh | ||
200 | .byte 0 ; nop | ||
201 | .byte 1 ; mrs | ||
202 | .byte 0 ; nop | ||
203 | _sdram_commands_end: | ||
204 | #endif | ||
205 | #endif | ||
diff --git a/arch/cris/arch-v10/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S new file mode 100644 index 000000000000..56905aaa7b6e --- /dev/null +++ b/arch/cris/arch-v10/lib/hw_settings.S | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $ | ||
3 | * | ||
4 | * This table is used by some tools to extract hardware parameters. | ||
5 | * The table should be included in the kernel and the decompressor. | ||
6 | * Don't forget to update the tools if you change this table. | ||
7 | * | ||
8 | * Copyright (C) 2001 Axis Communications AB | ||
9 | * | ||
10 | * Authors: Mikael Starvik (starvik@axis.com) | ||
11 | */ | ||
12 | |||
13 | #define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \ | ||
14 | (CONFIG_ETRAX_DEF_R_PORT_PA_DATA)) | ||
15 | #define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \ | ||
16 | (CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \ | ||
17 | (CONFIG_ETRAX_DEF_R_PORT_PB_DATA)) | ||
18 | |||
19 | .ascii "HW_PARAM_MAGIC" ; Magic number | ||
20 | .dword 0xc0004000 ; Kernel start address | ||
21 | |||
22 | ; Debug port | ||
23 | #ifdef CONFIG_ETRAX_DEBUG_PORT0 | ||
24 | .dword 0 | ||
25 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | ||
26 | .dword 1 | ||
27 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | ||
28 | .dword 2 | ||
29 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | ||
30 | .dword 3 | ||
31 | #else | ||
32 | .dword 4 ; No debug | ||
33 | #endif | ||
34 | |||
35 | ; SDRAM or EDO DRAM? | ||
36 | #ifdef CONFIG_ETRAX_SDRAM | ||
37 | .dword 1 | ||
38 | #else | ||
39 | .dword 0 | ||
40 | #endif | ||
41 | |||
42 | ; Register values | ||
43 | .dword R_WAITSTATES | ||
44 | .dword CONFIG_ETRAX_DEF_R_WAITSTATES | ||
45 | .dword R_BUS_CONFIG | ||
46 | .dword CONFIG_ETRAX_DEF_R_BUS_CONFIG | ||
47 | #ifdef CONFIG_ETRAX_SDRAM | ||
48 | .dword R_SDRAM_CONFIG | ||
49 | .dword CONFIG_ETRAX_DEF_R_SDRAM_CONFIG | ||
50 | .dword R_SDRAM_TIMING | ||
51 | .dword CONFIG_ETRAX_DEF_R_SDRAM_TIMING | ||
52 | #else | ||
53 | .dword R_DRAM_CONFIG | ||
54 | .dword CONFIG_ETRAX_DEF_R_DRAM_CONFIG | ||
55 | .dword R_DRAM_TIMING | ||
56 | .dword CONFIG_ETRAX_DEF_R_DRAM_TIMING | ||
57 | #endif | ||
58 | .dword R_PORT_PA_SET | ||
59 | .dword PA_SET_VALUE | ||
60 | .dword R_PORT_PB_SET | ||
61 | .dword PB_SET_VALUE | ||
62 | .dword 0 ; No more register values | ||
diff --git a/arch/cris/arch-v10/lib/memset.c b/arch/cris/arch-v10/lib/memset.c new file mode 100644 index 000000000000..82bb66839171 --- /dev/null +++ b/arch/cris/arch-v10/lib/memset.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /*#************************************************************************#*/ | ||
2 | /*#-------------------------------------------------------------------------*/ | ||
3 | /*# */ | ||
4 | /*# FUNCTION NAME: memset() */ | ||
5 | /*# */ | ||
6 | /*# PARAMETERS: void* dst; Destination address. */ | ||
7 | /*# int c; Value of byte to write. */ | ||
8 | /*# int len; Number of bytes to write. */ | ||
9 | /*# */ | ||
10 | /*# RETURNS: dst. */ | ||
11 | /*# */ | ||
12 | /*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */ | ||
13 | /*# Framework taken from memcpy. This routine is */ | ||
14 | /*# very sensitive to compiler changes in register allocation. */ | ||
15 | /*# Should really be rewritten to avoid this problem. */ | ||
16 | /*# */ | ||
17 | /*#-------------------------------------------------------------------------*/ | ||
18 | /*# */ | ||
19 | /*# HISTORY */ | ||
20 | /*# */ | ||
21 | /*# DATE NAME CHANGES */ | ||
22 | /*# ---- ---- ------- */ | ||
23 | /*# 990713 HP Tired of watching this function (or */ | ||
24 | /*# really, the nonoptimized generic */ | ||
25 | /*# implementation) take up 90% of simulator */ | ||
26 | /*# output. Measurements needed. */ | ||
27 | /*# */ | ||
28 | /*#-------------------------------------------------------------------------*/ | ||
29 | |||
30 | #include <linux/types.h> | ||
31 | |||
32 | /* No, there's no macro saying 12*4, since it is "hard" to get it into | ||
33 | the asm in a good way. Thus better to expose the problem everywhere. | ||
34 | */ | ||
35 | |||
36 | /* Assuming 1 cycle per dword written or read (ok, not really true), and | ||
37 | one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1) | ||
38 | so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */ | ||
39 | |||
40 | #define ZERO_BLOCK_SIZE (1*12*4) | ||
41 | |||
42 | void *memset(void *pdst, | ||
43 | int c, | ||
44 | size_t plen) | ||
45 | { | ||
46 | /* Ok. Now we want the parameters put in special registers. | ||
47 | Make sure the compiler is able to make something useful of this. */ | ||
48 | |||
49 | register char *return_dst __asm__ ("r10") = pdst; | ||
50 | register int n __asm__ ("r12") = plen; | ||
51 | register int lc __asm__ ("r11") = c; | ||
52 | |||
53 | /* Most apps use memset sanely. Only those memsetting about 3..4 | ||
54 | bytes or less get penalized compared to the generic implementation | ||
55 | - and that's not really sane use. */ | ||
56 | |||
57 | /* Ugh. This is fragile at best. Check with newer GCC releases, if | ||
58 | they compile cascaded "x |= x << 8" sanely! */ | ||
59 | __asm__("movu.b %0,$r13\n\t" | ||
60 | "lslq 8,$r13\n\t" | ||
61 | "move.b %0,$r13\n\t" | ||
62 | "move.d $r13,%0\n\t" | ||
63 | "lslq 16,$r13\n\t" | ||
64 | "or.d $r13,%0" | ||
65 | : "=r" (lc) : "0" (lc) : "r13"); | ||
66 | |||
67 | { | ||
68 | register char *dst __asm__ ("r13") = pdst; | ||
69 | |||
70 | /* This is NONPORTABLE, but since this whole routine is */ | ||
71 | /* grossly nonportable that doesn't matter. */ | ||
72 | |||
73 | if (((unsigned long) pdst & 3) != 0 | ||
74 | /* Oops! n=0 must be a legal call, regardless of alignment. */ | ||
75 | && n >= 3) | ||
76 | { | ||
77 | if ((unsigned long)dst & 1) | ||
78 | { | ||
79 | *dst = (char) lc; | ||
80 | n--; | ||
81 | dst++; | ||
82 | } | ||
83 | |||
84 | if ((unsigned long)dst & 2) | ||
85 | { | ||
86 | *(short *)dst = lc; | ||
87 | n -= 2; | ||
88 | dst += 2; | ||
89 | } | ||
90 | } | ||
91 | |||
92 | /* Now the fun part. For the threshold value of this, check the equation | ||
93 | above. */ | ||
94 | /* Decide which copying method to use. */ | ||
95 | if (n >= ZERO_BLOCK_SIZE) | ||
96 | { | ||
97 | /* For large copies we use 'movem' */ | ||
98 | |||
99 | /* It is not optimal to tell the compiler about clobbering any | ||
100 | registers; that will move the saving/restoring of those registers | ||
101 | to the function prologue/epilogue, and make non-movem sizes | ||
102 | suboptimal. | ||
103 | |||
104 | This method is not foolproof; it assumes that the "asm reg" | ||
105 | declarations at the beginning of the function really are used | ||
106 | here (beware: they may be moved to temporary registers). | ||
107 | This way, we do not have to save/move the registers around into | ||
108 | temporaries; we can safely use them straight away. | ||
109 | |||
110 | If you want to check that the allocation was right; then | ||
111 | check the equalities in the first comment. It should say | ||
112 | "r13=r13, r12=r12, r11=r11" */ | ||
113 | __asm__ volatile (" | ||
114 | ;; Check that the following is true (same register names on | ||
115 | ;; both sides of equal sign, as in r8=r8): | ||
116 | ;; %0=r13, %1=r12, %4=r11 | ||
117 | ;; | ||
118 | ;; Save the registers we'll clobber in the movem process | ||
119 | ;; on the stack. Don't mention them to gcc, it will only be | ||
120 | ;; upset. | ||
121 | subq 11*4,$sp | ||
122 | movem $r10,[$sp] | ||
123 | |||
124 | move.d $r11,$r0 | ||
125 | move.d $r11,$r1 | ||
126 | move.d $r11,$r2 | ||
127 | move.d $r11,$r3 | ||
128 | move.d $r11,$r4 | ||
129 | move.d $r11,$r5 | ||
130 | move.d $r11,$r6 | ||
131 | move.d $r11,$r7 | ||
132 | move.d $r11,$r8 | ||
133 | move.d $r11,$r9 | ||
134 | move.d $r11,$r10 | ||
135 | |||
136 | ;; Now we've got this: | ||
137 | ;; r13 - dst | ||
138 | ;; r12 - n | ||
139 | |||
140 | ;; Update n for the first loop | ||
141 | subq 12*4,$r12 | ||
142 | 0: | ||
143 | subq 12*4,$r12 | ||
144 | bge 0b | ||
145 | movem $r11,[$r13+] | ||
146 | |||
147 | addq 12*4,$r12 ;; compensate for last loop underflowing n | ||
148 | |||
149 | ;; Restore registers from stack | ||
150 | movem [$sp+],$r10" | ||
151 | |||
152 | /* Outputs */ : "=r" (dst), "=r" (n) | ||
153 | /* Inputs */ : "0" (dst), "1" (n), "r" (lc)); | ||
154 | |||
155 | } | ||
156 | |||
157 | /* Either we directly starts copying, using dword copying | ||
158 | in a loop, or we copy as much as possible with 'movem' | ||
159 | and then the last block (<44 bytes) is copied here. | ||
160 | This will work since 'movem' will have updated src,dst,n. */ | ||
161 | |||
162 | while ( n >= 16 ) | ||
163 | { | ||
164 | *((long*)dst)++ = lc; | ||
165 | *((long*)dst)++ = lc; | ||
166 | *((long*)dst)++ = lc; | ||
167 | *((long*)dst)++ = lc; | ||
168 | n -= 16; | ||
169 | } | ||
170 | |||
171 | /* A switch() is definitely the fastest although it takes a LOT of code. | ||
172 | * Particularly if you inline code this. | ||
173 | */ | ||
174 | switch (n) | ||
175 | { | ||
176 | case 0: | ||
177 | break; | ||
178 | case 1: | ||
179 | *(char*)dst = (char) lc; | ||
180 | break; | ||
181 | case 2: | ||
182 | *(short*)dst = (short) lc; | ||
183 | break; | ||
184 | case 3: | ||
185 | *((short*)dst)++ = (short) lc; | ||
186 | *(char*)dst = (char) lc; | ||
187 | break; | ||
188 | case 4: | ||
189 | *((long*)dst)++ = lc; | ||
190 | break; | ||
191 | case 5: | ||
192 | *((long*)dst)++ = lc; | ||
193 | *(char*)dst = (char) lc; | ||
194 | break; | ||
195 | case 6: | ||
196 | *((long*)dst)++ = lc; | ||
197 | *(short*)dst = (short) lc; | ||
198 | break; | ||
199 | case 7: | ||
200 | *((long*)dst)++ = lc; | ||
201 | *((short*)dst)++ = (short) lc; | ||
202 | *(char*)dst = (char) lc; | ||
203 | break; | ||
204 | case 8: | ||
205 | *((long*)dst)++ = lc; | ||
206 | *((long*)dst)++ = lc; | ||
207 | break; | ||
208 | case 9: | ||
209 | *((long*)dst)++ = lc; | ||
210 | *((long*)dst)++ = lc; | ||
211 | *(char*)dst = (char) lc; | ||
212 | break; | ||
213 | case 10: | ||
214 | *((long*)dst)++ = lc; | ||
215 | *((long*)dst)++ = lc; | ||
216 | *(short*)dst = (short) lc; | ||
217 | break; | ||
218 | case 11: | ||
219 | *((long*)dst)++ = lc; | ||
220 | *((long*)dst)++ = lc; | ||
221 | *((short*)dst)++ = (short) lc; | ||
222 | *(char*)dst = (char) lc; | ||
223 | break; | ||
224 | case 12: | ||
225 | *((long*)dst)++ = lc; | ||
226 | *((long*)dst)++ = lc; | ||
227 | *((long*)dst)++ = lc; | ||
228 | break; | ||
229 | case 13: | ||
230 | *((long*)dst)++ = lc; | ||
231 | *((long*)dst)++ = lc; | ||
232 | *((long*)dst)++ = lc; | ||
233 | *(char*)dst = (char) lc; | ||
234 | break; | ||
235 | case 14: | ||
236 | *((long*)dst)++ = lc; | ||
237 | *((long*)dst)++ = lc; | ||
238 | *((long*)dst)++ = lc; | ||
239 | *(short*)dst = (short) lc; | ||
240 | break; | ||
241 | case 15: | ||
242 | *((long*)dst)++ = lc; | ||
243 | *((long*)dst)++ = lc; | ||
244 | *((long*)dst)++ = lc; | ||
245 | *((short*)dst)++ = (short) lc; | ||
246 | *(char*)dst = (char) lc; | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | return return_dst; /* destination pointer. */ | ||
252 | } /* memset() */ | ||
diff --git a/arch/cris/arch-v10/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c new file mode 100644 index 000000000000..22a6f0aa9cef --- /dev/null +++ b/arch/cris/arch-v10/lib/old_checksum.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* $Id: old_checksum.c,v 1.3 2003/10/27 08:04:32 starvik Exp $ | ||
2 | * | ||
3 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
4 | * operating system. INET is implemented using the BSD Socket | ||
5 | * interface as the means of communication with the user level. | ||
6 | * | ||
7 | * IP/TCP/UDP checksumming routines | ||
8 | * | ||
9 | * Authors: Jorge Cwik, <jorge@laser.satlink.net> | ||
10 | * Arnt Gulbrandsen, <agulbra@nvg.unit.no> | ||
11 | * Tom May, <ftom@netcom.com> | ||
12 | * Lots of code moved from tcp.c and ip.c; see those files | ||
13 | * for more names. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * as published by the Free Software Foundation; either version | ||
18 | * 2 of the License, or (at your option) any later version. | ||
19 | */ | ||
20 | |||
21 | #include <net/checksum.h> | ||
22 | #include <net/module.h> | ||
23 | |||
24 | #undef PROFILE_CHECKSUM | ||
25 | |||
26 | #ifdef PROFILE_CHECKSUM | ||
27 | /* these are just for profiling the checksum code with an oscillioscope.. uh */ | ||
28 | #if 0 | ||
29 | #define BITOFF *((unsigned char *)0xb0000030) = 0xff | ||
30 | #define BITON *((unsigned char *)0xb0000030) = 0x0 | ||
31 | #endif | ||
32 | #include <asm/io.h> | ||
33 | #define CBITON LED_ACTIVE_SET(1) | ||
34 | #define CBITOFF LED_ACTIVE_SET(0) | ||
35 | #define BITOFF | ||
36 | #define BITON | ||
37 | #else | ||
38 | #define BITOFF | ||
39 | #define BITON | ||
40 | #define CBITOFF | ||
41 | #define CBITON | ||
42 | #endif | ||
43 | |||
44 | /* | ||
45 | * computes a partial checksum, e.g. for TCP/UDP fragments | ||
46 | */ | ||
47 | |||
48 | #include <asm/delay.h> | ||
49 | |||
50 | unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) | ||
51 | { | ||
52 | /* | ||
53 | * Experiments with ethernet and slip connections show that buff | ||
54 | * is aligned on either a 2-byte or 4-byte boundary. | ||
55 | */ | ||
56 | const unsigned char *endMarker = buff + len; | ||
57 | const unsigned char *marker = endMarker - (len % 16); | ||
58 | #if 0 | ||
59 | if((int)buff & 0x3) | ||
60 | printk("unaligned buff %p\n", buff); | ||
61 | __delay(900); /* extra delay of 90 us to test performance hit */ | ||
62 | #endif | ||
63 | BITON; | ||
64 | while (buff < marker) { | ||
65 | sum += *((unsigned short *)buff)++; | ||
66 | sum += *((unsigned short *)buff)++; | ||
67 | sum += *((unsigned short *)buff)++; | ||
68 | sum += *((unsigned short *)buff)++; | ||
69 | sum += *((unsigned short *)buff)++; | ||
70 | sum += *((unsigned short *)buff)++; | ||
71 | sum += *((unsigned short *)buff)++; | ||
72 | sum += *((unsigned short *)buff)++; | ||
73 | } | ||
74 | marker = endMarker - (len % 2); | ||
75 | while(buff < marker) { | ||
76 | sum += *((unsigned short *)buff)++; | ||
77 | } | ||
78 | if(endMarker - buff > 0) { | ||
79 | sum += *buff; /* add extra byte seperately */ | ||
80 | } | ||
81 | BITOFF; | ||
82 | return(sum); | ||
83 | } | ||
84 | |||
85 | EXPORT_SYMBOL(csum_partial); | ||
diff --git a/arch/cris/arch-v10/lib/string.c b/arch/cris/arch-v10/lib/string.c new file mode 100644 index 000000000000..8ffde4901b57 --- /dev/null +++ b/arch/cris/arch-v10/lib/string.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /*#************************************************************************#*/ | ||
2 | /*#-------------------------------------------------------------------------*/ | ||
3 | /*# */ | ||
4 | /*# FUNCTION NAME: memcpy() */ | ||
5 | /*# */ | ||
6 | /*# PARAMETERS: void* dst; Destination address. */ | ||
7 | /*# void* src; Source address. */ | ||
8 | /*# int len; Number of bytes to copy. */ | ||
9 | /*# */ | ||
10 | /*# RETURNS: dst. */ | ||
11 | /*# */ | ||
12 | /*# DESCRIPTION: Copies len bytes of memory from src to dst. No guarantees */ | ||
13 | /*# about copying of overlapping memory areas. This routine is */ | ||
14 | /*# very sensitive to compiler changes in register allocation. */ | ||
15 | /*# Should really be rewritten to avoid this problem. */ | ||
16 | /*# */ | ||
17 | /*#-------------------------------------------------------------------------*/ | ||
18 | /*# */ | ||
19 | /*# HISTORY */ | ||
20 | /*# */ | ||
21 | /*# DATE NAME CHANGES */ | ||
22 | /*# ---- ---- ------- */ | ||
23 | /*# 941007 Kenny R Creation */ | ||
24 | /*# 941011 Kenny R Lots of optimizations and inlining. */ | ||
25 | /*# 941129 Ulf A Adapted for use in libc. */ | ||
26 | /*# 950216 HP N==0 forgotten if non-aligned src/dst. */ | ||
27 | /*# Added some optimizations. */ | ||
28 | /*# 001025 HP Make src and dst char *. Align dst to */ | ||
29 | /*# dword, not just word-if-both-src-and-dst- */ | ||
30 | /*# are-misaligned. */ | ||
31 | /*# */ | ||
32 | /*#-------------------------------------------------------------------------*/ | ||
33 | |||
34 | #include <linux/types.h> | ||
35 | |||
36 | void *memcpy(void *pdst, | ||
37 | const void *psrc, | ||
38 | size_t pn) | ||
39 | { | ||
40 | /* Ok. Now we want the parameters put in special registers. | ||
41 | Make sure the compiler is able to make something useful of this. | ||
42 | As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). | ||
43 | |||
44 | If gcc was allright, it really would need no temporaries, and no | ||
45 | stack space to save stuff on. */ | ||
46 | |||
47 | register void *return_dst __asm__ ("r10") = pdst; | ||
48 | register char *dst __asm__ ("r13") = pdst; | ||
49 | register const char *src __asm__ ("r11") = psrc; | ||
50 | register int n __asm__ ("r12") = pn; | ||
51 | |||
52 | |||
53 | /* When src is aligned but not dst, this makes a few extra needless | ||
54 | cycles. I believe it would take as many to check that the | ||
55 | re-alignment was unnecessary. */ | ||
56 | if (((unsigned long) dst & 3) != 0 | ||
57 | /* Don't align if we wouldn't copy more than a few bytes; so we | ||
58 | don't have to check further for overflows. */ | ||
59 | && n >= 3) | ||
60 | { | ||
61 | if ((unsigned long) dst & 1) | ||
62 | { | ||
63 | n--; | ||
64 | *(char*)dst = *(char*)src; | ||
65 | src++; | ||
66 | dst++; | ||
67 | } | ||
68 | |||
69 | if ((unsigned long) dst & 2) | ||
70 | { | ||
71 | n -= 2; | ||
72 | *(short*)dst = *(short*)src; | ||
73 | src += 2; | ||
74 | dst += 2; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | /* Decide which copying method to use. */ | ||
79 | if (n >= 44*2) /* Break even between movem and | ||
80 | move16 is at 38.7*2, but modulo 44. */ | ||
81 | { | ||
82 | /* For large copies we use 'movem' */ | ||
83 | |||
84 | /* It is not optimal to tell the compiler about clobbering any | ||
85 | registers; that will move the saving/restoring of those registers | ||
86 | to the function prologue/epilogue, and make non-movem sizes | ||
87 | suboptimal. | ||
88 | |||
89 | This method is not foolproof; it assumes that the "asm reg" | ||
90 | declarations at the beginning of the function really are used | ||
91 | here (beware: they may be moved to temporary registers). | ||
92 | This way, we do not have to save/move the registers around into | ||
93 | temporaries; we can safely use them straight away. | ||
94 | |||
95 | If you want to check that the allocation was right; then | ||
96 | check the equalities in the first comment. It should say | ||
97 | "r13=r13, r11=r11, r12=r12" */ | ||
98 | __asm__ volatile (" | ||
99 | ;; Check that the following is true (same register names on | ||
100 | ;; both sides of equal sign, as in r8=r8): | ||
101 | ;; %0=r13, %1=r11, %2=r12 | ||
102 | ;; | ||
103 | ;; Save the registers we'll use in the movem process | ||
104 | ;; on the stack. | ||
105 | subq 11*4,$sp | ||
106 | movem $r10,[$sp] | ||
107 | |||
108 | ;; Now we've got this: | ||
109 | ;; r11 - src | ||
110 | ;; r13 - dst | ||
111 | ;; r12 - n | ||
112 | |||
113 | ;; Update n for the first loop | ||
114 | subq 44,$r12 | ||
115 | 0: | ||
116 | movem [$r11+],$r10 | ||
117 | subq 44,$r12 | ||
118 | bge 0b | ||
119 | movem $r10,[$r13+] | ||
120 | |||
121 | addq 44,$r12 ;; compensate for last loop underflowing n | ||
122 | |||
123 | ;; Restore registers from stack | ||
124 | movem [$sp+],$r10" | ||
125 | |||
126 | /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n) | ||
127 | /* Inputs */ : "0" (dst), "1" (src), "2" (n)); | ||
128 | |||
129 | } | ||
130 | |||
131 | /* Either we directly starts copying, using dword copying | ||
132 | in a loop, or we copy as much as possible with 'movem' | ||
133 | and then the last block (<44 bytes) is copied here. | ||
134 | This will work since 'movem' will have updated src,dst,n. */ | ||
135 | |||
136 | while ( n >= 16 ) | ||
137 | { | ||
138 | *((long*)dst)++ = *((long*)src)++; | ||
139 | *((long*)dst)++ = *((long*)src)++; | ||
140 | *((long*)dst)++ = *((long*)src)++; | ||
141 | *((long*)dst)++ = *((long*)src)++; | ||
142 | n -= 16; | ||
143 | } | ||
144 | |||
145 | /* A switch() is definitely the fastest although it takes a LOT of code. | ||
146 | * Particularly if you inline code this. | ||
147 | */ | ||
148 | switch (n) | ||
149 | { | ||
150 | case 0: | ||
151 | break; | ||
152 | case 1: | ||
153 | *(char*)dst = *(char*)src; | ||
154 | break; | ||
155 | case 2: | ||
156 | *(short*)dst = *(short*)src; | ||
157 | break; | ||
158 | case 3: | ||
159 | *((short*)dst)++ = *((short*)src)++; | ||
160 | *(char*)dst = *(char*)src; | ||
161 | break; | ||
162 | case 4: | ||
163 | *((long*)dst)++ = *((long*)src)++; | ||
164 | break; | ||
165 | case 5: | ||
166 | *((long*)dst)++ = *((long*)src)++; | ||
167 | *(char*)dst = *(char*)src; | ||
168 | break; | ||
169 | case 6: | ||
170 | *((long*)dst)++ = *((long*)src)++; | ||
171 | *(short*)dst = *(short*)src; | ||
172 | break; | ||
173 | case 7: | ||
174 | *((long*)dst)++ = *((long*)src)++; | ||
175 | *((short*)dst)++ = *((short*)src)++; | ||
176 | *(char*)dst = *(char*)src; | ||
177 | break; | ||
178 | case 8: | ||
179 | *((long*)dst)++ = *((long*)src)++; | ||
180 | *((long*)dst)++ = *((long*)src)++; | ||
181 | break; | ||
182 | case 9: | ||
183 | *((long*)dst)++ = *((long*)src)++; | ||
184 | *((long*)dst)++ = *((long*)src)++; | ||
185 | *(char*)dst = *(char*)src; | ||
186 | break; | ||
187 | case 10: | ||
188 | *((long*)dst)++ = *((long*)src)++; | ||
189 | *((long*)dst)++ = *((long*)src)++; | ||
190 | *(short*)dst = *(short*)src; | ||
191 | break; | ||
192 | case 11: | ||
193 | *((long*)dst)++ = *((long*)src)++; | ||
194 | *((long*)dst)++ = *((long*)src)++; | ||
195 | *((short*)dst)++ = *((short*)src)++; | ||
196 | *(char*)dst = *(char*)src; | ||
197 | break; | ||
198 | case 12: | ||
199 | *((long*)dst)++ = *((long*)src)++; | ||
200 | *((long*)dst)++ = *((long*)src)++; | ||
201 | *((long*)dst)++ = *((long*)src)++; | ||
202 | break; | ||
203 | case 13: | ||
204 | *((long*)dst)++ = *((long*)src)++; | ||
205 | *((long*)dst)++ = *((long*)src)++; | ||
206 | *((long*)dst)++ = *((long*)src)++; | ||
207 | *(char*)dst = *(char*)src; | ||
208 | break; | ||
209 | case 14: | ||
210 | *((long*)dst)++ = *((long*)src)++; | ||
211 | *((long*)dst)++ = *((long*)src)++; | ||
212 | *((long*)dst)++ = *((long*)src)++; | ||
213 | *(short*)dst = *(short*)src; | ||
214 | break; | ||
215 | case 15: | ||
216 | *((long*)dst)++ = *((long*)src)++; | ||
217 | *((long*)dst)++ = *((long*)src)++; | ||
218 | *((long*)dst)++ = *((long*)src)++; | ||
219 | *((short*)dst)++ = *((short*)src)++; | ||
220 | *(char*)dst = *(char*)src; | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | return return_dst; /* destination pointer. */ | ||
225 | } /* memcpy() */ | ||
diff --git a/arch/cris/arch-v10/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c new file mode 100644 index 000000000000..43778d53c254 --- /dev/null +++ b/arch/cris/arch-v10/lib/usercopy.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* | ||
2 | * User address space access functions. | ||
3 | * The non-inlined parts of asm-cris/uaccess.h are here. | ||
4 | * | ||
5 | * Copyright (C) 2000, Axis Communications AB. | ||
6 | * | ||
7 | * Written by Hans-Peter Nilsson. | ||
8 | * Pieces used from memcpy, originally by Kenny Ranerup long time ago. | ||
9 | */ | ||
10 | |||
11 | #include <asm/uaccess.h> | ||
12 | |||
13 | /* Asm:s have been tweaked (within the domain of correctness) to give | ||
14 | satisfactory results for "gcc version 2.96 20000427 (experimental)". | ||
15 | |||
16 | Check regularly... | ||
17 | |||
18 | Note that the PC saved at a bus-fault is the address *after* the | ||
19 | faulting instruction, which means the branch-target for instructions in | ||
20 | delay-slots for taken branches. Note also that the postincrement in | ||
21 | the instruction is performed regardless of bus-fault; the register is | ||
22 | seen updated in fault handlers. | ||
23 | |||
24 | Oh, and on the code formatting issue, to whomever feels like "fixing | ||
25 | it" to Conformity: I'm too "lazy", but why don't you go ahead and "fix" | ||
26 | string.c too. I just don't think too many people will hack this file | ||
27 | for the code format to be an issue. */ | ||
28 | |||
29 | |||
30 | /* Copy to userspace. This is based on the memcpy used for | ||
31 | kernel-to-kernel copying; see "string.c". */ | ||
32 | |||
33 | unsigned long | ||
34 | __copy_user (void __user *pdst, const void *psrc, unsigned long pn) | ||
35 | { | ||
36 | /* We want the parameters put in special registers. | ||
37 | Make sure the compiler is able to make something useful of this. | ||
38 | As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). | ||
39 | |||
40 | FIXME: Comment for old gcc version. Check. | ||
41 | If gcc was allright, it really would need no temporaries, and no | ||
42 | stack space to save stuff on. */ | ||
43 | |||
44 | register char *dst __asm__ ("r13") = pdst; | ||
45 | register const char *src __asm__ ("r11") = psrc; | ||
46 | register int n __asm__ ("r12") = pn; | ||
47 | register int retn __asm__ ("r10") = 0; | ||
48 | |||
49 | |||
50 | /* When src is aligned but not dst, this makes a few extra needless | ||
51 | cycles. I believe it would take as many to check that the | ||
52 | re-alignment was unnecessary. */ | ||
53 | if (((unsigned long) dst & 3) != 0 | ||
54 | /* Don't align if we wouldn't copy more than a few bytes; so we | ||
55 | don't have to check further for overflows. */ | ||
56 | && n >= 3) | ||
57 | { | ||
58 | if ((unsigned long) dst & 1) | ||
59 | { | ||
60 | __asm_copy_to_user_1 (dst, src, retn); | ||
61 | n--; | ||
62 | } | ||
63 | |||
64 | if ((unsigned long) dst & 2) | ||
65 | { | ||
66 | __asm_copy_to_user_2 (dst, src, retn); | ||
67 | n -= 2; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | /* Decide which copying method to use. */ | ||
72 | if (n >= 44*2) /* Break even between movem and | ||
73 | move16 is at 38.7*2, but modulo 44. */ | ||
74 | { | ||
75 | /* For large copies we use 'movem'. */ | ||
76 | |||
77 | /* It is not optimal to tell the compiler about clobbering any | ||
78 | registers; that will move the saving/restoring of those registers | ||
79 | to the function prologue/epilogue, and make non-movem sizes | ||
80 | suboptimal. | ||
81 | |||
82 | This method is not foolproof; it assumes that the "asm reg" | ||
83 | declarations at the beginning of the function really are used | ||
84 | here (beware: they may be moved to temporary registers). | ||
85 | This way, we do not have to save/move the registers around into | ||
86 | temporaries; we can safely use them straight away. | ||
87 | |||
88 | If you want to check that the allocation was right; then | ||
89 | check the equalities in the first comment. It should say | ||
90 | "r13=r13, r11=r11, r12=r12". */ | ||
91 | __asm__ volatile ("\ | ||
92 | .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ | ||
93 | .err \n\ | ||
94 | .endif \n\ | ||
95 | |||
96 | ;; Save the registers we'll use in the movem process | ||
97 | ;; on the stack. | ||
98 | subq 11*4,$sp | ||
99 | movem $r10,[$sp] | ||
100 | |||
101 | ;; Now we've got this: | ||
102 | ;; r11 - src | ||
103 | ;; r13 - dst | ||
104 | ;; r12 - n | ||
105 | |||
106 | ;; Update n for the first loop | ||
107 | subq 44,$r12 | ||
108 | |||
109 | ; Since the noted PC of a faulting instruction in a delay-slot of a taken | ||
110 | ; branch, is that of the branch target, we actually point at the from-movem | ||
111 | ; for this case. There is no ambiguity here; if there was a fault in that | ||
112 | ; instruction (meaning a kernel oops), the faulted PC would be the address | ||
113 | ; after *that* movem. | ||
114 | |||
115 | 0: | ||
116 | movem [$r11+],$r10 | ||
117 | subq 44,$r12 | ||
118 | bge 0b | ||
119 | movem $r10,[$r13+] | ||
120 | 1: | ||
121 | addq 44,$r12 ;; compensate for last loop underflowing n | ||
122 | |||
123 | ;; Restore registers from stack | ||
124 | movem [$sp+],$r10 | ||
125 | 2: | ||
126 | .section .fixup,\"ax\" | ||
127 | |||
128 | ; To provide a correct count in r10 of bytes that failed to be copied, | ||
129 | ; we jump back into the loop if the loop-branch was taken. There is no | ||
130 | ; performance penalty for sany use; the program will segfault soon enough. | ||
131 | |||
132 | 3: | ||
133 | move.d [$sp],$r10 | ||
134 | addq 44,$r10 | ||
135 | move.d $r10,[$sp] | ||
136 | jump 0b | ||
137 | 4: | ||
138 | movem [$sp+],$r10 | ||
139 | addq 44,$r10 | ||
140 | addq 44,$r12 | ||
141 | jump 2b | ||
142 | |||
143 | .previous | ||
144 | .section __ex_table,\"a\" | ||
145 | .dword 0b,3b | ||
146 | .dword 1b,4b | ||
147 | .previous" | ||
148 | |||
149 | /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) | ||
150 | /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); | ||
151 | |||
152 | } | ||
153 | |||
154 | /* Either we directly start copying, using dword copying in a loop, or | ||
155 | we copy as much as possible with 'movem' and then the last block (<44 | ||
156 | bytes) is copied here. This will work since 'movem' will have | ||
157 | updated SRC, DST and N. */ | ||
158 | |||
159 | while (n >= 16) | ||
160 | { | ||
161 | __asm_copy_to_user_16 (dst, src, retn); | ||
162 | n -= 16; | ||
163 | } | ||
164 | |||
165 | /* Having a separate by-four loops cuts down on cache footprint. | ||
166 | FIXME: Test with and without; increasing switch to be 0..15. */ | ||
167 | while (n >= 4) | ||
168 | { | ||
169 | __asm_copy_to_user_4 (dst, src, retn); | ||
170 | n -= 4; | ||
171 | } | ||
172 | |||
173 | switch (n) | ||
174 | { | ||
175 | case 0: | ||
176 | break; | ||
177 | case 1: | ||
178 | __asm_copy_to_user_1 (dst, src, retn); | ||
179 | break; | ||
180 | case 2: | ||
181 | __asm_copy_to_user_2 (dst, src, retn); | ||
182 | break; | ||
183 | case 3: | ||
184 | __asm_copy_to_user_3 (dst, src, retn); | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | return retn; | ||
189 | } | ||
190 | |||
191 | /* Copy from user to kernel, zeroing the bytes that were inaccessible in | ||
192 | userland. The return-value is the number of bytes that were | ||
193 | inaccessible. */ | ||
194 | |||
195 | unsigned long | ||
196 | __copy_user_zeroing (void __user *pdst, const void *psrc, unsigned long pn) | ||
197 | { | ||
198 | /* We want the parameters put in special registers. | ||
199 | Make sure the compiler is able to make something useful of this. | ||
200 | As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). | ||
201 | |||
202 | FIXME: Comment for old gcc version. Check. | ||
203 | If gcc was allright, it really would need no temporaries, and no | ||
204 | stack space to save stuff on. */ | ||
205 | |||
206 | register char *dst __asm__ ("r13") = pdst; | ||
207 | register const char *src __asm__ ("r11") = psrc; | ||
208 | register int n __asm__ ("r12") = pn; | ||
209 | register int retn __asm__ ("r10") = 0; | ||
210 | |||
211 | /* The best reason to align src is that we then know that a read-fault | ||
212 | was for aligned bytes; there's no 1..3 remaining good bytes to | ||
213 | pickle. */ | ||
214 | if (((unsigned long) src & 3) != 0) | ||
215 | { | ||
216 | if (((unsigned long) src & 1) && n != 0) | ||
217 | { | ||
218 | __asm_copy_from_user_1 (dst, src, retn); | ||
219 | n--; | ||
220 | } | ||
221 | |||
222 | if (((unsigned long) src & 2) && n >= 2) | ||
223 | { | ||
224 | __asm_copy_from_user_2 (dst, src, retn); | ||
225 | n -= 2; | ||
226 | } | ||
227 | |||
228 | /* We only need one check after the unalignment-adjustments, because | ||
229 | if both adjustments were done, either both or neither reference | ||
230 | had an exception. */ | ||
231 | if (retn != 0) | ||
232 | goto copy_exception_bytes; | ||
233 | } | ||
234 | |||
235 | /* Decide which copying method to use. */ | ||
236 | if (n >= 44*2) /* Break even between movem and | ||
237 | move16 is at 38.7*2, but modulo 44. | ||
238 | FIXME: We use move4 now. */ | ||
239 | { | ||
240 | /* For large copies we use 'movem' */ | ||
241 | |||
242 | /* It is not optimal to tell the compiler about clobbering any | ||
243 | registers; that will move the saving/restoring of those registers | ||
244 | to the function prologue/epilogue, and make non-movem sizes | ||
245 | suboptimal. | ||
246 | |||
247 | This method is not foolproof; it assumes that the "asm reg" | ||
248 | declarations at the beginning of the function really are used | ||
249 | here (beware: they may be moved to temporary registers). | ||
250 | This way, we do not have to save/move the registers around into | ||
251 | temporaries; we can safely use them straight away. | ||
252 | |||
253 | If you want to check that the allocation was right; then | ||
254 | check the equalities in the first comment. It should say | ||
255 | "r13=r13, r11=r11, r12=r12" */ | ||
256 | __asm__ volatile (" | ||
257 | .ifnc %0%1%2%3,$r13$r11$r12$r10 \n\ | ||
258 | .err \n\ | ||
259 | .endif \n\ | ||
260 | |||
261 | ;; Save the registers we'll use in the movem process | ||
262 | ;; on the stack. | ||
263 | subq 11*4,$sp | ||
264 | movem $r10,[$sp] | ||
265 | |||
266 | ;; Now we've got this: | ||
267 | ;; r11 - src | ||
268 | ;; r13 - dst | ||
269 | ;; r12 - n | ||
270 | |||
271 | ;; Update n for the first loop | ||
272 | subq 44,$r12 | ||
273 | 0: | ||
274 | movem [$r11+],$r10 | ||
275 | 1: | ||
276 | subq 44,$r12 | ||
277 | bge 0b | ||
278 | movem $r10,[$r13+] | ||
279 | |||
280 | addq 44,$r12 ;; compensate for last loop underflowing n | ||
281 | |||
282 | ;; Restore registers from stack | ||
283 | movem [$sp+],$r10 | ||
284 | 4: | ||
285 | .section .fixup,\"ax\" | ||
286 | |||
287 | ;; Do not jump back into the loop if we fail. For some uses, we get a | ||
288 | ;; page fault somewhere on the line. Without checking for page limits, | ||
289 | ;; we don't know where, but we need to copy accurately and keep an | ||
290 | ;; accurate count; not just clear the whole line. To do that, we fall | ||
291 | ;; down in the code below, proceeding with smaller amounts. It should | ||
292 | ;; be kept in mind that we have to cater to code like what at one time | ||
293 | ;; was in fs/super.c: | ||
294 | ;; i = size - copy_from_user((void *)page, data, size); | ||
295 | ;; which would cause repeated faults while clearing the remainder of | ||
296 | ;; the SIZE bytes at PAGE after the first fault. | ||
297 | ;; A caveat here is that we must not fall through from a failing page | ||
298 | ;; to a valid page. | ||
299 | |||
300 | 3: | ||
301 | movem [$sp+],$r10 | ||
302 | addq 44,$r12 ;; Get back count before faulting point. | ||
303 | subq 44,$r11 ;; Get back pointer to faulting movem-line. | ||
304 | jump 4b ;; Fall through, pretending the fault didn't happen. | ||
305 | |||
306 | .previous | ||
307 | .section __ex_table,\"a\" | ||
308 | .dword 1b,3b | ||
309 | .previous" | ||
310 | |||
311 | /* Outputs */ : "=r" (dst), "=r" (src), "=r" (n), "=r" (retn) | ||
312 | /* Inputs */ : "0" (dst), "1" (src), "2" (n), "3" (retn)); | ||
313 | |||
314 | } | ||
315 | |||
316 | /* Either we directly start copying here, using dword copying in a loop, | ||
317 | or we copy as much as possible with 'movem' and then the last block | ||
318 | (<44 bytes) is copied here. This will work since 'movem' will have | ||
319 | updated src, dst and n. (Except with failing src.) | ||
320 | |||
321 | Since we want to keep src accurate, we can't use | ||
322 | __asm_copy_from_user_N with N != (1, 2, 4); it updates dst and | ||
323 | retn, but not src (by design; it's value is ignored elsewhere). */ | ||
324 | |||
325 | while (n >= 4) | ||
326 | { | ||
327 | __asm_copy_from_user_4 (dst, src, retn); | ||
328 | n -= 4; | ||
329 | |||
330 | if (retn) | ||
331 | goto copy_exception_bytes; | ||
332 | } | ||
333 | |||
334 | /* If we get here, there were no memory read faults. */ | ||
335 | switch (n) | ||
336 | { | ||
337 | /* These copies are at least "naturally aligned" (so we don't have | ||
338 | to check each byte), due to the src alignment code before the | ||
339 | movem loop. The *_3 case *will* get the correct count for retn. */ | ||
340 | case 0: | ||
341 | /* This case deliberately left in (if you have doubts check the | ||
342 | generated assembly code). */ | ||
343 | break; | ||
344 | case 1: | ||
345 | __asm_copy_from_user_1 (dst, src, retn); | ||
346 | break; | ||
347 | case 2: | ||
348 | __asm_copy_from_user_2 (dst, src, retn); | ||
349 | break; | ||
350 | case 3: | ||
351 | __asm_copy_from_user_3 (dst, src, retn); | ||
352 | break; | ||
353 | } | ||
354 | |||
355 | /* If we get here, retn correctly reflects the number of failing | ||
356 | bytes. */ | ||
357 | return retn; | ||
358 | |||
359 | copy_exception_bytes: | ||
360 | /* We already have "retn" bytes cleared, and need to clear the | ||
361 | remaining "n" bytes. A non-optimized simple byte-for-byte in-line | ||
362 | memset is preferred here, since this isn't speed-critical code and | ||
363 | we'd rather have this a leaf-function than calling memset. */ | ||
364 | { | ||
365 | char *endp; | ||
366 | for (endp = dst + n; dst < endp; dst++) | ||
367 | *dst = 0; | ||
368 | } | ||
369 | |||
370 | return retn + n; | ||
371 | } | ||
372 | |||
373 | /* Zero userspace. */ | ||
374 | |||
375 | unsigned long | ||
376 | __do_clear_user (void __user *pto, unsigned long pn) | ||
377 | { | ||
378 | /* We want the parameters put in special registers. | ||
379 | Make sure the compiler is able to make something useful of this. | ||
380 | As it is now: r10 -> r13; r11 -> r11 (nop); r12 -> r12 (nop). | ||
381 | |||
382 | FIXME: Comment for old gcc version. Check. | ||
383 | If gcc was allright, it really would need no temporaries, and no | ||
384 | stack space to save stuff on. */ | ||
385 | |||
386 | register char *dst __asm__ ("r13") = pto; | ||
387 | register int n __asm__ ("r12") = pn; | ||
388 | register int retn __asm__ ("r10") = 0; | ||
389 | |||
390 | |||
391 | if (((unsigned long) dst & 3) != 0 | ||
392 | /* Don't align if we wouldn't copy more than a few bytes. */ | ||
393 | && n >= 3) | ||
394 | { | ||
395 | if ((unsigned long) dst & 1) | ||
396 | { | ||
397 | __asm_clear_1 (dst, retn); | ||
398 | n--; | ||
399 | } | ||
400 | |||
401 | if ((unsigned long) dst & 2) | ||
402 | { | ||
403 | __asm_clear_2 (dst, retn); | ||
404 | n -= 2; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | /* Decide which copying method to use. | ||
409 | FIXME: This number is from the "ordinary" kernel memset. */ | ||
410 | if (n >= (1*48)) | ||
411 | { | ||
412 | /* For large clears we use 'movem' */ | ||
413 | |||
414 | /* It is not optimal to tell the compiler about clobbering any | ||
415 | call-saved registers; that will move the saving/restoring of | ||
416 | those registers to the function prologue/epilogue, and make | ||
417 | non-movem sizes suboptimal. | ||
418 | |||
419 | This method is not foolproof; it assumes that the "asm reg" | ||
420 | declarations at the beginning of the function really are used | ||
421 | here (beware: they may be moved to temporary registers). | ||
422 | This way, we do not have to save/move the registers around into | ||
423 | temporaries; we can safely use them straight away. | ||
424 | |||
425 | If you want to check that the allocation was right; then | ||
426 | check the equalities in the first comment. It should say | ||
427 | something like "r13=r13, r11=r11, r12=r12". */ | ||
428 | __asm__ volatile (" | ||
429 | .ifnc %0%1%2,$r13$r12$r10 \n\ | ||
430 | .err \n\ | ||
431 | .endif \n\ | ||
432 | |||
433 | ;; Save the registers we'll clobber in the movem process | ||
434 | ;; on the stack. Don't mention them to gcc, it will only be | ||
435 | ;; upset. | ||
436 | subq 11*4,$sp | ||
437 | movem $r10,[$sp] | ||
438 | |||
439 | clear.d $r0 | ||
440 | clear.d $r1 | ||
441 | clear.d $r2 | ||
442 | clear.d $r3 | ||
443 | clear.d $r4 | ||
444 | clear.d $r5 | ||
445 | clear.d $r6 | ||
446 | clear.d $r7 | ||
447 | clear.d $r8 | ||
448 | clear.d $r9 | ||
449 | clear.d $r10 | ||
450 | clear.d $r11 | ||
451 | |||
452 | ;; Now we've got this: | ||
453 | ;; r13 - dst | ||
454 | ;; r12 - n | ||
455 | |||
456 | ;; Update n for the first loop | ||
457 | subq 12*4,$r12 | ||
458 | 0: | ||
459 | subq 12*4,$r12 | ||
460 | bge 0b | ||
461 | movem $r11,[$r13+] | ||
462 | 1: | ||
463 | addq 12*4,$r12 ;; compensate for last loop underflowing n | ||
464 | |||
465 | ;; Restore registers from stack | ||
466 | movem [$sp+],$r10 | ||
467 | 2: | ||
468 | .section .fixup,\"ax\" | ||
469 | 3: | ||
470 | move.d [$sp],$r10 | ||
471 | addq 12*4,$r10 | ||
472 | move.d $r10,[$sp] | ||
473 | clear.d $r10 | ||
474 | jump 0b | ||
475 | |||
476 | 4: | ||
477 | movem [$sp+],$r10 | ||
478 | addq 12*4,$r10 | ||
479 | addq 12*4,$r12 | ||
480 | jump 2b | ||
481 | |||
482 | .previous | ||
483 | .section __ex_table,\"a\" | ||
484 | .dword 0b,3b | ||
485 | .dword 1b,4b | ||
486 | .previous" | ||
487 | |||
488 | /* Outputs */ : "=r" (dst), "=r" (n), "=r" (retn) | ||
489 | /* Inputs */ : "0" (dst), "1" (n), "2" (retn) | ||
490 | /* Clobber */ : "r11"); | ||
491 | } | ||
492 | |||
493 | while (n >= 16) | ||
494 | { | ||
495 | __asm_clear_16 (dst, retn); | ||
496 | n -= 16; | ||
497 | } | ||
498 | |||
499 | /* Having a separate by-four loops cuts down on cache footprint. | ||
500 | FIXME: Test with and without; increasing switch to be 0..15. */ | ||
501 | while (n >= 4) | ||
502 | { | ||
503 | __asm_clear_4 (dst, retn); | ||
504 | n -= 4; | ||
505 | } | ||
506 | |||
507 | switch (n) | ||
508 | { | ||
509 | case 0: | ||
510 | break; | ||
511 | case 1: | ||
512 | __asm_clear_1 (dst, retn); | ||
513 | break; | ||
514 | case 2: | ||
515 | __asm_clear_2 (dst, retn); | ||
516 | break; | ||
517 | case 3: | ||
518 | __asm_clear_3 (dst, retn); | ||
519 | break; | ||
520 | } | ||
521 | |||
522 | return retn; | ||
523 | } | ||
diff --git a/arch/cris/arch-v10/mm/Makefile b/arch/cris/arch-v10/mm/Makefile new file mode 100644 index 000000000000..588b4baee85e --- /dev/null +++ b/arch/cris/arch-v10/mm/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the linux cris-specific parts of the memory manager. | ||
3 | # | ||
4 | |||
5 | obj-y := fault.o init.o tlb.o | ||
6 | |||
diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c new file mode 100644 index 000000000000..6805cdb25a53 --- /dev/null +++ b/arch/cris/arch-v10/mm/fault.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/mm/fault.c | ||
3 | * | ||
4 | * Low level bus fault handler | ||
5 | * | ||
6 | * | ||
7 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
8 | * | ||
9 | * Authors: Bjorn Wesen | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/mm.h> | ||
14 | #include <asm/uaccess.h> | ||
15 | #include <asm/pgtable.h> | ||
16 | #include <asm/arch/svinto.h> | ||
17 | |||
18 | /* debug of low-level TLB reload */ | ||
19 | #undef DEBUG | ||
20 | |||
21 | #ifdef DEBUG | ||
22 | #define D(x) x | ||
23 | #else | ||
24 | #define D(x) | ||
25 | #endif | ||
26 | |||
27 | extern volatile pgd_t *current_pgd; | ||
28 | |||
29 | extern const struct exception_table_entry | ||
30 | *search_exception_tables(unsigned long addr); | ||
31 | |||
32 | asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs, | ||
33 | int protection, int writeaccess); | ||
34 | |||
35 | /* fast TLB-fill fault handler | ||
36 | * this is called from entry.S with interrupts disabled | ||
37 | */ | ||
38 | |||
39 | void | ||
40 | handle_mmu_bus_fault(struct pt_regs *regs) | ||
41 | { | ||
42 | int cause; | ||
43 | int select; | ||
44 | #ifdef DEBUG | ||
45 | int index; | ||
46 | int page_id; | ||
47 | int acc, inv; | ||
48 | #endif | ||
49 | pgd_t* pgd = (pgd_t*)current_pgd; | ||
50 | pmd_t *pmd; | ||
51 | pte_t pte; | ||
52 | int miss, we, writeac; | ||
53 | unsigned long address; | ||
54 | unsigned long flags; | ||
55 | |||
56 | cause = *R_MMU_CAUSE; | ||
57 | |||
58 | address = cause & PAGE_MASK; /* get faulting address */ | ||
59 | select = *R_TLB_SELECT; | ||
60 | |||
61 | #ifdef DEBUG | ||
62 | page_id = IO_EXTRACT(R_MMU_CAUSE, page_id, cause); | ||
63 | acc = IO_EXTRACT(R_MMU_CAUSE, acc_excp, cause); | ||
64 | inv = IO_EXTRACT(R_MMU_CAUSE, inv_excp, cause); | ||
65 | index = IO_EXTRACT(R_TLB_SELECT, index, select); | ||
66 | #endif | ||
67 | miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); | ||
68 | we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); | ||
69 | writeac = IO_EXTRACT(R_MMU_CAUSE, wr_rd, cause); | ||
70 | |||
71 | D(printk("bus_fault from IRP 0x%lx: addr 0x%lx, miss %d, inv %d, we %d, acc %d, dx %d pid %d\n", | ||
72 | regs->irp, address, miss, inv, we, acc, index, page_id)); | ||
73 | |||
74 | /* leave it to the MM system fault handler */ | ||
75 | if (miss) | ||
76 | do_page_fault(address, regs, 0, writeac); | ||
77 | else | ||
78 | do_page_fault(address, regs, 1, we); | ||
79 | |||
80 | /* Reload TLB with new entry to avoid an extra miss exception. | ||
81 | * do_page_fault may have flushed the TLB so we have to restore | ||
82 | * the MMU registers. | ||
83 | */ | ||
84 | local_save_flags(flags); | ||
85 | local_irq_disable(); | ||
86 | pmd = (pmd_t *)(pgd + pgd_index(address)); | ||
87 | if (pmd_none(*pmd)) | ||
88 | return; | ||
89 | pte = *pte_offset_kernel(pmd, address); | ||
90 | if (!pte_present(pte)) | ||
91 | return; | ||
92 | *R_TLB_SELECT = select; | ||
93 | *R_TLB_HI = cause; | ||
94 | *R_TLB_LO = pte_val(pte); | ||
95 | local_irq_restore(flags); | ||
96 | } | ||
97 | |||
98 | /* Called from arch/cris/mm/fault.c to find fixup code. */ | ||
99 | int | ||
100 | find_fixup_code(struct pt_regs *regs) | ||
101 | { | ||
102 | const struct exception_table_entry *fixup; | ||
103 | |||
104 | if ((fixup = search_exception_tables(regs->irp)) != 0) { | ||
105 | /* Adjust the instruction pointer in the stackframe. */ | ||
106 | regs->irp = fixup->fixup; | ||
107 | |||
108 | /* | ||
109 | * Don't return by restoring the CPU state, so switch | ||
110 | * frame-type. | ||
111 | */ | ||
112 | regs->frametype = CRIS_FRAME_NORMAL; | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | return 0; | ||
117 | } | ||
diff --git a/arch/cris/arch-v10/mm/init.c b/arch/cris/arch-v10/mm/init.c new file mode 100644 index 000000000000..a9f975a9cfb5 --- /dev/null +++ b/arch/cris/arch-v10/mm/init.c | |||
@@ -0,0 +1,264 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/arch-v10/mm/init.c | ||
3 | * | ||
4 | */ | ||
5 | #include <linux/config.h> | ||
6 | #include <linux/mmzone.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/bootmem.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <asm/pgtable.h> | ||
11 | #include <asm/page.h> | ||
12 | #include <asm/types.h> | ||
13 | #include <asm/mmu.h> | ||
14 | #include <asm/io.h> | ||
15 | #include <asm/mmu_context.h> | ||
16 | #include <asm/arch/svinto.h> | ||
17 | |||
18 | extern void tlb_init(void); | ||
19 | |||
20 | /* | ||
21 | * The kernel is already mapped with a kernel segment at kseg_c so | ||
22 | * we don't need to map it with a page table. However head.S also | ||
23 | * temporarily mapped it at kseg_4 so we should set up the ksegs again, | ||
24 | * clear the TLB and do some other paging setup stuff. | ||
25 | */ | ||
26 | |||
27 | void __init | ||
28 | paging_init(void) | ||
29 | { | ||
30 | int i; | ||
31 | unsigned long zones_size[MAX_NR_ZONES]; | ||
32 | |||
33 | printk("Setting up paging and the MMU.\n"); | ||
34 | |||
35 | /* clear out the init_mm.pgd that will contain the kernel's mappings */ | ||
36 | |||
37 | for(i = 0; i < PTRS_PER_PGD; i++) | ||
38 | swapper_pg_dir[i] = __pgd(0); | ||
39 | |||
40 | /* make sure the current pgd table points to something sane | ||
41 | * (even if it is most probably not used until the next | ||
42 | * switch_mm) | ||
43 | */ | ||
44 | |||
45 | current_pgd = init_mm.pgd; | ||
46 | |||
47 | /* initialise the TLB (tlb.c) */ | ||
48 | |||
49 | tlb_init(); | ||
50 | |||
51 | /* see README.mm for details on the KSEG setup */ | ||
52 | |||
53 | #ifdef CONFIG_CRIS_LOW_MAP | ||
54 | /* Etrax-100 LX version 1 has a bug so that we cannot map anything | ||
55 | * across the 0x80000000 boundary, so we need to shrink the user-virtual | ||
56 | * area to 0x50000000 instead of 0xb0000000 and map things slightly | ||
57 | * different. The unused areas are marked as paged so that we can catch | ||
58 | * freak kernel accesses there. | ||
59 | * | ||
60 | * The ARTPEC chip is mapped at 0xa so we pass that segment straight | ||
61 | * through. We cannot vremap it because the vmalloc area is below 0x8 | ||
62 | * and Juliette needs an uncached area above 0x8. | ||
63 | * | ||
64 | * Same thing with 0xc and 0x9, which is memory-mapped I/O on some boards. | ||
65 | * We map them straight over in LOW_MAP, but use vremap in LX version 2. | ||
66 | */ | ||
67 | |||
68 | #define CACHED_BOOTROM (KSEG_F | 0x08000000UL) | ||
69 | |||
70 | *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* bootrom */ | ||
71 | IO_STATE(R_MMU_KSEG, seg_e, page ) | | ||
72 | IO_STATE(R_MMU_KSEG, seg_d, page ) | | ||
73 | IO_STATE(R_MMU_KSEG, seg_c, page ) | | ||
74 | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ | ||
75 | #ifdef CONFIG_JULIETTE | ||
76 | IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* ARTPEC etc. */ | ||
77 | #else | ||
78 | IO_STATE(R_MMU_KSEG, seg_a, page ) | | ||
79 | #endif | ||
80 | IO_STATE(R_MMU_KSEG, seg_9, seg ) | /* LED's on some boards */ | ||
81 | IO_STATE(R_MMU_KSEG, seg_8, seg ) | /* CSE0/1, flash and I/O */ | ||
82 | IO_STATE(R_MMU_KSEG, seg_7, page ) | /* kernel vmalloc area */ | ||
83 | IO_STATE(R_MMU_KSEG, seg_6, seg ) | /* kernel DRAM area */ | ||
84 | IO_STATE(R_MMU_KSEG, seg_5, seg ) | /* cached flash */ | ||
85 | IO_STATE(R_MMU_KSEG, seg_4, page ) | /* user area */ | ||
86 | IO_STATE(R_MMU_KSEG, seg_3, page ) | /* user area */ | ||
87 | IO_STATE(R_MMU_KSEG, seg_2, page ) | /* user area */ | ||
88 | IO_STATE(R_MMU_KSEG, seg_1, page ) | /* user area */ | ||
89 | IO_STATE(R_MMU_KSEG, seg_0, page ) ); /* user area */ | ||
90 | |||
91 | *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x3 ) | | ||
92 | IO_FIELD(R_MMU_KBASE_HI, base_e, 0x0 ) | | ||
93 | IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | | ||
94 | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x0 ) | | ||
95 | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | | ||
96 | #ifdef CONFIG_JULIETTE | ||
97 | IO_FIELD(R_MMU_KBASE_HI, base_a, 0xa ) | | ||
98 | #else | ||
99 | IO_FIELD(R_MMU_KBASE_HI, base_a, 0x0 ) | | ||
100 | #endif | ||
101 | IO_FIELD(R_MMU_KBASE_HI, base_9, 0x9 ) | | ||
102 | IO_FIELD(R_MMU_KBASE_HI, base_8, 0x8 ) ); | ||
103 | |||
104 | *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | | ||
105 | IO_FIELD(R_MMU_KBASE_LO, base_6, 0x4 ) | | ||
106 | IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | | ||
107 | IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | | ||
108 | IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | | ||
109 | IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | | ||
110 | IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | | ||
111 | IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); | ||
112 | #else | ||
113 | /* This code is for the corrected Etrax-100 LX version 2... */ | ||
114 | |||
115 | #define CACHED_BOOTROM (KSEG_A | 0x08000000UL) | ||
116 | |||
117 | *R_MMU_KSEG = ( IO_STATE(R_MMU_KSEG, seg_f, seg ) | /* cached flash */ | ||
118 | IO_STATE(R_MMU_KSEG, seg_e, seg ) | /* uncached flash */ | ||
119 | IO_STATE(R_MMU_KSEG, seg_d, page ) | /* vmalloc area */ | ||
120 | IO_STATE(R_MMU_KSEG, seg_c, seg ) | /* kernel area */ | ||
121 | IO_STATE(R_MMU_KSEG, seg_b, seg ) | /* kernel reg area */ | ||
122 | IO_STATE(R_MMU_KSEG, seg_a, seg ) | /* bootrom */ | ||
123 | IO_STATE(R_MMU_KSEG, seg_9, page ) | /* user area */ | ||
124 | IO_STATE(R_MMU_KSEG, seg_8, page ) | | ||
125 | IO_STATE(R_MMU_KSEG, seg_7, page ) | | ||
126 | IO_STATE(R_MMU_KSEG, seg_6, page ) | | ||
127 | IO_STATE(R_MMU_KSEG, seg_5, page ) | | ||
128 | IO_STATE(R_MMU_KSEG, seg_4, page ) | | ||
129 | IO_STATE(R_MMU_KSEG, seg_3, page ) | | ||
130 | IO_STATE(R_MMU_KSEG, seg_2, page ) | | ||
131 | IO_STATE(R_MMU_KSEG, seg_1, page ) | | ||
132 | IO_STATE(R_MMU_KSEG, seg_0, page ) ); | ||
133 | |||
134 | *R_MMU_KBASE_HI = ( IO_FIELD(R_MMU_KBASE_HI, base_f, 0x0 ) | | ||
135 | IO_FIELD(R_MMU_KBASE_HI, base_e, 0x8 ) | | ||
136 | IO_FIELD(R_MMU_KBASE_HI, base_d, 0x0 ) | | ||
137 | IO_FIELD(R_MMU_KBASE_HI, base_c, 0x4 ) | | ||
138 | IO_FIELD(R_MMU_KBASE_HI, base_b, 0xb ) | | ||
139 | IO_FIELD(R_MMU_KBASE_HI, base_a, 0x3 ) | | ||
140 | IO_FIELD(R_MMU_KBASE_HI, base_9, 0x0 ) | | ||
141 | IO_FIELD(R_MMU_KBASE_HI, base_8, 0x0 ) ); | ||
142 | |||
143 | *R_MMU_KBASE_LO = ( IO_FIELD(R_MMU_KBASE_LO, base_7, 0x0 ) | | ||
144 | IO_FIELD(R_MMU_KBASE_LO, base_6, 0x0 ) | | ||
145 | IO_FIELD(R_MMU_KBASE_LO, base_5, 0x0 ) | | ||
146 | IO_FIELD(R_MMU_KBASE_LO, base_4, 0x0 ) | | ||
147 | IO_FIELD(R_MMU_KBASE_LO, base_3, 0x0 ) | | ||
148 | IO_FIELD(R_MMU_KBASE_LO, base_2, 0x0 ) | | ||
149 | IO_FIELD(R_MMU_KBASE_LO, base_1, 0x0 ) | | ||
150 | IO_FIELD(R_MMU_KBASE_LO, base_0, 0x0 ) ); | ||
151 | #endif | ||
152 | |||
153 | *R_MMU_CONTEXT = ( IO_FIELD(R_MMU_CONTEXT, page_id, 0 ) ); | ||
154 | |||
155 | /* The MMU has been enabled ever since head.S but just to make | ||
156 | * it totally obvious we do it here as well. | ||
157 | */ | ||
158 | |||
159 | *R_MMU_CTRL = ( IO_STATE(R_MMU_CTRL, inv_excp, enable ) | | ||
160 | IO_STATE(R_MMU_CTRL, acc_excp, enable ) | | ||
161 | IO_STATE(R_MMU_CTRL, we_excp, enable ) ); | ||
162 | |||
163 | *R_MMU_ENABLE = IO_STATE(R_MMU_ENABLE, mmu_enable, enable); | ||
164 | |||
165 | /* | ||
166 | * initialize the bad page table and bad page to point | ||
167 | * to a couple of allocated pages | ||
168 | */ | ||
169 | |||
170 | empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE); | ||
171 | memset((void *)empty_zero_page, 0, PAGE_SIZE); | ||
172 | |||
173 | /* All pages are DMA'able in Etrax, so put all in the DMA'able zone */ | ||
174 | |||
175 | zones_size[0] = ((unsigned long)high_memory - PAGE_OFFSET) >> PAGE_SHIFT; | ||
176 | |||
177 | for (i = 1; i < MAX_NR_ZONES; i++) | ||
178 | zones_size[i] = 0; | ||
179 | |||
180 | /* Use free_area_init_node instead of free_area_init, because the former | ||
181 | * is designed for systems where the DRAM starts at an address substantially | ||
182 | * higher than 0, like us (we start at PAGE_OFFSET). This saves space in the | ||
183 | * mem_map page array. | ||
184 | */ | ||
185 | |||
186 | free_area_init_node(0, &contig_page_data, zones_size, PAGE_OFFSET >> PAGE_SHIFT, 0); | ||
187 | } | ||
188 | |||
189 | /* Initialize remaps of some I/O-ports. It is important that this | ||
190 | * is called before any driver is initialized. | ||
191 | */ | ||
192 | |||
193 | static int | ||
194 | __init init_ioremap(void) | ||
195 | { | ||
196 | |||
197 | /* Give the external I/O-port addresses their values */ | ||
198 | |||
199 | #ifdef CONFIG_CRIS_LOW_MAP | ||
200 | /* Simply a linear map (see the KSEG map above in paging_init) */ | ||
201 | port_cse1_addr = (volatile unsigned long *)(MEM_CSE1_START | | ||
202 | MEM_NON_CACHEABLE); | ||
203 | port_csp0_addr = (volatile unsigned long *)(MEM_CSP0_START | | ||
204 | MEM_NON_CACHEABLE); | ||
205 | port_csp4_addr = (volatile unsigned long *)(MEM_CSP4_START | | ||
206 | MEM_NON_CACHEABLE); | ||
207 | #else | ||
208 | /* Note that nothing blows up just because we do this remapping | ||
209 | * it's ok even if the ports are not used or connected | ||
210 | * to anything (or connected to a non-I/O thing) */ | ||
211 | port_cse1_addr = (volatile unsigned long *) | ||
212 | ioremap((unsigned long)(MEM_CSE1_START | MEM_NON_CACHEABLE), 16); | ||
213 | port_csp0_addr = (volatile unsigned long *) | ||
214 | ioremap((unsigned long)(MEM_CSP0_START | MEM_NON_CACHEABLE), 16); | ||
215 | port_csp4_addr = (volatile unsigned long *) | ||
216 | ioremap((unsigned long)(MEM_CSP4_START | MEM_NON_CACHEABLE), 16); | ||
217 | #endif | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | __initcall(init_ioremap); | ||
222 | |||
223 | /* Helper function for the two below */ | ||
224 | |||
225 | static inline void | ||
226 | flush_etrax_cacherange(void *startadr, int length) | ||
227 | { | ||
228 | /* CACHED_BOOTROM is mapped to the boot-rom area (cached) which | ||
229 | * we can use to get fast dummy-reads of cachelines | ||
230 | */ | ||
231 | |||
232 | volatile short *flushadr = (volatile short *)(((unsigned long)startadr & ~PAGE_MASK) | | ||
233 | CACHED_BOOTROM); | ||
234 | |||
235 | length = length > 8192 ? 8192 : length; /* No need to flush more than cache size */ | ||
236 | |||
237 | while(length > 0) { | ||
238 | *flushadr; /* dummy read to flush */ | ||
239 | flushadr += (32/sizeof(short)); /* a cacheline is 32 bytes */ | ||
240 | length -= 32; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* Due to a bug in Etrax100(LX) all versions, receiving DMA buffers | ||
245 | * will occationally corrupt certain CPU writes if the DMA buffers | ||
246 | * happen to be hot in the cache. | ||
247 | * | ||
248 | * As a workaround, we have to flush the relevant parts of the cache | ||
249 | * before (re) inserting any receiving descriptor into the DMA HW. | ||
250 | */ | ||
251 | |||
252 | void | ||
253 | prepare_rx_descriptor(struct etrax_dma_descr *desc) | ||
254 | { | ||
255 | flush_etrax_cacherange((void *)desc->buf, desc->sw_len ? desc->sw_len : 65536); | ||
256 | } | ||
257 | |||
258 | /* Do the same thing but flush the entire cache */ | ||
259 | |||
260 | void | ||
261 | flush_etrax_cache(void) | ||
262 | { | ||
263 | flush_etrax_cacherange(0, 8192); | ||
264 | } | ||
diff --git a/arch/cris/arch-v10/mm/tlb.c b/arch/cris/arch-v10/mm/tlb.c new file mode 100644 index 000000000000..9d06125ff5a2 --- /dev/null +++ b/arch/cris/arch-v10/mm/tlb.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/arch-v10/mm/tlb.c | ||
3 | * | ||
4 | * Low level TLB handling | ||
5 | * | ||
6 | * | ||
7 | * Copyright (C) 2000-2002 Axis Communications AB | ||
8 | * | ||
9 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <asm/tlb.h> | ||
14 | #include <asm/mmu_context.h> | ||
15 | #include <asm/arch/svinto.h> | ||
16 | |||
17 | #define D(x) | ||
18 | |||
19 | /* The TLB can host up to 64 different mm contexts at the same time. | ||
20 | * The running context is R_MMU_CONTEXT, and each TLB entry contains a | ||
21 | * page_id that has to match to give a hit. In page_id_map, we keep track | ||
22 | * of which mm's we have assigned which page_id's, so that we know when | ||
23 | * to invalidate TLB entries. | ||
24 | * | ||
25 | * The last page_id is never running - it is used as an invalid page_id | ||
26 | * so we can make TLB entries that will never match. | ||
27 | * | ||
28 | * Notice that we need to make the flushes atomic, otherwise an interrupt | ||
29 | * handler that uses vmalloced memory might cause a TLB load in the middle | ||
30 | * of a flush causing. | ||
31 | */ | ||
32 | |||
33 | /* invalidate all TLB entries */ | ||
34 | |||
35 | void | ||
36 | flush_tlb_all(void) | ||
37 | { | ||
38 | int i; | ||
39 | unsigned long flags; | ||
40 | |||
41 | /* the vpn of i & 0xf is so we dont write similar TLB entries | ||
42 | * in the same 4-way entry group. details.. | ||
43 | */ | ||
44 | |||
45 | local_save_flags(flags); | ||
46 | local_irq_disable(); | ||
47 | for(i = 0; i < NUM_TLB_ENTRIES; i++) { | ||
48 | *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); | ||
49 | *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | | ||
50 | IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); | ||
51 | |||
52 | *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | | ||
53 | IO_STATE(R_TLB_LO, valid, no ) | | ||
54 | IO_STATE(R_TLB_LO, kernel,no ) | | ||
55 | IO_STATE(R_TLB_LO, we, no ) | | ||
56 | IO_FIELD(R_TLB_LO, pfn, 0 ) ); | ||
57 | } | ||
58 | local_irq_restore(flags); | ||
59 | D(printk("tlb: flushed all\n")); | ||
60 | } | ||
61 | |||
62 | /* invalidate the selected mm context only */ | ||
63 | |||
64 | void | ||
65 | flush_tlb_mm(struct mm_struct *mm) | ||
66 | { | ||
67 | int i; | ||
68 | int page_id = mm->context.page_id; | ||
69 | unsigned long flags; | ||
70 | |||
71 | D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); | ||
72 | |||
73 | if(page_id == NO_CONTEXT) | ||
74 | return; | ||
75 | |||
76 | /* mark the TLB entries that match the page_id as invalid. | ||
77 | * here we could also check the _PAGE_GLOBAL bit and NOT flush | ||
78 | * global pages. is it worth the extra I/O ? | ||
79 | */ | ||
80 | |||
81 | local_save_flags(flags); | ||
82 | local_irq_disable(); | ||
83 | for(i = 0; i < NUM_TLB_ENTRIES; i++) { | ||
84 | *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); | ||
85 | if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { | ||
86 | *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | | ||
87 | IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); | ||
88 | |||
89 | *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | | ||
90 | IO_STATE(R_TLB_LO, valid, no ) | | ||
91 | IO_STATE(R_TLB_LO, kernel,no ) | | ||
92 | IO_STATE(R_TLB_LO, we, no ) | | ||
93 | IO_FIELD(R_TLB_LO, pfn, 0 ) ); | ||
94 | } | ||
95 | } | ||
96 | local_irq_restore(flags); | ||
97 | } | ||
98 | |||
99 | /* invalidate a single page */ | ||
100 | |||
101 | void | ||
102 | flush_tlb_page(struct vm_area_struct *vma, | ||
103 | unsigned long addr) | ||
104 | { | ||
105 | struct mm_struct *mm = vma->vm_mm; | ||
106 | int page_id = mm->context.page_id; | ||
107 | int i; | ||
108 | unsigned long flags; | ||
109 | |||
110 | D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); | ||
111 | |||
112 | if(page_id == NO_CONTEXT) | ||
113 | return; | ||
114 | |||
115 | addr &= PAGE_MASK; /* perhaps not necessary */ | ||
116 | |||
117 | /* invalidate those TLB entries that match both the mm context | ||
118 | * and the virtual address requested | ||
119 | */ | ||
120 | |||
121 | local_save_flags(flags); | ||
122 | local_irq_disable(); | ||
123 | for(i = 0; i < NUM_TLB_ENTRIES; i++) { | ||
124 | unsigned long tlb_hi; | ||
125 | *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); | ||
126 | tlb_hi = *R_TLB_HI; | ||
127 | if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && | ||
128 | (tlb_hi & PAGE_MASK) == addr) { | ||
129 | *R_TLB_HI = IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | | ||
130 | addr; /* same addr as before works. */ | ||
131 | |||
132 | *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | | ||
133 | IO_STATE(R_TLB_LO, valid, no ) | | ||
134 | IO_STATE(R_TLB_LO, kernel,no ) | | ||
135 | IO_STATE(R_TLB_LO, we, no ) | | ||
136 | IO_FIELD(R_TLB_LO, pfn, 0 ) ); | ||
137 | } | ||
138 | } | ||
139 | local_irq_restore(flags); | ||
140 | } | ||
141 | |||
142 | /* invalidate a page range */ | ||
143 | |||
144 | void | ||
145 | flush_tlb_range(struct vm_area_struct *vma, | ||
146 | unsigned long start, | ||
147 | unsigned long end) | ||
148 | { | ||
149 | struct mm_struct *mm = vma->vm_mm; | ||
150 | int page_id = mm->context.page_id; | ||
151 | int i; | ||
152 | unsigned long flags; | ||
153 | |||
154 | D(printk("tlb: flush range %p<->%p in context %d (%p)\n", | ||
155 | start, end, page_id, mm)); | ||
156 | |||
157 | if(page_id == NO_CONTEXT) | ||
158 | return; | ||
159 | |||
160 | start &= PAGE_MASK; /* probably not necessary */ | ||
161 | end &= PAGE_MASK; /* dito */ | ||
162 | |||
163 | /* invalidate those TLB entries that match both the mm context | ||
164 | * and the virtual address range | ||
165 | */ | ||
166 | |||
167 | local_save_flags(flags); | ||
168 | local_irq_disable(); | ||
169 | for(i = 0; i < NUM_TLB_ENTRIES; i++) { | ||
170 | unsigned long tlb_hi, vpn; | ||
171 | *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); | ||
172 | tlb_hi = *R_TLB_HI; | ||
173 | vpn = tlb_hi & PAGE_MASK; | ||
174 | if (IO_EXTRACT(R_TLB_HI, page_id, tlb_hi) == page_id && | ||
175 | vpn >= start && vpn < end) { | ||
176 | *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | | ||
177 | IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); | ||
178 | |||
179 | *R_TLB_LO = ( IO_STATE(R_TLB_LO, global,no ) | | ||
180 | IO_STATE(R_TLB_LO, valid, no ) | | ||
181 | IO_STATE(R_TLB_LO, kernel,no ) | | ||
182 | IO_STATE(R_TLB_LO, we, no ) | | ||
183 | IO_FIELD(R_TLB_LO, pfn, 0 ) ); | ||
184 | } | ||
185 | } | ||
186 | local_irq_restore(flags); | ||
187 | } | ||
188 | |||
189 | /* dump the entire TLB for debug purposes */ | ||
190 | |||
191 | #if 0 | ||
192 | void | ||
193 | dump_tlb_all(void) | ||
194 | { | ||
195 | int i; | ||
196 | unsigned long flags; | ||
197 | |||
198 | printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); | ||
199 | |||
200 | local_save_flags(flags); | ||
201 | local_irq_disable(); | ||
202 | for(i = 0; i < NUM_TLB_ENTRIES; i++) { | ||
203 | *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); | ||
204 | printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", | ||
205 | i, *R_TLB_HI, *R_TLB_LO); | ||
206 | } | ||
207 | local_irq_restore(flags); | ||
208 | } | ||
209 | #endif | ||
210 | |||
211 | /* | ||
212 | * Initialize the context related info for a new mm_struct | ||
213 | * instance. | ||
214 | */ | ||
215 | |||
216 | int | ||
217 | init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
218 | { | ||
219 | mm->context.page_id = NO_CONTEXT; | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* called in schedule() just before actually doing the switch_to */ | ||
224 | |||
225 | void | ||
226 | switch_mm(struct mm_struct *prev, struct mm_struct *next, | ||
227 | struct task_struct *tsk) | ||
228 | { | ||
229 | /* make sure we have a context */ | ||
230 | |||
231 | get_mmu_context(next); | ||
232 | |||
233 | /* remember the pgd for the fault handlers | ||
234 | * this is similar to the pgd register in some other CPU's. | ||
235 | * we need our own copy of it because current and active_mm | ||
236 | * might be invalid at points where we still need to derefer | ||
237 | * the pgd. | ||
238 | */ | ||
239 | |||
240 | current_pgd = next->pgd; | ||
241 | |||
242 | /* switch context in the MMU */ | ||
243 | |||
244 | D(printk("switching mmu_context to %d (%p)\n", next->context, next)); | ||
245 | |||
246 | *R_MMU_CONTEXT = IO_FIELD(R_MMU_CONTEXT, page_id, next->context.page_id); | ||
247 | } | ||
248 | |||
diff --git a/arch/cris/arch-v10/output_arch.ld b/arch/cris/arch-v10/output_arch.ld new file mode 100644 index 000000000000..2f3288006991 --- /dev/null +++ b/arch/cris/arch-v10/output_arch.ld | |||
@@ -0,0 +1,2 @@ | |||
1 | /* At the time of this writing, there's no equivalent ld option. */ | ||
2 | OUTPUT_ARCH (cris) | ||
diff --git a/arch/cris/arch-v10/vmlinux.lds.S b/arch/cris/arch-v10/vmlinux.lds.S new file mode 100644 index 000000000000..71ba736be8f0 --- /dev/null +++ b/arch/cris/arch-v10/vmlinux.lds.S | |||
@@ -0,0 +1,120 @@ | |||
1 | /* ld script to make the Linux/CRIS kernel | ||
2 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
3 | * | ||
4 | * It is VERY DANGEROUS to fiddle around with the symbols in this | ||
5 | * script. It is for example quite vital that all generated sections | ||
6 | * that are used are actually named here, otherwise the linker will | ||
7 | * put them at the end, where the init stuff is which is FREED after | ||
8 | * the kernel has booted. | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <asm-generic/vmlinux.lds.h> | ||
13 | |||
14 | jiffies = jiffies_64; | ||
15 | SECTIONS | ||
16 | { | ||
17 | . = DRAM_VIRTUAL_BASE; | ||
18 | dram_start = .; | ||
19 | ibr_start = .; | ||
20 | . = . + 0x4000; /* see head.S and pages reserved at the start */ | ||
21 | |||
22 | _text = .; /* Text and read-only data */ | ||
23 | text_start = .; /* lots of aliases */ | ||
24 | _stext = .; | ||
25 | __stext = .; | ||
26 | .text : { | ||
27 | *(.text) | ||
28 | SCHED_TEXT | ||
29 | LOCK_TEXT | ||
30 | *(.fixup) | ||
31 | *(.text.__*) | ||
32 | } | ||
33 | |||
34 | _etext = . ; /* End of text section */ | ||
35 | __etext = .; | ||
36 | |||
37 | . = ALIGN(4); /* Exception table */ | ||
38 | __start___ex_table = .; | ||
39 | __ex_table : { *(__ex_table) } | ||
40 | __stop___ex_table = .; | ||
41 | |||
42 | RODATA | ||
43 | |||
44 | . = ALIGN (4); | ||
45 | ___data_start = . ; | ||
46 | __Sdata = . ; | ||
47 | .data : { /* Data */ | ||
48 | *(.data) | ||
49 | } | ||
50 | __edata = . ; /* End of data section */ | ||
51 | _edata = . ; | ||
52 | |||
53 | . = ALIGN(8192); /* init_task and stack, must be aligned */ | ||
54 | .data.init_task : { *(.data.init_task) } | ||
55 | |||
56 | . = ALIGN(8192); /* Init code and data */ | ||
57 | __init_begin = .; | ||
58 | .init.text : { | ||
59 | _sinittext = .; | ||
60 | *(.init.text) | ||
61 | _einittext = .; | ||
62 | } | ||
63 | .init.data : { *(.init.data) } | ||
64 | . = ALIGN(16); | ||
65 | __setup_start = .; | ||
66 | .init.setup : { *(.init.setup) } | ||
67 | __setup_end = .; | ||
68 | .initcall.init : { | ||
69 | __initcall_start = .; | ||
70 | *(.initcall1.init); | ||
71 | *(.initcall2.init); | ||
72 | *(.initcall3.init); | ||
73 | *(.initcall4.init); | ||
74 | *(.initcall5.init); | ||
75 | *(.initcall6.init); | ||
76 | *(.initcall7.init); | ||
77 | __initcall_end = .; | ||
78 | } | ||
79 | |||
80 | .con_initcall.init : { | ||
81 | __con_initcall_start = .; | ||
82 | *(.con_initcall.init) | ||
83 | __con_initcall_end = .; | ||
84 | } | ||
85 | SECURITY_INIT | ||
86 | |||
87 | .init.ramfs : { | ||
88 | __initramfs_start = .; | ||
89 | *(.init.ramfs) | ||
90 | __initramfs_end = .; | ||
91 | /* We fill to the next page, so we can discard all init | ||
92 | pages without needing to consider what payload might be | ||
93 | appended to the kernel image. */ | ||
94 | FILL (0); | ||
95 | . = ALIGN (8192); | ||
96 | } | ||
97 | |||
98 | __vmlinux_end = .; /* last address of the physical file */ | ||
99 | __init_end = .; | ||
100 | |||
101 | __data_end = . ; /* Move to _edata ? */ | ||
102 | __bss_start = .; /* BSS */ | ||
103 | .bss : { | ||
104 | *(COMMON) | ||
105 | *(.bss) | ||
106 | } | ||
107 | |||
108 | . = ALIGN (0x20); | ||
109 | _end = .; | ||
110 | __end = .; | ||
111 | |||
112 | /* Sections to be discarded */ | ||
113 | /DISCARD/ : { | ||
114 | *(.text.exit) | ||
115 | *(.data.exit) | ||
116 | *(.exitcall.exit) | ||
117 | } | ||
118 | |||
119 | dram_end = dram_start + CONFIG_ETRAX_DRAM_SIZE*1024*1024; | ||
120 | } | ||
diff --git a/arch/cris/defconfig b/arch/cris/defconfig new file mode 100644 index 000000000000..32c9c987dbaa --- /dev/null +++ b/arch/cris/defconfig | |||
@@ -0,0 +1,591 @@ | |||
1 | # | ||
2 | # Automatically generated make config: don't edit | ||
3 | # | ||
4 | CONFIG_MMU=y | ||
5 | CONFIG_UID16=y | ||
6 | CONFIG_RWSEM_GENERIC_SPINLOCK=y | ||
7 | |||
8 | # | ||
9 | # Code maturity level options | ||
10 | # | ||
11 | CONFIG_EXPERIMENTAL=y | ||
12 | CONFIG_CLEAN_COMPILE=y | ||
13 | CONFIG_STANDALONE=y | ||
14 | CONFIG_BROKEN_ON_SMP=y | ||
15 | |||
16 | # | ||
17 | # General setup | ||
18 | # | ||
19 | CONFIG_SWAP=y | ||
20 | # CONFIG_SYSVIPC is not set | ||
21 | # CONFIG_POSIX_MQUEUE is not set | ||
22 | # CONFIG_BSD_PROCESS_ACCT is not set | ||
23 | CONFIG_SYSCTL=y | ||
24 | # CONFIG_AUDIT is not set | ||
25 | CONFIG_LOG_BUF_SHIFT=14 | ||
26 | # CONFIG_HOTPLUG is not set | ||
27 | # CONFIG_IKCONFIG is not set | ||
28 | CONFIG_EMBEDDED=y | ||
29 | # CONFIG_KALLSYMS is not set | ||
30 | CONFIG_FUTEX=y | ||
31 | CONFIG_EPOLL=y | ||
32 | CONFIG_IOSCHED_NOOP=y | ||
33 | CONFIG_IOSCHED_AS=y | ||
34 | CONFIG_IOSCHED_DEADLINE=y | ||
35 | CONFIG_IOSCHED_CFQ=y | ||
36 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
37 | |||
38 | # | ||
39 | # Loadable module support | ||
40 | # | ||
41 | # CONFIG_MODULES is not set | ||
42 | |||
43 | # | ||
44 | # General setup | ||
45 | # | ||
46 | CONFIG_BINFMT_ELF=y | ||
47 | # CONFIG_BINFMT_MISC is not set | ||
48 | CONFIG_ETRAX_CMDLINE="root=/dev/mtdblock3 init=/linuxrc" | ||
49 | CONFIG_ETRAX_WATCHDOG=y | ||
50 | CONFIG_ETRAX_WATCHDOG_NICE_DOGGY=y | ||
51 | CONFIG_ETRAX_FAST_TIMER=y | ||
52 | # CONFIG_PREEMPT is not set | ||
53 | |||
54 | # | ||
55 | # Hardware setup | ||
56 | # | ||
57 | CONFIG_ETRAX100LX=y | ||
58 | # CONFIG_ETRAX100LX_V2 is not set | ||
59 | # CONFIG_SVINTO_SIM is not set | ||
60 | CONFIG_ETRAX_ARCH_V10=y | ||
61 | CONFIG_ETRAX_DRAM_SIZE=16 | ||
62 | CONFIG_ETRAX_FLASH_BUSWIDTH=2 | ||
63 | CONFIG_CRIS_LOW_MAP=y | ||
64 | CONFIG_ETRAX_DRAM_VIRTUAL_BASE=60000000 | ||
65 | CONFIG_ETRAX_PA_LEDS=y | ||
66 | # CONFIG_ETRAX_PB_LEDS is not set | ||
67 | # CONFIG_ETRAX_CSP0_LEDS is not set | ||
68 | # CONFIG_ETRAX_NO_LEDS is not set | ||
69 | CONFIG_ETRAX_LED1G=2 | ||
70 | CONFIG_ETRAX_LED1R=2 | ||
71 | CONFIG_ETRAX_LED2G=3 | ||
72 | CONFIG_ETRAX_LED2R=3 | ||
73 | CONFIG_ETRAX_LED3G=2 | ||
74 | CONFIG_ETRAX_LED3R=2 | ||
75 | CONFIG_ETRAX_DEBUG_PORT0=y | ||
76 | # CONFIG_ETRAX_DEBUG_PORT1 is not set | ||
77 | # CONFIG_ETRAX_DEBUG_PORT2 is not set | ||
78 | # CONFIG_ETRAX_DEBUG_PORT3 is not set | ||
79 | # CONFIG_ETRAX_DEBUG_PORT_NULL is not set | ||
80 | CONFIG_ETRAX_RESCUE_SER0=y | ||
81 | # CONFIG_ETRAX_RESCUE_SER1 is not set | ||
82 | # CONFIG_ETRAX_RESCUE_SER2 is not set | ||
83 | # CONFIG_ETRAX_RESCUE_SER3 is not set | ||
84 | CONFIG_ETRAX_DEF_R_WAITSTATES=0x95f8 | ||
85 | CONFIG_ETRAX_DEF_R_BUS_CONFIG=0x104 | ||
86 | CONFIG_ETRAX_SDRAM=y | ||
87 | CONFIG_ETRAX_DEF_R_SDRAM_CONFIG=0x00e03636 | ||
88 | CONFIG_ETRAX_DEF_R_SDRAM_TIMING=0x80008002 | ||
89 | CONFIG_ETRAX_DEF_R_PORT_PA_DIR=0x1d | ||
90 | CONFIG_ETRAX_DEF_R_PORT_PA_DATA=0xf0 | ||
91 | CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG=0x00 | ||
92 | CONFIG_ETRAX_DEF_R_PORT_PB_DIR=0x1e | ||
93 | CONFIG_ETRAX_DEF_R_PORT_PB_DATA=0xf3 | ||
94 | # CONFIG_ETRAX_SOFT_SHUTDOWN is not set | ||
95 | |||
96 | # | ||
97 | # Drivers for built-in interfaces | ||
98 | # | ||
99 | CONFIG_ETRAX_ETHERNET=y | ||
100 | CONFIG_NET_ETHERNET=y | ||
101 | # CONFIG_ETRAX_NETWORK_LED_ON_WHEN_LINK is not set | ||
102 | CONFIG_ETRAX_NETWORK_LED_ON_WHEN_ACTIVITY=y | ||
103 | CONFIG_ETRAX_SERIAL=y | ||
104 | CONFIG_ETRAX_SERIAL_FAST_TIMER=y | ||
105 | CONFIG_ETRAX_SERIAL_PORT0=y | ||
106 | # CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_OUT is not set | ||
107 | CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT=y | ||
108 | # CONFIG_CONFIG_ETRAX_SERIAL_PORT0_NO_DMA_IN is not set | ||
109 | CONFIG_CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN=y | ||
110 | CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_NONE=y | ||
111 | # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PA is not set | ||
112 | # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_ON_PB is not set | ||
113 | # CONFIG_ETRAX_SER0_DTR_RI_DSR_CD_MIXED is not set | ||
114 | CONFIG_ETRAX_SER0_DTR_ON_PA_BIT=-1 | ||
115 | CONFIG_ETRAX_SER0_RI_ON_PA_BIT=-1 | ||
116 | CONFIG_ETRAX_SER0_DSR_ON_PA_BIT=-1 | ||
117 | CONFIG_ETRAX_SER0_CD_ON_PA_BIT=-1 | ||
118 | CONFIG_ETRAX_SER0_DTR_ON_PB_BIT=-1 | ||
119 | CONFIG_ETRAX_SER0_RI_ON_PB_BIT=-1 | ||
120 | CONFIG_ETRAX_SER0_DSR_ON_PB_BIT=-1 | ||
121 | CONFIG_ETRAX_SER0_CD_ON_PB_BIT=-1 | ||
122 | # CONFIG_ETRAX_SERIAL_PORT1 is not set | ||
123 | CONFIG_ETRAX_SERIAL_PORT2=y | ||
124 | # CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_OUT is not set | ||
125 | CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT=y | ||
126 | # CONFIG_CONFIG_ETRAX_SERIAL_PORT2_NO_DMA_IN is not set | ||
127 | CONFIG_CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN=y | ||
128 | CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_NONE=y | ||
129 | # CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PA is not set | ||
130 | # CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_ON_PB is not set | ||
131 | # CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED is not set | ||
132 | CONFIG_ETRAX_SER2_DTR_ON_PA_BIT=-1 | ||
133 | CONFIG_ETRAX_SER2_RI_ON_PA_BIT=-1 | ||
134 | CONFIG_ETRAX_SER2_DSR_ON_PA_BIT=-1 | ||
135 | CONFIG_ETRAX_SER2_CD_ON_PA_BIT=-1 | ||
136 | CONFIG_ETRAX_SER2_DTR_ON_PB_BIT=-1 | ||
137 | CONFIG_ETRAX_SER2_RI_ON_PB_BIT=-1 | ||
138 | CONFIG_ETRAX_SER2_DSR_ON_PB_BIT=-1 | ||
139 | CONFIG_ETRAX_SER2_CD_ON_PB_BIT=-1 | ||
140 | # CONFIG_ETRAX_SERIAL_PORT3 is not set | ||
141 | # CONFIG_ETRAX_RS485 is not set | ||
142 | # CONFIG_ETRAX_IDE is not set | ||
143 | # CONFIG_IDE is not set | ||
144 | # CONFIG_ETRAX_USB_HOST is not set | ||
145 | CONFIG_ETRAX_AXISFLASHMAP=y | ||
146 | CONFIG_ETRAX_PTABLE_SECTOR=65536 | ||
147 | CONFIG_MTD=y | ||
148 | CONFIG_MTD_CFI=y | ||
149 | CONFIG_MTD_CFI_AMDSTD=y | ||
150 | CONFIG_MTD_OBSOLETE_CHIPS=y | ||
151 | CONFIG_MTD_AMDSTD=y | ||
152 | CONFIG_MTD_CHAR=y | ||
153 | CONFIG_MTD_BLOCK=y | ||
154 | CONFIG_MTD_PARTITIONS=y | ||
155 | CONFIG_MTD_CONCAT=y | ||
156 | # CONFIG_ETRAX_I2C is not set | ||
157 | CONFIG_ETRAX_GPIO=y | ||
158 | CONFIG_ETRAX_PA_BUTTON_BITMASK=0x02 | ||
159 | CONFIG_ETRAX_PA_CHANGEABLE_DIR=0x00 | ||
160 | CONFIG_ETRAX_PA_CHANGEABLE_BITS=0xFF | ||
161 | CONFIG_ETRAX_PB_CHANGEABLE_DIR=0x00 | ||
162 | CONFIG_ETRAX_PB_CHANGEABLE_BITS=0xFF | ||
163 | # CONFIG_ETRAX_RTC is not set | ||
164 | |||
165 | # | ||
166 | # Generic Driver Options | ||
167 | # | ||
168 | |||
169 | # | ||
170 | # Memory Technology Devices (MTD) | ||
171 | # | ||
172 | # CONFIG_MTD_DEBUG is not set | ||
173 | # CONFIG_MTD_REDBOOT_PARTS is not set | ||
174 | # CONFIG_MTD_CMDLINE_PARTS is not set | ||
175 | |||
176 | # | ||
177 | # User Modules And Translation Layers | ||
178 | # | ||
179 | # CONFIG_FTL is not set | ||
180 | # CONFIG_NFTL is not set | ||
181 | # CONFIG_INFTL is not set | ||
182 | |||
183 | # | ||
184 | # RAM/ROM/Flash chip drivers | ||
185 | # | ||
186 | # CONFIG_MTD_JEDECPROBE is not set | ||
187 | CONFIG_MTD_GEN_PROBE=y | ||
188 | # CONFIG_MTD_CFI_ADV_OPTIONS is not set | ||
189 | # CONFIG_MTD_CFI_INTELEXT is not set | ||
190 | # CONFIG_MTD_CFI_STAA is not set | ||
191 | CONFIG_MTD_RAM=y | ||
192 | # CONFIG_MTD_ROM is not set | ||
193 | # CONFIG_MTD_ABSENT is not set | ||
194 | # CONFIG_MTD_SHARP is not set | ||
195 | # CONFIG_MTD_JEDEC is not set | ||
196 | |||
197 | # | ||
198 | # Mapping drivers for chip access | ||
199 | # | ||
200 | CONFIG_MTD_COMPLEX_MAPPINGS=y | ||
201 | # CONFIG_MTD_PHYSMAP is not set | ||
202 | |||
203 | # | ||
204 | # Self-contained MTD device drivers | ||
205 | # | ||
206 | # CONFIG_MTD_SLRAM is not set | ||
207 | CONFIG_MTD_MTDRAM=y | ||
208 | CONFIG_MTDRAM_TOTAL_SIZE=0 | ||
209 | CONFIG_MTDRAM_ERASE_SIZE=64 | ||
210 | CONFIG_MTDRAM_ABS_POS=0x0 | ||
211 | # CONFIG_MTD_BLKMTD is not set | ||
212 | |||
213 | # | ||
214 | # Disk-On-Chip Device Drivers | ||
215 | # | ||
216 | # CONFIG_MTD_DOC2000 is not set | ||
217 | # CONFIG_MTD_DOC2001 is not set | ||
218 | # CONFIG_MTD_DOC2001PLUS is not set | ||
219 | |||
220 | # | ||
221 | # NAND Flash Device Drivers | ||
222 | # | ||
223 | # CONFIG_MTD_NAND is not set | ||
224 | |||
225 | # | ||
226 | # Parallel port support | ||
227 | # | ||
228 | # CONFIG_PARPORT is not set | ||
229 | |||
230 | # | ||
231 | # Plug and Play support | ||
232 | # | ||
233 | |||
234 | # | ||
235 | # Block devices | ||
236 | # | ||
237 | # CONFIG_BLK_DEV_FD is not set | ||
238 | # CONFIG_BLK_DEV_LOOP is not set | ||
239 | # CONFIG_BLK_DEV_NBD is not set | ||
240 | CONFIG_BLK_DEV_RAM=y | ||
241 | CONFIG_BLK_DEV_RAM_SIZE=4096 | ||
242 | # CONFIG_BLK_DEV_INITRD is not set | ||
243 | |||
244 | # | ||
245 | # Multi-device support (RAID and LVM) | ||
246 | # | ||
247 | # CONFIG_MD is not set | ||
248 | |||
249 | # | ||
250 | # ATA/ATAPI/MFM/RLL support | ||
251 | # | ||
252 | |||
253 | # | ||
254 | # SCSI device support | ||
255 | # | ||
256 | # CONFIG_SCSI is not set | ||
257 | |||
258 | # | ||
259 | # IEEE 1394 (FireWire) support | ||
260 | # | ||
261 | # CONFIG_IEEE1394 is not set | ||
262 | |||
263 | # | ||
264 | # I2O device support | ||
265 | # | ||
266 | |||
267 | # | ||
268 | # Networking support | ||
269 | # | ||
270 | CONFIG_NET=y | ||
271 | |||
272 | # | ||
273 | # Networking options | ||
274 | # | ||
275 | CONFIG_PACKET=y | ||
276 | # CONFIG_PACKET_MMAP is not set | ||
277 | # CONFIG_NETLINK_DEV is not set | ||
278 | CONFIG_UNIX=y | ||
279 | # CONFIG_NET_KEY is not set | ||
280 | CONFIG_INET=y | ||
281 | # CONFIG_IP_MULTICAST is not set | ||
282 | # CONFIG_IP_ADVANCED_ROUTER is not set | ||
283 | # CONFIG_IP_PNP is not set | ||
284 | # CONFIG_NET_IPIP is not set | ||
285 | # CONFIG_NET_IPGRE is not set | ||
286 | # CONFIG_ARPD is not set | ||
287 | # CONFIG_SYN_COOKIES is not set | ||
288 | # CONFIG_INET_AH is not set | ||
289 | # CONFIG_INET_ESP is not set | ||
290 | # CONFIG_INET_IPCOMP is not set | ||
291 | |||
292 | # | ||
293 | # IP: Virtual Server Configuration | ||
294 | # | ||
295 | # CONFIG_IP_VS is not set | ||
296 | # CONFIG_IPV6 is not set | ||
297 | CONFIG_NETFILTER=y | ||
298 | # CONFIG_NETFILTER_DEBUG is not set | ||
299 | |||
300 | # | ||
301 | # IP: Netfilter Configuration | ||
302 | # | ||
303 | # CONFIG_IP_NF_CONNTRACK is not set | ||
304 | # CONFIG_IP_NF_QUEUE is not set | ||
305 | # CONFIG_IP_NF_IPTABLES is not set | ||
306 | # CONFIG_IP_NF_ARPTABLES is not set | ||
307 | # CONFIG_IP_NF_COMPAT_IPCHAINS is not set | ||
308 | # CONFIG_IP_NF_COMPAT_IPFWADM is not set | ||
309 | |||
310 | # | ||
311 | # SCTP Configuration (EXPERIMENTAL) | ||
312 | # | ||
313 | # CONFIG_IP_SCTP is not set | ||
314 | # CONFIG_ATM is not set | ||
315 | # CONFIG_BRIDGE is not set | ||
316 | # CONFIG_VLAN_8021Q is not set | ||
317 | # CONFIG_DECNET is not set | ||
318 | # CONFIG_LLC2 is not set | ||
319 | # CONFIG_IPX is not set | ||
320 | # CONFIG_ATALK is not set | ||
321 | # CONFIG_X25 is not set | ||
322 | # CONFIG_LAPB is not set | ||
323 | # CONFIG_NET_DIVERT is not set | ||
324 | # CONFIG_ECONET is not set | ||
325 | # CONFIG_WAN_ROUTER is not set | ||
326 | # CONFIG_NET_HW_FLOWCONTROL is not set | ||
327 | |||
328 | # | ||
329 | # QoS and/or fair queueing | ||
330 | # | ||
331 | # CONFIG_NET_SCHED is not set | ||
332 | |||
333 | # | ||
334 | # Network testing | ||
335 | # | ||
336 | # CONFIG_NET_PKTGEN is not set | ||
337 | # CONFIG_NETPOLL is not set | ||
338 | # CONFIG_NET_POLL_CONTROLLER is not set | ||
339 | # CONFIG_HAMRADIO is not set | ||
340 | # CONFIG_IRDA is not set | ||
341 | # CONFIG_BT is not set | ||
342 | CONFIG_NETDEVICES=y | ||
343 | # CONFIG_DUMMY is not set | ||
344 | # CONFIG_BONDING is not set | ||
345 | # CONFIG_EQUALIZER is not set | ||
346 | # CONFIG_TUN is not set | ||
347 | |||
348 | # | ||
349 | # Ethernet (10 or 100Mbit) | ||
350 | # | ||
351 | # CONFIG_MII is not set | ||
352 | |||
353 | # | ||
354 | # Ethernet (1000 Mbit) | ||
355 | # | ||
356 | |||
357 | # | ||
358 | # Ethernet (10000 Mbit) | ||
359 | # | ||
360 | |||
361 | # | ||
362 | # Token Ring devices | ||
363 | # | ||
364 | |||
365 | # | ||
366 | # Wireless LAN (non-hamradio) | ||
367 | # | ||
368 | # CONFIG_NET_RADIO is not set | ||
369 | |||
370 | # | ||
371 | # Wan interfaces | ||
372 | # | ||
373 | # CONFIG_WAN is not set | ||
374 | # CONFIG_PPP is not set | ||
375 | # CONFIG_SLIP is not set | ||
376 | # CONFIG_SHAPER is not set | ||
377 | # CONFIG_NETCONSOLE is not set | ||
378 | |||
379 | # | ||
380 | # ISDN subsystem | ||
381 | # | ||
382 | # CONFIG_ISDN is not set | ||
383 | |||
384 | # | ||
385 | # Telephony Support | ||
386 | # | ||
387 | # CONFIG_PHONE is not set | ||
388 | |||
389 | # | ||
390 | # Input device support | ||
391 | # | ||
392 | # CONFIG_INPUT is not set | ||
393 | |||
394 | # | ||
395 | # Userland interfaces | ||
396 | # | ||
397 | |||
398 | # | ||
399 | # Input I/O drivers | ||
400 | # | ||
401 | # CONFIG_GAMEPORT is not set | ||
402 | CONFIG_SOUND_GAMEPORT=y | ||
403 | CONFIG_SERIO=y | ||
404 | # CONFIG_SERIO_I8042 is not set | ||
405 | # CONFIG_SERIO_SERPORT is not set | ||
406 | # CONFIG_SERIO_CT82C710 is not set | ||
407 | |||
408 | # | ||
409 | # Input Device Drivers | ||
410 | # | ||
411 | |||
412 | # | ||
413 | # Character devices | ||
414 | # | ||
415 | # CONFIG_VT is not set | ||
416 | # CONFIG_SERIAL_NONSTANDARD is not set | ||
417 | |||
418 | # | ||
419 | # Serial drivers | ||
420 | # | ||
421 | # CONFIG_SERIAL_8250 is not set | ||
422 | |||
423 | # | ||
424 | # Non-8250 serial port support | ||
425 | # | ||
426 | CONFIG_UNIX98_PTYS=y | ||
427 | CONFIG_LEGACY_PTYS=y | ||
428 | CONFIG_LEGACY_PTY_COUNT=256 | ||
429 | # CONFIG_QIC02_TAPE is not set | ||
430 | |||
431 | # | ||
432 | # IPMI | ||
433 | # | ||
434 | # CONFIG_IPMI_HANDLER is not set | ||
435 | |||
436 | # | ||
437 | # Watchdog Cards | ||
438 | # | ||
439 | # CONFIG_WATCHDOG is not set | ||
440 | # CONFIG_RTC is not set | ||
441 | # CONFIG_GEN_RTC is not set | ||
442 | # CONFIG_DTLK is not set | ||
443 | # CONFIG_R3964 is not set | ||
444 | # CONFIG_APPLICOM is not set | ||
445 | |||
446 | # | ||
447 | # Ftape, the floppy tape device driver | ||
448 | # | ||
449 | # CONFIG_FTAPE is not set | ||
450 | # CONFIG_AGP is not set | ||
451 | # CONFIG_DRM is not set | ||
452 | # CONFIG_RAW_DRIVER is not set | ||
453 | |||
454 | # | ||
455 | # Multimedia devices | ||
456 | # | ||
457 | # CONFIG_VIDEO_DEV is not set | ||
458 | |||
459 | # | ||
460 | # Digital Video Broadcasting Devices | ||
461 | # | ||
462 | # CONFIG_DVB is not set | ||
463 | |||
464 | # | ||
465 | # File systems | ||
466 | # | ||
467 | # CONFIG_EXT2_FS is not set | ||
468 | # CONFIG_EXT3_FS is not set | ||
469 | # CONFIG_JBD is not set | ||
470 | # CONFIG_REISERFS_FS is not set | ||
471 | # CONFIG_JFS_FS is not set | ||
472 | # CONFIG_XFS_FS is not set | ||
473 | # CONFIG_MINIX_FS is not set | ||
474 | # CONFIG_ROMFS_FS is not set | ||
475 | # CONFIG_QUOTA is not set | ||
476 | # CONFIG_AUTOFS_FS is not set | ||
477 | # CONFIG_AUTOFS4_FS is not set | ||
478 | |||
479 | # | ||
480 | # CD-ROM/DVD Filesystems | ||
481 | # | ||
482 | # CONFIG_ISO9660_FS is not set | ||
483 | # CONFIG_UDF_FS is not set | ||
484 | |||
485 | # | ||
486 | # DOS/FAT/NT Filesystems | ||
487 | # | ||
488 | # CONFIG_FAT_FS is not set | ||
489 | # CONFIG_NTFS_FS is not set | ||
490 | |||
491 | # | ||
492 | # Pseudo filesystems | ||
493 | # | ||
494 | CONFIG_PROC_FS=y | ||
495 | CONFIG_PROC_KCORE=y | ||
496 | CONFIG_SYSFS=y | ||
497 | # CONFIG_DEVFS_FS is not set | ||
498 | # CONFIG_DEVPTS_FS_XATTR is not set | ||
499 | CONFIG_TMPFS=y | ||
500 | # CONFIG_HUGETLB_PAGE is not set | ||
501 | CONFIG_RAMFS=y | ||
502 | |||
503 | # | ||
504 | # Miscellaneous filesystems | ||
505 | # | ||
506 | # CONFIG_ADFS_FS is not set | ||
507 | # CONFIG_AFFS_FS is not set | ||
508 | # CONFIG_HFS_FS is not set | ||
509 | # CONFIG_HFSPLUS_FS is not set | ||
510 | # CONFIG_BEFS_FS is not set | ||
511 | # CONFIG_BFS_FS is not set | ||
512 | # CONFIG_EFS_FS is not set | ||
513 | CONFIG_JFFS_FS=y | ||
514 | CONFIG_JFFS_FS_VERBOSE=0 | ||
515 | # CONFIG_JFFS2_FS is not set | ||
516 | CONFIG_CRAMFS=y | ||
517 | # CONFIG_VXFS_FS is not set | ||
518 | # CONFIG_HPFS_FS is not set | ||
519 | # CONFIG_QNX4FS_FS is not set | ||
520 | # CONFIG_SYSV_FS is not set | ||
521 | # CONFIG_UFS_FS is not set | ||
522 | |||
523 | # | ||
524 | # Network File Systems | ||
525 | # | ||
526 | CONFIG_NFS_FS=y | ||
527 | CONFIG_NFS_V3=y | ||
528 | # CONFIG_NFS_V4 is not set | ||
529 | # CONFIG_NFS_DIRECTIO is not set | ||
530 | # CONFIG_NFSD is not set | ||
531 | CONFIG_LOCKD=y | ||
532 | CONFIG_LOCKD_V4=y | ||
533 | # CONFIG_EXPORTFS is not set | ||
534 | CONFIG_SUNRPC=y | ||
535 | # CONFIG_RPCSEC_GSS_KRB5 is not set | ||
536 | # CONFIG_SMB_FS is not set | ||
537 | # CONFIG_CIFS is not set | ||
538 | # CONFIG_NCP_FS is not set | ||
539 | # CONFIG_CODA_FS is not set | ||
540 | # CONFIG_INTERMEZZO_FS is not set | ||
541 | # CONFIG_AFS_FS is not set | ||
542 | |||
543 | # | ||
544 | # Partition Types | ||
545 | # | ||
546 | # CONFIG_PARTITION_ADVANCED is not set | ||
547 | CONFIG_MSDOS_PARTITION=y | ||
548 | |||
549 | # | ||
550 | # Native Language Support | ||
551 | # | ||
552 | # CONFIG_NLS is not set | ||
553 | |||
554 | # | ||
555 | # Sound | ||
556 | # | ||
557 | # CONFIG_SOUND is not set | ||
558 | |||
559 | # | ||
560 | # USB support | ||
561 | # | ||
562 | |||
563 | # | ||
564 | # USB Gadget Support | ||
565 | # | ||
566 | # CONFIG_USB_GADGET is not set | ||
567 | |||
568 | # | ||
569 | # Kernel hacking | ||
570 | # | ||
571 | # CONFIG_PROFILE is not set | ||
572 | # CONFIG_ETRAX_KGDB is not set | ||
573 | # CONFIG_DEBUG_INFO is not set | ||
574 | # CONFIG_FRAME_POINTER is not set | ||
575 | |||
576 | # | ||
577 | # Security options | ||
578 | # | ||
579 | # CONFIG_SECURITY is not set | ||
580 | |||
581 | # | ||
582 | # Cryptographic options | ||
583 | # | ||
584 | # CONFIG_CRYPTO is not set | ||
585 | |||
586 | # | ||
587 | # Library routines | ||
588 | # | ||
589 | # CONFIG_CRC32 is not set | ||
590 | # CONFIG_LIBCRC32C is not set | ||
591 | CONFIG_ZLIB_INFLATE=y | ||
diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile new file mode 100644 index 000000000000..1546a0e74047 --- /dev/null +++ b/arch/cris/kernel/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | # $Id: Makefile,v 1.10 2004/05/14 10:18:12 starvik Exp $ | ||
2 | # | ||
3 | # Makefile for the linux kernel. | ||
4 | # | ||
5 | |||
6 | extra-y := vmlinux.lds | ||
7 | |||
8 | obj-y := process.o traps.o irq.o ptrace.o setup.o \ | ||
9 | time.o sys_cris.o semaphore.o | ||
10 | |||
11 | obj-$(CONFIG_MODULES) += crisksyms.o | ||
12 | obj-$(CONFIG_MODULES) += module.o | ||
13 | |||
14 | clean: | ||
15 | |||
diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c new file mode 100644 index 000000000000..7141bbecd7e4 --- /dev/null +++ b/arch/cris/kernel/crisksyms.c | |||
@@ -0,0 +1,103 @@ | |||
1 | #include <linux/config.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/user.h> | ||
4 | #include <linux/elfcore.h> | ||
5 | #include <linux/sched.h> | ||
6 | #include <linux/in6.h> | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/smp_lock.h> | ||
9 | #include <linux/pm.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/string.h> | ||
12 | #include <linux/tty.h> | ||
13 | |||
14 | #include <asm/semaphore.h> | ||
15 | #include <asm/processor.h> | ||
16 | #include <asm/uaccess.h> | ||
17 | #include <asm/checksum.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <asm/delay.h> | ||
20 | #include <asm/irq.h> | ||
21 | #include <asm/pgtable.h> | ||
22 | #include <asm/fasttimer.h> | ||
23 | |||
24 | extern void dump_thread(struct pt_regs *, struct user *); | ||
25 | extern unsigned long get_cmos_time(void); | ||
26 | extern void __Udiv(void); | ||
27 | extern void __Umod(void); | ||
28 | extern void __Div(void); | ||
29 | extern void __Mod(void); | ||
30 | extern void __ashrdi3(void); | ||
31 | extern void iounmap(void *addr); | ||
32 | |||
33 | /* Platform dependent support */ | ||
34 | EXPORT_SYMBOL(dump_thread); | ||
35 | EXPORT_SYMBOL(enable_irq); | ||
36 | EXPORT_SYMBOL(disable_irq); | ||
37 | EXPORT_SYMBOL(kernel_thread); | ||
38 | EXPORT_SYMBOL(get_cmos_time); | ||
39 | EXPORT_SYMBOL(loops_per_usec); | ||
40 | |||
41 | /* String functions */ | ||
42 | EXPORT_SYMBOL(memcmp); | ||
43 | EXPORT_SYMBOL(memmove); | ||
44 | EXPORT_SYMBOL(strpbrk); | ||
45 | EXPORT_SYMBOL(strstr); | ||
46 | EXPORT_SYMBOL(strcpy); | ||
47 | EXPORT_SYMBOL(strchr); | ||
48 | EXPORT_SYMBOL(strcmp); | ||
49 | EXPORT_SYMBOL(strlen); | ||
50 | EXPORT_SYMBOL(strcat); | ||
51 | EXPORT_SYMBOL(strncat); | ||
52 | EXPORT_SYMBOL(strncmp); | ||
53 | EXPORT_SYMBOL(strncpy); | ||
54 | |||
55 | /* Math functions */ | ||
56 | EXPORT_SYMBOL(__Udiv); | ||
57 | EXPORT_SYMBOL(__Umod); | ||
58 | EXPORT_SYMBOL(__Div); | ||
59 | EXPORT_SYMBOL(__Mod); | ||
60 | EXPORT_SYMBOL(__ashrdi3); | ||
61 | |||
62 | /* Memory functions */ | ||
63 | EXPORT_SYMBOL(__ioremap); | ||
64 | EXPORT_SYMBOL(iounmap); | ||
65 | |||
66 | /* Semaphore functions */ | ||
67 | EXPORT_SYMBOL(__up); | ||
68 | EXPORT_SYMBOL(__down); | ||
69 | EXPORT_SYMBOL(__down_interruptible); | ||
70 | EXPORT_SYMBOL(__down_trylock); | ||
71 | |||
72 | /* Export shadow registers for the CPU I/O pins */ | ||
73 | EXPORT_SYMBOL(genconfig_shadow); | ||
74 | EXPORT_SYMBOL(port_pa_data_shadow); | ||
75 | EXPORT_SYMBOL(port_pa_dir_shadow); | ||
76 | EXPORT_SYMBOL(port_pb_data_shadow); | ||
77 | EXPORT_SYMBOL(port_pb_dir_shadow); | ||
78 | EXPORT_SYMBOL(port_pb_config_shadow); | ||
79 | EXPORT_SYMBOL(port_g_data_shadow); | ||
80 | |||
81 | /* Userspace access functions */ | ||
82 | EXPORT_SYMBOL(__copy_user_zeroing); | ||
83 | EXPORT_SYMBOL(__copy_user); | ||
84 | |||
85 | /* Cache flush functions */ | ||
86 | EXPORT_SYMBOL(flush_etrax_cache); | ||
87 | EXPORT_SYMBOL(prepare_rx_descriptor); | ||
88 | |||
89 | #undef memcpy | ||
90 | #undef memset | ||
91 | extern void * memset(void *, int, __kernel_size_t); | ||
92 | extern void * memcpy(void *, const void *, __kernel_size_t); | ||
93 | EXPORT_SYMBOL(memcpy); | ||
94 | EXPORT_SYMBOL(memset); | ||
95 | |||
96 | #ifdef CONFIG_ETRAX_FAST_TIMER | ||
97 | /* Fast timer functions */ | ||
98 | EXPORT_SYMBOL(fast_timer_list); | ||
99 | EXPORT_SYMBOL(start_one_shot_timer); | ||
100 | EXPORT_SYMBOL(del_fast_timer); | ||
101 | EXPORT_SYMBOL(schedule_usleep); | ||
102 | #endif | ||
103 | |||
diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c new file mode 100644 index 000000000000..d848b9407457 --- /dev/null +++ b/arch/cris/kernel/irq.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/arch/cris/kernel/irq.c | ||
4 | * | ||
5 | * Copyright (c) 2000,2001 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * This file contains the code used by various IRQ handling routines: | ||
10 | * asking for different IRQ's should be done through these routines | ||
11 | * instead of just grabbing them. Thus setups with different IRQ numbers | ||
12 | * shouldn't result in any weird surprises, and installing new handlers | ||
13 | * should be easier. | ||
14 | * | ||
15 | * Notice Linux/CRIS: these routines do not care about SMP | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | /* | ||
20 | * IRQ's are in fact implemented a bit like signal handlers for the kernel. | ||
21 | * Naturally it's not a 1:1 relation, but there are similarities. | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/ptrace.h> | ||
27 | |||
28 | #include <linux/kernel_stat.h> | ||
29 | #include <linux/signal.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/ioport.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/timex.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/random.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/seq_file.h> | ||
38 | #include <linux/errno.h> | ||
39 | #include <linux/bitops.h> | ||
40 | |||
41 | #include <asm/io.h> | ||
42 | |||
43 | /* Defined in arch specific irq.c */ | ||
44 | extern void arch_setup_irq(int irq); | ||
45 | extern void arch_free_irq(int irq); | ||
46 | |||
47 | void | ||
48 | disable_irq(unsigned int irq_nr) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | |||
52 | local_save_flags(flags); | ||
53 | local_irq_disable(); | ||
54 | mask_irq(irq_nr); | ||
55 | local_irq_restore(flags); | ||
56 | } | ||
57 | |||
58 | void | ||
59 | enable_irq(unsigned int irq_nr) | ||
60 | { | ||
61 | unsigned long flags; | ||
62 | local_save_flags(flags); | ||
63 | local_irq_disable(); | ||
64 | unmask_irq(irq_nr); | ||
65 | local_irq_restore(flags); | ||
66 | } | ||
67 | |||
68 | unsigned long | ||
69 | probe_irq_on() | ||
70 | { | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | EXPORT_SYMBOL(probe_irq_on); | ||
75 | |||
76 | int | ||
77 | probe_irq_off(unsigned long x) | ||
78 | { | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL(probe_irq_off); | ||
83 | |||
84 | /* | ||
85 | * Initial irq handlers. | ||
86 | */ | ||
87 | |||
88 | static struct irqaction *irq_action[NR_IRQS]; | ||
89 | |||
90 | int show_interrupts(struct seq_file *p, void *v) | ||
91 | { | ||
92 | int i = *(loff_t *) v; | ||
93 | struct irqaction * action; | ||
94 | unsigned long flags; | ||
95 | |||
96 | if (i < NR_IRQS) { | ||
97 | local_irq_save(flags); | ||
98 | action = irq_action[i]; | ||
99 | if (!action) | ||
100 | goto skip; | ||
101 | seq_printf(p, "%2d: %10u %c %s", | ||
102 | i, kstat_this_cpu.irqs[i], | ||
103 | (action->flags & SA_INTERRUPT) ? '+' : ' ', | ||
104 | action->name); | ||
105 | for (action = action->next; action; action = action->next) { | ||
106 | seq_printf(p, ",%s %s", | ||
107 | (action->flags & SA_INTERRUPT) ? " +" : "", | ||
108 | action->name); | ||
109 | } | ||
110 | seq_putc(p, '\n'); | ||
111 | skip: | ||
112 | local_irq_restore(flags); | ||
113 | } | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | /* called by the assembler IRQ entry functions defined in irq.h | ||
118 | * to dispatch the interrupts to registred handlers | ||
119 | * interrupts are disabled upon entry - depending on if the | ||
120 | * interrupt was registred with SA_INTERRUPT or not, interrupts | ||
121 | * are re-enabled or not. | ||
122 | */ | ||
123 | |||
124 | asmlinkage void do_IRQ(int irq, struct pt_regs * regs) | ||
125 | { | ||
126 | struct irqaction *action; | ||
127 | int do_random, cpu; | ||
128 | int ret, retval = 0; | ||
129 | |||
130 | cpu = smp_processor_id(); | ||
131 | irq_enter(); | ||
132 | kstat_cpu(cpu).irqs[irq - FIRST_IRQ]++; | ||
133 | action = irq_action[irq - FIRST_IRQ]; | ||
134 | |||
135 | if (action) { | ||
136 | if (!(action->flags & SA_INTERRUPT)) | ||
137 | local_irq_enable(); | ||
138 | do_random = 0; | ||
139 | do { | ||
140 | ret = action->handler(irq, action->dev_id, regs); | ||
141 | if (ret == IRQ_HANDLED) | ||
142 | do_random |= action->flags; | ||
143 | retval |= ret; | ||
144 | action = action->next; | ||
145 | } while (action); | ||
146 | |||
147 | if (retval != 1) { | ||
148 | if (retval) { | ||
149 | printk("irq event %d: bogus retval mask %x\n", | ||
150 | irq, retval); | ||
151 | } else { | ||
152 | printk("irq %d: nobody cared\n", irq); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | if (do_random & SA_SAMPLE_RANDOM) | ||
157 | add_interrupt_randomness(irq); | ||
158 | local_irq_disable(); | ||
159 | } | ||
160 | irq_exit(); | ||
161 | } | ||
162 | |||
163 | /* this function links in a handler into the chain of handlers for the | ||
164 | given irq, and if the irq has never been registred, the appropriate | ||
165 | handler is entered into the interrupt vector | ||
166 | */ | ||
167 | |||
168 | int setup_irq(int irq, struct irqaction * new) | ||
169 | { | ||
170 | int shared = 0; | ||
171 | struct irqaction *old, **p; | ||
172 | unsigned long flags; | ||
173 | |||
174 | p = irq_action + irq - FIRST_IRQ; | ||
175 | if ((old = *p) != NULL) { | ||
176 | /* Can't share interrupts unless both agree to */ | ||
177 | if (!(old->flags & new->flags & SA_SHIRQ)) | ||
178 | return -EBUSY; | ||
179 | |||
180 | /* Can't share interrupts unless both are same type */ | ||
181 | if ((old->flags ^ new->flags) & SA_INTERRUPT) | ||
182 | return -EBUSY; | ||
183 | |||
184 | /* add new interrupt at end of irq queue */ | ||
185 | do { | ||
186 | p = &old->next; | ||
187 | old = *p; | ||
188 | } while (old); | ||
189 | shared = 1; | ||
190 | } | ||
191 | |||
192 | if (new->flags & SA_SAMPLE_RANDOM) | ||
193 | rand_initialize_irq(irq); | ||
194 | |||
195 | local_save_flags(flags); | ||
196 | local_irq_disable(); | ||
197 | *p = new; | ||
198 | |||
199 | if (!shared) { | ||
200 | /* if the irq wasn't registred before, enter it into the vector table | ||
201 | and unmask it physically | ||
202 | */ | ||
203 | arch_setup_irq(irq); | ||
204 | unmask_irq(irq); | ||
205 | } | ||
206 | |||
207 | local_irq_restore(flags); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* this function is called by a driver to register an irq handler | ||
212 | Valid flags: | ||
213 | SA_INTERRUPT -> it's a fast interrupt, handler called with irq disabled and | ||
214 | no signal checking etc is performed upon exit | ||
215 | SA_SHIRQ -> the interrupt can be shared between different handlers, the handler | ||
216 | is required to check if the irq was "aimed" at it explicitely | ||
217 | SA_RANDOM -> the interrupt will add to the random generators entropy | ||
218 | */ | ||
219 | |||
220 | int request_irq(unsigned int irq, | ||
221 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
222 | unsigned long irqflags, | ||
223 | const char * devname, | ||
224 | void *dev_id) | ||
225 | { | ||
226 | int retval; | ||
227 | struct irqaction * action; | ||
228 | |||
229 | if(!handler) | ||
230 | return -EINVAL; | ||
231 | |||
232 | /* allocate and fill in a handler structure and setup the irq */ | ||
233 | |||
234 | action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
235 | if (!action) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | action->handler = handler; | ||
239 | action->flags = irqflags; | ||
240 | cpus_clear(action->mask); | ||
241 | action->name = devname; | ||
242 | action->next = NULL; | ||
243 | action->dev_id = dev_id; | ||
244 | |||
245 | retval = setup_irq(irq, action); | ||
246 | |||
247 | if (retval) | ||
248 | kfree(action); | ||
249 | return retval; | ||
250 | } | ||
251 | |||
252 | EXPORT_SYMBOL(request_irq); | ||
253 | |||
254 | void free_irq(unsigned int irq, void *dev_id) | ||
255 | { | ||
256 | struct irqaction * action, **p; | ||
257 | unsigned long flags; | ||
258 | |||
259 | if (irq >= NR_IRQS) { | ||
260 | printk("Trying to free IRQ%d\n",irq); | ||
261 | return; | ||
262 | } | ||
263 | for (p = irq - FIRST_IRQ + irq_action; (action = *p) != NULL; p = &action->next) { | ||
264 | if (action->dev_id != dev_id) | ||
265 | continue; | ||
266 | |||
267 | /* Found it - now free it */ | ||
268 | local_save_flags(flags); | ||
269 | local_irq_disable(); | ||
270 | *p = action->next; | ||
271 | if (!irq_action[irq - FIRST_IRQ]) { | ||
272 | mask_irq(irq); | ||
273 | arch_free_irq(irq); | ||
274 | } | ||
275 | local_irq_restore(flags); | ||
276 | kfree(action); | ||
277 | return; | ||
278 | } | ||
279 | printk("Trying to free free IRQ%d\n",irq); | ||
280 | } | ||
281 | |||
282 | EXPORT_SYMBOL(free_irq); | ||
283 | |||
284 | void weird_irq(void) | ||
285 | { | ||
286 | local_irq_disable(); | ||
287 | printk("weird irq\n"); | ||
288 | while(1); | ||
289 | } | ||
290 | |||
291 | #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) | ||
292 | /* Used by other archs to show/control IRQ steering during SMP */ | ||
293 | void __init | ||
294 | init_irq_proc(void) | ||
295 | { | ||
296 | } | ||
297 | #endif | ||
diff --git a/arch/cris/kernel/module.c b/arch/cris/kernel/module.c new file mode 100644 index 000000000000..f1d3e784f30c --- /dev/null +++ b/arch/cris/kernel/module.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* Kernel module help for i386. | ||
2 | Copyright (C) 2001 Rusty Russell. | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 2 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #include <linux/moduleloader.h> | ||
19 | #include <linux/elf.h> | ||
20 | #include <linux/vmalloc.h> | ||
21 | #include <linux/fs.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/kernel.h> | ||
24 | |||
25 | #if 0 | ||
26 | #define DEBUGP printk | ||
27 | #else | ||
28 | #define DEBUGP(fmt , ...) | ||
29 | #endif | ||
30 | |||
31 | void *module_alloc(unsigned long size) | ||
32 | { | ||
33 | if (size == 0) | ||
34 | return NULL; | ||
35 | return vmalloc(size); | ||
36 | } | ||
37 | |||
38 | |||
39 | /* Free memory returned from module_alloc */ | ||
40 | void module_free(struct module *mod, void *module_region) | ||
41 | { | ||
42 | vfree(module_region); | ||
43 | /* FIXME: If module_region == mod->init_region, trim exception | ||
44 | table entries. */ | ||
45 | } | ||
46 | |||
47 | /* We don't need anything special. */ | ||
48 | int module_frob_arch_sections(Elf_Ehdr *hdr, | ||
49 | Elf_Shdr *sechdrs, | ||
50 | char *secstrings, | ||
51 | struct module *mod) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | int apply_relocate(Elf32_Shdr *sechdrs, | ||
57 | const char *strtab, | ||
58 | unsigned int symindex, | ||
59 | unsigned int relsec, | ||
60 | struct module *me) | ||
61 | { | ||
62 | unsigned int i; | ||
63 | Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; | ||
64 | Elf32_Sym *sym; | ||
65 | uint32_t *location; | ||
66 | |||
67 | DEBUGP("Applying relocate section %u to %u\n", relsec, | ||
68 | sechdrs[relsec].sh_info); | ||
69 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { | ||
70 | /* This is where to make the change */ | ||
71 | location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_offset | ||
72 | + rel[i].r_offset; | ||
73 | /* This is the symbol it is referring to. Note that all | ||
74 | undefined symbols have been resolved. */ | ||
75 | sym = (Elf32_Sym *)sechdrs[symindex].sh_addr | ||
76 | + ELF32_R_SYM(rel[i].r_info); | ||
77 | |||
78 | /* We add the value into the location given */ | ||
79 | *location += sym->st_value; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | int apply_relocate_add(Elf32_Shdr *sechdrs, | ||
85 | const char *strtab, | ||
86 | unsigned int symindex, | ||
87 | unsigned int relsec, | ||
88 | struct module *me) | ||
89 | { | ||
90 | unsigned int i; | ||
91 | Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr; | ||
92 | |||
93 | DEBUGP ("Applying relocate section %u to %u\n", relsec, | ||
94 | sechdrs[relsec].sh_info); | ||
95 | |||
96 | for (i = 0; i < sechdrs[relsec].sh_size / sizeof (*rela); i++) { | ||
97 | /* This is where to make the change */ | ||
98 | uint32_t *loc | ||
99 | = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr | ||
100 | + rela[i].r_offset); | ||
101 | /* This is the symbol it is referring to. Note that all | ||
102 | undefined symbols have been resolved. */ | ||
103 | Elf32_Sym *sym | ||
104 | = ((Elf32_Sym *)sechdrs[symindex].sh_addr | ||
105 | + ELF32_R_SYM (rela[i].r_info)); | ||
106 | *loc = sym->st_value + rela[i].r_addend; | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | int module_finalize(const Elf_Ehdr *hdr, | ||
113 | const Elf_Shdr *sechdrs, | ||
114 | struct module *me) | ||
115 | { | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | void module_arch_cleanup(struct module *mod) | ||
120 | { | ||
121 | } | ||
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c new file mode 100644 index 000000000000..9f7cad7c7849 --- /dev/null +++ b/arch/cris/kernel/process.c | |||
@@ -0,0 +1,280 @@ | |||
1 | /* $Id: process.c,v 1.17 2004/04/05 13:53:48 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/process.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (C) 2000-2002 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
9 | * | ||
10 | * $Log: process.c,v $ | ||
11 | * Revision 1.17 2004/04/05 13:53:48 starvik | ||
12 | * Merge of Linux 2.6.5 | ||
13 | * | ||
14 | * Revision 1.16 2003/10/27 08:04:33 starvik | ||
15 | * Merge of Linux 2.6.0-test9 | ||
16 | * | ||
17 | * Revision 1.15 2003/09/11 07:29:52 starvik | ||
18 | * Merge of Linux 2.6.0-test5 | ||
19 | * | ||
20 | * Revision 1.14 2003/06/10 10:21:12 johana | ||
21 | * Moved thread_saved_pc() from arch/cris/kernel/process.c to | ||
22 | * subarch specific process.c. arch-v32 has an erp, no irp. | ||
23 | * | ||
24 | * Revision 1.13 2003/04/09 05:20:47 starvik | ||
25 | * Merge of Linux 2.5.67 | ||
26 | * | ||
27 | * Revision 1.12 2002/12/11 15:41:11 starvik | ||
28 | * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/kernel | ||
29 | * | ||
30 | * Revision 1.11 2002/12/10 09:00:10 starvik | ||
31 | * Merge of Linux 2.5.51 | ||
32 | * | ||
33 | * Revision 1.10 2002/11/27 08:42:34 starvik | ||
34 | * Argument to user_regs() is thread_info* | ||
35 | * | ||
36 | * Revision 1.9 2002/11/26 09:44:21 starvik | ||
37 | * New threads exits through ret_from_fork (necessary for preemptive scheduling) | ||
38 | * | ||
39 | * Revision 1.8 2002/11/19 14:35:24 starvik | ||
40 | * Changes from linux 2.4 | ||
41 | * Changed struct initializer syntax to the currently prefered notation | ||
42 | * | ||
43 | * Revision 1.7 2002/11/18 07:39:42 starvik | ||
44 | * thread_saved_pc moved here from processor.h | ||
45 | * | ||
46 | * Revision 1.6 2002/11/14 06:51:27 starvik | ||
47 | * Made cpu_idle more similar with other archs | ||
48 | * init_task_union -> init_thread_union | ||
49 | * Updated for new interrupt macros | ||
50 | * sys_clone and do_fork have a new argument, user_tid | ||
51 | * | ||
52 | * Revision 1.5 2002/11/05 06:45:11 starvik | ||
53 | * Merge of Linux 2.5.45 | ||
54 | * | ||
55 | * Revision 1.4 2002/02/05 15:37:44 bjornw | ||
56 | * Need init_task.h | ||
57 | * | ||
58 | * Revision 1.3 2002/01/21 15:22:49 bjornw | ||
59 | * current->counter is gone | ||
60 | * | ||
61 | * Revision 1.22 2001/11/13 09:40:43 orjanf | ||
62 | * Added dump_fpu (needed for core dumps). | ||
63 | * | ||
64 | * Revision 1.21 2001/11/12 18:26:21 pkj | ||
65 | * Fixed compiler warnings. | ||
66 | * | ||
67 | * Revision 1.20 2001/10/03 08:21:39 jonashg | ||
68 | * cause_of_death does not exist if CONFIG_SVINTO_SIM is defined. | ||
69 | * | ||
70 | * Revision 1.19 2001/09/26 11:52:54 bjornw | ||
71 | * INIT_MMAP is gone in 2.4.10 | ||
72 | * | ||
73 | * Revision 1.18 2001/08/21 21:43:51 hp | ||
74 | * Move last watchdog fix inside #ifdef CONFIG_ETRAX_WATCHDOG | ||
75 | * | ||
76 | * Revision 1.17 2001/08/21 13:48:01 jonashg | ||
77 | * Added fix by HP to avoid oops when doing a hard_reset_now. | ||
78 | * | ||
79 | * Revision 1.16 2001/06/21 02:00:40 hp | ||
80 | * * entry.S: Include asm/unistd.h. | ||
81 | * (_sys_call_table): Use section .rodata, not .data. | ||
82 | * (_kernel_thread): Move from... | ||
83 | * * process.c: ... here. | ||
84 | * * entryoffsets.c (VAL): Break out from... | ||
85 | * (OF): Use VAL. | ||
86 | * (LCLONE_VM): New asmified value from CLONE_VM. | ||
87 | * | ||
88 | * Revision 1.15 2001/06/20 16:31:57 hp | ||
89 | * Add comments to describe empty functions according to review. | ||
90 | * | ||
91 | * Revision 1.14 2001/05/29 11:27:59 markusl | ||
92 | * Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled | ||
93 | * | ||
94 | * Revision 1.13 2001/03/20 19:44:06 bjornw | ||
95 | * Use the 7th syscall argument for regs instead of current_regs | ||
96 | * | ||
97 | */ | ||
98 | |||
99 | /* | ||
100 | * This file handles the architecture-dependent parts of process handling.. | ||
101 | */ | ||
102 | |||
103 | #include <asm/atomic.h> | ||
104 | #include <asm/pgtable.h> | ||
105 | #include <asm/uaccess.h> | ||
106 | #include <asm/irq.h> | ||
107 | #include <linux/module.h> | ||
108 | #include <linux/spinlock.h> | ||
109 | #include <linux/fs_struct.h> | ||
110 | #include <linux/init_task.h> | ||
111 | #include <linux/sched.h> | ||
112 | #include <linux/fs.h> | ||
113 | #include <linux/user.h> | ||
114 | #include <linux/elfcore.h> | ||
115 | #include <linux/mqueue.h> | ||
116 | |||
117 | //#define DEBUG | ||
118 | |||
119 | /* | ||
120 | * Initial task structure. Make this a per-architecture thing, | ||
121 | * because different architectures tend to have different | ||
122 | * alignment requirements and potentially different initial | ||
123 | * setup. | ||
124 | */ | ||
125 | |||
126 | static struct fs_struct init_fs = INIT_FS; | ||
127 | static struct files_struct init_files = INIT_FILES; | ||
128 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
129 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
130 | struct mm_struct init_mm = INIT_MM(init_mm); | ||
131 | |||
132 | EXPORT_SYMBOL(init_mm); | ||
133 | |||
134 | /* | ||
135 | * Initial thread structure. | ||
136 | * | ||
137 | * We need to make sure that this is 8192-byte aligned due to the | ||
138 | * way process stacks are handled. This is done by having a special | ||
139 | * "init_task" linker map entry.. | ||
140 | */ | ||
141 | union thread_union init_thread_union | ||
142 | __attribute__((__section__(".data.init_task"))) = | ||
143 | { INIT_THREAD_INFO(init_task) }; | ||
144 | |||
145 | /* | ||
146 | * Initial task structure. | ||
147 | * | ||
148 | * All other task structs will be allocated on slabs in fork.c | ||
149 | */ | ||
150 | struct task_struct init_task = INIT_TASK(init_task); | ||
151 | |||
152 | EXPORT_SYMBOL(init_task); | ||
153 | |||
154 | /* | ||
155 | * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if | ||
156 | * there would ever be a halt sequence (for power save when idle) with | ||
157 | * some largish delay when halting or resuming *and* a driver that can't | ||
158 | * afford that delay. The hlt_counter would then be checked before | ||
159 | * executing the halt sequence, and the driver marks the unhaltable | ||
160 | * region by enable_hlt/disable_hlt. | ||
161 | */ | ||
162 | |||
163 | static int hlt_counter=0; | ||
164 | |||
165 | void disable_hlt(void) | ||
166 | { | ||
167 | hlt_counter++; | ||
168 | } | ||
169 | |||
170 | EXPORT_SYMBOL(disable_hlt); | ||
171 | |||
172 | void enable_hlt(void) | ||
173 | { | ||
174 | hlt_counter--; | ||
175 | } | ||
176 | |||
177 | EXPORT_SYMBOL(enable_hlt); | ||
178 | |||
179 | /* | ||
180 | * The following aren't currently used. | ||
181 | */ | ||
182 | void (*pm_idle)(void); | ||
183 | |||
184 | extern void default_idle(void); | ||
185 | |||
186 | /* | ||
187 | * The idle thread. There's no useful work to be | ||
188 | * done, so just try to conserve power and have a | ||
189 | * low exit latency (ie sit in a loop waiting for | ||
190 | * somebody to say that they'd like to reschedule) | ||
191 | */ | ||
192 | void cpu_idle (void) | ||
193 | { | ||
194 | /* endless idle loop with no priority at all */ | ||
195 | while (1) { | ||
196 | while (!need_resched()) { | ||
197 | void (*idle)(void) = pm_idle; | ||
198 | |||
199 | if (!idle) | ||
200 | idle = default_idle; | ||
201 | |||
202 | idle(); | ||
203 | } | ||
204 | schedule(); | ||
205 | } | ||
206 | |||
207 | } | ||
208 | |||
209 | void hard_reset_now (void); | ||
210 | |||
211 | void machine_restart(void) | ||
212 | { | ||
213 | hard_reset_now(); | ||
214 | } | ||
215 | |||
216 | EXPORT_SYMBOL(machine_restart); | ||
217 | |||
218 | /* | ||
219 | * Similar to machine_power_off, but don't shut off power. Add code | ||
220 | * here to freeze the system for e.g. post-mortem debug purpose when | ||
221 | * possible. This halt has nothing to do with the idle halt. | ||
222 | */ | ||
223 | |||
224 | void machine_halt(void) | ||
225 | { | ||
226 | } | ||
227 | |||
228 | EXPORT_SYMBOL(machine_halt); | ||
229 | |||
230 | /* If or when software power-off is implemented, add code here. */ | ||
231 | |||
232 | void machine_power_off(void) | ||
233 | { | ||
234 | } | ||
235 | |||
236 | EXPORT_SYMBOL(machine_power_off); | ||
237 | |||
238 | /* | ||
239 | * When a process does an "exec", machine state like FPU and debug | ||
240 | * registers need to be reset. This is a hook function for that. | ||
241 | * Currently we don't have any such state to reset, so this is empty. | ||
242 | */ | ||
243 | |||
244 | void flush_thread(void) | ||
245 | { | ||
246 | } | ||
247 | |||
248 | /* | ||
249 | * fill in the user structure for a core dump.. | ||
250 | */ | ||
251 | void dump_thread(struct pt_regs * regs, struct user * dump) | ||
252 | { | ||
253 | #if 0 | ||
254 | int i; | ||
255 | |||
256 | /* changed the size calculations - should hopefully work better. lbt */ | ||
257 | dump->magic = CMAGIC; | ||
258 | dump->start_code = 0; | ||
259 | dump->start_stack = regs->esp & ~(PAGE_SIZE - 1); | ||
260 | dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT; | ||
261 | dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT; | ||
262 | dump->u_dsize -= dump->u_tsize; | ||
263 | dump->u_ssize = 0; | ||
264 | for (i = 0; i < 8; i++) | ||
265 | dump->u_debugreg[i] = current->debugreg[i]; | ||
266 | |||
267 | if (dump->start_stack < TASK_SIZE) | ||
268 | dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT; | ||
269 | |||
270 | dump->regs = *regs; | ||
271 | |||
272 | dump->u_fpvalid = dump_fpu (regs, &dump->i387); | ||
273 | #endif | ||
274 | } | ||
275 | |||
276 | /* Fill in the fpu structure for a core dump. */ | ||
277 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | ||
278 | { | ||
279 | return 0; | ||
280 | } | ||
diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c new file mode 100644 index 000000000000..e85a2fdd9acf --- /dev/null +++ b/arch/cris/kernel/ptrace.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/kernel/ptrace.c | ||
3 | * | ||
4 | * Parts taken from the m68k port. | ||
5 | * | ||
6 | * Copyright (c) 2000, 2001, 2002 Axis Communications AB | ||
7 | * | ||
8 | * Authors: Bjorn Wesen | ||
9 | * | ||
10 | * $Log: ptrace.c,v $ | ||
11 | * Revision 1.9 2003/07/04 12:56:11 tobiasa | ||
12 | * Moved arch-specific code to arch-specific files. | ||
13 | * | ||
14 | * Revision 1.8 2003/04/09 05:20:47 starvik | ||
15 | * Merge of Linux 2.5.67 | ||
16 | * | ||
17 | * Revision 1.7 2002/11/27 08:42:34 starvik | ||
18 | * Argument to user_regs() is thread_info* | ||
19 | * | ||
20 | * Revision 1.6 2002/11/20 11:56:11 starvik | ||
21 | * Merge of Linux 2.5.48 | ||
22 | * | ||
23 | * Revision 1.5 2002/11/18 07:41:19 starvik | ||
24 | * Removed warning | ||
25 | * | ||
26 | * Revision 1.4 2002/11/11 12:47:28 starvik | ||
27 | * SYSCALL_TRACE has been moved to thread flags | ||
28 | * | ||
29 | * Revision 1.3 2002/02/05 15:37:18 bjornw | ||
30 | * * Add do_notify_resume (replaces do_signal in the callchain) | ||
31 | * * syscall_trace is now do_syscall_trace | ||
32 | * * current->ptrace flag PT_TRACESYS -> PT_SYSCALLTRACE | ||
33 | * * Keep track of the current->work.syscall_trace counter | ||
34 | * | ||
35 | * Revision 1.2 2001/12/18 13:35:20 bjornw | ||
36 | * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). | ||
37 | * | ||
38 | * Revision 1.8 2001/11/12 18:26:21 pkj | ||
39 | * Fixed compiler warnings. | ||
40 | * | ||
41 | * Revision 1.7 2001/09/26 11:53:49 bjornw | ||
42 | * PTRACE_DETACH works more simple in 2.4.10 | ||
43 | * | ||
44 | * Revision 1.6 2001/07/25 16:08:47 bjornw | ||
45 | * PTRACE_ATTACH bulk moved into arch-independent code in 2.4.7 | ||
46 | * | ||
47 | * Revision 1.5 2001/03/26 14:24:28 orjanf | ||
48 | * * Changed loop condition. | ||
49 | * * Added comment documenting non-standard ptrace behaviour. | ||
50 | * | ||
51 | * Revision 1.4 2001/03/20 19:44:41 bjornw | ||
52 | * Use the user_regs macro instead of thread.esp0 | ||
53 | * | ||
54 | * Revision 1.3 2000/12/18 23:45:25 bjornw | ||
55 | * Linux/CRIS first version | ||
56 | * | ||
57 | * | ||
58 | */ | ||
59 | |||
60 | #include <linux/kernel.h> | ||
61 | #include <linux/sched.h> | ||
62 | #include <linux/mm.h> | ||
63 | #include <linux/smp.h> | ||
64 | #include <linux/smp_lock.h> | ||
65 | #include <linux/errno.h> | ||
66 | #include <linux/ptrace.h> | ||
67 | #include <linux/user.h> | ||
68 | |||
69 | #include <asm/uaccess.h> | ||
70 | #include <asm/page.h> | ||
71 | #include <asm/pgtable.h> | ||
72 | #include <asm/system.h> | ||
73 | #include <asm/processor.h> | ||
74 | |||
75 | /* | ||
76 | * Get contents of register REGNO in task TASK. | ||
77 | */ | ||
78 | inline long get_reg(struct task_struct *task, unsigned int regno) | ||
79 | { | ||
80 | /* USP is a special case, it's not in the pt_regs struct but | ||
81 | * in the tasks thread struct | ||
82 | */ | ||
83 | |||
84 | if (regno == PT_USP) | ||
85 | return task->thread.usp; | ||
86 | else if (regno < PT_MAX) | ||
87 | return ((unsigned long *)user_regs(task->thread_info))[regno]; | ||
88 | else | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Write contents of register REGNO in task TASK. | ||
94 | */ | ||
95 | inline int put_reg(struct task_struct *task, unsigned int regno, | ||
96 | unsigned long data) | ||
97 | { | ||
98 | if (regno == PT_USP) | ||
99 | task->thread.usp = data; | ||
100 | else if (regno < PT_MAX) | ||
101 | ((unsigned long *)user_regs(task->thread_info))[regno] = data; | ||
102 | else | ||
103 | return -1; | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | /* notification of userspace execution resumption | ||
108 | * - triggered by current->work.notify_resume | ||
109 | */ | ||
110 | extern int do_signal(int canrestart, sigset_t *oldset, struct pt_regs *regs); | ||
111 | |||
112 | |||
113 | void do_notify_resume(int canrestart, sigset_t *oldset, struct pt_regs *regs, | ||
114 | __u32 thread_info_flags ) | ||
115 | { | ||
116 | /* deal with pending signal delivery */ | ||
117 | if (thread_info_flags & _TIF_SIGPENDING) | ||
118 | do_signal(canrestart,oldset,regs); | ||
119 | } | ||
diff --git a/arch/cris/kernel/semaphore.c b/arch/cris/kernel/semaphore.c new file mode 100644 index 000000000000..b884263d3cd4 --- /dev/null +++ b/arch/cris/kernel/semaphore.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * Generic semaphore code. Buyer beware. Do your own | ||
3 | * specific changes in <asm/semaphore-helper.h> | ||
4 | */ | ||
5 | |||
6 | #include <linux/sched.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <asm/semaphore-helper.h> | ||
9 | |||
10 | /* | ||
11 | * Semaphores are implemented using a two-way counter: | ||
12 | * The "count" variable is decremented for each process | ||
13 | * that tries to sleep, while the "waking" variable is | ||
14 | * incremented when the "up()" code goes to wake up waiting | ||
15 | * processes. | ||
16 | * | ||
17 | * Notably, the inline "up()" and "down()" functions can | ||
18 | * efficiently test if they need to do any extra work (up | ||
19 | * needs to do something only if count was negative before | ||
20 | * the increment operation. | ||
21 | * | ||
22 | * waking_non_zero() (from asm/semaphore.h) must execute | ||
23 | * atomically. | ||
24 | * | ||
25 | * When __up() is called, the count was negative before | ||
26 | * incrementing it, and we need to wake up somebody. | ||
27 | * | ||
28 | * This routine adds one to the count of processes that need to | ||
29 | * wake up and exit. ALL waiting processes actually wake up but | ||
30 | * only the one that gets to the "waking" field first will gate | ||
31 | * through and acquire the semaphore. The others will go back | ||
32 | * to sleep. | ||
33 | * | ||
34 | * Note that these functions are only called when there is | ||
35 | * contention on the lock, and as such all this is the | ||
36 | * "non-critical" part of the whole semaphore business. The | ||
37 | * critical part is the inline stuff in <asm/semaphore.h> | ||
38 | * where we want to avoid any extra jumps and calls. | ||
39 | */ | ||
40 | void __up(struct semaphore *sem) | ||
41 | { | ||
42 | wake_one_more(sem); | ||
43 | wake_up(&sem->wait); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * Perform the "down" function. Return zero for semaphore acquired, | ||
48 | * return negative for signalled out of the function. | ||
49 | * | ||
50 | * If called from __down, the return is ignored and the wait loop is | ||
51 | * not interruptible. This means that a task waiting on a semaphore | ||
52 | * using "down()" cannot be killed until someone does an "up()" on | ||
53 | * the semaphore. | ||
54 | * | ||
55 | * If called from __down_interruptible, the return value gets checked | ||
56 | * upon return. If the return value is negative then the task continues | ||
57 | * with the negative value in the return register (it can be tested by | ||
58 | * the caller). | ||
59 | * | ||
60 | * Either form may be used in conjunction with "up()". | ||
61 | * | ||
62 | */ | ||
63 | |||
64 | #define DOWN_VAR \ | ||
65 | struct task_struct *tsk = current; \ | ||
66 | wait_queue_t wait; \ | ||
67 | init_waitqueue_entry(&wait, tsk); | ||
68 | |||
69 | #define DOWN_HEAD(task_state) \ | ||
70 | \ | ||
71 | \ | ||
72 | tsk->state = (task_state); \ | ||
73 | add_wait_queue(&sem->wait, &wait); \ | ||
74 | \ | ||
75 | /* \ | ||
76 | * Ok, we're set up. sem->count is known to be less than zero \ | ||
77 | * so we must wait. \ | ||
78 | * \ | ||
79 | * We can let go the lock for purposes of waiting. \ | ||
80 | * We re-acquire it after awaking so as to protect \ | ||
81 | * all semaphore operations. \ | ||
82 | * \ | ||
83 | * If "up()" is called before we call waking_non_zero() then \ | ||
84 | * we will catch it right away. If it is called later then \ | ||
85 | * we will have to go through a wakeup cycle to catch it. \ | ||
86 | * \ | ||
87 | * Multiple waiters contend for the semaphore lock to see \ | ||
88 | * who gets to gate through and who has to wait some more. \ | ||
89 | */ \ | ||
90 | for (;;) { | ||
91 | |||
92 | #define DOWN_TAIL(task_state) \ | ||
93 | tsk->state = (task_state); \ | ||
94 | } \ | ||
95 | tsk->state = TASK_RUNNING; \ | ||
96 | remove_wait_queue(&sem->wait, &wait); | ||
97 | |||
98 | void __sched __down(struct semaphore * sem) | ||
99 | { | ||
100 | DOWN_VAR | ||
101 | DOWN_HEAD(TASK_UNINTERRUPTIBLE) | ||
102 | if (waking_non_zero(sem)) | ||
103 | break; | ||
104 | schedule(); | ||
105 | DOWN_TAIL(TASK_UNINTERRUPTIBLE) | ||
106 | } | ||
107 | |||
108 | int __sched __down_interruptible(struct semaphore * sem) | ||
109 | { | ||
110 | int ret = 0; | ||
111 | DOWN_VAR | ||
112 | DOWN_HEAD(TASK_INTERRUPTIBLE) | ||
113 | |||
114 | ret = waking_non_zero_interruptible(sem, tsk); | ||
115 | if (ret) | ||
116 | { | ||
117 | if (ret == 1) | ||
118 | /* ret != 0 only if we get interrupted -arca */ | ||
119 | ret = 0; | ||
120 | break; | ||
121 | } | ||
122 | schedule(); | ||
123 | DOWN_TAIL(TASK_INTERRUPTIBLE) | ||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | int __down_trylock(struct semaphore * sem) | ||
128 | { | ||
129 | return waking_non_zero_trylock(sem); | ||
130 | } | ||
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c new file mode 100644 index 000000000000..6ec2671078bf --- /dev/null +++ b/arch/cris/kernel/setup.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * | ||
3 | * linux/arch/cris/kernel/setup.c | ||
4 | * | ||
5 | * Copyright (C) 1995 Linus Torvalds | ||
6 | * Copyright (c) 2001 Axis Communications AB | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * This file handles the architecture-dependent parts of initialization | ||
11 | */ | ||
12 | |||
13 | #include <linux/config.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/bootmem.h> | ||
17 | #include <asm/pgtable.h> | ||
18 | #include <linux/seq_file.h> | ||
19 | #include <linux/tty.h> | ||
20 | |||
21 | #include <asm/setup.h> | ||
22 | |||
23 | /* | ||
24 | * Setup options | ||
25 | */ | ||
26 | struct drive_info_struct { char dummy[32]; } drive_info; | ||
27 | struct screen_info screen_info; | ||
28 | |||
29 | extern int root_mountflags; | ||
30 | extern char _etext, _edata, _end; | ||
31 | |||
32 | static char command_line[COMMAND_LINE_SIZE] = { 0, }; | ||
33 | |||
34 | extern const unsigned long text_start, edata; /* set by the linker script */ | ||
35 | extern unsigned long dram_start, dram_end; | ||
36 | |||
37 | extern unsigned long romfs_start, romfs_length, romfs_in_flash; /* from head.S */ | ||
38 | |||
39 | extern void show_etrax_copyright(void); /* arch-vX/kernel/setup.c */ | ||
40 | |||
41 | /* This mainly sets up the memory area, and can be really confusing. | ||
42 | * | ||
43 | * The physical DRAM is virtually mapped into dram_start to dram_end | ||
44 | * (usually c0000000 to c0000000 + DRAM size). The physical address is | ||
45 | * given by the macro __pa(). | ||
46 | * | ||
47 | * In this DRAM, the kernel code and data is loaded, in the beginning. | ||
48 | * It really starts at c0004000 to make room for some special pages - | ||
49 | * the start address is text_start. The kernel data ends at _end. After | ||
50 | * this the ROM filesystem is appended (if there is any). | ||
51 | * | ||
52 | * Between this address and dram_end, we have RAM pages usable to the | ||
53 | * boot code and the system. | ||
54 | * | ||
55 | */ | ||
56 | |||
57 | void __init | ||
58 | setup_arch(char **cmdline_p) | ||
59 | { | ||
60 | extern void init_etrax_debug(void); | ||
61 | unsigned long bootmap_size; | ||
62 | unsigned long start_pfn, max_pfn; | ||
63 | unsigned long memory_start; | ||
64 | |||
65 | /* register an initial console printing routine for printk's */ | ||
66 | |||
67 | init_etrax_debug(); | ||
68 | |||
69 | /* we should really poll for DRAM size! */ | ||
70 | |||
71 | high_memory = &dram_end; | ||
72 | |||
73 | if(romfs_in_flash || !romfs_length) { | ||
74 | /* if we have the romfs in flash, or if there is no rom filesystem, | ||
75 | * our free area starts directly after the BSS | ||
76 | */ | ||
77 | memory_start = (unsigned long) &_end; | ||
78 | } else { | ||
79 | /* otherwise the free area starts after the ROM filesystem */ | ||
80 | printk("ROM fs in RAM, size %lu bytes\n", romfs_length); | ||
81 | memory_start = romfs_start + romfs_length; | ||
82 | } | ||
83 | |||
84 | /* process 1's initial memory region is the kernel code/data */ | ||
85 | |||
86 | init_mm.start_code = (unsigned long) &text_start; | ||
87 | init_mm.end_code = (unsigned long) &_etext; | ||
88 | init_mm.end_data = (unsigned long) &_edata; | ||
89 | init_mm.brk = (unsigned long) &_end; | ||
90 | |||
91 | #define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) | ||
92 | #define PFN_DOWN(x) ((x) >> PAGE_SHIFT) | ||
93 | #define PFN_PHYS(x) ((x) << PAGE_SHIFT) | ||
94 | |||
95 | /* min_low_pfn points to the start of DRAM, start_pfn points | ||
96 | * to the first DRAM pages after the kernel, and max_low_pfn | ||
97 | * to the end of DRAM. | ||
98 | */ | ||
99 | |||
100 | /* | ||
101 | * partially used pages are not usable - thus | ||
102 | * we are rounding upwards: | ||
103 | */ | ||
104 | |||
105 | start_pfn = PFN_UP(memory_start); /* usually c0000000 + kernel + romfs */ | ||
106 | max_pfn = PFN_DOWN((unsigned long)high_memory); /* usually c0000000 + dram size */ | ||
107 | |||
108 | /* | ||
109 | * Initialize the boot-time allocator (start, end) | ||
110 | * | ||
111 | * We give it access to all our DRAM, but we could as well just have | ||
112 | * given it a small slice. No point in doing that though, unless we | ||
113 | * have non-contiguous memory and want the boot-stuff to be in, say, | ||
114 | * the smallest area. | ||
115 | * | ||
116 | * It will put a bitmap of the allocated pages in the beginning | ||
117 | * of the range we give it, but it won't mark the bitmaps pages | ||
118 | * as reserved. We have to do that ourselves below. | ||
119 | * | ||
120 | * We need to use init_bootmem_node instead of init_bootmem | ||
121 | * because our map starts at a quite high address (min_low_pfn). | ||
122 | */ | ||
123 | |||
124 | max_low_pfn = max_pfn; | ||
125 | min_low_pfn = PAGE_OFFSET >> PAGE_SHIFT; | ||
126 | |||
127 | bootmap_size = init_bootmem_node(NODE_DATA(0), start_pfn, | ||
128 | min_low_pfn, | ||
129 | max_low_pfn); | ||
130 | |||
131 | /* And free all memory not belonging to the kernel (addr, size) */ | ||
132 | |||
133 | free_bootmem(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn - start_pfn)); | ||
134 | |||
135 | /* | ||
136 | * Reserve the bootmem bitmap itself as well. We do this in two | ||
137 | * steps (first step was init_bootmem()) because this catches | ||
138 | * the (very unlikely) case of us accidentally initializing the | ||
139 | * bootmem allocator with an invalid RAM area. | ||
140 | * | ||
141 | * Arguments are start, size | ||
142 | */ | ||
143 | |||
144 | reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); | ||
145 | |||
146 | /* paging_init() sets up the MMU and marks all pages as reserved */ | ||
147 | |||
148 | paging_init(); | ||
149 | |||
150 | /* We don't use a command line yet, so just re-initialize it without | ||
151 | saving anything that might be there. */ | ||
152 | |||
153 | *cmdline_p = command_line; | ||
154 | |||
155 | #ifdef CONFIG_ETRAX_CMDLINE | ||
156 | strlcpy(command_line, CONFIG_ETRAX_CMDLINE, COMMAND_LINE_SIZE); | ||
157 | command_line[COMMAND_LINE_SIZE - 1] = '\0'; | ||
158 | |||
159 | /* Save command line for future references. */ | ||
160 | memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE); | ||
161 | saved_command_line[COMMAND_LINE_SIZE - 1] = '\0'; | ||
162 | #endif | ||
163 | |||
164 | /* give credit for the CRIS port */ | ||
165 | show_etrax_copyright(); | ||
166 | } | ||
167 | |||
168 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
169 | { | ||
170 | /* We only got one CPU... */ | ||
171 | return *pos < 1 ? (void *)1 : NULL; | ||
172 | } | ||
173 | |||
174 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
175 | { | ||
176 | ++*pos; | ||
177 | return NULL; | ||
178 | } | ||
179 | |||
180 | static void c_stop(struct seq_file *m, void *v) | ||
181 | { | ||
182 | } | ||
183 | |||
184 | extern int show_cpuinfo(struct seq_file *m, void *v); | ||
185 | |||
186 | struct seq_operations cpuinfo_op = { | ||
187 | .start = c_start, | ||
188 | .next = c_next, | ||
189 | .stop = c_stop, | ||
190 | .show = show_cpuinfo, | ||
191 | }; | ||
192 | |||
193 | |||
diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c new file mode 100644 index 000000000000..0aa0e0ebb3a9 --- /dev/null +++ b/arch/cris/kernel/sys_cris.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* $Id: sys_cris.c,v 1.6 2004/03/11 11:38:40 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/sys_cris.c | ||
4 | * | ||
5 | * This file contains various random system calls that | ||
6 | * have a non-standard calling sequence on some platforms. | ||
7 | * Since we don't have to do any backwards compatibility, our | ||
8 | * versions are done in the most "normal" way possible. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/errno.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/syscalls.h> | ||
15 | #include <linux/mm.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/smp_lock.h> | ||
18 | #include <linux/sem.h> | ||
19 | #include <linux/msg.h> | ||
20 | #include <linux/shm.h> | ||
21 | #include <linux/stat.h> | ||
22 | #include <linux/mman.h> | ||
23 | #include <linux/file.h> | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/ipc.h> | ||
27 | #include <asm/segment.h> | ||
28 | |||
29 | /* | ||
30 | * sys_pipe() is the normal C calling standard for creating | ||
31 | * a pipe. It's not the way Unix traditionally does this, though. | ||
32 | */ | ||
33 | asmlinkage int sys_pipe(unsigned long __user * fildes) | ||
34 | { | ||
35 | int fd[2]; | ||
36 | int error; | ||
37 | |||
38 | lock_kernel(); | ||
39 | error = do_pipe(fd); | ||
40 | unlock_kernel(); | ||
41 | if (!error) { | ||
42 | if (copy_to_user(fildes, fd, 2*sizeof(int))) | ||
43 | error = -EFAULT; | ||
44 | } | ||
45 | return error; | ||
46 | } | ||
47 | |||
48 | /* common code for old and new mmaps */ | ||
49 | static inline long | ||
50 | do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, | ||
51 | unsigned long flags, unsigned long fd, unsigned long pgoff) | ||
52 | { | ||
53 | int error = -EBADF; | ||
54 | struct file * file = NULL; | ||
55 | |||
56 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
57 | if (!(flags & MAP_ANONYMOUS)) { | ||
58 | file = fget(fd); | ||
59 | if (!file) | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | down_write(¤t->mm->mmap_sem); | ||
64 | error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
65 | up_write(¤t->mm->mmap_sem); | ||
66 | |||
67 | if (file) | ||
68 | fput(file); | ||
69 | out: | ||
70 | return error; | ||
71 | } | ||
72 | |||
73 | asmlinkage unsigned long old_mmap(unsigned long __user *args) | ||
74 | { | ||
75 | unsigned long buffer[6]; | ||
76 | int err = -EFAULT; | ||
77 | |||
78 | if (copy_from_user(&buffer, args, sizeof(buffer))) | ||
79 | goto out; | ||
80 | |||
81 | err = -EINVAL; | ||
82 | if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ | ||
83 | goto out; | ||
84 | |||
85 | err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], | ||
86 | buffer[4], buffer[5] >> PAGE_SHIFT); | ||
87 | out: | ||
88 | return err; | ||
89 | } | ||
90 | |||
91 | asmlinkage long | ||
92 | sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, | ||
93 | unsigned long flags, unsigned long fd, unsigned long pgoff) | ||
94 | { | ||
95 | return do_mmap2(addr, len, prot, flags, fd, pgoff); | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * sys_ipc() is the de-multiplexer for the SysV IPC calls.. | ||
100 | * | ||
101 | * This is really horribly ugly. (same as arch/i386) | ||
102 | */ | ||
103 | |||
104 | asmlinkage int sys_ipc (uint call, int first, int second, | ||
105 | int third, void __user *ptr, long fifth) | ||
106 | { | ||
107 | int version, ret; | ||
108 | |||
109 | version = call >> 16; /* hack for backward compatibility */ | ||
110 | call &= 0xffff; | ||
111 | |||
112 | switch (call) { | ||
113 | case SEMOP: | ||
114 | return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL); | ||
115 | case SEMTIMEDOP: | ||
116 | return sys_semtimedop(first, (struct sembuf __user *)ptr, second, | ||
117 | (const struct timespec __user *)fifth); | ||
118 | |||
119 | case SEMGET: | ||
120 | return sys_semget (first, second, third); | ||
121 | case SEMCTL: { | ||
122 | union semun fourth; | ||
123 | if (!ptr) | ||
124 | return -EINVAL; | ||
125 | if (get_user(fourth.__pad, (void * __user *) ptr)) | ||
126 | return -EFAULT; | ||
127 | return sys_semctl (first, second, third, fourth); | ||
128 | } | ||
129 | |||
130 | case MSGSND: | ||
131 | return sys_msgsnd (first, (struct msgbuf __user *) ptr, | ||
132 | second, third); | ||
133 | case MSGRCV: | ||
134 | switch (version) { | ||
135 | case 0: { | ||
136 | struct ipc_kludge tmp; | ||
137 | if (!ptr) | ||
138 | return -EINVAL; | ||
139 | |||
140 | if (copy_from_user(&tmp, | ||
141 | (struct ipc_kludge __user *) ptr, | ||
142 | sizeof (tmp))) | ||
143 | return -EFAULT; | ||
144 | return sys_msgrcv (first, tmp.msgp, second, | ||
145 | tmp.msgtyp, third); | ||
146 | } | ||
147 | default: | ||
148 | return sys_msgrcv (first, | ||
149 | (struct msgbuf __user *) ptr, | ||
150 | second, fifth, third); | ||
151 | } | ||
152 | case MSGGET: | ||
153 | return sys_msgget ((key_t) first, second); | ||
154 | case MSGCTL: | ||
155 | return sys_msgctl (first, second, (struct msqid_ds __user *) ptr); | ||
156 | |||
157 | case SHMAT: { | ||
158 | ulong raddr; | ||
159 | ret = do_shmat (first, (char __user *) ptr, second, &raddr); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | return put_user (raddr, (ulong __user *) third); | ||
163 | } | ||
164 | case SHMDT: | ||
165 | return sys_shmdt ((char __user *)ptr); | ||
166 | case SHMGET: | ||
167 | return sys_shmget (first, second, third); | ||
168 | case SHMCTL: | ||
169 | return sys_shmctl (first, second, | ||
170 | (struct shmid_ds __user *) ptr); | ||
171 | default: | ||
172 | return -ENOSYS; | ||
173 | } | ||
174 | } | ||
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c new file mode 100644 index 000000000000..6c28b0e7f7b4 --- /dev/null +++ b/arch/cris/kernel/time.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* $Id: time.c,v 1.14 2004/06/01 05:38:11 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/kernel/time.c | ||
4 | * | ||
5 | * Copyright (C) 1991, 1992, 1995 Linus Torvalds | ||
6 | * Copyright (C) 1999, 2000, 2001 Axis Communications AB | ||
7 | * | ||
8 | * 1994-07-02 Alan Modra | ||
9 | * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime | ||
10 | * 1995-03-26 Markus Kuhn | ||
11 | * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 | ||
12 | * precision CMOS clock update | ||
13 | * 1996-05-03 Ingo Molnar | ||
14 | * fixed time warps in do_[slow|fast]_gettimeoffset() | ||
15 | * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 | ||
16 | * "A Kernel Model for Precision Timekeeping" by Dave Mills | ||
17 | * | ||
18 | * Linux/CRIS specific code: | ||
19 | * | ||
20 | * Authors: Bjorn Wesen | ||
21 | * Johan Adolfsson | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <asm/rtc.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/param.h> | ||
29 | #include <linux/jiffies.h> | ||
30 | #include <linux/bcd.h> | ||
31 | #include <linux/timex.h> | ||
32 | #include <linux/init.h> | ||
33 | |||
34 | u64 jiffies_64 = INITIAL_JIFFIES; | ||
35 | |||
36 | EXPORT_SYMBOL(jiffies_64); | ||
37 | |||
38 | int have_rtc; /* used to remember if we have an RTC or not */; | ||
39 | |||
40 | #define TICK_SIZE tick | ||
41 | |||
42 | extern unsigned long wall_jiffies; | ||
43 | extern unsigned long loops_per_jiffy; /* init/main.c */ | ||
44 | unsigned long loops_per_usec; | ||
45 | |||
46 | extern unsigned long do_slow_gettimeoffset(void); | ||
47 | static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset; | ||
48 | |||
49 | /* | ||
50 | * This version of gettimeofday has near microsecond resolution. | ||
51 | * | ||
52 | * Note: Division is quite slow on CRIS and do_gettimeofday is called | ||
53 | * rather often. Maybe we should do some kind of approximation here | ||
54 | * (a naive approximation would be to divide by 1024). | ||
55 | */ | ||
56 | void do_gettimeofday(struct timeval *tv) | ||
57 | { | ||
58 | unsigned long flags; | ||
59 | signed long usec, sec; | ||
60 | local_irq_save(flags); | ||
61 | local_irq_disable(); | ||
62 | usec = do_gettimeoffset(); | ||
63 | { | ||
64 | unsigned long lost = jiffies - wall_jiffies; | ||
65 | if (lost) | ||
66 | usec += lost * (1000000 / HZ); | ||
67 | } | ||
68 | |||
69 | /* | ||
70 | * If time_adjust is negative then NTP is slowing the clock | ||
71 | * so make sure not to go into next possible interval. | ||
72 | * Better to lose some accuracy than have time go backwards.. | ||
73 | */ | ||
74 | if (unlikely(time_adjust < 0) && usec > tickadj) | ||
75 | usec = tickadj; | ||
76 | |||
77 | sec = xtime.tv_sec; | ||
78 | usec += xtime.tv_nsec / 1000; | ||
79 | local_irq_restore(flags); | ||
80 | |||
81 | while (usec >= 1000000) { | ||
82 | usec -= 1000000; | ||
83 | sec++; | ||
84 | } | ||
85 | |||
86 | tv->tv_sec = sec; | ||
87 | tv->tv_usec = usec; | ||
88 | } | ||
89 | |||
90 | EXPORT_SYMBOL(do_gettimeofday); | ||
91 | |||
92 | int do_settimeofday(struct timespec *tv) | ||
93 | { | ||
94 | time_t wtm_sec, sec = tv->tv_sec; | ||
95 | long wtm_nsec, nsec = tv->tv_nsec; | ||
96 | |||
97 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
98 | return -EINVAL; | ||
99 | |||
100 | write_seqlock_irq(&xtime_lock); | ||
101 | /* | ||
102 | * This is revolting. We need to set "xtime" correctly. However, the | ||
103 | * value in this location is the value at the most recent update of | ||
104 | * wall time. Discover what correction gettimeofday() would have | ||
105 | * made, and then undo it! | ||
106 | */ | ||
107 | nsec -= do_gettimeoffset() * NSEC_PER_USEC; | ||
108 | nsec -= (jiffies - wall_jiffies) * TICK_NSEC; | ||
109 | |||
110 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
111 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
112 | |||
113 | set_normalized_timespec(&xtime, sec, nsec); | ||
114 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
115 | |||
116 | time_adjust = 0; /* stop active adjtime() */ | ||
117 | time_status |= STA_UNSYNC; | ||
118 | time_maxerror = NTP_PHASE_LIMIT; | ||
119 | time_esterror = NTP_PHASE_LIMIT; | ||
120 | write_sequnlock_irq(&xtime_lock); | ||
121 | clock_was_set(); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | EXPORT_SYMBOL(do_settimeofday); | ||
126 | |||
127 | |||
128 | /* | ||
129 | * BUG: This routine does not handle hour overflow properly; it just | ||
130 | * sets the minutes. Usually you'll only notice that after reboot! | ||
131 | */ | ||
132 | |||
133 | int set_rtc_mmss(unsigned long nowtime) | ||
134 | { | ||
135 | int retval = 0; | ||
136 | int real_seconds, real_minutes, cmos_minutes; | ||
137 | |||
138 | printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime); | ||
139 | |||
140 | if(!have_rtc) | ||
141 | return 0; | ||
142 | |||
143 | cmos_minutes = CMOS_READ(RTC_MINUTES); | ||
144 | BCD_TO_BIN(cmos_minutes); | ||
145 | |||
146 | /* | ||
147 | * since we're only adjusting minutes and seconds, | ||
148 | * don't interfere with hour overflow. This avoids | ||
149 | * messing with unknown time zones but requires your | ||
150 | * RTC not to be off by more than 15 minutes | ||
151 | */ | ||
152 | real_seconds = nowtime % 60; | ||
153 | real_minutes = nowtime / 60; | ||
154 | if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) | ||
155 | real_minutes += 30; /* correct for half hour time zone */ | ||
156 | real_minutes %= 60; | ||
157 | |||
158 | if (abs(real_minutes - cmos_minutes) < 30) { | ||
159 | BIN_TO_BCD(real_seconds); | ||
160 | BIN_TO_BCD(real_minutes); | ||
161 | CMOS_WRITE(real_seconds,RTC_SECONDS); | ||
162 | CMOS_WRITE(real_minutes,RTC_MINUTES); | ||
163 | } else { | ||
164 | printk(KERN_WARNING | ||
165 | "set_rtc_mmss: can't update from %d to %d\n", | ||
166 | cmos_minutes, real_minutes); | ||
167 | retval = -1; | ||
168 | } | ||
169 | |||
170 | return retval; | ||
171 | } | ||
172 | |||
173 | /* grab the time from the RTC chip */ | ||
174 | |||
175 | unsigned long | ||
176 | get_cmos_time(void) | ||
177 | { | ||
178 | unsigned int year, mon, day, hour, min, sec; | ||
179 | |||
180 | sec = CMOS_READ(RTC_SECONDS); | ||
181 | min = CMOS_READ(RTC_MINUTES); | ||
182 | hour = CMOS_READ(RTC_HOURS); | ||
183 | day = CMOS_READ(RTC_DAY_OF_MONTH); | ||
184 | mon = CMOS_READ(RTC_MONTH); | ||
185 | year = CMOS_READ(RTC_YEAR); | ||
186 | |||
187 | printk(KERN_DEBUG | ||
188 | "rtc: sec 0x%x min 0x%x hour 0x%x day 0x%x mon 0x%x year 0x%x\n", | ||
189 | sec, min, hour, day, mon, year); | ||
190 | |||
191 | BCD_TO_BIN(sec); | ||
192 | BCD_TO_BIN(min); | ||
193 | BCD_TO_BIN(hour); | ||
194 | BCD_TO_BIN(day); | ||
195 | BCD_TO_BIN(mon); | ||
196 | BCD_TO_BIN(year); | ||
197 | |||
198 | if ((year += 1900) < 1970) | ||
199 | year += 100; | ||
200 | |||
201 | return mktime(year, mon, day, hour, min, sec); | ||
202 | } | ||
203 | |||
204 | /* update xtime from the CMOS settings. used when /dev/rtc gets a SET_TIME. | ||
205 | * TODO: this doesn't reset the fancy NTP phase stuff as do_settimeofday does. | ||
206 | */ | ||
207 | |||
208 | void | ||
209 | update_xtime_from_cmos(void) | ||
210 | { | ||
211 | if(have_rtc) { | ||
212 | xtime.tv_sec = get_cmos_time(); | ||
213 | xtime.tv_nsec = 0; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Scheduler clock - returns current time in nanosec units. | ||
219 | */ | ||
220 | unsigned long long sched_clock(void) | ||
221 | { | ||
222 | return (unsigned long long)jiffies * (1000000000 / HZ); | ||
223 | } | ||
224 | |||
225 | static int | ||
226 | __init init_udelay(void) | ||
227 | { | ||
228 | loops_per_usec = (loops_per_jiffy * HZ) / 1000000; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | __initcall(init_udelay); | ||
diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c new file mode 100644 index 000000000000..d4dfa050e3a5 --- /dev/null +++ b/arch/cris/kernel/traps.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* $Id: traps.c,v 1.9 2004/05/11 12:28:26 starvik Exp $ | ||
2 | * | ||
3 | * linux/arch/cris/traps.c | ||
4 | * | ||
5 | * Here we handle the break vectors not used by the system call | ||
6 | * mechanism, as well as some general stack/register dumping | ||
7 | * things. | ||
8 | * | ||
9 | * Copyright (C) 2000-2002 Axis Communications AB | ||
10 | * | ||
11 | * Authors: Bjorn Wesen | ||
12 | * Hans-Peter Nilsson | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <asm/pgtable.h> | ||
19 | #include <asm/uaccess.h> | ||
20 | |||
21 | static int kstack_depth_to_print = 24; | ||
22 | |||
23 | void show_trace(unsigned long * stack) | ||
24 | { | ||
25 | unsigned long addr, module_start, module_end; | ||
26 | extern char _stext, _etext; | ||
27 | int i; | ||
28 | |||
29 | printk("\nCall Trace: "); | ||
30 | |||
31 | i = 1; | ||
32 | module_start = VMALLOC_START; | ||
33 | module_end = VMALLOC_END; | ||
34 | |||
35 | while (((long) stack & (THREAD_SIZE-1)) != 0) { | ||
36 | if (__get_user (addr, stack)) { | ||
37 | /* This message matches "failing address" marked | ||
38 | s390 in ksymoops, so lines containing it will | ||
39 | not be filtered out by ksymoops. */ | ||
40 | printk ("Failing address 0x%lx\n", (unsigned long)stack); | ||
41 | break; | ||
42 | } | ||
43 | stack++; | ||
44 | |||
45 | /* | ||
46 | * If the address is either in the text segment of the | ||
47 | * kernel, or in the region which contains vmalloc'ed | ||
48 | * memory, it *may* be the address of a calling | ||
49 | * routine; if so, print it so that someone tracing | ||
50 | * down the cause of the crash will be able to figure | ||
51 | * out the call path that was taken. | ||
52 | */ | ||
53 | if (((addr >= (unsigned long) &_stext) && | ||
54 | (addr <= (unsigned long) &_etext)) || | ||
55 | ((addr >= module_start) && (addr <= module_end))) { | ||
56 | if (i && ((i % 8) == 0)) | ||
57 | printk("\n "); | ||
58 | printk("[<%08lx>] ", addr); | ||
59 | i++; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * These constants are for searching for possible module text | ||
66 | * segments. MODULE_RANGE is a guess of how much space is likely | ||
67 | * to be vmalloced. | ||
68 | */ | ||
69 | |||
70 | #define MODULE_RANGE (8*1024*1024) | ||
71 | |||
72 | /* | ||
73 | * The output (format, strings and order) is adjusted to be usable with | ||
74 | * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't | ||
75 | * change it unless you're serious about adjusting ksymoops and syncing | ||
76 | * with the ksymoops maintainer. | ||
77 | */ | ||
78 | |||
79 | void | ||
80 | show_stack(struct task_struct *task, unsigned long *sp) | ||
81 | { | ||
82 | unsigned long *stack, addr; | ||
83 | int i; | ||
84 | |||
85 | /* | ||
86 | * debugging aid: "show_stack(NULL);" prints a | ||
87 | * back trace. | ||
88 | */ | ||
89 | |||
90 | if(sp == NULL) { | ||
91 | if (task) | ||
92 | sp = (unsigned long*)task->thread.ksp; | ||
93 | else | ||
94 | sp = (unsigned long*)rdsp(); | ||
95 | } | ||
96 | |||
97 | stack = sp; | ||
98 | |||
99 | printk("\nStack from %08lx:\n ", (unsigned long)stack); | ||
100 | for(i = 0; i < kstack_depth_to_print; i++) { | ||
101 | if (((long) stack & (THREAD_SIZE-1)) == 0) | ||
102 | break; | ||
103 | if (i && ((i % 8) == 0)) | ||
104 | printk("\n "); | ||
105 | if (__get_user (addr, stack)) { | ||
106 | /* This message matches "failing address" marked | ||
107 | s390 in ksymoops, so lines containing it will | ||
108 | not be filtered out by ksymoops. */ | ||
109 | printk ("Failing address 0x%lx\n", (unsigned long)stack); | ||
110 | break; | ||
111 | } | ||
112 | stack++; | ||
113 | printk("%08lx ", addr); | ||
114 | } | ||
115 | show_trace(sp); | ||
116 | } | ||
117 | |||
118 | #if 0 | ||
119 | /* displays a short stack trace */ | ||
120 | |||
121 | int | ||
122 | show_stack() | ||
123 | { | ||
124 | unsigned long *sp = (unsigned long *)rdusp(); | ||
125 | int i; | ||
126 | printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); | ||
127 | for(i = 0; i < 16; i++) | ||
128 | printk("sp + %d: 0x%08lx\n", i*4, sp[i]); | ||
129 | return 0; | ||
130 | } | ||
131 | #endif | ||
132 | |||
133 | void dump_stack(void) | ||
134 | { | ||
135 | show_stack(NULL, NULL); | ||
136 | } | ||
137 | |||
138 | EXPORT_SYMBOL(dump_stack); | ||
139 | |||
140 | void __init | ||
141 | trap_init(void) | ||
142 | { | ||
143 | /* Nothing needs to be done */ | ||
144 | } | ||
diff --git a/arch/cris/mm/Makefile b/arch/cris/mm/Makefile new file mode 100644 index 000000000000..d3ae08c90b4e --- /dev/null +++ b/arch/cris/mm/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the linux cris-specific parts of the memory manager. | ||
3 | # | ||
4 | |||
5 | obj-y := init.o fault.o tlb.o ioremap.o | ||
6 | |||
diff --git a/arch/cris/mm/fault.c b/arch/cris/mm/fault.c new file mode 100644 index 000000000000..03254b9eded1 --- /dev/null +++ b/arch/cris/mm/fault.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/mm/fault.c | ||
3 | * | ||
4 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
5 | * | ||
6 | * Authors: Bjorn Wesen | ||
7 | * | ||
8 | * $Log: fault.c,v $ | ||
9 | * Revision 1.11 2004/05/14 07:58:05 starvik | ||
10 | * Merge of changes from 2.4 | ||
11 | * | ||
12 | * Revision 1.10 2003/10/27 14:51:24 starvik | ||
13 | * Removed debugcode | ||
14 | * | ||
15 | * Revision 1.9 2003/10/27 14:50:42 starvik | ||
16 | * Changed do_page_fault signature | ||
17 | * | ||
18 | * Revision 1.8 2003/07/04 13:02:48 tobiasa | ||
19 | * Moved code snippet from arch/cris/mm/fault.c that searches for fixup code | ||
20 | * to seperate function in arch-specific files. | ||
21 | * | ||
22 | * Revision 1.7 2003/01/22 06:48:38 starvik | ||
23 | * Fixed warnings issued by GCC 3.2.1 | ||
24 | * | ||
25 | * Revision 1.6 2003/01/09 14:42:52 starvik | ||
26 | * Merge of Linux 2.5.55 | ||
27 | * | ||
28 | * Revision 1.5 2002/12/11 14:44:48 starvik | ||
29 | * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm | ||
30 | * | ||
31 | * Revision 1.4 2002/11/13 15:10:28 starvik | ||
32 | * pte_offset has been renamed to pte_offset_kernel | ||
33 | * | ||
34 | * Revision 1.3 2002/11/05 06:45:13 starvik | ||
35 | * Merge of Linux 2.5.45 | ||
36 | * | ||
37 | * Revision 1.2 2001/12/18 13:35:22 bjornw | ||
38 | * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). | ||
39 | * | ||
40 | * Revision 1.20 2001/11/22 13:34:06 bjornw | ||
41 | * * Bug workaround (LX TR89): force a rerun of the whole of an interrupted | ||
42 | * unaligned write, because the second half of the write will be corrupted | ||
43 | * otherwise. Affected unaligned writes spanning not-yet mapped pages. | ||
44 | * * Optimization: use the wr_rd bit in R_MMU_CAUSE to know whether a miss | ||
45 | * was due to a read or a write (before we didn't know this until the next | ||
46 | * restart of the interrupted instruction, thus wasting one fault-irq) | ||
47 | * | ||
48 | * Revision 1.19 2001/11/12 19:02:10 pkj | ||
49 | * Fixed compiler warnings. | ||
50 | * | ||
51 | * Revision 1.18 2001/07/18 22:14:32 bjornw | ||
52 | * Enable interrupts in the bulk of do_page_fault | ||
53 | * | ||
54 | * Revision 1.17 2001/07/18 13:07:23 bjornw | ||
55 | * * Detect non-existant PTE's in vmalloc pmd synchronization | ||
56 | * * Remove comment about fast-paths for VMALLOC_START etc, because all that | ||
57 | * was totally bogus anyway it turned out :) | ||
58 | * * Fix detection of vmalloc-area synchronization | ||
59 | * * Add some comments | ||
60 | * | ||
61 | * Revision 1.16 2001/06/13 00:06:08 bjornw | ||
62 | * current_pgd should be volatile | ||
63 | * | ||
64 | * Revision 1.15 2001/06/13 00:02:23 bjornw | ||
65 | * Use a separate variable to store the current pgd to avoid races in schedule | ||
66 | * | ||
67 | * Revision 1.14 2001/05/16 17:41:07 hp | ||
68 | * Last comment tweak further tweaked. | ||
69 | * | ||
70 | * Revision 1.13 2001/05/15 00:58:44 hp | ||
71 | * Expand a bit on the comment why we compare address >= TASK_SIZE rather | ||
72 | * than >= VMALLOC_START. | ||
73 | * | ||
74 | * Revision 1.12 2001/04/04 10:51:14 bjornw | ||
75 | * mmap_sem is grabbed for reading | ||
76 | * | ||
77 | * Revision 1.11 2001/03/23 07:36:07 starvik | ||
78 | * Corrected according to review remarks | ||
79 | * | ||
80 | * Revision 1.10 2001/03/21 16:10:11 bjornw | ||
81 | * CRIS_FRAME_FIXUP not needed anymore, use FRAME_NORMAL | ||
82 | * | ||
83 | * Revision 1.9 2001/03/05 13:22:20 bjornw | ||
84 | * Spell-fix and fix in vmalloc_fault handling | ||
85 | * | ||
86 | * Revision 1.8 2000/11/22 14:45:31 bjornw | ||
87 | * * 2.4.0-test10 removed the set_pgdir instantaneous kernel global mapping | ||
88 | * into all processes. Instead we fill in the missing PTE entries on demand. | ||
89 | * | ||
90 | * Revision 1.7 2000/11/21 16:39:09 bjornw | ||
91 | * fixup switches frametype | ||
92 | * | ||
93 | * Revision 1.6 2000/11/17 16:54:08 bjornw | ||
94 | * More detailed siginfo reporting | ||
95 | * | ||
96 | * | ||
97 | */ | ||
98 | |||
99 | #include <linux/mm.h> | ||
100 | #include <linux/interrupt.h> | ||
101 | #include <linux/module.h> | ||
102 | #include <asm/uaccess.h> | ||
103 | |||
104 | extern int find_fixup_code(struct pt_regs *); | ||
105 | extern void die_if_kernel(const char *, struct pt_regs *, long); | ||
106 | |||
107 | /* debug of low-level TLB reload */ | ||
108 | #undef DEBUG | ||
109 | |||
110 | #ifdef DEBUG | ||
111 | #define D(x) x | ||
112 | #else | ||
113 | #define D(x) | ||
114 | #endif | ||
115 | |||
116 | /* debug of higher-level faults */ | ||
117 | #define DPG(x) | ||
118 | |||
119 | /* current active page directory */ | ||
120 | |||
121 | volatile pgd_t *current_pgd; | ||
122 | |||
123 | /* | ||
124 | * This routine handles page faults. It determines the address, | ||
125 | * and the problem, and then passes it off to one of the appropriate | ||
126 | * routines. | ||
127 | * | ||
128 | * Notice that the address we're given is aligned to the page the fault | ||
129 | * occurred in, since we only get the PFN in R_MMU_CAUSE not the complete | ||
130 | * address. | ||
131 | * | ||
132 | * error_code: | ||
133 | * bit 0 == 0 means no page found, 1 means protection fault | ||
134 | * bit 1 == 0 means read, 1 means write | ||
135 | * | ||
136 | * If this routine detects a bad access, it returns 1, otherwise it | ||
137 | * returns 0. | ||
138 | */ | ||
139 | |||
140 | asmlinkage void | ||
141 | do_page_fault(unsigned long address, struct pt_regs *regs, | ||
142 | int protection, int writeaccess) | ||
143 | { | ||
144 | struct task_struct *tsk; | ||
145 | struct mm_struct *mm; | ||
146 | struct vm_area_struct * vma; | ||
147 | siginfo_t info; | ||
148 | |||
149 | D(printk("Page fault for %X at %X, prot %d write %d\n", | ||
150 | address, regs->erp, protection, writeaccess)); | ||
151 | |||
152 | tsk = current; | ||
153 | |||
154 | /* | ||
155 | * We fault-in kernel-space virtual memory on-demand. The | ||
156 | * 'reference' page table is init_mm.pgd. | ||
157 | * | ||
158 | * NOTE! We MUST NOT take any locks for this case. We may | ||
159 | * be in an interrupt or a critical region, and should | ||
160 | * only copy the information from the master page table, | ||
161 | * nothing more. | ||
162 | * | ||
163 | * NOTE2: This is done so that, when updating the vmalloc | ||
164 | * mappings we don't have to walk all processes pgdirs and | ||
165 | * add the high mappings all at once. Instead we do it as they | ||
166 | * are used. However vmalloc'ed page entries have the PAGE_GLOBAL | ||
167 | * bit set so sometimes the TLB can use a lingering entry. | ||
168 | * | ||
169 | * This verifies that the fault happens in kernel space | ||
170 | * and that the fault was not a protection error (error_code & 1). | ||
171 | */ | ||
172 | |||
173 | if (address >= VMALLOC_START && | ||
174 | !protection && | ||
175 | !user_mode(regs)) | ||
176 | goto vmalloc_fault; | ||
177 | |||
178 | /* we can and should enable interrupts at this point */ | ||
179 | sti(); | ||
180 | |||
181 | mm = tsk->mm; | ||
182 | info.si_code = SEGV_MAPERR; | ||
183 | |||
184 | /* | ||
185 | * If we're in an interrupt or have no user | ||
186 | * context, we must not take the fault.. | ||
187 | */ | ||
188 | |||
189 | if (in_interrupt() || !mm) | ||
190 | goto no_context; | ||
191 | |||
192 | down_read(&mm->mmap_sem); | ||
193 | vma = find_vma(mm, address); | ||
194 | if (!vma) | ||
195 | goto bad_area; | ||
196 | if (vma->vm_start <= address) | ||
197 | goto good_area; | ||
198 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
199 | goto bad_area; | ||
200 | if (user_mode(regs)) { | ||
201 | /* | ||
202 | * accessing the stack below usp is always a bug. | ||
203 | * we get page-aligned addresses so we can only check | ||
204 | * if we're within a page from usp, but that might be | ||
205 | * enough to catch brutal errors at least. | ||
206 | */ | ||
207 | if (address + PAGE_SIZE < rdusp()) | ||
208 | goto bad_area; | ||
209 | } | ||
210 | if (expand_stack(vma, address)) | ||
211 | goto bad_area; | ||
212 | |||
213 | /* | ||
214 | * Ok, we have a good vm_area for this memory access, so | ||
215 | * we can handle it.. | ||
216 | */ | ||
217 | |||
218 | good_area: | ||
219 | info.si_code = SEGV_ACCERR; | ||
220 | |||
221 | /* first do some preliminary protection checks */ | ||
222 | |||
223 | if (writeaccess) { | ||
224 | if (!(vma->vm_flags & VM_WRITE)) | ||
225 | goto bad_area; | ||
226 | } else { | ||
227 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | ||
228 | goto bad_area; | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * If for any reason at all we couldn't handle the fault, | ||
233 | * make sure we exit gracefully rather than endlessly redo | ||
234 | * the fault. | ||
235 | */ | ||
236 | |||
237 | switch (handle_mm_fault(mm, vma, address, writeaccess)) { | ||
238 | case 1: | ||
239 | tsk->min_flt++; | ||
240 | break; | ||
241 | case 2: | ||
242 | tsk->maj_flt++; | ||
243 | break; | ||
244 | case 0: | ||
245 | goto do_sigbus; | ||
246 | default: | ||
247 | goto out_of_memory; | ||
248 | } | ||
249 | |||
250 | up_read(&mm->mmap_sem); | ||
251 | return; | ||
252 | |||
253 | /* | ||
254 | * Something tried to access memory that isn't in our memory map.. | ||
255 | * Fix it, but check if it's kernel or user first.. | ||
256 | */ | ||
257 | |||
258 | bad_area: | ||
259 | up_read(&mm->mmap_sem); | ||
260 | |||
261 | bad_area_nosemaphore: | ||
262 | DPG(show_registers(regs)); | ||
263 | |||
264 | /* User mode accesses just cause a SIGSEGV */ | ||
265 | |||
266 | if (user_mode(regs)) { | ||
267 | info.si_signo = SIGSEGV; | ||
268 | info.si_errno = 0; | ||
269 | /* info.si_code has been set above */ | ||
270 | info.si_addr = (void *)address; | ||
271 | force_sig_info(SIGSEGV, &info, tsk); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | no_context: | ||
276 | |||
277 | /* Are we prepared to handle this kernel fault? | ||
278 | * | ||
279 | * (The kernel has valid exception-points in the source | ||
280 | * when it acesses user-memory. When it fails in one | ||
281 | * of those points, we find it in a table and do a jump | ||
282 | * to some fixup code that loads an appropriate error | ||
283 | * code) | ||
284 | */ | ||
285 | |||
286 | if (find_fixup_code(regs)) | ||
287 | return; | ||
288 | |||
289 | /* | ||
290 | * Oops. The kernel tried to access some bad page. We'll have to | ||
291 | * terminate things with extreme prejudice. | ||
292 | */ | ||
293 | |||
294 | if ((unsigned long) (address) < PAGE_SIZE) | ||
295 | printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); | ||
296 | else | ||
297 | printk(KERN_ALERT "Unable to handle kernel access"); | ||
298 | printk(" at virtual address %08lx\n",address); | ||
299 | |||
300 | die_if_kernel("Oops", regs, (writeaccess << 1) | protection); | ||
301 | |||
302 | do_exit(SIGKILL); | ||
303 | |||
304 | /* | ||
305 | * We ran out of memory, or some other thing happened to us that made | ||
306 | * us unable to handle the page fault gracefully. | ||
307 | */ | ||
308 | |||
309 | out_of_memory: | ||
310 | up_read(&mm->mmap_sem); | ||
311 | printk("VM: killing process %s\n", tsk->comm); | ||
312 | if (user_mode(regs)) | ||
313 | do_exit(SIGKILL); | ||
314 | goto no_context; | ||
315 | |||
316 | do_sigbus: | ||
317 | up_read(&mm->mmap_sem); | ||
318 | |||
319 | /* | ||
320 | * Send a sigbus, regardless of whether we were in kernel | ||
321 | * or user mode. | ||
322 | */ | ||
323 | info.si_signo = SIGBUS; | ||
324 | info.si_errno = 0; | ||
325 | info.si_code = BUS_ADRERR; | ||
326 | info.si_addr = (void *)address; | ||
327 | force_sig_info(SIGBUS, &info, tsk); | ||
328 | |||
329 | /* Kernel mode? Handle exceptions or die */ | ||
330 | if (!user_mode(regs)) | ||
331 | goto no_context; | ||
332 | return; | ||
333 | |||
334 | vmalloc_fault: | ||
335 | { | ||
336 | /* | ||
337 | * Synchronize this task's top level page-table | ||
338 | * with the 'reference' page table. | ||
339 | * | ||
340 | * Use current_pgd instead of tsk->active_mm->pgd | ||
341 | * since the latter might be unavailable if this | ||
342 | * code is executed in a misfortunately run irq | ||
343 | * (like inside schedule() between switch_mm and | ||
344 | * switch_to...). | ||
345 | */ | ||
346 | |||
347 | int offset = pgd_index(address); | ||
348 | pgd_t *pgd, *pgd_k; | ||
349 | pmd_t *pmd, *pmd_k; | ||
350 | pte_t *pte_k; | ||
351 | |||
352 | pgd = (pgd_t *)current_pgd + offset; | ||
353 | pgd_k = init_mm.pgd + offset; | ||
354 | |||
355 | /* Since we're two-level, we don't need to do both | ||
356 | * set_pgd and set_pmd (they do the same thing). If | ||
357 | * we go three-level at some point, do the right thing | ||
358 | * with pgd_present and set_pgd here. | ||
359 | * | ||
360 | * Also, since the vmalloc area is global, we don't | ||
361 | * need to copy individual PTE's, it is enough to | ||
362 | * copy the pgd pointer into the pte page of the | ||
363 | * root task. If that is there, we'll find our pte if | ||
364 | * it exists. | ||
365 | */ | ||
366 | |||
367 | pmd = pmd_offset(pgd, address); | ||
368 | pmd_k = pmd_offset(pgd_k, address); | ||
369 | |||
370 | if (!pmd_present(*pmd_k)) | ||
371 | goto bad_area_nosemaphore; | ||
372 | |||
373 | set_pmd(pmd, *pmd_k); | ||
374 | |||
375 | /* Make sure the actual PTE exists as well to | ||
376 | * catch kernel vmalloc-area accesses to non-mapped | ||
377 | * addresses. If we don't do this, this will just | ||
378 | * silently loop forever. | ||
379 | */ | ||
380 | |||
381 | pte_k = pte_offset_kernel(pmd_k, address); | ||
382 | if (!pte_present(*pte_k)) | ||
383 | goto no_context; | ||
384 | |||
385 | return; | ||
386 | } | ||
387 | } | ||
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c new file mode 100644 index 000000000000..31a0018b525a --- /dev/null +++ b/arch/cris/mm/init.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/mm/init.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Linus Torvalds | ||
5 | * Copyright (C) 2000,2001 Axis Communications AB | ||
6 | * | ||
7 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
8 | * | ||
9 | * $Log: init.c,v $ | ||
10 | * Revision 1.11 2004/05/28 09:28:56 starvik | ||
11 | * Calculation of loops_per_usec moved because initalization order has changed | ||
12 | * in Linux 2.6. | ||
13 | * | ||
14 | * Revision 1.10 2004/05/14 07:58:05 starvik | ||
15 | * Merge of changes from 2.4 | ||
16 | * | ||
17 | * Revision 1.9 2003/07/04 08:27:54 starvik | ||
18 | * Merge of Linux 2.5.74 | ||
19 | * | ||
20 | * Revision 1.8 2003/04/09 05:20:48 starvik | ||
21 | * Merge of Linux 2.5.67 | ||
22 | * | ||
23 | * Revision 1.7 2003/01/22 06:48:38 starvik | ||
24 | * Fixed warnings issued by GCC 3.2.1 | ||
25 | * | ||
26 | * Revision 1.6 2002/12/11 14:44:48 starvik | ||
27 | * Extracted v10 (ETRAX 100LX) specific stuff to arch/cris/arch-v10/mm | ||
28 | * | ||
29 | * Revision 1.5 2002/11/18 07:37:37 starvik | ||
30 | * Added cache bug workaround (from Linux 2.4) | ||
31 | * | ||
32 | * Revision 1.4 2002/11/13 15:40:24 starvik | ||
33 | * Removed the page table cache stuff (as done in other archs) | ||
34 | * | ||
35 | * Revision 1.3 2002/11/05 06:45:13 starvik | ||
36 | * Merge of Linux 2.5.45 | ||
37 | * | ||
38 | * Revision 1.2 2001/12/18 13:35:22 bjornw | ||
39 | * Applied the 2.4.13->2.4.16 CRIS patch to 2.5.1 (is a copy of 2.4.15). | ||
40 | * | ||
41 | * Revision 1.31 2001/11/13 16:22:00 bjornw | ||
42 | * Skip calculating totalram and sharedram in si_meminfo | ||
43 | * | ||
44 | * Revision 1.30 2001/11/12 19:02:10 pkj | ||
45 | * Fixed compiler warnings. | ||
46 | * | ||
47 | * Revision 1.29 2001/07/25 16:09:50 bjornw | ||
48 | * val->sharedram will stay 0 | ||
49 | * | ||
50 | * Revision 1.28 2001/06/28 16:30:17 bjornw | ||
51 | * Oops. This needs to wait until 2.4.6 is merged | ||
52 | * | ||
53 | * Revision 1.27 2001/06/28 14:04:07 bjornw | ||
54 | * Fill in sharedram | ||
55 | * | ||
56 | * Revision 1.26 2001/06/18 06:36:02 hp | ||
57 | * Enable free_initmem of __init-type pages | ||
58 | * | ||
59 | * Revision 1.25 2001/06/13 00:02:23 bjornw | ||
60 | * Use a separate variable to store the current pgd to avoid races in schedule | ||
61 | * | ||
62 | * Revision 1.24 2001/05/15 00:52:20 hp | ||
63 | * Only map segment 0xa as seg if CONFIG_JULIETTE | ||
64 | * | ||
65 | * Revision 1.23 2001/04/04 14:35:40 bjornw | ||
66 | * * Removed get_pte_slow and friends (2.4.3 change) | ||
67 | * * Removed bad_pmd handling (2.4.3 change) | ||
68 | * | ||
69 | * Revision 1.22 2001/04/04 13:38:04 matsfg | ||
70 | * Moved ioremap to a separate function instead | ||
71 | * | ||
72 | * Revision 1.21 2001/03/27 09:28:33 bjornw | ||
73 | * ioremap used too early - lets try it in mem_init instead | ||
74 | * | ||
75 | * Revision 1.20 2001/03/23 07:39:21 starvik | ||
76 | * Corrected according to review remarks | ||
77 | * | ||
78 | * Revision 1.19 2001/03/15 14:25:17 bjornw | ||
79 | * More general shadow registers and ioremaped addresses for external I/O | ||
80 | * | ||
81 | * Revision 1.18 2001/02/23 12:46:44 bjornw | ||
82 | * * 0xc was not CSE1; 0x8 is, same as uncached flash, so we move the uncached | ||
83 | * flash during CRIS_LOW_MAP from 0xe to 0x8 so both the flash and the I/O | ||
84 | * is mapped straight over (for !CRIS_LOW_MAP the uncached flash is still 0xe) | ||
85 | * | ||
86 | * Revision 1.17 2001/02/22 15:05:21 bjornw | ||
87 | * Map 0x9 straight over during LOW_MAP to allow for memory mapped LEDs | ||
88 | * | ||
89 | * Revision 1.16 2001/02/22 15:02:35 bjornw | ||
90 | * Map 0xc straight over during LOW_MAP to allow for memory mapped I/O | ||
91 | * | ||
92 | * Revision 1.15 2001/01/10 21:12:10 bjornw | ||
93 | * loops_per_sec -> loops_per_jiffy | ||
94 | * | ||
95 | * Revision 1.14 2000/11/22 16:23:20 bjornw | ||
96 | * Initialize totalhigh counters to 0 to make /proc/meminfo look nice. | ||
97 | * | ||
98 | * Revision 1.13 2000/11/21 16:37:51 bjornw | ||
99 | * Temporarily disable initmem freeing | ||
100 | * | ||
101 | * Revision 1.12 2000/11/21 13:55:07 bjornw | ||
102 | * Use CONFIG_CRIS_LOW_MAP for the low VM map instead of explicit CPU type | ||
103 | * | ||
104 | * Revision 1.11 2000/10/06 12:38:22 bjornw | ||
105 | * Cast empty_bad_page correctly (should really be of * type from the start.. | ||
106 | * | ||
107 | * Revision 1.10 2000/10/04 16:53:57 bjornw | ||
108 | * Fix memory-map due to LX features | ||
109 | * | ||
110 | * Revision 1.9 2000/09/13 15:47:49 bjornw | ||
111 | * Wrong count in reserved-pages loop | ||
112 | * | ||
113 | * Revision 1.8 2000/09/13 14:35:10 bjornw | ||
114 | * 2.4.0-test8 added a new arg to free_area_init_node | ||
115 | * | ||
116 | * Revision 1.7 2000/08/17 15:35:55 bjornw | ||
117 | * 2.4.0-test6 removed MAP_NR and inserted virt_to_page | ||
118 | * | ||
119 | * | ||
120 | */ | ||
121 | |||
122 | #include <linux/init.h> | ||
123 | #include <linux/bootmem.h> | ||
124 | #include <asm/tlb.h> | ||
125 | |||
126 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | ||
127 | |||
128 | unsigned long empty_zero_page; | ||
129 | |||
130 | extern char _stext, _edata, _etext; /* From linkerscript */ | ||
131 | extern char __init_begin, __init_end; | ||
132 | |||
133 | void | ||
134 | show_mem(void) | ||
135 | { | ||
136 | int i,free = 0,total = 0,cached = 0, reserved = 0, nonshared = 0; | ||
137 | int shared = 0; | ||
138 | |||
139 | printk("\nMem-info:\n"); | ||
140 | show_free_areas(); | ||
141 | printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); | ||
142 | i = max_mapnr; | ||
143 | while (i-- > 0) { | ||
144 | total++; | ||
145 | if (PageReserved(mem_map+i)) | ||
146 | reserved++; | ||
147 | else if (PageSwapCache(mem_map+i)) | ||
148 | cached++; | ||
149 | else if (!page_count(mem_map+i)) | ||
150 | free++; | ||
151 | else if (page_count(mem_map+i) == 1) | ||
152 | nonshared++; | ||
153 | else | ||
154 | shared += page_count(mem_map+i) - 1; | ||
155 | } | ||
156 | printk("%d pages of RAM\n",total); | ||
157 | printk("%d free pages\n",free); | ||
158 | printk("%d reserved pages\n",reserved); | ||
159 | printk("%d pages nonshared\n",nonshared); | ||
160 | printk("%d pages shared\n",shared); | ||
161 | printk("%d pages swap cached\n",cached); | ||
162 | } | ||
163 | |||
164 | void __init | ||
165 | mem_init(void) | ||
166 | { | ||
167 | int codesize, reservedpages, datasize, initsize; | ||
168 | unsigned long tmp; | ||
169 | |||
170 | if(!mem_map) | ||
171 | BUG(); | ||
172 | |||
173 | /* max/min_low_pfn was set by setup.c | ||
174 | * now we just copy it to some other necessary places... | ||
175 | * | ||
176 | * high_memory was also set in setup.c | ||
177 | */ | ||
178 | |||
179 | max_mapnr = num_physpages = max_low_pfn - min_low_pfn; | ||
180 | |||
181 | /* this will put all memory onto the freelists */ | ||
182 | totalram_pages = free_all_bootmem(); | ||
183 | |||
184 | reservedpages = 0; | ||
185 | for (tmp = 0; tmp < max_mapnr; tmp++) { | ||
186 | /* | ||
187 | * Only count reserved RAM pages | ||
188 | */ | ||
189 | if (PageReserved(mem_map + tmp)) | ||
190 | reservedpages++; | ||
191 | } | ||
192 | |||
193 | codesize = (unsigned long) &_etext - (unsigned long) &_stext; | ||
194 | datasize = (unsigned long) &_edata - (unsigned long) &_etext; | ||
195 | initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; | ||
196 | |||
197 | printk(KERN_INFO | ||
198 | "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, " | ||
199 | "%dk init)\n" , | ||
200 | (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), | ||
201 | max_mapnr << (PAGE_SHIFT-10), | ||
202 | codesize >> 10, | ||
203 | reservedpages << (PAGE_SHIFT-10), | ||
204 | datasize >> 10, | ||
205 | initsize >> 10 | ||
206 | ); | ||
207 | } | ||
208 | |||
209 | /* free the pages occupied by initialization code */ | ||
210 | |||
211 | void | ||
212 | free_initmem(void) | ||
213 | { | ||
214 | unsigned long addr; | ||
215 | |||
216 | addr = (unsigned long)(&__init_begin); | ||
217 | for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { | ||
218 | ClearPageReserved(virt_to_page(addr)); | ||
219 | set_page_count(virt_to_page(addr), 1); | ||
220 | free_page(addr); | ||
221 | totalram_pages++; | ||
222 | } | ||
223 | printk (KERN_INFO "Freeing unused kernel memory: %luk freed\n", | ||
224 | (unsigned long)((&__init_end - &__init_begin) >> 10)); | ||
225 | } | ||
diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c new file mode 100644 index 000000000000..6b9130bfb6c1 --- /dev/null +++ b/arch/cris/mm/ioremap.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * arch/cris/mm/ioremap.c | ||
3 | * | ||
4 | * Re-map IO memory to kernel address space so that we can access it. | ||
5 | * Needed for memory-mapped I/O devices mapped outside our normal DRAM | ||
6 | * window (that is, all memory-mapped I/O devices). | ||
7 | * | ||
8 | * (C) Copyright 1995 1996 Linus Torvalds | ||
9 | * CRIS-port by Axis Communications AB | ||
10 | */ | ||
11 | |||
12 | #include <linux/vmalloc.h> | ||
13 | #include <asm/io.h> | ||
14 | #include <asm/pgalloc.h> | ||
15 | #include <asm/cacheflush.h> | ||
16 | #include <asm/tlbflush.h> | ||
17 | |||
18 | extern inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, | ||
19 | unsigned long phys_addr, unsigned long flags) | ||
20 | { | ||
21 | unsigned long end; | ||
22 | |||
23 | address &= ~PMD_MASK; | ||
24 | end = address + size; | ||
25 | if (end > PMD_SIZE) | ||
26 | end = PMD_SIZE; | ||
27 | if (address >= end) | ||
28 | BUG(); | ||
29 | do { | ||
30 | if (!pte_none(*pte)) { | ||
31 | printk("remap_area_pte: page already exists\n"); | ||
32 | BUG(); | ||
33 | } | ||
34 | set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | __READABLE | | ||
35 | __WRITEABLE | _PAGE_GLOBAL | | ||
36 | _PAGE_KERNEL | flags))); | ||
37 | address += PAGE_SIZE; | ||
38 | phys_addr += PAGE_SIZE; | ||
39 | pte++; | ||
40 | } while (address && (address < end)); | ||
41 | } | ||
42 | |||
43 | static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, | ||
44 | unsigned long phys_addr, unsigned long flags) | ||
45 | { | ||
46 | unsigned long end; | ||
47 | |||
48 | address &= ~PGDIR_MASK; | ||
49 | end = address + size; | ||
50 | if (end > PGDIR_SIZE) | ||
51 | end = PGDIR_SIZE; | ||
52 | phys_addr -= address; | ||
53 | if (address >= end) | ||
54 | BUG(); | ||
55 | do { | ||
56 | pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address); | ||
57 | if (!pte) | ||
58 | return -ENOMEM; | ||
59 | remap_area_pte(pte, address, end - address, address + phys_addr, flags); | ||
60 | address = (address + PMD_SIZE) & PMD_MASK; | ||
61 | pmd++; | ||
62 | } while (address && (address < end)); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int remap_area_pages(unsigned long address, unsigned long phys_addr, | ||
67 | unsigned long size, unsigned long flags) | ||
68 | { | ||
69 | int error; | ||
70 | pgd_t * dir; | ||
71 | unsigned long end = address + size; | ||
72 | |||
73 | phys_addr -= address; | ||
74 | dir = pgd_offset(&init_mm, address); | ||
75 | flush_cache_all(); | ||
76 | if (address >= end) | ||
77 | BUG(); | ||
78 | spin_lock(&init_mm.page_table_lock); | ||
79 | do { | ||
80 | pmd_t *pmd; | ||
81 | pmd = pmd_alloc(&init_mm, dir, address); | ||
82 | error = -ENOMEM; | ||
83 | if (!pmd) | ||
84 | break; | ||
85 | if (remap_area_pmd(pmd, address, end - address, | ||
86 | phys_addr + address, flags)) | ||
87 | break; | ||
88 | error = 0; | ||
89 | address = (address + PGDIR_SIZE) & PGDIR_MASK; | ||
90 | dir++; | ||
91 | } while (address && (address < end)); | ||
92 | spin_unlock(&init_mm.page_table_lock); | ||
93 | flush_tlb_all(); | ||
94 | return error; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Generic mapping function (not visible outside): | ||
99 | */ | ||
100 | |||
101 | /* | ||
102 | * Remap an arbitrary physical address space into the kernel virtual | ||
103 | * address space. Needed when the kernel wants to access high addresses | ||
104 | * directly. | ||
105 | * | ||
106 | * NOTE! We need to allow non-page-aligned mappings too: we will obviously | ||
107 | * have to convert them into an offset in a page-aligned mapping, but the | ||
108 | * caller shouldn't need to know that small detail. | ||
109 | */ | ||
110 | void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) | ||
111 | { | ||
112 | void * addr; | ||
113 | struct vm_struct * area; | ||
114 | unsigned long offset, last_addr; | ||
115 | |||
116 | /* Don't allow wraparound or zero size */ | ||
117 | last_addr = phys_addr + size - 1; | ||
118 | if (!size || last_addr < phys_addr) | ||
119 | return NULL; | ||
120 | |||
121 | /* | ||
122 | * Mappings have to be page-aligned | ||
123 | */ | ||
124 | offset = phys_addr & ~PAGE_MASK; | ||
125 | phys_addr &= PAGE_MASK; | ||
126 | size = PAGE_ALIGN(last_addr+1) - phys_addr; | ||
127 | |||
128 | /* | ||
129 | * Ok, go for it.. | ||
130 | */ | ||
131 | area = get_vm_area(size, VM_IOREMAP); | ||
132 | if (!area) | ||
133 | return NULL; | ||
134 | addr = area->addr; | ||
135 | if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) { | ||
136 | vfree(addr); | ||
137 | return NULL; | ||
138 | } | ||
139 | return (void *) (offset + (char *)addr); | ||
140 | } | ||
141 | |||
142 | void iounmap(void *addr) | ||
143 | { | ||
144 | if (addr > high_memory) | ||
145 | return vfree((void *) (PAGE_MASK & (unsigned long) addr)); | ||
146 | } | ||
diff --git a/arch/cris/mm/tlb.c b/arch/cris/mm/tlb.c new file mode 100644 index 000000000000..23eca5ad7389 --- /dev/null +++ b/arch/cris/mm/tlb.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/arch/cris/mm/tlb.c | ||
3 | * | ||
4 | * Copyright (C) 2000, 2001 Axis Communications AB | ||
5 | * | ||
6 | * Authors: Bjorn Wesen (bjornw@axis.com) | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <asm/tlb.h> | ||
12 | |||
13 | #define D(x) | ||
14 | |||
15 | /* The TLB can host up to 64 different mm contexts at the same time. | ||
16 | * The running context is R_MMU_CONTEXT, and each TLB entry contains a | ||
17 | * page_id that has to match to give a hit. In page_id_map, we keep track | ||
18 | * of which mm's we have assigned which page_id's, so that we know when | ||
19 | * to invalidate TLB entries. | ||
20 | * | ||
21 | * The last page_id is never running - it is used as an invalid page_id | ||
22 | * so we can make TLB entries that will never match. | ||
23 | * | ||
24 | * Notice that we need to make the flushes atomic, otherwise an interrupt | ||
25 | * handler that uses vmalloced memory might cause a TLB load in the middle | ||
26 | * of a flush causing. | ||
27 | */ | ||
28 | |||
29 | struct mm_struct *page_id_map[NUM_PAGEID]; | ||
30 | static int map_replace_ptr = 1; /* which page_id_map entry to replace next */ | ||
31 | |||
32 | /* | ||
33 | * Initialize the context related info for a new mm_struct | ||
34 | * instance. | ||
35 | */ | ||
36 | |||
37 | int | ||
38 | init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
39 | { | ||
40 | mm->context = NO_CONTEXT; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* the following functions are similar to those used in the PPC port */ | ||
45 | |||
46 | static inline void | ||
47 | alloc_context(struct mm_struct *mm) | ||
48 | { | ||
49 | struct mm_struct *old_mm; | ||
50 | |||
51 | D(printk("tlb: alloc context %d (%p)\n", map_replace_ptr, mm)); | ||
52 | |||
53 | /* did we replace an mm ? */ | ||
54 | |||
55 | old_mm = page_id_map[map_replace_ptr]; | ||
56 | |||
57 | if(old_mm) { | ||
58 | /* throw out any TLB entries belonging to the mm we replace | ||
59 | * in the map | ||
60 | */ | ||
61 | flush_tlb_mm(old_mm); | ||
62 | |||
63 | old_mm->context = NO_CONTEXT; | ||
64 | } | ||
65 | |||
66 | /* insert it into the page_id_map */ | ||
67 | |||
68 | mm->context = map_replace_ptr; | ||
69 | page_id_map[map_replace_ptr] = mm; | ||
70 | |||
71 | map_replace_ptr++; | ||
72 | |||
73 | if(map_replace_ptr == INVALID_PAGEID) | ||
74 | map_replace_ptr = 0; /* wrap around */ | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * if needed, get a new MMU context for the mm. otherwise nothing is done. | ||
79 | */ | ||
80 | |||
81 | void | ||
82 | get_mmu_context(struct mm_struct *mm) | ||
83 | { | ||
84 | if(mm->context == NO_CONTEXT) | ||
85 | alloc_context(mm); | ||
86 | } | ||
87 | |||
88 | /* called by __exit_mm to destroy the used MMU context if any before | ||
89 | * destroying the mm itself. this is only called when the last user of the mm | ||
90 | * drops it. | ||
91 | * | ||
92 | * the only thing we really need to do here is mark the used PID slot | ||
93 | * as empty. | ||
94 | */ | ||
95 | |||
96 | void | ||
97 | destroy_context(struct mm_struct *mm) | ||
98 | { | ||
99 | if(mm->context != NO_CONTEXT) { | ||
100 | D(printk("destroy_context %d (%p)\n", mm->context, mm)); | ||
101 | flush_tlb_mm(mm); /* TODO this might be redundant ? */ | ||
102 | page_id_map[mm->context] = NULL; | ||
103 | /* mm->context = NO_CONTEXT; redundant.. mm will be freed */ | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /* called once during VM initialization, from init.c */ | ||
108 | |||
109 | void __init | ||
110 | tlb_init(void) | ||
111 | { | ||
112 | int i; | ||
113 | |||
114 | /* clear the page_id map */ | ||
115 | |||
116 | for (i = 1; i < sizeof (page_id_map) / sizeof (page_id_map[0]); i++) | ||
117 | page_id_map[i] = NULL; | ||
118 | |||
119 | /* invalidate the entire TLB */ | ||
120 | |||
121 | flush_tlb_all(); | ||
122 | |||
123 | /* the init_mm has context 0 from the boot */ | ||
124 | |||
125 | page_id_map[0] = &init_mm; | ||
126 | } | ||