diff options
Diffstat (limited to 'arch/sparc')
147 files changed, 3353 insertions, 10813 deletions
diff --git a/arch/sparc/Kbuild b/arch/sparc/Kbuild new file mode 100644 index 000000000000..5cd01161fd00 --- /dev/null +++ b/arch/sparc/Kbuild | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # core part of the sparc kernel | ||
3 | # | ||
4 | |||
5 | obj-y += kernel/ | ||
6 | obj-y += mm/ | ||
7 | obj-y += math-emu/ | ||
8 | obj-y += net/ | ||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 6c0683d3fcba..1ea3fd954756 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -30,11 +30,14 @@ config SPARC | |||
30 | select USE_GENERIC_SMP_HELPERS if SMP | 30 | select USE_GENERIC_SMP_HELPERS if SMP |
31 | select GENERIC_PCI_IOMAP | 31 | select GENERIC_PCI_IOMAP |
32 | select HAVE_NMI_WATCHDOG if SPARC64 | 32 | select HAVE_NMI_WATCHDOG if SPARC64 |
33 | select HAVE_BPF_JIT | ||
34 | select GENERIC_SMP_IDLE_THREAD | ||
33 | 35 | ||
34 | config SPARC32 | 36 | config SPARC32 |
35 | def_bool !64BIT | 37 | def_bool !64BIT |
36 | select GENERIC_ATOMIC64 | 38 | select GENERIC_ATOMIC64 |
37 | select CLZ_TAB | 39 | select CLZ_TAB |
40 | select ARCH_THREAD_INFO_ALLOCATOR | ||
38 | 41 | ||
39 | config SPARC64 | 42 | config SPARC64 |
40 | def_bool 64BIT | 43 | def_bool 64BIT |
@@ -61,6 +64,7 @@ config SPARC64 | |||
61 | select IRQ_PREFLOW_FASTEOI | 64 | select IRQ_PREFLOW_FASTEOI |
62 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 65 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
63 | select HAVE_C_RECORDMCOUNT | 66 | select HAVE_C_RECORDMCOUNT |
67 | select NO_BOOTMEM | ||
64 | 68 | ||
65 | config ARCH_DEFCONFIG | 69 | config ARCH_DEFCONFIG |
66 | string | 70 | string |
@@ -73,17 +77,12 @@ config BITS | |||
73 | default 32 if SPARC32 | 77 | default 32 if SPARC32 |
74 | default 64 if SPARC64 | 78 | default 64 if SPARC64 |
75 | 79 | ||
76 | config ARCH_USES_GETTIMEOFFSET | ||
77 | bool | ||
78 | default y if SPARC32 | ||
79 | |||
80 | config GENERIC_CMOS_UPDATE | 80 | config GENERIC_CMOS_UPDATE |
81 | bool | 81 | bool |
82 | default y | 82 | default y |
83 | 83 | ||
84 | config GENERIC_CLOCKEVENTS | 84 | config GENERIC_CLOCKEVENTS |
85 | bool | 85 | def_bool y |
86 | default y if SPARC64 | ||
87 | 86 | ||
88 | config IOMMU_HELPER | 87 | config IOMMU_HELPER |
89 | bool | 88 | bool |
@@ -154,7 +153,7 @@ source "kernel/Kconfig.freezer" | |||
154 | menu "Processor type and features" | 153 | menu "Processor type and features" |
155 | 154 | ||
156 | config SMP | 155 | config SMP |
157 | bool "Symmetric multi-processing support (does not work on sun4/sun4c)" | 156 | bool "Symmetric multi-processing support" |
158 | ---help--- | 157 | ---help--- |
159 | This enables support for systems with more than one CPU. If you have | 158 | This enables support for systems with more than one CPU. If you have |
160 | a system with only one CPU, say N. If you have a system with more | 159 | a system with only one CPU, say N. If you have a system with more |
@@ -584,6 +583,9 @@ config SYSVIPC_COMPAT | |||
584 | depends on COMPAT && SYSVIPC | 583 | depends on COMPAT && SYSVIPC |
585 | default y | 584 | default y |
586 | 585 | ||
586 | config KEYS_COMPAT | ||
587 | def_bool y if COMPAT && KEYS | ||
588 | |||
587 | endmenu | 589 | endmenu |
588 | 590 | ||
589 | source "net/Kconfig" | 591 | source "net/Kconfig" |
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index eddcfb36aafb..541b8b075c7d 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile | |||
@@ -19,39 +19,27 @@ ifeq ($(CONFIG_SPARC32),y) | |||
19 | # sparc32 | 19 | # sparc32 |
20 | # | 20 | # |
21 | 21 | ||
22 | # | ||
23 | # Uncomment the first KBUILD_CFLAGS if you are doing kgdb source level | ||
24 | # debugging of the kernel to get the proper debugging information. | ||
25 | |||
26 | AS := $(AS) -32 | ||
27 | LDFLAGS := -m elf32_sparc | ||
28 | CHECKFLAGS += -D__sparc__ | 22 | CHECKFLAGS += -D__sparc__ |
23 | LDFLAGS := -m elf32_sparc | ||
29 | export BITS := 32 | 24 | export BITS := 32 |
30 | UTS_MACHINE := sparc | 25 | UTS_MACHINE := sparc |
31 | 26 | ||
32 | #KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7 | 27 | KBUILD_CFLAGS += -m32 -mcpu=v8 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 |
33 | KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7 | 28 | KBUILD_AFLAGS += -m32 -Wa,-Av8 |
34 | KBUILD_AFLAGS += -m32 -Wa,-Av8 | ||
35 | |||
36 | #LDFLAGS_vmlinux = -N -Ttext 0xf0004000 | ||
37 | # Since 2.5.40, the first stage is left not btfix-ed. | ||
38 | # Actual linking is done with "make image". | ||
39 | LDFLAGS_vmlinux = -r | ||
40 | 29 | ||
41 | else | 30 | else |
42 | ##### | 31 | ##### |
43 | # sparc64 | 32 | # sparc64 |
44 | # | 33 | # |
45 | 34 | ||
46 | CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64 | 35 | CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64 |
36 | LDFLAGS := -m elf64_sparc | ||
37 | export BITS := 64 | ||
38 | UTS_MACHINE := sparc64 | ||
47 | 39 | ||
48 | LDFLAGS := -m elf64_sparc | 40 | KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow |
49 | export BITS := 64 | 41 | KBUILD_CFLAGS += -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare |
50 | UTS_MACHINE := sparc64 | 42 | KBUILD_CFLAGS += -Wa,--undeclared-regs |
51 | |||
52 | KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \ | ||
53 | -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \ | ||
54 | -Wa,--undeclared-regs | ||
55 | KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3) | 43 | KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3) |
56 | KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs | 44 | KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs |
57 | 45 | ||
@@ -62,27 +50,15 @@ endif | |||
62 | endif | 50 | endif |
63 | 51 | ||
64 | head-y := arch/sparc/kernel/head_$(BITS).o | 52 | head-y := arch/sparc/kernel/head_$(BITS).o |
65 | head-y += arch/sparc/kernel/init_task.o | ||
66 | 53 | ||
67 | core-y += arch/sparc/kernel/ | 54 | # See arch/sparc/Kbuild for the core part of the kernel |
68 | core-y += arch/sparc/mm/ arch/sparc/math-emu/ | 55 | core-y += arch/sparc/ |
69 | 56 | ||
70 | libs-y += arch/sparc/prom/ | 57 | libs-y += arch/sparc/prom/ |
71 | libs-y += arch/sparc/lib/ | 58 | libs-y += arch/sparc/lib/ |
72 | 59 | ||
73 | drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ | 60 | drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ |
74 | 61 | ||
75 | # Export what is needed by arch/sparc/boot/Makefile | ||
76 | export VMLINUX_INIT VMLINUX_MAIN | ||
77 | VMLINUX_INIT := $(head-y) $(init-y) | ||
78 | VMLINUX_MAIN := $(core-y) kernel/ mm/ fs/ ipc/ security/ crypto/ block/ | ||
79 | VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y) | ||
80 | VMLINUX_MAIN += $(drivers-y) $(net-y) | ||
81 | |||
82 | ifdef CONFIG_KALLSYMS | ||
83 | export kallsyms.o := .tmp_kallsyms2.o | ||
84 | endif | ||
85 | |||
86 | boot := arch/sparc/boot | 62 | boot := arch/sparc/boot |
87 | 63 | ||
88 | # Default target | 64 | # Default target |
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile index d56d199c1aa8..6e63afb128d9 100644 --- a/arch/sparc/boot/Makefile +++ b/arch/sparc/boot/Makefile | |||
@@ -6,8 +6,8 @@ | |||
6 | ROOT_IMG := /usr/src/root.img | 6 | ROOT_IMG := /usr/src/root.img |
7 | ELFTOAOUT := elftoaout | 7 | ELFTOAOUT := elftoaout |
8 | 8 | ||
9 | hostprogs-y := piggyback btfixupprep | 9 | hostprogs-y := piggyback |
10 | targets := tftpboot.img btfix.o btfix.S image zImage vmlinux.aout | 10 | targets := tftpboot.img image zImage vmlinux.aout |
11 | clean-files := System.map | 11 | clean-files := System.map |
12 | 12 | ||
13 | quiet_cmd_elftoaout = ELFTOAOUT $@ | 13 | quiet_cmd_elftoaout = ELFTOAOUT $@ |
@@ -17,58 +17,9 @@ quiet_cmd_piggy = PIGGY $@ | |||
17 | quiet_cmd_strip = STRIP $@ | 17 | quiet_cmd_strip = STRIP $@ |
18 | cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start $< -o $@ | 18 | cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start $< -o $@ |
19 | 19 | ||
20 | ifeq ($(CONFIG_SPARC32),y) | ||
21 | quiet_cmd_btfix = BTFIX $@ | ||
22 | cmd_btfix = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@ | ||
23 | quiet_cmd_sysmap = SYSMAP $(obj)/System.map | ||
24 | cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap | ||
25 | quiet_cmd_image = LD $@ | ||
26 | cmd_image = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) -o $@ | ||
27 | |||
28 | define rule_image | ||
29 | $(if $($(quiet)cmd_image), \ | ||
30 | echo ' $($(quiet)cmd_image)' &&) \ | ||
31 | $(cmd_image); \ | ||
32 | $(if $($(quiet)cmd_sysmap), \ | ||
33 | echo ' $($(quiet)cmd_sysmap)' &&) \ | ||
34 | $(cmd_sysmap) $@ $(obj)/System.map; \ | ||
35 | if [ $$? -ne 0 ]; then \ | ||
36 | rm -f $@; \ | ||
37 | /bin/false; \ | ||
38 | fi; \ | ||
39 | echo 'cmd_$@ := $(cmd_image)' > $(@D)/.$(@F).cmd | ||
40 | endef | ||
41 | |||
42 | BTOBJS := $(patsubst %/, %/built-in.o, $(VMLINUX_INIT)) | ||
43 | BTLIBS := $(patsubst %/, %/built-in.o, $(VMLINUX_MAIN)) | ||
44 | LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds $(BTOBJS) \ | ||
45 | --start-group $(BTLIBS) --end-group \ | ||
46 | $(kallsyms.o) $(obj)/btfix.o | ||
47 | |||
48 | # Link the final image including btfixup'ed symbols. | ||
49 | # This is a replacement for the link done in the top-level Makefile. | ||
50 | # Note: No dependency on the prerequisite files since that would require | ||
51 | # make to try check if they are updated - and due to changes | ||
52 | # in gcc options (path for example) this would result in | ||
53 | # these files being recompiled for each build. | ||
54 | $(obj)/image: $(obj)/btfix.o FORCE | ||
55 | $(call if_changed_rule,image) | ||
56 | |||
57 | $(obj)/zImage: $(obj)/image | ||
58 | $(call if_changed,strip) | ||
59 | @echo ' kernel: $@ is ready' | ||
60 | |||
61 | $(obj)/btfix.S: $(obj)/btfixupprep vmlinux FORCE | ||
62 | $(call if_changed,btfix) | ||
63 | |||
64 | endif | ||
65 | |||
66 | ifeq ($(CONFIG_SPARC64),y) | 20 | ifeq ($(CONFIG_SPARC64),y) |
67 | 21 | ||
68 | # Actual linking | 22 | # Actual linking |
69 | $(obj)/image: vmlinux FORCE | ||
70 | $(call if_changed,strip) | ||
71 | @echo ' kernel: $@ is ready' | ||
72 | 23 | ||
73 | $(obj)/zImage: $(obj)/image | 24 | $(obj)/zImage: $(obj)/image |
74 | $(call if_changed,gzip) | 25 | $(call if_changed,gzip) |
@@ -79,6 +30,10 @@ $(obj)/vmlinux.aout: vmlinux FORCE | |||
79 | @echo ' kernel: $@ is ready' | 30 | @echo ' kernel: $@ is ready' |
80 | else | 31 | else |
81 | 32 | ||
33 | $(obj)/zImage: $(obj)/image | ||
34 | $(call if_changed,strip) | ||
35 | @echo ' kernel: $@ is ready' | ||
36 | |||
82 | # The following lines make a readable image for U-Boot. | 37 | # The following lines make a readable image for U-Boot. |
83 | # uImage - Binary file read by U-boot | 38 | # uImage - Binary file read by U-boot |
84 | # uImage.o - object file of uImage for loading with a | 39 | # uImage.o - object file of uImage for loading with a |
@@ -107,6 +62,10 @@ $(obj)/uImage: $(obj)/image.gz | |||
107 | 62 | ||
108 | endif | 63 | endif |
109 | 64 | ||
65 | $(obj)/image: vmlinux FORCE | ||
66 | $(call if_changed,strip) | ||
67 | @echo ' kernel: $@ is ready' | ||
68 | |||
110 | $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback System.map $(ROOT_IMG) FORCE | 69 | $(obj)/tftpboot.img: $(obj)/image $(obj)/piggyback System.map $(ROOT_IMG) FORCE |
111 | $(call if_changed,elftoaout) | 70 | $(call if_changed,elftoaout) |
112 | $(call if_changed,piggy) | 71 | $(call if_changed,piggy) |
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c deleted file mode 100644 index da031159e2b7..000000000000 --- a/arch/sparc/boot/btfixupprep.c +++ /dev/null | |||
@@ -1,386 +0,0 @@ | |||
1 | /* | ||
2 | Simple utility to prepare vmlinux image for sparc. | ||
3 | Resolves all BTFIXUP uses and settings and creates | ||
4 | a special .s object to link to the image. | ||
5 | |||
6 | Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2 of the License, or | ||
11 | (at your option) any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
21 | |||
22 | #include <stdio.h> | ||
23 | #include <string.h> | ||
24 | #include <ctype.h> | ||
25 | #include <errno.h> | ||
26 | #include <unistd.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <malloc.h> | ||
29 | |||
30 | #define MAXSYMS 1024 | ||
31 | |||
32 | static char *symtab = "SYMBOL TABLE:"; | ||
33 | static char *relrec = "RELOCATION RECORDS FOR ["; | ||
34 | static int rellen; | ||
35 | static int symlen; | ||
36 | int mode; | ||
37 | |||
38 | struct _btfixup; | ||
39 | |||
40 | typedef struct _btfixuprel { | ||
41 | char *sect; | ||
42 | unsigned long offset; | ||
43 | struct _btfixup *f; | ||
44 | int frel; | ||
45 | struct _btfixuprel *next; | ||
46 | } btfixuprel; | ||
47 | |||
48 | typedef struct _btfixup { | ||
49 | int type; | ||
50 | int setinitval; | ||
51 | unsigned int initval; | ||
52 | char *initvalstr; | ||
53 | char *name; | ||
54 | btfixuprel *rel; | ||
55 | } btfixup; | ||
56 | |||
57 | btfixup array[MAXSYMS]; | ||
58 | int last = 0; | ||
59 | char buffer[1024]; | ||
60 | unsigned long lastfoffset = -1; | ||
61 | unsigned long lastfrelno; | ||
62 | btfixup *lastf; | ||
63 | |||
64 | static void fatal(void) __attribute__((noreturn)); | ||
65 | static void fatal(void) | ||
66 | { | ||
67 | fprintf(stderr, "Malformed output from objdump\n%s\n", buffer); | ||
68 | exit(1); | ||
69 | } | ||
70 | |||
71 | static btfixup *find(int type, char *name) | ||
72 | { | ||
73 | int i; | ||
74 | for (i = 0; i < last; i++) { | ||
75 | if (array[i].type == type && !strcmp(array[i].name, name)) | ||
76 | return array + i; | ||
77 | } | ||
78 | array[last].type = type; | ||
79 | array[last].name = strdup(name); | ||
80 | array[last].setinitval = 0; | ||
81 | if (!array[last].name) fatal(); | ||
82 | array[last].rel = NULL; | ||
83 | last++; | ||
84 | if (last >= MAXSYMS) { | ||
85 | fprintf(stderr, "Ugh. Something strange. More than %d different BTFIXUP symbols\n", MAXSYMS); | ||
86 | exit(1); | ||
87 | } | ||
88 | return array + last - 1; | ||
89 | } | ||
90 | |||
91 | static void set_mode (char *buffer) | ||
92 | { | ||
93 | for (mode = 0;; mode++) | ||
94 | if (buffer[mode] < '0' || buffer[mode] > '9') | ||
95 | break; | ||
96 | if (mode != 8 && mode != 16) | ||
97 | fatal(); | ||
98 | } | ||
99 | |||
100 | |||
101 | int main(int argc,char **argv) | ||
102 | { | ||
103 | char *p, *q; | ||
104 | char *sect; | ||
105 | int i, j, k; | ||
106 | unsigned int initval; | ||
107 | int shift; | ||
108 | btfixup *f; | ||
109 | btfixuprel *r, **rr; | ||
110 | unsigned long offset; | ||
111 | char *initvalstr; | ||
112 | |||
113 | symlen = strlen(symtab); | ||
114 | while (fgets (buffer, 1024, stdin) != NULL) | ||
115 | if (!strncmp (buffer, symtab, symlen)) | ||
116 | goto main0; | ||
117 | fatal(); | ||
118 | main0: | ||
119 | rellen = strlen(relrec); | ||
120 | while (fgets (buffer, 1024, stdin) != NULL) | ||
121 | if (!strncmp (buffer, relrec, rellen)) | ||
122 | goto main1; | ||
123 | fatal(); | ||
124 | main1: | ||
125 | sect = malloc(strlen (buffer + rellen) + 1); | ||
126 | if (!sect) fatal(); | ||
127 | strcpy (sect, buffer + rellen); | ||
128 | p = strchr (sect, ']'); | ||
129 | if (!p) fatal(); | ||
130 | *p = 0; | ||
131 | if (fgets (buffer, 1024, stdin) == NULL) | ||
132 | fatal(); | ||
133 | while (fgets (buffer, 1024, stdin) != NULL) { | ||
134 | int nbase; | ||
135 | if (!strncmp (buffer, relrec, rellen)) | ||
136 | goto main1; | ||
137 | if (mode == 0) | ||
138 | set_mode (buffer); | ||
139 | p = strchr (buffer, '\n'); | ||
140 | if (p) *p = 0; | ||
141 | if (strlen (buffer) < 22+mode) | ||
142 | continue; | ||
143 | if (strncmp (buffer + mode, " R_SPARC_", 9)) | ||
144 | continue; | ||
145 | nbase = 27 - 8 + mode; | ||
146 | if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_') | ||
147 | continue; | ||
148 | switch (buffer[nbase+3]) { | ||
149 | case 'f': /* CALL */ | ||
150 | case 'b': /* BLACKBOX */ | ||
151 | case 's': /* SIMM13 */ | ||
152 | case 'a': /* HALF */ | ||
153 | case 'h': /* SETHI */ | ||
154 | case 'i': /* INT */ | ||
155 | break; | ||
156 | default: | ||
157 | continue; | ||
158 | } | ||
159 | p = strchr (buffer + nbase+5, '+'); | ||
160 | if (p) *p = 0; | ||
161 | shift = nbase + 5; | ||
162 | if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') { | ||
163 | shift = nbase + 6; | ||
164 | if (strcmp (sect, ".init.text")) { | ||
165 | fprintf(stderr, | ||
166 | "Wrong use of '%s' BTFIXUPSET in '%s' section.\n" | ||
167 | "BTFIXUPSET_CALL can be used only in" | ||
168 | " __init sections\n", | ||
169 | buffer + shift, sect); | ||
170 | exit(1); | ||
171 | } | ||
172 | } else if (buffer[nbase+4] != '_') | ||
173 | continue; | ||
174 | if (!strcmp (sect, ".text.exit")) | ||
175 | continue; | ||
176 | if (strcmp (sect, ".text") && | ||
177 | strcmp (sect, ".init.text") && | ||
178 | strcmp (sect, ".fixup") && | ||
179 | (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) { | ||
180 | if (buffer[nbase+3] == 'f') | ||
181 | fprintf(stderr, | ||
182 | "Wrong use of '%s' in '%s' section.\n" | ||
183 | " It can be used only in .text, .init.text," | ||
184 | " .fixup and __ksymtab\n", | ||
185 | buffer + shift, sect); | ||
186 | else | ||
187 | fprintf(stderr, | ||
188 | "Wrong use of '%s' in '%s' section.\n" | ||
189 | " It can be only used in .text, .init.text," | ||
190 | " and .fixup\n", buffer + shift, sect); | ||
191 | exit(1); | ||
192 | } | ||
193 | p = strstr (buffer + shift, "__btset_"); | ||
194 | if (p && buffer[nbase+4] == 's') { | ||
195 | fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer); | ||
196 | exit(1); | ||
197 | } | ||
198 | initval = 0; | ||
199 | initvalstr = NULL; | ||
200 | if (p) { | ||
201 | if (p[8] != '0' || p[9] != 'x') { | ||
202 | fprintf(stderr, "Pre-initialized values can be only initialized with hexadecimal constants starting 0x\n%s\n", buffer); | ||
203 | exit(1); | ||
204 | } | ||
205 | initval = strtoul(p + 10, &q, 16); | ||
206 | if (*q || !initval) { | ||
207 | fprintf(stderr, "Pre-initialized values can be only in the form name__btset_0xXXXXXXXX where X are hex digits.\nThey cannot be name__btset_0x00000000 though. Use BTFIXUPDEF_XX instead of BTFIXUPDEF_XX_INIT then.\n%s\n", buffer); | ||
208 | exit(1); | ||
209 | } | ||
210 | initvalstr = p + 10; | ||
211 | *p = 0; | ||
212 | } | ||
213 | f = find(buffer[nbase+3], buffer + shift); | ||
214 | if (buffer[nbase+4] == 's') | ||
215 | continue; | ||
216 | switch (buffer[nbase+3]) { | ||
217 | case 'f': | ||
218 | if (initval) { | ||
219 | fprintf(stderr, "Cannot use pre-initialized fixups for calls\n%s\n", buffer); | ||
220 | exit(1); | ||
221 | } | ||
222 | if (!strcmp (sect, "__ksymtab")) { | ||
223 | if (strncmp (buffer + mode+9, "32 ", 10)) { | ||
224 | fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer); | ||
225 | exit(1); | ||
226 | } | ||
227 | } else if (strncmp (buffer + mode+9, "WDISP30 ", 10) && | ||
228 | strncmp (buffer + mode+9, "HI22 ", 10) && | ||
229 | strncmp (buffer + mode+9, "LO10 ", 10)) { | ||
230 | fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer); | ||
231 | exit(1); | ||
232 | } | ||
233 | break; | ||
234 | case 'b': | ||
235 | if (initval) { | ||
236 | fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer); | ||
237 | exit(1); | ||
238 | } | ||
239 | if (strncmp (buffer + mode+9, "HI22 ", 10)) { | ||
240 | fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer); | ||
241 | exit(1); | ||
242 | } | ||
243 | break; | ||
244 | case 's': | ||
245 | if (initval + 0x1000 >= 0x2000) { | ||
246 | fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer); | ||
247 | exit(1); | ||
248 | } | ||
249 | if (strncmp (buffer + mode+9, "13 ", 10)) { | ||
250 | fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer); | ||
251 | exit(1); | ||
252 | } | ||
253 | break; | ||
254 | case 'a': | ||
255 | if (initval + 0x1000 >= 0x2000 && (initval & 0x3ff)) { | ||
256 | fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer); | ||
257 | exit(1); | ||
258 | } | ||
259 | if (strncmp (buffer + mode+9, "13 ", 10)) { | ||
260 | fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer); | ||
261 | exit(1); | ||
262 | } | ||
263 | break; | ||
264 | case 'h': | ||
265 | if (initval & 0x3ff) { | ||
266 | fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer); | ||
267 | exit(1); | ||
268 | } | ||
269 | if (strncmp (buffer + mode+9, "HI22 ", 10)) { | ||
270 | fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer); | ||
271 | exit(1); | ||
272 | } | ||
273 | break; | ||
274 | case 'i': | ||
275 | if (initval) { | ||
276 | fprintf(stderr, "Cannot use pre-initialized fixups for INT\n%s\n", buffer); | ||
277 | exit(1); | ||
278 | } | ||
279 | if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) { | ||
280 | fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer); | ||
281 | exit(1); | ||
282 | } | ||
283 | break; | ||
284 | } | ||
285 | if (!f->setinitval) { | ||
286 | f->initval = initval; | ||
287 | if (initvalstr) { | ||
288 | f->initvalstr = strdup(initvalstr); | ||
289 | if (!f->initvalstr) fatal(); | ||
290 | } | ||
291 | f->setinitval = 1; | ||
292 | } else if (f->initval != initval) { | ||
293 | fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer\n%s\n", | ||
294 | f->name, f->initvalstr ? : "0x00000000", buffer); | ||
295 | exit(1); | ||
296 | } else if (initval && strcmp(f->initvalstr, initvalstr)) { | ||
297 | fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer.\n" | ||
298 | "Initializers have to match literally as well.\n%s\n", | ||
299 | f->name, f->initvalstr, buffer); | ||
300 | exit(1); | ||
301 | } | ||
302 | offset = strtoul(buffer, &q, 16); | ||
303 | if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) { | ||
304 | fprintf(stderr, "Malformed relocation address in\n%s\n", buffer); | ||
305 | exit(1); | ||
306 | } | ||
307 | for (k = 0, r = f->rel, rr = &f->rel; r; rr = &r->next, r = r->next, k++) | ||
308 | if (r->offset == offset && !strcmp(r->sect, sect)) { | ||
309 | fprintf(stderr, "Ugh. One address has two relocation records\n"); | ||
310 | exit(1); | ||
311 | } | ||
312 | *rr = malloc(sizeof(btfixuprel)); | ||
313 | if (!*rr) fatal(); | ||
314 | (*rr)->offset = offset; | ||
315 | (*rr)->f = NULL; | ||
316 | if (buffer[nbase+3] == 'f') { | ||
317 | lastf = f; | ||
318 | lastfoffset = offset; | ||
319 | lastfrelno = k; | ||
320 | } else if (lastfoffset + 4 == offset) { | ||
321 | (*rr)->f = lastf; | ||
322 | (*rr)->frel = lastfrelno; | ||
323 | } | ||
324 | (*rr)->sect = sect; | ||
325 | (*rr)->next = NULL; | ||
326 | } | ||
327 | printf("! Generated by btfixupprep. Do not edit.\n\n"); | ||
328 | printf("\t.section\t\".data..init\",#alloc,#write\n\t.align\t4\n\n"); | ||
329 | printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n"); | ||
330 | for (i = 0; i < last; i++) { | ||
331 | f = array + i; | ||
332 | printf("\t.global\t___%cs_%s\n", f->type, f->name); | ||
333 | if (f->type == 'f') | ||
334 | printf("___%cs_%s:\n\t.word 0x%08x,0,0,", f->type, f->name, f->type << 24); | ||
335 | else | ||
336 | printf("___%cs_%s:\n\t.word 0x%08x,0,", f->type, f->name, f->type << 24); | ||
337 | for (j = 0, r = f->rel; r != NULL; j++, r = r->next); | ||
338 | if (j) | ||
339 | printf("%d\n\t.word\t", j * 2); | ||
340 | else | ||
341 | printf("0\n"); | ||
342 | for (r = f->rel, j--; r != NULL; j--, r = r->next) { | ||
343 | if (!strcmp (r->sect, ".text")) | ||
344 | printf ("_stext+0x%08lx", r->offset); | ||
345 | else if (!strcmp (r->sect, ".init.text")) | ||
346 | printf ("__init_begin+0x%08lx", r->offset); | ||
347 | else if (!strcmp (r->sect, "__ksymtab")) | ||
348 | printf ("__start___ksymtab+0x%08lx", r->offset); | ||
349 | else if (!strcmp (r->sect, ".fixup")) | ||
350 | printf ("__start___fixup+0x%08lx", r->offset); | ||
351 | else | ||
352 | fatal(); | ||
353 | if (f->type == 'f' || !r->f) | ||
354 | printf (",0"); | ||
355 | else | ||
356 | printf (",___fs_%s+0x%08x", r->f->name, (4 + r->frel*2)*4 + 4); | ||
357 | if (j) printf (","); | ||
358 | else printf ("\n"); | ||
359 | } | ||
360 | printf("\n"); | ||
361 | } | ||
362 | printf("\n\t.global\t___btfixup_end\n___btfixup_end:\n"); | ||
363 | printf("\n\n! Define undefined references\n\n"); | ||
364 | for (i = 0; i < last; i++) { | ||
365 | f = array + i; | ||
366 | if (f->type == 'f') { | ||
367 | printf("\t.global\t___f_%s\n", f->name); | ||
368 | printf("___f_%s:\n", f->name); | ||
369 | } | ||
370 | } | ||
371 | printf("\tretl\n\t nop\n\n"); | ||
372 | for (i = 0; i < last; i++) { | ||
373 | f = array + i; | ||
374 | if (f->type != 'f') { | ||
375 | if (!f->initval) { | ||
376 | printf("\t.global\t___%c_%s\n", f->type, f->name); | ||
377 | printf("___%c_%s = 0\n", f->type, f->name); | ||
378 | } else { | ||
379 | printf("\t.global\t___%c_%s__btset_0x%s\n", f->type, f->name, f->initvalstr); | ||
380 | printf("___%c_%s__btset_0x%s = 0x%08x\n", f->type, f->name, f->initvalstr, f->initval); | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | printf("\n\n"); | ||
385 | exit(0); | ||
386 | } | ||
diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/asm/asi.h index b2e3db63a64b..cbb93e5141de 100644 --- a/arch/sparc/include/asm/asi.h +++ b/arch/sparc/include/asm/asi.h | |||
@@ -112,6 +112,20 @@ | |||
112 | 112 | ||
113 | #define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */ | 113 | #define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */ |
114 | 114 | ||
115 | /* LEON ASI */ | ||
116 | #define ASI_LEON_NOCACHE 0x01 | ||
117 | |||
118 | #define ASI_LEON_DCACHE_MISS 0x01 | ||
119 | |||
120 | #define ASI_LEON_CACHEREGS 0x02 | ||
121 | #define ASI_LEON_IFLUSH 0x10 | ||
122 | #define ASI_LEON_DFLUSH 0x11 | ||
123 | |||
124 | #define ASI_LEON_MMUFLUSH 0x18 | ||
125 | #define ASI_LEON_MMUREGS 0x19 | ||
126 | #define ASI_LEON_BYPASS 0x1c | ||
127 | #define ASI_LEON_FLUSH_PAGE 0x10 | ||
128 | |||
115 | /* V9 Architecture mandary ASIs. */ | 129 | /* V9 Architecture mandary ASIs. */ |
116 | #define ASI_N 0x04 /* Nucleus */ | 130 | #define ASI_N 0x04 /* Nucleus */ |
117 | #define ASI_NL 0x0c /* Nucleus, little endian */ | 131 | #define ASI_NL 0x0c /* Nucleus, little endian */ |
diff --git a/arch/sparc/include/asm/asmmacro.h b/arch/sparc/include/asm/asmmacro.h index a995bf8aba3f..02a172fb193a 100644 --- a/arch/sparc/include/asm/asmmacro.h +++ b/arch/sparc/include/asm/asmmacro.h | |||
@@ -6,17 +6,6 @@ | |||
6 | #ifndef _SPARC_ASMMACRO_H | 6 | #ifndef _SPARC_ASMMACRO_H |
7 | #define _SPARC_ASMMACRO_H | 7 | #define _SPARC_ASMMACRO_H |
8 | 8 | ||
9 | #include <asm/btfixup.h> | ||
10 | #include <asm/asi.h> | ||
11 | |||
12 | #define GET_PROCESSOR4M_ID(reg) \ | ||
13 | rd %tbr, %reg; \ | ||
14 | srl %reg, 12, %reg; \ | ||
15 | and %reg, 3, %reg; | ||
16 | |||
17 | #define GET_PROCESSOR4D_ID(reg) \ | ||
18 | lda [%g0] ASI_M_VIKING_TMP1, %reg; | ||
19 | |||
20 | /* All trap entry points _must_ begin with this macro or else you | 9 | /* All trap entry points _must_ begin with this macro or else you |
21 | * lose. It makes sure the kernel has a proper window so that | 10 | * lose. It makes sure the kernel has a proper window so that |
22 | * c-code can be called. | 11 | * c-code can be called. |
@@ -31,10 +20,4 @@ | |||
31 | /* All traps low-level code here must end with this macro. */ | 20 | /* All traps low-level code here must end with this macro. */ |
32 | #define RESTORE_ALL b ret_trap_entry; clr %l6; | 21 | #define RESTORE_ALL b ret_trap_entry; clr %l6; |
33 | 22 | ||
34 | /* sun4 probably wants half word accesses to ASI_SEGMAP, while sun4c+ | ||
35 | likes byte accesses. These are to avoid ifdef mania. */ | ||
36 | |||
37 | #define lduXa lduba | ||
38 | #define stXa stba | ||
39 | |||
40 | #endif /* !(_SPARC_ASMMACRO_H) */ | 23 | #endif /* !(_SPARC_ASMMACRO_H) */ |
diff --git a/arch/sparc/include/asm/btfixup.h b/arch/sparc/include/asm/btfixup.h deleted file mode 100644 index 797722cf69f2..000000000000 --- a/arch/sparc/include/asm/btfixup.h +++ /dev/null | |||
@@ -1,208 +0,0 @@ | |||
1 | /* | ||
2 | * asm/btfixup.h: Macros for boot time linking. | ||
3 | * | ||
4 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
5 | */ | ||
6 | |||
7 | #ifndef _SPARC_BTFIXUP_H | ||
8 | #define _SPARC_BTFIXUP_H | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | |||
12 | #ifndef __ASSEMBLY__ | ||
13 | |||
14 | #ifdef MODULE | ||
15 | extern unsigned int ___illegal_use_of_BTFIXUP_SIMM13_in_module(void); | ||
16 | extern unsigned int ___illegal_use_of_BTFIXUP_SETHI_in_module(void); | ||
17 | extern unsigned int ___illegal_use_of_BTFIXUP_HALF_in_module(void); | ||
18 | extern unsigned int ___illegal_use_of_BTFIXUP_INT_in_module(void); | ||
19 | |||
20 | #define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module() | ||
21 | #define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module() | ||
22 | #define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module() | ||
23 | #define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module() | ||
24 | #define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module | ||
25 | |||
26 | #else | ||
27 | |||
28 | #define BTFIXUP_SIMM13(__name) ___sf_##__name() | ||
29 | #define BTFIXUP_HALF(__name) ___af_##__name() | ||
30 | #define BTFIXUP_SETHI(__name) ___hf_##__name() | ||
31 | #define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name) | ||
32 | /* This must be written in assembly and present in a sethi */ | ||
33 | #define BTFIXUP_BLACKBOX(__name) ___b_##__name | ||
34 | #endif /* MODULE */ | ||
35 | |||
36 | /* Fixup call xx */ | ||
37 | |||
38 | #define BTFIXUPDEF_CALL(__type, __name, __args...) \ | ||
39 | extern __type ___f_##__name(__args); \ | ||
40 | extern unsigned ___fs_##__name[3]; | ||
41 | #define BTFIXUPDEF_CALL_CONST(__type, __name, __args...) \ | ||
42 | extern __type ___f_##__name(__args) __attribute_const__; \ | ||
43 | extern unsigned ___fs_##__name[3]; | ||
44 | #define BTFIXUP_CALL(__name) ___f_##__name | ||
45 | |||
46 | #define BTFIXUPDEF_BLACKBOX(__name) \ | ||
47 | extern unsigned ___bs_##__name[2]; | ||
48 | |||
49 | /* Put bottom 13bits into some register variable */ | ||
50 | |||
51 | #define BTFIXUPDEF_SIMM13(__name) \ | ||
52 | static inline unsigned int ___sf_##__name(void) __attribute_const__; \ | ||
53 | extern unsigned ___ss_##__name[2]; \ | ||
54 | static inline unsigned int ___sf_##__name(void) { \ | ||
55 | unsigned int ret; \ | ||
56 | __asm__ ("or %%g0, ___s_" #__name ", %0" : "=r"(ret)); \ | ||
57 | return ret; \ | ||
58 | } | ||
59 | #define BTFIXUPDEF_SIMM13_INIT(__name,__val) \ | ||
60 | static inline unsigned int ___sf_##__name(void) __attribute_const__; \ | ||
61 | extern unsigned ___ss_##__name[2]; \ | ||
62 | static inline unsigned int ___sf_##__name(void) { \ | ||
63 | unsigned int ret; \ | ||
64 | __asm__ ("or %%g0, ___s_" #__name "__btset_" #__val ", %0" : "=r"(ret));\ | ||
65 | return ret; \ | ||
66 | } | ||
67 | |||
68 | /* Put either bottom 13 bits, or upper 22 bits into some register variable | ||
69 | * (depending on the value, this will lead into sethi FIX, reg; or | ||
70 | * mov FIX, reg; ) | ||
71 | */ | ||
72 | |||
73 | #define BTFIXUPDEF_HALF(__name) \ | ||
74 | static inline unsigned int ___af_##__name(void) __attribute_const__; \ | ||
75 | extern unsigned ___as_##__name[2]; \ | ||
76 | static inline unsigned int ___af_##__name(void) { \ | ||
77 | unsigned int ret; \ | ||
78 | __asm__ ("or %%g0, ___a_" #__name ", %0" : "=r"(ret)); \ | ||
79 | return ret; \ | ||
80 | } | ||
81 | #define BTFIXUPDEF_HALF_INIT(__name,__val) \ | ||
82 | static inline unsigned int ___af_##__name(void) __attribute_const__; \ | ||
83 | extern unsigned ___as_##__name[2]; \ | ||
84 | static inline unsigned int ___af_##__name(void) { \ | ||
85 | unsigned int ret; \ | ||
86 | __asm__ ("or %%g0, ___a_" #__name "__btset_" #__val ", %0" : "=r"(ret));\ | ||
87 | return ret; \ | ||
88 | } | ||
89 | |||
90 | /* Put upper 22 bits into some register variable */ | ||
91 | |||
92 | #define BTFIXUPDEF_SETHI(__name) \ | ||
93 | static inline unsigned int ___hf_##__name(void) __attribute_const__; \ | ||
94 | extern unsigned ___hs_##__name[2]; \ | ||
95 | static inline unsigned int ___hf_##__name(void) { \ | ||
96 | unsigned int ret; \ | ||
97 | __asm__ ("sethi %%hi(___h_" #__name "), %0" : "=r"(ret)); \ | ||
98 | return ret; \ | ||
99 | } | ||
100 | #define BTFIXUPDEF_SETHI_INIT(__name,__val) \ | ||
101 | static inline unsigned int ___hf_##__name(void) __attribute_const__; \ | ||
102 | extern unsigned ___hs_##__name[2]; \ | ||
103 | static inline unsigned int ___hf_##__name(void) { \ | ||
104 | unsigned int ret; \ | ||
105 | __asm__ ("sethi %%hi(___h_" #__name "__btset_" #__val "), %0" : \ | ||
106 | "=r"(ret)); \ | ||
107 | return ret; \ | ||
108 | } | ||
109 | |||
110 | /* Put a full 32bit integer into some register variable */ | ||
111 | |||
112 | #define BTFIXUPDEF_INT(__name) \ | ||
113 | extern unsigned char ___i_##__name; \ | ||
114 | extern unsigned ___is_##__name[2]; | ||
115 | |||
116 | #define BTFIXUPCALL_NORM 0x00000000 /* Always call */ | ||
117 | #define BTFIXUPCALL_NOP 0x01000000 /* Possibly optimize to nop */ | ||
118 | #define BTFIXUPCALL_RETINT(i) (0x90102000|((i) & 0x1fff)) /* Possibly optimize to mov i, %o0 */ | ||
119 | #define BTFIXUPCALL_ORINT(i) (0x90122000|((i) & 0x1fff)) /* Possibly optimize to or %o0, i, %o0 */ | ||
120 | #define BTFIXUPCALL_RETO0 0x01000000 /* Return first parameter, actually a nop */ | ||
121 | #define BTFIXUPCALL_ANDNINT(i) (0x902a2000|((i) & 0x1fff)) /* Possibly optimize to andn %o0, i, %o0 */ | ||
122 | #define BTFIXUPCALL_SWAPO0O1 0xd27a0000 /* Possibly optimize to swap [%o0],%o1 */ | ||
123 | #define BTFIXUPCALL_SWAPO0G0 0xc07a0000 /* Possibly optimize to swap [%o0],%g0 */ | ||
124 | #define BTFIXUPCALL_SWAPG1G2 0xc4784000 /* Possibly optimize to swap [%g1],%g2 */ | ||
125 | #define BTFIXUPCALL_STG0O0 0xc0220000 /* Possibly optimize to st %g0,[%o0] */ | ||
126 | #define BTFIXUPCALL_STO1O0 0xd2220000 /* Possibly optimize to st %o1,[%o0] */ | ||
127 | |||
128 | #define BTFIXUPSET_CALL(__name, __addr, __insn) \ | ||
129 | do { \ | ||
130 | ___fs_##__name[0] |= 1; \ | ||
131 | ___fs_##__name[1] = (unsigned long)__addr; \ | ||
132 | ___fs_##__name[2] = __insn; \ | ||
133 | } while (0) | ||
134 | |||
135 | #define BTFIXUPSET_BLACKBOX(__name, __func) \ | ||
136 | do { \ | ||
137 | ___bs_##__name[0] |= 1; \ | ||
138 | ___bs_##__name[1] = (unsigned long)__func; \ | ||
139 | } while (0) | ||
140 | |||
141 | #define BTFIXUPCOPY_CALL(__name, __from) \ | ||
142 | do { \ | ||
143 | ___fs_##__name[0] |= 1; \ | ||
144 | ___fs_##__name[1] = ___fs_##__from[1]; \ | ||
145 | ___fs_##__name[2] = ___fs_##__from[2]; \ | ||
146 | } while (0) | ||
147 | |||
148 | #define BTFIXUPSET_SIMM13(__name, __val) \ | ||
149 | do { \ | ||
150 | ___ss_##__name[0] |= 1; \ | ||
151 | ___ss_##__name[1] = (unsigned)__val; \ | ||
152 | } while (0) | ||
153 | |||
154 | #define BTFIXUPCOPY_SIMM13(__name, __from) \ | ||
155 | do { \ | ||
156 | ___ss_##__name[0] |= 1; \ | ||
157 | ___ss_##__name[1] = ___ss_##__from[1]; \ | ||
158 | } while (0) | ||
159 | |||
160 | #define BTFIXUPSET_HALF(__name, __val) \ | ||
161 | do { \ | ||
162 | ___as_##__name[0] |= 1; \ | ||
163 | ___as_##__name[1] = (unsigned)__val; \ | ||
164 | } while (0) | ||
165 | |||
166 | #define BTFIXUPCOPY_HALF(__name, __from) \ | ||
167 | do { \ | ||
168 | ___as_##__name[0] |= 1; \ | ||
169 | ___as_##__name[1] = ___as_##__from[1]; \ | ||
170 | } while (0) | ||
171 | |||
172 | #define BTFIXUPSET_SETHI(__name, __val) \ | ||
173 | do { \ | ||
174 | ___hs_##__name[0] |= 1; \ | ||
175 | ___hs_##__name[1] = (unsigned)__val; \ | ||
176 | } while (0) | ||
177 | |||
178 | #define BTFIXUPCOPY_SETHI(__name, __from) \ | ||
179 | do { \ | ||
180 | ___hs_##__name[0] |= 1; \ | ||
181 | ___hs_##__name[1] = ___hs_##__from[1]; \ | ||
182 | } while (0) | ||
183 | |||
184 | #define BTFIXUPSET_INT(__name, __val) \ | ||
185 | do { \ | ||
186 | ___is_##__name[0] |= 1; \ | ||
187 | ___is_##__name[1] = (unsigned)__val; \ | ||
188 | } while (0) | ||
189 | |||
190 | #define BTFIXUPCOPY_INT(__name, __from) \ | ||
191 | do { \ | ||
192 | ___is_##__name[0] |= 1; \ | ||
193 | ___is_##__name[1] = ___is_##__from[1]; \ | ||
194 | } while (0) | ||
195 | |||
196 | #define BTFIXUPVAL_CALL(__name) \ | ||
197 | ((unsigned long)___fs_##__name[1]) | ||
198 | |||
199 | extern void btfixup(void); | ||
200 | |||
201 | #else /* __ASSEMBLY__ */ | ||
202 | |||
203 | #define BTFIXUP_SETHI(__name) %hi(___h_ ## __name) | ||
204 | #define BTFIXUP_SETHI_INIT(__name,__val) %hi(___h_ ## __name ## __btset_ ## __val) | ||
205 | |||
206 | #endif /* __ASSEMBLY__ */ | ||
207 | |||
208 | #endif /* !(_SPARC_BTFIXUP_H) */ | ||
diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h index 69358b590c91..5bb6991b4857 100644 --- a/arch/sparc/include/asm/cache.h +++ b/arch/sparc/include/asm/cache.h | |||
@@ -22,118 +22,4 @@ | |||
22 | 22 | ||
23 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) | 23 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) |
24 | 24 | ||
25 | #ifdef CONFIG_SPARC32 | ||
26 | #include <asm/asi.h> | ||
27 | |||
28 | /* Direct access to the instruction cache is provided through and | ||
29 | * alternate address space. The IDC bit must be off in the ICCR on | ||
30 | * HyperSparcs for these accesses to work. The code below does not do | ||
31 | * any checking, the caller must do so. These routines are for | ||
32 | * diagnostics only, but could end up being useful. Use with care. | ||
33 | * Also, you are asking for trouble if you execute these in one of the | ||
34 | * three instructions following a %asr/%psr access or modification. | ||
35 | */ | ||
36 | |||
37 | /* First, cache-tag access. */ | ||
38 | static inline unsigned int get_icache_tag(int setnum, int tagnum) | ||
39 | { | ||
40 | unsigned int vaddr, retval; | ||
41 | |||
42 | vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5); | ||
43 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
44 | "=r" (retval) : | ||
45 | "r" (vaddr), "i" (ASI_M_TXTC_TAG)); | ||
46 | return retval; | ||
47 | } | ||
48 | |||
49 | static inline void put_icache_tag(int setnum, int tagnum, unsigned int entry) | ||
50 | { | ||
51 | unsigned int vaddr; | ||
52 | |||
53 | vaddr = ((setnum&1) << 12) | ((tagnum&0x7f) << 5); | ||
54 | __asm__ __volatile__("sta %0, [%1] %2\n\t" : : | ||
55 | "r" (entry), "r" (vaddr), "i" (ASI_M_TXTC_TAG) : | ||
56 | "memory"); | ||
57 | } | ||
58 | |||
59 | /* Second cache-data access. The data is returned two-32bit quantities | ||
60 | * at a time. | ||
61 | */ | ||
62 | static inline void get_icache_data(int setnum, int tagnum, int subblock, | ||
63 | unsigned int *data) | ||
64 | { | ||
65 | unsigned int value1, value2, vaddr; | ||
66 | |||
67 | vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | | ||
68 | ((subblock&0x3) << 3); | ||
69 | __asm__ __volatile__("ldda [%2] %3, %%g2\n\t" | ||
70 | "or %%g0, %%g2, %0\n\t" | ||
71 | "or %%g0, %%g3, %1\n\t" : | ||
72 | "=r" (value1), "=r" (value2) : | ||
73 | "r" (vaddr), "i" (ASI_M_TXTC_DATA) : | ||
74 | "g2", "g3"); | ||
75 | data[0] = value1; data[1] = value2; | ||
76 | } | ||
77 | |||
78 | static inline void put_icache_data(int setnum, int tagnum, int subblock, | ||
79 | unsigned int *data) | ||
80 | { | ||
81 | unsigned int value1, value2, vaddr; | ||
82 | |||
83 | vaddr = ((setnum&0x1) << 12) | ((tagnum&0x7f) << 5) | | ||
84 | ((subblock&0x3) << 3); | ||
85 | value1 = data[0]; value2 = data[1]; | ||
86 | __asm__ __volatile__("or %%g0, %0, %%g2\n\t" | ||
87 | "or %%g0, %1, %%g3\n\t" | ||
88 | "stda %%g2, [%2] %3\n\t" : : | ||
89 | "r" (value1), "r" (value2), | ||
90 | "r" (vaddr), "i" (ASI_M_TXTC_DATA) : | ||
91 | "g2", "g3", "memory" /* no joke */); | ||
92 | } | ||
93 | |||
94 | /* Different types of flushes with the ICACHE. Some of the flushes | ||
95 | * affect both the ICACHE and the external cache. Others only clear | ||
96 | * the ICACHE entries on the cpu itself. V8's (most) allow | ||
97 | * granularity of flushes on the packet (element in line), whole line, | ||
98 | * and entire cache (ie. all lines) level. The ICACHE only flushes are | ||
99 | * ROSS HyperSparc specific and are in ross.h | ||
100 | */ | ||
101 | |||
102 | /* Flushes which clear out both the on-chip and external caches */ | ||
103 | static inline void flush_ei_page(unsigned int addr) | ||
104 | { | ||
105 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
106 | "r" (addr), "i" (ASI_M_FLUSH_PAGE) : | ||
107 | "memory"); | ||
108 | } | ||
109 | |||
110 | static inline void flush_ei_seg(unsigned int addr) | ||
111 | { | ||
112 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
113 | "r" (addr), "i" (ASI_M_FLUSH_SEG) : | ||
114 | "memory"); | ||
115 | } | ||
116 | |||
117 | static inline void flush_ei_region(unsigned int addr) | ||
118 | { | ||
119 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
120 | "r" (addr), "i" (ASI_M_FLUSH_REGION) : | ||
121 | "memory"); | ||
122 | } | ||
123 | |||
124 | static inline void flush_ei_ctx(unsigned int addr) | ||
125 | { | ||
126 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
127 | "r" (addr), "i" (ASI_M_FLUSH_CTX) : | ||
128 | "memory"); | ||
129 | } | ||
130 | |||
131 | static inline void flush_ei_user(unsigned int addr) | ||
132 | { | ||
133 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
134 | "r" (addr), "i" (ASI_M_FLUSH_USER) : | ||
135 | "memory"); | ||
136 | } | ||
137 | #endif /* CONFIG_SPARC32 */ | ||
138 | |||
139 | #endif /* !(_SPARC_CACHE_H) */ | 25 | #endif /* !(_SPARC_CACHE_H) */ |
diff --git a/arch/sparc/include/asm/cacheflush.h b/arch/sparc/include/asm/cacheflush.h index 049168087b19..f6c4839b8388 100644 --- a/arch/sparc/include/asm/cacheflush.h +++ b/arch/sparc/include/asm/cacheflush.h | |||
@@ -1,5 +1,9 @@ | |||
1 | #ifndef ___ASM_SPARC_CACHEFLUSH_H | 1 | #ifndef ___ASM_SPARC_CACHEFLUSH_H |
2 | #define ___ASM_SPARC_CACHEFLUSH_H | 2 | #define ___ASM_SPARC_CACHEFLUSH_H |
3 | |||
4 | /* flush addr - to allow use of self-modifying code */ | ||
5 | #define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") | ||
6 | |||
3 | #if defined(__sparc__) && defined(__arch64__) | 7 | #if defined(__sparc__) && defined(__arch64__) |
4 | #include <asm/cacheflush_64.h> | 8 | #include <asm/cacheflush_64.h> |
5 | #else | 9 | #else |
diff --git a/arch/sparc/include/asm/cacheflush_32.h b/arch/sparc/include/asm/cacheflush_32.h index 68431b47a22a..bb014c24f318 100644 --- a/arch/sparc/include/asm/cacheflush_32.h +++ b/arch/sparc/include/asm/cacheflush_32.h | |||
@@ -1,56 +1,18 @@ | |||
1 | #ifndef _SPARC_CACHEFLUSH_H | 1 | #ifndef _SPARC_CACHEFLUSH_H |
2 | #define _SPARC_CACHEFLUSH_H | 2 | #define _SPARC_CACHEFLUSH_H |
3 | 3 | ||
4 | #include <linux/mm.h> /* Common for other includes */ | 4 | #include <asm/cachetlb_32.h> |
5 | // #include <linux/kernel.h> from pgalloc.h | 5 | |
6 | // #include <linux/sched.h> from pgalloc.h | 6 | #define flush_cache_all() \ |
7 | 7 | sparc32_cachetlb_ops->cache_all() | |
8 | // #include <asm/page.h> | 8 | #define flush_cache_mm(mm) \ |
9 | #include <asm/btfixup.h> | 9 | sparc32_cachetlb_ops->cache_mm(mm) |
10 | 10 | #define flush_cache_dup_mm(mm) \ | |
11 | /* | 11 | sparc32_cachetlb_ops->cache_mm(mm) |
12 | * Fine grained cache flushing. | 12 | #define flush_cache_range(vma,start,end) \ |
13 | */ | 13 | sparc32_cachetlb_ops->cache_range(vma, start, end) |
14 | #ifdef CONFIG_SMP | 14 | #define flush_cache_page(vma,addr,pfn) \ |
15 | 15 | sparc32_cachetlb_ops->cache_page(vma, addr) | |
16 | BTFIXUPDEF_CALL(void, local_flush_cache_all, void) | ||
17 | BTFIXUPDEF_CALL(void, local_flush_cache_mm, struct mm_struct *) | ||
18 | BTFIXUPDEF_CALL(void, local_flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long) | ||
19 | BTFIXUPDEF_CALL(void, local_flush_cache_page, struct vm_area_struct *, unsigned long) | ||
20 | |||
21 | #define local_flush_cache_all() BTFIXUP_CALL(local_flush_cache_all)() | ||
22 | #define local_flush_cache_mm(mm) BTFIXUP_CALL(local_flush_cache_mm)(mm) | ||
23 | #define local_flush_cache_range(vma,start,end) BTFIXUP_CALL(local_flush_cache_range)(vma,start,end) | ||
24 | #define local_flush_cache_page(vma,addr) BTFIXUP_CALL(local_flush_cache_page)(vma,addr) | ||
25 | |||
26 | BTFIXUPDEF_CALL(void, local_flush_page_to_ram, unsigned long) | ||
27 | BTFIXUPDEF_CALL(void, local_flush_sig_insns, struct mm_struct *, unsigned long) | ||
28 | |||
29 | #define local_flush_page_to_ram(addr) BTFIXUP_CALL(local_flush_page_to_ram)(addr) | ||
30 | #define local_flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(local_flush_sig_insns)(mm,insn_addr) | ||
31 | |||
32 | extern void smp_flush_cache_all(void); | ||
33 | extern void smp_flush_cache_mm(struct mm_struct *mm); | ||
34 | extern void smp_flush_cache_range(struct vm_area_struct *vma, | ||
35 | unsigned long start, | ||
36 | unsigned long end); | ||
37 | extern void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page); | ||
38 | |||
39 | extern void smp_flush_page_to_ram(unsigned long page); | ||
40 | extern void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr); | ||
41 | |||
42 | #endif /* CONFIG_SMP */ | ||
43 | |||
44 | BTFIXUPDEF_CALL(void, flush_cache_all, void) | ||
45 | BTFIXUPDEF_CALL(void, flush_cache_mm, struct mm_struct *) | ||
46 | BTFIXUPDEF_CALL(void, flush_cache_range, struct vm_area_struct *, unsigned long, unsigned long) | ||
47 | BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) | ||
48 | |||
49 | #define flush_cache_all() BTFIXUP_CALL(flush_cache_all)() | ||
50 | #define flush_cache_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) | ||
51 | #define flush_cache_dup_mm(mm) BTFIXUP_CALL(flush_cache_mm)(mm) | ||
52 | #define flush_cache_range(vma,start,end) BTFIXUP_CALL(flush_cache_range)(vma,start,end) | ||
53 | #define flush_cache_page(vma,addr,pfn) BTFIXUP_CALL(flush_cache_page)(vma,addr) | ||
54 | #define flush_icache_range(start, end) do { } while (0) | 16 | #define flush_icache_range(start, end) do { } while (0) |
55 | #define flush_icache_page(vma, pg) do { } while (0) | 17 | #define flush_icache_page(vma, pg) do { } while (0) |
56 | 18 | ||
@@ -67,11 +29,12 @@ BTFIXUPDEF_CALL(void, flush_cache_page, struct vm_area_struct *, unsigned long) | |||
67 | memcpy(dst, src, len); \ | 29 | memcpy(dst, src, len); \ |
68 | } while (0) | 30 | } while (0) |
69 | 31 | ||
70 | BTFIXUPDEF_CALL(void, __flush_page_to_ram, unsigned long) | 32 | #define __flush_page_to_ram(addr) \ |
71 | BTFIXUPDEF_CALL(void, flush_sig_insns, struct mm_struct *, unsigned long) | 33 | sparc32_cachetlb_ops->page_to_ram(addr) |
72 | 34 | #define flush_sig_insns(mm,insn_addr) \ | |
73 | #define __flush_page_to_ram(addr) BTFIXUP_CALL(__flush_page_to_ram)(addr) | 35 | sparc32_cachetlb_ops->sig_insns(mm, insn_addr) |
74 | #define flush_sig_insns(mm,insn_addr) BTFIXUP_CALL(flush_sig_insns)(mm,insn_addr) | 36 | #define flush_page_for_dma(addr) \ |
37 | sparc32_cachetlb_ops->page_for_dma(addr) | ||
75 | 38 | ||
76 | extern void sparc_flush_page_to_ram(struct page *page); | 39 | extern void sparc_flush_page_to_ram(struct page *page); |
77 | 40 | ||
diff --git a/arch/sparc/include/asm/cacheflush_64.h b/arch/sparc/include/asm/cacheflush_64.h index 2efea2ff88b7..301736d9e7a1 100644 --- a/arch/sparc/include/asm/cacheflush_64.h +++ b/arch/sparc/include/asm/cacheflush_64.h | |||
@@ -8,9 +8,6 @@ | |||
8 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
9 | 9 | ||
10 | /* Cache flush operations. */ | 10 | /* Cache flush operations. */ |
11 | |||
12 | |||
13 | #define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") | ||
14 | #define flushw_all() __asm__ __volatile__("flushw") | 11 | #define flushw_all() __asm__ __volatile__("flushw") |
15 | 12 | ||
16 | extern void __flushw_user(void); | 13 | extern void __flushw_user(void); |
diff --git a/arch/sparc/include/asm/cachetlb_32.h b/arch/sparc/include/asm/cachetlb_32.h new file mode 100644 index 000000000000..efb19889a083 --- /dev/null +++ b/arch/sparc/include/asm/cachetlb_32.h | |||
@@ -0,0 +1,29 @@ | |||
1 | #ifndef _SPARC_CACHETLB_H | ||
2 | #define _SPARC_CACHETLB_H | ||
3 | |||
4 | struct mm_struct; | ||
5 | struct vm_area_struct; | ||
6 | |||
7 | struct sparc32_cachetlb_ops { | ||
8 | void (*cache_all)(void); | ||
9 | void (*cache_mm)(struct mm_struct *); | ||
10 | void (*cache_range)(struct vm_area_struct *, unsigned long, | ||
11 | unsigned long); | ||
12 | void (*cache_page)(struct vm_area_struct *, unsigned long); | ||
13 | |||
14 | void (*tlb_all)(void); | ||
15 | void (*tlb_mm)(struct mm_struct *); | ||
16 | void (*tlb_range)(struct vm_area_struct *, unsigned long, | ||
17 | unsigned long); | ||
18 | void (*tlb_page)(struct vm_area_struct *, unsigned long); | ||
19 | |||
20 | void (*page_to_ram)(unsigned long); | ||
21 | void (*sig_insns)(struct mm_struct *, unsigned long); | ||
22 | void (*page_for_dma)(unsigned long); | ||
23 | }; | ||
24 | extern const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops; | ||
25 | #ifdef CONFIG_SMP | ||
26 | extern const struct sparc32_cachetlb_ops *local_ops; | ||
27 | #endif | ||
28 | |||
29 | #endif /* SPARC_CACHETLB_H */ | ||
diff --git a/arch/sparc/include/asm/cmpxchg_32.h b/arch/sparc/include/asm/cmpxchg_32.h index c786b0a92b51..1fae1a02e3c2 100644 --- a/arch/sparc/include/asm/cmpxchg_32.h +++ b/arch/sparc/include/asm/cmpxchg_32.h | |||
@@ -11,40 +11,13 @@ | |||
11 | #ifndef __ARCH_SPARC_CMPXCHG__ | 11 | #ifndef __ARCH_SPARC_CMPXCHG__ |
12 | #define __ARCH_SPARC_CMPXCHG__ | 12 | #define __ARCH_SPARC_CMPXCHG__ |
13 | 13 | ||
14 | #include <asm/btfixup.h> | ||
15 | |||
16 | /* This has special calling conventions */ | ||
17 | #ifndef CONFIG_SMP | ||
18 | BTFIXUPDEF_CALL(void, ___xchg32, void) | ||
19 | #endif | ||
20 | |||
21 | static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) | 14 | static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) |
22 | { | 15 | { |
23 | #ifdef CONFIG_SMP | ||
24 | __asm__ __volatile__("swap [%2], %0" | 16 | __asm__ __volatile__("swap [%2], %0" |
25 | : "=&r" (val) | 17 | : "=&r" (val) |
26 | : "0" (val), "r" (m) | 18 | : "0" (val), "r" (m) |
27 | : "memory"); | 19 | : "memory"); |
28 | return val; | 20 | return val; |
29 | #else | ||
30 | register unsigned long *ptr asm("g1"); | ||
31 | register unsigned long ret asm("g2"); | ||
32 | |||
33 | ptr = (unsigned long *) m; | ||
34 | ret = val; | ||
35 | |||
36 | /* Note: this is magic and the nop there is | ||
37 | really needed. */ | ||
38 | __asm__ __volatile__( | ||
39 | "mov %%o7, %%g4\n\t" | ||
40 | "call ___f____xchg32\n\t" | ||
41 | " nop\n\t" | ||
42 | : "=&r" (ret) | ||
43 | : "0" (ret), "r" (ptr) | ||
44 | : "g3", "g4", "g7", "memory", "cc"); | ||
45 | |||
46 | return ret; | ||
47 | #endif | ||
48 | } | 21 | } |
49 | 22 | ||
50 | extern void __xchg_called_with_bad_pointer(void); | 23 | extern void __xchg_called_with_bad_pointer(void); |
diff --git a/arch/sparc/include/asm/contregs.h b/arch/sparc/include/asm/contregs.h index 48fa8a4ef357..b8abdfcf5555 100644 --- a/arch/sparc/include/asm/contregs.h +++ b/arch/sparc/include/asm/contregs.h | |||
@@ -7,28 +7,6 @@ | |||
7 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | 7 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* 3=sun3 | ||
11 | 4=sun4 (as in sun4 sysmaint student book) | ||
12 | c=sun4c (according to davem) */ | ||
13 | |||
14 | #define AC_IDPROM 0x00000000 /* 34 ID PROM, R/O, byte, 32 bytes */ | ||
15 | #define AC_PAGEMAP 0x10000000 /* 3 Pagemap R/W, long */ | ||
16 | #define AC_SEGMAP 0x20000000 /* 3 Segment map, byte */ | ||
17 | #define AC_CONTEXT 0x30000000 /* 34c current mmu-context */ | ||
18 | #define AC_SENABLE 0x40000000 /* 34c system dvma/cache/reset enable reg*/ | ||
19 | #define AC_UDVMA_ENB 0x50000000 /* 34 Not used on Sun boards, byte */ | ||
20 | #define AC_BUS_ERROR 0x60000000 /* 34 Not cleared on read, byte. */ | ||
21 | #define AC_SYNC_ERR 0x60000000 /* c fault type */ | ||
22 | #define AC_SYNC_VA 0x60000004 /* c fault virtual address */ | ||
23 | #define AC_ASYNC_ERR 0x60000008 /* c asynchronous fault type */ | ||
24 | #define AC_ASYNC_VA 0x6000000c /* c async fault virtual address */ | ||
25 | #define AC_LEDS 0x70000000 /* 34 Zero turns on LEDs, byte */ | ||
26 | #define AC_CACHETAGS 0x80000000 /* 34c direct access to the VAC tags */ | ||
27 | #define AC_CACHEDDATA 0x90000000 /* 3 c direct access to the VAC data */ | ||
28 | #define AC_UDVMA_MAP 0xD0000000 /* 4 Not used on Sun boards, byte */ | ||
29 | #define AC_VME_VECTOR 0xE0000000 /* 4 For non-Autovector VME, byte */ | ||
30 | #define AC_BOOT_SCC 0xF0000000 /* 34 bypass to access Zilog 8530. byte.*/ | ||
31 | |||
32 | /* s=Swift, h=Ross_HyperSPARC, v=TI_Viking, t=Tsunami, r=Ross_Cypress */ | 10 | /* s=Swift, h=Ross_HyperSPARC, v=TI_Viking, t=Tsunami, r=Ross_Cypress */ |
33 | #define AC_M_PCR 0x0000 /* shv Processor Control Reg */ | 11 | #define AC_M_PCR 0x0000 /* shv Processor Control Reg */ |
34 | #define AC_M_CTPR 0x0100 /* shv Context Table Pointer Reg */ | 12 | #define AC_M_CTPR 0x0100 /* shv Context Table Pointer Reg */ |
diff --git a/arch/sparc/include/asm/cpu_type.h b/arch/sparc/include/asm/cpu_type.h index 4ca184d95d82..84d7d83b8084 100644 --- a/arch/sparc/include/asm/cpu_type.h +++ b/arch/sparc/include/asm/cpu_type.h | |||
@@ -5,30 +5,24 @@ | |||
5 | * Sparc (general) CPU types | 5 | * Sparc (general) CPU types |
6 | */ | 6 | */ |
7 | enum sparc_cpu { | 7 | enum sparc_cpu { |
8 | sun4 = 0x00, | 8 | sun4m = 0x00, |
9 | sun4c = 0x01, | 9 | sun4d = 0x01, |
10 | sun4m = 0x02, | 10 | sun4e = 0x02, |
11 | sun4d = 0x03, | 11 | sun4u = 0x03, /* V8 ploos ploos */ |
12 | sun4e = 0x04, | 12 | sun_unknown = 0x04, |
13 | sun4u = 0x05, /* V8 ploos ploos */ | 13 | ap1000 = 0x05, /* almost a sun4m */ |
14 | sun_unknown = 0x06, | 14 | sparc_leon = 0x06, /* Leon SoC */ |
15 | ap1000 = 0x07, /* almost a sun4m */ | ||
16 | sparc_leon = 0x08, /* Leon SoC */ | ||
17 | }; | 15 | }; |
18 | 16 | ||
19 | #ifdef CONFIG_SPARC32 | 17 | #ifdef CONFIG_SPARC32 |
20 | extern enum sparc_cpu sparc_cpu_model; | 18 | extern enum sparc_cpu sparc_cpu_model; |
21 | 19 | ||
22 | #define ARCH_SUN4C (sparc_cpu_model==sun4c) | ||
23 | |||
24 | #define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */ | 20 | #define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */ |
25 | 21 | ||
26 | #else | 22 | #else |
27 | 23 | ||
28 | #define sparc_cpu_model sun4u | 24 | #define sparc_cpu_model sun4u |
29 | 25 | ||
30 | /* This cannot ever be a sun4c :) That's just history. */ | ||
31 | #define ARCH_SUN4C 0 | ||
32 | #endif | 26 | #endif |
33 | 27 | ||
34 | #endif /* __ASM_CPU_TYPE_H */ | 28 | #endif /* __ASM_CPU_TYPE_H */ |
diff --git a/arch/sparc/include/asm/cpudata_32.h b/arch/sparc/include/asm/cpudata_32.h index a4c5a938b936..0300d94c25b3 100644 --- a/arch/sparc/include/asm/cpudata_32.h +++ b/arch/sparc/include/asm/cpudata_32.h | |||
@@ -14,7 +14,6 @@ | |||
14 | typedef struct { | 14 | typedef struct { |
15 | unsigned long udelay_val; | 15 | unsigned long udelay_val; |
16 | unsigned long clock_tick; | 16 | unsigned long clock_tick; |
17 | unsigned int multiplier; | ||
18 | unsigned int counter; | 17 | unsigned int counter; |
19 | #ifdef CONFIG_SMP | 18 | #ifdef CONFIG_SMP |
20 | unsigned int irq_resched_count; | 19 | unsigned int irq_resched_count; |
diff --git a/arch/sparc/include/asm/cypress.h b/arch/sparc/include/asm/cypress.h deleted file mode 100644 index 95e9772ea394..000000000000 --- a/arch/sparc/include/asm/cypress.h +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | /* | ||
2 | * cypress.h: Cypress module specific definitions and defines. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #ifndef _SPARC_CYPRESS_H | ||
8 | #define _SPARC_CYPRESS_H | ||
9 | |||
10 | /* Cypress chips have %psr 'impl' of '0001' and 'vers' of '0001'. */ | ||
11 | |||
12 | /* The MMU control register fields on the Sparc Cypress 604/605 MMU's. | ||
13 | * | ||
14 | * --------------------------------------------------------------- | ||
15 | * |implvers| MCA | MCM |MV| MID |BM| C|RSV|MR|CM|CL|CE|RSV|NF|ME| | ||
16 | * --------------------------------------------------------------- | ||
17 | * 31 24 23-22 21-20 19 18-15 14 13 12 11 10 9 8 7-2 1 0 | ||
18 | * | ||
19 | * MCA: MultiChip Access -- Used for configuration of multiple | ||
20 | * CY7C604/605 cache units. | ||
21 | * MCM: MultiChip Mask -- Again, for multiple cache unit config. | ||
22 | * MV: MultiChip Valid -- Indicates MCM and MCA have valid settings. | ||
23 | * MID: ModuleID -- Unique processor ID for MBus transactions. (605 only) | ||
24 | * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode | ||
25 | * C: Cacheable -- Indicates whether accesses are cacheable while | ||
26 | * the MMU is off. 0=no 1=yes | ||
27 | * MR: MemoryReflection -- Indicates whether the bus attached to the | ||
28 | * MBus supports memory reflection. 0=no 1=yes (605 only) | ||
29 | * CM: CacheMode -- Indicates whether the cache is operating in write | ||
30 | * through or copy-back mode. 0=write-through 1=copy-back | ||
31 | * CL: CacheLock -- Indicates if the entire cache is locked or not. | ||
32 | * 0=not-locked 1=locked (604 only) | ||
33 | * CE: CacheEnable -- Is the virtual cache on? 0=no 1=yes | ||
34 | * NF: NoFault -- Do faults generate traps? 0=yes 1=no | ||
35 | * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes | ||
36 | */ | ||
37 | |||
38 | #define CYPRESS_MCA 0x00c00000 | ||
39 | #define CYPRESS_MCM 0x00300000 | ||
40 | #define CYPRESS_MVALID 0x00080000 | ||
41 | #define CYPRESS_MIDMASK 0x00078000 /* Only on 605 */ | ||
42 | #define CYPRESS_BMODE 0x00004000 | ||
43 | #define CYPRESS_ACENABLE 0x00002000 | ||
44 | #define CYPRESS_MRFLCT 0x00000800 /* Only on 605 */ | ||
45 | #define CYPRESS_CMODE 0x00000400 | ||
46 | #define CYPRESS_CLOCK 0x00000200 /* Only on 604 */ | ||
47 | #define CYPRESS_CENABLE 0x00000100 | ||
48 | #define CYPRESS_NFAULT 0x00000002 | ||
49 | #define CYPRESS_MENABLE 0x00000001 | ||
50 | |||
51 | static inline void cypress_flush_page(unsigned long page) | ||
52 | { | ||
53 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
54 | "r" (page), "i" (ASI_M_FLUSH_PAGE)); | ||
55 | } | ||
56 | |||
57 | static inline void cypress_flush_segment(unsigned long addr) | ||
58 | { | ||
59 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
60 | "r" (addr), "i" (ASI_M_FLUSH_SEG)); | ||
61 | } | ||
62 | |||
63 | static inline void cypress_flush_region(unsigned long addr) | ||
64 | { | ||
65 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
66 | "r" (addr), "i" (ASI_M_FLUSH_REGION)); | ||
67 | } | ||
68 | |||
69 | static inline void cypress_flush_context(void) | ||
70 | { | ||
71 | __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : | ||
72 | "i" (ASI_M_FLUSH_CTX)); | ||
73 | } | ||
74 | |||
75 | /* XXX Displacement flushes for buggy chips and initial testing | ||
76 | * XXX go here. | ||
77 | */ | ||
78 | |||
79 | #endif /* !(_SPARC_CYPRESS_H) */ | ||
diff --git a/arch/sparc/include/asm/dma.h b/arch/sparc/include/asm/dma.h index b554927bbaf6..3d434ef5eae3 100644 --- a/arch/sparc/include/asm/dma.h +++ b/arch/sparc/include/asm/dma.h | |||
@@ -92,27 +92,31 @@ extern int isa_dma_bridge_buggy; | |||
92 | #ifdef CONFIG_SPARC32 | 92 | #ifdef CONFIG_SPARC32 |
93 | 93 | ||
94 | /* Routines for data transfer buffers. */ | 94 | /* Routines for data transfer buffers. */ |
95 | BTFIXUPDEF_CALL(char *, mmu_lockarea, char *, unsigned long) | ||
96 | BTFIXUPDEF_CALL(void, mmu_unlockarea, char *, unsigned long) | ||
97 | |||
98 | #define mmu_lockarea(vaddr,len) BTFIXUP_CALL(mmu_lockarea)(vaddr,len) | ||
99 | #define mmu_unlockarea(vaddr,len) BTFIXUP_CALL(mmu_unlockarea)(vaddr,len) | ||
100 | |||
101 | struct page; | ||
102 | struct device; | 95 | struct device; |
103 | struct scatterlist; | 96 | struct scatterlist; |
104 | 97 | ||
105 | /* These are implementations for sbus_map_sg/sbus_unmap_sg... collapse later */ | 98 | struct sparc32_dma_ops { |
106 | BTFIXUPDEF_CALL(__u32, mmu_get_scsi_one, struct device *, char *, unsigned long) | 99 | __u32 (*get_scsi_one)(struct device *, char *, unsigned long); |
107 | BTFIXUPDEF_CALL(void, mmu_get_scsi_sgl, struct device *, struct scatterlist *, int) | 100 | void (*get_scsi_sgl)(struct device *, struct scatterlist *, int); |
108 | BTFIXUPDEF_CALL(void, mmu_release_scsi_one, struct device *, __u32, unsigned long) | 101 | void (*release_scsi_one)(struct device *, __u32, unsigned long); |
109 | BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct device *, struct scatterlist *, int) | 102 | void (*release_scsi_sgl)(struct device *, struct scatterlist *,int); |
110 | 103 | #ifdef CONFIG_SBUS | |
111 | #define mmu_get_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_get_scsi_one)(dev,vaddr,len) | 104 | int (*map_dma_area)(struct device *, dma_addr_t *, unsigned long, unsigned long, int); |
112 | #define mmu_get_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_get_scsi_sgl)(dev,sg,sz) | 105 | void (*unmap_dma_area)(struct device *, unsigned long, int); |
113 | #define mmu_release_scsi_one(dev,vaddr,len) BTFIXUP_CALL(mmu_release_scsi_one)(dev,vaddr,len) | 106 | #endif |
114 | #define mmu_release_scsi_sgl(dev,sg,sz) BTFIXUP_CALL(mmu_release_scsi_sgl)(dev,sg,sz) | 107 | }; |
115 | 108 | extern const struct sparc32_dma_ops *sparc32_dma_ops; | |
109 | |||
110 | #define mmu_get_scsi_one(dev,vaddr,len) \ | ||
111 | sparc32_dma_ops->get_scsi_one(dev, vaddr, len) | ||
112 | #define mmu_get_scsi_sgl(dev,sg,sz) \ | ||
113 | sparc32_dma_ops->get_scsi_sgl(dev, sg, sz) | ||
114 | #define mmu_release_scsi_one(dev,vaddr,len) \ | ||
115 | sparc32_dma_ops->release_scsi_one(dev, vaddr,len) | ||
116 | #define mmu_release_scsi_sgl(dev,sg,sz) \ | ||
117 | sparc32_dma_ops->release_scsi_sgl(dev, sg, sz) | ||
118 | |||
119 | #ifdef CONFIG_SBUS | ||
116 | /* | 120 | /* |
117 | * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep. | 121 | * mmu_map/unmap are provided by iommu/iounit; Invalid to call on IIep. |
118 | * | 122 | * |
@@ -123,17 +127,17 @@ BTFIXUPDEF_CALL(void, mmu_release_scsi_sgl, struct device *, struct scatterlist | |||
123 | * Second mapping is for device visible address, or "bus" address. | 127 | * Second mapping is for device visible address, or "bus" address. |
124 | * The bus address is returned at '*pba'. | 128 | * The bus address is returned at '*pba'. |
125 | * | 129 | * |
126 | * These functions seem distinct, but are hard to split. On sun4c, | 130 | * These functions seem distinct, but are hard to split. |
127 | * at least for now, 'a' is equal to bus address, and retured in *pba. | ||
128 | * On sun4m, page attributes depend on the CPU type, so we have to | 131 | * On sun4m, page attributes depend on the CPU type, so we have to |
129 | * know if we are mapping RAM or I/O, so it has to be an additional argument | 132 | * know if we are mapping RAM or I/O, so it has to be an additional argument |
130 | * to a separate mapping function for CPU visible mappings. | 133 | * to a separate mapping function for CPU visible mappings. |
131 | */ | 134 | */ |
132 | BTFIXUPDEF_CALL(int, mmu_map_dma_area, struct device *, dma_addr_t *, unsigned long, unsigned long, int len) | 135 | #define sbus_map_dma_area(dev,pba,va,a,len) \ |
133 | BTFIXUPDEF_CALL(void, mmu_unmap_dma_area, struct device *, unsigned long busa, int len) | 136 | sparc32_dma_ops->map_dma_area(dev, pba, va, a, len) |
137 | #define sbus_unmap_dma_area(dev,ba,len) \ | ||
138 | sparc32_dma_ops->unmap_dma_area(dev, ba, len) | ||
139 | #endif /* CONFIG_SBUS */ | ||
134 | 140 | ||
135 | #define mmu_map_dma_area(dev,pba,va,a,len) BTFIXUP_CALL(mmu_map_dma_area)(dev,pba,va,a,len) | ||
136 | #define mmu_unmap_dma_area(dev,ba,len) BTFIXUP_CALL(mmu_unmap_dma_area)(dev,ba,len) | ||
137 | #endif | 141 | #endif |
138 | 142 | ||
139 | #endif /* !(_ASM_SPARC_DMA_H) */ | 143 | #endif /* !(_ASM_SPARC_DMA_H) */ |
diff --git a/arch/sparc/include/asm/elf_32.h b/arch/sparc/include/asm/elf_32.h index 4269ca6ad18a..2d4d755cba9e 100644 --- a/arch/sparc/include/asm/elf_32.h +++ b/arch/sparc/include/asm/elf_32.h | |||
@@ -118,16 +118,9 @@ typedef struct { | |||
118 | instruction set this cpu supports. This can NOT be done in userspace | 118 | instruction set this cpu supports. This can NOT be done in userspace |
119 | on Sparc. */ | 119 | on Sparc. */ |
120 | 120 | ||
121 | /* Sun4c has none of the capabilities, most sun4m's have them all. | 121 | /* Most sun4m's have them all. */ |
122 | * XXX This is gross, set some global variable at boot time. -DaveM | 122 | #define ELF_HWCAP (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ |
123 | */ | 123 | HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV) |
124 | #define ELF_HWCAP ((ARCH_SUN4C) ? 0 : \ | ||
125 | (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \ | ||
126 | HWCAP_SPARC_SWAP | \ | ||
127 | ((srmmu_modtype != Cypress && \ | ||
128 | srmmu_modtype != Cypress_vE && \ | ||
129 | srmmu_modtype != Cypress_vD) ? \ | ||
130 | HWCAP_SPARC_MULDIV : 0))) | ||
131 | 124 | ||
132 | /* This yields a string that ld.so will use to load implementation | 125 | /* This yields a string that ld.so will use to load implementation |
133 | specific libraries for optimization. This is more specific in | 126 | specific libraries for optimization. This is more specific in |
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h index 698d9559fead..fb3f16954c69 100644 --- a/arch/sparc/include/asm/floppy_32.h +++ b/arch/sparc/include/asm/floppy_32.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <asm/page.h> | 12 | #include <asm/page.h> |
13 | #include <asm/pgtable.h> | 13 | #include <asm/pgtable.h> |
14 | #include <asm/idprom.h> | 14 | #include <asm/idprom.h> |
15 | #include <asm/machines.h> | ||
16 | #include <asm/oplib.h> | 15 | #include <asm/oplib.h> |
17 | #include <asm/auxio.h> | 16 | #include <asm/auxio.h> |
18 | #include <asm/irq.h> | 17 | #include <asm/irq.h> |
@@ -103,25 +102,13 @@ static struct sun_floppy_ops sun_fdops; | |||
103 | /* Routines unique to each controller type on a Sun. */ | 102 | /* Routines unique to each controller type on a Sun. */ |
104 | static void sun_set_dor(unsigned char value, int fdc_82077) | 103 | static void sun_set_dor(unsigned char value, int fdc_82077) |
105 | { | 104 | { |
106 | if (sparc_cpu_model == sun4c) { | 105 | if (fdc_82077) |
107 | unsigned int bits = 0; | ||
108 | if (value & 0x10) | ||
109 | bits |= AUXIO_FLPY_DSEL; | ||
110 | if ((value & 0x80) == 0) | ||
111 | bits |= AUXIO_FLPY_EJCT; | ||
112 | set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT)); | ||
113 | } | ||
114 | if (fdc_82077) { | ||
115 | sun_fdc->dor_82077 = value; | 106 | sun_fdc->dor_82077 = value; |
116 | } | ||
117 | } | 107 | } |
118 | 108 | ||
119 | static unsigned char sun_read_dir(void) | 109 | static unsigned char sun_read_dir(void) |
120 | { | 110 | { |
121 | if (sparc_cpu_model == sun4c) | 111 | return sun_fdc->dir_82077; |
122 | return (get_auxio() & AUXIO_FLPY_DCHG) ? 0x80 : 0; | ||
123 | else | ||
124 | return sun_fdc->dir_82077; | ||
125 | } | 112 | } |
126 | 113 | ||
127 | static unsigned char sun_82072_fd_inb(int port) | 114 | static unsigned char sun_82072_fd_inb(int port) |
@@ -242,10 +229,7 @@ static inline void virtual_dma_init(void) | |||
242 | static inline void sun_fd_disable_dma(void) | 229 | static inline void sun_fd_disable_dma(void) |
243 | { | 230 | { |
244 | doing_pdma = 0; | 231 | doing_pdma = 0; |
245 | if (pdma_base) { | 232 | pdma_base = NULL; |
246 | mmu_unlockarea(pdma_base, pdma_areasize); | ||
247 | pdma_base = NULL; | ||
248 | } | ||
249 | } | 233 | } |
250 | 234 | ||
251 | static inline void sun_fd_set_dma_mode(int mode) | 235 | static inline void sun_fd_set_dma_mode(int mode) |
@@ -275,7 +259,6 @@ static inline void sun_fd_set_dma_count(int length) | |||
275 | 259 | ||
276 | static inline void sun_fd_enable_dma(void) | 260 | static inline void sun_fd_enable_dma(void) |
277 | { | 261 | { |
278 | pdma_vaddr = mmu_lockarea(pdma_vaddr, pdma_size); | ||
279 | pdma_base = pdma_vaddr; | 262 | pdma_base = pdma_vaddr; |
280 | pdma_areasize = pdma_size; | 263 | pdma_areasize = pdma_size; |
281 | } | 264 | } |
@@ -301,38 +284,36 @@ static int sun_floppy_init(void) | |||
301 | { | 284 | { |
302 | struct platform_device *op; | 285 | struct platform_device *op; |
303 | struct device_node *dp; | 286 | struct device_node *dp; |
287 | struct resource r; | ||
304 | char state[128]; | 288 | char state[128]; |
305 | phandle tnode, fd_node; | 289 | phandle fd_node; |
290 | phandle tnode; | ||
306 | int num_regs; | 291 | int num_regs; |
307 | struct resource r; | ||
308 | 292 | ||
309 | use_virtual_dma = 1; | 293 | use_virtual_dma = 1; |
310 | 294 | ||
311 | /* Forget it if we aren't on a machine that could possibly | 295 | /* Forget it if we aren't on a machine that could possibly |
312 | * ever have a floppy drive. | 296 | * ever have a floppy drive. |
313 | */ | 297 | */ |
314 | if((sparc_cpu_model != sun4c && sparc_cpu_model != sun4m) || | 298 | if (sparc_cpu_model != sun4m) { |
315 | ((idprom->id_machtype == (SM_SUN4C | SM_4C_SLC)) || | ||
316 | (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC)))) { | ||
317 | /* We certainly don't have a floppy controller. */ | 299 | /* We certainly don't have a floppy controller. */ |
318 | goto no_sun_fdc; | 300 | goto no_sun_fdc; |
319 | } | 301 | } |
320 | /* Well, try to find one. */ | 302 | /* Well, try to find one. */ |
321 | tnode = prom_getchild(prom_root_node); | 303 | tnode = prom_getchild(prom_root_node); |
322 | fd_node = prom_searchsiblings(tnode, "obio"); | 304 | fd_node = prom_searchsiblings(tnode, "obio"); |
323 | if(fd_node != 0) { | 305 | if (fd_node != 0) { |
324 | tnode = prom_getchild(fd_node); | 306 | tnode = prom_getchild(fd_node); |
325 | fd_node = prom_searchsiblings(tnode, "SUNW,fdtwo"); | 307 | fd_node = prom_searchsiblings(tnode, "SUNW,fdtwo"); |
326 | } else { | 308 | } else { |
327 | fd_node = prom_searchsiblings(tnode, "fd"); | 309 | fd_node = prom_searchsiblings(tnode, "fd"); |
328 | } | 310 | } |
329 | if(fd_node == 0) { | 311 | if (fd_node == 0) { |
330 | goto no_sun_fdc; | 312 | goto no_sun_fdc; |
331 | } | 313 | } |
332 | 314 | ||
333 | /* The sun4m lets us know if the controller is actually usable. */ | 315 | /* The sun4m lets us know if the controller is actually usable. */ |
334 | if(sparc_cpu_model == sun4m && | 316 | if (prom_getproperty(fd_node, "status", state, sizeof(state)) != -1) { |
335 | prom_getproperty(fd_node, "status", state, sizeof(state)) != -1) { | ||
336 | if(!strcmp(state, "disabled")) { | 317 | if(!strcmp(state, "disabled")) { |
337 | goto no_sun_fdc; | 318 | goto no_sun_fdc; |
338 | } | 319 | } |
@@ -343,12 +324,12 @@ static int sun_floppy_init(void) | |||
343 | memset(&r, 0, sizeof(r)); | 324 | memset(&r, 0, sizeof(r)); |
344 | r.flags = fd_regs[0].which_io; | 325 | r.flags = fd_regs[0].which_io; |
345 | r.start = fd_regs[0].phys_addr; | 326 | r.start = fd_regs[0].phys_addr; |
346 | sun_fdc = (struct sun_flpy_controller *) | 327 | sun_fdc = of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); |
347 | of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy"); | ||
348 | 328 | ||
349 | /* Look up irq in platform_device. | 329 | /* Look up irq in platform_device. |
350 | * We try "SUNW,fdtwo" and "fd" | 330 | * We try "SUNW,fdtwo" and "fd" |
351 | */ | 331 | */ |
332 | op = NULL; | ||
352 | for_each_node_by_name(dp, "SUNW,fdtwo") { | 333 | for_each_node_by_name(dp, "SUNW,fdtwo") { |
353 | op = of_find_device_by_node(dp); | 334 | op = of_find_device_by_node(dp); |
354 | if (op) | 335 | if (op) |
@@ -367,7 +348,7 @@ static int sun_floppy_init(void) | |||
367 | FLOPPY_IRQ = op->archdata.irqs[0]; | 348 | FLOPPY_IRQ = op->archdata.irqs[0]; |
368 | 349 | ||
369 | /* Last minute sanity check... */ | 350 | /* Last minute sanity check... */ |
370 | if(sun_fdc->status_82072 == 0xff) { | 351 | if (sun_fdc->status_82072 == 0xff) { |
371 | sun_fdc = NULL; | 352 | sun_fdc = NULL; |
372 | goto no_sun_fdc; | 353 | goto no_sun_fdc; |
373 | } | 354 | } |
diff --git a/arch/sparc/include/asm/floppy_64.h b/arch/sparc/include/asm/floppy_64.h index bcef1f5a2a6d..e204f902e6c9 100644 --- a/arch/sparc/include/asm/floppy_64.h +++ b/arch/sparc/include/asm/floppy_64.h | |||
@@ -161,10 +161,7 @@ unsigned long pdma_areasize; | |||
161 | static void sun_fd_disable_dma(void) | 161 | static void sun_fd_disable_dma(void) |
162 | { | 162 | { |
163 | doing_pdma = 0; | 163 | doing_pdma = 0; |
164 | if (pdma_base) { | 164 | pdma_base = NULL; |
165 | mmu_unlockarea(pdma_base, pdma_areasize); | ||
166 | pdma_base = NULL; | ||
167 | } | ||
168 | } | 165 | } |
169 | 166 | ||
170 | static void sun_fd_set_dma_mode(int mode) | 167 | static void sun_fd_set_dma_mode(int mode) |
@@ -194,7 +191,6 @@ static void sun_fd_set_dma_count(int length) | |||
194 | 191 | ||
195 | static void sun_fd_enable_dma(void) | 192 | static void sun_fd_enable_dma(void) |
196 | { | 193 | { |
197 | pdma_vaddr = mmu_lockarea(pdma_vaddr, pdma_size); | ||
198 | pdma_base = pdma_vaddr; | 194 | pdma_base = pdma_vaddr; |
199 | pdma_areasize = pdma_size; | 195 | pdma_areasize = pdma_size; |
200 | } | 196 | } |
diff --git a/arch/sparc/include/asm/head_32.h b/arch/sparc/include/asm/head_32.h index 7c35491a8b53..a76874838f61 100644 --- a/arch/sparc/include/asm/head_32.h +++ b/arch/sparc/include/asm/head_32.h | |||
@@ -2,15 +2,8 @@ | |||
2 | #define __SPARC_HEAD_H | 2 | #define __SPARC_HEAD_H |
3 | 3 | ||
4 | #define KERNBASE 0xf0000000 /* First address the kernel will eventually be */ | 4 | #define KERNBASE 0xf0000000 /* First address the kernel will eventually be */ |
5 | #define LOAD_ADDR 0x4000 /* prom jumps to us here unless this is elf /boot */ | ||
6 | #define SUN4C_SEGSZ (1 << 18) | ||
7 | #define SRMMU_L1_KBASE_OFFSET ((KERNBASE>>24)<<2) /* Used in boot remapping. */ | ||
8 | #define INTS_ENAB 0x01 /* entry.S uses this. */ | ||
9 | |||
10 | #define SUN4_PROM_VECTOR 0xFFE81000 /* SUN4 PROM needs to be hardwired */ | ||
11 | 5 | ||
12 | #define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ | 6 | #define WRITE_PAUSE nop; nop; nop; /* Have to do this after %wim/%psr chg */ |
13 | #define NOP_INSN 0x01000000 /* Used to patch sparc_save_state */ | ||
14 | 7 | ||
15 | /* Here are some trap goodies */ | 8 | /* Here are some trap goodies */ |
16 | 9 | ||
@@ -18,9 +11,7 @@ | |||
18 | #define TRAP_ENTRY(type, label) \ | 11 | #define TRAP_ENTRY(type, label) \ |
19 | rd %psr, %l0; b label; rd %wim, %l3; nop; | 12 | rd %psr, %l0; b label; rd %wim, %l3; nop; |
20 | 13 | ||
21 | /* Data/text faults. Defaults to sun4c version at boot time. */ | 14 | /* Data/text faults */ |
22 | #define SPARC_TFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 1, %l7; | ||
23 | #define SPARC_DFAULT rd %psr, %l0; rd %wim, %l3; b sun4c_fault; mov 0, %l7; | ||
24 | #define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b srmmu_fault; mov 1, %l7; | 15 | #define SRMMU_TFAULT rd %psr, %l0; rd %wim, %l3; b srmmu_fault; mov 1, %l7; |
25 | #define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b srmmu_fault; mov 0, %l7; | 16 | #define SRMMU_DFAULT rd %psr, %l0; rd %wim, %l3; b srmmu_fault; mov 0, %l7; |
26 | 17 | ||
@@ -80,16 +71,6 @@ | |||
80 | #define TRAP_ENTRY_INTERRUPT(int_level) \ | 71 | #define TRAP_ENTRY_INTERRUPT(int_level) \ |
81 | mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; | 72 | mov int_level, %l7; rd %psr, %l0; b real_irq_entry; rd %wim, %l3; |
82 | 73 | ||
83 | /* NMI's (Non Maskable Interrupts) are special, you can't keep them | ||
84 | * from coming in, and basically if you get one, the shows over. ;( | ||
85 | * On the sun4c they are usually asynchronous memory errors, on the | ||
86 | * the sun4m they could be either due to mem errors or a software | ||
87 | * initiated interrupt from the prom/kern on an SMP box saying "I | ||
88 | * command you to do CPU tricks, read your mailbox for more info." | ||
89 | */ | ||
90 | #define NMI_TRAP \ | ||
91 | rd %wim, %l3; b linux_trap_nmi_sun4c; mov %psr, %l0; nop; | ||
92 | |||
93 | /* Window overflows/underflows are special and we need to try to be as | 74 | /* Window overflows/underflows are special and we need to try to be as |
94 | * efficient as possible here.... | 75 | * efficient as possible here.... |
95 | */ | 76 | */ |
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h index a4e457f003ed..07659124c140 100644 --- a/arch/sparc/include/asm/leon.h +++ b/arch/sparc/include/asm/leon.h | |||
@@ -10,19 +10,6 @@ | |||
10 | 10 | ||
11 | #ifdef CONFIG_SPARC_LEON | 11 | #ifdef CONFIG_SPARC_LEON |
12 | 12 | ||
13 | #define ASI_LEON_NOCACHE 0x01 | ||
14 | |||
15 | #define ASI_LEON_DCACHE_MISS 0x1 | ||
16 | |||
17 | #define ASI_LEON_CACHEREGS 0x02 | ||
18 | #define ASI_LEON_IFLUSH 0x10 | ||
19 | #define ASI_LEON_DFLUSH 0x11 | ||
20 | |||
21 | #define ASI_LEON_MMUFLUSH 0x18 | ||
22 | #define ASI_LEON_MMUREGS 0x19 | ||
23 | #define ASI_LEON_BYPASS 0x1c | ||
24 | #define ASI_LEON_FLUSH_PAGE 0x10 | ||
25 | |||
26 | /* mmu register access, ASI_LEON_MMUREGS */ | 13 | /* mmu register access, ASI_LEON_MMUREGS */ |
27 | #define LEON_CNR_CTRL 0x000 | 14 | #define LEON_CNR_CTRL 0x000 |
28 | #define LEON_CNR_CTXP 0x100 | 15 | #define LEON_CNR_CTXP 0x100 |
@@ -57,29 +44,6 @@ | |||
57 | #define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */ | 44 | #define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */ |
58 | #define LEON_IRQPRIO_R 0xfffe0000 /* bit 31-17 of lregs.irqmask */ | 45 | #define LEON_IRQPRIO_R 0xfffe0000 /* bit 31-17 of lregs.irqmask */ |
59 | 46 | ||
60 | /* leon uart register definitions */ | ||
61 | #define LEON_OFF_UDATA 0x0 | ||
62 | #define LEON_OFF_USTAT 0x4 | ||
63 | #define LEON_OFF_UCTRL 0x8 | ||
64 | #define LEON_OFF_USCAL 0xc | ||
65 | |||
66 | #define LEON_UCTRL_RE 0x01 | ||
67 | #define LEON_UCTRL_TE 0x02 | ||
68 | #define LEON_UCTRL_RI 0x04 | ||
69 | #define LEON_UCTRL_TI 0x08 | ||
70 | #define LEON_UCTRL_PS 0x10 | ||
71 | #define LEON_UCTRL_PE 0x20 | ||
72 | #define LEON_UCTRL_FL 0x40 | ||
73 | #define LEON_UCTRL_LB 0x80 | ||
74 | |||
75 | #define LEON_USTAT_DR 0x01 | ||
76 | #define LEON_USTAT_TS 0x02 | ||
77 | #define LEON_USTAT_TH 0x04 | ||
78 | #define LEON_USTAT_BR 0x08 | ||
79 | #define LEON_USTAT_OV 0x10 | ||
80 | #define LEON_USTAT_PE 0x20 | ||
81 | #define LEON_USTAT_FE 0x40 | ||
82 | |||
83 | #define LEON_MCFG2_SRAMDIS 0x00002000 | 47 | #define LEON_MCFG2_SRAMDIS 0x00002000 |
84 | #define LEON_MCFG2_SDRAMEN 0x00004000 | 48 | #define LEON_MCFG2_SDRAMEN 0x00004000 |
85 | #define LEON_MCFG2_SRAMBANKSZ 0x00001e00 /* [12-9] */ | 49 | #define LEON_MCFG2_SRAMBANKSZ 0x00001e00 /* [12-9] */ |
@@ -89,8 +53,6 @@ | |||
89 | 53 | ||
90 | #define LEON_TCNT0_MASK 0x7fffff | 54 | #define LEON_TCNT0_MASK 0x7fffff |
91 | 55 | ||
92 | #define LEON_USTAT_ERROR (LEON_USTAT_OV | LEON_USTAT_PE | LEON_USTAT_FE) | ||
93 | /* no break yet */ | ||
94 | 56 | ||
95 | #define ASI_LEON3_SYSCTRL 0x02 | 57 | #define ASI_LEON3_SYSCTRL 0x02 |
96 | #define ASI_LEON3_SYSCTRL_ICFG 0x08 | 58 | #define ASI_LEON3_SYSCTRL_ICFG 0x08 |
@@ -278,18 +240,11 @@ static inline int sparc_leon3_cpuid(void) | |||
278 | #define LEON2_CFG_SSIZE_MASK 0x00007000UL | 240 | #define LEON2_CFG_SSIZE_MASK 0x00007000UL |
279 | 241 | ||
280 | #ifndef __ASSEMBLY__ | 242 | #ifndef __ASSEMBLY__ |
281 | extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); | ||
282 | extern void leon_flush_icache_all(void); | ||
283 | extern void leon_flush_dcache_all(void); | ||
284 | extern void leon_flush_cache_all(void); | ||
285 | extern void leon_flush_tlb_all(void); | ||
286 | extern int leon_flush_during_switch; | ||
287 | extern int leon_flush_needed(void); | ||
288 | |||
289 | struct vm_area_struct; | 243 | struct vm_area_struct; |
244 | |||
245 | extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); | ||
290 | extern void leon_flush_icache_all(void); | 246 | extern void leon_flush_icache_all(void); |
291 | extern void leon_flush_dcache_all(void); | 247 | extern void leon_flush_dcache_all(void); |
292 | extern void leon_flush_pcache_all(struct vm_area_struct *vma, unsigned long page); | ||
293 | extern void leon_flush_cache_all(void); | 248 | extern void leon_flush_cache_all(void); |
294 | extern void leon_flush_tlb_all(void); | 249 | extern void leon_flush_tlb_all(void); |
295 | extern int leon_flush_during_switch; | 250 | extern int leon_flush_during_switch; |
@@ -315,28 +270,19 @@ struct leon2_cacheregs { | |||
315 | #include <linux/interrupt.h> | 270 | #include <linux/interrupt.h> |
316 | 271 | ||
317 | struct device_node; | 272 | struct device_node; |
273 | struct task_struct; | ||
318 | extern unsigned int leon_build_device_irq(unsigned int real_irq, | 274 | extern unsigned int leon_build_device_irq(unsigned int real_irq, |
319 | irq_flow_handler_t flow_handler, | 275 | irq_flow_handler_t flow_handler, |
320 | const char *name, int do_ack); | 276 | const char *name, int do_ack); |
321 | extern void leon_update_virq_handling(unsigned int virq, | 277 | extern void leon_update_virq_handling(unsigned int virq, |
322 | irq_flow_handler_t flow_handler, | 278 | irq_flow_handler_t flow_handler, |
323 | const char *name, int do_ack); | 279 | const char *name, int do_ack); |
324 | extern void leon_clear_clock_irq(void); | 280 | extern void leon_init_timers(void); |
325 | extern void leon_load_profile_irq(int cpu, unsigned int limit); | ||
326 | extern void leon_init_timers(irq_handler_t counter_fn); | ||
327 | extern void leon_clear_clock_irq(void); | ||
328 | extern void leon_load_profile_irq(int cpu, unsigned int limit); | ||
329 | extern void leon_trans_init(struct device_node *dp); | 281 | extern void leon_trans_init(struct device_node *dp); |
330 | extern void leon_node_init(struct device_node *dp, struct device_node ***nextp); | 282 | extern void leon_node_init(struct device_node *dp, struct device_node ***nextp); |
331 | extern void leon_init_IRQ(void); | ||
332 | extern void leon_init(void); | ||
333 | extern unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr); | ||
334 | extern void init_leon(void); | 283 | extern void init_leon(void); |
335 | extern void poke_leonsparc(void); | 284 | extern void poke_leonsparc(void); |
336 | extern void leon3_getCacheRegs(struct leon3_cacheregs *regs); | 285 | extern void leon3_getCacheRegs(struct leon3_cacheregs *regs); |
337 | extern int leon_flush_needed(void); | ||
338 | extern void leon_switch_mm(void); | ||
339 | extern int srmmu_swprobe_trace; | ||
340 | extern int leon3_ticker_irq; | 286 | extern int leon3_ticker_irq; |
341 | 287 | ||
342 | #ifdef CONFIG_SMP | 288 | #ifdef CONFIG_SMP |
@@ -344,7 +290,7 @@ extern int leon_smp_nrcpus(void); | |||
344 | extern void leon_clear_profile_irq(int cpu); | 290 | extern void leon_clear_profile_irq(int cpu); |
345 | extern void leon_smp_done(void); | 291 | extern void leon_smp_done(void); |
346 | extern void leon_boot_cpus(void); | 292 | extern void leon_boot_cpus(void); |
347 | extern int leon_boot_one_cpu(int i); | 293 | extern int leon_boot_one_cpu(int i, struct task_struct *); |
348 | void leon_init_smp(void); | 294 | void leon_init_smp(void); |
349 | extern void cpu_idle(void); | 295 | extern void cpu_idle(void); |
350 | extern void init_IRQ(void); | 296 | extern void init_IRQ(void); |
@@ -380,7 +326,7 @@ extern int leon_ipi_irq; | |||
380 | #define init_leon() do {} while (0) | 326 | #define init_leon() do {} while (0) |
381 | #define leon_smp_done() do {} while (0) | 327 | #define leon_smp_done() do {} while (0) |
382 | #define leon_boot_cpus() do {} while (0) | 328 | #define leon_boot_cpus() do {} while (0) |
383 | #define leon_boot_one_cpu(i) 1 | 329 | #define leon_boot_one_cpu(i, t) 1 |
384 | #define leon_init_smp() do {} while (0) | 330 | #define leon_init_smp() do {} while (0) |
385 | 331 | ||
386 | #endif /* !defined(CONFIG_SPARC_LEON) */ | 332 | #endif /* !defined(CONFIG_SPARC_LEON) */ |
diff --git a/arch/sparc/include/asm/machines.h b/arch/sparc/include/asm/machines.h index cd9c099567e4..fd6ddb05d1b7 100644 --- a/arch/sparc/include/asm/machines.h +++ b/arch/sparc/include/asm/machines.h | |||
@@ -12,11 +12,6 @@ struct Sun_Machine_Models { | |||
12 | unsigned char id_machtype; | 12 | unsigned char id_machtype; |
13 | }; | 13 | }; |
14 | 14 | ||
15 | /* Current number of machines we know about that has an IDPROM | ||
16 | * machtype entry including one entry for the 0x80 OBP machines. | ||
17 | */ | ||
18 | #define NUM_SUN_MACHINES 16 | ||
19 | |||
20 | /* The machine type in the idprom area looks like this: | 15 | /* The machine type in the idprom area looks like this: |
21 | * | 16 | * |
22 | * --------------- | 17 | * --------------- |
@@ -24,36 +19,20 @@ struct Sun_Machine_Models { | |||
24 | * --------------- | 19 | * --------------- |
25 | * 7 4 3 0 | 20 | * 7 4 3 0 |
26 | * | 21 | * |
27 | * The ARCH field determines the architecture line (sun4, sun4c, etc). | 22 | * The ARCH field determines the architecture line (sun4m, etc). |
28 | * The MACH field determines the machine make within that architecture. | 23 | * The MACH field determines the machine make within that architecture. |
29 | */ | 24 | */ |
30 | 25 | ||
31 | #define SM_ARCH_MASK 0xf0 | 26 | #define SM_ARCH_MASK 0xf0 |
32 | #define SM_SUN4 0x20 | ||
33 | #define M_LEON 0x30 | 27 | #define M_LEON 0x30 |
34 | #define SM_SUN4C 0x50 | ||
35 | #define SM_SUN4M 0x70 | 28 | #define SM_SUN4M 0x70 |
36 | #define SM_SUN4M_OBP 0x80 | 29 | #define SM_SUN4M_OBP 0x80 |
37 | 30 | ||
38 | #define SM_TYP_MASK 0x0f | 31 | #define SM_TYP_MASK 0x0f |
39 | /* Sun4 machines */ | ||
40 | #define SM_4_260 0x01 /* Sun 4/200 series */ | ||
41 | #define SM_4_110 0x02 /* Sun 4/100 series */ | ||
42 | #define SM_4_330 0x03 /* Sun 4/300 series */ | ||
43 | #define SM_4_470 0x04 /* Sun 4/400 series */ | ||
44 | 32 | ||
45 | /* Leon machines */ | 33 | /* Leon machines */ |
46 | #define M_LEON3_SOC 0x02 /* Leon3 SoC */ | 34 | #define M_LEON3_SOC 0x02 /* Leon3 SoC */ |
47 | 35 | ||
48 | /* Sun4c machines Full Name - PROM NAME */ | ||
49 | #define SM_4C_SS1 0x01 /* Sun4c SparcStation 1 - Sun 4/60 */ | ||
50 | #define SM_4C_IPC 0x02 /* Sun4c SparcStation IPC - Sun 4/40 */ | ||
51 | #define SM_4C_SS1PLUS 0x03 /* Sun4c SparcStation 1+ - Sun 4/65 */ | ||
52 | #define SM_4C_SLC 0x04 /* Sun4c SparcStation SLC - Sun 4/20 */ | ||
53 | #define SM_4C_SS2 0x05 /* Sun4c SparcStation 2 - Sun 4/75 */ | ||
54 | #define SM_4C_ELC 0x06 /* Sun4c SparcStation ELC - Sun 4/25 */ | ||
55 | #define SM_4C_IPX 0x07 /* Sun4c SparcStation IPX - Sun 4/50 */ | ||
56 | |||
57 | /* Sun4m machines, these predate the OpenBoot. These values only mean | 36 | /* Sun4m machines, these predate the OpenBoot. These values only mean |
58 | * something if the value in the ARCH field is SM_SUN4M, if it is | 37 | * something if the value in the ARCH field is SM_SUN4M, if it is |
59 | * SM_SUN4M_OBP then you have the following situation: | 38 | * SM_SUN4M_OBP then you have the following situation: |
diff --git a/arch/sparc/include/asm/mbus.h b/arch/sparc/include/asm/mbus.h index 69f07a022ee6..14128bcc5821 100644 --- a/arch/sparc/include/asm/mbus.h +++ b/arch/sparc/include/asm/mbus.h | |||
@@ -8,14 +8,10 @@ | |||
8 | #define _SPARC_MBUS_H | 8 | #define _SPARC_MBUS_H |
9 | 9 | ||
10 | #include <asm/ross.h> /* HyperSparc stuff */ | 10 | #include <asm/ross.h> /* HyperSparc stuff */ |
11 | #include <asm/cypress.h> /* Cypress Chips */ | ||
12 | #include <asm/viking.h> /* Ugh, bug city... */ | 11 | #include <asm/viking.h> /* Ugh, bug city... */ |
13 | 12 | ||
14 | enum mbus_module { | 13 | enum mbus_module { |
15 | HyperSparc = 0, | 14 | HyperSparc = 0, |
16 | Cypress = 1, | ||
17 | Cypress_vE = 2, | ||
18 | Cypress_vD = 3, | ||
19 | Swift_ok = 4, | 15 | Swift_ok = 4, |
20 | Swift_bad_c = 5, | 16 | Swift_bad_c = 5, |
21 | Swift_lots_o_bugs = 6, | 17 | Swift_lots_o_bugs = 6, |
diff --git a/arch/sparc/include/asm/memreg.h b/arch/sparc/include/asm/memreg.h deleted file mode 100644 index 845ad2b39183..000000000000 --- a/arch/sparc/include/asm/memreg.h +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | #ifndef _SPARC_MEMREG_H | ||
2 | #define _SPARC_MEMREG_H | ||
3 | /* memreg.h: Definitions of the values found in the synchronous | ||
4 | * and asynchronous memory error registers when a fault | ||
5 | * occurs on the sun4c. | ||
6 | * | ||
7 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
8 | */ | ||
9 | |||
10 | /* First the synchronous error codes, these are usually just | ||
11 | * normal page faults. | ||
12 | */ | ||
13 | |||
14 | #define SUN4C_SYNC_WDRESET 0x0001 /* watchdog reset */ | ||
15 | #define SUN4C_SYNC_SIZE 0x0002 /* bad access size? whuz this? */ | ||
16 | #define SUN4C_SYNC_PARITY 0x0008 /* bad ram chips caused a parity error */ | ||
17 | #define SUN4C_SYNC_SBUS 0x0010 /* the SBUS had some problems... */ | ||
18 | #define SUN4C_SYNC_NOMEM 0x0020 /* translation to non-existent ram */ | ||
19 | #define SUN4C_SYNC_PROT 0x0040 /* access violated pte protections */ | ||
20 | #define SUN4C_SYNC_NPRESENT 0x0080 /* pte said that page was not present */ | ||
21 | #define SUN4C_SYNC_BADWRITE 0x8000 /* while writing something went bogus */ | ||
22 | |||
23 | #define SUN4C_SYNC_BOLIXED \ | ||
24 | (SUN4C_SYNC_WDRESET | SUN4C_SYNC_SIZE | SUN4C_SYNC_SBUS | \ | ||
25 | SUN4C_SYNC_NOMEM | SUN4C_SYNC_PARITY) | ||
26 | |||
27 | /* Now the asynchronous error codes, these are almost always produced | ||
28 | * by the cache writing things back to memory and getting a bad translation. | ||
29 | * Bad DVMA transactions can cause these faults too. | ||
30 | */ | ||
31 | |||
32 | #define SUN4C_ASYNC_BADDVMA 0x0010 /* error during DVMA access */ | ||
33 | #define SUN4C_ASYNC_NOMEM 0x0020 /* write back pointed to bad phys addr */ | ||
34 | #define SUN4C_ASYNC_BADWB 0x0080 /* write back points to non-present page */ | ||
35 | |||
36 | /* Memory parity error register with associated bit constants. */ | ||
37 | #ifndef __ASSEMBLY__ | ||
38 | extern __volatile__ unsigned long __iomem *sun4c_memerr_reg; | ||
39 | #endif | ||
40 | |||
41 | #define SUN4C_MPE_ERROR 0x80 /* Parity error detected. (ro) */ | ||
42 | #define SUN4C_MPE_MULTI 0x40 /* Multiple parity errors detected. (ro) */ | ||
43 | #define SUN4C_MPE_TEST 0x20 /* Write inverse parity. (rw) */ | ||
44 | #define SUN4C_MPE_CHECK 0x10 /* Enable parity checking. (rw) */ | ||
45 | #define SUN4C_MPE_ERR00 0x08 /* Parity error in bits 0-7. (ro) */ | ||
46 | #define SUN4C_MPE_ERR08 0x04 /* Parity error in bits 8-15. (ro) */ | ||
47 | #define SUN4C_MPE_ERR16 0x02 /* Parity error in bits 16-23. (ro) */ | ||
48 | #define SUN4C_MPE_ERR24 0x01 /* Parity error in bits 24-31. (ro) */ | ||
49 | #define SUN4C_MPE_ERRS 0x0F /* Bit mask for the error bits. (ro) */ | ||
50 | |||
51 | #endif /* !(_SPARC_MEMREG_H) */ | ||
diff --git a/arch/sparc/include/asm/mmu_context_32.h b/arch/sparc/include/asm/mmu_context_32.h index 671a997b9e69..01456c900720 100644 --- a/arch/sparc/include/asm/mmu_context_32.h +++ b/arch/sparc/include/asm/mmu_context_32.h | |||
@@ -1,8 +1,6 @@ | |||
1 | #ifndef __SPARC_MMU_CONTEXT_H | 1 | #ifndef __SPARC_MMU_CONTEXT_H |
2 | #define __SPARC_MMU_CONTEXT_H | 2 | #define __SPARC_MMU_CONTEXT_H |
3 | 3 | ||
4 | #include <asm/btfixup.h> | ||
5 | |||
6 | #ifndef __ASSEMBLY__ | 4 | #ifndef __ASSEMBLY__ |
7 | 5 | ||
8 | #include <asm-generic/mm_hooks.h> | 6 | #include <asm-generic/mm_hooks.h> |
@@ -23,14 +21,11 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) | |||
23 | * all the page tables have been flushed. Our job is to destroy | 21 | * all the page tables have been flushed. Our job is to destroy |
24 | * any remaining processor-specific state. | 22 | * any remaining processor-specific state. |
25 | */ | 23 | */ |
26 | BTFIXUPDEF_CALL(void, destroy_context, struct mm_struct *) | 24 | void destroy_context(struct mm_struct *mm); |
27 | |||
28 | #define destroy_context(mm) BTFIXUP_CALL(destroy_context)(mm) | ||
29 | 25 | ||
30 | /* Switch the current MM context. */ | 26 | /* Switch the current MM context. */ |
31 | BTFIXUPDEF_CALL(void, switch_mm, struct mm_struct *, struct mm_struct *, struct task_struct *) | 27 | void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, |
32 | 28 | struct task_struct *tsk); | |
33 | #define switch_mm(old_mm, mm, tsk) BTFIXUP_CALL(switch_mm)(old_mm, mm, tsk) | ||
34 | 29 | ||
35 | #define deactivate_mm(tsk,mm) do { } while (0) | 30 | #define deactivate_mm(tsk,mm) do { } while (0) |
36 | 31 | ||
diff --git a/arch/sparc/include/asm/obio.h b/arch/sparc/include/asm/obio.h index 4ade0c8a2c79..910c1d9af1f8 100644 --- a/arch/sparc/include/asm/obio.h +++ b/arch/sparc/include/asm/obio.h | |||
@@ -220,19 +220,6 @@ static inline void cc_set_igen(unsigned gen) | |||
220 | "i" (ASI_M_MXCC)); | 220 | "i" (ASI_M_MXCC)); |
221 | } | 221 | } |
222 | 222 | ||
223 | /* +-------+-------------+-----------+------------------------------------+ | ||
224 | * | bcast | devid | sid | levels mask | | ||
225 | * +-------+-------------+-----------+------------------------------------+ | ||
226 | * 31 30 23 22 15 14 0 | ||
227 | */ | ||
228 | #define IGEN_MESSAGE(bcast, devid, sid, levels) \ | ||
229 | (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels)) | ||
230 | |||
231 | static inline void sun4d_send_ipi(int cpu, int level) | ||
232 | { | ||
233 | cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1))); | ||
234 | } | ||
235 | |||
236 | #endif /* !__ASSEMBLY__ */ | 223 | #endif /* !__ASSEMBLY__ */ |
237 | 224 | ||
238 | #endif /* !(_SPARC_OBIO_H) */ | 225 | #endif /* !(_SPARC_OBIO_H) */ |
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h index 71e5e9aeb67e..27517879a6c2 100644 --- a/arch/sparc/include/asm/oplib_32.h +++ b/arch/sparc/include/asm/oplib_32.h | |||
@@ -105,14 +105,6 @@ extern void prom_write(const char *buf, unsigned int len); | |||
105 | extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table, | 105 | extern int prom_startcpu(int cpunode, struct linux_prom_registers *context_table, |
106 | int context, char *program_counter); | 106 | int context, char *program_counter); |
107 | 107 | ||
108 | /* Sun4/sun4c specific memory-management startup hook. */ | ||
109 | |||
110 | /* Map the passed segment in the given context at the passed | ||
111 | * virtual address. | ||
112 | */ | ||
113 | extern void prom_putsegment(int context, unsigned long virt_addr, | ||
114 | int physical_segment); | ||
115 | |||
116 | /* Initialize the memory lists based upon the prom version. */ | 108 | /* Initialize the memory lists based upon the prom version. */ |
117 | void prom_meminit(void); | 109 | void prom_meminit(void); |
118 | 110 | ||
diff --git a/arch/sparc/include/asm/page_32.h b/arch/sparc/include/asm/page_32.h index bb5c2ac4055d..fab78a308ebf 100644 --- a/arch/sparc/include/asm/page_32.h +++ b/arch/sparc/include/asm/page_32.h | |||
@@ -14,8 +14,6 @@ | |||
14 | #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) | 14 | #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) |
15 | #define PAGE_MASK (~(PAGE_SIZE-1)) | 15 | #define PAGE_MASK (~(PAGE_SIZE-1)) |
16 | 16 | ||
17 | #include <asm/btfixup.h> | ||
18 | |||
19 | #ifndef __ASSEMBLY__ | 17 | #ifndef __ASSEMBLY__ |
20 | 18 | ||
21 | #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) | 19 | #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) |
@@ -45,12 +43,6 @@ struct sparc_phys_banks { | |||
45 | 43 | ||
46 | extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1]; | 44 | extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1]; |
47 | 45 | ||
48 | /* Cache alias structure. Entry is valid if context != -1. */ | ||
49 | struct cache_palias { | ||
50 | unsigned long vaddr; | ||
51 | int context; | ||
52 | }; | ||
53 | |||
54 | /* passing structs on the Sparc slow us down tremendously... */ | 46 | /* passing structs on the Sparc slow us down tremendously... */ |
55 | 47 | ||
56 | /* #define STRICT_MM_TYPECHECKS */ | 48 | /* #define STRICT_MM_TYPECHECKS */ |
@@ -116,10 +108,7 @@ typedef unsigned long iopgprot_t; | |||
116 | typedef struct page *pgtable_t; | 108 | typedef struct page *pgtable_t; |
117 | 109 | ||
118 | extern unsigned long sparc_unmapped_base; | 110 | extern unsigned long sparc_unmapped_base; |
119 | 111 | #define TASK_UNMAPPED_BASE sparc_unmapped_base | |
120 | BTFIXUPDEF_SETHI(sparc_unmapped_base) | ||
121 | |||
122 | #define TASK_UNMAPPED_BASE BTFIXUP_SETHI(sparc_unmapped_base) | ||
123 | 112 | ||
124 | #else /* !(__ASSEMBLY__) */ | 113 | #else /* !(__ASSEMBLY__) */ |
125 | 114 | ||
diff --git a/arch/sparc/include/asm/pgalloc_32.h b/arch/sparc/include/asm/pgalloc_32.h index ca2b34456c4b..e5b169b46d21 100644 --- a/arch/sparc/include/asm/pgalloc_32.h +++ b/arch/sparc/include/asm/pgalloc_32.h | |||
@@ -4,8 +4,10 @@ | |||
4 | #include <linux/kernel.h> | 4 | #include <linux/kernel.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
6 | 6 | ||
7 | #include <asm/pgtsrmmu.h> | ||
8 | #include <asm/pgtable.h> | ||
9 | #include <asm/vaddrs.h> | ||
7 | #include <asm/page.h> | 10 | #include <asm/page.h> |
8 | #include <asm/btfixup.h> | ||
9 | 11 | ||
10 | struct page; | 12 | struct page; |
11 | 13 | ||
@@ -15,54 +17,74 @@ extern struct pgtable_cache_struct { | |||
15 | unsigned long pgtable_cache_sz; | 17 | unsigned long pgtable_cache_sz; |
16 | unsigned long pgd_cache_sz; | 18 | unsigned long pgd_cache_sz; |
17 | } pgt_quicklists; | 19 | } pgt_quicklists; |
20 | |||
21 | unsigned long srmmu_get_nocache(int size, int align); | ||
22 | void srmmu_free_nocache(unsigned long vaddr, int size); | ||
23 | |||
18 | #define pgd_quicklist (pgt_quicklists.pgd_cache) | 24 | #define pgd_quicklist (pgt_quicklists.pgd_cache) |
19 | #define pmd_quicklist ((unsigned long *)0) | 25 | #define pmd_quicklist ((unsigned long *)0) |
20 | #define pte_quicklist (pgt_quicklists.pte_cache) | 26 | #define pte_quicklist (pgt_quicklists.pte_cache) |
21 | #define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) | 27 | #define pgtable_cache_size (pgt_quicklists.pgtable_cache_sz) |
22 | #define pgd_cache_size (pgt_quicklists.pgd_cache_sz) | 28 | #define pgd_cache_size (pgt_quicklists.pgd_cache_sz) |
23 | 29 | ||
24 | extern void check_pgt_cache(void); | 30 | #define check_pgt_cache() do { } while (0) |
25 | BTFIXUPDEF_CALL(void, do_check_pgt_cache, int, int) | ||
26 | #define do_check_pgt_cache(low,high) BTFIXUP_CALL(do_check_pgt_cache)(low,high) | ||
27 | |||
28 | BTFIXUPDEF_CALL(pgd_t *, get_pgd_fast, void) | ||
29 | #define get_pgd_fast() BTFIXUP_CALL(get_pgd_fast)() | ||
30 | 31 | ||
31 | BTFIXUPDEF_CALL(void, free_pgd_fast, pgd_t *) | 32 | pgd_t *get_pgd_fast(void); |
32 | #define free_pgd_fast(pgd) BTFIXUP_CALL(free_pgd_fast)(pgd) | 33 | static inline void free_pgd_fast(pgd_t *pgd) |
34 | { | ||
35 | srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE); | ||
36 | } | ||
33 | 37 | ||
34 | #define pgd_free(mm, pgd) free_pgd_fast(pgd) | 38 | #define pgd_free(mm, pgd) free_pgd_fast(pgd) |
35 | #define pgd_alloc(mm) get_pgd_fast() | 39 | #define pgd_alloc(mm) get_pgd_fast() |
36 | 40 | ||
37 | BTFIXUPDEF_CALL(void, pgd_set, pgd_t *, pmd_t *) | 41 | static inline void pgd_set(pgd_t * pgdp, pmd_t * pmdp) |
38 | #define pgd_set(pgdp,pmdp) BTFIXUP_CALL(pgd_set)(pgdp,pmdp) | 42 | { |
43 | unsigned long pa = __nocache_pa((unsigned long)pmdp); | ||
44 | |||
45 | set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (pa >> 4))); | ||
46 | } | ||
47 | |||
39 | #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) | 48 | #define pgd_populate(MM, PGD, PMD) pgd_set(PGD, PMD) |
40 | 49 | ||
41 | BTFIXUPDEF_CALL(pmd_t *, pmd_alloc_one, struct mm_struct *, unsigned long) | 50 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, |
42 | #define pmd_alloc_one(mm, address) BTFIXUP_CALL(pmd_alloc_one)(mm, address) | 51 | unsigned long address) |
52 | { | ||
53 | return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, | ||
54 | SRMMU_PMD_TABLE_SIZE); | ||
55 | } | ||
43 | 56 | ||
44 | BTFIXUPDEF_CALL(void, free_pmd_fast, pmd_t *) | 57 | static inline void free_pmd_fast(pmd_t * pmd) |
45 | #define free_pmd_fast(pmd) BTFIXUP_CALL(free_pmd_fast)(pmd) | 58 | { |
59 | srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE); | ||
60 | } | ||
46 | 61 | ||
47 | #define pmd_free(mm, pmd) free_pmd_fast(pmd) | 62 | #define pmd_free(mm, pmd) free_pmd_fast(pmd) |
48 | #define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) | 63 | #define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd) |
49 | 64 | ||
50 | BTFIXUPDEF_CALL(void, pmd_populate, pmd_t *, struct page *) | 65 | void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep); |
51 | #define pmd_populate(MM, PMD, PTE) BTFIXUP_CALL(pmd_populate)(PMD, PTE) | ||
52 | #define pmd_pgtable(pmd) pmd_page(pmd) | 66 | #define pmd_pgtable(pmd) pmd_page(pmd) |
53 | BTFIXUPDEF_CALL(void, pmd_set, pmd_t *, pte_t *) | ||
54 | #define pmd_populate_kernel(MM, PMD, PTE) BTFIXUP_CALL(pmd_set)(PMD, PTE) | ||
55 | 67 | ||
56 | BTFIXUPDEF_CALL(pgtable_t , pte_alloc_one, struct mm_struct *, unsigned long) | 68 | void pmd_set(pmd_t *pmdp, pte_t *ptep); |
57 | #define pte_alloc_one(mm, address) BTFIXUP_CALL(pte_alloc_one)(mm, address) | 69 | #define pmd_populate_kernel(MM, PMD, PTE) pmd_set(PMD, PTE) |
58 | BTFIXUPDEF_CALL(pte_t *, pte_alloc_one_kernel, struct mm_struct *, unsigned long) | 70 | |
59 | #define pte_alloc_one_kernel(mm, addr) BTFIXUP_CALL(pte_alloc_one_kernel)(mm, addr) | 71 | pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address); |
72 | |||
73 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | ||
74 | unsigned long address) | ||
75 | { | ||
76 | return (pte_t *)srmmu_get_nocache(PTE_SIZE, PTE_SIZE); | ||
77 | } | ||
78 | |||
79 | |||
80 | static inline void free_pte_fast(pte_t *pte) | ||
81 | { | ||
82 | srmmu_free_nocache((unsigned long)pte, PTE_SIZE); | ||
83 | } | ||
60 | 84 | ||
61 | BTFIXUPDEF_CALL(void, free_pte_fast, pte_t *) | 85 | #define pte_free_kernel(mm, pte) free_pte_fast(pte) |
62 | #define pte_free_kernel(mm, pte) BTFIXUP_CALL(free_pte_fast)(pte) | ||
63 | 86 | ||
64 | BTFIXUPDEF_CALL(void, pte_free, pgtable_t ) | 87 | void pte_free(struct mm_struct * mm, pgtable_t pte); |
65 | #define pte_free(mm, pte) BTFIXUP_CALL(pte_free)(pte) | ||
66 | #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) | 88 | #define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte) |
67 | 89 | ||
68 | #endif /* _SPARC_PGALLOC_H */ | 90 | #endif /* _SPARC_PGALLOC_H */ |
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 3d7101860e68..cbbbed5cb3aa 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h | |||
@@ -16,11 +16,9 @@ | |||
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/swap.h> | 17 | #include <linux/swap.h> |
18 | #include <asm/types.h> | 18 | #include <asm/types.h> |
19 | #include <asm/pgtsun4c.h> | ||
20 | #include <asm/pgtsrmmu.h> | 19 | #include <asm/pgtsrmmu.h> |
21 | #include <asm/vac-ops.h> | 20 | #include <asm/vaddrs.h> |
22 | #include <asm/oplib.h> | 21 | #include <asm/oplib.h> |
23 | #include <asm/btfixup.h> | ||
24 | #include <asm/cpu_type.h> | 22 | #include <asm/cpu_type.h> |
25 | 23 | ||
26 | 24 | ||
@@ -30,87 +28,55 @@ struct page; | |||
30 | extern void load_mmu(void); | 28 | extern void load_mmu(void); |
31 | extern unsigned long calc_highpages(void); | 29 | extern unsigned long calc_highpages(void); |
32 | 30 | ||
33 | BTFIXUPDEF_SIMM13(pgdir_shift) | ||
34 | BTFIXUPDEF_SETHI(pgdir_size) | ||
35 | BTFIXUPDEF_SETHI(pgdir_mask) | ||
36 | |||
37 | BTFIXUPDEF_SIMM13(ptrs_per_pmd) | ||
38 | BTFIXUPDEF_SIMM13(ptrs_per_pgd) | ||
39 | BTFIXUPDEF_SIMM13(user_ptrs_per_pgd) | ||
40 | |||
41 | #define pte_ERROR(e) __builtin_trap() | 31 | #define pte_ERROR(e) __builtin_trap() |
42 | #define pmd_ERROR(e) __builtin_trap() | 32 | #define pmd_ERROR(e) __builtin_trap() |
43 | #define pgd_ERROR(e) __builtin_trap() | 33 | #define pgd_ERROR(e) __builtin_trap() |
44 | 34 | ||
45 | BTFIXUPDEF_INT(page_none) | 35 | #define PMD_SHIFT 22 |
46 | BTFIXUPDEF_INT(page_copy) | ||
47 | BTFIXUPDEF_INT(page_readonly) | ||
48 | BTFIXUPDEF_INT(page_kernel) | ||
49 | |||
50 | #define PMD_SHIFT SUN4C_PMD_SHIFT | ||
51 | #define PMD_SIZE (1UL << PMD_SHIFT) | 36 | #define PMD_SIZE (1UL << PMD_SHIFT) |
52 | #define PMD_MASK (~(PMD_SIZE-1)) | 37 | #define PMD_MASK (~(PMD_SIZE-1)) |
53 | #define PMD_ALIGN(__addr) (((__addr) + ~PMD_MASK) & PMD_MASK) | 38 | #define PMD_ALIGN(__addr) (((__addr) + ~PMD_MASK) & PMD_MASK) |
54 | #define PGDIR_SHIFT BTFIXUP_SIMM13(pgdir_shift) | 39 | #define PGDIR_SHIFT SRMMU_PGDIR_SHIFT |
55 | #define PGDIR_SIZE BTFIXUP_SETHI(pgdir_size) | 40 | #define PGDIR_SIZE SRMMU_PGDIR_SIZE |
56 | #define PGDIR_MASK BTFIXUP_SETHI(pgdir_mask) | 41 | #define PGDIR_MASK SRMMU_PGDIR_MASK |
57 | #define PTRS_PER_PTE 1024 | 42 | #define PTRS_PER_PTE 1024 |
58 | #define PTRS_PER_PMD BTFIXUP_SIMM13(ptrs_per_pmd) | 43 | #define PTRS_PER_PMD SRMMU_PTRS_PER_PMD |
59 | #define PTRS_PER_PGD BTFIXUP_SIMM13(ptrs_per_pgd) | 44 | #define PTRS_PER_PGD SRMMU_PTRS_PER_PGD |
60 | #define USER_PTRS_PER_PGD BTFIXUP_SIMM13(user_ptrs_per_pgd) | 45 | #define USER_PTRS_PER_PGD PAGE_OFFSET / SRMMU_PGDIR_SIZE |
61 | #define FIRST_USER_ADDRESS 0 | 46 | #define FIRST_USER_ADDRESS 0 |
62 | #define PTE_SIZE (PTRS_PER_PTE*4) | 47 | #define PTE_SIZE (PTRS_PER_PTE*4) |
63 | 48 | ||
64 | #define PAGE_NONE __pgprot(BTFIXUP_INT(page_none)) | 49 | #define PAGE_NONE SRMMU_PAGE_NONE |
65 | extern pgprot_t PAGE_SHARED; | 50 | #define PAGE_SHARED SRMMU_PAGE_SHARED |
66 | #define PAGE_COPY __pgprot(BTFIXUP_INT(page_copy)) | 51 | #define PAGE_COPY SRMMU_PAGE_COPY |
67 | #define PAGE_READONLY __pgprot(BTFIXUP_INT(page_readonly)) | 52 | #define PAGE_READONLY SRMMU_PAGE_RDONLY |
68 | 53 | #define PAGE_KERNEL SRMMU_PAGE_KERNEL | |
69 | extern unsigned long page_kernel; | ||
70 | |||
71 | #ifdef MODULE | ||
72 | #define PAGE_KERNEL page_kernel | ||
73 | #else | ||
74 | #define PAGE_KERNEL __pgprot(BTFIXUP_INT(page_kernel)) | ||
75 | #endif | ||
76 | 54 | ||
77 | /* Top-level page directory */ | 55 | /* Top-level page directory */ |
78 | extern pgd_t swapper_pg_dir[1024]; | 56 | extern pgd_t swapper_pg_dir[1024]; |
79 | 57 | ||
80 | extern void paging_init(void); | 58 | extern void paging_init(void); |
81 | 59 | ||
82 | /* Page table for 0-4MB for everybody, on the Sparc this | ||
83 | * holds the same as on the i386. | ||
84 | */ | ||
85 | extern pte_t pg0[1024]; | ||
86 | extern pte_t pg1[1024]; | ||
87 | extern pte_t pg2[1024]; | ||
88 | extern pte_t pg3[1024]; | ||
89 | |||
90 | extern unsigned long ptr_in_current_pgd; | 60 | extern unsigned long ptr_in_current_pgd; |
91 | 61 | ||
92 | /* Here is a trick, since mmap.c need the initializer elements for | 62 | /* xwr */ |
93 | * protection_map[] to be constant at compile time, I set the following | 63 | #define __P000 PAGE_NONE |
94 | * to all zeros. I set it to the real values after I link in the | 64 | #define __P001 PAGE_READONLY |
95 | * appropriate MMU page table routines at boot time. | 65 | #define __P010 PAGE_COPY |
96 | */ | 66 | #define __P011 PAGE_COPY |
97 | #define __P000 __pgprot(0) | 67 | #define __P100 PAGE_READONLY |
98 | #define __P001 __pgprot(0) | 68 | #define __P101 PAGE_READONLY |
99 | #define __P010 __pgprot(0) | 69 | #define __P110 PAGE_COPY |
100 | #define __P011 __pgprot(0) | 70 | #define __P111 PAGE_COPY |
101 | #define __P100 __pgprot(0) | 71 | |
102 | #define __P101 __pgprot(0) | 72 | #define __S000 PAGE_NONE |
103 | #define __P110 __pgprot(0) | 73 | #define __S001 PAGE_READONLY |
104 | #define __P111 __pgprot(0) | 74 | #define __S010 PAGE_SHARED |
105 | 75 | #define __S011 PAGE_SHARED | |
106 | #define __S000 __pgprot(0) | 76 | #define __S100 PAGE_READONLY |
107 | #define __S001 __pgprot(0) | 77 | #define __S101 PAGE_READONLY |
108 | #define __S010 __pgprot(0) | 78 | #define __S110 PAGE_SHARED |
109 | #define __S011 __pgprot(0) | 79 | #define __S111 PAGE_SHARED |
110 | #define __S100 __pgprot(0) | ||
111 | #define __S101 __pgprot(0) | ||
112 | #define __S110 __pgprot(0) | ||
113 | #define __S111 __pgprot(0) | ||
114 | 80 | ||
115 | extern int num_contexts; | 81 | extern int num_contexts; |
116 | 82 | ||
@@ -137,82 +103,137 @@ extern unsigned long empty_zero_page; | |||
137 | #define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page)) | 103 | #define ZERO_PAGE(vaddr) (virt_to_page(&empty_zero_page)) |
138 | 104 | ||
139 | /* | 105 | /* |
106 | * In general all page table modifications should use the V8 atomic | ||
107 | * swap instruction. This insures the mmu and the cpu are in sync | ||
108 | * with respect to ref/mod bits in the page tables. | ||
109 | */ | ||
110 | static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value) | ||
111 | { | ||
112 | __asm__ __volatile__("swap [%2], %0" : "=&r" (value) : "0" (value), "r" (addr)); | ||
113 | return value; | ||
114 | } | ||
115 | |||
116 | /* Certain architectures need to do special things when pte's | ||
117 | * within a page table are directly modified. Thus, the following | ||
118 | * hook is made available. | ||
140 | */ | 119 | */ |
141 | BTFIXUPDEF_CALL_CONST(struct page *, pmd_page, pmd_t) | ||
142 | BTFIXUPDEF_CALL_CONST(unsigned long, pgd_page_vaddr, pgd_t) | ||
143 | 120 | ||
144 | #define pmd_page(pmd) BTFIXUP_CALL(pmd_page)(pmd) | 121 | static inline void set_pte(pte_t *ptep, pte_t pteval) |
145 | #define pgd_page_vaddr(pgd) BTFIXUP_CALL(pgd_page_vaddr)(pgd) | 122 | { |
123 | srmmu_swap((unsigned long *)ptep, pte_val(pteval)); | ||
124 | } | ||
125 | |||
126 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) | ||
127 | |||
128 | static inline int srmmu_device_memory(unsigned long x) | ||
129 | { | ||
130 | return ((x & 0xF0000000) != 0); | ||
131 | } | ||
132 | |||
133 | static inline struct page *pmd_page(pmd_t pmd) | ||
134 | { | ||
135 | if (srmmu_device_memory(pmd_val(pmd))) | ||
136 | BUG(); | ||
137 | return pfn_to_page((pmd_val(pmd) & SRMMU_PTD_PMASK) >> (PAGE_SHIFT-4)); | ||
138 | } | ||
139 | |||
140 | static inline unsigned long pgd_page_vaddr(pgd_t pgd) | ||
141 | { | ||
142 | if (srmmu_device_memory(pgd_val(pgd))) { | ||
143 | return ~0; | ||
144 | } else { | ||
145 | unsigned long v = pgd_val(pgd) & SRMMU_PTD_PMASK; | ||
146 | return (unsigned long)__nocache_va(v << 4); | ||
147 | } | ||
148 | } | ||
146 | 149 | ||
147 | BTFIXUPDEF_CALL_CONST(int, pte_present, pte_t) | 150 | static inline int pte_present(pte_t pte) |
148 | BTFIXUPDEF_CALL(void, pte_clear, pte_t *) | 151 | { |
152 | return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); | ||
153 | } | ||
149 | 154 | ||
150 | static inline int pte_none(pte_t pte) | 155 | static inline int pte_none(pte_t pte) |
151 | { | 156 | { |
152 | return !pte_val(pte); | 157 | return !pte_val(pte); |
153 | } | 158 | } |
154 | 159 | ||
155 | #define pte_present(pte) BTFIXUP_CALL(pte_present)(pte) | 160 | static inline void __pte_clear(pte_t *ptep) |
156 | #define pte_clear(mm,addr,pte) BTFIXUP_CALL(pte_clear)(pte) | 161 | { |
162 | set_pte(ptep, __pte(0)); | ||
163 | } | ||
164 | |||
165 | static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) | ||
166 | { | ||
167 | __pte_clear(ptep); | ||
168 | } | ||
169 | |||
170 | static inline int pmd_bad(pmd_t pmd) | ||
171 | { | ||
172 | return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; | ||
173 | } | ||
157 | 174 | ||
158 | BTFIXUPDEF_CALL_CONST(int, pmd_bad, pmd_t) | 175 | static inline int pmd_present(pmd_t pmd) |
159 | BTFIXUPDEF_CALL_CONST(int, pmd_present, pmd_t) | 176 | { |
160 | BTFIXUPDEF_CALL(void, pmd_clear, pmd_t *) | 177 | return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); |
178 | } | ||
161 | 179 | ||
162 | static inline int pmd_none(pmd_t pmd) | 180 | static inline int pmd_none(pmd_t pmd) |
163 | { | 181 | { |
164 | return !pmd_val(pmd); | 182 | return !pmd_val(pmd); |
165 | } | 183 | } |
166 | 184 | ||
167 | #define pmd_bad(pmd) BTFIXUP_CALL(pmd_bad)(pmd) | 185 | static inline void pmd_clear(pmd_t *pmdp) |
168 | #define pmd_present(pmd) BTFIXUP_CALL(pmd_present)(pmd) | 186 | { |
169 | #define pmd_clear(pmd) BTFIXUP_CALL(pmd_clear)(pmd) | 187 | int i; |
188 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) | ||
189 | set_pte((pte_t *)&pmdp->pmdv[i], __pte(0)); | ||
190 | } | ||
170 | 191 | ||
171 | BTFIXUPDEF_CALL_CONST(int, pgd_none, pgd_t) | 192 | static inline int pgd_none(pgd_t pgd) |
172 | BTFIXUPDEF_CALL_CONST(int, pgd_bad, pgd_t) | 193 | { |
173 | BTFIXUPDEF_CALL_CONST(int, pgd_present, pgd_t) | 194 | return !(pgd_val(pgd) & 0xFFFFFFF); |
174 | BTFIXUPDEF_CALL(void, pgd_clear, pgd_t *) | 195 | } |
175 | 196 | ||
176 | #define pgd_none(pgd) BTFIXUP_CALL(pgd_none)(pgd) | 197 | static inline int pgd_bad(pgd_t pgd) |
177 | #define pgd_bad(pgd) BTFIXUP_CALL(pgd_bad)(pgd) | 198 | { |
178 | #define pgd_present(pgd) BTFIXUP_CALL(pgd_present)(pgd) | 199 | return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; |
179 | #define pgd_clear(pgd) BTFIXUP_CALL(pgd_clear)(pgd) | 200 | } |
201 | |||
202 | static inline int pgd_present(pgd_t pgd) | ||
203 | { | ||
204 | return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); | ||
205 | } | ||
206 | |||
207 | static inline void pgd_clear(pgd_t *pgdp) | ||
208 | { | ||
209 | set_pte((pte_t *)pgdp, __pte(0)); | ||
210 | } | ||
180 | 211 | ||
181 | /* | 212 | /* |
182 | * The following only work if pte_present() is true. | 213 | * The following only work if pte_present() is true. |
183 | * Undefined behaviour if not.. | 214 | * Undefined behaviour if not.. |
184 | */ | 215 | */ |
185 | BTFIXUPDEF_HALF(pte_writei) | ||
186 | BTFIXUPDEF_HALF(pte_dirtyi) | ||
187 | BTFIXUPDEF_HALF(pte_youngi) | ||
188 | |||
189 | static int pte_write(pte_t pte) __attribute_const__; | ||
190 | static inline int pte_write(pte_t pte) | 216 | static inline int pte_write(pte_t pte) |
191 | { | 217 | { |
192 | return pte_val(pte) & BTFIXUP_HALF(pte_writei); | 218 | return pte_val(pte) & SRMMU_WRITE; |
193 | } | 219 | } |
194 | 220 | ||
195 | static int pte_dirty(pte_t pte) __attribute_const__; | ||
196 | static inline int pte_dirty(pte_t pte) | 221 | static inline int pte_dirty(pte_t pte) |
197 | { | 222 | { |
198 | return pte_val(pte) & BTFIXUP_HALF(pte_dirtyi); | 223 | return pte_val(pte) & SRMMU_DIRTY; |
199 | } | 224 | } |
200 | 225 | ||
201 | static int pte_young(pte_t pte) __attribute_const__; | ||
202 | static inline int pte_young(pte_t pte) | 226 | static inline int pte_young(pte_t pte) |
203 | { | 227 | { |
204 | return pte_val(pte) & BTFIXUP_HALF(pte_youngi); | 228 | return pte_val(pte) & SRMMU_REF; |
205 | } | 229 | } |
206 | 230 | ||
207 | /* | 231 | /* |
208 | * The following only work if pte_present() is not true. | 232 | * The following only work if pte_present() is not true. |
209 | */ | 233 | */ |
210 | BTFIXUPDEF_HALF(pte_filei) | ||
211 | |||
212 | static int pte_file(pte_t pte) __attribute_const__; | ||
213 | static inline int pte_file(pte_t pte) | 234 | static inline int pte_file(pte_t pte) |
214 | { | 235 | { |
215 | return pte_val(pte) & BTFIXUP_HALF(pte_filei); | 236 | return pte_val(pte) & SRMMU_FILE; |
216 | } | 237 | } |
217 | 238 | ||
218 | static inline int pte_special(pte_t pte) | 239 | static inline int pte_special(pte_t pte) |
@@ -220,68 +241,85 @@ static inline int pte_special(pte_t pte) | |||
220 | return 0; | 241 | return 0; |
221 | } | 242 | } |
222 | 243 | ||
223 | /* | ||
224 | */ | ||
225 | BTFIXUPDEF_HALF(pte_wrprotecti) | ||
226 | BTFIXUPDEF_HALF(pte_mkcleani) | ||
227 | BTFIXUPDEF_HALF(pte_mkoldi) | ||
228 | |||
229 | static pte_t pte_wrprotect(pte_t pte) __attribute_const__; | ||
230 | static inline pte_t pte_wrprotect(pte_t pte) | 244 | static inline pte_t pte_wrprotect(pte_t pte) |
231 | { | 245 | { |
232 | return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_wrprotecti)); | 246 | return __pte(pte_val(pte) & ~SRMMU_WRITE); |
233 | } | 247 | } |
234 | 248 | ||
235 | static pte_t pte_mkclean(pte_t pte) __attribute_const__; | ||
236 | static inline pte_t pte_mkclean(pte_t pte) | 249 | static inline pte_t pte_mkclean(pte_t pte) |
237 | { | 250 | { |
238 | return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_mkcleani)); | 251 | return __pte(pte_val(pte) & ~SRMMU_DIRTY); |
239 | } | 252 | } |
240 | 253 | ||
241 | static pte_t pte_mkold(pte_t pte) __attribute_const__; | ||
242 | static inline pte_t pte_mkold(pte_t pte) | 254 | static inline pte_t pte_mkold(pte_t pte) |
243 | { | 255 | { |
244 | return __pte(pte_val(pte) & ~BTFIXUP_HALF(pte_mkoldi)); | 256 | return __pte(pte_val(pte) & ~SRMMU_REF); |
245 | } | 257 | } |
246 | 258 | ||
247 | BTFIXUPDEF_CALL_CONST(pte_t, pte_mkwrite, pte_t) | 259 | static inline pte_t pte_mkwrite(pte_t pte) |
248 | BTFIXUPDEF_CALL_CONST(pte_t, pte_mkdirty, pte_t) | 260 | { |
249 | BTFIXUPDEF_CALL_CONST(pte_t, pte_mkyoung, pte_t) | 261 | return __pte(pte_val(pte) | SRMMU_WRITE); |
262 | } | ||
263 | |||
264 | static inline pte_t pte_mkdirty(pte_t pte) | ||
265 | { | ||
266 | return __pte(pte_val(pte) | SRMMU_DIRTY); | ||
267 | } | ||
250 | 268 | ||
251 | #define pte_mkwrite(pte) BTFIXUP_CALL(pte_mkwrite)(pte) | 269 | static inline pte_t pte_mkyoung(pte_t pte) |
252 | #define pte_mkdirty(pte) BTFIXUP_CALL(pte_mkdirty)(pte) | 270 | { |
253 | #define pte_mkyoung(pte) BTFIXUP_CALL(pte_mkyoung)(pte) | 271 | return __pte(pte_val(pte) | SRMMU_REF); |
272 | } | ||
254 | 273 | ||
255 | #define pte_mkspecial(pte) (pte) | 274 | #define pte_mkspecial(pte) (pte) |
256 | 275 | ||
257 | #define pfn_pte(pfn, prot) mk_pte(pfn_to_page(pfn), prot) | 276 | #define pfn_pte(pfn, prot) mk_pte(pfn_to_page(pfn), prot) |
258 | 277 | ||
259 | BTFIXUPDEF_CALL(unsigned long, pte_pfn, pte_t) | 278 | static inline unsigned long pte_pfn(pte_t pte) |
260 | #define pte_pfn(pte) BTFIXUP_CALL(pte_pfn)(pte) | 279 | { |
280 | if (srmmu_device_memory(pte_val(pte))) { | ||
281 | /* Just return something that will cause | ||
282 | * pfn_valid() to return false. This makes | ||
283 | * copy_one_pte() to just directly copy to | ||
284 | * PTE over. | ||
285 | */ | ||
286 | return ~0UL; | ||
287 | } | ||
288 | return (pte_val(pte) & SRMMU_PTE_PMASK) >> (PAGE_SHIFT-4); | ||
289 | } | ||
290 | |||
261 | #define pte_page(pte) pfn_to_page(pte_pfn(pte)) | 291 | #define pte_page(pte) pfn_to_page(pte_pfn(pte)) |
262 | 292 | ||
263 | /* | 293 | /* |
264 | * Conversion functions: convert a page and protection to a page entry, | 294 | * Conversion functions: convert a page and protection to a page entry, |
265 | * and a page entry and page directory to the page they refer to. | 295 | * and a page entry and page directory to the page they refer to. |
266 | */ | 296 | */ |
267 | BTFIXUPDEF_CALL_CONST(pte_t, mk_pte, struct page *, pgprot_t) | 297 | static inline pte_t mk_pte(struct page *page, pgprot_t pgprot) |
268 | 298 | { | |
269 | BTFIXUPDEF_CALL_CONST(pte_t, mk_pte_phys, unsigned long, pgprot_t) | 299 | return __pte((page_to_pfn(page) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); |
270 | BTFIXUPDEF_CALL_CONST(pte_t, mk_pte_io, unsigned long, pgprot_t, int) | 300 | } |
271 | BTFIXUPDEF_CALL_CONST(pgprot_t, pgprot_noncached, pgprot_t) | ||
272 | 301 | ||
273 | #define mk_pte(page,pgprot) BTFIXUP_CALL(mk_pte)(page,pgprot) | 302 | static inline pte_t mk_pte_phys(unsigned long page, pgprot_t pgprot) |
274 | #define mk_pte_phys(page,pgprot) BTFIXUP_CALL(mk_pte_phys)(page,pgprot) | 303 | { |
275 | #define mk_pte_io(page,pgprot,space) BTFIXUP_CALL(mk_pte_io)(page,pgprot,space) | 304 | return __pte(((page) >> 4) | pgprot_val(pgprot)); |
305 | } | ||
276 | 306 | ||
277 | #define pgprot_noncached(pgprot) BTFIXUP_CALL(pgprot_noncached)(pgprot) | 307 | static inline pte_t mk_pte_io(unsigned long page, pgprot_t pgprot, int space) |
308 | { | ||
309 | return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); | ||
310 | } | ||
278 | 311 | ||
279 | BTFIXUPDEF_INT(pte_modify_mask) | 312 | #define pgprot_noncached pgprot_noncached |
313 | static inline pgprot_t pgprot_noncached(pgprot_t prot) | ||
314 | { | ||
315 | prot &= ~__pgprot(SRMMU_CACHE); | ||
316 | return prot; | ||
317 | } | ||
280 | 318 | ||
281 | static pte_t pte_modify(pte_t pte, pgprot_t newprot) __attribute_const__; | 319 | static pte_t pte_modify(pte_t pte, pgprot_t newprot) __attribute_const__; |
282 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | 320 | static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) |
283 | { | 321 | { |
284 | return __pte((pte_val(pte) & BTFIXUP_INT(pte_modify_mask)) | | 322 | return __pte((pte_val(pte) & SRMMU_CHG_MASK) | |
285 | pgprot_val(newprot)); | 323 | pgprot_val(newprot)); |
286 | } | 324 | } |
287 | 325 | ||
@@ -294,74 +332,69 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) | |||
294 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) | 332 | #define pgd_offset_k(address) pgd_offset(&init_mm, address) |
295 | 333 | ||
296 | /* Find an entry in the second-level page table.. */ | 334 | /* Find an entry in the second-level page table.. */ |
297 | BTFIXUPDEF_CALL(pmd_t *, pmd_offset, pgd_t *, unsigned long) | 335 | static inline pmd_t *pmd_offset(pgd_t * dir, unsigned long address) |
298 | #define pmd_offset(dir,addr) BTFIXUP_CALL(pmd_offset)(dir,addr) | 336 | { |
337 | return (pmd_t *) pgd_page_vaddr(*dir) + | ||
338 | ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); | ||
339 | } | ||
299 | 340 | ||
300 | /* Find an entry in the third-level page table.. */ | 341 | /* Find an entry in the third-level page table.. */ |
301 | BTFIXUPDEF_CALL(pte_t *, pte_offset_kernel, pmd_t *, unsigned long) | 342 | pte_t *pte_offset_kernel(pmd_t * dir, unsigned long address); |
302 | #define pte_offset_kernel(dir,addr) BTFIXUP_CALL(pte_offset_kernel)(dir,addr) | ||
303 | 343 | ||
304 | /* | 344 | /* |
305 | * This shortcut works on sun4m (and sun4d) because the nocache area is static, | 345 | * This shortcut works on sun4m (and sun4d) because the nocache area is static. |
306 | * and sun4c is guaranteed to have no highmem anyway. | ||
307 | */ | 346 | */ |
308 | #define pte_offset_map(d, a) pte_offset_kernel(d,a) | 347 | #define pte_offset_map(d, a) pte_offset_kernel(d,a) |
309 | #define pte_unmap(pte) do{}while(0) | 348 | #define pte_unmap(pte) do{}while(0) |
310 | 349 | ||
311 | /* Certain architectures need to do special things when pte's | ||
312 | * within a page table are directly modified. Thus, the following | ||
313 | * hook is made available. | ||
314 | */ | ||
315 | |||
316 | BTFIXUPDEF_CALL(void, set_pte, pte_t *, pte_t) | ||
317 | |||
318 | #define set_pte(ptep,pteval) BTFIXUP_CALL(set_pte)(ptep,pteval) | ||
319 | #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) | ||
320 | |||
321 | struct seq_file; | 350 | struct seq_file; |
322 | BTFIXUPDEF_CALL(void, mmu_info, struct seq_file *) | 351 | void mmu_info(struct seq_file *m); |
323 | |||
324 | #define mmu_info(p) BTFIXUP_CALL(mmu_info)(p) | ||
325 | 352 | ||
326 | /* Fault handler stuff... */ | 353 | /* Fault handler stuff... */ |
327 | #define FAULT_CODE_PROT 0x1 | 354 | #define FAULT_CODE_PROT 0x1 |
328 | #define FAULT_CODE_WRITE 0x2 | 355 | #define FAULT_CODE_WRITE 0x2 |
329 | #define FAULT_CODE_USER 0x4 | 356 | #define FAULT_CODE_USER 0x4 |
330 | 357 | ||
331 | BTFIXUPDEF_CALL(void, update_mmu_cache, struct vm_area_struct *, unsigned long, pte_t *) | 358 | #define update_mmu_cache(vma, address, ptep) do { } while (0) |
332 | |||
333 | #define update_mmu_cache(vma,addr,ptep) BTFIXUP_CALL(update_mmu_cache)(vma,addr,ptep) | ||
334 | |||
335 | BTFIXUPDEF_CALL(void, sparc_mapiorange, unsigned int, unsigned long, | ||
336 | unsigned long, unsigned int) | ||
337 | BTFIXUPDEF_CALL(void, sparc_unmapiorange, unsigned long, unsigned int) | ||
338 | #define sparc_mapiorange(bus,pa,va,len) BTFIXUP_CALL(sparc_mapiorange)(bus,pa,va,len) | ||
339 | #define sparc_unmapiorange(va,len) BTFIXUP_CALL(sparc_unmapiorange)(va,len) | ||
340 | 359 | ||
341 | extern int invalid_segment; | 360 | void srmmu_mapiorange(unsigned int bus, unsigned long xpa, |
361 | unsigned long xva, unsigned int len); | ||
362 | void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len); | ||
342 | 363 | ||
343 | /* Encode and de-code a swap entry */ | 364 | /* Encode and de-code a swap entry */ |
344 | BTFIXUPDEF_CALL(unsigned long, __swp_type, swp_entry_t) | 365 | static inline unsigned long __swp_type(swp_entry_t entry) |
345 | BTFIXUPDEF_CALL(unsigned long, __swp_offset, swp_entry_t) | 366 | { |
346 | BTFIXUPDEF_CALL(swp_entry_t, __swp_entry, unsigned long, unsigned long) | 367 | return (entry.val >> SRMMU_SWP_TYPE_SHIFT) & SRMMU_SWP_TYPE_MASK; |
368 | } | ||
369 | |||
370 | static inline unsigned long __swp_offset(swp_entry_t entry) | ||
371 | { | ||
372 | return (entry.val >> SRMMU_SWP_OFF_SHIFT) & SRMMU_SWP_OFF_MASK; | ||
373 | } | ||
347 | 374 | ||
348 | #define __swp_type(__x) BTFIXUP_CALL(__swp_type)(__x) | 375 | static inline swp_entry_t __swp_entry(unsigned long type, unsigned long offset) |
349 | #define __swp_offset(__x) BTFIXUP_CALL(__swp_offset)(__x) | 376 | { |
350 | #define __swp_entry(__type,__off) BTFIXUP_CALL(__swp_entry)(__type,__off) | 377 | return (swp_entry_t) { |
378 | (type & SRMMU_SWP_TYPE_MASK) << SRMMU_SWP_TYPE_SHIFT | ||
379 | | (offset & SRMMU_SWP_OFF_MASK) << SRMMU_SWP_OFF_SHIFT }; | ||
380 | } | ||
351 | 381 | ||
352 | #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) | 382 | #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) |
353 | #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) | 383 | #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) |
354 | 384 | ||
355 | /* file-offset-in-pte helpers */ | 385 | /* file-offset-in-pte helpers */ |
356 | BTFIXUPDEF_CALL(unsigned long, pte_to_pgoff, pte_t pte); | 386 | static inline unsigned long pte_to_pgoff(pte_t pte) |
357 | BTFIXUPDEF_CALL(pte_t, pgoff_to_pte, unsigned long pgoff); | 387 | { |
388 | return pte_val(pte) >> SRMMU_PTE_FILE_SHIFT; | ||
389 | } | ||
358 | 390 | ||
359 | #define pte_to_pgoff(pte) BTFIXUP_CALL(pte_to_pgoff)(pte) | 391 | static inline pte_t pgoff_to_pte(unsigned long pgoff) |
360 | #define pgoff_to_pte(off) BTFIXUP_CALL(pgoff_to_pte)(off) | 392 | { |
393 | return __pte((pgoff << SRMMU_PTE_FILE_SHIFT) | SRMMU_FILE); | ||
394 | } | ||
361 | 395 | ||
362 | /* | 396 | /* |
363 | * This is made a constant because mm/fremap.c required a constant. | 397 | * This is made a constant because mm/fremap.c required a constant. |
364 | * Note that layout of these bits is different between sun4c.c and srmmu.c. | ||
365 | */ | 398 | */ |
366 | #define PTE_FILE_MAX_BITS 24 | 399 | #define PTE_FILE_MAX_BITS 24 |
367 | 400 | ||
@@ -399,9 +432,6 @@ static inline unsigned long | |||
399 | __get_phys (unsigned long addr) | 432 | __get_phys (unsigned long addr) |
400 | { | 433 | { |
401 | switch (sparc_cpu_model){ | 434 | switch (sparc_cpu_model){ |
402 | case sun4: | ||
403 | case sun4c: | ||
404 | return sun4c_get_pte (addr) << PAGE_SHIFT; | ||
405 | case sun4m: | 435 | case sun4m: |
406 | case sun4d: | 436 | case sun4d: |
407 | return ((srmmu_get_pte (addr) & 0xffffff00) << 4); | 437 | return ((srmmu_get_pte (addr) & 0xffffff00) << 4); |
@@ -414,9 +444,6 @@ static inline int | |||
414 | __get_iospace (unsigned long addr) | 444 | __get_iospace (unsigned long addr) |
415 | { | 445 | { |
416 | switch (sparc_cpu_model){ | 446 | switch (sparc_cpu_model){ |
417 | case sun4: | ||
418 | case sun4c: | ||
419 | return -1; /* Don't check iospace on sun4c */ | ||
420 | case sun4m: | 447 | case sun4m: |
421 | case sun4d: | 448 | case sun4d: |
422 | return (srmmu_get_pte (addr) >> 28); | 449 | return (srmmu_get_pte (addr) >> 28); |
@@ -463,7 +490,7 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, | |||
463 | set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ | 490 | set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \ |
464 | flush_tlb_page(__vma, __address); \ | 491 | flush_tlb_page(__vma, __address); \ |
465 | } \ | 492 | } \ |
466 | (sparc_cpu_model == sun4c) || __changed; \ | 493 | __changed; \ |
467 | }) | 494 | }) |
468 | 495 | ||
469 | #include <asm-generic/pgtable.h> | 496 | #include <asm-generic/pgtable.h> |
@@ -471,10 +498,8 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, | |||
471 | #endif /* !(__ASSEMBLY__) */ | 498 | #endif /* !(__ASSEMBLY__) */ |
472 | 499 | ||
473 | #define VMALLOC_START _AC(0xfe600000,UL) | 500 | #define VMALLOC_START _AC(0xfe600000,UL) |
474 | /* XXX Alter this when I get around to fixing sun4c - Anton */ | ||
475 | #define VMALLOC_END _AC(0xffc00000,UL) | 501 | #define VMALLOC_END _AC(0xffc00000,UL) |
476 | 502 | ||
477 | |||
478 | /* We provide our own get_unmapped_area to cope with VA holes for userland */ | 503 | /* We provide our own get_unmapped_area to cope with VA holes for userland */ |
479 | #define HAVE_ARCH_UNMAPPED_AREA | 504 | #define HAVE_ARCH_UNMAPPED_AREA |
480 | 505 | ||
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 76e4a52aa85e..61210db139fb 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h | |||
@@ -717,10 +717,6 @@ extern unsigned long find_ecache_flush_span(unsigned long size); | |||
717 | struct seq_file; | 717 | struct seq_file; |
718 | extern void mmu_info(struct seq_file *); | 718 | extern void mmu_info(struct seq_file *); |
719 | 719 | ||
720 | /* These do nothing with the way I have things setup. */ | ||
721 | #define mmu_lockarea(vaddr, len) (vaddr) | ||
722 | #define mmu_unlockarea(vaddr, len) do { } while(0) | ||
723 | |||
724 | struct vm_area_struct; | 720 | struct vm_area_struct; |
725 | extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *); | 721 | extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *); |
726 | 722 | ||
diff --git a/arch/sparc/include/asm/pgtsrmmu.h b/arch/sparc/include/asm/pgtsrmmu.h index f6ae2b2b6870..cb828703a63a 100644 --- a/arch/sparc/include/asm/pgtsrmmu.h +++ b/arch/sparc/include/asm/pgtsrmmu.h | |||
@@ -173,17 +173,6 @@ static inline void srmmu_set_ctable_ptr(unsigned long paddr) | |||
173 | "memory"); | 173 | "memory"); |
174 | } | 174 | } |
175 | 175 | ||
176 | static inline unsigned long srmmu_get_ctable_ptr(void) | ||
177 | { | ||
178 | unsigned int retval; | ||
179 | |||
180 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
181 | "=r" (retval) : | ||
182 | "r" (SRMMU_CTXTBL_PTR), | ||
183 | "i" (ASI_M_MMUREGS)); | ||
184 | return (retval & SRMMU_CTX_PMASK) << 4; | ||
185 | } | ||
186 | |||
187 | static inline void srmmu_set_context(int context) | 176 | static inline void srmmu_set_context(int context) |
188 | { | 177 | { |
189 | __asm__ __volatile__("sta %0, [%1] %2\n\t" : : | 178 | __asm__ __volatile__("sta %0, [%1] %2\n\t" : : |
@@ -231,42 +220,6 @@ static inline void srmmu_flush_whole_tlb(void) | |||
231 | } | 220 | } |
232 | 221 | ||
233 | /* These flush types are not available on all chips... */ | 222 | /* These flush types are not available on all chips... */ |
234 | static inline void srmmu_flush_tlb_ctx(void) | ||
235 | { | ||
236 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : | ||
237 | "r" (0x300), /* Flush TLB ctx.. */ | ||
238 | "i" (ASI_M_FLUSH_PROBE) : "memory"); | ||
239 | |||
240 | } | ||
241 | |||
242 | static inline void srmmu_flush_tlb_region(unsigned long addr) | ||
243 | { | ||
244 | addr &= SRMMU_PGDIR_MASK; | ||
245 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : | ||
246 | "r" (addr | 0x200), /* Flush TLB region.. */ | ||
247 | "i" (ASI_M_FLUSH_PROBE) : "memory"); | ||
248 | |||
249 | } | ||
250 | |||
251 | |||
252 | static inline void srmmu_flush_tlb_segment(unsigned long addr) | ||
253 | { | ||
254 | addr &= SRMMU_REAL_PMD_MASK; | ||
255 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : | ||
256 | "r" (addr | 0x100), /* Flush TLB segment.. */ | ||
257 | "i" (ASI_M_FLUSH_PROBE) : "memory"); | ||
258 | |||
259 | } | ||
260 | |||
261 | static inline void srmmu_flush_tlb_page(unsigned long page) | ||
262 | { | ||
263 | page &= PAGE_MASK; | ||
264 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t": : | ||
265 | "r" (page), /* Flush TLB page.. */ | ||
266 | "i" (ASI_M_FLUSH_PROBE) : "memory"); | ||
267 | |||
268 | } | ||
269 | |||
270 | #ifndef CONFIG_SPARC_LEON | 223 | #ifndef CONFIG_SPARC_LEON |
271 | static inline unsigned long srmmu_hwprobe(unsigned long vaddr) | 224 | static inline unsigned long srmmu_hwprobe(unsigned long vaddr) |
272 | { | 225 | { |
@@ -294,9 +247,6 @@ srmmu_get_pte (unsigned long addr) | |||
294 | return entry; | 247 | return entry; |
295 | } | 248 | } |
296 | 249 | ||
297 | extern unsigned long (*srmmu_read_physical)(unsigned long paddr); | ||
298 | extern void (*srmmu_write_physical)(unsigned long paddr, unsigned long word); | ||
299 | |||
300 | #endif /* !(__ASSEMBLY__) */ | 250 | #endif /* !(__ASSEMBLY__) */ |
301 | 251 | ||
302 | #endif /* !(_SPARC_PGTSRMMU_H) */ | 252 | #endif /* !(_SPARC_PGTSRMMU_H) */ |
diff --git a/arch/sparc/include/asm/pgtsun4c.h b/arch/sparc/include/asm/pgtsun4c.h deleted file mode 100644 index aeb25e912179..000000000000 --- a/arch/sparc/include/asm/pgtsun4c.h +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | /* | ||
2 | * pgtsun4c.h: Sun4c specific pgtable.h defines and code. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | #ifndef _SPARC_PGTSUN4C_H | ||
7 | #define _SPARC_PGTSUN4C_H | ||
8 | |||
9 | #include <asm/contregs.h> | ||
10 | |||
11 | /* PMD_SHIFT determines the size of the area a second-level page table can map */ | ||
12 | #define SUN4C_PMD_SHIFT 22 | ||
13 | |||
14 | /* PGDIR_SHIFT determines what a third-level page table entry can map */ | ||
15 | #define SUN4C_PGDIR_SHIFT 22 | ||
16 | #define SUN4C_PGDIR_SIZE (1UL << SUN4C_PGDIR_SHIFT) | ||
17 | #define SUN4C_PGDIR_MASK (~(SUN4C_PGDIR_SIZE-1)) | ||
18 | #define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK) | ||
19 | |||
20 | /* To represent how the sun4c mmu really lays things out. */ | ||
21 | #define SUN4C_REAL_PGDIR_SHIFT 18 | ||
22 | #define SUN4C_REAL_PGDIR_SIZE (1UL << SUN4C_REAL_PGDIR_SHIFT) | ||
23 | #define SUN4C_REAL_PGDIR_MASK (~(SUN4C_REAL_PGDIR_SIZE-1)) | ||
24 | #define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK) | ||
25 | |||
26 | /* 16 bit PFN on sun4c */ | ||
27 | #define SUN4C_PFN_MASK 0xffff | ||
28 | |||
29 | /* Don't increase these unless the structures in sun4c.c are fixed */ | ||
30 | #define SUN4C_MAX_SEGMAPS 256 | ||
31 | #define SUN4C_MAX_CONTEXTS 16 | ||
32 | |||
33 | /* | ||
34 | * To be efficient, and not have to worry about allocating such | ||
35 | * a huge pgd, we make the kernel sun4c tables each hold 1024 | ||
36 | * entries and the pgd similarly just like the i386 tables. | ||
37 | */ | ||
38 | #define SUN4C_PTRS_PER_PTE 1024 | ||
39 | #define SUN4C_PTRS_PER_PMD 1 | ||
40 | #define SUN4C_PTRS_PER_PGD 1024 | ||
41 | |||
42 | /* | ||
43 | * Sparc SUN4C pte fields. | ||
44 | */ | ||
45 | #define _SUN4C_PAGE_VALID 0x80000000 | ||
46 | #define _SUN4C_PAGE_SILENT_READ 0x80000000 /* synonym */ | ||
47 | #define _SUN4C_PAGE_DIRTY 0x40000000 | ||
48 | #define _SUN4C_PAGE_SILENT_WRITE 0x40000000 /* synonym */ | ||
49 | #define _SUN4C_PAGE_PRIV 0x20000000 /* privileged page */ | ||
50 | #define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ | ||
51 | #define _SUN4C_PAGE_PRESENT 0x08000000 /* implemented in software */ | ||
52 | #define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ | ||
53 | #define _SUN4C_PAGE_FILE 0x02000000 /* implemented in software */ | ||
54 | #define _SUN4C_PAGE_READ 0x00800000 /* implemented in software */ | ||
55 | #define _SUN4C_PAGE_WRITE 0x00400000 /* implemented in software */ | ||
56 | #define _SUN4C_PAGE_ACCESSED 0x00200000 /* implemented in software */ | ||
57 | #define _SUN4C_PAGE_MODIFIED 0x00100000 /* implemented in software */ | ||
58 | |||
59 | #define _SUN4C_READABLE (_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\ | ||
60 | _SUN4C_PAGE_ACCESSED) | ||
61 | #define _SUN4C_WRITEABLE (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\ | ||
62 | _SUN4C_PAGE_MODIFIED) | ||
63 | |||
64 | #define _SUN4C_PAGE_CHG_MASK (0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED) | ||
65 | |||
66 | #define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_PRESENT) | ||
67 | #define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\ | ||
68 | _SUN4C_PAGE_WRITE) | ||
69 | #define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) | ||
70 | #define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) | ||
71 | #define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\ | ||
72 | _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV) | ||
73 | |||
74 | /* SUN4C swap entry encoding | ||
75 | * | ||
76 | * We use 5 bits for the type and 19 for the offset. This gives us | ||
77 | * 32 swapfiles of 4GB each. Encoding looks like: | ||
78 | * | ||
79 | * RRRRRRRRooooooooooooooooooottttt | ||
80 | * fedcba9876543210fedcba9876543210 | ||
81 | * | ||
82 | * The top 8 bits are reserved for protection and status bits, especially | ||
83 | * FILE and PRESENT. | ||
84 | */ | ||
85 | #define SUN4C_SWP_TYPE_MASK 0x1f | ||
86 | #define SUN4C_SWP_OFF_MASK 0x7ffff | ||
87 | #define SUN4C_SWP_OFF_SHIFT 5 | ||
88 | |||
89 | #ifndef __ASSEMBLY__ | ||
90 | |||
91 | static inline unsigned long sun4c_get_synchronous_error(void) | ||
92 | { | ||
93 | unsigned long sync_err; | ||
94 | |||
95 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
96 | "=r" (sync_err) : | ||
97 | "r" (AC_SYNC_ERR), "i" (ASI_CONTROL)); | ||
98 | return sync_err; | ||
99 | } | ||
100 | |||
101 | static inline unsigned long sun4c_get_synchronous_address(void) | ||
102 | { | ||
103 | unsigned long sync_addr; | ||
104 | |||
105 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
106 | "=r" (sync_addr) : | ||
107 | "r" (AC_SYNC_VA), "i" (ASI_CONTROL)); | ||
108 | return sync_addr; | ||
109 | } | ||
110 | |||
111 | /* SUN4C pte, segmap, and context manipulation */ | ||
112 | static inline unsigned long sun4c_get_segmap(unsigned long addr) | ||
113 | { | ||
114 | register unsigned long entry; | ||
115 | |||
116 | __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : | ||
117 | "=r" (entry) : | ||
118 | "r" (addr), "i" (ASI_SEGMAP)); | ||
119 | |||
120 | return entry; | ||
121 | } | ||
122 | |||
123 | static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry) | ||
124 | { | ||
125 | |||
126 | __asm__ __volatile__("\n\tstba %1, [%0] %2; nop; nop; nop;\n\t" : : | ||
127 | "r" (addr), "r" (entry), | ||
128 | "i" (ASI_SEGMAP) | ||
129 | : "memory"); | ||
130 | } | ||
131 | |||
132 | static inline unsigned long sun4c_get_pte(unsigned long addr) | ||
133 | { | ||
134 | register unsigned long entry; | ||
135 | |||
136 | __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : | ||
137 | "=r" (entry) : | ||
138 | "r" (addr), "i" (ASI_PTE)); | ||
139 | return entry; | ||
140 | } | ||
141 | |||
142 | static inline void sun4c_put_pte(unsigned long addr, unsigned long entry) | ||
143 | { | ||
144 | __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : : | ||
145 | "r" (addr), | ||
146 | "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE) | ||
147 | : "memory"); | ||
148 | } | ||
149 | |||
150 | static inline int sun4c_get_context(void) | ||
151 | { | ||
152 | register int ctx; | ||
153 | |||
154 | __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : | ||
155 | "=r" (ctx) : | ||
156 | "r" (AC_CONTEXT), "i" (ASI_CONTROL)); | ||
157 | |||
158 | return ctx; | ||
159 | } | ||
160 | |||
161 | static inline int sun4c_set_context(int ctx) | ||
162 | { | ||
163 | __asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : : | ||
164 | "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL) | ||
165 | : "memory"); | ||
166 | |||
167 | return ctx; | ||
168 | } | ||
169 | |||
170 | #endif /* !(__ASSEMBLY__) */ | ||
171 | |||
172 | #endif /* !(_SPARC_PGTSUN4C_H) */ | ||
diff --git a/arch/sparc/include/asm/processor_32.h b/arch/sparc/include/asm/processor_32.h index 09521c6a5edb..9cbd854fdfdd 100644 --- a/arch/sparc/include/asm/processor_32.h +++ b/arch/sparc/include/asm/processor_32.h | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <asm/ptrace.h> | 16 | #include <asm/ptrace.h> |
17 | #include <asm/head.h> | 17 | #include <asm/head.h> |
18 | #include <asm/signal.h> | 18 | #include <asm/signal.h> |
19 | #include <asm/btfixup.h> | ||
20 | #include <asm/page.h> | 19 | #include <asm/page.h> |
21 | 20 | ||
22 | /* | 21 | /* |
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h index 00497abec996..8a83699a5507 100644 --- a/arch/sparc/include/asm/setup.h +++ b/arch/sparc/include/asm/setup.h | |||
@@ -20,10 +20,7 @@ extern char reboot_command[]; | |||
20 | * Only sun4d + leon may have boot_cpu_id != 0 | 20 | * Only sun4d + leon may have boot_cpu_id != 0 |
21 | */ | 21 | */ |
22 | extern unsigned char boot_cpu_id; | 22 | extern unsigned char boot_cpu_id; |
23 | extern unsigned char boot_cpu_id4; | ||
24 | 23 | ||
25 | extern unsigned long empty_bad_page; | ||
26 | extern unsigned long empty_bad_page_table; | ||
27 | extern unsigned long empty_zero_page; | 24 | extern unsigned long empty_zero_page; |
28 | 25 | ||
29 | extern int serial_console; | 26 | extern int serial_console; |
diff --git a/arch/sparc/include/asm/shmparam_32.h b/arch/sparc/include/asm/shmparam_32.h index 59a1243c12f3..142825c8d3ac 100644 --- a/arch/sparc/include/asm/shmparam_32.h +++ b/arch/sparc/include/asm/shmparam_32.h | |||
@@ -4,8 +4,6 @@ | |||
4 | #define __ARCH_FORCE_SHMLBA 1 | 4 | #define __ARCH_FORCE_SHMLBA 1 |
5 | 5 | ||
6 | extern int vac_cache_size; | 6 | extern int vac_cache_size; |
7 | #define SHMLBA (vac_cache_size ? vac_cache_size : \ | 7 | #define SHMLBA (vac_cache_size ? vac_cache_size : PAGE_SIZE) |
8 | (sparc_cpu_model == sun4c ? (64 * 1024) : \ | ||
9 | (sparc_cpu_model == sun4 ? (128 * 1024) : PAGE_SIZE))) | ||
10 | 8 | ||
11 | #endif /* _ASMSPARC_SHMPARAM_H */ | 9 | #endif /* _ASMSPARC_SHMPARAM_H */ |
diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h index 01c51c704341..b73da3c5f10a 100644 --- a/arch/sparc/include/asm/smp_32.h +++ b/arch/sparc/include/asm/smp_32.h | |||
@@ -8,7 +8,6 @@ | |||
8 | 8 | ||
9 | #include <linux/threads.h> | 9 | #include <linux/threads.h> |
10 | #include <asm/head.h> | 10 | #include <asm/head.h> |
11 | #include <asm/btfixup.h> | ||
12 | 11 | ||
13 | #ifndef __ASSEMBLY__ | 12 | #ifndef __ASSEMBLY__ |
14 | 13 | ||
@@ -58,104 +57,53 @@ struct seq_file; | |||
58 | void smp_bogo(struct seq_file *); | 57 | void smp_bogo(struct seq_file *); |
59 | void smp_info(struct seq_file *); | 58 | void smp_info(struct seq_file *); |
60 | 59 | ||
61 | BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, cpumask_t, unsigned long, unsigned long, unsigned long, unsigned long) | 60 | struct sparc32_ipi_ops { |
62 | BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void) | 61 | void (*cross_call)(smpfunc_t func, cpumask_t mask, unsigned long arg1, |
63 | BTFIXUPDEF_CALL(void, smp_ipi_resched, int); | 62 | unsigned long arg2, unsigned long arg3, |
64 | BTFIXUPDEF_CALL(void, smp_ipi_single, int); | 63 | unsigned long arg4); |
65 | BTFIXUPDEF_CALL(void, smp_ipi_mask_one, int); | 64 | void (*resched)(int cpu); |
66 | BTFIXUPDEF_BLACKBOX(hard_smp_processor_id) | 65 | void (*single)(int cpu); |
67 | BTFIXUPDEF_BLACKBOX(load_current) | 66 | void (*mask_one)(int cpu); |
68 | 67 | }; | |
69 | #define smp_cross_call(func,mask,arg1,arg2,arg3,arg4) BTFIXUP_CALL(smp_cross_call)(func,mask,arg1,arg2,arg3,arg4) | 68 | extern const struct sparc32_ipi_ops *sparc32_ipi_ops; |
69 | |||
70 | static inline void xc0(smpfunc_t func) | ||
71 | { | ||
72 | sparc32_ipi_ops->cross_call(func, *cpu_online_mask, 0, 0, 0, 0); | ||
73 | } | ||
70 | 74 | ||
71 | static inline void xc0(smpfunc_t func) { smp_cross_call(func, *cpu_online_mask, 0, 0, 0, 0); } | ||
72 | static inline void xc1(smpfunc_t func, unsigned long arg1) | 75 | static inline void xc1(smpfunc_t func, unsigned long arg1) |
73 | { smp_cross_call(func, *cpu_online_mask, arg1, 0, 0, 0); } | ||
74 | static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2) | ||
75 | { smp_cross_call(func, *cpu_online_mask, arg1, arg2, 0, 0); } | ||
76 | static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2, | ||
77 | unsigned long arg3) | ||
78 | { smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, 0); } | ||
79 | static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, | ||
80 | unsigned long arg3, unsigned long arg4) | ||
81 | { smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, arg4); } | ||
82 | |||
83 | extern void arch_send_call_function_single_ipi(int cpu); | ||
84 | extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); | ||
85 | |||
86 | static inline int cpu_logical_map(int cpu) | ||
87 | { | 76 | { |
88 | return cpu; | 77 | sparc32_ipi_ops->cross_call(func, *cpu_online_mask, arg1, 0, 0, 0); |
89 | } | 78 | } |
90 | 79 | static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2) | |
91 | static inline int hard_smp4m_processor_id(void) | ||
92 | { | 80 | { |
93 | int cpuid; | 81 | sparc32_ipi_ops->cross_call(func, *cpu_online_mask, arg1, arg2, 0, 0); |
94 | |||
95 | __asm__ __volatile__("rd %%tbr, %0\n\t" | ||
96 | "srl %0, 12, %0\n\t" | ||
97 | "and %0, 3, %0\n\t" : | ||
98 | "=&r" (cpuid)); | ||
99 | return cpuid; | ||
100 | } | 82 | } |
101 | 83 | ||
102 | static inline int hard_smp4d_processor_id(void) | 84 | static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2, |
85 | unsigned long arg3) | ||
103 | { | 86 | { |
104 | int cpuid; | 87 | sparc32_ipi_ops->cross_call(func, *cpu_online_mask, |
105 | 88 | arg1, arg2, arg3, 0); | |
106 | __asm__ __volatile__("lda [%%g0] %1, %0\n\t" : | ||
107 | "=&r" (cpuid) : "i" (ASI_M_VIKING_TMP1)); | ||
108 | return cpuid; | ||
109 | } | 89 | } |
110 | 90 | ||
111 | extern inline int hard_smpleon_processor_id(void) | 91 | static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2, |
92 | unsigned long arg3, unsigned long arg4) | ||
112 | { | 93 | { |
113 | int cpuid; | 94 | sparc32_ipi_ops->cross_call(func, *cpu_online_mask, |
114 | __asm__ __volatile__("rd %%asr17,%0\n\t" | 95 | arg1, arg2, arg3, arg4); |
115 | "srl %0,28,%0" : | ||
116 | "=&r" (cpuid) : ); | ||
117 | return cpuid; | ||
118 | } | 96 | } |
119 | 97 | ||
120 | #ifndef MODULE | 98 | extern void arch_send_call_function_single_ipi(int cpu); |
121 | static inline int hard_smp_processor_id(void) | 99 | extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); |
100 | |||
101 | static inline int cpu_logical_map(int cpu) | ||
122 | { | 102 | { |
123 | int cpuid; | 103 | return cpu; |
124 | |||
125 | /* Black box - sun4m | ||
126 | __asm__ __volatile__("rd %%tbr, %0\n\t" | ||
127 | "srl %0, 12, %0\n\t" | ||
128 | "and %0, 3, %0\n\t" : | ||
129 | "=&r" (cpuid)); | ||
130 | - sun4d | ||
131 | __asm__ __volatile__("lda [%g0] ASI_M_VIKING_TMP1, %0\n\t" | ||
132 | "nop; nop" : | ||
133 | "=&r" (cpuid)); | ||
134 | - leon | ||
135 | __asm__ __volatile__( "rd %asr17, %0\n\t" | ||
136 | "srl %0, 0x1c, %0\n\t" | ||
137 | "nop\n\t" : | ||
138 | "=&r" (cpuid)); | ||
139 | See btfixup.h and btfixupprep.c to understand how a blackbox works. | ||
140 | */ | ||
141 | __asm__ __volatile__("sethi %%hi(___b_hard_smp_processor_id), %0\n\t" | ||
142 | "sethi %%hi(boot_cpu_id), %0\n\t" | ||
143 | "ldub [%0 + %%lo(boot_cpu_id)], %0\n\t" : | ||
144 | "=&r" (cpuid)); | ||
145 | return cpuid; | ||
146 | } | 104 | } |
147 | #else | ||
148 | static inline int hard_smp_processor_id(void) | ||
149 | { | ||
150 | int cpuid; | ||
151 | 105 | ||
152 | __asm__ __volatile__("mov %%o7, %%g1\n\t" | 106 | extern int hard_smp_processor_id(void); |
153 | "call ___f___hard_smp_processor_id\n\t" | ||
154 | " nop\n\t" | ||
155 | "mov %%g2, %0\n\t" : "=r"(cpuid) : : "g1", "g2"); | ||
156 | return cpuid; | ||
157 | } | ||
158 | #endif | ||
159 | 107 | ||
160 | #define raw_smp_processor_id() (current_thread_info()->cpu) | 108 | #define raw_smp_processor_id() (current_thread_info()->cpu) |
161 | 109 | ||
diff --git a/arch/sparc/include/asm/smpprim.h b/arch/sparc/include/asm/smpprim.h deleted file mode 100644 index eb849d862c64..000000000000 --- a/arch/sparc/include/asm/smpprim.h +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | /* | ||
2 | * smpprim.h: SMP locking primitives on the Sparc | ||
3 | * | ||
4 | * God knows we won't be actually using this code for some time | ||
5 | * but I thought I'd write it since I knew how. | ||
6 | * | ||
7 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
8 | */ | ||
9 | |||
10 | #ifndef __SPARC_SMPPRIM_H | ||
11 | #define __SPARC_SMPPRIM_H | ||
12 | |||
13 | /* Test and set the unsigned byte at ADDR to 1. Returns the previous | ||
14 | * value. On the Sparc we use the ldstub instruction since it is | ||
15 | * atomic. | ||
16 | */ | ||
17 | |||
18 | static inline __volatile__ char test_and_set(void *addr) | ||
19 | { | ||
20 | char state = 0; | ||
21 | |||
22 | __asm__ __volatile__("ldstub [%0], %1 ! test_and_set\n\t" | ||
23 | "=r" (addr), "=r" (state) : | ||
24 | "0" (addr), "1" (state) : "memory"); | ||
25 | |||
26 | return state; | ||
27 | } | ||
28 | |||
29 | /* Initialize a spin-lock. */ | ||
30 | static inline __volatile__ smp_initlock(void *spinlock) | ||
31 | { | ||
32 | /* Unset the lock. */ | ||
33 | *((unsigned char *) spinlock) = 0; | ||
34 | |||
35 | return; | ||
36 | } | ||
37 | |||
38 | /* This routine spins until it acquires the lock at ADDR. */ | ||
39 | static inline __volatile__ smp_lock(void *addr) | ||
40 | { | ||
41 | while(test_and_set(addr) == 0xff) | ||
42 | ; | ||
43 | |||
44 | /* We now have the lock */ | ||
45 | return; | ||
46 | } | ||
47 | |||
48 | /* This routine releases the lock at ADDR. */ | ||
49 | static inline __volatile__ smp_unlock(void *addr) | ||
50 | { | ||
51 | *((unsigned char *) addr) = 0; | ||
52 | } | ||
53 | |||
54 | #endif /* !(__SPARC_SMPPRIM_H) */ | ||
diff --git a/arch/sparc/include/asm/string_32.h b/arch/sparc/include/asm/string_32.h index edf196ee4ef8..12f67857152e 100644 --- a/arch/sparc/include/asm/string_32.h +++ b/arch/sparc/include/asm/string_32.h | |||
@@ -61,68 +61,7 @@ extern int memcmp(const void *,const void *,__kernel_size_t); | |||
61 | extern __kernel_size_t strlen(const char *); | 61 | extern __kernel_size_t strlen(const char *); |
62 | 62 | ||
63 | #define __HAVE_ARCH_STRNCMP | 63 | #define __HAVE_ARCH_STRNCMP |
64 | 64 | extern int strncmp(const char *, const char *, __kernel_size_t); | |
65 | extern int __strncmp(const char *, const char *, __kernel_size_t); | ||
66 | |||
67 | static inline int __constant_strncmp(const char *src, const char *dest, __kernel_size_t count) | ||
68 | { | ||
69 | register int retval; | ||
70 | switch(count) { | ||
71 | case 0: return 0; | ||
72 | case 1: return (src[0] - dest[0]); | ||
73 | case 2: retval = (src[0] - dest[0]); | ||
74 | if(!retval && src[0]) | ||
75 | retval = (src[1] - dest[1]); | ||
76 | return retval; | ||
77 | case 3: retval = (src[0] - dest[0]); | ||
78 | if(!retval && src[0]) { | ||
79 | retval = (src[1] - dest[1]); | ||
80 | if(!retval && src[1]) | ||
81 | retval = (src[2] - dest[2]); | ||
82 | } | ||
83 | return retval; | ||
84 | case 4: retval = (src[0] - dest[0]); | ||
85 | if(!retval && src[0]) { | ||
86 | retval = (src[1] - dest[1]); | ||
87 | if(!retval && src[1]) { | ||
88 | retval = (src[2] - dest[2]); | ||
89 | if (!retval && src[2]) | ||
90 | retval = (src[3] - dest[3]); | ||
91 | } | ||
92 | } | ||
93 | return retval; | ||
94 | case 5: retval = (src[0] - dest[0]); | ||
95 | if(!retval && src[0]) { | ||
96 | retval = (src[1] - dest[1]); | ||
97 | if(!retval && src[1]) { | ||
98 | retval = (src[2] - dest[2]); | ||
99 | if (!retval && src[2]) { | ||
100 | retval = (src[3] - dest[3]); | ||
101 | if (!retval && src[3]) | ||
102 | retval = (src[4] - dest[4]); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | return retval; | ||
107 | default: | ||
108 | retval = (src[0] - dest[0]); | ||
109 | if(!retval && src[0]) { | ||
110 | retval = (src[1] - dest[1]); | ||
111 | if(!retval && src[1]) { | ||
112 | retval = (src[2] - dest[2]); | ||
113 | if(!retval && src[2]) | ||
114 | retval = __strncmp(src+3,dest+3,count-3); | ||
115 | } | ||
116 | } | ||
117 | return retval; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | #undef strncmp | ||
122 | #define strncmp(__arg0, __arg1, __arg2) \ | ||
123 | (__builtin_constant_p(__arg2) ? \ | ||
124 | __constant_strncmp(__arg0, __arg1, __arg2) : \ | ||
125 | __strncmp(__arg0, __arg1, __arg2)) | ||
126 | 65 | ||
127 | #endif /* !EXPORT_SYMTAB_STROPS */ | 66 | #endif /* !EXPORT_SYMTAB_STROPS */ |
128 | 67 | ||
diff --git a/arch/sparc/include/asm/sysen.h b/arch/sparc/include/asm/sysen.h deleted file mode 100644 index 6af34abde6e7..000000000000 --- a/arch/sparc/include/asm/sysen.h +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | /* | ||
2 | * sysen.h: Bit fields within the "System Enable" register accessed via | ||
3 | * the ASI_CONTROL address space at address AC_SYSENABLE. | ||
4 | * | ||
5 | * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | ||
7 | |||
8 | #ifndef _SPARC_SYSEN_H | ||
9 | #define _SPARC_SYSEN_H | ||
10 | |||
11 | #define SENABLE_DVMA 0x20 /* enable dvma transfers */ | ||
12 | #define SENABLE_CACHE 0x10 /* enable VAC cache */ | ||
13 | #define SENABLE_RESET 0x04 /* reset whole machine, danger Will Robinson */ | ||
14 | |||
15 | #endif /* _SPARC_SYSEN_H */ | ||
diff --git a/arch/sparc/include/asm/thread_info_32.h b/arch/sparc/include/asm/thread_info_32.h index c2a1080cdd3b..21a38946541d 100644 --- a/arch/sparc/include/asm/thread_info_32.h +++ b/arch/sparc/include/asm/thread_info_32.h | |||
@@ -15,7 +15,6 @@ | |||
15 | 15 | ||
16 | #ifndef __ASSEMBLY__ | 16 | #ifndef __ASSEMBLY__ |
17 | 17 | ||
18 | #include <asm/btfixup.h> | ||
19 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
20 | #include <asm/page.h> | 19 | #include <asm/page.h> |
21 | 20 | ||
@@ -80,13 +79,8 @@ register struct thread_info *current_thread_info_reg asm("g6"); | |||
80 | */ | 79 | */ |
81 | #define THREAD_INFO_ORDER 1 | 80 | #define THREAD_INFO_ORDER 1 |
82 | 81 | ||
83 | #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR | 82 | struct thread_info * alloc_thread_info_node(struct task_struct *tsk, int node); |
84 | 83 | void free_thread_info(struct thread_info *); | |
85 | BTFIXUPDEF_CALL(struct thread_info *, alloc_thread_info_node, int) | ||
86 | #define alloc_thread_info_node(tsk, node) BTFIXUP_CALL(alloc_thread_info_node)(node) | ||
87 | |||
88 | BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *) | ||
89 | #define free_thread_info(ti) BTFIXUP_CALL(free_thread_info)(ti) | ||
90 | 84 | ||
91 | #endif /* __ASSEMBLY__ */ | 85 | #endif /* __ASSEMBLY__ */ |
92 | 86 | ||
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 01d057fe6a3f..7f0981b09451 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h | |||
@@ -138,32 +138,11 @@ register struct thread_info *current_thread_info_reg asm("g6"); | |||
138 | 138 | ||
139 | /* thread information allocation */ | 139 | /* thread information allocation */ |
140 | #if PAGE_SHIFT == 13 | 140 | #if PAGE_SHIFT == 13 |
141 | #define __THREAD_INFO_ORDER 1 | 141 | #define THREAD_SIZE_ORDER 1 |
142 | #else /* PAGE_SHIFT == 13 */ | 142 | #else /* PAGE_SHIFT == 13 */ |
143 | #define __THREAD_INFO_ORDER 0 | 143 | #define THREAD_SIZE_ORDER 0 |
144 | #endif /* PAGE_SHIFT == 13 */ | 144 | #endif /* PAGE_SHIFT == 13 */ |
145 | 145 | ||
146 | #define __HAVE_ARCH_THREAD_INFO_ALLOCATOR | ||
147 | |||
148 | #ifdef CONFIG_DEBUG_STACK_USAGE | ||
149 | #define THREAD_FLAGS (GFP_KERNEL | __GFP_ZERO) | ||
150 | #else | ||
151 | #define THREAD_FLAGS (GFP_KERNEL) | ||
152 | #endif | ||
153 | |||
154 | #define alloc_thread_info_node(tsk, node) \ | ||
155 | ({ \ | ||
156 | struct page *page = alloc_pages_node(node, THREAD_FLAGS, \ | ||
157 | __THREAD_INFO_ORDER); \ | ||
158 | struct thread_info *ret; \ | ||
159 | \ | ||
160 | ret = page ? page_address(page) : NULL; \ | ||
161 | ret; \ | ||
162 | }) | ||
163 | |||
164 | #define free_thread_info(ti) \ | ||
165 | free_pages((unsigned long)(ti),__THREAD_INFO_ORDER) | ||
166 | |||
167 | #define __thread_flag_byte_ptr(ti) \ | 146 | #define __thread_flag_byte_ptr(ti) \ |
168 | ((unsigned char *)(&((ti)->flags))) | 147 | ((unsigned char *)(&((ti)->flags))) |
169 | #define __cur_thread_flag_byte_ptr __thread_flag_byte_ptr(current_thread_info()) | 148 | #define __cur_thread_flag_byte_ptr __thread_flag_byte_ptr(current_thread_info()) |
diff --git a/arch/sparc/include/asm/timer_32.h b/arch/sparc/include/asm/timer_32.h index 1a91e11dd104..72f40a546de3 100644 --- a/arch/sparc/include/asm/timer_32.h +++ b/arch/sparc/include/asm/timer_32.h | |||
@@ -8,14 +8,37 @@ | |||
8 | #ifndef _SPARC_TIMER_H | 8 | #ifndef _SPARC_TIMER_H |
9 | #define _SPARC_TIMER_H | 9 | #define _SPARC_TIMER_H |
10 | 10 | ||
11 | #include <linux/clocksource.h> | ||
12 | #include <linux/irqreturn.h> | ||
13 | |||
14 | #include <asm-generic/percpu.h> | ||
15 | |||
11 | #include <asm/cpu_type.h> /* For SUN4M_NCPUS */ | 16 | #include <asm/cpu_type.h> /* For SUN4M_NCPUS */ |
12 | #include <asm/btfixup.h> | 17 | |
18 | #define SBUS_CLOCK_RATE 2000000 /* 2MHz */ | ||
19 | #define TIMER_VALUE_SHIFT 9 | ||
20 | #define TIMER_VALUE_MASK 0x3fffff | ||
21 | #define TIMER_LIMIT_BIT (1 << 31) /* Bit 31 in Counter-Timer register */ | ||
22 | |||
23 | /* The counter timer register has the value offset by 9 bits. | ||
24 | * From sun4m manual: | ||
25 | * When a counter reaches the value in the corresponding limit register, | ||
26 | * the Limit bit is set and the counter is set to 500 nS (i.e. 0x00000200). | ||
27 | * | ||
28 | * To compensate for this add one to the value. | ||
29 | */ | ||
30 | static inline unsigned int timer_value(unsigned int value) | ||
31 | { | ||
32 | return (value + 1) << TIMER_VALUE_SHIFT; | ||
33 | } | ||
13 | 34 | ||
14 | extern __volatile__ unsigned int *master_l10_counter; | 35 | extern __volatile__ unsigned int *master_l10_counter; |
15 | 36 | ||
16 | /* FIXME: Make do_[gs]ettimeofday btfixup calls */ | 37 | extern irqreturn_t notrace timer_interrupt(int dummy, void *dev_id); |
17 | struct timespec; | 38 | |
18 | BTFIXUPDEF_CALL(int, bus_do_settimeofday, struct timespec *tv) | 39 | #ifdef CONFIG_SMP |
19 | #define bus_do_settimeofday(tv) BTFIXUP_CALL(bus_do_settimeofday)(tv) | 40 | DECLARE_PER_CPU(struct clock_event_device, sparc32_clockevent); |
41 | extern void register_percpu_ce(int cpu); | ||
42 | #endif | ||
20 | 43 | ||
21 | #endif /* !(_SPARC_TIMER_H) */ | 44 | #endif /* !(_SPARC_TIMER_H) */ |
diff --git a/arch/sparc/include/asm/timex_32.h b/arch/sparc/include/asm/timex_32.h index a254750e4c03..b6ccdb0d6f7d 100644 --- a/arch/sparc/include/asm/timex_32.h +++ b/arch/sparc/include/asm/timex_32.h | |||
@@ -12,5 +12,4 @@ | |||
12 | typedef unsigned long cycles_t; | 12 | typedef unsigned long cycles_t; |
13 | #define get_cycles() (0) | 13 | #define get_cycles() (0) |
14 | 14 | ||
15 | extern u32 (*do_arch_gettimeoffset)(void); | ||
16 | #endif | 15 | #endif |
diff --git a/arch/sparc/include/asm/tlbflush_32.h b/arch/sparc/include/asm/tlbflush_32.h index fe0a71abc9bb..a5c4142130f5 100644 --- a/arch/sparc/include/asm/tlbflush_32.h +++ b/arch/sparc/include/asm/tlbflush_32.h | |||
@@ -1,52 +1,16 @@ | |||
1 | #ifndef _SPARC_TLBFLUSH_H | 1 | #ifndef _SPARC_TLBFLUSH_H |
2 | #define _SPARC_TLBFLUSH_H | 2 | #define _SPARC_TLBFLUSH_H |
3 | 3 | ||
4 | #include <linux/mm.h> | 4 | #include <asm/cachetlb_32.h> |
5 | // #include <asm/processor.h> | 5 | |
6 | 6 | #define flush_tlb_all() \ | |
7 | /* | 7 | sparc32_cachetlb_ops->tlb_all() |
8 | * TLB flushing: | 8 | #define flush_tlb_mm(mm) \ |
9 | * | 9 | sparc32_cachetlb_ops->tlb_mm(mm) |
10 | * - flush_tlb() flushes the current mm struct TLBs XXX Exists? | 10 | #define flush_tlb_range(vma, start, end) \ |
11 | * - flush_tlb_all() flushes all processes TLBs | 11 | sparc32_cachetlb_ops->tlb_range(vma, start, end) |
12 | * - flush_tlb_mm(mm) flushes the specified mm context TLB's | 12 | #define flush_tlb_page(vma, addr) \ |
13 | * - flush_tlb_page(vma, vmaddr) flushes one page | 13 | sparc32_cachetlb_ops->tlb_page(vma, addr) |
14 | * - flush_tlb_range(vma, start, end) flushes a range of pages | ||
15 | * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages | ||
16 | */ | ||
17 | |||
18 | #ifdef CONFIG_SMP | ||
19 | |||
20 | BTFIXUPDEF_CALL(void, local_flush_tlb_all, void) | ||
21 | BTFIXUPDEF_CALL(void, local_flush_tlb_mm, struct mm_struct *) | ||
22 | BTFIXUPDEF_CALL(void, local_flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long) | ||
23 | BTFIXUPDEF_CALL(void, local_flush_tlb_page, struct vm_area_struct *, unsigned long) | ||
24 | |||
25 | #define local_flush_tlb_all() BTFIXUP_CALL(local_flush_tlb_all)() | ||
26 | #define local_flush_tlb_mm(mm) BTFIXUP_CALL(local_flush_tlb_mm)(mm) | ||
27 | #define local_flush_tlb_range(vma,start,end) BTFIXUP_CALL(local_flush_tlb_range)(vma,start,end) | ||
28 | #define local_flush_tlb_page(vma,addr) BTFIXUP_CALL(local_flush_tlb_page)(vma,addr) | ||
29 | |||
30 | extern void smp_flush_tlb_all(void); | ||
31 | extern void smp_flush_tlb_mm(struct mm_struct *mm); | ||
32 | extern void smp_flush_tlb_range(struct vm_area_struct *vma, | ||
33 | unsigned long start, | ||
34 | unsigned long end); | ||
35 | extern void smp_flush_tlb_page(struct vm_area_struct *mm, unsigned long page); | ||
36 | |||
37 | #endif /* CONFIG_SMP */ | ||
38 | |||
39 | BTFIXUPDEF_CALL(void, flush_tlb_all, void) | ||
40 | BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *) | ||
41 | BTFIXUPDEF_CALL(void, flush_tlb_range, struct vm_area_struct *, unsigned long, unsigned long) | ||
42 | BTFIXUPDEF_CALL(void, flush_tlb_page, struct vm_area_struct *, unsigned long) | ||
43 | |||
44 | #define flush_tlb_all() BTFIXUP_CALL(flush_tlb_all)() | ||
45 | #define flush_tlb_mm(mm) BTFIXUP_CALL(flush_tlb_mm)(mm) | ||
46 | #define flush_tlb_range(vma,start,end) BTFIXUP_CALL(flush_tlb_range)(vma,start,end) | ||
47 | #define flush_tlb_page(vma,addr) BTFIXUP_CALL(flush_tlb_page)(vma,addr) | ||
48 | |||
49 | // #define flush_tlb() flush_tlb_mm(current->active_mm) /* XXX Sure? */ | ||
50 | 14 | ||
51 | /* | 15 | /* |
52 | * This is a kludge, until I know better. --zaitcev XXX | 16 | * This is a kludge, until I know better. --zaitcev XXX |
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h index 8303ac481034..d50c310f5d38 100644 --- a/arch/sparc/include/asm/uaccess_32.h +++ b/arch/sparc/include/asm/uaccess_32.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <asm/vac-ops.h> | ||
16 | #endif | 15 | #endif |
17 | 16 | ||
18 | #ifndef __ASSEMBLY__ | 17 | #ifndef __ASSEMBLY__ |
diff --git a/arch/sparc/include/asm/vac-ops.h b/arch/sparc/include/asm/vac-ops.h deleted file mode 100644 index a63e88ef0426..000000000000 --- a/arch/sparc/include/asm/vac-ops.h +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | #ifndef _SPARC_VAC_OPS_H | ||
2 | #define _SPARC_VAC_OPS_H | ||
3 | |||
4 | /* vac-ops.h: Inline assembly routines to do operations on the Sparc | ||
5 | * VAC (virtual address cache) for the sun4c. | ||
6 | * | ||
7 | * Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu) | ||
8 | */ | ||
9 | |||
10 | #include <asm/sysen.h> | ||
11 | #include <asm/contregs.h> | ||
12 | #include <asm/asi.h> | ||
13 | |||
14 | /* The SUN4C models have a virtually addressed write-through | ||
15 | * cache. | ||
16 | * | ||
17 | * The cache tags are directly accessible through an ASI and | ||
18 | * each have the form: | ||
19 | * | ||
20 | * ------------------------------------------------------------ | ||
21 | * | MBZ | CONTEXT | WRITE | PRIV | VALID | MBZ | TagID | MBZ | | ||
22 | * ------------------------------------------------------------ | ||
23 | * 31 25 24 22 21 20 19 18 16 15 2 1 0 | ||
24 | * | ||
25 | * MBZ: These bits are either unused and/or reserved and should | ||
26 | * be written as zeroes. | ||
27 | * | ||
28 | * CONTEXT: Records the context to which this cache line belongs. | ||
29 | * | ||
30 | * WRITE: A copy of the writable bit from the mmu pte access bits. | ||
31 | * | ||
32 | * PRIV: A copy of the privileged bit from the pte access bits. | ||
33 | * | ||
34 | * VALID: If set, this line is valid, else invalid. | ||
35 | * | ||
36 | * TagID: Fourteen bits of tag ID. | ||
37 | * | ||
38 | * Every virtual address is seen by the cache like this: | ||
39 | * | ||
40 | * ---------------------------------------- | ||
41 | * | RESV | TagID | LINE | BYTE-in-LINE | | ||
42 | * ---------------------------------------- | ||
43 | * 31 30 29 16 15 4 3 0 | ||
44 | * | ||
45 | * RESV: Unused/reserved. | ||
46 | * | ||
47 | * TagID: Used to match the Tag-ID in that vac tags. | ||
48 | * | ||
49 | * LINE: Which line within the cache | ||
50 | * | ||
51 | * BYTE-in-LINE: Which byte within the cache line. | ||
52 | */ | ||
53 | |||
54 | /* Sun4c VAC Tags */ | ||
55 | #define S4CVACTAG_CID 0x01c00000 | ||
56 | #define S4CVACTAG_W 0x00200000 | ||
57 | #define S4CVACTAG_P 0x00100000 | ||
58 | #define S4CVACTAG_V 0x00080000 | ||
59 | #define S4CVACTAG_TID 0x0000fffc | ||
60 | |||
61 | /* Sun4c VAC Virtual Address */ | ||
62 | /* These aren't used, why bother? (Anton) */ | ||
63 | #if 0 | ||
64 | #define S4CVACVA_TID 0x3fff0000 | ||
65 | #define S4CVACVA_LINE 0x0000fff0 | ||
66 | #define S4CVACVA_BIL 0x0000000f | ||
67 | #endif | ||
68 | |||
69 | /* The indexing of cache lines creates a problem. Because the line | ||
70 | * field of a virtual address extends past the page offset within | ||
71 | * the virtual address it is possible to have what are called | ||
72 | * 'bad aliases' which will create inconsistencies. So we must make | ||
73 | * sure that within a context that if a physical page is mapped | ||
74 | * more than once, that 'extra' line bits are the same. If this is | ||
75 | * not the case, and thus is a 'bad alias' we must turn off the | ||
76 | * cacheable bit in the pte's of all such pages. | ||
77 | */ | ||
78 | |||
79 | #define S4CVAC_BADBITS 0x0000f000 | ||
80 | |||
81 | /* The following is true if vaddr1 and vaddr2 would cause | ||
82 | * a 'bad alias'. | ||
83 | */ | ||
84 | #define S4CVAC_BADALIAS(vaddr1, vaddr2) \ | ||
85 | ((((unsigned long) (vaddr1)) ^ ((unsigned long) (vaddr2))) & \ | ||
86 | (S4CVAC_BADBITS)) | ||
87 | |||
88 | /* The following structure describes the characteristics of a sun4c | ||
89 | * VAC as probed from the prom during boot time. | ||
90 | */ | ||
91 | struct sun4c_vac_props { | ||
92 | unsigned int num_bytes; /* Size of the cache */ | ||
93 | unsigned int do_hwflushes; /* Hardware flushing available? */ | ||
94 | unsigned int linesize; /* Size of each line in bytes */ | ||
95 | unsigned int log2lsize; /* log2(linesize) */ | ||
96 | unsigned int on; /* VAC is enabled */ | ||
97 | }; | ||
98 | |||
99 | extern struct sun4c_vac_props sun4c_vacinfo; | ||
100 | |||
101 | /* sun4c_enable_vac() enables the sun4c virtual address cache. */ | ||
102 | static inline void sun4c_enable_vac(void) | ||
103 | { | ||
104 | __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" | ||
105 | "or %%g1, %2, %%g1\n\t" | ||
106 | "stba %%g1, [%0] %1\n\t" | ||
107 | : /* no outputs */ | ||
108 | : "r" ((unsigned int) AC_SENABLE), | ||
109 | "i" (ASI_CONTROL), "i" (SENABLE_CACHE) | ||
110 | : "g1", "memory"); | ||
111 | sun4c_vacinfo.on = 1; | ||
112 | } | ||
113 | |||
114 | /* sun4c_disable_vac() disables the virtual address cache. */ | ||
115 | static inline void sun4c_disable_vac(void) | ||
116 | { | ||
117 | __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" | ||
118 | "andn %%g1, %2, %%g1\n\t" | ||
119 | "stba %%g1, [%0] %1\n\t" | ||
120 | : /* no outputs */ | ||
121 | : "r" ((unsigned int) AC_SENABLE), | ||
122 | "i" (ASI_CONTROL), "i" (SENABLE_CACHE) | ||
123 | : "g1", "memory"); | ||
124 | sun4c_vacinfo.on = 0; | ||
125 | } | ||
126 | |||
127 | #endif /* !(_SPARC_VAC_OPS_H) */ | ||
diff --git a/arch/sparc/include/asm/vaddrs.h b/arch/sparc/include/asm/vaddrs.h index 541e13755cec..da6535d88a72 100644 --- a/arch/sparc/include/asm/vaddrs.h +++ b/arch/sparc/include/asm/vaddrs.h | |||
@@ -34,22 +34,6 @@ | |||
34 | #define IOBASE_VADDR 0xfe000000 | 34 | #define IOBASE_VADDR 0xfe000000 |
35 | #define IOBASE_END 0xfe600000 | 35 | #define IOBASE_END 0xfe600000 |
36 | 36 | ||
37 | /* | ||
38 | * On the sun4/4c we need a place | ||
39 | * to reliably map locked down kernel data. This includes the | ||
40 | * task_struct and kernel stack pages of each process plus the | ||
41 | * scsi buffers during dvma IO transfers, also the floppy buffers | ||
42 | * during pseudo dma which runs with traps off (no faults allowed). | ||
43 | * Some quick calculations yield: | ||
44 | * NR_TASKS <512> * (3 * PAGE_SIZE) == 0x600000 | ||
45 | * Subtract this from 0xc00000 and you get 0x927C0 of vm left | ||
46 | * over to map SCSI dvma + floppy pseudo-dma buffers. So be | ||
47 | * careful if you change NR_TASKS or else there won't be enough | ||
48 | * room for it all. | ||
49 | */ | ||
50 | #define SUN4C_LOCK_VADDR 0xff000000 | ||
51 | #define SUN4C_LOCK_END 0xffc00000 | ||
52 | |||
53 | #define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */ | 37 | #define KADB_DEBUGGER_BEGVM 0xffc00000 /* Where kern debugger is in virt-mem */ |
54 | #define KADB_DEBUGGER_ENDVM 0xffd00000 | 38 | #define KADB_DEBUGGER_ENDVM 0xffd00000 |
55 | #define DEBUG_FIRSTVADDR KADB_DEBUGGER_BEGVM | 39 | #define DEBUG_FIRSTVADDR KADB_DEBUGGER_BEGVM |
diff --git a/arch/sparc/include/asm/winmacro.h b/arch/sparc/include/asm/winmacro.h index a9be04b0d049..9b7b21764cde 100644 --- a/arch/sparc/include/asm/winmacro.h +++ b/arch/sparc/include/asm/winmacro.h | |||
@@ -103,37 +103,24 @@ | |||
103 | st %scratch, [%cur_reg + TI_W_SAVED]; | 103 | st %scratch, [%cur_reg + TI_W_SAVED]; |
104 | 104 | ||
105 | #ifdef CONFIG_SMP | 105 | #ifdef CONFIG_SMP |
106 | /* Results of LOAD_CURRENT() after BTFIXUP for SUN4M, SUN4D & LEON (comments) */ | 106 | #define LOAD_CURRENT(dest_reg, idreg) \ |
107 | #define LOAD_CURRENT4M(dest_reg, idreg) \ | 107 | 661: rd %tbr, %idreg; \ |
108 | rd %tbr, %idreg; \ | 108 | srl %idreg, 10, %idreg; \ |
109 | sethi %hi(current_set), %dest_reg; \ | 109 | and %idreg, 0xc, %idreg; \ |
110 | srl %idreg, 10, %idreg; \ | 110 | .section .cpuid_patch, "ax"; \ |
111 | or %dest_reg, %lo(current_set), %dest_reg; \ | 111 | /* Instruction location. */ \ |
112 | and %idreg, 0xc, %idreg; \ | 112 | .word 661b; \ |
113 | ld [%idreg + %dest_reg], %dest_reg; | 113 | /* SUN4D implementation. */ \ |
114 | 114 | lda [%g0] ASI_M_VIKING_TMP1, %idreg; \ | |
115 | #define LOAD_CURRENT4D(dest_reg, idreg) \ | 115 | sll %idreg, 2, %idreg; \ |
116 | lda [%g0] ASI_M_VIKING_TMP1, %idreg; \ | 116 | nop; \ |
117 | sethi %hi(C_LABEL(current_set)), %dest_reg; \ | 117 | /* LEON implementation. */ \ |
118 | sll %idreg, 2, %idreg; \ | 118 | rd %asr17, %idreg; \ |
119 | or %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \ | 119 | srl %idreg, 0x1c, %idreg; \ |
120 | ld [%idreg + %dest_reg], %dest_reg; | 120 | sll %idreg, 0x02, %idreg; \ |
121 | 121 | .previous; \ | |
122 | #define LOAD_CURRENT_LEON(dest_reg, idreg) \ | 122 | sethi %hi(current_set), %dest_reg; \ |
123 | rd %asr17, %idreg; \ | 123 | or %dest_reg, %lo(current_set), %dest_reg;\ |
124 | sethi %hi(current_set), %dest_reg; \ | ||
125 | srl %idreg, 0x1c, %idreg; \ | ||
126 | or %dest_reg, %lo(current_set), %dest_reg; \ | ||
127 | sll %idreg, 0x2, %idreg; \ | ||
128 | ld [%idreg + %dest_reg], %dest_reg; | ||
129 | |||
130 | /* Blackbox - take care with this... - check smp4m and smp4d before changing this. */ | ||
131 | #define LOAD_CURRENT(dest_reg, idreg) \ | ||
132 | sethi %hi(___b_load_current), %idreg; \ | ||
133 | sethi %hi(current_set), %dest_reg; \ | ||
134 | sethi %hi(boot_cpu_id4), %idreg; \ | ||
135 | or %dest_reg, %lo(current_set), %dest_reg; \ | ||
136 | ldub [%idreg + %lo(boot_cpu_id4)], %idreg; \ | ||
137 | ld [%idreg + %dest_reg], %dest_reg; | 124 | ld [%idreg + %dest_reg], %dest_reg; |
138 | #else | 125 | #else |
139 | #define LOAD_CURRENT(dest_reg, idreg) \ | 126 | #define LOAD_CURRENT(dest_reg, idreg) \ |
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index cb85458f89d2..72308f9b0096 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -6,7 +6,6 @@ asflags-y := -ansi | |||
6 | ccflags-y := -Werror | 6 | ccflags-y := -Werror |
7 | 7 | ||
8 | extra-y := head_$(BITS).o | 8 | extra-y := head_$(BITS).o |
9 | extra-y += init_task.o | ||
10 | 9 | ||
11 | # Undefine sparc when processing vmlinux.lds - it is used | 10 | # Undefine sparc when processing vmlinux.lds - it is used |
12 | # And teach CPP we are doing $(BITS) builds (for this case) | 11 | # And teach CPP we are doing $(BITS) builds (for this case) |
@@ -28,7 +27,7 @@ obj-y += traps_$(BITS).o | |||
28 | 27 | ||
29 | # IRQ | 28 | # IRQ |
30 | obj-y += irq_$(BITS).o | 29 | obj-y += irq_$(BITS).o |
31 | obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4c_irq.o sun4d_irq.o | 30 | obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4d_irq.o |
32 | 31 | ||
33 | obj-y += process_$(BITS).o | 32 | obj-y += process_$(BITS).o |
34 | obj-y += signal_$(BITS).o | 33 | obj-y += signal_$(BITS).o |
@@ -46,7 +45,6 @@ obj-$(CONFIG_SPARC32) += tadpole.o | |||
46 | obj-y += ptrace_$(BITS).o | 45 | obj-y += ptrace_$(BITS).o |
47 | obj-y += unaligned_$(BITS).o | 46 | obj-y += unaligned_$(BITS).o |
48 | obj-y += una_asm_$(BITS).o | 47 | obj-y += una_asm_$(BITS).o |
49 | obj-$(CONFIG_SPARC32) += muldiv.o | ||
50 | obj-y += prom_common.o | 48 | obj-y += prom_common.o |
51 | obj-y += prom_$(BITS).o | 49 | obj-y += prom_$(BITS).o |
52 | obj-y += of_device_common.o | 50 | obj-y += of_device_common.o |
diff --git a/arch/sparc/kernel/auxio_32.c b/arch/sparc/kernel/auxio_32.c index 56d0f52c3e62..e20cc55fb768 100644 --- a/arch/sparc/kernel/auxio_32.c +++ b/arch/sparc/kernel/auxio_32.c | |||
@@ -32,7 +32,6 @@ void __init auxio_probe(void) | |||
32 | switch (sparc_cpu_model) { | 32 | switch (sparc_cpu_model) { |
33 | case sparc_leon: | 33 | case sparc_leon: |
34 | case sun4d: | 34 | case sun4d: |
35 | case sun4: | ||
36 | return; | 35 | return; |
37 | default: | 36 | default: |
38 | break; | 37 | break; |
@@ -65,9 +64,8 @@ void __init auxio_probe(void) | |||
65 | r.start = auxregs[0].phys_addr; | 64 | r.start = auxregs[0].phys_addr; |
66 | r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; | 65 | r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; |
67 | auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); | 66 | auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); |
68 | /* Fix the address on sun4m and sun4c. */ | 67 | /* Fix the address on sun4m. */ |
69 | if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || | 68 | if ((((unsigned long) auxregs[0].phys_addr) & 3) == 3) |
70 | sparc_cpu_model == sun4c) | ||
71 | auxio_register += (3 - ((unsigned long)auxio_register & 3)); | 69 | auxio_register += (3 - ((unsigned long)auxio_register & 3)); |
72 | 70 | ||
73 | set_auxio(AUXIO_LED, 0); | 71 | set_auxio(AUXIO_LED, 0); |
@@ -86,12 +84,7 @@ void set_auxio(unsigned char bits_on, unsigned char bits_off) | |||
86 | unsigned char regval; | 84 | unsigned char regval; |
87 | unsigned long flags; | 85 | unsigned long flags; |
88 | spin_lock_irqsave(&auxio_lock, flags); | 86 | spin_lock_irqsave(&auxio_lock, flags); |
89 | switch(sparc_cpu_model) { | 87 | switch (sparc_cpu_model) { |
90 | case sun4c: | ||
91 | regval = sbus_readb(auxio_register); | ||
92 | sbus_writeb(((regval | bits_on) & ~bits_off) | AUXIO_ORMEIN, | ||
93 | auxio_register); | ||
94 | break; | ||
95 | case sun4m: | 88 | case sun4m: |
96 | if(!auxio_register) | 89 | if(!auxio_register) |
97 | break; /* VME chassis sun4m, no auxio. */ | 90 | break; /* VME chassis sun4m, no auxio. */ |
diff --git a/arch/sparc/kernel/central.c b/arch/sparc/kernel/central.c index 38d48a59879c..9708851a8b9f 100644 --- a/arch/sparc/kernel/central.c +++ b/arch/sparc/kernel/central.c | |||
@@ -269,4 +269,4 @@ static int __init sunfire_init(void) | |||
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | 271 | ||
272 | subsys_initcall(sunfire_init); | 272 | fs_initcall(sunfire_init); |
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index 6b2f56a6f8af..3d465e87f7e2 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <asm/cpu_type.h> | 21 | #include <asm/cpu_type.h> |
22 | 22 | ||
23 | extern void clock_stop_probe(void); /* tadpole.c */ | 23 | extern void clock_stop_probe(void); /* tadpole.c */ |
24 | extern void sun4c_probe_memerr_reg(void); | ||
25 | 24 | ||
26 | static char *cpu_mid_prop(void) | 25 | static char *cpu_mid_prop(void) |
27 | { | 26 | { |
@@ -139,7 +138,4 @@ void __init device_scan(void) | |||
139 | auxio_power_probe(); | 138 | auxio_power_probe(); |
140 | } | 139 | } |
141 | clock_stop_probe(); | 140 | clock_stop_probe(); |
142 | |||
143 | if (ARCH_SUN4C) | ||
144 | sun4c_probe_memerr_reg(); | ||
145 | } | 141 | } |
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index b93c2c9ccb1d..f09257c86107 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c | |||
@@ -868,7 +868,7 @@ void ldom_power_off(void) | |||
868 | 868 | ||
869 | static void ds_conn_reset(struct ds_info *dp) | 869 | static void ds_conn_reset(struct ds_info *dp) |
870 | { | 870 | { |
871 | printk(KERN_ERR "ds-%llu: ds_conn_reset() from %p\n", | 871 | printk(KERN_ERR "ds-%llu: ds_conn_reset() from %pf\n", |
872 | dp->id, __builtin_return_address(0)); | 872 | dp->id, __builtin_return_address(0)); |
873 | } | 873 | } |
874 | 874 | ||
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index f445e98463e6..2dbe1806e530 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -7,6 +7,7 @@ | |||
7 | * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) | 7 | * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/linkage.h> | ||
10 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
11 | 12 | ||
12 | #include <asm/head.h> | 13 | #include <asm/head.h> |
@@ -17,10 +18,8 @@ | |||
17 | #include <asm/asm-offsets.h> | 18 | #include <asm/asm-offsets.h> |
18 | #include <asm/psr.h> | 19 | #include <asm/psr.h> |
19 | #include <asm/vaddrs.h> | 20 | #include <asm/vaddrs.h> |
20 | #include <asm/memreg.h> | ||
21 | #include <asm/page.h> | 21 | #include <asm/page.h> |
22 | #include <asm/pgtable.h> | 22 | #include <asm/pgtable.h> |
23 | #include <asm/pgtsun4c.h> | ||
24 | #include <asm/winmacro.h> | 23 | #include <asm/winmacro.h> |
25 | #include <asm/signal.h> | 24 | #include <asm/signal.h> |
26 | #include <asm/obio.h> | 25 | #include <asm/obio.h> |
@@ -125,22 +124,11 @@ floppy_tdone: | |||
125 | set auxio_register, %l7 | 124 | set auxio_register, %l7 |
126 | ld [%l7], %l7 | 125 | ld [%l7], %l7 |
127 | 126 | ||
128 | set sparc_cpu_model, %l5 | 127 | ldub [%l7], %l5 |
129 | ld [%l5], %l5 | ||
130 | subcc %l5, 1, %g0 /* enum { sun4c = 1 }; */ | ||
131 | be 1f | ||
132 | ldub [%l7], %l5 | ||
133 | 128 | ||
134 | or %l5, 0xc2, %l5 | 129 | or %l5, 0xc2, %l5 |
135 | stb %l5, [%l7] | 130 | stb %l5, [%l7] |
136 | andn %l5, 0x02, %l5 | 131 | andn %l5, 0x02, %l5 |
137 | b 2f | ||
138 | nop | ||
139 | |||
140 | 1: | ||
141 | or %l5, 0xf4, %l5 | ||
142 | stb %l5, [%l7] | ||
143 | andn %l5, 0x04, %l5 | ||
144 | 132 | ||
145 | 2: | 133 | 2: |
146 | /* Kill some time so the bits set */ | 134 | /* Kill some time so the bits set */ |
@@ -266,6 +254,11 @@ smp4m_ticker: | |||
266 | WRITE_PAUSE | 254 | WRITE_PAUSE |
267 | RESTORE_ALL | 255 | RESTORE_ALL |
268 | 256 | ||
257 | #define GET_PROCESSOR4M_ID(reg) \ | ||
258 | rd %tbr, %reg; \ | ||
259 | srl %reg, 12, %reg; \ | ||
260 | and %reg, 3, %reg; | ||
261 | |||
269 | /* Here is where we check for possible SMP IPI passed to us | 262 | /* Here is where we check for possible SMP IPI passed to us |
270 | * on some level other than 15 which is the NMI and only used | 263 | * on some level other than 15 which is the NMI and only used |
271 | * for cross calls. That has a separate entry point below. | 264 | * for cross calls. That has a separate entry point below. |
@@ -328,7 +321,7 @@ linux_trap_ipi15_sun4m: | |||
328 | ld [%o5 + %o0], %o5 | 321 | ld [%o5 + %o0], %o5 |
329 | ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending | 322 | ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending |
330 | andcc %o3, %o2, %g0 | 323 | andcc %o3, %o2, %g0 |
331 | be 1f ! Must be an NMI async memory error | 324 | be sun4m_nmi_error ! Must be an NMI async memory error |
332 | st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000 | 325 | st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000 |
333 | WRITE_PAUSE | 326 | WRITE_PAUSE |
334 | ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending | 327 | ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending |
@@ -342,27 +335,6 @@ linux_trap_ipi15_sun4m: | |||
342 | nop | 335 | nop |
343 | b ret_trap_lockless_ipi | 336 | b ret_trap_lockless_ipi |
344 | clr %l6 | 337 | clr %l6 |
345 | 1: | ||
346 | /* NMI async memory error handling. */ | ||
347 | sethi %hi(0x80000000), %l4 | ||
348 | sethi %hi(sun4m_irq_global), %o5 | ||
349 | ld [%o5 + %lo(sun4m_irq_global)], %l5 | ||
350 | st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000 | ||
351 | WRITE_PAUSE | ||
352 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending | ||
353 | WRITE_PAUSE | ||
354 | or %l0, PSR_PIL, %l4 | ||
355 | wr %l4, 0x0, %psr | ||
356 | WRITE_PAUSE | ||
357 | wr %l4, PSR_ET, %psr | ||
358 | WRITE_PAUSE | ||
359 | call sun4m_nmi | ||
360 | nop | ||
361 | st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000 | ||
362 | WRITE_PAUSE | ||
363 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending | ||
364 | WRITE_PAUSE | ||
365 | RESTORE_ALL | ||
366 | 338 | ||
367 | .globl smp4d_ticker | 339 | .globl smp4d_ticker |
368 | /* SMP per-cpu ticker interrupts are handled specially. */ | 340 | /* SMP per-cpu ticker interrupts are handled specially. */ |
@@ -760,326 +732,37 @@ setcc_trap_handler: | |||
760 | jmp %l2 ! advance over trap instruction | 732 | jmp %l2 ! advance over trap instruction |
761 | rett %l2 + 0x4 ! like this... | 733 | rett %l2 + 0x4 ! like this... |
762 | 734 | ||
763 | .align 4 | 735 | sun4m_nmi_error: |
764 | .globl linux_trap_nmi_sun4c | 736 | /* NMI async memory error handling. */ |
765 | linux_trap_nmi_sun4c: | 737 | sethi %hi(0x80000000), %l4 |
766 | SAVE_ALL | 738 | sethi %hi(sun4m_irq_global), %o5 |
767 | 739 | ld [%o5 + %lo(sun4m_irq_global)], %l5 | |
768 | /* Ugh, we need to clear the IRQ line. This is now | 740 | st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000 |
769 | * a very sun4c specific trap handler... | ||
770 | */ | ||
771 | sethi %hi(interrupt_enable), %l5 | ||
772 | ld [%l5 + %lo(interrupt_enable)], %l5 | ||
773 | ldub [%l5], %l6 | ||
774 | andn %l6, INTS_ENAB, %l6 | ||
775 | stb %l6, [%l5] | ||
776 | |||
777 | /* Now it is safe to re-enable traps without recursion. */ | ||
778 | or %l0, PSR_PIL, %l0 | ||
779 | wr %l0, PSR_ET, %psr | ||
780 | WRITE_PAUSE | 741 | WRITE_PAUSE |
781 | 742 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending | |
782 | /* Now call the c-code with the pt_regs frame ptr and the | ||
783 | * memory error registers as arguments. The ordering chosen | ||
784 | * here is due to unlatching semantics. | ||
785 | */ | ||
786 | sethi %hi(AC_SYNC_ERR), %o0 | ||
787 | add %o0, 0x4, %o0 | ||
788 | lda [%o0] ASI_CONTROL, %o2 ! sync vaddr | ||
789 | sub %o0, 0x4, %o0 | ||
790 | lda [%o0] ASI_CONTROL, %o1 ! sync error | ||
791 | add %o0, 0xc, %o0 | ||
792 | lda [%o0] ASI_CONTROL, %o4 ! async vaddr | ||
793 | sub %o0, 0x4, %o0 | ||
794 | lda [%o0] ASI_CONTROL, %o3 ! async error | ||
795 | call sparc_lvl15_nmi | ||
796 | add %sp, STACKFRAME_SZ, %o0 | ||
797 | |||
798 | RESTORE_ALL | ||
799 | |||
800 | .align 4 | ||
801 | .globl invalid_segment_patch1_ff | ||
802 | .globl invalid_segment_patch2_ff | ||
803 | invalid_segment_patch1_ff: cmp %l4, 0xff | ||
804 | invalid_segment_patch2_ff: mov 0xff, %l3 | ||
805 | |||
806 | .align 4 | ||
807 | .globl invalid_segment_patch1_1ff | ||
808 | .globl invalid_segment_patch2_1ff | ||
809 | invalid_segment_patch1_1ff: cmp %l4, 0x1ff | ||
810 | invalid_segment_patch2_1ff: mov 0x1ff, %l3 | ||
811 | |||
812 | .align 4 | ||
813 | .globl num_context_patch1_16, num_context_patch2_16 | ||
814 | num_context_patch1_16: mov 0x10, %l7 | ||
815 | num_context_patch2_16: mov 0x10, %l7 | ||
816 | |||
817 | .align 4 | ||
818 | .globl vac_linesize_patch_32 | ||
819 | vac_linesize_patch_32: subcc %l7, 32, %l7 | ||
820 | |||
821 | .align 4 | ||
822 | .globl vac_hwflush_patch1_on, vac_hwflush_patch2_on | ||
823 | |||
824 | /* | ||
825 | * Ugly, but we can't use hardware flushing on the sun4 and we'd require | ||
826 | * two instructions (Anton) | ||
827 | */ | ||
828 | vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7 | ||
829 | |||
830 | vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG | ||
831 | |||
832 | .globl invalid_segment_patch1, invalid_segment_patch2 | ||
833 | .globl num_context_patch1 | ||
834 | .globl vac_linesize_patch, vac_hwflush_patch1 | ||
835 | .globl vac_hwflush_patch2 | ||
836 | |||
837 | .align 4 | ||
838 | .globl sun4c_fault | ||
839 | |||
840 | ! %l0 = %psr | ||
841 | ! %l1 = %pc | ||
842 | ! %l2 = %npc | ||
843 | ! %l3 = %wim | ||
844 | ! %l7 = 1 for textfault | ||
845 | ! We want error in %l5, vaddr in %l6 | ||
846 | sun4c_fault: | ||
847 | sethi %hi(AC_SYNC_ERR), %l4 | ||
848 | add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6 | ||
849 | lda [%l6] ASI_CONTROL, %l5 ! Address | ||
850 | lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit | ||
851 | |||
852 | andn %l5, 0xfff, %l5 ! Encode all info into l7 | ||
853 | srl %l6, 14, %l4 | ||
854 | |||
855 | and %l4, 2, %l4 | ||
856 | or %l5, %l4, %l4 | ||
857 | |||
858 | or %l4, %l7, %l7 ! l7 = [addr,write,txtfault] | ||
859 | |||
860 | andcc %l0, PSR_PS, %g0 | ||
861 | be sun4c_fault_fromuser | ||
862 | andcc %l7, 1, %g0 ! Text fault? | ||
863 | |||
864 | be 1f | ||
865 | sethi %hi(KERNBASE), %l4 | ||
866 | |||
867 | mov %l1, %l5 ! PC | ||
868 | |||
869 | 1: | ||
870 | cmp %l5, %l4 | ||
871 | blu sun4c_fault_fromuser | ||
872 | sethi %hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4 | ||
873 | |||
874 | /* If the kernel references a bum kernel pointer, or a pte which | ||
875 | * points to a non existent page in ram, we will run this code | ||
876 | * _forever_ and lock up the machine!!!!! So we must check for | ||
877 | * this condition, the AC_SYNC_ERR bits are what we must examine. | ||
878 | * Also a parity error would make this happen as well. So we just | ||
879 | * check that we are in fact servicing a tlb miss and not some | ||
880 | * other type of fault for the kernel. | ||
881 | */ | ||
882 | andcc %l6, 0x80, %g0 | ||
883 | be sun4c_fault_fromuser | ||
884 | and %l5, %l4, %l5 | ||
885 | |||
886 | /* Test for NULL pte_t * in vmalloc area. */ | ||
887 | sethi %hi(VMALLOC_START), %l4 | ||
888 | cmp %l5, %l4 | ||
889 | blu,a invalid_segment_patch1 | ||
890 | lduXa [%l5] ASI_SEGMAP, %l4 | ||
891 | |||
892 | sethi %hi(swapper_pg_dir), %l4 | ||
893 | srl %l5, SUN4C_PGDIR_SHIFT, %l6 | ||
894 | or %l4, %lo(swapper_pg_dir), %l4 | ||
895 | sll %l6, 2, %l6 | ||
896 | ld [%l4 + %l6], %l4 | ||
897 | andcc %l4, PAGE_MASK, %g0 | ||
898 | be sun4c_fault_fromuser | ||
899 | lduXa [%l5] ASI_SEGMAP, %l4 | ||
900 | |||
901 | invalid_segment_patch1: | ||
902 | cmp %l4, 0x7f | ||
903 | bne 1f | ||
904 | sethi %hi(sun4c_kfree_ring), %l4 | ||
905 | or %l4, %lo(sun4c_kfree_ring), %l4 | ||
906 | ld [%l4 + 0x18], %l3 | ||
907 | deccc %l3 ! do we have a free entry? | ||
908 | bcs,a 2f ! no, unmap one. | ||
909 | sethi %hi(sun4c_kernel_ring), %l4 | ||
910 | |||
911 | st %l3, [%l4 + 0x18] ! sun4c_kfree_ring.num_entries-- | ||
912 | |||
913 | ld [%l4 + 0x00], %l6 ! entry = sun4c_kfree_ring.ringhd.next | ||
914 | st %l5, [%l6 + 0x08] ! entry->vaddr = address | ||
915 | |||
916 | ld [%l6 + 0x00], %l3 ! next = entry->next | ||
917 | ld [%l6 + 0x04], %l7 ! entry->prev | ||
918 | |||
919 | st %l7, [%l3 + 0x04] ! next->prev = entry->prev | ||
920 | st %l3, [%l7 + 0x00] ! entry->prev->next = next | ||
921 | |||
922 | sethi %hi(sun4c_kernel_ring), %l4 | ||
923 | or %l4, %lo(sun4c_kernel_ring), %l4 | ||
924 | ! head = &sun4c_kernel_ring.ringhd | ||
925 | |||
926 | ld [%l4 + 0x00], %l7 ! head->next | ||
927 | |||
928 | st %l4, [%l6 + 0x04] ! entry->prev = head | ||
929 | st %l7, [%l6 + 0x00] ! entry->next = head->next | ||
930 | st %l6, [%l7 + 0x04] ! head->next->prev = entry | ||
931 | |||
932 | st %l6, [%l4 + 0x00] ! head->next = entry | ||
933 | |||
934 | ld [%l4 + 0x18], %l3 | ||
935 | inc %l3 ! sun4c_kernel_ring.num_entries++ | ||
936 | st %l3, [%l4 + 0x18] | ||
937 | b 4f | ||
938 | ld [%l6 + 0x08], %l5 | ||
939 | |||
940 | 2: | ||
941 | or %l4, %lo(sun4c_kernel_ring), %l4 | ||
942 | ! head = &sun4c_kernel_ring.ringhd | ||
943 | |||
944 | ld [%l4 + 0x04], %l6 ! entry = head->prev | ||
945 | |||
946 | ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr | ||
947 | |||
948 | ! Flush segment from the cache. | ||
949 | sethi %hi((64 * 1024)), %l7 | ||
950 | 9: | ||
951 | vac_hwflush_patch1: | ||
952 | vac_linesize_patch: | ||
953 | subcc %l7, 16, %l7 | ||
954 | bne 9b | ||
955 | vac_hwflush_patch2: | ||
956 | sta %g0, [%l3 + %l7] ASI_FLUSHSEG | ||
957 | |||
958 | st %l5, [%l6 + 0x08] ! entry->vaddr = address | ||
959 | |||
960 | ld [%l6 + 0x00], %l5 ! next = entry->next | ||
961 | ld [%l6 + 0x04], %l7 ! entry->prev | ||
962 | |||
963 | st %l7, [%l5 + 0x04] ! next->prev = entry->prev | ||
964 | st %l5, [%l7 + 0x00] ! entry->prev->next = next | ||
965 | st %l4, [%l6 + 0x04] ! entry->prev = head | ||
966 | |||
967 | ld [%l4 + 0x00], %l7 ! head->next | ||
968 | |||
969 | st %l7, [%l6 + 0x00] ! entry->next = head->next | ||
970 | st %l6, [%l7 + 0x04] ! head->next->prev = entry | ||
971 | st %l6, [%l4 + 0x00] ! head->next = entry | ||
972 | |||
973 | mov %l3, %l5 ! address = tmp | ||
974 | |||
975 | 4: | ||
976 | num_context_patch1: | ||
977 | mov 0x08, %l7 | ||
978 | |||
979 | ld [%l6 + 0x08], %l4 | ||
980 | ldub [%l6 + 0x0c], %l3 | ||
981 | or %l4, %l3, %l4 ! encode new vaddr/pseg into l4 | ||
982 | |||
983 | sethi %hi(AC_CONTEXT), %l3 | ||
984 | lduba [%l3] ASI_CONTROL, %l6 | ||
985 | |||
986 | /* Invalidate old mapping, instantiate new mapping, | ||
987 | * for each context. Registers l6/l7 are live across | ||
988 | * this loop. | ||
989 | */ | ||
990 | 3: deccc %l7 | ||
991 | sethi %hi(AC_CONTEXT), %l3 | ||
992 | stba %l7, [%l3] ASI_CONTROL | ||
993 | invalid_segment_patch2: | ||
994 | mov 0x7f, %l3 | ||
995 | stXa %l3, [%l5] ASI_SEGMAP | ||
996 | andn %l4, 0x1ff, %l3 | ||
997 | bne 3b | ||
998 | stXa %l4, [%l3] ASI_SEGMAP | ||
999 | |||
1000 | sethi %hi(AC_CONTEXT), %l3 | ||
1001 | stba %l6, [%l3] ASI_CONTROL | ||
1002 | |||
1003 | andn %l4, 0x1ff, %l5 | ||
1004 | |||
1005 | 1: | ||
1006 | sethi %hi(VMALLOC_START), %l4 | ||
1007 | cmp %l5, %l4 | ||
1008 | |||
1009 | bgeu 1f | ||
1010 | mov 1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7 | ||
1011 | |||
1012 | sethi %hi(KERNBASE), %l6 | ||
1013 | |||
1014 | sub %l5, %l6, %l4 | ||
1015 | srl %l4, PAGE_SHIFT, %l4 | ||
1016 | sethi %hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3 | ||
1017 | or %l3, %l4, %l3 | ||
1018 | |||
1019 | sethi %hi(PAGE_SIZE), %l4 | ||
1020 | |||
1021 | 2: | ||
1022 | sta %l3, [%l5] ASI_PTE | ||
1023 | deccc %l7 | ||
1024 | inc %l3 | ||
1025 | bne 2b | ||
1026 | add %l5, %l4, %l5 | ||
1027 | |||
1028 | b 7f | ||
1029 | sethi %hi(sun4c_kernel_faults), %l4 | ||
1030 | |||
1031 | 1: | ||
1032 | srl %l5, SUN4C_PGDIR_SHIFT, %l3 | ||
1033 | sethi %hi(swapper_pg_dir), %l4 | ||
1034 | or %l4, %lo(swapper_pg_dir), %l4 | ||
1035 | sll %l3, 2, %l3 | ||
1036 | ld [%l4 + %l3], %l4 | ||
1037 | and %l4, PAGE_MASK, %l4 | ||
1038 | |||
1039 | srl %l5, (PAGE_SHIFT - 2), %l6 | ||
1040 | and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6 | ||
1041 | add %l6, %l4, %l6 | ||
1042 | |||
1043 | sethi %hi(PAGE_SIZE), %l4 | ||
1044 | |||
1045 | 2: | ||
1046 | ld [%l6], %l3 | ||
1047 | deccc %l7 | ||
1048 | sta %l3, [%l5] ASI_PTE | ||
1049 | add %l6, 0x4, %l6 | ||
1050 | bne 2b | ||
1051 | add %l5, %l4, %l5 | ||
1052 | |||
1053 | sethi %hi(sun4c_kernel_faults), %l4 | ||
1054 | 7: | ||
1055 | ld [%l4 + %lo(sun4c_kernel_faults)], %l3 | ||
1056 | inc %l3 | ||
1057 | st %l3, [%l4 + %lo(sun4c_kernel_faults)] | ||
1058 | |||
1059 | /* Restore condition codes */ | ||
1060 | wr %l0, 0x0, %psr | ||
1061 | WRITE_PAUSE | 743 | WRITE_PAUSE |
1062 | jmp %l1 | 744 | or %l0, PSR_PIL, %l4 |
1063 | rett %l2 | 745 | wr %l4, 0x0, %psr |
1064 | 746 | WRITE_PAUSE | |
1065 | sun4c_fault_fromuser: | 747 | wr %l4, PSR_ET, %psr |
1066 | SAVE_ALL | 748 | WRITE_PAUSE |
749 | call sun4m_nmi | ||
1067 | nop | 750 | nop |
1068 | 751 | st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000 | |
1069 | mov %l7, %o1 ! Decode the info from %l7 | ||
1070 | mov %l7, %o2 | ||
1071 | and %o1, 1, %o1 ! arg2 = text_faultp | ||
1072 | mov %l7, %o3 | ||
1073 | and %o2, 2, %o2 ! arg3 = writep | ||
1074 | andn %o3, 0xfff, %o3 ! arg4 = faulting address | ||
1075 | |||
1076 | wr %l0, PSR_ET, %psr | ||
1077 | WRITE_PAUSE | 752 | WRITE_PAUSE |
753 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending | ||
754 | WRITE_PAUSE | ||
755 | RESTORE_ALL | ||
1078 | 756 | ||
1079 | call do_sun4c_fault | 757 | #ifndef CONFIG_SMP |
1080 | add %sp, STACKFRAME_SZ, %o0 ! arg1 = pt_regs ptr | 758 | .align 4 |
759 | .globl linux_trap_ipi15_sun4m | ||
760 | linux_trap_ipi15_sun4m: | ||
761 | SAVE_ALL | ||
1081 | 762 | ||
1082 | RESTORE_ALL | 763 | ba sun4m_nmi_error |
764 | nop | ||
765 | #endif /* CONFIG_SMP */ | ||
1083 | 766 | ||
1084 | .align 4 | 767 | .align 4 |
1085 | .globl srmmu_fault | 768 | .globl srmmu_fault |
@@ -1483,11 +1166,13 @@ fpload: | |||
1483 | .globl __ndelay | 1166 | .globl __ndelay |
1484 | __ndelay: | 1167 | __ndelay: |
1485 | save %sp, -STACKFRAME_SZ, %sp | 1168 | save %sp, -STACKFRAME_SZ, %sp |
1486 | mov %i0, %o0 | 1169 | mov %i0, %o0 ! round multiplier up so large ns ok |
1487 | call .umul ! round multiplier up so large ns ok | 1170 | mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ) |
1488 | mov 0x1ae, %o1 ! 2**32 / (1 000 000 000 / HZ) | 1171 | umul %o0, %o1, %o0 |
1489 | call .umul | 1172 | rd %y, %o1 |
1490 | mov %i1, %o1 ! udelay_val | 1173 | mov %i1, %o1 ! udelay_val |
1174 | umul %o0, %o1, %o0 | ||
1175 | rd %y, %o1 | ||
1491 | ba delay_continue | 1176 | ba delay_continue |
1492 | mov %o1, %o0 ! >>32 later for better resolution | 1177 | mov %o1, %o0 ! >>32 later for better resolution |
1493 | 1178 | ||
@@ -1496,18 +1181,21 @@ __udelay: | |||
1496 | save %sp, -STACKFRAME_SZ, %sp | 1181 | save %sp, -STACKFRAME_SZ, %sp |
1497 | mov %i0, %o0 | 1182 | mov %i0, %o0 |
1498 | sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok | 1183 | sethi %hi(0x10c7), %o1 ! round multiplier up so large us ok |
1499 | call .umul | 1184 | or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000 |
1500 | or %o1, %lo(0x10c7), %o1 ! 2**32 / 1 000 000 | 1185 | umul %o0, %o1, %o0 |
1501 | call .umul | 1186 | rd %y, %o1 |
1502 | mov %i1, %o1 ! udelay_val | 1187 | mov %i1, %o1 ! udelay_val |
1188 | umul %o0, %o1, %o0 | ||
1189 | rd %y, %o1 | ||
1503 | sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32, | 1190 | sethi %hi(0x028f4b62), %l0 ! Add in rounding constant * 2**32, |
1504 | or %g0, %lo(0x028f4b62), %l0 | 1191 | or %g0, %lo(0x028f4b62), %l0 |
1505 | addcc %o0, %l0, %o0 ! 2**32 * 0.009 999 | 1192 | addcc %o0, %l0, %o0 ! 2**32 * 0.009 999 |
1506 | bcs,a 3f | 1193 | bcs,a 3f |
1507 | add %o1, 0x01, %o1 | 1194 | add %o1, 0x01, %o1 |
1508 | 3: | 1195 | 3: |
1509 | call .umul | 1196 | mov HZ, %o0 ! >>32 earlier for wider range |
1510 | mov HZ, %o0 ! >>32 earlier for wider range | 1197 | umul %o0, %o1, %o0 |
1198 | rd %y, %o1 | ||
1511 | 1199 | ||
1512 | delay_continue: | 1200 | delay_continue: |
1513 | cmp %o0, 0x0 | 1201 | cmp %o0, 0x0 |
@@ -1670,4 +1358,26 @@ flushw_all: | |||
1670 | ret | 1358 | ret |
1671 | restore | 1359 | restore |
1672 | 1360 | ||
1361 | #ifdef CONFIG_SMP | ||
1362 | ENTRY(hard_smp_processor_id) | ||
1363 | 661: rd %tbr, %g1 | ||
1364 | srl %g1, 12, %o0 | ||
1365 | and %o0, 3, %o0 | ||
1366 | .section .cpuid_patch, "ax" | ||
1367 | /* Instruction location. */ | ||
1368 | .word 661b | ||
1369 | /* SUN4D implementation. */ | ||
1370 | lda [%g0] ASI_M_VIKING_TMP1, %o0 | ||
1371 | nop | ||
1372 | nop | ||
1373 | /* LEON implementation. */ | ||
1374 | rd %asr17, %o0 | ||
1375 | srl %o0, 0x1c, %o0 | ||
1376 | nop | ||
1377 | .previous | ||
1378 | retl | ||
1379 | nop | ||
1380 | ENDPROC(hard_smp_processor_id) | ||
1381 | #endif | ||
1382 | |||
1673 | /* End of entry.S */ | 1383 | /* End of entry.S */ |
diff --git a/arch/sparc/kernel/etrap_32.S b/arch/sparc/kernel/etrap_32.S index e806fcdc46db..84b5f0d2afde 100644 --- a/arch/sparc/kernel/etrap_32.S +++ b/arch/sparc/kernel/etrap_32.S | |||
@@ -216,9 +216,7 @@ tsetup_patch6: | |||
216 | /* Call MMU-architecture dependent stack checking | 216 | /* Call MMU-architecture dependent stack checking |
217 | * routine. | 217 | * routine. |
218 | */ | 218 | */ |
219 | .globl tsetup_mmu_patchme | 219 | b tsetup_srmmu_stackchk |
220 | tsetup_mmu_patchme: | ||
221 | b tsetup_sun4c_stackchk | ||
222 | andcc %sp, 0x7, %g0 | 220 | andcc %sp, 0x7, %g0 |
223 | 221 | ||
224 | /* Architecture specific stack checking routines. When either | 222 | /* Architecture specific stack checking routines. When either |
@@ -228,52 +226,6 @@ tsetup_mmu_patchme: | |||
228 | */ | 226 | */ |
229 | #define glob_tmp g1 | 227 | #define glob_tmp g1 |
230 | 228 | ||
231 | tsetup_sun4c_stackchk: | ||
232 | /* Done by caller: andcc %sp, 0x7, %g0 */ | ||
233 | bne trap_setup_user_stack_is_bolixed | ||
234 | sra %sp, 29, %glob_tmp | ||
235 | |||
236 | add %glob_tmp, 0x1, %glob_tmp | ||
237 | andncc %glob_tmp, 0x1, %g0 | ||
238 | bne trap_setup_user_stack_is_bolixed | ||
239 | and %sp, 0xfff, %glob_tmp ! delay slot | ||
240 | |||
241 | /* See if our dump area will be on more than one | ||
242 | * page. | ||
243 | */ | ||
244 | add %glob_tmp, 0x38, %glob_tmp | ||
245 | andncc %glob_tmp, 0xff8, %g0 | ||
246 | be tsetup_sun4c_onepage ! only one page to check | ||
247 | lda [%sp] ASI_PTE, %glob_tmp ! have to check first page anyways | ||
248 | |||
249 | tsetup_sun4c_twopages: | ||
250 | /* Is first page ok permission wise? */ | ||
251 | srl %glob_tmp, 29, %glob_tmp | ||
252 | cmp %glob_tmp, 0x6 | ||
253 | bne trap_setup_user_stack_is_bolixed | ||
254 | add %sp, 0x38, %glob_tmp /* Is second page in vma hole? */ | ||
255 | |||
256 | sra %glob_tmp, 29, %glob_tmp | ||
257 | add %glob_tmp, 0x1, %glob_tmp | ||
258 | andncc %glob_tmp, 0x1, %g0 | ||
259 | bne trap_setup_user_stack_is_bolixed | ||
260 | add %sp, 0x38, %glob_tmp | ||
261 | |||
262 | lda [%glob_tmp] ASI_PTE, %glob_tmp | ||
263 | |||
264 | tsetup_sun4c_onepage: | ||
265 | srl %glob_tmp, 29, %glob_tmp | ||
266 | cmp %glob_tmp, 0x6 ! can user write to it? | ||
267 | bne trap_setup_user_stack_is_bolixed ! failure | ||
268 | nop | ||
269 | |||
270 | STORE_WINDOW(sp) | ||
271 | |||
272 | restore %g0, %g0, %g0 | ||
273 | |||
274 | jmpl %t_retpc + 0x8, %g0 | ||
275 | mov %t_kstack, %sp | ||
276 | |||
277 | .globl tsetup_srmmu_stackchk | 229 | .globl tsetup_srmmu_stackchk |
278 | tsetup_srmmu_stackchk: | 230 | tsetup_srmmu_stackchk: |
279 | /* Check results of callers andcc %sp, 0x7, %g0 */ | 231 | /* Check results of callers andcc %sp, 0x7, %g0 */ |
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S index 587785759838..a0f5c20e4b9c 100644 --- a/arch/sparc/kernel/head_32.S +++ b/arch/sparc/kernel/head_32.S | |||
@@ -26,11 +26,9 @@ | |||
26 | #include <asm/pgtsrmmu.h> /* SRMMU_PGDIR_SHIFT */ | 26 | #include <asm/pgtsrmmu.h> /* SRMMU_PGDIR_SHIFT */ |
27 | 27 | ||
28 | .data | 28 | .data |
29 | /* | 29 | /* The following are used with the prom_vector node-ops to figure out |
30 | * The following are used with the prom_vector node-ops to figure out | 30 | * the cpu-type |
31 | * the cpu-type | ||
32 | */ | 31 | */ |
33 | |||
34 | .align 4 | 32 | .align 4 |
35 | cputyp: | 33 | cputyp: |
36 | .word 1 | 34 | .word 1 |
@@ -38,384 +36,35 @@ cputyp: | |||
38 | .align 4 | 36 | .align 4 |
39 | .globl cputypval | 37 | .globl cputypval |
40 | cputypval: | 38 | cputypval: |
41 | .asciz "sun4c" | 39 | .asciz "sun4m" |
42 | .ascii " " | 40 | .ascii " " |
43 | 41 | ||
44 | cputypvalend: | 42 | /* Tested on SS-5, SS-10 */ |
45 | cputypvallen = cputypvar - cputypval | ||
46 | |||
47 | .align 4 | 43 | .align 4 |
48 | /* | ||
49 | * Sun people can't spell worth damn. "compatability" indeed. | ||
50 | * At least we *know* we can't spell, and use a spell-checker. | ||
51 | */ | ||
52 | |||
53 | /* Uh, actually Linus it is I who cannot spell. Too much murky | ||
54 | * Sparc assembly will do this to ya. | ||
55 | */ | ||
56 | cputypvar: | 44 | cputypvar: |
57 | .asciz "compatability" | ||
58 | |||
59 | /* Tested on SS-5, SS-10. Probably someone at Sun applied a spell-checker. */ | ||
60 | .align 4 | ||
61 | cputypvar_sun4m: | ||
62 | .asciz "compatible" | 45 | .asciz "compatible" |
63 | 46 | ||
64 | .align 4 | 47 | .align 4 |
65 | 48 | ||
66 | sun4_notsup: | 49 | sun4c_notsup: |
67 | .asciz "Sparc-Linux sun4 support does no longer exist.\n\n" | 50 | .asciz "Sparc-Linux sun4/sun4c support does no longer exist.\n\n" |
68 | .align 4 | 51 | .align 4 |
69 | 52 | ||
70 | sun4e_notsup: | 53 | sun4e_notsup: |
71 | .asciz "Sparc-Linux sun4e support does not exist\n\n" | 54 | .asciz "Sparc-Linux sun4e support does not exist\n\n" |
72 | .align 4 | 55 | .align 4 |
73 | 56 | ||
74 | /* The Sparc trap table, bootloader gives us control at _start. */ | 57 | /* The trap-table - located in the __HEAD section */ |
75 | __HEAD | 58 | #include "ttable_32.S" |
76 | .globl _stext, _start, __stext | ||
77 | .globl trapbase | ||
78 | _start: /* danger danger */ | ||
79 | __stext: | ||
80 | _stext: | ||
81 | trapbase: | ||
82 | #ifdef CONFIG_SMP | ||
83 | trapbase_cpu0: | ||
84 | #endif | ||
85 | /* We get control passed to us here at t_zero. */ | ||
86 | t_zero: b gokernel; nop; nop; nop; | ||
87 | t_tflt: SPARC_TFAULT /* Inst. Access Exception */ | ||
88 | t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ | ||
89 | t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ | ||
90 | t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ | ||
91 | t_wovf: WINDOW_SPILL /* Window Overflow */ | ||
92 | t_wunf: WINDOW_FILL /* Window Underflow */ | ||
93 | t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ | ||
94 | t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ | ||
95 | t_dflt: SPARC_DFAULT /* Data Miss Exception */ | ||
96 | t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ | ||
97 | t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ | ||
98 | t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
99 | t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ | ||
100 | t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ | ||
101 | t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ | ||
102 | t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ | ||
103 | t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ | ||
104 | t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ | ||
105 | t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ | ||
106 | t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ | ||
107 | t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ | ||
108 | t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ | ||
109 | t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ | ||
110 | t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ | ||
111 | t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ | ||
112 | t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ | ||
113 | .globl t_nmi | ||
114 | #ifndef CONFIG_SMP | ||
115 | t_nmi: NMI_TRAP /* Level 15 (NMI) */ | ||
116 | #else | ||
117 | t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
118 | #endif | ||
119 | t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ | ||
120 | t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ | ||
121 | t_bad22:BAD_TRAP(0x22) BAD_TRAP(0x23) | ||
122 | t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ | ||
123 | t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ | ||
124 | t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) | ||
125 | t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ | ||
126 | t_dacce:SPARC_DFAULT /* Data Access Error */ | ||
127 | t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ | ||
128 | t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ | ||
129 | t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ | ||
130 | t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
131 | t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
132 | t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
133 | t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ | ||
134 | t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41) | ||
135 | t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) | ||
136 | t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) | ||
137 | t_bad4c:BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) BAD_TRAP(0x50) | ||
138 | t_bad51:BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
139 | t_bad56:BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
140 | t_bad5b:BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
141 | t_bad60:BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
142 | t_bad65:BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
143 | t_bad6a:BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
144 | t_bad6f:BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
145 | t_bad74:BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
146 | t_bad79:BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
147 | t_bad7e:BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
148 | t_bad80:BAD_TRAP(0x80) /* SunOS System Call */ | ||
149 | t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ | ||
150 | t_divz: TRAP_ENTRY(0x82, do_hw_divzero) /* Divide by zero trap */ | ||
151 | t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ | ||
152 | t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ | ||
153 | t_rchk: BAD_TRAP(0x85) /* Range Check */ | ||
154 | t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ | ||
155 | t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ | ||
156 | t_bad88:BAD_TRAP(0x88) /* Slowaris System Call */ | ||
157 | t_bad89:BAD_TRAP(0x89) /* Net-B.S. System Call */ | ||
158 | t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) | ||
159 | t_bad8f:BAD_TRAP(0x8f) | ||
160 | t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ | ||
161 | t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) | ||
162 | t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) | ||
163 | t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) | ||
164 | t_getcc:GETCC_TRAP /* Get Condition Codes */ | ||
165 | t_setcc:SETCC_TRAP /* Set Condition Codes */ | ||
166 | t_getpsr:GETPSR_TRAP /* Get PSR Register */ | ||
167 | t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
168 | t_bada7:BAD_TRAP(0xa7) | ||
169 | t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
170 | t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
171 | t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
172 | t_badb6:BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
173 | t_badbb:BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
174 | t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
175 | t_badc5:BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
176 | t_badca:BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
177 | t_badcf:BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
178 | t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
179 | t_badd9:BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
180 | t_badde:BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
181 | t_bade3:BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
182 | t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
183 | t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
184 | t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
185 | t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
186 | t_badfc:BAD_TRAP(0xfc) | ||
187 | t_kgdb: KGDB_TRAP(0xfd) | ||
188 | dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ | ||
189 | dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ | ||
190 | |||
191 | .globl end_traptable | ||
192 | end_traptable: | ||
193 | |||
194 | #ifdef CONFIG_SMP | ||
195 | /* Trap tables for the other cpus. */ | ||
196 | .globl trapbase_cpu1, trapbase_cpu2, trapbase_cpu3 | ||
197 | trapbase_cpu1: | ||
198 | BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) | ||
199 | TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) | ||
200 | WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) | ||
201 | TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT | ||
202 | TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) | ||
203 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
204 | TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) | ||
205 | TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) | ||
206 | TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) | ||
207 | TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) | ||
208 | TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) | ||
209 | TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) | ||
210 | TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) | ||
211 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
212 | TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) | ||
213 | BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush) | ||
214 | BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) | ||
215 | SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) | ||
216 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
217 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
218 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
219 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
220 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
221 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
222 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
223 | BAD_TRAP(0x50) | ||
224 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
225 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
226 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
227 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
228 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
229 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
230 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
231 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
232 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
233 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
234 | BAD_TRAP(0x80) | ||
235 | BREAKPOINT_TRAP | ||
236 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
237 | TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) | ||
238 | BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) | ||
239 | BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
240 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
241 | LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
242 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
243 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
244 | BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP | ||
245 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
246 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
247 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
248 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
249 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
250 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
251 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
252 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
253 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
254 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
255 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
256 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
257 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
258 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
259 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
260 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
261 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
262 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
263 | BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) | ||
264 | |||
265 | trapbase_cpu2: | ||
266 | BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) | ||
267 | TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) | ||
268 | WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) | ||
269 | TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT | ||
270 | TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) | ||
271 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
272 | TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) | ||
273 | TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) | ||
274 | TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) | ||
275 | TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) | ||
276 | TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) | ||
277 | TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) | ||
278 | TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) | ||
279 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
280 | TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) | ||
281 | BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush) | ||
282 | BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) | ||
283 | SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) | ||
284 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
285 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
286 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
287 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
288 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
289 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
290 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
291 | BAD_TRAP(0x50) | ||
292 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
293 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
294 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
295 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
296 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
297 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
298 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
299 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
300 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
301 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
302 | BAD_TRAP(0x80) | ||
303 | BREAKPOINT_TRAP | ||
304 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
305 | TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) | ||
306 | BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) | ||
307 | BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
308 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
309 | LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
310 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
311 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
312 | BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP | ||
313 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
314 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
315 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
316 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
317 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
318 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
319 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
320 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
321 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
322 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
323 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
324 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
325 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
326 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
327 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
328 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
329 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
330 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
331 | BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) | ||
332 | |||
333 | trapbase_cpu3: | ||
334 | BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction) | ||
335 | TRAP_ENTRY(0x3, priv_instruction) TRAP_ENTRY(0x4, fpd_trap_handler) | ||
336 | WINDOW_SPILL WINDOW_FILL TRAP_ENTRY(0x7, mna_handler) | ||
337 | TRAP_ENTRY(0x8, fpe_trap_handler) SRMMU_DFAULT | ||
338 | TRAP_ENTRY(0xa, do_tag_overflow) TRAP_ENTRY(0xb, do_watchpoint) | ||
339 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
340 | TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) | ||
341 | TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) | ||
342 | TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) | ||
343 | TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) | ||
344 | TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) | ||
345 | TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) | ||
346 | TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) | ||
347 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
348 | TRAP_ENTRY(0x20, do_reg_access) BAD_TRAP(0x21) BAD_TRAP(0x22) | ||
349 | BAD_TRAP(0x23) TRAP_ENTRY(0x24, do_cp_disabled) SKIP_TRAP(0x25, unimp_flush) | ||
350 | BAD_TRAP(0x26) BAD_TRAP(0x27) TRAP_ENTRY(0x28, do_cp_exception) | ||
351 | SRMMU_DFAULT TRAP_ENTRY(0x2a, do_hw_divzero) BAD_TRAP(0x2b) BAD_TRAP(0x2c) | ||
352 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
353 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
354 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
355 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
356 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
357 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
358 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
359 | BAD_TRAP(0x50) | ||
360 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
361 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
362 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
363 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
364 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
365 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
366 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
367 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
368 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
369 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
370 | BAD_TRAP(0x80) | ||
371 | BREAKPOINT_TRAP | ||
372 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
373 | TRAP_ENTRY(0x83, do_flush_windows) BAD_TRAP(0x84) BAD_TRAP(0x85) | ||
374 | BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) | ||
375 | BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
376 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
377 | LINUX_SYSCALL_TRAP BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
378 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
379 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
380 | BAD_TRAP(0x9f) GETCC_TRAP SETCC_TRAP GETPSR_TRAP | ||
381 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
382 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
383 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
384 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
385 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
386 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
387 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
388 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
389 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
390 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
391 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
392 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
393 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
394 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
395 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
396 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
397 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
398 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
399 | BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff) | ||
400 | 59 | ||
401 | #endif | ||
402 | .align PAGE_SIZE | 60 | .align PAGE_SIZE |
403 | 61 | ||
404 | /* This was the only reasonable way I could think of to properly align | 62 | /* This was the only reasonable way I could think of to properly align |
405 | * these page-table data structures. | 63 | * these page-table data structures. |
406 | */ | 64 | */ |
407 | .globl pg0, pg1, pg2, pg3 | ||
408 | .globl empty_bad_page | ||
409 | .globl empty_bad_page_table | ||
410 | .globl empty_zero_page | ||
411 | .globl swapper_pg_dir | 65 | .globl swapper_pg_dir |
412 | swapper_pg_dir: .skip PAGE_SIZE | 66 | swapper_pg_dir: .skip PAGE_SIZE |
413 | pg0: .skip PAGE_SIZE | 67 | .globl empty_zero_page |
414 | pg1: .skip PAGE_SIZE | ||
415 | pg2: .skip PAGE_SIZE | ||
416 | pg3: .skip PAGE_SIZE | ||
417 | empty_bad_page: .skip PAGE_SIZE | ||
418 | empty_bad_page_table: .skip PAGE_SIZE | ||
419 | empty_zero_page: .skip PAGE_SIZE | 68 | empty_zero_page: .skip PAGE_SIZE |
420 | 69 | ||
421 | .global root_flags | 70 | .global root_flags |
@@ -523,10 +172,10 @@ copy_prom_lvl14: | |||
523 | ldd [%g2 + 0x8], %g4 | 172 | ldd [%g2 + 0x8], %g4 |
524 | std %g4, [%g3 + 0x8] ! Copy proms handler | 173 | std %g4, [%g3 + 0x8] ! Copy proms handler |
525 | 174 | ||
526 | /* Must determine whether we are on a sun4c MMU, SRMMU, or SUN4/400 MUTANT | 175 | /* DON'T TOUCH %l0 thru %l5 in these remapping routines, |
527 | * MMU so we can remap ourselves properly. DON'T TOUCH %l0 thru %l5 in these | 176 | * we need their values afterwards! |
528 | * remapping routines, we need their values afterwards! | ||
529 | */ | 177 | */ |
178 | |||
530 | /* Now check whether we are already mapped, if we | 179 | /* Now check whether we are already mapped, if we |
531 | * are we can skip all this garbage coming up. | 180 | * are we can skip all this garbage coming up. |
532 | */ | 181 | */ |
@@ -535,26 +184,29 @@ copy_prom_done: | |||
535 | be go_to_highmem ! this will be a nop then | 184 | be go_to_highmem ! this will be a nop then |
536 | nop | 185 | nop |
537 | 186 | ||
538 | set LOAD_ADDR, %g6 | 187 | /* Validate that we are in fact running on an |
188 | * SRMMU based cpu. | ||
189 | */ | ||
190 | set 0x4000, %g6 | ||
539 | cmp %g7, %g6 | 191 | cmp %g7, %g6 |
540 | bne remap_not_a_sun4 ! This is not a Sun4 | 192 | bne not_a_sun4 |
541 | nop | 193 | nop |
542 | 194 | ||
543 | or %g0, 0x1, %g1 | 195 | halt_sun4_or_sun4c: |
544 | lduba [%g1] ASI_CONTROL, %g1 ! Only safe to try on Sun4. | 196 | ld [%g7 + 0x68], %o1 |
545 | subcc %g1, 0x24, %g0 ! Is this a mutant Sun4/400??? | 197 | set sun4c_notsup, %o0 |
546 | be sun4_mutant_remap ! Ugh, it is... | 198 | sub %o0, %l6, %o0 |
199 | call %o1 | ||
547 | nop | 200 | nop |
548 | 201 | ba halt_me | |
549 | b sun4_normal_remap ! regular sun4, 2 level mmu | ||
550 | nop | 202 | nop |
551 | 203 | ||
552 | remap_not_a_sun4: | 204 | not_a_sun4: |
553 | lda [%g0] ASI_M_MMUREGS, %g1 ! same as ASI_PTE on sun4c | 205 | lda [%g0] ASI_M_MMUREGS, %g1 |
554 | and %g1, 0x1, %g1 ! Test SRMMU Enable bit ;-) | 206 | andcc %g1, 1, %g0 |
555 | cmp %g1, 0x0 | 207 | be halt_sun4_or_sun4c |
556 | be sun4c_remap ! A sun4c MMU or normal Sun4 | ||
557 | nop | 208 | nop |
209 | |||
558 | srmmu_remap: | 210 | srmmu_remap: |
559 | /* First, check for a viking (TI) module. */ | 211 | /* First, check for a viking (TI) module. */ |
560 | set 0x40000000, %g2 | 212 | set 0x40000000, %g2 |
@@ -660,72 +312,6 @@ srmmu_nviking: | |||
660 | b go_to_highmem | 312 | b go_to_highmem |
661 | nop ! wheee.... | 313 | nop ! wheee.... |
662 | 314 | ||
663 | /* This remaps the kernel on Sun4/4xx machines | ||
664 | * that have the Sun Mutant Three Level MMU. | ||
665 | * It's like a platypus, Sun didn't have the | ||
666 | * SRMMU in conception so they kludged the three | ||
667 | * level logic in the regular Sun4 MMU probably. | ||
668 | * | ||
669 | * Basically, you take each entry in the top level | ||
670 | * directory that maps the low 3MB starting at | ||
671 | * address zero and put the mapping in the KERNBASE | ||
672 | * slots. These top level pgd's are called regmaps. | ||
673 | */ | ||
674 | sun4_mutant_remap: | ||
675 | or %g0, %g0, %g3 ! source base | ||
676 | sethi %hi(KERNBASE), %g4 ! destination base | ||
677 | or %g4, %lo(KERNBASE), %g4 | ||
678 | sethi %hi(0x300000), %g5 | ||
679 | or %g5, %lo(0x300000), %g5 ! upper bound 3MB | ||
680 | or %g0, 0x1, %l6 | ||
681 | sll %l6, 24, %l6 ! Regmap mapping size | ||
682 | add %g3, 0x2, %g3 ! Base magic | ||
683 | add %g4, 0x2, %g4 ! Base magic | ||
684 | |||
685 | /* Main remapping loop on Sun4-Mutant-MMU. | ||
686 | * "I am not an animal..." -Famous Mutant Person | ||
687 | */ | ||
688 | sun4_mutant_loop: | ||
689 | lduha [%g3] ASI_REGMAP, %g2 ! Get lower entry | ||
690 | stha %g2, [%g4] ASI_REGMAP ! Store in high entry | ||
691 | add %g4, %l6, %g4 ! Move up high memory ptr | ||
692 | subcc %g3, %g5, %g0 ! Reached our limit? | ||
693 | blu sun4_mutant_loop ! Nope, loop again | ||
694 | add %g3, %l6, %g3 ! delay, Move up low ptr | ||
695 | b go_to_highmem ! Jump to high memory. | ||
696 | nop | ||
697 | |||
698 | /* The following is for non-4/4xx sun4 MMU's. */ | ||
699 | sun4_normal_remap: | ||
700 | mov 0, %g3 ! source base | ||
701 | set KERNBASE, %g4 ! destination base | ||
702 | set 0x300000, %g5 ! upper bound 3MB | ||
703 | mov 1, %l6 | ||
704 | sll %l6, 18, %l6 ! sun4 mmu segmap size | ||
705 | sun4_normal_loop: | ||
706 | lduha [%g3] ASI_SEGMAP, %g6 ! load phys_seg | ||
707 | stha %g6, [%g4] ASI_SEGMAP ! stort new virt mapping | ||
708 | add %g3, %l6, %g3 ! increment source pointer | ||
709 | subcc %g3, %g5, %g0 ! reached limit? | ||
710 | blu sun4_normal_loop ! nope, loop again | ||
711 | add %g4, %l6, %g4 ! delay, increment dest ptr | ||
712 | b go_to_highmem | ||
713 | nop | ||
714 | |||
715 | /* The following works for Sun4c MMU's */ | ||
716 | sun4c_remap: | ||
717 | mov 0, %g3 ! source base | ||
718 | set KERNBASE, %g4 ! destination base | ||
719 | set 0x300000, %g5 ! upper bound 3MB | ||
720 | mov 1, %l6 | ||
721 | sll %l6, 18, %l6 ! sun4c mmu segmap size | ||
722 | sun4c_remap_loop: | ||
723 | lda [%g3] ASI_SEGMAP, %g6 ! load phys_seg | ||
724 | sta %g6, [%g4] ASI_SEGMAP ! store new virt mapping | ||
725 | add %g3, %l6, %g3 ! Increment source ptr | ||
726 | subcc %g3, %g5, %g0 ! Reached limit? | ||
727 | bl sun4c_remap_loop ! Nope, loop again | ||
728 | add %g4, %l6, %g4 ! delay, Increment dest ptr | ||
729 | 315 | ||
730 | /* Now do a non-relative jump so that PC is in high-memory */ | 316 | /* Now do a non-relative jump so that PC is in high-memory */ |
731 | go_to_highmem: | 317 | go_to_highmem: |
@@ -750,35 +336,12 @@ execute_in_high_mem: | |||
750 | sethi %hi(linux_dbvec), %g1 | 336 | sethi %hi(linux_dbvec), %g1 |
751 | st %o1, [%g1 + %lo(linux_dbvec)] | 337 | st %o1, [%g1 + %lo(linux_dbvec)] |
752 | 338 | ||
753 | ld [%o0 + 0x4], %o3 | ||
754 | and %o3, 0x3, %o5 ! get the version | ||
755 | |||
756 | cmp %o3, 0x2 ! a v2 prom? | ||
757 | be found_version | ||
758 | nop | ||
759 | |||
760 | /* paul@sfe.com.au */ | ||
761 | cmp %o3, 0x3 ! a v3 prom? | ||
762 | be found_version | ||
763 | nop | ||
764 | |||
765 | /* Old sun4's pass our load address into %o0 instead of the prom | ||
766 | * pointer. On sun4's you have to hard code the romvec pointer into | ||
767 | * your code. Sun probably still does that because they don't even | ||
768 | * trust their own "OpenBoot" specifications. | ||
769 | */ | ||
770 | set LOAD_ADDR, %g6 | ||
771 | cmp %o0, %g6 ! an old sun4? | ||
772 | be sun4_init | ||
773 | nop | ||
774 | |||
775 | found_version: | ||
776 | /* Get the machine type via the mysterious romvec node operations. */ | 339 | /* Get the machine type via the mysterious romvec node operations. */ |
777 | 340 | ||
778 | add %g7, 0x1c, %l1 | 341 | add %g7, 0x1c, %l1 |
779 | ld [%l1], %l0 | 342 | ld [%l1], %l0 |
780 | ld [%l0], %l0 | 343 | ld [%l0], %l0 |
781 | call %l0 | 344 | call %l0 |
782 | or %g0, %g0, %o0 ! next_node(0) = first_node | 345 | or %g0, %g0, %o0 ! next_node(0) = first_node |
783 | or %o0, %g0, %g6 | 346 | or %o0, %g0, %g6 |
784 | 347 | ||
@@ -786,28 +349,13 @@ found_version: | |||
786 | or %o1, %lo(cputypvar), %o1 | 349 | or %o1, %lo(cputypvar), %o1 |
787 | sethi %hi(cputypval), %o2 ! information, the string | 350 | sethi %hi(cputypval), %o2 ! information, the string |
788 | or %o2, %lo(cputypval), %o2 | 351 | or %o2, %lo(cputypval), %o2 |
789 | ld [%l1], %l0 ! 'compatibility' tells | 352 | ld [%l1], %l0 ! 'compatible' tells |
790 | ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where | 353 | ld [%l0 + 0xc], %l0 ! that we want 'sun4x' where |
791 | call %l0 ! x is one of '', 'c', 'm', | 354 | call %l0 ! x is one of 'm', 'd' or 'e'. |
792 | nop ! 'd' or 'e'. %o2 holds pointer | 355 | nop ! %o2 holds pointer |
793 | ! to a buf where above string | 356 | ! to a buf where above string |
794 | ! will get stored by the prom. | 357 | ! will get stored by the prom. |
795 | 358 | ||
796 | subcc %o0, %g0, %g0 | ||
797 | bpos got_prop ! Got the property | ||
798 | nop | ||
799 | |||
800 | or %g6, %g0, %o0 | ||
801 | sethi %hi(cputypvar_sun4m), %o1 | ||
802 | or %o1, %lo(cputypvar_sun4m), %o1 | ||
803 | sethi %hi(cputypval), %o2 | ||
804 | or %o2, %lo(cputypval), %o2 | ||
805 | ld [%l1], %l0 | ||
806 | ld [%l0 + 0xc], %l0 | ||
807 | call %l0 | ||
808 | nop | ||
809 | |||
810 | got_prop: | ||
811 | #ifdef CONFIG_SPARC_LEON | 359 | #ifdef CONFIG_SPARC_LEON |
812 | /* no cpu-type check is needed, it is a SPARC-LEON */ | 360 | /* no cpu-type check is needed, it is a SPARC-LEON */ |
813 | 361 | ||
@@ -826,45 +374,29 @@ got_prop: | |||
826 | /* Update boot_cpu_id only on boot cpu */ | 374 | /* Update boot_cpu_id only on boot cpu */ |
827 | stub %g1, [%g2 + %lo(boot_cpu_id)] | 375 | stub %g1, [%g2 + %lo(boot_cpu_id)] |
828 | 376 | ||
829 | ba sun4c_continue_boot | 377 | ba continue_boot |
830 | nop | 378 | nop |
831 | #endif | 379 | #endif |
380 | |||
381 | /* Check to cputype. We may be booted on a sun4u (64 bit box), | ||
382 | * and sun4d needs special treatment. | ||
383 | */ | ||
384 | |||
832 | set cputypval, %o2 | 385 | set cputypval, %o2 |
833 | ldub [%o2 + 0x4], %l1 | 386 | ldub [%o2 + 0x4], %l1 |
834 | 387 | ||
835 | cmp %l1, ' ' | 388 | cmp %l1, 'm' |
836 | be 1f | 389 | be sun4m_init |
837 | cmp %l1, 'c' | ||
838 | be 1f | ||
839 | cmp %l1, 'm' | ||
840 | be 1f | ||
841 | cmp %l1, 's' | 390 | cmp %l1, 's' |
842 | be 1f | 391 | be sun4m_init |
843 | cmp %l1, 'd' | 392 | cmp %l1, 'd' |
844 | be 1f | 393 | be sun4d_init |
845 | cmp %l1, 'e' | 394 | cmp %l1, 'e' |
846 | be no_sun4e_here ! Could be a sun4e. | 395 | be no_sun4e_here ! Could be a sun4e. |
847 | nop | 396 | nop |
848 | b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :)) | 397 | b no_sun4u_here ! AIEEE, a V9 sun4u... Get our BIG BROTHER kernel :)) |
849 | nop | 398 | nop |
850 | 399 | ||
851 | 1: set cputypval, %l1 | ||
852 | ldub [%l1 + 0x4], %l1 | ||
853 | cmp %l1, 'm' ! Test for sun4d, sun4e ? | ||
854 | be sun4m_init | ||
855 | cmp %l1, 's' ! Treat sun4s as sun4m | ||
856 | be sun4m_init | ||
857 | cmp %l1, 'd' ! Let us see how the beast will die | ||
858 | be sun4d_init | ||
859 | nop | ||
860 | |||
861 | /* Jump into mmu context zero. */ | ||
862 | set AC_CONTEXT, %g1 | ||
863 | stba %g0, [%g1] ASI_CONTROL | ||
864 | |||
865 | b sun4c_continue_boot | ||
866 | nop | ||
867 | |||
868 | /* CPUID in bootbus can be found at PA 0xff0140000 */ | 400 | /* CPUID in bootbus can be found at PA 0xff0140000 */ |
869 | #define SUN4D_BOOTBUS_CPUID 0xf0140000 | 401 | #define SUN4D_BOOTBUS_CPUID 0xf0140000 |
870 | 402 | ||
@@ -892,66 +424,6 @@ sun4d_init: | |||
892 | /* Fall through to sun4m_init */ | 424 | /* Fall through to sun4m_init */ |
893 | 425 | ||
894 | sun4m_init: | 426 | sun4m_init: |
895 | /* XXX Fucking Cypress... */ | ||
896 | lda [%g0] ASI_M_MMUREGS, %g5 | ||
897 | srl %g5, 28, %g4 | ||
898 | |||
899 | cmp %g4, 1 | ||
900 | bne 1f | ||
901 | srl %g5, 24, %g4 | ||
902 | |||
903 | and %g4, 0xf, %g4 | ||
904 | cmp %g4, 7 /* This would be a HyperSparc. */ | ||
905 | |||
906 | bne 2f | ||
907 | nop | ||
908 | |||
909 | 1: | ||
910 | |||
911 | #define PATCH_IT(dst, src) \ | ||
912 | set (dst), %g5; \ | ||
913 | set (src), %g4; \ | ||
914 | ld [%g4], %g3; \ | ||
915 | st %g3, [%g5]; \ | ||
916 | ld [%g4+0x4], %g3; \ | ||
917 | st %g3, [%g5+0x4]; | ||
918 | |||
919 | /* Signed multiply. */ | ||
920 | PATCH_IT(.mul, .mul_patch) | ||
921 | PATCH_IT(.mul+0x08, .mul_patch+0x08) | ||
922 | |||
923 | /* Signed remainder. */ | ||
924 | PATCH_IT(.rem, .rem_patch) | ||
925 | PATCH_IT(.rem+0x08, .rem_patch+0x08) | ||
926 | PATCH_IT(.rem+0x10, .rem_patch+0x10) | ||
927 | PATCH_IT(.rem+0x18, .rem_patch+0x18) | ||
928 | PATCH_IT(.rem+0x20, .rem_patch+0x20) | ||
929 | PATCH_IT(.rem+0x28, .rem_patch+0x28) | ||
930 | |||
931 | /* Signed division. */ | ||
932 | PATCH_IT(.div, .div_patch) | ||
933 | PATCH_IT(.div+0x08, .div_patch+0x08) | ||
934 | PATCH_IT(.div+0x10, .div_patch+0x10) | ||
935 | PATCH_IT(.div+0x18, .div_patch+0x18) | ||
936 | PATCH_IT(.div+0x20, .div_patch+0x20) | ||
937 | |||
938 | /* Unsigned multiply. */ | ||
939 | PATCH_IT(.umul, .umul_patch) | ||
940 | PATCH_IT(.umul+0x08, .umul_patch+0x08) | ||
941 | |||
942 | /* Unsigned remainder. */ | ||
943 | PATCH_IT(.urem, .urem_patch) | ||
944 | PATCH_IT(.urem+0x08, .urem_patch+0x08) | ||
945 | PATCH_IT(.urem+0x10, .urem_patch+0x10) | ||
946 | PATCH_IT(.urem+0x18, .urem_patch+0x18) | ||
947 | |||
948 | /* Unsigned division. */ | ||
949 | PATCH_IT(.udiv, .udiv_patch) | ||
950 | PATCH_IT(.udiv+0x08, .udiv_patch+0x08) | ||
951 | PATCH_IT(.udiv+0x10, .udiv_patch+0x10) | ||
952 | |||
953 | #undef PATCH_IT | ||
954 | |||
955 | /* Ok, the PROM could have done funny things and apple cider could still | 427 | /* Ok, the PROM could have done funny things and apple cider could still |
956 | * be sitting in the fault status/address registers. Read them all to | 428 | * be sitting in the fault status/address registers. Read them all to |
957 | * clear them so we don't get magic faults later on. | 429 | * clear them so we don't get magic faults later on. |
@@ -962,7 +434,7 @@ sun4m_init: | |||
962 | srl %o1, 28, %o1 ! Get a type of the CPU | 434 | srl %o1, 28, %o1 ! Get a type of the CPU |
963 | 435 | ||
964 | subcc %o1, 4, %g0 ! TI: Viking or MicroSPARC | 436 | subcc %o1, 4, %g0 ! TI: Viking or MicroSPARC |
965 | be sun4c_continue_boot | 437 | be continue_boot |
966 | nop | 438 | nop |
967 | 439 | ||
968 | set AC_M_SFSR, %o0 | 440 | set AC_M_SFSR, %o0 |
@@ -972,7 +444,7 @@ sun4m_init: | |||
972 | 444 | ||
973 | /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */ | 445 | /* Fujitsu MicroSPARC-II has no asynchronous flavors of FARs */ |
974 | subcc %o1, 0, %g0 | 446 | subcc %o1, 0, %g0 |
975 | be sun4c_continue_boot | 447 | be continue_boot |
976 | nop | 448 | nop |
977 | 449 | ||
978 | set AC_M_AFSR, %o0 | 450 | set AC_M_AFSR, %o0 |
@@ -982,8 +454,7 @@ sun4m_init: | |||
982 | nop | 454 | nop |
983 | 455 | ||
984 | 456 | ||
985 | sun4c_continue_boot: | 457 | continue_boot: |
986 | |||
987 | 458 | ||
988 | /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's | 459 | /* Aieee, now set PC and nPC, enable traps, give ourselves a stack and it's |
989 | * show-time! | 460 | * show-time! |
@@ -1026,10 +497,7 @@ sun4c_continue_boot: | |||
1026 | mov %g0, %g3 | 497 | mov %g0, %g3 |
1027 | stub %g3, [%g2 + %lo(boot_cpu_id)] | 498 | stub %g3, [%g2 + %lo(boot_cpu_id)] |
1028 | 499 | ||
1029 | 1: /* boot_cpu_id set. calculate boot_cpu_id4 = boot_cpu_id*4 */ | 500 | 1: sll %g3, 2, %g3 |
1030 | sll %g3, 2, %g3 | ||
1031 | sethi %hi(boot_cpu_id4), %g2 | ||
1032 | stub %g3, [%g2 + %lo(boot_cpu_id4)] | ||
1033 | 501 | ||
1034 | /* Initialize the uwinmask value for init task just in case. | 502 | /* Initialize the uwinmask value for init task just in case. |
1035 | * But first make current_set[boot_cpu_id] point to something useful. | 503 | * But first make current_set[boot_cpu_id] point to something useful. |
@@ -1165,19 +633,6 @@ sun4c_continue_boot: | |||
1165 | call halt_me | 633 | call halt_me |
1166 | nop | 634 | nop |
1167 | 635 | ||
1168 | sun4_init: | ||
1169 | sethi %hi(SUN4_PROM_VECTOR+0x84), %o1 | ||
1170 | ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1 | ||
1171 | set sun4_notsup, %o0 | ||
1172 | call %o1 /* printf */ | ||
1173 | nop | ||
1174 | sethi %hi(SUN4_PROM_VECTOR+0xc4), %o1 | ||
1175 | ld [%o1 + %lo(SUN4_PROM_VECTOR+0xc4)], %o1 | ||
1176 | call %o1 /* exittomon */ | ||
1177 | nop | ||
1178 | 1: ba 1b ! Cannot exit into KMON | ||
1179 | nop | ||
1180 | |||
1181 | no_sun4e_here: | 636 | no_sun4e_here: |
1182 | ld [%g7 + 0x68], %o1 | 637 | ld [%g7 + 0x68], %o1 |
1183 | set sun4e_notsup, %o0 | 638 | set sun4e_notsup, %o0 |
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S index 0d810c2f1d00..b42ddbf9651e 100644 --- a/arch/sparc/kernel/head_64.S +++ b/arch/sparc/kernel/head_64.S | |||
@@ -906,7 +906,7 @@ swapper_4m_tsb: | |||
906 | * error and will instead write junk into the relocation and | 906 | * error and will instead write junk into the relocation and |
907 | * you'll have an unbootable kernel. | 907 | * you'll have an unbootable kernel. |
908 | */ | 908 | */ |
909 | #include "ttable.S" | 909 | #include "ttable_64.S" |
910 | 910 | ||
911 | ! 0x0000000000428000 | 911 | ! 0x0000000000428000 |
912 | 912 | ||
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c index 9167db40720e..6bd75012109d 100644 --- a/arch/sparc/kernel/idprom.c +++ b/arch/sparc/kernel/idprom.c | |||
@@ -25,22 +25,9 @@ static struct idprom idprom_buffer; | |||
25 | * of the Sparc CPU and have a meaningful IDPROM machtype value that we | 25 | * of the Sparc CPU and have a meaningful IDPROM machtype value that we |
26 | * know about. See asm-sparc/machines.h for empirical constants. | 26 | * know about. See asm-sparc/machines.h for empirical constants. |
27 | */ | 27 | */ |
28 | static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = { | 28 | static struct Sun_Machine_Models Sun_Machines[] = { |
29 | /* First, Sun4's */ | 29 | /* First, Leon */ |
30 | { .name = "Sun 4/100 Series", .id_machtype = (SM_SUN4 | SM_4_110) }, | ||
31 | { .name = "Sun 4/200 Series", .id_machtype = (SM_SUN4 | SM_4_260) }, | ||
32 | { .name = "Sun 4/300 Series", .id_machtype = (SM_SUN4 | SM_4_330) }, | ||
33 | { .name = "Sun 4/400 Series", .id_machtype = (SM_SUN4 | SM_4_470) }, | ||
34 | /* Now Leon */ | ||
35 | { .name = "Leon3 System-on-a-Chip", .id_machtype = (M_LEON | M_LEON3_SOC) }, | 30 | { .name = "Leon3 System-on-a-Chip", .id_machtype = (M_LEON | M_LEON3_SOC) }, |
36 | /* Now, Sun4c's */ | ||
37 | { .name = "Sun4c SparcStation 1", .id_machtype = (SM_SUN4C | SM_4C_SS1) }, | ||
38 | { .name = "Sun4c SparcStation IPC", .id_machtype = (SM_SUN4C | SM_4C_IPC) }, | ||
39 | { .name = "Sun4c SparcStation 1+", .id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) }, | ||
40 | { .name = "Sun4c SparcStation SLC", .id_machtype = (SM_SUN4C | SM_4C_SLC) }, | ||
41 | { .name = "Sun4c SparcStation 2", .id_machtype = (SM_SUN4C | SM_4C_SS2) }, | ||
42 | { .name = "Sun4c SparcStation ELC", .id_machtype = (SM_SUN4C | SM_4C_ELC) }, | ||
43 | { .name = "Sun4c SparcStation IPX", .id_machtype = (SM_SUN4C | SM_4C_IPX) }, | ||
44 | /* Finally, early Sun4m's */ | 31 | /* Finally, early Sun4m's */ |
45 | { .name = "Sun4m SparcSystem600", .id_machtype = (SM_SUN4M | SM_4M_SS60) }, | 32 | { .name = "Sun4m SparcSystem600", .id_machtype = (SM_SUN4M | SM_4M_SS60) }, |
46 | { .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) }, | 33 | { .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) }, |
@@ -53,7 +40,7 @@ static void __init display_system_type(unsigned char machtype) | |||
53 | char sysname[128]; | 40 | char sysname[128]; |
54 | register int i; | 41 | register int i; |
55 | 42 | ||
56 | for (i = 0; i < NUM_SUN_MACHINES; i++) { | 43 | for (i = 0; i < ARRAY_SIZE(Sun_Machines); i++) { |
57 | if (Sun_Machines[i].id_machtype == machtype) { | 44 | if (Sun_Machines[i].id_machtype == machtype) { |
58 | if (machtype != (SM_SUN4M_OBP | 0x00) || | 45 | if (machtype != (SM_SUN4M_OBP | 0x00) || |
59 | prom_getproperty(prom_root_node, "banner-name", | 46 | prom_getproperty(prom_root_node, "banner-name", |
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c deleted file mode 100644 index 35f141a9f506..000000000000 --- a/arch/sparc/kernel/init_task.c +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | #include <linux/mm.h> | ||
2 | #include <linux/fs.h> | ||
3 | #include <linux/module.h> | ||
4 | #include <linux/sched.h> | ||
5 | #include <linux/init_task.h> | ||
6 | #include <linux/mqueue.h> | ||
7 | |||
8 | #include <asm/pgtable.h> | ||
9 | #include <asm/uaccess.h> | ||
10 | |||
11 | static struct signal_struct init_signals = INIT_SIGNALS(init_signals); | ||
12 | static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); | ||
13 | struct task_struct init_task = INIT_TASK(init_task); | ||
14 | EXPORT_SYMBOL(init_task); | ||
15 | |||
16 | /* .text section in head.S is aligned at 8k boundary and this gets linked | ||
17 | * right after that so that the init_thread_union is aligned properly as well. | ||
18 | * If this is not aligned on a 8k boundary, then you should change code | ||
19 | * in etrap.S which assumes it. | ||
20 | */ | ||
21 | union thread_union init_thread_union __init_task_data = | ||
22 | { INIT_THREAD_INFO(init_task) }; | ||
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 21bd73943f7f..a2846f5e32d8 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c | |||
@@ -50,6 +50,8 @@ | |||
50 | #include <asm/io-unit.h> | 50 | #include <asm/io-unit.h> |
51 | #include <asm/leon.h> | 51 | #include <asm/leon.h> |
52 | 52 | ||
53 | const struct sparc32_dma_ops *sparc32_dma_ops; | ||
54 | |||
53 | /* This function must make sure that caches and memory are coherent after DMA | 55 | /* This function must make sure that caches and memory are coherent after DMA |
54 | * On LEON systems without cache snooping it flushes the entire D-CACHE. | 56 | * On LEON systems without cache snooping it flushes the entire D-CACHE. |
55 | */ | 57 | */ |
@@ -229,7 +231,7 @@ _sparc_ioremap(struct resource *res, u32 bus, u32 pa, int sz) | |||
229 | } | 231 | } |
230 | 232 | ||
231 | pa &= PAGE_MASK; | 233 | pa &= PAGE_MASK; |
232 | sparc_mapiorange(bus, pa, res->start, resource_size(res)); | 234 | srmmu_mapiorange(bus, pa, res->start, resource_size(res)); |
233 | 235 | ||
234 | return (void __iomem *)(unsigned long)(res->start + offset); | 236 | return (void __iomem *)(unsigned long)(res->start + offset); |
235 | } | 237 | } |
@@ -243,7 +245,7 @@ static void _sparc_free_io(struct resource *res) | |||
243 | 245 | ||
244 | plen = resource_size(res); | 246 | plen = resource_size(res); |
245 | BUG_ON((plen & (PAGE_SIZE-1)) != 0); | 247 | BUG_ON((plen & (PAGE_SIZE-1)) != 0); |
246 | sparc_unmapiorange(res->start, plen); | 248 | srmmu_unmapiorange(res->start, plen); |
247 | release_resource(res); | 249 | release_resource(res); |
248 | } | 250 | } |
249 | 251 | ||
@@ -292,13 +294,13 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len, | |||
292 | goto err_nova; | 294 | goto err_nova; |
293 | } | 295 | } |
294 | 296 | ||
295 | // XXX The mmu_map_dma_area does this for us below, see comments. | 297 | // XXX The sbus_map_dma_area does this for us below, see comments. |
296 | // sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); | 298 | // srmmu_mapiorange(0, virt_to_phys(va), res->start, len_total); |
297 | /* | 299 | /* |
298 | * XXX That's where sdev would be used. Currently we load | 300 | * XXX That's where sdev would be used. Currently we load |
299 | * all iommu tables with the same translations. | 301 | * all iommu tables with the same translations. |
300 | */ | 302 | */ |
301 | if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) | 303 | if (sbus_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) |
302 | goto err_noiommu; | 304 | goto err_noiommu; |
303 | 305 | ||
304 | res->name = op->dev.of_node->name; | 306 | res->name = op->dev.of_node->name; |
@@ -343,7 +345,7 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p, | |||
343 | kfree(res); | 345 | kfree(res); |
344 | 346 | ||
345 | pgv = virt_to_page(p); | 347 | pgv = virt_to_page(p); |
346 | mmu_unmap_dma_area(dev, ba, n); | 348 | sbus_unmap_dma_area(dev, ba, n); |
347 | 349 | ||
348 | __free_pages(pgv, get_order(n)); | 350 | __free_pages(pgv, get_order(n)); |
349 | } | 351 | } |
@@ -381,11 +383,6 @@ static int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, | |||
381 | enum dma_data_direction dir, struct dma_attrs *attrs) | 383 | enum dma_data_direction dir, struct dma_attrs *attrs) |
382 | { | 384 | { |
383 | mmu_get_scsi_sgl(dev, sg, n); | 385 | mmu_get_scsi_sgl(dev, sg, n); |
384 | |||
385 | /* | ||
386 | * XXX sparc64 can return a partial length here. sun4c should do this | ||
387 | * but it currently panics if it can't fulfill the request - Anton | ||
388 | */ | ||
389 | return n; | 386 | return n; |
390 | } | 387 | } |
391 | 388 | ||
@@ -469,7 +466,7 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len, | |||
469 | printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total); | 466 | printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total); |
470 | goto err_nova; | 467 | goto err_nova; |
471 | } | 468 | } |
472 | sparc_mapiorange(0, virt_to_phys(va), res->start, len_total); | 469 | srmmu_mapiorange(0, virt_to_phys(va), res->start, len_total); |
473 | 470 | ||
474 | *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ | 471 | *pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */ |
475 | return (void *) res->start; | 472 | return (void *) res->start; |
@@ -514,7 +511,7 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p, | |||
514 | } | 511 | } |
515 | 512 | ||
516 | dma_make_coherent(ba, n); | 513 | dma_make_coherent(ba, n); |
517 | sparc_unmapiorange((unsigned long)p, n); | 514 | srmmu_unmapiorange((unsigned long)p, n); |
518 | 515 | ||
519 | release_resource(res); | 516 | release_resource(res); |
520 | kfree(res); | 517 | kfree(res); |
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index 5a021dd2f854..b66b6aad1d6d 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h | |||
@@ -1,6 +1,5 @@ | |||
1 | #include <linux/platform_device.h> | 1 | #include <linux/platform_device.h> |
2 | 2 | ||
3 | #include <asm/btfixup.h> | ||
4 | #include <asm/cpu_type.h> | 3 | #include <asm/cpu_type.h> |
5 | 4 | ||
6 | struct irq_bucket { | 5 | struct irq_bucket { |
@@ -10,6 +9,9 @@ struct irq_bucket { | |||
10 | unsigned int pil; | 9 | unsigned int pil; |
11 | }; | 10 | }; |
12 | 11 | ||
12 | #define SUN4M_HARD_INT(x) (0x000000001 << (x)) | ||
13 | #define SUN4M_SOFT_INT(x) (0x000010000 << (x)) | ||
14 | |||
13 | #define SUN4D_MAX_BOARD 10 | 15 | #define SUN4D_MAX_BOARD 10 |
14 | #define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5) | 16 | #define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5) |
15 | 17 | ||
@@ -41,52 +43,46 @@ struct sun4m_irq_global { | |||
41 | extern struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; | 43 | extern struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; |
42 | extern struct sun4m_irq_global __iomem *sun4m_irq_global; | 44 | extern struct sun4m_irq_global __iomem *sun4m_irq_global; |
43 | 45 | ||
46 | /* The following definitions describe the individual platform features: */ | ||
47 | #define FEAT_L10_CLOCKSOURCE (1 << 0) /* L10 timer is used as a clocksource */ | ||
48 | #define FEAT_L10_CLOCKEVENT (1 << 1) /* L10 timer is used as a clockevent */ | ||
49 | #define FEAT_L14_ONESHOT (1 << 2) /* L14 timer clockevent can oneshot */ | ||
50 | |||
44 | /* | 51 | /* |
45 | * Platform specific irq configuration | 52 | * Platform specific configuration |
46 | * The individual platforms assign their platform | 53 | * The individual platforms assign their platform |
47 | * specifics in their init functions. | 54 | * specifics in their init functions. |
48 | */ | 55 | */ |
49 | struct sparc_irq_config { | 56 | struct sparc_config { |
50 | void (*init_timers)(irq_handler_t); | 57 | void (*init_timers)(void); |
51 | unsigned int (*build_device_irq)(struct platform_device *op, | 58 | unsigned int (*build_device_irq)(struct platform_device *op, |
52 | unsigned int real_irq); | 59 | unsigned int real_irq); |
60 | |||
61 | /* generic clockevent features - see FEAT_* above */ | ||
62 | int features; | ||
63 | |||
64 | /* clock rate used for clock event timer */ | ||
65 | int clock_rate; | ||
66 | |||
67 | /* one period for clock source timer */ | ||
68 | unsigned int cs_period; | ||
69 | |||
70 | /* function to obtain offsett for cs period */ | ||
71 | unsigned int (*get_cycles_offset)(void); | ||
72 | |||
73 | void (*clear_clock_irq)(void); | ||
74 | void (*load_profile_irq)(int cpu, unsigned int limit); | ||
53 | }; | 75 | }; |
54 | extern struct sparc_irq_config sparc_irq_config; | 76 | extern struct sparc_config sparc_config; |
55 | 77 | ||
56 | unsigned int irq_alloc(unsigned int real_irq, unsigned int pil); | 78 | unsigned int irq_alloc(unsigned int real_irq, unsigned int pil); |
57 | void irq_link(unsigned int irq); | 79 | void irq_link(unsigned int irq); |
58 | void irq_unlink(unsigned int irq); | 80 | void irq_unlink(unsigned int irq); |
59 | void handler_irq(unsigned int pil, struct pt_regs *regs); | 81 | void handler_irq(unsigned int pil, struct pt_regs *regs); |
60 | 82 | ||
61 | /* Dave Redman (djhr@tadpole.co.uk) | 83 | unsigned long leon_get_irqmask(unsigned int irq); |
62 | * changed these to function pointers.. it saves cycles and will allow | ||
63 | * the irq dependencies to be split into different files at a later date | ||
64 | * sun4c_irq.c, sun4m_irq.c etc so we could reduce the kernel size. | ||
65 | * Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
66 | * Changed these to btfixup entities... It saves cycles :) | ||
67 | */ | ||
68 | |||
69 | BTFIXUPDEF_CALL(void, clear_clock_irq, void) | ||
70 | BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) | ||
71 | |||
72 | static inline void clear_clock_irq(void) | ||
73 | { | ||
74 | BTFIXUP_CALL(clear_clock_irq)(); | ||
75 | } | ||
76 | |||
77 | static inline void load_profile_irq(int cpu, int limit) | ||
78 | { | ||
79 | BTFIXUP_CALL(load_profile_irq)(cpu, limit); | ||
80 | } | ||
81 | 84 | ||
82 | #ifdef CONFIG_SMP | 85 | #ifdef CONFIG_SMP |
83 | BTFIXUPDEF_CALL(void, set_cpu_int, int, int) | ||
84 | BTFIXUPDEF_CALL(void, clear_cpu_int, int, int) | ||
85 | BTFIXUPDEF_CALL(void, set_irq_udt, int) | ||
86 | |||
87 | #define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level) | ||
88 | #define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level) | ||
89 | #define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu) | ||
90 | 86 | ||
91 | /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ | 87 | /* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */ |
92 | #define SUN4D_IPI_IRQ 13 | 88 | #define SUN4D_IPI_IRQ 13 |
diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c index b2668afd1c34..ae04914f7774 100644 --- a/arch/sparc/kernel/irq_32.c +++ b/arch/sparc/kernel/irq_32.c | |||
@@ -23,16 +23,8 @@ | |||
23 | #include "kernel.h" | 23 | #include "kernel.h" |
24 | #include "irq.h" | 24 | #include "irq.h" |
25 | 25 | ||
26 | #ifdef CONFIG_SMP | ||
27 | #define SMP_NOP2 "nop; nop;\n\t" | ||
28 | #define SMP_NOP3 "nop; nop; nop;\n\t" | ||
29 | #else | ||
30 | #define SMP_NOP2 | ||
31 | #define SMP_NOP3 | ||
32 | #endif /* SMP */ | ||
33 | |||
34 | /* platform specific irq setup */ | 26 | /* platform specific irq setup */ |
35 | struct sparc_irq_config sparc_irq_config; | 27 | struct sparc_config sparc_config; |
36 | 28 | ||
37 | unsigned long arch_local_irq_save(void) | 29 | unsigned long arch_local_irq_save(void) |
38 | { | 30 | { |
@@ -41,7 +33,6 @@ unsigned long arch_local_irq_save(void) | |||
41 | 33 | ||
42 | __asm__ __volatile__( | 34 | __asm__ __volatile__( |
43 | "rd %%psr, %0\n\t" | 35 | "rd %%psr, %0\n\t" |
44 | SMP_NOP3 /* Sun4m + Cypress + SMP bug */ | ||
45 | "or %0, %2, %1\n\t" | 36 | "or %0, %2, %1\n\t" |
46 | "wr %1, 0, %%psr\n\t" | 37 | "wr %1, 0, %%psr\n\t" |
47 | "nop; nop; nop\n" | 38 | "nop; nop; nop\n" |
@@ -59,7 +50,6 @@ void arch_local_irq_enable(void) | |||
59 | 50 | ||
60 | __asm__ __volatile__( | 51 | __asm__ __volatile__( |
61 | "rd %%psr, %0\n\t" | 52 | "rd %%psr, %0\n\t" |
62 | SMP_NOP3 /* Sun4m + Cypress + SMP bug */ | ||
63 | "andn %0, %1, %0\n\t" | 53 | "andn %0, %1, %0\n\t" |
64 | "wr %0, 0, %%psr\n\t" | 54 | "wr %0, 0, %%psr\n\t" |
65 | "nop; nop; nop\n" | 55 | "nop; nop; nop\n" |
@@ -76,7 +66,6 @@ void arch_local_irq_restore(unsigned long old_psr) | |||
76 | __asm__ __volatile__( | 66 | __asm__ __volatile__( |
77 | "rd %%psr, %0\n\t" | 67 | "rd %%psr, %0\n\t" |
78 | "and %2, %1, %2\n\t" | 68 | "and %2, %1, %2\n\t" |
79 | SMP_NOP2 /* Sun4m + Cypress + SMP bug */ | ||
80 | "andn %0, %1, %0\n\t" | 69 | "andn %0, %1, %0\n\t" |
81 | "wr %0, %2, %%psr\n\t" | 70 | "wr %0, %2, %%psr\n\t" |
82 | "nop; nop; nop\n" | 71 | "nop; nop; nop\n" |
@@ -346,11 +335,6 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
346 | void __init init_IRQ(void) | 335 | void __init init_IRQ(void) |
347 | { | 336 | { |
348 | switch (sparc_cpu_model) { | 337 | switch (sparc_cpu_model) { |
349 | case sun4c: | ||
350 | case sun4: | ||
351 | sun4c_init_IRQ(); | ||
352 | break; | ||
353 | |||
354 | case sun4m: | 338 | case sun4m: |
355 | pcic_probe(); | 339 | pcic_probe(); |
356 | if (pcic_present()) | 340 | if (pcic_present()) |
@@ -371,6 +355,5 @@ void __init init_IRQ(void) | |||
371 | prom_printf("Cannot initialize IRQs on this Sun machine..."); | 355 | prom_printf("Cannot initialize IRQs on this Sun machine..."); |
372 | break; | 356 | break; |
373 | } | 357 | } |
374 | btfixup(); | ||
375 | } | 358 | } |
376 | 359 | ||
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index dff2c3d7d370..9bcbbe2c4e7e 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
@@ -799,7 +799,7 @@ static void kill_prom_timer(void) | |||
799 | prom_limit0 = prom_timers->limit0; | 799 | prom_limit0 = prom_timers->limit0; |
800 | prom_limit1 = prom_timers->limit1; | 800 | prom_limit1 = prom_timers->limit1; |
801 | 801 | ||
802 | /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14. | 802 | /* Just as in sun4c PROM uses timer which ticks at IRQ 14. |
803 | * We turn both off here just to be paranoid. | 803 | * We turn both off here just to be paranoid. |
804 | */ | 804 | */ |
805 | prom_timers->limit0 = 0; | 805 | prom_timers->limit0 = 0; |
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h index fd6c36b1df74..a86372d34587 100644 --- a/arch/sparc/kernel/kernel.h +++ b/arch/sparc/kernel/kernel.h | |||
@@ -32,9 +32,6 @@ extern void cpu_probe(void); | |||
32 | /* traps_32.c */ | 32 | /* traps_32.c */ |
33 | extern void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, | 33 | extern void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, |
34 | unsigned long npc, unsigned long psr); | 34 | unsigned long npc, unsigned long psr); |
35 | /* muldiv.c */ | ||
36 | extern int do_user_muldiv (struct pt_regs *, unsigned long); | ||
37 | |||
38 | /* irq_32.c */ | 35 | /* irq_32.c */ |
39 | extern struct irqaction static_irqaction[]; | 36 | extern struct irqaction static_irqaction[]; |
40 | extern int static_irq_count; | 37 | extern int static_irq_count; |
@@ -43,12 +40,7 @@ extern spinlock_t irq_action_lock; | |||
43 | extern void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs); | 40 | extern void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs); |
44 | extern void init_IRQ(void); | 41 | extern void init_IRQ(void); |
45 | 42 | ||
46 | /* sun4c_irq.c */ | ||
47 | extern void sun4c_init_IRQ(void); | ||
48 | |||
49 | /* sun4m_irq.c */ | 43 | /* sun4m_irq.c */ |
50 | extern unsigned int lvl14_resolution; | ||
51 | |||
52 | extern void sun4m_init_IRQ(void); | 44 | extern void sun4m_init_IRQ(void); |
53 | extern void sun4m_unmask_profile_irq(void); | 45 | extern void sun4m_unmask_profile_irq(void); |
54 | extern void sun4m_clear_profile_irq(int cpu); | 46 | extern void sun4m_clear_profile_irq(int cpu); |
@@ -85,8 +77,6 @@ extern unsigned int patchme_maybe_smp_msg[]; | |||
85 | extern void floppy_hardint(void); | 77 | extern void floppy_hardint(void); |
86 | 78 | ||
87 | /* trampoline_32.S */ | 79 | /* trampoline_32.S */ |
88 | extern int __smp4m_processor_id(void); | ||
89 | extern int __smp4d_processor_id(void); | ||
90 | extern unsigned long sun4m_cpu_startup; | 80 | extern unsigned long sun4m_cpu_startup; |
91 | extern unsigned long sun4d_cpu_startup; | 81 | extern unsigned long sun4d_cpu_startup; |
92 | 82 | ||
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 35e43673c453..77c1b916e4dd 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <linux/of_platform.h> | 10 | #include <linux/of_platform.h> |
11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
12 | #include <linux/of_device.h> | 12 | #include <linux/of_device.h> |
13 | #include <linux/clocksource.h> | ||
14 | #include <linux/clockchips.h> | ||
13 | 15 | ||
14 | #include <asm/oplib.h> | 16 | #include <asm/oplib.h> |
15 | #include <asm/timer.h> | 17 | #include <asm/timer.h> |
@@ -84,7 +86,7 @@ void leon_eirq_setup(unsigned int eirq) | |||
84 | sparc_leon_eirq = eirq; | 86 | sparc_leon_eirq = eirq; |
85 | } | 87 | } |
86 | 88 | ||
87 | static inline unsigned long get_irqmask(unsigned int irq) | 89 | unsigned long leon_get_irqmask(unsigned int irq) |
88 | { | 90 | { |
89 | unsigned long mask; | 91 | unsigned long mask; |
90 | 92 | ||
@@ -210,7 +212,7 @@ unsigned int leon_build_device_irq(unsigned int real_irq, | |||
210 | unsigned long mask; | 212 | unsigned long mask; |
211 | 213 | ||
212 | irq = 0; | 214 | irq = 0; |
213 | mask = get_irqmask(real_irq); | 215 | mask = leon_get_irqmask(real_irq); |
214 | if (mask == 0) | 216 | if (mask == 0) |
215 | goto out; | 217 | goto out; |
216 | 218 | ||
@@ -250,7 +252,38 @@ void leon_update_virq_handling(unsigned int virq, | |||
250 | irq_set_chip_data(virq, (void *)mask); | 252 | irq_set_chip_data(virq, (void *)mask); |
251 | } | 253 | } |
252 | 254 | ||
253 | void __init leon_init_timers(irq_handler_t counter_fn) | 255 | static u32 leon_cycles_offset(void) |
256 | { | ||
257 | u32 rld, val, off; | ||
258 | rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld); | ||
259 | val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val); | ||
260 | off = rld - val; | ||
261 | return rld - val; | ||
262 | } | ||
263 | |||
264 | #ifdef CONFIG_SMP | ||
265 | |||
266 | /* smp clockevent irq */ | ||
267 | irqreturn_t leon_percpu_timer_ce_interrupt(int irq, void *unused) | ||
268 | { | ||
269 | struct clock_event_device *ce; | ||
270 | int cpu = smp_processor_id(); | ||
271 | |||
272 | leon_clear_profile_irq(cpu); | ||
273 | |||
274 | ce = &per_cpu(sparc32_clockevent, cpu); | ||
275 | |||
276 | irq_enter(); | ||
277 | if (ce->event_handler) | ||
278 | ce->event_handler(ce); | ||
279 | irq_exit(); | ||
280 | |||
281 | return IRQ_HANDLED; | ||
282 | } | ||
283 | |||
284 | #endif /* CONFIG_SMP */ | ||
285 | |||
286 | void __init leon_init_timers(void) | ||
254 | { | 287 | { |
255 | int irq, eirq; | 288 | int irq, eirq; |
256 | struct device_node *rootnp, *np, *nnp; | 289 | struct device_node *rootnp, *np, *nnp; |
@@ -260,6 +293,14 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
260 | int ampopts; | 293 | int ampopts; |
261 | int err; | 294 | int err; |
262 | 295 | ||
296 | sparc_config.get_cycles_offset = leon_cycles_offset; | ||
297 | sparc_config.cs_period = 1000000 / HZ; | ||
298 | sparc_config.features |= FEAT_L10_CLOCKSOURCE; | ||
299 | |||
300 | #ifndef CONFIG_SMP | ||
301 | sparc_config.features |= FEAT_L10_CLOCKEVENT; | ||
302 | #endif | ||
303 | |||
263 | leondebug_irq_disable = 0; | 304 | leondebug_irq_disable = 0; |
264 | leon_debug_irqout = 0; | 305 | leon_debug_irqout = 0; |
265 | master_l10_counter = (unsigned int *)&dummy_master_l10_counter; | 306 | master_l10_counter = (unsigned int *)&dummy_master_l10_counter; |
@@ -369,7 +410,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
369 | leon_eirq_setup(eirq); | 410 | leon_eirq_setup(eirq); |
370 | 411 | ||
371 | irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); | 412 | irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx); |
372 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | 413 | err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL); |
373 | if (err) { | 414 | if (err) { |
374 | printk(KERN_ERR "unable to attach timer IRQ%d\n", irq); | 415 | printk(KERN_ERR "unable to attach timer IRQ%d\n", irq); |
375 | prom_halt(); | 416 | prom_halt(); |
@@ -386,7 +427,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
386 | */ | 427 | */ |
387 | local_irq_save(flags); | 428 | local_irq_save(flags); |
388 | patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ | 429 | patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ |
389 | local_flush_cache_all(); | 430 | local_ops->cache_all(); |
390 | local_irq_restore(flags); | 431 | local_irq_restore(flags); |
391 | } | 432 | } |
392 | #endif | 433 | #endif |
@@ -401,7 +442,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
401 | /* Install per-cpu IRQ handler for broadcasted ticker */ | 442 | /* Install per-cpu IRQ handler for broadcasted ticker */ |
402 | irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, | 443 | irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq, |
403 | "per-cpu", 0); | 444 | "per-cpu", 0); |
404 | err = request_irq(irq, leon_percpu_timer_interrupt, | 445 | err = request_irq(irq, leon_percpu_timer_ce_interrupt, |
405 | IRQF_PERCPU | IRQF_TIMER, "ticker", | 446 | IRQF_PERCPU | IRQF_TIMER, "ticker", |
406 | NULL); | 447 | NULL); |
407 | if (err) { | 448 | if (err) { |
@@ -422,13 +463,12 @@ bad: | |||
422 | return; | 463 | return; |
423 | } | 464 | } |
424 | 465 | ||
425 | void leon_clear_clock_irq(void) | 466 | static void leon_clear_clock_irq(void) |
426 | { | 467 | { |
427 | } | 468 | } |
428 | 469 | ||
429 | void leon_load_profile_irq(int cpu, unsigned int limit) | 470 | static void leon_load_profile_irq(int cpu, unsigned int limit) |
430 | { | 471 | { |
431 | BUG(); | ||
432 | } | 472 | } |
433 | 473 | ||
434 | void __init leon_trans_init(struct device_node *dp) | 474 | void __init leon_trans_init(struct device_node *dp) |
@@ -457,25 +497,6 @@ void __init leon_node_init(struct device_node *dp, struct device_node ***nextp) | |||
457 | } | 497 | } |
458 | 498 | ||
459 | #ifdef CONFIG_SMP | 499 | #ifdef CONFIG_SMP |
460 | |||
461 | void leon_set_cpu_int(int cpu, int level) | ||
462 | { | ||
463 | unsigned long mask; | ||
464 | mask = get_irqmask(level); | ||
465 | LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask); | ||
466 | } | ||
467 | |||
468 | static void leon_clear_ipi(int cpu, int level) | ||
469 | { | ||
470 | unsigned long mask; | ||
471 | mask = get_irqmask(level); | ||
472 | LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask<<16); | ||
473 | } | ||
474 | |||
475 | static void leon_set_udt(int cpu) | ||
476 | { | ||
477 | } | ||
478 | |||
479 | void leon_clear_profile_irq(int cpu) | 500 | void leon_clear_profile_irq(int cpu) |
480 | { | 501 | { |
481 | } | 502 | } |
@@ -483,7 +504,7 @@ void leon_clear_profile_irq(int cpu) | |||
483 | void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) | 504 | void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) |
484 | { | 505 | { |
485 | unsigned long mask, flags, *addr; | 506 | unsigned long mask, flags, *addr; |
486 | mask = get_irqmask(irq_nr); | 507 | mask = leon_get_irqmask(irq_nr); |
487 | spin_lock_irqsave(&leon_irq_lock, flags); | 508 | spin_lock_irqsave(&leon_irq_lock, flags); |
488 | addr = (unsigned long *)LEON_IMASK(cpu); | 509 | addr = (unsigned long *)LEON_IMASK(cpu); |
489 | LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | mask)); | 510 | LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | mask)); |
@@ -494,20 +515,11 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu) | |||
494 | 515 | ||
495 | void __init leon_init_IRQ(void) | 516 | void __init leon_init_IRQ(void) |
496 | { | 517 | { |
497 | sparc_irq_config.init_timers = leon_init_timers; | 518 | sparc_config.init_timers = leon_init_timers; |
498 | sparc_irq_config.build_device_irq = _leon_build_device_irq; | 519 | sparc_config.build_device_irq = _leon_build_device_irq; |
499 | 520 | sparc_config.clock_rate = 1000000; | |
500 | BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq, | 521 | sparc_config.clear_clock_irq = leon_clear_clock_irq; |
501 | BTFIXUPCALL_NORM); | 522 | sparc_config.load_profile_irq = leon_load_profile_irq; |
502 | BTFIXUPSET_CALL(load_profile_irq, leon_load_profile_irq, | ||
503 | BTFIXUPCALL_NOP); | ||
504 | |||
505 | #ifdef CONFIG_SMP | ||
506 | BTFIXUPSET_CALL(set_cpu_int, leon_set_cpu_int, BTFIXUPCALL_NORM); | ||
507 | BTFIXUPSET_CALL(clear_cpu_int, leon_clear_ipi, BTFIXUPCALL_NORM); | ||
508 | BTFIXUPSET_CALL(set_irq_udt, leon_set_udt, BTFIXUPCALL_NORM); | ||
509 | #endif | ||
510 | |||
511 | } | 523 | } |
512 | 524 | ||
513 | void __init leon_init(void) | 525 | void __init leon_init(void) |
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c index 160cac9c4036..a469090faf9f 100644 --- a/arch/sparc/kernel/leon_smp.c +++ b/arch/sparc/kernel/leon_smp.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/gfp.h> | 25 | #include <linux/gfp.h> |
26 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
27 | #include <linux/clockchips.h> | ||
27 | 28 | ||
28 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
29 | #include <asm/tlbflush.h> | 30 | #include <asm/tlbflush.h> |
@@ -43,6 +44,7 @@ | |||
43 | #include <asm/asi.h> | 44 | #include <asm/asi.h> |
44 | #include <asm/leon.h> | 45 | #include <asm/leon.h> |
45 | #include <asm/leon_amba.h> | 46 | #include <asm/leon_amba.h> |
47 | #include <asm/timer.h> | ||
46 | 48 | ||
47 | #include "kernel.h" | 49 | #include "kernel.h" |
48 | 50 | ||
@@ -69,26 +71,24 @@ static inline unsigned long do_swap(volatile unsigned long *ptr, | |||
69 | return val; | 71 | return val; |
70 | } | 72 | } |
71 | 73 | ||
72 | static void smp_setup_percpu_timer(void); | ||
73 | |||
74 | void __cpuinit leon_callin(void) | 74 | void __cpuinit leon_callin(void) |
75 | { | 75 | { |
76 | int cpuid = hard_smpleon_processor_id(); | 76 | int cpuid = hard_smp_processor_id(); |
77 | 77 | ||
78 | local_flush_cache_all(); | 78 | local_ops->cache_all(); |
79 | local_flush_tlb_all(); | 79 | local_ops->tlb_all(); |
80 | leon_configure_cache_smp(); | 80 | leon_configure_cache_smp(); |
81 | 81 | ||
82 | notify_cpu_starting(cpuid); | 82 | notify_cpu_starting(cpuid); |
83 | 83 | ||
84 | /* Get our local ticker going. */ | 84 | /* Get our local ticker going. */ |
85 | smp_setup_percpu_timer(); | 85 | register_percpu_ce(cpuid); |
86 | 86 | ||
87 | calibrate_delay(); | 87 | calibrate_delay(); |
88 | smp_store_cpu_info(cpuid); | 88 | smp_store_cpu_info(cpuid); |
89 | 89 | ||
90 | local_flush_cache_all(); | 90 | local_ops->cache_all(); |
91 | local_flush_tlb_all(); | 91 | local_ops->tlb_all(); |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Unblock the master CPU _only_ when the scheduler state | 94 | * Unblock the master CPU _only_ when the scheduler state |
@@ -99,8 +99,8 @@ void __cpuinit leon_callin(void) | |||
99 | */ | 99 | */ |
100 | do_swap(&cpu_callin_map[cpuid], 1); | 100 | do_swap(&cpu_callin_map[cpuid], 1); |
101 | 101 | ||
102 | local_flush_cache_all(); | 102 | local_ops->cache_all(); |
103 | local_flush_tlb_all(); | 103 | local_ops->tlb_all(); |
104 | 104 | ||
105 | /* Fix idle thread fields. */ | 105 | /* Fix idle thread fields. */ |
106 | __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(¤t_set[cpuid]) | 106 | __asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(¤t_set[cpuid]) |
@@ -143,8 +143,8 @@ void __init leon_configure_cache_smp(void) | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | local_flush_cache_all(); | 146 | local_ops->cache_all(); |
147 | local_flush_tlb_all(); | 147 | local_ops->tlb_all(); |
148 | } | 148 | } |
149 | 149 | ||
150 | void leon_smp_setbroadcast(unsigned int mask) | 150 | void leon_smp_setbroadcast(unsigned int mask) |
@@ -199,21 +199,15 @@ void __init leon_boot_cpus(void) | |||
199 | leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER); | 199 | leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER); |
200 | 200 | ||
201 | leon_configure_cache_smp(); | 201 | leon_configure_cache_smp(); |
202 | smp_setup_percpu_timer(); | 202 | local_ops->cache_all(); |
203 | local_flush_cache_all(); | ||
204 | 203 | ||
205 | } | 204 | } |
206 | 205 | ||
207 | int __cpuinit leon_boot_one_cpu(int i) | 206 | int __cpuinit leon_boot_one_cpu(int i, struct task_struct *idle) |
208 | { | 207 | { |
209 | |||
210 | struct task_struct *p; | ||
211 | int timeout; | 208 | int timeout; |
212 | 209 | ||
213 | /* Cook up an idler for this guy. */ | 210 | current_set[i] = task_thread_info(idle); |
214 | p = fork_idle(i); | ||
215 | |||
216 | current_set[i] = task_thread_info(p); | ||
217 | 211 | ||
218 | /* See trampoline.S:leon_smp_cpu_startup for details... | 212 | /* See trampoline.S:leon_smp_cpu_startup for details... |
219 | * Initialize the contexts table | 213 | * Initialize the contexts table |
@@ -227,7 +221,7 @@ int __cpuinit leon_boot_one_cpu(int i) | |||
227 | /* whirrr, whirrr, whirrrrrrrrr... */ | 221 | /* whirrr, whirrr, whirrrrrrrrr... */ |
228 | printk(KERN_INFO "Starting CPU %d : (irqmp: 0x%x)\n", (unsigned int)i, | 222 | printk(KERN_INFO "Starting CPU %d : (irqmp: 0x%x)\n", (unsigned int)i, |
229 | (unsigned int)&leon3_irqctrl_regs->mpstatus); | 223 | (unsigned int)&leon3_irqctrl_regs->mpstatus); |
230 | local_flush_cache_all(); | 224 | local_ops->cache_all(); |
231 | 225 | ||
232 | /* Make sure all IRQs are of from the start for this new CPU */ | 226 | /* Make sure all IRQs are of from the start for this new CPU */ |
233 | LEON_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[i], 0); | 227 | LEON_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[i], 0); |
@@ -252,7 +246,7 @@ int __cpuinit leon_boot_one_cpu(int i) | |||
252 | leon_enable_irq_cpu(leon_ipi_irq, i); | 246 | leon_enable_irq_cpu(leon_ipi_irq, i); |
253 | } | 247 | } |
254 | 248 | ||
255 | local_flush_cache_all(); | 249 | local_ops->cache_all(); |
256 | return 0; | 250 | return 0; |
257 | } | 251 | } |
258 | 252 | ||
@@ -272,7 +266,7 @@ void __init leon_smp_done(void) | |||
272 | } | 266 | } |
273 | } | 267 | } |
274 | *prev = first; | 268 | *prev = first; |
275 | local_flush_cache_all(); | 269 | local_ops->cache_all(); |
276 | 270 | ||
277 | /* Free unneeded trap tables */ | 271 | /* Free unneeded trap tables */ |
278 | if (!cpu_present(1)) { | 272 | if (!cpu_present(1)) { |
@@ -338,7 +332,7 @@ static void __init leon_ipi_init(void) | |||
338 | local_irq_save(flags); | 332 | local_irq_save(flags); |
339 | trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_ipi_irq - 1)]; | 333 | trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_ipi_irq - 1)]; |
340 | trap_table->inst_three += smpleon_ipi - real_irq_entry; | 334 | trap_table->inst_three += smpleon_ipi - real_irq_entry; |
341 | local_flush_cache_all(); | 335 | local_ops->cache_all(); |
342 | local_irq_restore(flags); | 336 | local_irq_restore(flags); |
343 | 337 | ||
344 | for_each_possible_cpu(cpu) { | 338 | for_each_possible_cpu(cpu) { |
@@ -347,6 +341,13 @@ static void __init leon_ipi_init(void) | |||
347 | } | 341 | } |
348 | } | 342 | } |
349 | 343 | ||
344 | static void leon_send_ipi(int cpu, int level) | ||
345 | { | ||
346 | unsigned long mask; | ||
347 | mask = leon_get_irqmask(level); | ||
348 | LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->force[cpu], mask); | ||
349 | } | ||
350 | |||
350 | static void leon_ipi_single(int cpu) | 351 | static void leon_ipi_single(int cpu) |
351 | { | 352 | { |
352 | struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu); | 353 | struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu); |
@@ -355,7 +356,7 @@ static void leon_ipi_single(int cpu) | |||
355 | work->single = 1; | 356 | work->single = 1; |
356 | 357 | ||
357 | /* Generate IRQ on the CPU */ | 358 | /* Generate IRQ on the CPU */ |
358 | set_cpu_int(cpu, leon_ipi_irq); | 359 | leon_send_ipi(cpu, leon_ipi_irq); |
359 | } | 360 | } |
360 | 361 | ||
361 | static void leon_ipi_mask_one(int cpu) | 362 | static void leon_ipi_mask_one(int cpu) |
@@ -366,7 +367,7 @@ static void leon_ipi_mask_one(int cpu) | |||
366 | work->msk = 1; | 367 | work->msk = 1; |
367 | 368 | ||
368 | /* Generate IRQ on the CPU */ | 369 | /* Generate IRQ on the CPU */ |
369 | set_cpu_int(cpu, leon_ipi_irq); | 370 | leon_send_ipi(cpu, leon_ipi_irq); |
370 | } | 371 | } |
371 | 372 | ||
372 | static void leon_ipi_resched(int cpu) | 373 | static void leon_ipi_resched(int cpu) |
@@ -377,7 +378,7 @@ static void leon_ipi_resched(int cpu) | |||
377 | work->resched = 1; | 378 | work->resched = 1; |
378 | 379 | ||
379 | /* Generate IRQ on the CPU (any IRQ will cause resched) */ | 380 | /* Generate IRQ on the CPU (any IRQ will cause resched) */ |
380 | set_cpu_int(cpu, leon_ipi_irq); | 381 | leon_send_ipi(cpu, leon_ipi_irq); |
381 | } | 382 | } |
382 | 383 | ||
383 | void leonsmp_ipi_interrupt(void) | 384 | void leonsmp_ipi_interrupt(void) |
@@ -449,7 +450,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
449 | if (cpumask_test_cpu(i, &mask)) { | 450 | if (cpumask_test_cpu(i, &mask)) { |
450 | ccall_info.processors_in[i] = 0; | 451 | ccall_info.processors_in[i] = 0; |
451 | ccall_info.processors_out[i] = 0; | 452 | ccall_info.processors_out[i] = 0; |
452 | set_cpu_int(i, LEON3_IRQ_CROSS_CALL); | 453 | leon_send_ipi(i, LEON3_IRQ_CROSS_CALL); |
453 | 454 | ||
454 | } | 455 | } |
455 | } | 456 | } |
@@ -492,68 +493,19 @@ void leon_cross_call_irq(void) | |||
492 | ccall_info.processors_out[i] = 1; | 493 | ccall_info.processors_out[i] = 1; |
493 | } | 494 | } |
494 | 495 | ||
495 | irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused) | 496 | static const struct sparc32_ipi_ops leon_ipi_ops = { |
496 | { | 497 | .cross_call = leon_cross_call, |
497 | int cpu = smp_processor_id(); | 498 | .resched = leon_ipi_resched, |
498 | 499 | .single = leon_ipi_single, | |
499 | leon_clear_profile_irq(cpu); | 500 | .mask_one = leon_ipi_mask_one, |
500 | 501 | }; | |
501 | profile_tick(CPU_PROFILING); | ||
502 | |||
503 | if (!--prof_counter(cpu)) { | ||
504 | int user = user_mode(get_irq_regs()); | ||
505 | |||
506 | update_process_times(user); | ||
507 | |||
508 | prof_counter(cpu) = prof_multiplier(cpu); | ||
509 | } | ||
510 | |||
511 | return IRQ_HANDLED; | ||
512 | } | ||
513 | |||
514 | static void __init smp_setup_percpu_timer(void) | ||
515 | { | ||
516 | int cpu = smp_processor_id(); | ||
517 | |||
518 | prof_counter(cpu) = prof_multiplier(cpu) = 1; | ||
519 | } | ||
520 | |||
521 | void __init leon_blackbox_id(unsigned *addr) | ||
522 | { | ||
523 | int rd = *addr & 0x3e000000; | ||
524 | int rs1 = rd >> 11; | ||
525 | |||
526 | /* patch places where ___b_hard_smp_processor_id appears */ | ||
527 | addr[0] = 0x81444000 | rd; /* rd %asr17, reg */ | ||
528 | addr[1] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */ | ||
529 | addr[2] = 0x01000000; /* nop */ | ||
530 | } | ||
531 | |||
532 | void __init leon_blackbox_current(unsigned *addr) | ||
533 | { | ||
534 | int rd = *addr & 0x3e000000; | ||
535 | int rs1 = rd >> 11; | ||
536 | |||
537 | /* patch LOAD_CURRENT macro where ___b_load_current appears */ | ||
538 | addr[0] = 0x81444000 | rd; /* rd %asr17, reg */ | ||
539 | addr[2] = 0x8130201c | rd | rs1; /* srl reg, 0x1c, reg */ | ||
540 | addr[4] = 0x81282002 | rd | rs1; /* sll reg, 0x2, reg */ | ||
541 | |||
542 | } | ||
543 | 502 | ||
544 | void __init leon_init_smp(void) | 503 | void __init leon_init_smp(void) |
545 | { | 504 | { |
546 | /* Patch ipi15 trap table */ | 505 | /* Patch ipi15 trap table */ |
547 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_leon - linux_trap_ipi15_sun4m); | 506 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_leon - linux_trap_ipi15_sun4m); |
548 | 507 | ||
549 | BTFIXUPSET_BLACKBOX(hard_smp_processor_id, leon_blackbox_id); | 508 | sparc32_ipi_ops = &leon_ipi_ops; |
550 | BTFIXUPSET_BLACKBOX(load_current, leon_blackbox_current); | ||
551 | BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM); | ||
552 | BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id, | ||
553 | BTFIXUPCALL_NORM); | ||
554 | BTFIXUPSET_CALL(smp_ipi_resched, leon_ipi_resched, BTFIXUPCALL_NORM); | ||
555 | BTFIXUPSET_CALL(smp_ipi_single, leon_ipi_single, BTFIXUPCALL_NORM); | ||
556 | BTFIXUPSET_CALL(smp_ipi_mask_one, leon_ipi_mask_one, BTFIXUPCALL_NORM); | ||
557 | } | 509 | } |
558 | 510 | ||
559 | #endif /* CONFIG_SPARC_LEON */ | 511 | #endif /* CONFIG_SPARC_LEON */ |
diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 276359e1ff56..15e0a1693976 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c | |||
@@ -32,26 +32,11 @@ static void *module_map(unsigned long size) | |||
32 | GFP_KERNEL, PAGE_KERNEL, -1, | 32 | GFP_KERNEL, PAGE_KERNEL, -1, |
33 | __builtin_return_address(0)); | 33 | __builtin_return_address(0)); |
34 | } | 34 | } |
35 | |||
36 | static char *dot2underscore(char *name) | ||
37 | { | ||
38 | return name; | ||
39 | } | ||
40 | #else | 35 | #else |
41 | static void *module_map(unsigned long size) | 36 | static void *module_map(unsigned long size) |
42 | { | 37 | { |
43 | return vmalloc(size); | 38 | return vmalloc(size); |
44 | } | 39 | } |
45 | |||
46 | /* Replace references to .func with _Func */ | ||
47 | static char *dot2underscore(char *name) | ||
48 | { | ||
49 | if (name[0] == '.') { | ||
50 | name[0] = '_'; | ||
51 | name[1] = toupper(name[1]); | ||
52 | } | ||
53 | return name; | ||
54 | } | ||
55 | #endif /* CONFIG_SPARC64 */ | 40 | #endif /* CONFIG_SPARC64 */ |
56 | 41 | ||
57 | void *module_alloc(unsigned long size) | 42 | void *module_alloc(unsigned long size) |
@@ -93,12 +78,8 @@ int module_frob_arch_sections(Elf_Ehdr *hdr, | |||
93 | 78 | ||
94 | for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) { | 79 | for (i = 1; i < sechdrs[symidx].sh_size / sizeof(Elf_Sym); i++) { |
95 | if (sym[i].st_shndx == SHN_UNDEF) { | 80 | if (sym[i].st_shndx == SHN_UNDEF) { |
96 | if (ELF_ST_TYPE(sym[i].st_info) == STT_REGISTER) { | 81 | if (ELF_ST_TYPE(sym[i].st_info) == STT_REGISTER) |
97 | sym[i].st_shndx = SHN_ABS; | 82 | sym[i].st_shndx = SHN_ABS; |
98 | } else { | ||
99 | char *name = strtab + sym[i].st_name; | ||
100 | dot2underscore(name); | ||
101 | } | ||
102 | } | 83 | } |
103 | } | 84 | } |
104 | return 0; | 85 | return 0; |
diff --git a/arch/sparc/kernel/muldiv.c b/arch/sparc/kernel/muldiv.c deleted file mode 100644 index f7db516b07d8..000000000000 --- a/arch/sparc/kernel/muldiv.c +++ /dev/null | |||
@@ -1,238 +0,0 @@ | |||
1 | /* | ||
2 | * muldiv.c: Hardware multiply/division illegal instruction trap | ||
3 | * for sun4c/sun4 (which do not have those instructions) | ||
4 | * | ||
5 | * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | ||
7 | * | ||
8 | * 2004-12-25 Krzysztof Helt (krzysztof.h1@wp.pl) | ||
9 | * - fixed registers constrains in inline assembly declarations | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/mm.h> | ||
15 | #include <asm/ptrace.h> | ||
16 | #include <asm/processor.h> | ||
17 | #include <asm/uaccess.h> | ||
18 | |||
19 | #include "kernel.h" | ||
20 | |||
21 | /* #define DEBUG_MULDIV */ | ||
22 | |||
23 | static inline int has_imm13(int insn) | ||
24 | { | ||
25 | return (insn & 0x2000); | ||
26 | } | ||
27 | |||
28 | static inline int is_foocc(int insn) | ||
29 | { | ||
30 | return (insn & 0x800000); | ||
31 | } | ||
32 | |||
33 | static inline int sign_extend_imm13(int imm) | ||
34 | { | ||
35 | return imm << 19 >> 19; | ||
36 | } | ||
37 | |||
38 | static inline void advance(struct pt_regs *regs) | ||
39 | { | ||
40 | regs->pc = regs->npc; | ||
41 | regs->npc += 4; | ||
42 | } | ||
43 | |||
44 | static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, | ||
45 | unsigned int rd) | ||
46 | { | ||
47 | if(rs2 >= 16 || rs1 >= 16 || rd >= 16) { | ||
48 | /* Wheee... */ | ||
49 | __asm__ __volatile__("save %sp, -0x40, %sp\n\t" | ||
50 | "save %sp, -0x40, %sp\n\t" | ||
51 | "save %sp, -0x40, %sp\n\t" | ||
52 | "save %sp, -0x40, %sp\n\t" | ||
53 | "save %sp, -0x40, %sp\n\t" | ||
54 | "save %sp, -0x40, %sp\n\t" | ||
55 | "save %sp, -0x40, %sp\n\t" | ||
56 | "restore; restore; restore; restore;\n\t" | ||
57 | "restore; restore; restore;\n\t"); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | #define fetch_reg(reg, regs) ({ \ | ||
62 | struct reg_window32 __user *win; \ | ||
63 | register unsigned long ret; \ | ||
64 | \ | ||
65 | if (!(reg)) ret = 0; \ | ||
66 | else if ((reg) < 16) { \ | ||
67 | ret = regs->u_regs[(reg)]; \ | ||
68 | } else { \ | ||
69 | /* Ho hum, the slightly complicated case. */ \ | ||
70 | win = (struct reg_window32 __user *)regs->u_regs[UREG_FP];\ | ||
71 | if (get_user (ret, &win->locals[(reg) - 16])) return -1;\ | ||
72 | } \ | ||
73 | ret; \ | ||
74 | }) | ||
75 | |||
76 | static inline int | ||
77 | store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs) | ||
78 | { | ||
79 | struct reg_window32 __user *win; | ||
80 | |||
81 | if (!reg) | ||
82 | return 0; | ||
83 | if (reg < 16) { | ||
84 | regs->u_regs[reg] = result; | ||
85 | return 0; | ||
86 | } else { | ||
87 | /* need to use put_user() in this case: */ | ||
88 | win = (struct reg_window32 __user *) regs->u_regs[UREG_FP]; | ||
89 | return (put_user(result, &win->locals[reg - 16])); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* Should return 0 if mul/div emulation succeeded and SIGILL should | ||
94 | * not be issued. | ||
95 | */ | ||
96 | int do_user_muldiv(struct pt_regs *regs, unsigned long pc) | ||
97 | { | ||
98 | unsigned int insn; | ||
99 | int inst; | ||
100 | unsigned int rs1, rs2, rdv; | ||
101 | |||
102 | if (!pc) | ||
103 | return -1; /* This happens to often, I think */ | ||
104 | if (get_user (insn, (unsigned int __user *)pc)) | ||
105 | return -1; | ||
106 | if ((insn & 0xc1400000) != 0x80400000) | ||
107 | return -1; | ||
108 | inst = ((insn >> 19) & 0xf); | ||
109 | if ((inst & 0xe) != 10 && (inst & 0xe) != 14) | ||
110 | return -1; | ||
111 | |||
112 | /* Now we know we have to do something with umul, smul, udiv or sdiv */ | ||
113 | rs1 = (insn >> 14) & 0x1f; | ||
114 | rs2 = insn & 0x1f; | ||
115 | rdv = (insn >> 25) & 0x1f; | ||
116 | if (has_imm13(insn)) { | ||
117 | maybe_flush_windows(rs1, 0, rdv); | ||
118 | rs2 = sign_extend_imm13(insn); | ||
119 | } else { | ||
120 | maybe_flush_windows(rs1, rs2, rdv); | ||
121 | rs2 = fetch_reg(rs2, regs); | ||
122 | } | ||
123 | rs1 = fetch_reg(rs1, regs); | ||
124 | switch (inst) { | ||
125 | case 10: /* umul */ | ||
126 | #ifdef DEBUG_MULDIV | ||
127 | printk ("unsigned muldiv: 0x%x * 0x%x = ", rs1, rs2); | ||
128 | #endif | ||
129 | __asm__ __volatile__ ("\n\t" | ||
130 | "mov %0, %%o0\n\t" | ||
131 | "call .umul\n\t" | ||
132 | " mov %1, %%o1\n\t" | ||
133 | "mov %%o0, %0\n\t" | ||
134 | "mov %%o1, %1\n\t" | ||
135 | : "=r" (rs1), "=r" (rs2) | ||
136 | : "0" (rs1), "1" (rs2) | ||
137 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); | ||
138 | #ifdef DEBUG_MULDIV | ||
139 | printk ("0x%x%08x\n", rs2, rs1); | ||
140 | #endif | ||
141 | if (store_reg(rs1, rdv, regs)) | ||
142 | return -1; | ||
143 | regs->y = rs2; | ||
144 | break; | ||
145 | case 11: /* smul */ | ||
146 | #ifdef DEBUG_MULDIV | ||
147 | printk ("signed muldiv: 0x%x * 0x%x = ", rs1, rs2); | ||
148 | #endif | ||
149 | __asm__ __volatile__ ("\n\t" | ||
150 | "mov %0, %%o0\n\t" | ||
151 | "call .mul\n\t" | ||
152 | " mov %1, %%o1\n\t" | ||
153 | "mov %%o0, %0\n\t" | ||
154 | "mov %%o1, %1\n\t" | ||
155 | : "=r" (rs1), "=r" (rs2) | ||
156 | : "0" (rs1), "1" (rs2) | ||
157 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); | ||
158 | #ifdef DEBUG_MULDIV | ||
159 | printk ("0x%x%08x\n", rs2, rs1); | ||
160 | #endif | ||
161 | if (store_reg(rs1, rdv, regs)) | ||
162 | return -1; | ||
163 | regs->y = rs2; | ||
164 | break; | ||
165 | case 14: /* udiv */ | ||
166 | #ifdef DEBUG_MULDIV | ||
167 | printk ("unsigned muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); | ||
168 | #endif | ||
169 | if (!rs2) { | ||
170 | #ifdef DEBUG_MULDIV | ||
171 | printk ("DIVISION BY ZERO\n"); | ||
172 | #endif | ||
173 | handle_hw_divzero (regs, pc, regs->npc, regs->psr); | ||
174 | return 0; | ||
175 | } | ||
176 | __asm__ __volatile__ ("\n\t" | ||
177 | "mov %2, %%o0\n\t" | ||
178 | "mov %0, %%o1\n\t" | ||
179 | "mov %%g0, %%o2\n\t" | ||
180 | "call __udivdi3\n\t" | ||
181 | " mov %1, %%o3\n\t" | ||
182 | "mov %%o1, %0\n\t" | ||
183 | "mov %%o0, %1\n\t" | ||
184 | : "=r" (rs1), "=r" (rs2) | ||
185 | : "r" (regs->y), "0" (rs1), "1" (rs2) | ||
186 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", | ||
187 | "g1", "g2", "g3", "cc"); | ||
188 | #ifdef DEBUG_MULDIV | ||
189 | printk ("0x%x\n", rs1); | ||
190 | #endif | ||
191 | if (store_reg(rs1, rdv, regs)) | ||
192 | return -1; | ||
193 | break; | ||
194 | case 15: /* sdiv */ | ||
195 | #ifdef DEBUG_MULDIV | ||
196 | printk ("signed muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); | ||
197 | #endif | ||
198 | if (!rs2) { | ||
199 | #ifdef DEBUG_MULDIV | ||
200 | printk ("DIVISION BY ZERO\n"); | ||
201 | #endif | ||
202 | handle_hw_divzero (regs, pc, regs->npc, regs->psr); | ||
203 | return 0; | ||
204 | } | ||
205 | __asm__ __volatile__ ("\n\t" | ||
206 | "mov %2, %%o0\n\t" | ||
207 | "mov %0, %%o1\n\t" | ||
208 | "mov %%g0, %%o2\n\t" | ||
209 | "call __divdi3\n\t" | ||
210 | " mov %1, %%o3\n\t" | ||
211 | "mov %%o1, %0\n\t" | ||
212 | "mov %%o0, %1\n\t" | ||
213 | : "=r" (rs1), "=r" (rs2) | ||
214 | : "r" (regs->y), "0" (rs1), "1" (rs2) | ||
215 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", | ||
216 | "g1", "g2", "g3", "cc"); | ||
217 | #ifdef DEBUG_MULDIV | ||
218 | printk ("0x%x\n", rs1); | ||
219 | #endif | ||
220 | if (store_reg(rs1, rdv, regs)) | ||
221 | return -1; | ||
222 | break; | ||
223 | } | ||
224 | if (is_foocc (insn)) { | ||
225 | regs->psr &= ~PSR_ICC; | ||
226 | if ((inst & 0xe) == 14) { | ||
227 | /* ?div */ | ||
228 | if (rs2) regs->psr |= PSR_V; | ||
229 | } | ||
230 | if (!rs1) regs->psr |= PSR_Z; | ||
231 | if (((int)rs1) < 0) regs->psr |= PSR_N; | ||
232 | #ifdef DEBUG_MULDIV | ||
233 | printk ("psr muldiv: %08x\n", regs->psr); | ||
234 | #endif | ||
235 | } | ||
236 | advance(regs); | ||
237 | return 0; | ||
238 | } | ||
diff --git a/arch/sparc/kernel/of_device_32.c b/arch/sparc/kernel/of_device_32.c index 4ee8ce0d5d8d..185aa96fa5be 100644 --- a/arch/sparc/kernel/of_device_32.c +++ b/arch/sparc/kernel/of_device_32.c | |||
@@ -356,7 +356,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp, | |||
356 | op->archdata.num_irqs = len / sizeof(struct linux_prom_irqs); | 356 | op->archdata.num_irqs = len / sizeof(struct linux_prom_irqs); |
357 | for (i = 0; i < op->archdata.num_irqs; i++) | 357 | for (i = 0; i < op->archdata.num_irqs; i++) |
358 | op->archdata.irqs[i] = | 358 | op->archdata.irqs[i] = |
359 | sparc_irq_config.build_device_irq(op, intr[i].pri); | 359 | sparc_config.build_device_irq(op, intr[i].pri); |
360 | } else { | 360 | } else { |
361 | const unsigned int *irq = | 361 | const unsigned int *irq = |
362 | of_get_property(dp, "interrupts", &len); | 362 | of_get_property(dp, "interrupts", &len); |
@@ -365,7 +365,7 @@ static struct platform_device * __init scan_one_device(struct device_node *dp, | |||
365 | op->archdata.num_irqs = len / sizeof(unsigned int); | 365 | op->archdata.num_irqs = len / sizeof(unsigned int); |
366 | for (i = 0; i < op->archdata.num_irqs; i++) | 366 | for (i = 0; i < op->archdata.num_irqs; i++) |
367 | op->archdata.irqs[i] = | 367 | op->archdata.irqs[i] = |
368 | sparc_irq_config.build_device_irq(op, irq[i]); | 368 | sparc_config.build_device_irq(op, irq[i]); |
369 | } else { | 369 | } else { |
370 | op->archdata.num_irqs = 0; | 370 | op->archdata.num_irqs = 0; |
371 | } | 371 | } |
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index fcc148effaac..ded3f6090c3f 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c | |||
@@ -703,31 +703,28 @@ static void pcic_clear_clock_irq(void) | |||
703 | pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT); | 703 | pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT); |
704 | } | 704 | } |
705 | 705 | ||
706 | static irqreturn_t pcic_timer_handler (int irq, void *h) | 706 | /* CPU frequency is 100 MHz, timer increments every 4 CPU clocks */ |
707 | #define USECS_PER_JIFFY (1000000 / HZ) | ||
708 | #define TICK_TIMER_LIMIT ((100 * 1000000 / 4) / HZ) | ||
709 | |||
710 | static unsigned int pcic_cycles_offset(void) | ||
707 | { | 711 | { |
708 | pcic_clear_clock_irq(); | 712 | u32 value, count; |
709 | xtime_update(1); | ||
710 | #ifndef CONFIG_SMP | ||
711 | update_process_times(user_mode(get_irq_regs())); | ||
712 | #endif | ||
713 | return IRQ_HANDLED; | ||
714 | } | ||
715 | 713 | ||
716 | #define USECS_PER_JIFFY 10000 /* We have 100HZ "standard" timer for sparc */ | 714 | value = readl(pcic0.pcic_regs + PCI_SYS_COUNTER); |
717 | #define TICK_TIMER_LIMIT ((100*1000000/4)/100) | 715 | count = value & ~PCI_SYS_COUNTER_OVERFLOW; |
718 | 716 | ||
719 | u32 pci_gettimeoffset(void) | 717 | if (value & PCI_SYS_COUNTER_OVERFLOW) |
720 | { | 718 | count += TICK_TIMER_LIMIT; |
721 | /* | 719 | /* |
722 | * We divide all by 100 | 720 | * We divide all by HZ |
723 | * to have microsecond resolution and to avoid overflow | 721 | * to have microsecond resolution and to avoid overflow |
724 | */ | 722 | */ |
725 | unsigned long count = | 723 | count = ((count / HZ) * USECS_PER_JIFFY) / (TICK_TIMER_LIMIT / HZ); |
726 | readl(pcic0.pcic_regs+PCI_SYS_COUNTER) & ~PCI_SYS_COUNTER_OVERFLOW; | ||
727 | count = ((count/100)*USECS_PER_JIFFY) / (TICK_TIMER_LIMIT/100); | ||
728 | return count * 1000; | ||
729 | } | ||
730 | 724 | ||
725 | /* Coordinate with the sparc_config.clock_rate setting */ | ||
726 | return count * 2; | ||
727 | } | ||
731 | 728 | ||
732 | void __init pci_time_init(void) | 729 | void __init pci_time_init(void) |
733 | { | 730 | { |
@@ -736,9 +733,16 @@ void __init pci_time_init(void) | |||
736 | int timer_irq, irq; | 733 | int timer_irq, irq; |
737 | int err; | 734 | int err; |
738 | 735 | ||
739 | do_arch_gettimeoffset = pci_gettimeoffset; | 736 | #ifndef CONFIG_SMP |
740 | 737 | /* | |
741 | btfixup(); | 738 | * The clock_rate is in SBUS dimension. |
739 | * We take into account this in pcic_cycles_offset() | ||
740 | */ | ||
741 | sparc_config.clock_rate = SBUS_CLOCK_RATE / HZ; | ||
742 | sparc_config.features |= FEAT_L10_CLOCKEVENT; | ||
743 | #endif | ||
744 | sparc_config.features |= FEAT_L10_CLOCKSOURCE; | ||
745 | sparc_config.get_cycles_offset = pcic_cycles_offset; | ||
742 | 746 | ||
743 | writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); | 747 | writel (TICK_TIMER_LIMIT, pcic->pcic_regs+PCI_SYS_LIMIT); |
744 | /* PROM should set appropriate irq */ | 748 | /* PROM should set appropriate irq */ |
@@ -747,7 +751,7 @@ void __init pci_time_init(void) | |||
747 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), | 751 | writel (PCI_COUNTER_IRQ_SET(timer_irq, 0), |
748 | pcic->pcic_regs+PCI_COUNTER_IRQ); | 752 | pcic->pcic_regs+PCI_COUNTER_IRQ); |
749 | irq = pcic_build_device_irq(NULL, timer_irq); | 753 | irq = pcic_build_device_irq(NULL, timer_irq); |
750 | err = request_irq(irq, pcic_timer_handler, | 754 | err = request_irq(irq, timer_interrupt, |
751 | IRQF_TIMER, "timer", NULL); | 755 | IRQF_TIMER, "timer", NULL); |
752 | if (err) { | 756 | if (err) { |
753 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); | 757 | prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); |
@@ -875,10 +879,9 @@ static void pcic_load_profile_irq(int cpu, unsigned int limit) | |||
875 | 879 | ||
876 | void __init sun4m_pci_init_IRQ(void) | 880 | void __init sun4m_pci_init_IRQ(void) |
877 | { | 881 | { |
878 | sparc_irq_config.build_device_irq = pcic_build_device_irq; | 882 | sparc_config.build_device_irq = pcic_build_device_irq; |
879 | 883 | sparc_config.clear_clock_irq = pcic_clear_clock_irq; | |
880 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); | 884 | sparc_config.load_profile_irq = pcic_load_profile_irq; |
881 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); | ||
882 | } | 885 | } |
883 | 886 | ||
884 | int pcibios_assign_resource(struct pci_dev *pdev, int resource) | 887 | int pcibios_assign_resource(struct pci_dev *pdev, int resource) |
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index efa07542e85f..fe6787cc62fc 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c | |||
@@ -67,8 +67,6 @@ struct thread_info *current_set[NR_CPUS]; | |||
67 | 67 | ||
68 | #ifndef CONFIG_SMP | 68 | #ifndef CONFIG_SMP |
69 | 69 | ||
70 | #define SUN4C_FAULT_HIGH 100 | ||
71 | |||
72 | /* | 70 | /* |
73 | * the idle loop on a Sparc... ;) | 71 | * the idle loop on a Sparc... ;) |
74 | */ | 72 | */ |
@@ -76,36 +74,6 @@ void cpu_idle(void) | |||
76 | { | 74 | { |
77 | /* endless idle loop with no priority at all */ | 75 | /* endless idle loop with no priority at all */ |
78 | for (;;) { | 76 | for (;;) { |
79 | if (ARCH_SUN4C) { | ||
80 | static int count = HZ; | ||
81 | static unsigned long last_jiffies; | ||
82 | static unsigned long last_faults; | ||
83 | static unsigned long fps; | ||
84 | unsigned long now; | ||
85 | unsigned long faults; | ||
86 | |||
87 | extern unsigned long sun4c_kernel_faults; | ||
88 | extern void sun4c_grow_kernel_ring(void); | ||
89 | |||
90 | local_irq_disable(); | ||
91 | now = jiffies; | ||
92 | count -= (now - last_jiffies); | ||
93 | last_jiffies = now; | ||
94 | if (count < 0) { | ||
95 | count += HZ; | ||
96 | faults = sun4c_kernel_faults; | ||
97 | fps = (fps + (faults - last_faults)) >> 1; | ||
98 | last_faults = faults; | ||
99 | #if 0 | ||
100 | printk("kernel faults / second = %ld\n", fps); | ||
101 | #endif | ||
102 | if (fps >= SUN4C_FAULT_HIGH) { | ||
103 | sun4c_grow_kernel_ring(); | ||
104 | } | ||
105 | } | ||
106 | local_irq_enable(); | ||
107 | } | ||
108 | |||
109 | if (pm_idle) { | 77 | if (pm_idle) { |
110 | while (!need_resched()) | 78 | while (!need_resched()) |
111 | (*pm_idle)(); | 79 | (*pm_idle)(); |
@@ -114,7 +82,6 @@ void cpu_idle(void) | |||
114 | cpu_relax(); | 82 | cpu_relax(); |
115 | } | 83 | } |
116 | schedule_preempt_disabled(); | 84 | schedule_preempt_disabled(); |
117 | check_pgt_cache(); | ||
118 | } | 85 | } |
119 | } | 86 | } |
120 | 87 | ||
@@ -137,7 +104,6 @@ void cpu_idle(void) | |||
137 | cpu_relax(); | 104 | cpu_relax(); |
138 | } | 105 | } |
139 | schedule_preempt_disabled(); | 106 | schedule_preempt_disabled(); |
140 | check_pgt_cache(); | ||
141 | } | 107 | } |
142 | } | 108 | } |
143 | 109 | ||
@@ -179,88 +145,6 @@ void machine_power_off(void) | |||
179 | machine_halt(); | 145 | machine_halt(); |
180 | } | 146 | } |
181 | 147 | ||
182 | #if 0 | ||
183 | |||
184 | static DEFINE_SPINLOCK(sparc_backtrace_lock); | ||
185 | |||
186 | void __show_backtrace(unsigned long fp) | ||
187 | { | ||
188 | struct reg_window32 *rw; | ||
189 | unsigned long flags; | ||
190 | int cpu = smp_processor_id(); | ||
191 | |||
192 | spin_lock_irqsave(&sparc_backtrace_lock, flags); | ||
193 | |||
194 | rw = (struct reg_window32 *)fp; | ||
195 | while(rw && (((unsigned long) rw) >= PAGE_OFFSET) && | ||
196 | !(((unsigned long) rw) & 0x7)) { | ||
197 | printk("CPU[%d]: ARGS[%08lx,%08lx,%08lx,%08lx,%08lx,%08lx] " | ||
198 | "FP[%08lx] CALLER[%08lx]: ", cpu, | ||
199 | rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3], | ||
200 | rw->ins[4], rw->ins[5], | ||
201 | rw->ins[6], | ||
202 | rw->ins[7]); | ||
203 | printk("%pS\n", (void *) rw->ins[7]); | ||
204 | rw = (struct reg_window32 *) rw->ins[6]; | ||
205 | } | ||
206 | spin_unlock_irqrestore(&sparc_backtrace_lock, flags); | ||
207 | } | ||
208 | |||
209 | #define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t") | ||
210 | #define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t") | ||
211 | #define __GET_FP(fp) __asm__ __volatile__("mov %%i6, %0" : "=r" (fp)) | ||
212 | |||
213 | void show_backtrace(void) | ||
214 | { | ||
215 | unsigned long fp; | ||
216 | |||
217 | __SAVE; __SAVE; __SAVE; __SAVE; | ||
218 | __SAVE; __SAVE; __SAVE; __SAVE; | ||
219 | __RESTORE; __RESTORE; __RESTORE; __RESTORE; | ||
220 | __RESTORE; __RESTORE; __RESTORE; __RESTORE; | ||
221 | |||
222 | __GET_FP(fp); | ||
223 | |||
224 | __show_backtrace(fp); | ||
225 | } | ||
226 | |||
227 | #ifdef CONFIG_SMP | ||
228 | void smp_show_backtrace_all_cpus(void) | ||
229 | { | ||
230 | xc0((smpfunc_t) show_backtrace); | ||
231 | show_backtrace(); | ||
232 | } | ||
233 | #endif | ||
234 | |||
235 | void show_stackframe(struct sparc_stackf *sf) | ||
236 | { | ||
237 | unsigned long size; | ||
238 | unsigned long *stk; | ||
239 | int i; | ||
240 | |||
241 | printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx " | ||
242 | "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n", | ||
243 | sf->locals[0], sf->locals[1], sf->locals[2], sf->locals[3], | ||
244 | sf->locals[4], sf->locals[5], sf->locals[6], sf->locals[7]); | ||
245 | printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx " | ||
246 | "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n", | ||
247 | sf->ins[0], sf->ins[1], sf->ins[2], sf->ins[3], | ||
248 | sf->ins[4], sf->ins[5], (unsigned long)sf->fp, sf->callers_pc); | ||
249 | printk("sp: %08lx x0: %08lx x1: %08lx x2: %08lx " | ||
250 | "x3: %08lx x4: %08lx x5: %08lx xx: %08lx\n", | ||
251 | (unsigned long)sf->structptr, sf->xargs[0], sf->xargs[1], | ||
252 | sf->xargs[2], sf->xargs[3], sf->xargs[4], sf->xargs[5], | ||
253 | sf->xxargs[0]); | ||
254 | size = ((unsigned long)sf->fp) - ((unsigned long)sf); | ||
255 | size -= STACKFRAME_SZ; | ||
256 | stk = (unsigned long *)((unsigned long)sf + STACKFRAME_SZ); | ||
257 | i = 0; | ||
258 | do { | ||
259 | printk("s%d: %08lx\n", i++, *stk++); | ||
260 | } while ((size -= sizeof(unsigned long))); | ||
261 | } | ||
262 | #endif | ||
263 | |||
264 | void show_regs(struct pt_regs *r) | 148 | void show_regs(struct pt_regs *r) |
265 | { | 149 | { |
266 | struct reg_window32 *rw = (struct reg_window32 *) r->u_regs[14]; | 150 | struct reg_window32 *rw = (struct reg_window32 *) r->u_regs[14]; |
diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 6f97c0767995..484dabac7045 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c | |||
@@ -1062,7 +1062,7 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) | |||
1062 | int ret = 0; | 1062 | int ret = 0; |
1063 | 1063 | ||
1064 | /* do the secure computing check first */ | 1064 | /* do the secure computing check first */ |
1065 | secure_computing(regs->u_regs[UREG_G1]); | 1065 | secure_computing_strict(regs->u_regs[UREG_G1]); |
1066 | 1066 | ||
1067 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | 1067 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
1068 | ret = tracehook_report_syscall_entry(regs); | 1068 | ret = tracehook_report_syscall_entry(regs); |
diff --git a/arch/sparc/kernel/rtrap_32.S b/arch/sparc/kernel/rtrap_32.S index 5f5f74c2c2ca..7abc24e2bf1a 100644 --- a/arch/sparc/kernel/rtrap_32.S +++ b/arch/sparc/kernel/rtrap_32.S | |||
@@ -128,13 +128,12 @@ rtrap_patch2: and %glob_tmp, 0xff, %glob_tmp | |||
128 | 128 | ||
129 | wr %glob_tmp, 0x0, %wim | 129 | wr %glob_tmp, 0x0, %wim |
130 | 130 | ||
131 | /* Here comes the architecture specific | 131 | /* Here comes the architecture specific |
132 | * branch to the user stack checking routine | 132 | * branch to the user stack checking routine |
133 | * for return from traps. | 133 | * for return from traps. |
134 | */ | 134 | */ |
135 | .globl rtrap_mmu_patchme | 135 | b srmmu_rett_stackchk |
136 | rtrap_mmu_patchme: b sun4c_rett_stackchk | 136 | andcc %fp, 0x7, %g0 |
137 | andcc %fp, 0x7, %g0 | ||
138 | 137 | ||
139 | ret_trap_userwins_ok: | 138 | ret_trap_userwins_ok: |
140 | LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) | 139 | LOAD_PT_PRIV(sp, t_psr, t_pc, t_npc) |
@@ -225,69 +224,6 @@ ret_trap_user_stack_is_bolixed: | |||
225 | b signal_p | 224 | b signal_p |
226 | ld [%curptr + TI_FLAGS], %g2 | 225 | ld [%curptr + TI_FLAGS], %g2 |
227 | 226 | ||
228 | sun4c_rett_stackchk: | ||
229 | be 1f | ||
230 | and %fp, 0xfff, %g1 ! delay slot | ||
231 | |||
232 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
233 | wr %t_wim, 0x0, %wim | ||
234 | |||
235 | /* See if we have to check the sanity of one page or two */ | ||
236 | 1: | ||
237 | add %g1, 0x38, %g1 | ||
238 | sra %fp, 29, %g2 | ||
239 | add %g2, 0x1, %g2 | ||
240 | andncc %g2, 0x1, %g0 | ||
241 | be 1f | ||
242 | andncc %g1, 0xff8, %g0 | ||
243 | |||
244 | /* %sp is in vma hole, yuck */ | ||
245 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
246 | wr %t_wim, 0x0, %wim | ||
247 | |||
248 | 1: | ||
249 | be sun4c_rett_onepage /* Only one page to check */ | ||
250 | lda [%fp] ASI_PTE, %g2 | ||
251 | |||
252 | sun4c_rett_twopages: | ||
253 | add %fp, 0x38, %g1 | ||
254 | sra %g1, 29, %g2 | ||
255 | add %g2, 0x1, %g2 | ||
256 | andncc %g2, 0x1, %g0 | ||
257 | be 1f | ||
258 | lda [%g1] ASI_PTE, %g2 | ||
259 | |||
260 | /* Second page is in vma hole */ | ||
261 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
262 | wr %t_wim, 0x0, %wim | ||
263 | |||
264 | 1: | ||
265 | srl %g2, 29, %g2 | ||
266 | andcc %g2, 0x4, %g0 | ||
267 | bne sun4c_rett_onepage | ||
268 | lda [%fp] ASI_PTE, %g2 | ||
269 | |||
270 | /* Second page has bad perms */ | ||
271 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
272 | wr %t_wim, 0x0, %wim | ||
273 | |||
274 | sun4c_rett_onepage: | ||
275 | srl %g2, 29, %g2 | ||
276 | andcc %g2, 0x4, %g0 | ||
277 | bne,a 1f | ||
278 | restore %g0, %g0, %g0 | ||
279 | |||
280 | /* A page had bad page permissions, losing... */ | ||
281 | b ret_trap_user_stack_is_bolixed + 0x4 | ||
282 | wr %t_wim, 0x0, %wim | ||
283 | |||
284 | /* Whee, things are ok, load the window and continue. */ | ||
285 | 1: | ||
286 | LOAD_WINDOW(sp) | ||
287 | |||
288 | b ret_trap_userwins_ok | ||
289 | save %g0, %g0, %g0 | ||
290 | |||
291 | .globl srmmu_rett_stackchk | 227 | .globl srmmu_rett_stackchk |
292 | srmmu_rett_stackchk: | 228 | srmmu_rett_stackchk: |
293 | bne ret_trap_user_stack_is_bolixed | 229 | bne ret_trap_user_stack_is_bolixed |
diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S index 9171fc238def..afa2a9e3d0a0 100644 --- a/arch/sparc/kernel/rtrap_64.S +++ b/arch/sparc/kernel/rtrap_64.S | |||
@@ -73,18 +73,8 @@ rtrap_nmi: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 | |||
73 | .globl rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall | 73 | .globl rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall |
74 | rtrap_irq: | 74 | rtrap_irq: |
75 | rtrap: | 75 | rtrap: |
76 | #ifndef CONFIG_SMP | ||
77 | sethi %hi(__cpu_data), %l0 | ||
78 | lduw [%l0 + %lo(__cpu_data)], %l1 | ||
79 | #else | ||
80 | sethi %hi(__cpu_data), %l0 | ||
81 | or %l0, %lo(__cpu_data), %l0 | ||
82 | lduw [%l0 + %g5], %l1 | ||
83 | #endif | ||
84 | cmp %l1, 0 | ||
85 | |||
86 | /* mm/ultra.S:xcall_report_regs KNOWS about this load. */ | 76 | /* mm/ultra.S:xcall_report_regs KNOWS about this load. */ |
87 | ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 | 77 | ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 |
88 | rtrap_xcall: | 78 | rtrap_xcall: |
89 | sethi %hi(0xf << 20), %l4 | 79 | sethi %hi(0xf << 20), %l4 |
90 | and %l1, %l4, %l4 | 80 | and %l1, %l4, %l4 |
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index d444468b27f6..c052313f4dc5 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c | |||
@@ -42,7 +42,6 @@ | |||
42 | #include <asm/vaddrs.h> | 42 | #include <asm/vaddrs.h> |
43 | #include <asm/mbus.h> | 43 | #include <asm/mbus.h> |
44 | #include <asm/idprom.h> | 44 | #include <asm/idprom.h> |
45 | #include <asm/machines.h> | ||
46 | #include <asm/cpudata.h> | 45 | #include <asm/cpudata.h> |
47 | #include <asm/setup.h> | 46 | #include <asm/setup.h> |
48 | #include <asm/cacheflush.h> | 47 | #include <asm/cacheflush.h> |
@@ -106,7 +105,6 @@ unsigned long cmdline_memory_size __initdata = 0; | |||
106 | 105 | ||
107 | /* which CPU booted us (0xff = not set) */ | 106 | /* which CPU booted us (0xff = not set) */ |
108 | unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */ | 107 | unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */ |
109 | unsigned char boot_cpu_id4; /* boot_cpu_id << 2 */ | ||
110 | 108 | ||
111 | static void | 109 | static void |
112 | prom_console_write(struct console *con, const char *s, unsigned n) | 110 | prom_console_write(struct console *con, const char *s, unsigned n) |
@@ -182,13 +180,6 @@ static void __init boot_flags_init(char *commands) | |||
182 | } | 180 | } |
183 | } | 181 | } |
184 | 182 | ||
185 | /* This routine will in the future do all the nasty prom stuff | ||
186 | * to probe for the mmu type and its parameters, etc. This will | ||
187 | * also be where SMP things happen. | ||
188 | */ | ||
189 | |||
190 | extern void sun4c_probe_vac(void); | ||
191 | |||
192 | extern unsigned short root_flags; | 183 | extern unsigned short root_flags; |
193 | extern unsigned short root_dev; | 184 | extern unsigned short root_dev; |
194 | extern unsigned short ram_flags; | 185 | extern unsigned short ram_flags; |
@@ -200,6 +191,52 @@ extern int root_mountflags; | |||
200 | 191 | ||
201 | char reboot_command[COMMAND_LINE_SIZE]; | 192 | char reboot_command[COMMAND_LINE_SIZE]; |
202 | 193 | ||
194 | struct cpuid_patch_entry { | ||
195 | unsigned int addr; | ||
196 | unsigned int sun4d[3]; | ||
197 | unsigned int leon[3]; | ||
198 | }; | ||
199 | extern struct cpuid_patch_entry __cpuid_patch, __cpuid_patch_end; | ||
200 | |||
201 | static void __init per_cpu_patch(void) | ||
202 | { | ||
203 | struct cpuid_patch_entry *p; | ||
204 | |||
205 | if (sparc_cpu_model == sun4m) { | ||
206 | /* Nothing to do, this is what the unpatched code | ||
207 | * targets. | ||
208 | */ | ||
209 | return; | ||
210 | } | ||
211 | |||
212 | p = &__cpuid_patch; | ||
213 | while (p < &__cpuid_patch_end) { | ||
214 | unsigned long addr = p->addr; | ||
215 | unsigned int *insns; | ||
216 | |||
217 | switch (sparc_cpu_model) { | ||
218 | case sun4d: | ||
219 | insns = &p->sun4d[0]; | ||
220 | break; | ||
221 | |||
222 | case sparc_leon: | ||
223 | insns = &p->leon[0]; | ||
224 | break; | ||
225 | default: | ||
226 | prom_printf("Unknown cpu type, halting.\n"); | ||
227 | prom_halt(); | ||
228 | } | ||
229 | *(unsigned int *) (addr + 0) = insns[0]; | ||
230 | flushi(addr + 0); | ||
231 | *(unsigned int *) (addr + 4) = insns[1]; | ||
232 | flushi(addr + 4); | ||
233 | *(unsigned int *) (addr + 8) = insns[2]; | ||
234 | flushi(addr + 8); | ||
235 | |||
236 | p++; | ||
237 | } | ||
238 | } | ||
239 | |||
203 | enum sparc_cpu sparc_cpu_model; | 240 | enum sparc_cpu sparc_cpu_model; |
204 | EXPORT_SYMBOL(sparc_cpu_model); | 241 | EXPORT_SYMBOL(sparc_cpu_model); |
205 | 242 | ||
@@ -225,10 +262,6 @@ void __init setup_arch(char **cmdline_p) | |||
225 | 262 | ||
226 | /* Set sparc_cpu_model */ | 263 | /* Set sparc_cpu_model */ |
227 | sparc_cpu_model = sun_unknown; | 264 | sparc_cpu_model = sun_unknown; |
228 | if (!strcmp(&cputypval[0], "sun4 ")) | ||
229 | sparc_cpu_model = sun4; | ||
230 | if (!strcmp(&cputypval[0], "sun4c")) | ||
231 | sparc_cpu_model = sun4c; | ||
232 | if (!strcmp(&cputypval[0], "sun4m")) | 265 | if (!strcmp(&cputypval[0], "sun4m")) |
233 | sparc_cpu_model = sun4m; | 266 | sparc_cpu_model = sun4m; |
234 | if (!strcmp(&cputypval[0], "sun4s")) | 267 | if (!strcmp(&cputypval[0], "sun4s")) |
@@ -244,12 +277,6 @@ void __init setup_arch(char **cmdline_p) | |||
244 | 277 | ||
245 | printk("ARCH: "); | 278 | printk("ARCH: "); |
246 | switch(sparc_cpu_model) { | 279 | switch(sparc_cpu_model) { |
247 | case sun4: | ||
248 | printk("SUN4\n"); | ||
249 | break; | ||
250 | case sun4c: | ||
251 | printk("SUN4C\n"); | ||
252 | break; | ||
253 | case sun4m: | 280 | case sun4m: |
254 | printk("SUN4M\n"); | 281 | printk("SUN4M\n"); |
255 | break; | 282 | break; |
@@ -275,8 +302,6 @@ void __init setup_arch(char **cmdline_p) | |||
275 | #endif | 302 | #endif |
276 | 303 | ||
277 | idprom_init(); | 304 | idprom_init(); |
278 | if (ARCH_SUN4C) | ||
279 | sun4c_probe_vac(); | ||
280 | load_mmu(); | 305 | load_mmu(); |
281 | 306 | ||
282 | phys_base = 0xffffffffUL; | 307 | phys_base = 0xffffffffUL; |
@@ -313,6 +338,9 @@ void __init setup_arch(char **cmdline_p) | |||
313 | init_mm.context = (unsigned long) NO_CONTEXT; | 338 | init_mm.context = (unsigned long) NO_CONTEXT; |
314 | init_task.thread.kregs = &fake_swapper_regs; | 339 | init_task.thread.kregs = &fake_swapper_regs; |
315 | 340 | ||
341 | /* Run-time patch instructions to match the cpu model */ | ||
342 | per_cpu_patch(); | ||
343 | |||
316 | paging_init(); | 344 | paging_init(); |
317 | 345 | ||
318 | smp_setup_cpu_possible_map(); | 346 | smp_setup_cpu_possible_map(); |
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 1e750e415d7a..ac8e66b50f07 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c | |||
@@ -217,12 +217,9 @@ segv: | |||
217 | /* Checks if the fp is valid */ | 217 | /* Checks if the fp is valid */ |
218 | static inline int invalid_frame_pointer(void __user *fp, int fplen) | 218 | static inline int invalid_frame_pointer(void __user *fp, int fplen) |
219 | { | 219 | { |
220 | if ((((unsigned long) fp) & 7) || | 220 | if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen)) |
221 | !__access_ok((unsigned long)fp, fplen) || | ||
222 | ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) && | ||
223 | ((unsigned long) fp < 0xe0000000 && (unsigned long) fp >= 0x20000000))) | ||
224 | return 1; | 221 | return 1; |
225 | 222 | ||
226 | return 0; | 223 | return 0; |
227 | } | 224 | } |
228 | 225 | ||
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c index f671e7fd6ddc..79db45e5134a 100644 --- a/arch/sparc/kernel/smp_32.c +++ b/arch/sparc/kernel/smp_32.c | |||
@@ -40,6 +40,8 @@ volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,}; | |||
40 | 40 | ||
41 | cpumask_t smp_commenced_mask = CPU_MASK_NONE; | 41 | cpumask_t smp_commenced_mask = CPU_MASK_NONE; |
42 | 42 | ||
43 | const struct sparc32_ipi_ops *sparc32_ipi_ops; | ||
44 | |||
43 | /* The only guaranteed locking primitive available on all Sparc | 45 | /* The only guaranteed locking primitive available on all Sparc |
44 | * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically | 46 | * processors is 'ldstub [%reg + immediate], %dest_reg' which atomically |
45 | * places the current byte at the effective address into dest_reg and | 47 | * places the current byte at the effective address into dest_reg and |
@@ -85,14 +87,6 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
85 | (bogosum/(5000/HZ))%100); | 87 | (bogosum/(5000/HZ))%100); |
86 | 88 | ||
87 | switch(sparc_cpu_model) { | 89 | switch(sparc_cpu_model) { |
88 | case sun4: | ||
89 | printk("SUN4\n"); | ||
90 | BUG(); | ||
91 | break; | ||
92 | case sun4c: | ||
93 | printk("SUN4C\n"); | ||
94 | BUG(); | ||
95 | break; | ||
96 | case sun4m: | 90 | case sun4m: |
97 | smp4m_smp_done(); | 91 | smp4m_smp_done(); |
98 | break; | 92 | break; |
@@ -132,7 +126,7 @@ void smp_send_reschedule(int cpu) | |||
132 | * a single CPU. The trap handler needs only to do trap entry/return | 126 | * a single CPU. The trap handler needs only to do trap entry/return |
133 | * to call schedule. | 127 | * to call schedule. |
134 | */ | 128 | */ |
135 | BTFIXUP_CALL(smp_ipi_resched)(cpu); | 129 | sparc32_ipi_ops->resched(cpu); |
136 | } | 130 | } |
137 | 131 | ||
138 | void smp_send_stop(void) | 132 | void smp_send_stop(void) |
@@ -142,7 +136,7 @@ void smp_send_stop(void) | |||
142 | void arch_send_call_function_single_ipi(int cpu) | 136 | void arch_send_call_function_single_ipi(int cpu) |
143 | { | 137 | { |
144 | /* trigger one IPI single call on one CPU */ | 138 | /* trigger one IPI single call on one CPU */ |
145 | BTFIXUP_CALL(smp_ipi_single)(cpu); | 139 | sparc32_ipi_ops->single(cpu); |
146 | } | 140 | } |
147 | 141 | ||
148 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) | 142 | void arch_send_call_function_ipi_mask(const struct cpumask *mask) |
@@ -151,7 +145,7 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask) | |||
151 | 145 | ||
152 | /* trigger IPI mask call on each CPU */ | 146 | /* trigger IPI mask call on each CPU */ |
153 | for_each_cpu(cpu, mask) | 147 | for_each_cpu(cpu, mask) |
154 | BTFIXUP_CALL(smp_ipi_mask_one)(cpu); | 148 | sparc32_ipi_ops->mask_one(cpu); |
155 | } | 149 | } |
156 | 150 | ||
157 | void smp_resched_interrupt(void) | 151 | void smp_resched_interrupt(void) |
@@ -179,150 +173,9 @@ void smp_call_function_interrupt(void) | |||
179 | irq_exit(); | 173 | irq_exit(); |
180 | } | 174 | } |
181 | 175 | ||
182 | void smp_flush_cache_all(void) | ||
183 | { | ||
184 | xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all)); | ||
185 | local_flush_cache_all(); | ||
186 | } | ||
187 | |||
188 | void smp_flush_tlb_all(void) | ||
189 | { | ||
190 | xc0((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_all)); | ||
191 | local_flush_tlb_all(); | ||
192 | } | ||
193 | |||
194 | void smp_flush_cache_mm(struct mm_struct *mm) | ||
195 | { | ||
196 | if(mm->context != NO_CONTEXT) { | ||
197 | cpumask_t cpu_mask; | ||
198 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
199 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
200 | if (!cpumask_empty(&cpu_mask)) | ||
201 | xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm); | ||
202 | local_flush_cache_mm(mm); | ||
203 | } | ||
204 | } | ||
205 | |||
206 | void smp_flush_tlb_mm(struct mm_struct *mm) | ||
207 | { | ||
208 | if(mm->context != NO_CONTEXT) { | ||
209 | cpumask_t cpu_mask; | ||
210 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
211 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
212 | if (!cpumask_empty(&cpu_mask)) { | ||
213 | xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm); | ||
214 | if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm) | ||
215 | cpumask_copy(mm_cpumask(mm), | ||
216 | cpumask_of(smp_processor_id())); | ||
217 | } | ||
218 | local_flush_tlb_mm(mm); | ||
219 | } | ||
220 | } | ||
221 | |||
222 | void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start, | ||
223 | unsigned long end) | ||
224 | { | ||
225 | struct mm_struct *mm = vma->vm_mm; | ||
226 | |||
227 | if (mm->context != NO_CONTEXT) { | ||
228 | cpumask_t cpu_mask; | ||
229 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
230 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
231 | if (!cpumask_empty(&cpu_mask)) | ||
232 | xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end); | ||
233 | local_flush_cache_range(vma, start, end); | ||
234 | } | ||
235 | } | ||
236 | |||
237 | void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | ||
238 | unsigned long end) | ||
239 | { | ||
240 | struct mm_struct *mm = vma->vm_mm; | ||
241 | |||
242 | if (mm->context != NO_CONTEXT) { | ||
243 | cpumask_t cpu_mask; | ||
244 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
245 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
246 | if (!cpumask_empty(&cpu_mask)) | ||
247 | xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end); | ||
248 | local_flush_tlb_range(vma, start, end); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page) | ||
253 | { | ||
254 | struct mm_struct *mm = vma->vm_mm; | ||
255 | |||
256 | if(mm->context != NO_CONTEXT) { | ||
257 | cpumask_t cpu_mask; | ||
258 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
259 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
260 | if (!cpumask_empty(&cpu_mask)) | ||
261 | xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page); | ||
262 | local_flush_cache_page(vma, page); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | ||
267 | { | ||
268 | struct mm_struct *mm = vma->vm_mm; | ||
269 | |||
270 | if(mm->context != NO_CONTEXT) { | ||
271 | cpumask_t cpu_mask; | ||
272 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
273 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
274 | if (!cpumask_empty(&cpu_mask)) | ||
275 | xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page); | ||
276 | local_flush_tlb_page(vma, page); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | void smp_flush_page_to_ram(unsigned long page) | ||
281 | { | ||
282 | /* Current theory is that those who call this are the one's | ||
283 | * who have just dirtied their cache with the pages contents | ||
284 | * in kernel space, therefore we only run this on local cpu. | ||
285 | * | ||
286 | * XXX This experiment failed, research further... -DaveM | ||
287 | */ | ||
288 | #if 1 | ||
289 | xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_to_ram), page); | ||
290 | #endif | ||
291 | local_flush_page_to_ram(page); | ||
292 | } | ||
293 | |||
294 | void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) | ||
295 | { | ||
296 | cpumask_t cpu_mask; | ||
297 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
298 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
299 | if (!cpumask_empty(&cpu_mask)) | ||
300 | xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr); | ||
301 | local_flush_sig_insns(mm, insn_addr); | ||
302 | } | ||
303 | |||
304 | extern unsigned int lvl14_resolution; | ||
305 | |||
306 | /* /proc/profile writes can call this, don't __init it please. */ | ||
307 | static DEFINE_SPINLOCK(prof_setup_lock); | ||
308 | |||
309 | int setup_profiling_timer(unsigned int multiplier) | 176 | int setup_profiling_timer(unsigned int multiplier) |
310 | { | 177 | { |
311 | int i; | 178 | return -EINVAL; |
312 | unsigned long flags; | ||
313 | |||
314 | /* Prevent level14 ticker IRQ flooding. */ | ||
315 | if((!multiplier) || (lvl14_resolution / multiplier) < 500) | ||
316 | return -EINVAL; | ||
317 | |||
318 | spin_lock_irqsave(&prof_setup_lock, flags); | ||
319 | for_each_possible_cpu(i) { | ||
320 | load_profile_irq(i, lvl14_resolution / multiplier); | ||
321 | prof_multiplier(i) = multiplier; | ||
322 | } | ||
323 | spin_unlock_irqrestore(&prof_setup_lock, flags); | ||
324 | |||
325 | return 0; | ||
326 | } | 179 | } |
327 | 180 | ||
328 | void __init smp_prepare_cpus(unsigned int max_cpus) | 181 | void __init smp_prepare_cpus(unsigned int max_cpus) |
@@ -345,14 +198,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
345 | smp_store_cpu_info(boot_cpu_id); | 198 | smp_store_cpu_info(boot_cpu_id); |
346 | 199 | ||
347 | switch(sparc_cpu_model) { | 200 | switch(sparc_cpu_model) { |
348 | case sun4: | ||
349 | printk("SUN4\n"); | ||
350 | BUG(); | ||
351 | break; | ||
352 | case sun4c: | ||
353 | printk("SUN4C\n"); | ||
354 | BUG(); | ||
355 | break; | ||
356 | case sun4m: | 201 | case sun4m: |
357 | smp4m_boot_cpus(); | 202 | smp4m_boot_cpus(); |
358 | break; | 203 | break; |
@@ -411,29 +256,21 @@ void __init smp_prepare_boot_cpu(void) | |||
411 | set_cpu_possible(cpuid, true); | 256 | set_cpu_possible(cpuid, true); |
412 | } | 257 | } |
413 | 258 | ||
414 | int __cpuinit __cpu_up(unsigned int cpu) | 259 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) |
415 | { | 260 | { |
416 | extern int __cpuinit smp4m_boot_one_cpu(int); | 261 | extern int __cpuinit smp4m_boot_one_cpu(int, struct task_struct *); |
417 | extern int __cpuinit smp4d_boot_one_cpu(int); | 262 | extern int __cpuinit smp4d_boot_one_cpu(int, struct task_struct *); |
418 | int ret=0; | 263 | int ret=0; |
419 | 264 | ||
420 | switch(sparc_cpu_model) { | 265 | switch(sparc_cpu_model) { |
421 | case sun4: | ||
422 | printk("SUN4\n"); | ||
423 | BUG(); | ||
424 | break; | ||
425 | case sun4c: | ||
426 | printk("SUN4C\n"); | ||
427 | BUG(); | ||
428 | break; | ||
429 | case sun4m: | 266 | case sun4m: |
430 | ret = smp4m_boot_one_cpu(cpu); | 267 | ret = smp4m_boot_one_cpu(cpu, tidle); |
431 | break; | 268 | break; |
432 | case sun4d: | 269 | case sun4d: |
433 | ret = smp4d_boot_one_cpu(cpu); | 270 | ret = smp4d_boot_one_cpu(cpu, tidle); |
434 | break; | 271 | break; |
435 | case sparc_leon: | 272 | case sparc_leon: |
436 | ret = leon_boot_one_cpu(cpu); | 273 | ret = leon_boot_one_cpu(cpu, tidle); |
437 | break; | 274 | break; |
438 | case sun4e: | 275 | case sun4e: |
439 | printk("SUN4E\n"); | 276 | printk("SUN4E\n"); |
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 3b1bd7c50164..f591598d92f6 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -343,21 +343,17 @@ extern unsigned long sparc64_cpu_startup; | |||
343 | */ | 343 | */ |
344 | static struct thread_info *cpu_new_thread = NULL; | 344 | static struct thread_info *cpu_new_thread = NULL; |
345 | 345 | ||
346 | static int __cpuinit smp_boot_one_cpu(unsigned int cpu) | 346 | static int __cpuinit smp_boot_one_cpu(unsigned int cpu, struct task_struct *idle) |
347 | { | 347 | { |
348 | unsigned long entry = | 348 | unsigned long entry = |
349 | (unsigned long)(&sparc64_cpu_startup); | 349 | (unsigned long)(&sparc64_cpu_startup); |
350 | unsigned long cookie = | 350 | unsigned long cookie = |
351 | (unsigned long)(&cpu_new_thread); | 351 | (unsigned long)(&cpu_new_thread); |
352 | struct task_struct *p; | ||
353 | void *descr = NULL; | 352 | void *descr = NULL; |
354 | int timeout, ret; | 353 | int timeout, ret; |
355 | 354 | ||
356 | p = fork_idle(cpu); | ||
357 | if (IS_ERR(p)) | ||
358 | return PTR_ERR(p); | ||
359 | callin_flag = 0; | 355 | callin_flag = 0; |
360 | cpu_new_thread = task_thread_info(p); | 356 | cpu_new_thread = task_thread_info(idle); |
361 | 357 | ||
362 | if (tlb_type == hypervisor) { | 358 | if (tlb_type == hypervisor) { |
363 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) | 359 | #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) |
@@ -1227,9 +1223,9 @@ void __devinit smp_fill_in_sib_core_maps(void) | |||
1227 | } | 1223 | } |
1228 | } | 1224 | } |
1229 | 1225 | ||
1230 | int __cpuinit __cpu_up(unsigned int cpu) | 1226 | int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle) |
1231 | { | 1227 | { |
1232 | int ret = smp_boot_one_cpu(cpu); | 1228 | int ret = smp_boot_one_cpu(cpu, tidle); |
1233 | 1229 | ||
1234 | if (!ret) { | 1230 | if (!ret) { |
1235 | cpumask_set_cpu(cpu, &smp_commenced_mask); | 1231 | cpumask_set_cpu(cpu, &smp_commenced_mask); |
diff --git a/arch/sparc/kernel/sparc_ksyms_32.c b/arch/sparc/kernel/sparc_ksyms_32.c index baeab8720237..e521c54560f9 100644 --- a/arch/sparc/kernel/sparc_ksyms_32.c +++ b/arch/sparc/kernel/sparc_ksyms_32.c | |||
@@ -28,19 +28,5 @@ EXPORT_SYMBOL(__ndelay); | |||
28 | EXPORT_SYMBOL(__ret_efault); | 28 | EXPORT_SYMBOL(__ret_efault); |
29 | EXPORT_SYMBOL(empty_zero_page); | 29 | EXPORT_SYMBOL(empty_zero_page); |
30 | 30 | ||
31 | /* Defined using magic */ | ||
32 | #ifndef CONFIG_SMP | ||
33 | EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32)); | ||
34 | #else | ||
35 | EXPORT_SYMBOL(BTFIXUP_CALL(__hard_smp_processor_id)); | ||
36 | #endif | ||
37 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_unlockarea)); | ||
38 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_lockarea)); | ||
39 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_sgl)); | ||
40 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_get_scsi_one)); | ||
41 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_sgl)); | ||
42 | EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one)); | ||
43 | EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached)); | ||
44 | |||
45 | /* Exporting a symbol from /init/main.c */ | 31 | /* Exporting a symbol from /init/main.c */ |
46 | EXPORT_SYMBOL(saved_command_line); | 32 | EXPORT_SYMBOL(saved_command_line); |
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c deleted file mode 100644 index f6bf25a2ff80..000000000000 --- a/arch/sparc/kernel/sun4c_irq.c +++ /dev/null | |||
@@ -1,264 +0,0 @@ | |||
1 | /* | ||
2 | * sun4c irq support | ||
3 | * | ||
4 | * djhr: Hacked out of irq.c into a CPU dependent version. | ||
5 | * | ||
6 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
7 | * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) | ||
8 | * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com) | ||
9 | * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/oplib.h> | ||
15 | #include <asm/timer.h> | ||
16 | #include <asm/irq.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #include "irq.h" | ||
20 | |||
21 | /* Sun4c interrupts are typically laid out as follows: | ||
22 | * | ||
23 | * 1 - Software interrupt, SBUS level 1 | ||
24 | * 2 - SBUS level 2 | ||
25 | * 3 - ESP SCSI, SBUS level 3 | ||
26 | * 4 - Software interrupt | ||
27 | * 5 - Lance ethernet, SBUS level 4 | ||
28 | * 6 - Software interrupt | ||
29 | * 7 - Graphics card, SBUS level 5 | ||
30 | * 8 - SBUS level 6 | ||
31 | * 9 - SBUS level 7 | ||
32 | * 10 - Counter timer | ||
33 | * 11 - Floppy | ||
34 | * 12 - Zilog uart | ||
35 | * 13 - CS4231 audio | ||
36 | * 14 - Profiling timer | ||
37 | * 15 - NMI | ||
38 | * | ||
39 | * The interrupt enable bits in the interrupt mask register are | ||
40 | * really only used to enable/disable the timer interrupts, and | ||
41 | * for signalling software interrupts. There is also a master | ||
42 | * interrupt enable bit in this register. | ||
43 | * | ||
44 | * Interrupts are enabled by setting the SUN4C_INT_* bits, they | ||
45 | * are disabled by clearing those bits. | ||
46 | */ | ||
47 | |||
48 | /* | ||
49 | * Bit field defines for the interrupt registers on various | ||
50 | * Sparc machines. | ||
51 | */ | ||
52 | |||
53 | /* The sun4c interrupt register. */ | ||
54 | #define SUN4C_INT_ENABLE 0x01 /* Allow interrupts. */ | ||
55 | #define SUN4C_INT_E14 0x80 /* Enable level 14 IRQ. */ | ||
56 | #define SUN4C_INT_E10 0x20 /* Enable level 10 IRQ. */ | ||
57 | #define SUN4C_INT_E8 0x10 /* Enable level 8 IRQ. */ | ||
58 | #define SUN4C_INT_E6 0x08 /* Enable level 6 IRQ. */ | ||
59 | #define SUN4C_INT_E4 0x04 /* Enable level 4 IRQ. */ | ||
60 | #define SUN4C_INT_E1 0x02 /* Enable level 1 IRQ. */ | ||
61 | |||
62 | /* | ||
63 | * Pointer to the interrupt enable byte | ||
64 | * Used by entry.S | ||
65 | */ | ||
66 | unsigned char __iomem *interrupt_enable; | ||
67 | |||
68 | static void sun4c_mask_irq(struct irq_data *data) | ||
69 | { | ||
70 | unsigned long mask = (unsigned long)data->chip_data; | ||
71 | |||
72 | if (mask) { | ||
73 | unsigned long flags; | ||
74 | |||
75 | local_irq_save(flags); | ||
76 | mask = sbus_readb(interrupt_enable) & ~mask; | ||
77 | sbus_writeb(mask, interrupt_enable); | ||
78 | local_irq_restore(flags); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void sun4c_unmask_irq(struct irq_data *data) | ||
83 | { | ||
84 | unsigned long mask = (unsigned long)data->chip_data; | ||
85 | |||
86 | if (mask) { | ||
87 | unsigned long flags; | ||
88 | |||
89 | local_irq_save(flags); | ||
90 | mask = sbus_readb(interrupt_enable) | mask; | ||
91 | sbus_writeb(mask, interrupt_enable); | ||
92 | local_irq_restore(flags); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | static unsigned int sun4c_startup_irq(struct irq_data *data) | ||
97 | { | ||
98 | irq_link(data->irq); | ||
99 | sun4c_unmask_irq(data); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void sun4c_shutdown_irq(struct irq_data *data) | ||
105 | { | ||
106 | sun4c_mask_irq(data); | ||
107 | irq_unlink(data->irq); | ||
108 | } | ||
109 | |||
110 | static struct irq_chip sun4c_irq = { | ||
111 | .name = "sun4c", | ||
112 | .irq_startup = sun4c_startup_irq, | ||
113 | .irq_shutdown = sun4c_shutdown_irq, | ||
114 | .irq_mask = sun4c_mask_irq, | ||
115 | .irq_unmask = sun4c_unmask_irq, | ||
116 | }; | ||
117 | |||
118 | static unsigned int sun4c_build_device_irq(struct platform_device *op, | ||
119 | unsigned int real_irq) | ||
120 | { | ||
121 | unsigned int irq; | ||
122 | |||
123 | if (real_irq >= 16) { | ||
124 | prom_printf("Bogus sun4c IRQ %u\n", real_irq); | ||
125 | prom_halt(); | ||
126 | } | ||
127 | |||
128 | irq = irq_alloc(real_irq, real_irq); | ||
129 | if (irq) { | ||
130 | unsigned long mask = 0UL; | ||
131 | |||
132 | switch (real_irq) { | ||
133 | case 1: | ||
134 | mask = SUN4C_INT_E1; | ||
135 | break; | ||
136 | case 8: | ||
137 | mask = SUN4C_INT_E8; | ||
138 | break; | ||
139 | case 10: | ||
140 | mask = SUN4C_INT_E10; | ||
141 | break; | ||
142 | case 14: | ||
143 | mask = SUN4C_INT_E14; | ||
144 | break; | ||
145 | default: | ||
146 | /* All the rest are either always enabled, | ||
147 | * or are for signalling software interrupts. | ||
148 | */ | ||
149 | break; | ||
150 | } | ||
151 | irq_set_chip_and_handler_name(irq, &sun4c_irq, | ||
152 | handle_level_irq, "level"); | ||
153 | irq_set_chip_data(irq, (void *)mask); | ||
154 | } | ||
155 | return irq; | ||
156 | } | ||
157 | |||
158 | struct sun4c_timer_info { | ||
159 | u32 l10_count; | ||
160 | u32 l10_limit; | ||
161 | u32 l14_count; | ||
162 | u32 l14_limit; | ||
163 | }; | ||
164 | |||
165 | static struct sun4c_timer_info __iomem *sun4c_timers; | ||
166 | |||
167 | static void sun4c_clear_clock_irq(void) | ||
168 | { | ||
169 | sbus_readl(&sun4c_timers->l10_limit); | ||
170 | } | ||
171 | |||
172 | static void sun4c_load_profile_irq(int cpu, unsigned int limit) | ||
173 | { | ||
174 | /* Errm.. not sure how to do this.. */ | ||
175 | } | ||
176 | |||
177 | static void __init sun4c_init_timers(irq_handler_t counter_fn) | ||
178 | { | ||
179 | const struct linux_prom_irqs *prom_irqs; | ||
180 | struct device_node *dp; | ||
181 | unsigned int irq; | ||
182 | const u32 *addr; | ||
183 | int err; | ||
184 | |||
185 | dp = of_find_node_by_name(NULL, "counter-timer"); | ||
186 | if (!dp) { | ||
187 | prom_printf("sun4c_init_timers: Unable to find counter-timer\n"); | ||
188 | prom_halt(); | ||
189 | } | ||
190 | |||
191 | addr = of_get_property(dp, "address", NULL); | ||
192 | if (!addr) { | ||
193 | prom_printf("sun4c_init_timers: No address property\n"); | ||
194 | prom_halt(); | ||
195 | } | ||
196 | |||
197 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; | ||
198 | |||
199 | prom_irqs = of_get_property(dp, "intr", NULL); | ||
200 | of_node_put(dp); | ||
201 | if (!prom_irqs) { | ||
202 | prom_printf("sun4c_init_timers: No intr property\n"); | ||
203 | prom_halt(); | ||
204 | } | ||
205 | |||
206 | /* Have the level 10 timer tick at 100HZ. We don't touch the | ||
207 | * level 14 timer limit since we are letting the prom handle | ||
208 | * them until we have a real console driver so L1-A works. | ||
209 | */ | ||
210 | sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); | ||
211 | |||
212 | master_l10_counter = &sun4c_timers->l10_count; | ||
213 | |||
214 | irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); | ||
215 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | ||
216 | if (err) { | ||
217 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); | ||
218 | prom_halt(); | ||
219 | } | ||
220 | |||
221 | /* disable timer interrupt */ | ||
222 | sun4c_mask_irq(irq_get_irq_data(irq)); | ||
223 | } | ||
224 | |||
225 | #ifdef CONFIG_SMP | ||
226 | static void sun4c_nop(void) | ||
227 | { | ||
228 | } | ||
229 | #endif | ||
230 | |||
231 | void __init sun4c_init_IRQ(void) | ||
232 | { | ||
233 | struct device_node *dp; | ||
234 | const u32 *addr; | ||
235 | |||
236 | dp = of_find_node_by_name(NULL, "interrupt-enable"); | ||
237 | if (!dp) { | ||
238 | prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n"); | ||
239 | prom_halt(); | ||
240 | } | ||
241 | |||
242 | addr = of_get_property(dp, "address", NULL); | ||
243 | of_node_put(dp); | ||
244 | if (!addr) { | ||
245 | prom_printf("sun4c_init_IRQ: No address property\n"); | ||
246 | prom_halt(); | ||
247 | } | ||
248 | |||
249 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; | ||
250 | |||
251 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); | ||
252 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); | ||
253 | |||
254 | sparc_irq_config.init_timers = sun4c_init_timers; | ||
255 | sparc_irq_config.build_device_irq = sun4c_build_device_irq; | ||
256 | |||
257 | #ifdef CONFIG_SMP | ||
258 | BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | ||
259 | BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | ||
260 | BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); | ||
261 | #endif | ||
262 | sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable); | ||
263 | /* Cannot enable interrupts until OBP ticker is disabled. */ | ||
264 | } | ||
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 1d13c5bda0b1..e490ac9327c7 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/sbi.h> | 15 | #include <asm/sbi.h> |
16 | #include <asm/cacheflush.h> | 16 | #include <asm/cacheflush.h> |
17 | #include <asm/setup.h> | 17 | #include <asm/setup.h> |
18 | #include <asm/oplib.h> | ||
18 | 19 | ||
19 | #include "kernel.h" | 20 | #include "kernel.h" |
20 | #include "irq.h" | 21 | #include "irq.h" |
@@ -243,19 +244,6 @@ struct irq_chip sun4d_irq = { | |||
243 | }; | 244 | }; |
244 | 245 | ||
245 | #ifdef CONFIG_SMP | 246 | #ifdef CONFIG_SMP |
246 | static void sun4d_set_cpu_int(int cpu, int level) | ||
247 | { | ||
248 | sun4d_send_ipi(cpu, level); | ||
249 | } | ||
250 | |||
251 | static void sun4d_clear_ipi(int cpu, int level) | ||
252 | { | ||
253 | } | ||
254 | |||
255 | static void sun4d_set_udt(int cpu) | ||
256 | { | ||
257 | } | ||
258 | |||
259 | /* Setup IRQ distribution scheme. */ | 247 | /* Setup IRQ distribution scheme. */ |
260 | void __init sun4d_distribute_irqs(void) | 248 | void __init sun4d_distribute_irqs(void) |
261 | { | 249 | { |
@@ -282,7 +270,8 @@ static void sun4d_clear_clock_irq(void) | |||
282 | 270 | ||
283 | static void sun4d_load_profile_irq(int cpu, unsigned int limit) | 271 | static void sun4d_load_profile_irq(int cpu, unsigned int limit) |
284 | { | 272 | { |
285 | bw_set_prof_limit(cpu, limit); | 273 | unsigned int value = limit ? timer_value(limit) : 0; |
274 | bw_set_prof_limit(cpu, value); | ||
286 | } | 275 | } |
287 | 276 | ||
288 | static void __init sun4d_load_profile_irqs(void) | 277 | static void __init sun4d_load_profile_irqs(void) |
@@ -418,12 +407,12 @@ static void __init sun4d_fixup_trap_table(void) | |||
418 | trap_table->inst_two = lvl14_save[1]; | 407 | trap_table->inst_two = lvl14_save[1]; |
419 | trap_table->inst_three = lvl14_save[2]; | 408 | trap_table->inst_three = lvl14_save[2]; |
420 | trap_table->inst_four = lvl14_save[3]; | 409 | trap_table->inst_four = lvl14_save[3]; |
421 | local_flush_cache_all(); | 410 | local_ops->cache_all(); |
422 | local_irq_restore(flags); | 411 | local_irq_restore(flags); |
423 | #endif | 412 | #endif |
424 | } | 413 | } |
425 | 414 | ||
426 | static void __init sun4d_init_timers(irq_handler_t counter_fn) | 415 | static void __init sun4d_init_timers(void) |
427 | { | 416 | { |
428 | struct device_node *dp; | 417 | struct device_node *dp; |
429 | struct resource res; | 418 | struct resource res; |
@@ -466,12 +455,20 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
466 | prom_halt(); | 455 | prom_halt(); |
467 | } | 456 | } |
468 | 457 | ||
469 | sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit); | 458 | #ifdef CONFIG_SMP |
459 | sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */ | ||
460 | #else | ||
461 | sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */ | ||
462 | sparc_config.features |= FEAT_L10_CLOCKEVENT; | ||
463 | #endif | ||
464 | sparc_config.features |= FEAT_L10_CLOCKSOURCE; | ||
465 | sbus_writel(timer_value(sparc_config.cs_period), | ||
466 | &sun4d_timers->l10_timer_limit); | ||
470 | 467 | ||
471 | master_l10_counter = &sun4d_timers->l10_cur_count; | 468 | master_l10_counter = &sun4d_timers->l10_cur_count; |
472 | 469 | ||
473 | irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ); | 470 | irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ); |
474 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | 471 | err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL); |
475 | if (err) { | 472 | if (err) { |
476 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", | 473 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", |
477 | err); | 474 | err); |
@@ -509,16 +506,11 @@ void __init sun4d_init_IRQ(void) | |||
509 | { | 506 | { |
510 | local_irq_disable(); | 507 | local_irq_disable(); |
511 | 508 | ||
512 | BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); | 509 | sparc_config.init_timers = sun4d_init_timers; |
513 | BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); | 510 | sparc_config.build_device_irq = sun4d_build_device_irq; |
511 | sparc_config.clock_rate = SBUS_CLOCK_RATE; | ||
512 | sparc_config.clear_clock_irq = sun4d_clear_clock_irq; | ||
513 | sparc_config.load_profile_irq = sun4d_load_profile_irq; | ||
514 | 514 | ||
515 | sparc_irq_config.init_timers = sun4d_init_timers; | ||
516 | sparc_irq_config.build_device_irq = sun4d_build_device_irq; | ||
517 | |||
518 | #ifdef CONFIG_SMP | ||
519 | BTFIXUPSET_CALL(set_cpu_int, sun4d_set_cpu_int, BTFIXUPCALL_NORM); | ||
520 | BTFIXUPSET_CALL(clear_cpu_int, sun4d_clear_ipi, BTFIXUPCALL_NOP); | ||
521 | BTFIXUPSET_CALL(set_irq_udt, sun4d_set_udt, BTFIXUPCALL_NOP); | ||
522 | #endif | ||
523 | /* Cannot enable interrupts until OBP ticker is disabled. */ | 515 | /* Cannot enable interrupts until OBP ticker is disabled. */ |
524 | } | 516 | } |
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 540b2fec09f0..ddaea31de586 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c | |||
@@ -6,16 +6,20 @@ | |||
6 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 6 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/clockchips.h> | ||
9 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
10 | #include <linux/profile.h> | 11 | #include <linux/profile.h> |
11 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
13 | #include <linux/sched.h> | ||
12 | #include <linux/cpu.h> | 14 | #include <linux/cpu.h> |
13 | 15 | ||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/switch_to.h> | ||
18 | #include <asm/tlbflush.h> | ||
19 | #include <asm/timer.h> | ||
20 | #include <asm/oplib.h> | ||
14 | #include <asm/sbi.h> | 21 | #include <asm/sbi.h> |
15 | #include <asm/mmu.h> | 22 | #include <asm/mmu.h> |
16 | #include <asm/tlbflush.h> | ||
17 | #include <asm/switch_to.h> | ||
18 | #include <asm/cacheflush.h> | ||
19 | 23 | ||
20 | #include "kernel.h" | 24 | #include "kernel.h" |
21 | #include "irq.h" | 25 | #include "irq.h" |
@@ -34,7 +38,6 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon | |||
34 | } | 38 | } |
35 | 39 | ||
36 | static void smp4d_ipi_init(void); | 40 | static void smp4d_ipi_init(void); |
37 | static void smp_setup_percpu_timer(void); | ||
38 | 41 | ||
39 | static unsigned char cpu_leds[32]; | 42 | static unsigned char cpu_leds[32]; |
40 | 43 | ||
@@ -49,7 +52,7 @@ static inline void show_leds(int cpuid) | |||
49 | 52 | ||
50 | void __cpuinit smp4d_callin(void) | 53 | void __cpuinit smp4d_callin(void) |
51 | { | 54 | { |
52 | int cpuid = hard_smp4d_processor_id(); | 55 | int cpuid = hard_smp_processor_id(); |
53 | unsigned long flags; | 56 | unsigned long flags; |
54 | 57 | ||
55 | /* Show we are alive */ | 58 | /* Show we are alive */ |
@@ -59,8 +62,8 @@ void __cpuinit smp4d_callin(void) | |||
59 | /* Enable level15 interrupt, disable level14 interrupt for now */ | 62 | /* Enable level15 interrupt, disable level14 interrupt for now */ |
60 | cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); | 63 | cc_set_imsk((cc_get_imsk() & ~0x8000) | 0x4000); |
61 | 64 | ||
62 | local_flush_cache_all(); | 65 | local_ops->cache_all(); |
63 | local_flush_tlb_all(); | 66 | local_ops->tlb_all(); |
64 | 67 | ||
65 | notify_cpu_starting(cpuid); | 68 | notify_cpu_starting(cpuid); |
66 | /* | 69 | /* |
@@ -70,17 +73,17 @@ void __cpuinit smp4d_callin(void) | |||
70 | * to call the scheduler code. | 73 | * to call the scheduler code. |
71 | */ | 74 | */ |
72 | /* Get our local ticker going. */ | 75 | /* Get our local ticker going. */ |
73 | smp_setup_percpu_timer(); | 76 | register_percpu_ce(cpuid); |
74 | 77 | ||
75 | calibrate_delay(); | 78 | calibrate_delay(); |
76 | smp_store_cpu_info(cpuid); | 79 | smp_store_cpu_info(cpuid); |
77 | local_flush_cache_all(); | 80 | local_ops->cache_all(); |
78 | local_flush_tlb_all(); | 81 | local_ops->tlb_all(); |
79 | 82 | ||
80 | /* Allow master to continue. */ | 83 | /* Allow master to continue. */ |
81 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); | 84 | sun4d_swap((unsigned long *)&cpu_callin_map[cpuid], 1); |
82 | local_flush_cache_all(); | 85 | local_ops->cache_all(); |
83 | local_flush_tlb_all(); | 86 | local_ops->tlb_all(); |
84 | 87 | ||
85 | while ((unsigned long)current_set[cpuid] < PAGE_OFFSET) | 88 | while ((unsigned long)current_set[cpuid] < PAGE_OFFSET) |
86 | barrier(); | 89 | barrier(); |
@@ -100,8 +103,8 @@ void __cpuinit smp4d_callin(void) | |||
100 | atomic_inc(&init_mm.mm_count); | 103 | atomic_inc(&init_mm.mm_count); |
101 | current->active_mm = &init_mm; | 104 | current->active_mm = &init_mm; |
102 | 105 | ||
103 | local_flush_cache_all(); | 106 | local_ops->cache_all(); |
104 | local_flush_tlb_all(); | 107 | local_ops->tlb_all(); |
105 | 108 | ||
106 | local_irq_enable(); /* We don't allow PIL 14 yet */ | 109 | local_irq_enable(); /* We don't allow PIL 14 yet */ |
107 | 110 | ||
@@ -123,22 +126,17 @@ void __init smp4d_boot_cpus(void) | |||
123 | smp4d_ipi_init(); | 126 | smp4d_ipi_init(); |
124 | if (boot_cpu_id) | 127 | if (boot_cpu_id) |
125 | current_set[0] = NULL; | 128 | current_set[0] = NULL; |
126 | smp_setup_percpu_timer(); | 129 | local_ops->cache_all(); |
127 | local_flush_cache_all(); | ||
128 | } | 130 | } |
129 | 131 | ||
130 | int __cpuinit smp4d_boot_one_cpu(int i) | 132 | int __cpuinit smp4d_boot_one_cpu(int i, struct task_struct *idle) |
131 | { | 133 | { |
132 | unsigned long *entry = &sun4d_cpu_startup; | 134 | unsigned long *entry = &sun4d_cpu_startup; |
133 | struct task_struct *p; | ||
134 | int timeout; | 135 | int timeout; |
135 | int cpu_node; | 136 | int cpu_node; |
136 | 137 | ||
137 | cpu_find_by_instance(i, &cpu_node, NULL); | 138 | cpu_find_by_instance(i, &cpu_node, NULL); |
138 | /* Cook up an idler for this guy. */ | 139 | current_set[i] = task_thread_info(idle); |
139 | p = fork_idle(i); | ||
140 | current_set[i] = task_thread_info(p); | ||
141 | |||
142 | /* | 140 | /* |
143 | * Initialize the contexts table | 141 | * Initialize the contexts table |
144 | * Since the call to prom_startcpu() trashes the structure, | 142 | * Since the call to prom_startcpu() trashes the structure, |
@@ -150,7 +148,7 @@ int __cpuinit smp4d_boot_one_cpu(int i) | |||
150 | 148 | ||
151 | /* whirrr, whirrr, whirrrrrrrrr... */ | 149 | /* whirrr, whirrr, whirrrrrrrrr... */ |
152 | printk(KERN_INFO "Starting CPU %d at %p\n", i, entry); | 150 | printk(KERN_INFO "Starting CPU %d at %p\n", i, entry); |
153 | local_flush_cache_all(); | 151 | local_ops->cache_all(); |
154 | prom_startcpu(cpu_node, | 152 | prom_startcpu(cpu_node, |
155 | &smp_penguin_ctable, 0, (char *)entry); | 153 | &smp_penguin_ctable, 0, (char *)entry); |
156 | 154 | ||
@@ -168,7 +166,7 @@ int __cpuinit smp4d_boot_one_cpu(int i) | |||
168 | return -ENODEV; | 166 | return -ENODEV; |
169 | 167 | ||
170 | } | 168 | } |
171 | local_flush_cache_all(); | 169 | local_ops->cache_all(); |
172 | return 0; | 170 | return 0; |
173 | } | 171 | } |
174 | 172 | ||
@@ -185,7 +183,7 @@ void __init smp4d_smp_done(void) | |||
185 | prev = &cpu_data(i).next; | 183 | prev = &cpu_data(i).next; |
186 | } | 184 | } |
187 | *prev = first; | 185 | *prev = first; |
188 | local_flush_cache_all(); | 186 | local_ops->cache_all(); |
189 | 187 | ||
190 | /* Ok, they are spinning and ready to go. */ | 188 | /* Ok, they are spinning and ready to go. */ |
191 | smp_processors_ready = 1; | 189 | smp_processors_ready = 1; |
@@ -233,7 +231,20 @@ void sun4d_ipi_interrupt(void) | |||
233 | } | 231 | } |
234 | } | 232 | } |
235 | 233 | ||
236 | static void smp4d_ipi_single(int cpu) | 234 | /* +-------+-------------+-----------+------------------------------------+ |
235 | * | bcast | devid | sid | levels mask | | ||
236 | * +-------+-------------+-----------+------------------------------------+ | ||
237 | * 31 30 23 22 15 14 0 | ||
238 | */ | ||
239 | #define IGEN_MESSAGE(bcast, devid, sid, levels) \ | ||
240 | (((bcast) << 31) | ((devid) << 23) | ((sid) << 15) | (levels)) | ||
241 | |||
242 | static void sun4d_send_ipi(int cpu, int level) | ||
243 | { | ||
244 | cc_set_igen(IGEN_MESSAGE(0, cpu << 3, 6 + ((level >> 1) & 7), 1 << (level - 1))); | ||
245 | } | ||
246 | |||
247 | static void sun4d_ipi_single(int cpu) | ||
237 | { | 248 | { |
238 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | 249 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); |
239 | 250 | ||
@@ -244,7 +255,7 @@ static void smp4d_ipi_single(int cpu) | |||
244 | sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); | 255 | sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); |
245 | } | 256 | } |
246 | 257 | ||
247 | static void smp4d_ipi_mask_one(int cpu) | 258 | static void sun4d_ipi_mask_one(int cpu) |
248 | { | 259 | { |
249 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | 260 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); |
250 | 261 | ||
@@ -255,7 +266,7 @@ static void smp4d_ipi_mask_one(int cpu) | |||
255 | sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); | 266 | sun4d_send_ipi(cpu, SUN4D_IPI_IRQ); |
256 | } | 267 | } |
257 | 268 | ||
258 | static void smp4d_ipi_resched(int cpu) | 269 | static void sun4d_ipi_resched(int cpu) |
259 | { | 270 | { |
260 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); | 271 | struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu); |
261 | 272 | ||
@@ -280,7 +291,7 @@ static struct smp_funcall { | |||
280 | static DEFINE_SPINLOCK(cross_call_lock); | 291 | static DEFINE_SPINLOCK(cross_call_lock); |
281 | 292 | ||
282 | /* Cross calls must be serialized, at least currently. */ | 293 | /* Cross calls must be serialized, at least currently. */ |
283 | static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | 294 | static void sun4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, |
284 | unsigned long arg2, unsigned long arg3, | 295 | unsigned long arg2, unsigned long arg3, |
285 | unsigned long arg4) | 296 | unsigned long arg4) |
286 | { | 297 | { |
@@ -352,7 +363,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
352 | /* Running cross calls. */ | 363 | /* Running cross calls. */ |
353 | void smp4d_cross_call_irq(void) | 364 | void smp4d_cross_call_irq(void) |
354 | { | 365 | { |
355 | int i = hard_smp4d_processor_id(); | 366 | int i = hard_smp_processor_id(); |
356 | 367 | ||
357 | ccall_info.processors_in[i] = 1; | 368 | ccall_info.processors_in[i] = 1; |
358 | ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, | 369 | ccall_info.func(ccall_info.arg1, ccall_info.arg2, ccall_info.arg3, |
@@ -363,7 +374,8 @@ void smp4d_cross_call_irq(void) | |||
363 | void smp4d_percpu_timer_interrupt(struct pt_regs *regs) | 374 | void smp4d_percpu_timer_interrupt(struct pt_regs *regs) |
364 | { | 375 | { |
365 | struct pt_regs *old_regs; | 376 | struct pt_regs *old_regs; |
366 | int cpu = hard_smp4d_processor_id(); | 377 | int cpu = hard_smp_processor_id(); |
378 | struct clock_event_device *ce; | ||
367 | static int cpu_tick[NR_CPUS]; | 379 | static int cpu_tick[NR_CPUS]; |
368 | static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; | 380 | static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd }; |
369 | 381 | ||
@@ -379,45 +391,21 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs) | |||
379 | show_leds(cpu); | 391 | show_leds(cpu); |
380 | } | 392 | } |
381 | 393 | ||
382 | profile_tick(CPU_PROFILING); | 394 | ce = &per_cpu(sparc32_clockevent, cpu); |
383 | |||
384 | if (!--prof_counter(cpu)) { | ||
385 | int user = user_mode(regs); | ||
386 | 395 | ||
387 | irq_enter(); | 396 | irq_enter(); |
388 | update_process_times(user); | 397 | ce->event_handler(ce); |
389 | irq_exit(); | 398 | irq_exit(); |
390 | 399 | ||
391 | prof_counter(cpu) = prof_multiplier(cpu); | ||
392 | } | ||
393 | set_irq_regs(old_regs); | 400 | set_irq_regs(old_regs); |
394 | } | 401 | } |
395 | 402 | ||
396 | static void __cpuinit smp_setup_percpu_timer(void) | 403 | static const struct sparc32_ipi_ops sun4d_ipi_ops = { |
397 | { | 404 | .cross_call = sun4d_cross_call, |
398 | int cpu = hard_smp4d_processor_id(); | 405 | .resched = sun4d_ipi_resched, |
399 | 406 | .single = sun4d_ipi_single, | |
400 | prof_counter(cpu) = prof_multiplier(cpu) = 1; | 407 | .mask_one = sun4d_ipi_mask_one, |
401 | load_profile_irq(cpu, lvl14_resolution); | 408 | }; |
402 | } | ||
403 | |||
404 | void __init smp4d_blackbox_id(unsigned *addr) | ||
405 | { | ||
406 | int rd = *addr & 0x3e000000; | ||
407 | |||
408 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ | ||
409 | addr[1] = 0x01000000; /* nop */ | ||
410 | addr[2] = 0x01000000; /* nop */ | ||
411 | } | ||
412 | |||
413 | void __init smp4d_blackbox_current(unsigned *addr) | ||
414 | { | ||
415 | int rd = *addr & 0x3e000000; | ||
416 | |||
417 | addr[0] = 0xc0800800 | rd; /* lda [%g0] ASI_M_VIKING_TMP1, reg */ | ||
418 | addr[2] = 0x81282002 | rd | (rd >> 11); /* sll reg, 2, reg */ | ||
419 | addr[4] = 0x01000000; /* nop */ | ||
420 | } | ||
421 | 409 | ||
422 | void __init sun4d_init_smp(void) | 410 | void __init sun4d_init_smp(void) |
423 | { | 411 | { |
@@ -426,14 +414,7 @@ void __init sun4d_init_smp(void) | |||
426 | /* Patch ipi15 trap table */ | 414 | /* Patch ipi15 trap table */ |
427 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m); | 415 | t_nmi[1] = t_nmi[1] + (linux_trap_ipi15_sun4d - linux_trap_ipi15_sun4m); |
428 | 416 | ||
429 | /* And set btfixup... */ | 417 | sparc32_ipi_ops = &sun4d_ipi_ops; |
430 | BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id); | ||
431 | BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current); | ||
432 | BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM); | ||
433 | BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM); | ||
434 | BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM); | ||
435 | BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM); | ||
436 | BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM); | ||
437 | 418 | ||
438 | for (i = 0; i < NR_CPUS; i++) { | 419 | for (i = 0; i < NR_CPUS; i++) { |
439 | ccall_info.processors_in[i] = 1; | 420 | ccall_info.processors_in[i] = 1; |
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index e61165161dd3..c5ade9d27a1d 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c | |||
@@ -112,9 +112,6 @@ struct sun4m_handler_data { | |||
112 | #define SUN4M_INT_E14 0x00000080 | 112 | #define SUN4M_INT_E14 0x00000080 |
113 | #define SUN4M_INT_E10 0x00080000 | 113 | #define SUN4M_INT_E10 0x00080000 |
114 | 114 | ||
115 | #define SUN4M_HARD_INT(x) (0x000000001 << (x)) | ||
116 | #define SUN4M_SOFT_INT(x) (0x000010000 << (x)) | ||
117 | |||
118 | #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ | 115 | #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ |
119 | #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ | 116 | #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ |
120 | #define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */ | 117 | #define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */ |
@@ -282,23 +279,6 @@ out: | |||
282 | return irq; | 279 | return irq; |
283 | } | 280 | } |
284 | 281 | ||
285 | #ifdef CONFIG_SMP | ||
286 | static void sun4m_send_ipi(int cpu, int level) | ||
287 | { | ||
288 | sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set); | ||
289 | } | ||
290 | |||
291 | static void sun4m_clear_ipi(int cpu, int level) | ||
292 | { | ||
293 | sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->clear); | ||
294 | } | ||
295 | |||
296 | static void sun4m_set_udt(int cpu) | ||
297 | { | ||
298 | sbus_writel(cpu, &sun4m_irq_global->interrupt_target); | ||
299 | } | ||
300 | #endif | ||
301 | |||
302 | struct sun4m_timer_percpu { | 282 | struct sun4m_timer_percpu { |
303 | u32 l14_limit; | 283 | u32 l14_limit; |
304 | u32 l14_count; | 284 | u32 l14_count; |
@@ -318,9 +298,6 @@ struct sun4m_timer_global { | |||
318 | 298 | ||
319 | static struct sun4m_timer_global __iomem *timers_global; | 299 | static struct sun4m_timer_global __iomem *timers_global; |
320 | 300 | ||
321 | |||
322 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); | ||
323 | |||
324 | static void sun4m_clear_clock_irq(void) | 301 | static void sun4m_clear_clock_irq(void) |
325 | { | 302 | { |
326 | sbus_readl(&timers_global->l10_limit); | 303 | sbus_readl(&timers_global->l10_limit); |
@@ -369,10 +346,11 @@ void sun4m_clear_profile_irq(int cpu) | |||
369 | 346 | ||
370 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) | 347 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) |
371 | { | 348 | { |
372 | sbus_writel(limit, &timers_percpu[cpu]->l14_limit); | 349 | unsigned int value = limit ? timer_value(limit) : 0; |
350 | sbus_writel(value, &timers_percpu[cpu]->l14_limit); | ||
373 | } | 351 | } |
374 | 352 | ||
375 | static void __init sun4m_init_timers(irq_handler_t counter_fn) | 353 | static void __init sun4m_init_timers(void) |
376 | { | 354 | { |
377 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); | 355 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); |
378 | int i, err, len, num_cpu_timers; | 356 | int i, err, len, num_cpu_timers; |
@@ -402,13 +380,22 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) | |||
402 | /* Every per-cpu timer works in timer mode */ | 380 | /* Every per-cpu timer works in timer mode */ |
403 | sbus_writel(0x00000000, &timers_global->timer_config); | 381 | sbus_writel(0x00000000, &timers_global->timer_config); |
404 | 382 | ||
405 | sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); | 383 | #ifdef CONFIG_SMP |
384 | sparc_config.cs_period = SBUS_CLOCK_RATE * 2; /* 2 seconds */ | ||
385 | sparc_config.features |= FEAT_L14_ONESHOT; | ||
386 | #else | ||
387 | sparc_config.cs_period = SBUS_CLOCK_RATE / HZ; /* 1/HZ sec */ | ||
388 | sparc_config.features |= FEAT_L10_CLOCKEVENT; | ||
389 | #endif | ||
390 | sparc_config.features |= FEAT_L10_CLOCKSOURCE; | ||
391 | sbus_writel(timer_value(sparc_config.cs_period), | ||
392 | &timers_global->l10_limit); | ||
406 | 393 | ||
407 | master_l10_counter = &timers_global->l10_count; | 394 | master_l10_counter = &timers_global->l10_count; |
408 | 395 | ||
409 | irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ); | 396 | irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ); |
410 | 397 | ||
411 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | 398 | err = request_irq(irq, timer_interrupt, IRQF_TIMER, "timer", NULL); |
412 | if (err) { | 399 | if (err) { |
413 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", | 400 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", |
414 | err); | 401 | err); |
@@ -434,7 +421,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) | |||
434 | trap_table->inst_two = lvl14_save[1]; | 421 | trap_table->inst_two = lvl14_save[1]; |
435 | trap_table->inst_three = lvl14_save[2]; | 422 | trap_table->inst_three = lvl14_save[2]; |
436 | trap_table->inst_four = lvl14_save[3]; | 423 | trap_table->inst_four = lvl14_save[3]; |
437 | local_flush_cache_all(); | 424 | local_ops->cache_all(); |
438 | local_irq_restore(flags); | 425 | local_irq_restore(flags); |
439 | } | 426 | } |
440 | #endif | 427 | #endif |
@@ -475,17 +462,12 @@ void __init sun4m_init_IRQ(void) | |||
475 | if (num_cpu_iregs == 4) | 462 | if (num_cpu_iregs == 4) |
476 | sbus_writel(0, &sun4m_irq_global->interrupt_target); | 463 | sbus_writel(0, &sun4m_irq_global->interrupt_target); |
477 | 464 | ||
478 | BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); | 465 | sparc_config.init_timers = sun4m_init_timers; |
479 | BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); | 466 | sparc_config.build_device_irq = sun4m_build_device_irq; |
480 | 467 | sparc_config.clock_rate = SBUS_CLOCK_RATE; | |
481 | sparc_irq_config.init_timers = sun4m_init_timers; | 468 | sparc_config.clear_clock_irq = sun4m_clear_clock_irq; |
482 | sparc_irq_config.build_device_irq = sun4m_build_device_irq; | 469 | sparc_config.load_profile_irq = sun4m_load_profile_irq; |
483 | 470 | ||
484 | #ifdef CONFIG_SMP | ||
485 | BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM); | ||
486 | BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); | ||
487 | BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); | ||
488 | #endif | ||
489 | 471 | ||
490 | /* Cannot enable interrupts until OBP ticker is disabled. */ | 472 | /* Cannot enable interrupts until OBP ticker is disabled. */ |
491 | } | 473 | } |
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 02db9a0412ce..128af7304288 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c | |||
@@ -4,14 +4,18 @@ | |||
4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/clockchips.h> | ||
7 | #include <linux/interrupt.h> | 8 | #include <linux/interrupt.h> |
8 | #include <linux/profile.h> | 9 | #include <linux/profile.h> |
9 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
11 | #include <linux/sched.h> | ||
10 | #include <linux/cpu.h> | 12 | #include <linux/cpu.h> |
11 | 13 | ||
12 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
13 | #include <asm/switch_to.h> | 15 | #include <asm/switch_to.h> |
14 | #include <asm/tlbflush.h> | 16 | #include <asm/tlbflush.h> |
17 | #include <asm/timer.h> | ||
18 | #include <asm/oplib.h> | ||
15 | 19 | ||
16 | #include "irq.h" | 20 | #include "irq.h" |
17 | #include "kernel.h" | 21 | #include "kernel.h" |
@@ -30,26 +34,22 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val) | |||
30 | return val; | 34 | return val; |
31 | } | 35 | } |
32 | 36 | ||
33 | static void smp4m_ipi_init(void); | ||
34 | static void smp_setup_percpu_timer(void); | ||
35 | |||
36 | void __cpuinit smp4m_callin(void) | 37 | void __cpuinit smp4m_callin(void) |
37 | { | 38 | { |
38 | int cpuid = hard_smp_processor_id(); | 39 | int cpuid = hard_smp_processor_id(); |
39 | 40 | ||
40 | local_flush_cache_all(); | 41 | local_ops->cache_all(); |
41 | local_flush_tlb_all(); | 42 | local_ops->tlb_all(); |
42 | 43 | ||
43 | notify_cpu_starting(cpuid); | 44 | notify_cpu_starting(cpuid); |
44 | 45 | ||
45 | /* Get our local ticker going. */ | 46 | register_percpu_ce(cpuid); |
46 | smp_setup_percpu_timer(); | ||
47 | 47 | ||
48 | calibrate_delay(); | 48 | calibrate_delay(); |
49 | smp_store_cpu_info(cpuid); | 49 | smp_store_cpu_info(cpuid); |
50 | 50 | ||
51 | local_flush_cache_all(); | 51 | local_ops->cache_all(); |
52 | local_flush_tlb_all(); | 52 | local_ops->tlb_all(); |
53 | 53 | ||
54 | /* | 54 | /* |
55 | * Unblock the master CPU _only_ when the scheduler state | 55 | * Unblock the master CPU _only_ when the scheduler state |
@@ -61,8 +61,8 @@ void __cpuinit smp4m_callin(void) | |||
61 | swap_ulong(&cpu_callin_map[cpuid], 1); | 61 | swap_ulong(&cpu_callin_map[cpuid], 1); |
62 | 62 | ||
63 | /* XXX: What's up with all the flushes? */ | 63 | /* XXX: What's up with all the flushes? */ |
64 | local_flush_cache_all(); | 64 | local_ops->cache_all(); |
65 | local_flush_tlb_all(); | 65 | local_ops->tlb_all(); |
66 | 66 | ||
67 | /* Fix idle thread fields. */ | 67 | /* Fix idle thread fields. */ |
68 | __asm__ __volatile__("ld [%0], %%g6\n\t" | 68 | __asm__ __volatile__("ld [%0], %%g6\n\t" |
@@ -86,23 +86,19 @@ void __cpuinit smp4m_callin(void) | |||
86 | */ | 86 | */ |
87 | void __init smp4m_boot_cpus(void) | 87 | void __init smp4m_boot_cpus(void) |
88 | { | 88 | { |
89 | smp4m_ipi_init(); | 89 | sun4m_unmask_profile_irq(); |
90 | smp_setup_percpu_timer(); | 90 | local_ops->cache_all(); |
91 | local_flush_cache_all(); | ||
92 | } | 91 | } |
93 | 92 | ||
94 | int __cpuinit smp4m_boot_one_cpu(int i) | 93 | int __cpuinit smp4m_boot_one_cpu(int i, struct task_struct *idle) |
95 | { | 94 | { |
96 | unsigned long *entry = &sun4m_cpu_startup; | 95 | unsigned long *entry = &sun4m_cpu_startup; |
97 | struct task_struct *p; | ||
98 | int timeout; | 96 | int timeout; |
99 | int cpu_node; | 97 | int cpu_node; |
100 | 98 | ||
101 | cpu_find_by_mid(i, &cpu_node); | 99 | cpu_find_by_mid(i, &cpu_node); |
100 | current_set[i] = task_thread_info(idle); | ||
102 | 101 | ||
103 | /* Cook up an idler for this guy. */ | ||
104 | p = fork_idle(i); | ||
105 | current_set[i] = task_thread_info(p); | ||
106 | /* See trampoline.S for details... */ | 102 | /* See trampoline.S for details... */ |
107 | entry += ((i - 1) * 3); | 103 | entry += ((i - 1) * 3); |
108 | 104 | ||
@@ -117,7 +113,7 @@ int __cpuinit smp4m_boot_one_cpu(int i) | |||
117 | 113 | ||
118 | /* whirrr, whirrr, whirrrrrrrrr... */ | 114 | /* whirrr, whirrr, whirrrrrrrrr... */ |
119 | printk(KERN_INFO "Starting CPU %d at %p\n", i, entry); | 115 | printk(KERN_INFO "Starting CPU %d at %p\n", i, entry); |
120 | local_flush_cache_all(); | 116 | local_ops->cache_all(); |
121 | prom_startcpu(cpu_node, &smp_penguin_ctable, 0, (char *)entry); | 117 | prom_startcpu(cpu_node, &smp_penguin_ctable, 0, (char *)entry); |
122 | 118 | ||
123 | /* wheee... it's going... */ | 119 | /* wheee... it's going... */ |
@@ -132,7 +128,7 @@ int __cpuinit smp4m_boot_one_cpu(int i) | |||
132 | return -ENODEV; | 128 | return -ENODEV; |
133 | } | 129 | } |
134 | 130 | ||
135 | local_flush_cache_all(); | 131 | local_ops->cache_all(); |
136 | return 0; | 132 | return 0; |
137 | } | 133 | } |
138 | 134 | ||
@@ -149,30 +145,29 @@ void __init smp4m_smp_done(void) | |||
149 | prev = &cpu_data(i).next; | 145 | prev = &cpu_data(i).next; |
150 | } | 146 | } |
151 | *prev = first; | 147 | *prev = first; |
152 | local_flush_cache_all(); | 148 | local_ops->cache_all(); |
153 | 149 | ||
154 | /* Ok, they are spinning and ready to go. */ | 150 | /* Ok, they are spinning and ready to go. */ |
155 | } | 151 | } |
156 | 152 | ||
157 | 153 | static void sun4m_send_ipi(int cpu, int level) | |
158 | /* Initialize IPIs on the SUN4M SMP machine */ | ||
159 | static void __init smp4m_ipi_init(void) | ||
160 | { | 154 | { |
155 | sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set); | ||
161 | } | 156 | } |
162 | 157 | ||
163 | static void smp4m_ipi_resched(int cpu) | 158 | static void sun4m_ipi_resched(int cpu) |
164 | { | 159 | { |
165 | set_cpu_int(cpu, IRQ_IPI_RESCHED); | 160 | sun4m_send_ipi(cpu, IRQ_IPI_RESCHED); |
166 | } | 161 | } |
167 | 162 | ||
168 | static void smp4m_ipi_single(int cpu) | 163 | static void sun4m_ipi_single(int cpu) |
169 | { | 164 | { |
170 | set_cpu_int(cpu, IRQ_IPI_SINGLE); | 165 | sun4m_send_ipi(cpu, IRQ_IPI_SINGLE); |
171 | } | 166 | } |
172 | 167 | ||
173 | static void smp4m_ipi_mask_one(int cpu) | 168 | static void sun4m_ipi_mask_one(int cpu) |
174 | { | 169 | { |
175 | set_cpu_int(cpu, IRQ_IPI_MASK); | 170 | sun4m_send_ipi(cpu, IRQ_IPI_MASK); |
176 | } | 171 | } |
177 | 172 | ||
178 | static struct smp_funcall { | 173 | static struct smp_funcall { |
@@ -189,7 +184,7 @@ static struct smp_funcall { | |||
189 | static DEFINE_SPINLOCK(cross_call_lock); | 184 | static DEFINE_SPINLOCK(cross_call_lock); |
190 | 185 | ||
191 | /* Cross calls must be serialized, at least currently. */ | 186 | /* Cross calls must be serialized, at least currently. */ |
192 | static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | 187 | static void sun4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, |
193 | unsigned long arg2, unsigned long arg3, | 188 | unsigned long arg2, unsigned long arg3, |
194 | unsigned long arg4) | 189 | unsigned long arg4) |
195 | { | 190 | { |
@@ -216,7 +211,7 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1, | |||
216 | if (cpumask_test_cpu(i, &mask)) { | 211 | if (cpumask_test_cpu(i, &mask)) { |
217 | ccall_info.processors_in[i] = 0; | 212 | ccall_info.processors_in[i] = 0; |
218 | ccall_info.processors_out[i] = 0; | 213 | ccall_info.processors_out[i] = 0; |
219 | set_cpu_int(i, IRQ_CROSS_CALL); | 214 | sun4m_send_ipi(i, IRQ_CROSS_CALL); |
220 | } else { | 215 | } else { |
221 | ccall_info.processors_in[i] = 1; | 216 | ccall_info.processors_in[i] = 1; |
222 | ccall_info.processors_out[i] = 1; | 217 | ccall_info.processors_out[i] = 1; |
@@ -260,64 +255,33 @@ void smp4m_cross_call_irq(void) | |||
260 | void smp4m_percpu_timer_interrupt(struct pt_regs *regs) | 255 | void smp4m_percpu_timer_interrupt(struct pt_regs *regs) |
261 | { | 256 | { |
262 | struct pt_regs *old_regs; | 257 | struct pt_regs *old_regs; |
258 | struct clock_event_device *ce; | ||
263 | int cpu = smp_processor_id(); | 259 | int cpu = smp_processor_id(); |
264 | 260 | ||
265 | old_regs = set_irq_regs(regs); | 261 | old_regs = set_irq_regs(regs); |
266 | 262 | ||
267 | sun4m_clear_profile_irq(cpu); | 263 | ce = &per_cpu(sparc32_clockevent, cpu); |
268 | |||
269 | profile_tick(CPU_PROFILING); | ||
270 | 264 | ||
271 | if (!--prof_counter(cpu)) { | 265 | if (ce->mode & CLOCK_EVT_MODE_PERIODIC) |
272 | int user = user_mode(regs); | 266 | sun4m_clear_profile_irq(cpu); |
267 | else | ||
268 | sparc_config.load_profile_irq(cpu, 0); /* Is this needless? */ | ||
273 | 269 | ||
274 | irq_enter(); | 270 | irq_enter(); |
275 | update_process_times(user); | 271 | ce->event_handler(ce); |
276 | irq_exit(); | 272 | irq_exit(); |
277 | 273 | ||
278 | prof_counter(cpu) = prof_multiplier(cpu); | ||
279 | } | ||
280 | set_irq_regs(old_regs); | 274 | set_irq_regs(old_regs); |
281 | } | 275 | } |
282 | 276 | ||
283 | static void __cpuinit smp_setup_percpu_timer(void) | 277 | static const struct sparc32_ipi_ops sun4m_ipi_ops = { |
284 | { | 278 | .cross_call = sun4m_cross_call, |
285 | int cpu = smp_processor_id(); | 279 | .resched = sun4m_ipi_resched, |
286 | 280 | .single = sun4m_ipi_single, | |
287 | prof_counter(cpu) = prof_multiplier(cpu) = 1; | 281 | .mask_one = sun4m_ipi_mask_one, |
288 | load_profile_irq(cpu, lvl14_resolution); | 282 | }; |
289 | |||
290 | if (cpu == boot_cpu_id) | ||
291 | sun4m_unmask_profile_irq(); | ||
292 | } | ||
293 | |||
294 | static void __init smp4m_blackbox_id(unsigned *addr) | ||
295 | { | ||
296 | int rd = *addr & 0x3e000000; | ||
297 | int rs1 = rd >> 11; | ||
298 | |||
299 | addr[0] = 0x81580000 | rd; /* rd %tbr, reg */ | ||
300 | addr[1] = 0x8130200c | rd | rs1; /* srl reg, 0xc, reg */ | ||
301 | addr[2] = 0x80082003 | rd | rs1; /* and reg, 3, reg */ | ||
302 | } | ||
303 | |||
304 | static void __init smp4m_blackbox_current(unsigned *addr) | ||
305 | { | ||
306 | int rd = *addr & 0x3e000000; | ||
307 | int rs1 = rd >> 11; | ||
308 | |||
309 | addr[0] = 0x81580000 | rd; /* rd %tbr, reg */ | ||
310 | addr[2] = 0x8130200a | rd | rs1; /* srl reg, 0xa, reg */ | ||
311 | addr[4] = 0x8008200c | rd | rs1; /* and reg, 0xc, reg */ | ||
312 | } | ||
313 | 283 | ||
314 | void __init sun4m_init_smp(void) | 284 | void __init sun4m_init_smp(void) |
315 | { | 285 | { |
316 | BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4m_blackbox_id); | 286 | sparc32_ipi_ops = &sun4m_ipi_ops; |
317 | BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current); | ||
318 | BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM); | ||
319 | BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM); | ||
320 | BTFIXUPSET_CALL(smp_ipi_resched, smp4m_ipi_resched, BTFIXUPCALL_NORM); | ||
321 | BTFIXUPSET_CALL(smp_ipi_single, smp4m_ipi_single, BTFIXUPCALL_NORM); | ||
322 | BTFIXUPSET_CALL(smp_ipi_mask_one, smp4m_ipi_mask_one, BTFIXUPCALL_NORM); | ||
323 | } | 287 | } |
diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 42b282fa6112..627e89af1d71 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c | |||
@@ -53,8 +53,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
53 | /* See asm-sparc/uaccess.h */ | 53 | /* See asm-sparc/uaccess.h */ |
54 | if (len > TASK_SIZE - PAGE_SIZE) | 54 | if (len > TASK_SIZE - PAGE_SIZE) |
55 | return -ENOMEM; | 55 | return -ENOMEM; |
56 | if (ARCH_SUN4C && len > 0x20000000) | ||
57 | return -ENOMEM; | ||
58 | if (!addr) | 56 | if (!addr) |
59 | addr = TASK_UNMAPPED_BASE; | 57 | addr = TASK_UNMAPPED_BASE; |
60 | 58 | ||
@@ -65,10 +63,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
65 | 63 | ||
66 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { | 64 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { |
67 | /* At this point: (!vmm || addr < vmm->vm_end). */ | 65 | /* At this point: (!vmm || addr < vmm->vm_end). */ |
68 | if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) { | ||
69 | addr = PAGE_OFFSET; | ||
70 | vmm = find_vma(current->mm, PAGE_OFFSET); | ||
71 | } | ||
72 | if (TASK_SIZE - PAGE_SIZE - len < addr) | 66 | if (TASK_SIZE - PAGE_SIZE - len < addr) |
73 | return -ENOMEM; | 67 | return -ENOMEM; |
74 | if (!vmm || addr + len <= vmm->vm_start) | 68 | if (!vmm || addr + len <= vmm->vm_start) |
@@ -99,11 +93,6 @@ out: | |||
99 | 93 | ||
100 | int sparc_mmap_check(unsigned long addr, unsigned long len) | 94 | int sparc_mmap_check(unsigned long addr, unsigned long len) |
101 | { | 95 | { |
102 | if (ARCH_SUN4C && | ||
103 | (len > 0x20000000 || | ||
104 | (addr < 0xe0000000 && addr + len > 0x20000000))) | ||
105 | return -EINVAL; | ||
106 | |||
107 | /* See asm-sparc/uaccess.h */ | 96 | /* See asm-sparc/uaccess.h */ |
108 | if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE) | 97 | if (len > TASK_SIZE - PAGE_SIZE || addr + len > TASK_SIZE - PAGE_SIZE) |
109 | return -EINVAL; | 98 | return -EINVAL; |
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S index db86b1a0e9a9..3a58e0d66f51 100644 --- a/arch/sparc/kernel/systbls_64.S +++ b/arch/sparc/kernel/systbls_64.S | |||
@@ -74,7 +74,7 @@ sys_call_table32: | |||
74 | .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy | 74 | .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy |
75 | /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink | 75 | /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink |
76 | .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid | 76 | .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid |
77 | /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat | 77 | /*280*/ .word sys32_tee, sys_add_key, sys_request_key, compat_sys_keyctl, compat_sys_openat |
78 | .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 | 78 | .word sys_mkdirat, sys_mknodat, sys_fchownat, compat_sys_futimesat, compat_sys_fstatat64 |
79 | /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat | 79 | /*290*/ .word sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat |
80 | .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare | 80 | .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare |
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c index 7d0c088e8aba..953641549e82 100644 --- a/arch/sparc/kernel/time_32.c +++ b/arch/sparc/kernel/time_32.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/rtc.h> | 26 | #include <linux/rtc.h> |
27 | #include <linux/rtc/m48t59.h> | 27 | #include <linux/rtc/m48t59.h> |
28 | #include <linux/timex.h> | 28 | #include <linux/timex.h> |
29 | #include <linux/clocksource.h> | ||
30 | #include <linux/clockchips.h> | ||
29 | #include <linux/init.h> | 31 | #include <linux/init.h> |
30 | #include <linux/pci.h> | 32 | #include <linux/pci.h> |
31 | #include <linux/ioport.h> | 33 | #include <linux/ioport.h> |
@@ -40,13 +42,24 @@ | |||
40 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
41 | #include <asm/io.h> | 43 | #include <asm/io.h> |
42 | #include <asm/idprom.h> | 44 | #include <asm/idprom.h> |
43 | #include <asm/machines.h> | ||
44 | #include <asm/page.h> | 45 | #include <asm/page.h> |
45 | #include <asm/pcic.h> | 46 | #include <asm/pcic.h> |
46 | #include <asm/irq_regs.h> | 47 | #include <asm/irq_regs.h> |
48 | #include <asm/setup.h> | ||
47 | 49 | ||
48 | #include "irq.h" | 50 | #include "irq.h" |
49 | 51 | ||
52 | static __cacheline_aligned_in_smp DEFINE_SEQLOCK(timer_cs_lock); | ||
53 | static __volatile__ u64 timer_cs_internal_counter = 0; | ||
54 | static char timer_cs_enabled = 0; | ||
55 | |||
56 | static struct clock_event_device timer_ce; | ||
57 | static char timer_ce_enabled = 0; | ||
58 | |||
59 | #ifdef CONFIG_SMP | ||
60 | DEFINE_PER_CPU(struct clock_event_device, sparc32_clockevent); | ||
61 | #endif | ||
62 | |||
50 | DEFINE_SPINLOCK(rtc_lock); | 63 | DEFINE_SPINLOCK(rtc_lock); |
51 | EXPORT_SYMBOL(rtc_lock); | 64 | EXPORT_SYMBOL(rtc_lock); |
52 | 65 | ||
@@ -55,7 +68,6 @@ static int set_rtc_mmss(unsigned long); | |||
55 | unsigned long profile_pc(struct pt_regs *regs) | 68 | unsigned long profile_pc(struct pt_regs *regs) |
56 | { | 69 | { |
57 | extern char __copy_user_begin[], __copy_user_end[]; | 70 | extern char __copy_user_begin[], __copy_user_end[]; |
58 | extern char __atomic_begin[], __atomic_end[]; | ||
59 | extern char __bzero_begin[], __bzero_end[]; | 71 | extern char __bzero_begin[], __bzero_end[]; |
60 | 72 | ||
61 | unsigned long pc = regs->pc; | 73 | unsigned long pc = regs->pc; |
@@ -63,8 +75,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
63 | if (in_lock_functions(pc) || | 75 | if (in_lock_functions(pc) || |
64 | (pc >= (unsigned long) __copy_user_begin && | 76 | (pc >= (unsigned long) __copy_user_begin && |
65 | pc < (unsigned long) __copy_user_end) || | 77 | pc < (unsigned long) __copy_user_end) || |
66 | (pc >= (unsigned long) __atomic_begin && | ||
67 | pc < (unsigned long) __atomic_end) || | ||
68 | (pc >= (unsigned long) __bzero_begin && | 78 | (pc >= (unsigned long) __bzero_begin && |
69 | pc < (unsigned long) __bzero_end)) | 79 | pc < (unsigned long) __bzero_end)) |
70 | pc = regs->u_regs[UREG_RETPC]; | 80 | pc = regs->u_regs[UREG_RETPC]; |
@@ -75,36 +85,168 @@ EXPORT_SYMBOL(profile_pc); | |||
75 | 85 | ||
76 | __volatile__ unsigned int *master_l10_counter; | 86 | __volatile__ unsigned int *master_l10_counter; |
77 | 87 | ||
78 | u32 (*do_arch_gettimeoffset)(void); | ||
79 | |||
80 | int update_persistent_clock(struct timespec now) | 88 | int update_persistent_clock(struct timespec now) |
81 | { | 89 | { |
82 | return set_rtc_mmss(now.tv_sec); | 90 | return set_rtc_mmss(now.tv_sec); |
83 | } | 91 | } |
84 | 92 | ||
85 | /* | 93 | irqreturn_t notrace timer_interrupt(int dummy, void *dev_id) |
86 | * timer_interrupt() needs to keep up the real-time clock, | 94 | { |
87 | * as well as call the "xtime_update()" routine every clocktick | 95 | if (timer_cs_enabled) { |
88 | */ | 96 | write_seqlock(&timer_cs_lock); |
97 | timer_cs_internal_counter++; | ||
98 | sparc_config.clear_clock_irq(); | ||
99 | write_sequnlock(&timer_cs_lock); | ||
100 | } else { | ||
101 | sparc_config.clear_clock_irq(); | ||
102 | } | ||
89 | 103 | ||
90 | #define TICK_SIZE (tick_nsec / 1000) | 104 | if (timer_ce_enabled) |
105 | timer_ce.event_handler(&timer_ce); | ||
91 | 106 | ||
92 | static irqreturn_t timer_interrupt(int dummy, void *dev_id) | 107 | return IRQ_HANDLED; |
108 | } | ||
109 | |||
110 | static void timer_ce_set_mode(enum clock_event_mode mode, | ||
111 | struct clock_event_device *evt) | ||
93 | { | 112 | { |
94 | #ifndef CONFIG_SMP | 113 | switch (mode) { |
95 | profile_tick(CPU_PROFILING); | 114 | case CLOCK_EVT_MODE_PERIODIC: |
96 | #endif | 115 | case CLOCK_EVT_MODE_RESUME: |
116 | timer_ce_enabled = 1; | ||
117 | break; | ||
118 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
119 | timer_ce_enabled = 0; | ||
120 | break; | ||
121 | default: | ||
122 | break; | ||
123 | } | ||
124 | smp_mb(); | ||
125 | } | ||
97 | 126 | ||
98 | clear_clock_irq(); | 127 | static __init void setup_timer_ce(void) |
128 | { | ||
129 | struct clock_event_device *ce = &timer_ce; | ||
130 | |||
131 | BUG_ON(smp_processor_id() != boot_cpu_id); | ||
132 | |||
133 | ce->name = "timer_ce"; | ||
134 | ce->rating = 100; | ||
135 | ce->features = CLOCK_EVT_FEAT_PERIODIC; | ||
136 | ce->set_mode = timer_ce_set_mode; | ||
137 | ce->cpumask = cpu_possible_mask; | ||
138 | ce->shift = 32; | ||
139 | ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC, | ||
140 | ce->shift); | ||
141 | clockevents_register_device(ce); | ||
142 | } | ||
99 | 143 | ||
100 | xtime_update(1); | 144 | static unsigned int sbus_cycles_offset(void) |
145 | { | ||
146 | unsigned int val, offset; | ||
101 | 147 | ||
102 | #ifndef CONFIG_SMP | 148 | val = *master_l10_counter; |
103 | update_process_times(user_mode(get_irq_regs())); | 149 | offset = (val >> TIMER_VALUE_SHIFT) & TIMER_VALUE_MASK; |
104 | #endif | 150 | |
105 | return IRQ_HANDLED; | 151 | /* Limit hit? */ |
152 | if (val & TIMER_LIMIT_BIT) | ||
153 | offset += sparc_config.cs_period; | ||
154 | |||
155 | return offset; | ||
156 | } | ||
157 | |||
158 | static cycle_t timer_cs_read(struct clocksource *cs) | ||
159 | { | ||
160 | unsigned int seq, offset; | ||
161 | u64 cycles; | ||
162 | |||
163 | do { | ||
164 | seq = read_seqbegin(&timer_cs_lock); | ||
165 | |||
166 | cycles = timer_cs_internal_counter; | ||
167 | offset = sparc_config.get_cycles_offset(); | ||
168 | } while (read_seqretry(&timer_cs_lock, seq)); | ||
169 | |||
170 | /* Count absolute cycles */ | ||
171 | cycles *= sparc_config.cs_period; | ||
172 | cycles += offset; | ||
173 | |||
174 | return cycles; | ||
175 | } | ||
176 | |||
177 | static struct clocksource timer_cs = { | ||
178 | .name = "timer_cs", | ||
179 | .rating = 100, | ||
180 | .read = timer_cs_read, | ||
181 | .mask = CLOCKSOURCE_MASK(64), | ||
182 | .shift = 2, | ||
183 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
184 | }; | ||
185 | |||
186 | static __init int setup_timer_cs(void) | ||
187 | { | ||
188 | timer_cs_enabled = 1; | ||
189 | timer_cs.mult = clocksource_hz2mult(sparc_config.clock_rate, | ||
190 | timer_cs.shift); | ||
191 | |||
192 | return clocksource_register(&timer_cs); | ||
106 | } | 193 | } |
107 | 194 | ||
195 | #ifdef CONFIG_SMP | ||
196 | static void percpu_ce_setup(enum clock_event_mode mode, | ||
197 | struct clock_event_device *evt) | ||
198 | { | ||
199 | int cpu = __first_cpu(evt->cpumask); | ||
200 | |||
201 | switch (mode) { | ||
202 | case CLOCK_EVT_MODE_PERIODIC: | ||
203 | sparc_config.load_profile_irq(cpu, | ||
204 | SBUS_CLOCK_RATE / HZ); | ||
205 | break; | ||
206 | case CLOCK_EVT_MODE_ONESHOT: | ||
207 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
208 | case CLOCK_EVT_MODE_UNUSED: | ||
209 | sparc_config.load_profile_irq(cpu, 0); | ||
210 | break; | ||
211 | default: | ||
212 | break; | ||
213 | } | ||
214 | } | ||
215 | |||
216 | static int percpu_ce_set_next_event(unsigned long delta, | ||
217 | struct clock_event_device *evt) | ||
218 | { | ||
219 | int cpu = __first_cpu(evt->cpumask); | ||
220 | unsigned int next = (unsigned int)delta; | ||
221 | |||
222 | sparc_config.load_profile_irq(cpu, next); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | void register_percpu_ce(int cpu) | ||
227 | { | ||
228 | struct clock_event_device *ce = &per_cpu(sparc32_clockevent, cpu); | ||
229 | unsigned int features = CLOCK_EVT_FEAT_PERIODIC; | ||
230 | |||
231 | if (sparc_config.features & FEAT_L14_ONESHOT) | ||
232 | features |= CLOCK_EVT_FEAT_ONESHOT; | ||
233 | |||
234 | ce->name = "percpu_ce"; | ||
235 | ce->rating = 200; | ||
236 | ce->features = features; | ||
237 | ce->set_mode = percpu_ce_setup; | ||
238 | ce->set_next_event = percpu_ce_set_next_event; | ||
239 | ce->cpumask = cpumask_of(cpu); | ||
240 | ce->shift = 32; | ||
241 | ce->mult = div_sc(sparc_config.clock_rate, NSEC_PER_SEC, | ||
242 | ce->shift); | ||
243 | ce->max_delta_ns = clockevent_delta2ns(sparc_config.clock_rate, ce); | ||
244 | ce->min_delta_ns = clockevent_delta2ns(100, ce); | ||
245 | |||
246 | clockevents_register_device(ce); | ||
247 | } | ||
248 | #endif | ||
249 | |||
108 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) | 250 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) |
109 | { | 251 | { |
110 | struct platform_device *pdev = to_platform_device(dev); | 252 | struct platform_device *pdev = to_platform_device(dev); |
@@ -195,38 +337,28 @@ static int __init clock_init(void) | |||
195 | */ | 337 | */ |
196 | fs_initcall(clock_init); | 338 | fs_initcall(clock_init); |
197 | 339 | ||
198 | 340 | static void __init sparc32_late_time_init(void) | |
199 | u32 sbus_do_gettimeoffset(void) | ||
200 | { | ||
201 | unsigned long val = *master_l10_counter; | ||
202 | unsigned long usec = (val >> 10) & 0x1fffff; | ||
203 | |||
204 | /* Limit hit? */ | ||
205 | if (val & 0x80000000) | ||
206 | usec += 1000000 / HZ; | ||
207 | |||
208 | return usec * 1000; | ||
209 | } | ||
210 | |||
211 | |||
212 | u32 arch_gettimeoffset(void) | ||
213 | { | 341 | { |
214 | if (unlikely(!do_arch_gettimeoffset)) | 342 | if (sparc_config.features & FEAT_L10_CLOCKEVENT) |
215 | return 0; | 343 | setup_timer_ce(); |
216 | return do_arch_gettimeoffset(); | 344 | if (sparc_config.features & FEAT_L10_CLOCKSOURCE) |
345 | setup_timer_cs(); | ||
346 | #ifdef CONFIG_SMP | ||
347 | register_percpu_ce(smp_processor_id()); | ||
348 | #endif | ||
217 | } | 349 | } |
218 | 350 | ||
219 | static void __init sbus_time_init(void) | 351 | static void __init sbus_time_init(void) |
220 | { | 352 | { |
221 | do_arch_gettimeoffset = sbus_do_gettimeoffset; | 353 | sparc_config.get_cycles_offset = sbus_cycles_offset; |
222 | 354 | sparc_config.init_timers(); | |
223 | btfixup(); | ||
224 | |||
225 | sparc_irq_config.init_timers(timer_interrupt); | ||
226 | } | 355 | } |
227 | 356 | ||
228 | void __init time_init(void) | 357 | void __init time_init(void) |
229 | { | 358 | { |
359 | sparc_config.features = 0; | ||
360 | late_time_init = sparc32_late_time_init; | ||
361 | |||
230 | if (pcic_present()) | 362 | if (pcic_present()) |
231 | pci_time_init(); | 363 | pci_time_init(); |
232 | else | 364 | else |
diff --git a/arch/sparc/kernel/trampoline_32.S b/arch/sparc/kernel/trampoline_32.S index 691f484e03b3..7364ddc9e5aa 100644 --- a/arch/sparc/kernel/trampoline_32.S +++ b/arch/sparc/kernel/trampoline_32.S | |||
@@ -15,8 +15,8 @@ | |||
15 | #include <asm/contregs.h> | 15 | #include <asm/contregs.h> |
16 | #include <asm/thread_info.h> | 16 | #include <asm/thread_info.h> |
17 | 17 | ||
18 | .globl sun4m_cpu_startup, __smp4m_processor_id, __leon_processor_id | 18 | .globl sun4m_cpu_startup |
19 | .globl sun4d_cpu_startup, __smp4d_processor_id | 19 | .globl sun4d_cpu_startup |
20 | 20 | ||
21 | __CPUINIT | 21 | __CPUINIT |
22 | .align 4 | 22 | .align 4 |
@@ -94,24 +94,6 @@ smp_do_cpu_idle: | |||
94 | call cpu_panic | 94 | call cpu_panic |
95 | nop | 95 | nop |
96 | 96 | ||
97 | __smp4m_processor_id: | ||
98 | rd %tbr, %g2 | ||
99 | srl %g2, 12, %g2 | ||
100 | and %g2, 3, %g2 | ||
101 | retl | ||
102 | mov %g1, %o7 | ||
103 | |||
104 | __smp4d_processor_id: | ||
105 | lda [%g0] ASI_M_VIKING_TMP1, %g2 | ||
106 | retl | ||
107 | mov %g1, %o7 | ||
108 | |||
109 | __leon_processor_id: | ||
110 | rd %asr17,%g2 | ||
111 | srl %g2,28,%g2 | ||
112 | retl | ||
113 | mov %g1, %o7 | ||
114 | |||
115 | /* CPUID in bootbus can be found at PA 0xff0140000 */ | 97 | /* CPUID in bootbus can be found at PA 0xff0140000 */ |
116 | #define SUN4D_BOOTBUS_CPUID 0xf0140000 | 98 | #define SUN4D_BOOTBUS_CPUID 0xf0140000 |
117 | 99 | ||
diff --git a/arch/sparc/kernel/traps_32.c b/arch/sparc/kernel/traps_32.c index d2de21333146..a5785ea2a85d 100644 --- a/arch/sparc/kernel/traps_32.c +++ b/arch/sparc/kernel/traps_32.c | |||
@@ -120,8 +120,6 @@ void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned lon | |||
120 | printk("Ill instr. at pc=%08lx instruction is %08lx\n", | 120 | printk("Ill instr. at pc=%08lx instruction is %08lx\n", |
121 | regs->pc, *(unsigned long *)regs->pc); | 121 | regs->pc, *(unsigned long *)regs->pc); |
122 | #endif | 122 | #endif |
123 | if (!do_user_muldiv (regs, pc)) | ||
124 | return; | ||
125 | 123 | ||
126 | info.si_signo = SIGILL; | 124 | info.si_signo = SIGILL; |
127 | info.si_errno = 0; | 125 | info.si_errno = 0; |
diff --git a/arch/sparc/kernel/ttable_32.S b/arch/sparc/kernel/ttable_32.S new file mode 100644 index 000000000000..8a7a96ca676f --- /dev/null +++ b/arch/sparc/kernel/ttable_32.S | |||
@@ -0,0 +1,417 @@ | |||
1 | /* The Sparc trap table, bootloader gives us control at _start. */ | ||
2 | __HEAD | ||
3 | |||
4 | .globl _start | ||
5 | _start: | ||
6 | |||
7 | .globl _stext | ||
8 | _stext: | ||
9 | |||
10 | .globl trapbase | ||
11 | trapbase: | ||
12 | |||
13 | #ifdef CONFIG_SMP | ||
14 | trapbase_cpu0: | ||
15 | #endif | ||
16 | /* We get control passed to us here at t_zero. */ | ||
17 | t_zero: b gokernel; nop; nop; nop; | ||
18 | t_tflt: SRMMU_TFAULT /* Inst. Access Exception */ | ||
19 | t_bins: TRAP_ENTRY(0x2, bad_instruction) /* Illegal Instruction */ | ||
20 | t_pins: TRAP_ENTRY(0x3, priv_instruction) /* Privileged Instruction */ | ||
21 | t_fpd: TRAP_ENTRY(0x4, fpd_trap_handler) /* Floating Point Disabled */ | ||
22 | t_wovf: WINDOW_SPILL /* Window Overflow */ | ||
23 | t_wunf: WINDOW_FILL /* Window Underflow */ | ||
24 | t_mna: TRAP_ENTRY(0x7, mna_handler) /* Memory Address Not Aligned */ | ||
25 | t_fpe: TRAP_ENTRY(0x8, fpe_trap_handler) /* Floating Point Exception */ | ||
26 | t_dflt: SRMMU_DFAULT /* Data Miss Exception */ | ||
27 | t_tio: TRAP_ENTRY(0xa, do_tag_overflow) /* Tagged Instruction Ovrflw */ | ||
28 | t_wpt: TRAP_ENTRY(0xb, do_watchpoint) /* Watchpoint Detected */ | ||
29 | t_badc: BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
30 | t_irq1: TRAP_ENTRY_INTERRUPT(1) /* IRQ Software/SBUS Level 1 */ | ||
31 | t_irq2: TRAP_ENTRY_INTERRUPT(2) /* IRQ SBUS Level 2 */ | ||
32 | t_irq3: TRAP_ENTRY_INTERRUPT(3) /* IRQ SCSI/DMA/SBUS Level 3 */ | ||
33 | t_irq4: TRAP_ENTRY_INTERRUPT(4) /* IRQ Software Level 4 */ | ||
34 | t_irq5: TRAP_ENTRY_INTERRUPT(5) /* IRQ SBUS/Ethernet Level 5 */ | ||
35 | t_irq6: TRAP_ENTRY_INTERRUPT(6) /* IRQ Software Level 6 */ | ||
36 | t_irq7: TRAP_ENTRY_INTERRUPT(7) /* IRQ Video/SBUS Level 5 */ | ||
37 | t_irq8: TRAP_ENTRY_INTERRUPT(8) /* IRQ SBUS Level 6 */ | ||
38 | t_irq9: TRAP_ENTRY_INTERRUPT(9) /* IRQ SBUS Level 7 */ | ||
39 | t_irq10:TRAP_ENTRY_INTERRUPT(10) /* IRQ Timer #1 (one we use) */ | ||
40 | t_irq11:TRAP_ENTRY_INTERRUPT(11) /* IRQ Floppy Intr. */ | ||
41 | t_irq12:TRAP_ENTRY_INTERRUPT(12) /* IRQ Zilog serial chip */ | ||
42 | t_irq13:TRAP_ENTRY_INTERRUPT(13) /* IRQ Audio Intr. */ | ||
43 | t_irq14:TRAP_ENTRY_INTERRUPT(14) /* IRQ Timer #2 */ | ||
44 | |||
45 | .globl t_nmi | ||
46 | t_nmi: TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
47 | |||
48 | t_racc: TRAP_ENTRY(0x20, do_reg_access) /* General Register Access Error */ | ||
49 | t_iacce:BAD_TRAP(0x21) /* Instr Access Error */ | ||
50 | t_bad22:BAD_TRAP(0x22) | ||
51 | BAD_TRAP(0x23) | ||
52 | t_cpdis:TRAP_ENTRY(0x24, do_cp_disabled) /* Co-Processor Disabled */ | ||
53 | t_uflsh:SKIP_TRAP(0x25, unimp_flush) /* Unimplemented FLUSH inst. */ | ||
54 | t_bad26:BAD_TRAP(0x26) BAD_TRAP(0x27) | ||
55 | t_cpexc:TRAP_ENTRY(0x28, do_cp_exception) /* Co-Processor Exception */ | ||
56 | t_dacce:SRMMU_DFAULT /* Data Access Error */ | ||
57 | t_hwdz: TRAP_ENTRY(0x2a, do_hw_divzero) /* Division by zero, you lose... */ | ||
58 | t_dserr:BAD_TRAP(0x2b) /* Data Store Error */ | ||
59 | t_daccm:BAD_TRAP(0x2c) /* Data Access MMU-Miss */ | ||
60 | t_bad2d:BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
61 | t_bad32:BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
62 | t_bad37:BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
63 | t_iaccm:BAD_TRAP(0x3c) /* Instr Access MMU-Miss */ | ||
64 | t_bad3d:BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) BAD_TRAP(0x41) | ||
65 | t_bad42:BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) BAD_TRAP(0x46) | ||
66 | t_bad47:BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) BAD_TRAP(0x4b) | ||
67 | t_bad4c:BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) BAD_TRAP(0x50) | ||
68 | t_bad51:BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
69 | t_bad56:BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
70 | t_bad5b:BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
71 | t_bad60:BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
72 | t_bad65:BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
73 | t_bad6a:BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
74 | t_bad6f:BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
75 | t_bad74:BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
76 | t_bad79:BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
77 | t_bad7e:BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
78 | t_bad80:BAD_TRAP(0x80) /* SunOS System Call */ | ||
79 | t_sbkpt:BREAKPOINT_TRAP /* Software Breakpoint/KGDB */ | ||
80 | t_divz: TRAP_ENTRY(0x82, do_hw_divzero) /* Divide by zero trap */ | ||
81 | t_flwin:TRAP_ENTRY(0x83, do_flush_windows) /* Flush Windows Trap */ | ||
82 | t_clwin:BAD_TRAP(0x84) /* Clean Windows Trap */ | ||
83 | t_rchk: BAD_TRAP(0x85) /* Range Check */ | ||
84 | t_funal:BAD_TRAP(0x86) /* Fix Unaligned Access Trap */ | ||
85 | t_iovf: BAD_TRAP(0x87) /* Integer Overflow Trap */ | ||
86 | t_bad88:BAD_TRAP(0x88) /* Slowaris System Call */ | ||
87 | t_bad89:BAD_TRAP(0x89) /* Net-B.S. System Call */ | ||
88 | t_bad8a:BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) BAD_TRAP(0x8d) BAD_TRAP(0x8e) | ||
89 | t_bad8f:BAD_TRAP(0x8f) | ||
90 | t_linux:LINUX_SYSCALL_TRAP /* Linux System Call */ | ||
91 | t_bad91:BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) BAD_TRAP(0x95) | ||
92 | t_bad96:BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) BAD_TRAP(0x9a) | ||
93 | t_bad9b:BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) BAD_TRAP(0x9f) | ||
94 | t_getcc:GETCC_TRAP /* Get Condition Codes */ | ||
95 | t_setcc:SETCC_TRAP /* Set Condition Codes */ | ||
96 | t_getpsr:GETPSR_TRAP /* Get PSR Register */ | ||
97 | t_bada3:BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
98 | t_bada7:BAD_TRAP(0xa7) | ||
99 | t_bada8:BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
100 | t_badac:BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
101 | t_badb1:BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
102 | t_badb6:BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
103 | t_badbb:BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
104 | t_badc0:BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
105 | t_badc5:BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
106 | t_badca:BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
107 | t_badcf:BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
108 | t_badd4:BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
109 | t_badd9:BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
110 | t_badde:BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
111 | t_bade3:BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
112 | t_bade8:BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
113 | t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
114 | t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
115 | t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
116 | t_badfc:BAD_TRAP(0xfc) | ||
117 | t_kgdb: KGDB_TRAP(0xfd) | ||
118 | dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */ | ||
119 | dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */ | ||
120 | |||
121 | .globl end_traptable | ||
122 | end_traptable: | ||
123 | |||
124 | #ifdef CONFIG_SMP | ||
125 | /* Trap tables for the other cpus. */ | ||
126 | .globl trapbase_cpu1, trapbase_cpu2, trapbase_cpu3 | ||
127 | trapbase_cpu1: | ||
128 | BAD_TRAP(0x0) | ||
129 | SRMMU_TFAULT | ||
130 | TRAP_ENTRY(0x2, bad_instruction) | ||
131 | TRAP_ENTRY(0x3, priv_instruction) | ||
132 | TRAP_ENTRY(0x4, fpd_trap_handler) | ||
133 | WINDOW_SPILL | ||
134 | WINDOW_FILL | ||
135 | TRAP_ENTRY(0x7, mna_handler) | ||
136 | TRAP_ENTRY(0x8, fpe_trap_handler) | ||
137 | SRMMU_DFAULT | ||
138 | TRAP_ENTRY(0xa, do_tag_overflow) | ||
139 | TRAP_ENTRY(0xb, do_watchpoint) | ||
140 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
141 | TRAP_ENTRY_INTERRUPT(1) TRAP_ENTRY_INTERRUPT(2) | ||
142 | TRAP_ENTRY_INTERRUPT(3) TRAP_ENTRY_INTERRUPT(4) | ||
143 | TRAP_ENTRY_INTERRUPT(5) TRAP_ENTRY_INTERRUPT(6) | ||
144 | TRAP_ENTRY_INTERRUPT(7) TRAP_ENTRY_INTERRUPT(8) | ||
145 | TRAP_ENTRY_INTERRUPT(9) TRAP_ENTRY_INTERRUPT(10) | ||
146 | TRAP_ENTRY_INTERRUPT(11) TRAP_ENTRY_INTERRUPT(12) | ||
147 | TRAP_ENTRY_INTERRUPT(13) TRAP_ENTRY_INTERRUPT(14) | ||
148 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
149 | TRAP_ENTRY(0x20, do_reg_access) | ||
150 | BAD_TRAP(0x21) | ||
151 | BAD_TRAP(0x22) | ||
152 | BAD_TRAP(0x23) | ||
153 | TRAP_ENTRY(0x24, do_cp_disabled) | ||
154 | SKIP_TRAP(0x25, unimp_flush) | ||
155 | BAD_TRAP(0x26) | ||
156 | BAD_TRAP(0x27) | ||
157 | TRAP_ENTRY(0x28, do_cp_exception) | ||
158 | SRMMU_DFAULT | ||
159 | TRAP_ENTRY(0x2a, do_hw_divzero) | ||
160 | BAD_TRAP(0x2b) | ||
161 | BAD_TRAP(0x2c) | ||
162 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
163 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
164 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
165 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
166 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
167 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
168 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
169 | BAD_TRAP(0x50) | ||
170 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
171 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
172 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
173 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
174 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
175 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
176 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
177 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
178 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
179 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
180 | BAD_TRAP(0x80) | ||
181 | BREAKPOINT_TRAP | ||
182 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
183 | TRAP_ENTRY(0x83, do_flush_windows) | ||
184 | BAD_TRAP(0x84) BAD_TRAP(0x85) BAD_TRAP(0x86) | ||
185 | BAD_TRAP(0x87) BAD_TRAP(0x88) BAD_TRAP(0x89) | ||
186 | BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
187 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
188 | LINUX_SYSCALL_TRAP BAD_TRAP(0x91) | ||
189 | BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
190 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
191 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
192 | BAD_TRAP(0x9f) | ||
193 | GETCC_TRAP | ||
194 | SETCC_TRAP | ||
195 | GETPSR_TRAP | ||
196 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
197 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
198 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
199 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
200 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
201 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
202 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
203 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
204 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
205 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
206 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
207 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
208 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
209 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
210 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
211 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
212 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
213 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
214 | BAD_TRAP(0xfc) | ||
215 | KGDB_TRAP(0xfd) | ||
216 | BAD_TRAP(0xfe) | ||
217 | BAD_TRAP(0xff) | ||
218 | |||
219 | trapbase_cpu2: | ||
220 | BAD_TRAP(0x0) | ||
221 | SRMMU_TFAULT | ||
222 | TRAP_ENTRY(0x2, bad_instruction) | ||
223 | TRAP_ENTRY(0x3, priv_instruction) | ||
224 | TRAP_ENTRY(0x4, fpd_trap_handler) | ||
225 | WINDOW_SPILL | ||
226 | WINDOW_FILL | ||
227 | TRAP_ENTRY(0x7, mna_handler) | ||
228 | TRAP_ENTRY(0x8, fpe_trap_handler) | ||
229 | SRMMU_DFAULT | ||
230 | TRAP_ENTRY(0xa, do_tag_overflow) | ||
231 | TRAP_ENTRY(0xb, do_watchpoint) | ||
232 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
233 | TRAP_ENTRY_INTERRUPT(1) | ||
234 | TRAP_ENTRY_INTERRUPT(2) | ||
235 | TRAP_ENTRY_INTERRUPT(3) | ||
236 | TRAP_ENTRY_INTERRUPT(4) | ||
237 | TRAP_ENTRY_INTERRUPT(5) | ||
238 | TRAP_ENTRY_INTERRUPT(6) | ||
239 | TRAP_ENTRY_INTERRUPT(7) | ||
240 | TRAP_ENTRY_INTERRUPT(8) | ||
241 | TRAP_ENTRY_INTERRUPT(9) | ||
242 | TRAP_ENTRY_INTERRUPT(10) | ||
243 | TRAP_ENTRY_INTERRUPT(11) | ||
244 | TRAP_ENTRY_INTERRUPT(12) | ||
245 | TRAP_ENTRY_INTERRUPT(13) | ||
246 | TRAP_ENTRY_INTERRUPT(14) | ||
247 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
248 | TRAP_ENTRY(0x20, do_reg_access) | ||
249 | BAD_TRAP(0x21) | ||
250 | BAD_TRAP(0x22) | ||
251 | BAD_TRAP(0x23) | ||
252 | TRAP_ENTRY(0x24, do_cp_disabled) | ||
253 | SKIP_TRAP(0x25, unimp_flush) | ||
254 | BAD_TRAP(0x26) | ||
255 | BAD_TRAP(0x27) | ||
256 | TRAP_ENTRY(0x28, do_cp_exception) | ||
257 | SRMMU_DFAULT | ||
258 | TRAP_ENTRY(0x2a, do_hw_divzero) | ||
259 | BAD_TRAP(0x2b) | ||
260 | BAD_TRAP(0x2c) | ||
261 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
262 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
263 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
264 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
265 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
266 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
267 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
268 | BAD_TRAP(0x50) | ||
269 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
270 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
271 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
272 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
273 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
274 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
275 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
276 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
277 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
278 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
279 | BAD_TRAP(0x80) | ||
280 | BREAKPOINT_TRAP | ||
281 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
282 | TRAP_ENTRY(0x83, do_flush_windows) | ||
283 | BAD_TRAP(0x84) | ||
284 | BAD_TRAP(0x85) | ||
285 | BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) | ||
286 | BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
287 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
288 | LINUX_SYSCALL_TRAP BAD_TRAP(0x91) | ||
289 | BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
290 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
291 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
292 | BAD_TRAP(0x9f) | ||
293 | GETCC_TRAP | ||
294 | SETCC_TRAP | ||
295 | GETPSR_TRAP | ||
296 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
297 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
298 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
299 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
300 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
301 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
302 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
303 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
304 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
305 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
306 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
307 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
308 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
309 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
310 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
311 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
312 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
313 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
314 | BAD_TRAP(0xfc) | ||
315 | KGDB_TRAP(0xfd) | ||
316 | BAD_TRAP(0xfe) | ||
317 | BAD_TRAP(0xff) | ||
318 | |||
319 | trapbase_cpu3: | ||
320 | BAD_TRAP(0x0) | ||
321 | SRMMU_TFAULT | ||
322 | TRAP_ENTRY(0x2, bad_instruction) | ||
323 | TRAP_ENTRY(0x3, priv_instruction) | ||
324 | TRAP_ENTRY(0x4, fpd_trap_handler) | ||
325 | WINDOW_SPILL | ||
326 | WINDOW_FILL | ||
327 | TRAP_ENTRY(0x7, mna_handler) | ||
328 | TRAP_ENTRY(0x8, fpe_trap_handler) | ||
329 | SRMMU_DFAULT | ||
330 | TRAP_ENTRY(0xa, do_tag_overflow) | ||
331 | TRAP_ENTRY(0xb, do_watchpoint) | ||
332 | BAD_TRAP(0xc) BAD_TRAP(0xd) BAD_TRAP(0xe) BAD_TRAP(0xf) BAD_TRAP(0x10) | ||
333 | TRAP_ENTRY_INTERRUPT(1) | ||
334 | TRAP_ENTRY_INTERRUPT(2) | ||
335 | TRAP_ENTRY_INTERRUPT(3) | ||
336 | TRAP_ENTRY_INTERRUPT(4) | ||
337 | TRAP_ENTRY_INTERRUPT(5) | ||
338 | TRAP_ENTRY_INTERRUPT(6) | ||
339 | TRAP_ENTRY_INTERRUPT(7) | ||
340 | TRAP_ENTRY_INTERRUPT(8) | ||
341 | TRAP_ENTRY_INTERRUPT(9) | ||
342 | TRAP_ENTRY_INTERRUPT(10) | ||
343 | TRAP_ENTRY_INTERRUPT(11) | ||
344 | TRAP_ENTRY_INTERRUPT(12) | ||
345 | TRAP_ENTRY_INTERRUPT(13) | ||
346 | TRAP_ENTRY_INTERRUPT(14) | ||
347 | TRAP_ENTRY(0x1f, linux_trap_ipi15_sun4m) | ||
348 | TRAP_ENTRY(0x20, do_reg_access) | ||
349 | BAD_TRAP(0x21) | ||
350 | BAD_TRAP(0x22) | ||
351 | BAD_TRAP(0x23) | ||
352 | TRAP_ENTRY(0x24, do_cp_disabled) | ||
353 | SKIP_TRAP(0x25, unimp_flush) | ||
354 | BAD_TRAP(0x26) | ||
355 | BAD_TRAP(0x27) | ||
356 | TRAP_ENTRY(0x28, do_cp_exception) | ||
357 | SRMMU_DFAULT | ||
358 | TRAP_ENTRY(0x2a, do_hw_divzero) | ||
359 | BAD_TRAP(0x2b) BAD_TRAP(0x2c) | ||
360 | BAD_TRAP(0x2d) BAD_TRAP(0x2e) BAD_TRAP(0x2f) BAD_TRAP(0x30) BAD_TRAP(0x31) | ||
361 | BAD_TRAP(0x32) BAD_TRAP(0x33) BAD_TRAP(0x34) BAD_TRAP(0x35) BAD_TRAP(0x36) | ||
362 | BAD_TRAP(0x37) BAD_TRAP(0x38) BAD_TRAP(0x39) BAD_TRAP(0x3a) BAD_TRAP(0x3b) | ||
363 | BAD_TRAP(0x3c) BAD_TRAP(0x3d) BAD_TRAP(0x3e) BAD_TRAP(0x3f) BAD_TRAP(0x40) | ||
364 | BAD_TRAP(0x41) BAD_TRAP(0x42) BAD_TRAP(0x43) BAD_TRAP(0x44) BAD_TRAP(0x45) | ||
365 | BAD_TRAP(0x46) BAD_TRAP(0x47) BAD_TRAP(0x48) BAD_TRAP(0x49) BAD_TRAP(0x4a) | ||
366 | BAD_TRAP(0x4b) BAD_TRAP(0x4c) BAD_TRAP(0x4d) BAD_TRAP(0x4e) BAD_TRAP(0x4f) | ||
367 | BAD_TRAP(0x50) | ||
368 | BAD_TRAP(0x51) BAD_TRAP(0x52) BAD_TRAP(0x53) BAD_TRAP(0x54) BAD_TRAP(0x55) | ||
369 | BAD_TRAP(0x56) BAD_TRAP(0x57) BAD_TRAP(0x58) BAD_TRAP(0x59) BAD_TRAP(0x5a) | ||
370 | BAD_TRAP(0x5b) BAD_TRAP(0x5c) BAD_TRAP(0x5d) BAD_TRAP(0x5e) BAD_TRAP(0x5f) | ||
371 | BAD_TRAP(0x60) BAD_TRAP(0x61) BAD_TRAP(0x62) BAD_TRAP(0x63) BAD_TRAP(0x64) | ||
372 | BAD_TRAP(0x65) BAD_TRAP(0x66) BAD_TRAP(0x67) BAD_TRAP(0x68) BAD_TRAP(0x69) | ||
373 | BAD_TRAP(0x6a) BAD_TRAP(0x6b) BAD_TRAP(0x6c) BAD_TRAP(0x6d) BAD_TRAP(0x6e) | ||
374 | BAD_TRAP(0x6f) BAD_TRAP(0x70) BAD_TRAP(0x71) BAD_TRAP(0x72) BAD_TRAP(0x73) | ||
375 | BAD_TRAP(0x74) BAD_TRAP(0x75) BAD_TRAP(0x76) BAD_TRAP(0x77) BAD_TRAP(0x78) | ||
376 | BAD_TRAP(0x79) BAD_TRAP(0x7a) BAD_TRAP(0x7b) BAD_TRAP(0x7c) BAD_TRAP(0x7d) | ||
377 | BAD_TRAP(0x7e) BAD_TRAP(0x7f) | ||
378 | BAD_TRAP(0x80) | ||
379 | BREAKPOINT_TRAP | ||
380 | TRAP_ENTRY(0x82, do_hw_divzero) | ||
381 | TRAP_ENTRY(0x83, do_flush_windows) | ||
382 | BAD_TRAP(0x84) BAD_TRAP(0x85) | ||
383 | BAD_TRAP(0x86) BAD_TRAP(0x87) BAD_TRAP(0x88) | ||
384 | BAD_TRAP(0x89) BAD_TRAP(0x8a) BAD_TRAP(0x8b) BAD_TRAP(0x8c) | ||
385 | BAD_TRAP(0x8d) BAD_TRAP(0x8e) BAD_TRAP(0x8f) | ||
386 | LINUX_SYSCALL_TRAP | ||
387 | BAD_TRAP(0x91) BAD_TRAP(0x92) BAD_TRAP(0x93) BAD_TRAP(0x94) | ||
388 | BAD_TRAP(0x95) BAD_TRAP(0x96) BAD_TRAP(0x97) BAD_TRAP(0x98) BAD_TRAP(0x99) | ||
389 | BAD_TRAP(0x9a) BAD_TRAP(0x9b) BAD_TRAP(0x9c) BAD_TRAP(0x9d) BAD_TRAP(0x9e) | ||
390 | BAD_TRAP(0x9f) | ||
391 | GETCC_TRAP | ||
392 | SETCC_TRAP | ||
393 | GETPSR_TRAP | ||
394 | BAD_TRAP(0xa3) BAD_TRAP(0xa4) BAD_TRAP(0xa5) BAD_TRAP(0xa6) | ||
395 | BAD_TRAP(0xa7) BAD_TRAP(0xa8) BAD_TRAP(0xa9) BAD_TRAP(0xaa) BAD_TRAP(0xab) | ||
396 | BAD_TRAP(0xac) BAD_TRAP(0xad) BAD_TRAP(0xae) BAD_TRAP(0xaf) BAD_TRAP(0xb0) | ||
397 | BAD_TRAP(0xb1) BAD_TRAP(0xb2) BAD_TRAP(0xb3) BAD_TRAP(0xb4) BAD_TRAP(0xb5) | ||
398 | BAD_TRAP(0xb6) BAD_TRAP(0xb7) BAD_TRAP(0xb8) BAD_TRAP(0xb9) BAD_TRAP(0xba) | ||
399 | BAD_TRAP(0xbb) BAD_TRAP(0xbc) BAD_TRAP(0xbd) BAD_TRAP(0xbe) BAD_TRAP(0xbf) | ||
400 | BAD_TRAP(0xc0) BAD_TRAP(0xc1) BAD_TRAP(0xc2) BAD_TRAP(0xc3) BAD_TRAP(0xc4) | ||
401 | BAD_TRAP(0xc5) BAD_TRAP(0xc6) BAD_TRAP(0xc7) BAD_TRAP(0xc8) BAD_TRAP(0xc9) | ||
402 | BAD_TRAP(0xca) BAD_TRAP(0xcb) BAD_TRAP(0xcc) BAD_TRAP(0xcd) BAD_TRAP(0xce) | ||
403 | BAD_TRAP(0xcf) BAD_TRAP(0xd0) BAD_TRAP(0xd1) BAD_TRAP(0xd2) BAD_TRAP(0xd3) | ||
404 | BAD_TRAP(0xd4) BAD_TRAP(0xd5) BAD_TRAP(0xd6) BAD_TRAP(0xd7) BAD_TRAP(0xd8) | ||
405 | BAD_TRAP(0xd9) BAD_TRAP(0xda) BAD_TRAP(0xdb) BAD_TRAP(0xdc) BAD_TRAP(0xdd) | ||
406 | BAD_TRAP(0xde) BAD_TRAP(0xdf) BAD_TRAP(0xe0) BAD_TRAP(0xe1) BAD_TRAP(0xe2) | ||
407 | BAD_TRAP(0xe3) BAD_TRAP(0xe4) BAD_TRAP(0xe5) BAD_TRAP(0xe6) BAD_TRAP(0xe7) | ||
408 | BAD_TRAP(0xe8) BAD_TRAP(0xe9) BAD_TRAP(0xea) BAD_TRAP(0xeb) BAD_TRAP(0xec) | ||
409 | BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1) | ||
410 | BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6) | ||
411 | BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb) | ||
412 | BAD_TRAP(0xfc) | ||
413 | KGDB_TRAP(0xfd) | ||
414 | BAD_TRAP(0xfe) | ||
415 | BAD_TRAP(0xff) | ||
416 | |||
417 | #endif | ||
diff --git a/arch/sparc/kernel/ttable.S b/arch/sparc/kernel/ttable_64.S index c6dfdaa29e20..c6dfdaa29e20 100644 --- a/arch/sparc/kernel/ttable.S +++ b/arch/sparc/kernel/ttable_64.S | |||
diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index dae85bc2eda5..f81d038f7340 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/perf_event.h> | 22 | #include <linux/perf_event.h> |
23 | #include <linux/ratelimit.h> | 23 | #include <linux/ratelimit.h> |
24 | #include <linux/bitops.h> | ||
25 | #include <asm/fpumacro.h> | 24 | #include <asm/fpumacro.h> |
26 | #include <asm/cacheflush.h> | 25 | #include <asm/cacheflush.h> |
27 | 26 | ||
diff --git a/arch/sparc/kernel/wof.S b/arch/sparc/kernel/wof.S index 3bbcd8dc9abf..4c2de3cf309b 100644 --- a/arch/sparc/kernel/wof.S +++ b/arch/sparc/kernel/wof.S | |||
@@ -163,9 +163,8 @@ spwin_fromuser: | |||
163 | * the label 'spwin_user_stack_is_bolixed' which will take | 163 | * the label 'spwin_user_stack_is_bolixed' which will take |
164 | * care of things at that point. | 164 | * care of things at that point. |
165 | */ | 165 | */ |
166 | .globl spwin_mmu_patchme | 166 | b spwin_srmmu_stackchk |
167 | spwin_mmu_patchme: b spwin_sun4c_stackchk | 167 | andcc %sp, 0x7, %g0 |
168 | andcc %sp, 0x7, %g0 | ||
169 | 168 | ||
170 | spwin_good_ustack: | 169 | spwin_good_ustack: |
171 | /* LOCATION: Window to be saved */ | 170 | /* LOCATION: Window to be saved */ |
@@ -306,73 +305,6 @@ spwin_bad_ustack_from_kernel: | |||
306 | * As noted above %curptr cannot be touched by this routine at all. | 305 | * As noted above %curptr cannot be touched by this routine at all. |
307 | */ | 306 | */ |
308 | 307 | ||
309 | spwin_sun4c_stackchk: | ||
310 | /* LOCATION: Window to be saved on the stack */ | ||
311 | |||
312 | /* See if the stack is in the address space hole but first, | ||
313 | * check results of callers andcc %sp, 0x7, %g0 | ||
314 | */ | ||
315 | be 1f | ||
316 | sra %sp, 29, %glob_tmp | ||
317 | |||
318 | rd %psr, %glob_tmp | ||
319 | b spwin_user_stack_is_bolixed + 0x4 | ||
320 | nop | ||
321 | |||
322 | 1: | ||
323 | add %glob_tmp, 0x1, %glob_tmp | ||
324 | andncc %glob_tmp, 0x1, %g0 | ||
325 | be 1f | ||
326 | and %sp, 0xfff, %glob_tmp ! delay slot | ||
327 | |||
328 | rd %psr, %glob_tmp | ||
329 | b spwin_user_stack_is_bolixed + 0x4 | ||
330 | nop | ||
331 | |||
332 | /* See if our dump area will be on more than one | ||
333 | * page. | ||
334 | */ | ||
335 | 1: | ||
336 | add %glob_tmp, 0x38, %glob_tmp | ||
337 | andncc %glob_tmp, 0xff8, %g0 | ||
338 | be spwin_sun4c_onepage ! only one page to check | ||
339 | lda [%sp] ASI_PTE, %glob_tmp ! have to check first page anyways | ||
340 | |||
341 | spwin_sun4c_twopages: | ||
342 | /* Is first page ok permission wise? */ | ||
343 | srl %glob_tmp, 29, %glob_tmp | ||
344 | cmp %glob_tmp, 0x6 | ||
345 | be 1f | ||
346 | add %sp, 0x38, %glob_tmp /* Is second page in vma hole? */ | ||
347 | |||
348 | rd %psr, %glob_tmp | ||
349 | b spwin_user_stack_is_bolixed + 0x4 | ||
350 | nop | ||
351 | |||
352 | 1: | ||
353 | sra %glob_tmp, 29, %glob_tmp | ||
354 | add %glob_tmp, 0x1, %glob_tmp | ||
355 | andncc %glob_tmp, 0x1, %g0 | ||
356 | be 1f | ||
357 | add %sp, 0x38, %glob_tmp | ||
358 | |||
359 | rd %psr, %glob_tmp | ||
360 | b spwin_user_stack_is_bolixed + 0x4 | ||
361 | nop | ||
362 | |||
363 | 1: | ||
364 | lda [%glob_tmp] ASI_PTE, %glob_tmp | ||
365 | |||
366 | spwin_sun4c_onepage: | ||
367 | srl %glob_tmp, 29, %glob_tmp | ||
368 | cmp %glob_tmp, 0x6 ! can user write to it? | ||
369 | be spwin_good_ustack ! success | ||
370 | nop | ||
371 | |||
372 | rd %psr, %glob_tmp | ||
373 | b spwin_user_stack_is_bolixed + 0x4 | ||
374 | nop | ||
375 | |||
376 | /* This is a generic SRMMU routine. As far as I know this | 308 | /* This is a generic SRMMU routine. As far as I know this |
377 | * works for all current v8/srmmu implementations, we'll | 309 | * works for all current v8/srmmu implementations, we'll |
378 | * see... | 310 | * see... |
diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S index 779ff750603d..9fde91a249e0 100644 --- a/arch/sparc/kernel/wuf.S +++ b/arch/sparc/kernel/wuf.S | |||
@@ -131,12 +131,9 @@ fwin_from_user: | |||
131 | 131 | ||
132 | /* LOCATION: Window 'W' */ | 132 | /* LOCATION: Window 'W' */ |
133 | 133 | ||
134 | /* Branch to the architecture specific stack validation | 134 | /* Branch to the stack validation routine */ |
135 | * routine. They can be found below... | 135 | b srmmu_fwin_stackchk |
136 | */ | 136 | andcc %sp, 0x7, %g0 |
137 | .globl fwin_mmu_patchme | ||
138 | fwin_mmu_patchme: b sun4c_fwin_stackchk | ||
139 | andcc %sp, 0x7, %g0 | ||
140 | 137 | ||
141 | #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ) | 138 | #define STACK_OFFSET (THREAD_SIZE - TRACEREG_SZ - STACKFRAME_SZ) |
142 | 139 | ||
@@ -242,57 +239,6 @@ fwin_user_finish_up: | |||
242 | * 'someone elses' window possibly. | 239 | * 'someone elses' window possibly. |
243 | */ | 240 | */ |
244 | 241 | ||
245 | .align 4 | ||
246 | sun4c_fwin_stackchk: | ||
247 | /* LOCATION: Window 'W' */ | ||
248 | |||
249 | /* Caller did 'andcc %sp, 0x7, %g0' */ | ||
250 | be 1f | ||
251 | and %sp, 0xfff, %l0 ! delay slot | ||
252 | |||
253 | b,a fwin_user_stack_is_bolixed | ||
254 | |||
255 | /* See if we have to check the sanity of one page or two */ | ||
256 | 1: | ||
257 | add %l0, 0x38, %l0 | ||
258 | sra %sp, 29, %l5 | ||
259 | add %l5, 0x1, %l5 | ||
260 | andncc %l5, 0x1, %g0 | ||
261 | be 1f | ||
262 | andncc %l0, 0xff8, %g0 | ||
263 | |||
264 | b,a fwin_user_stack_is_bolixed /* %sp is in vma hole, yuck */ | ||
265 | |||
266 | 1: | ||
267 | be sun4c_fwin_onepage /* Only one page to check */ | ||
268 | lda [%sp] ASI_PTE, %l1 | ||
269 | sun4c_fwin_twopages: | ||
270 | add %sp, 0x38, %l0 | ||
271 | sra %l0, 29, %l5 | ||
272 | add %l5, 0x1, %l5 | ||
273 | andncc %l5, 0x1, %g0 | ||
274 | be 1f | ||
275 | lda [%l0] ASI_PTE, %l1 | ||
276 | |||
277 | b,a fwin_user_stack_is_bolixed /* Second page in vma hole */ | ||
278 | |||
279 | 1: | ||
280 | srl %l1, 29, %l1 | ||
281 | andcc %l1, 0x4, %g0 | ||
282 | bne sun4c_fwin_onepage | ||
283 | lda [%sp] ASI_PTE, %l1 | ||
284 | |||
285 | b,a fwin_user_stack_is_bolixed /* Second page has bad perms */ | ||
286 | |||
287 | sun4c_fwin_onepage: | ||
288 | srl %l1, 29, %l1 | ||
289 | andcc %l1, 0x4, %g0 | ||
290 | bne fwin_user_stack_is_ok | ||
291 | nop | ||
292 | |||
293 | /* A page had bad page permissions, losing... */ | ||
294 | b,a fwin_user_stack_is_bolixed | ||
295 | |||
296 | .globl srmmu_fwin_stackchk | 242 | .globl srmmu_fwin_stackchk |
297 | srmmu_fwin_stackchk: | 243 | srmmu_fwin_stackchk: |
298 | /* LOCATION: Window 'W' */ | 244 | /* LOCATION: Window 'W' */ |
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile index a3fc4375a150..389628f50a15 100644 --- a/arch/sparc/lib/Makefile +++ b/arch/sparc/lib/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | asflags-y := -ansi -DST_DIV0=0x02 | 4 | asflags-y := -ansi -DST_DIV0=0x02 |
5 | ccflags-y := -Werror | 5 | ccflags-y := -Werror |
6 | 6 | ||
7 | lib-$(CONFIG_SPARC32) += mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o | 7 | lib-$(CONFIG_SPARC32) += ashrdi3.o |
8 | lib-$(CONFIG_SPARC32) += memcpy.o memset.o | 8 | lib-$(CONFIG_SPARC32) += memcpy.o memset.o |
9 | lib-y += strlen.o | 9 | lib-y += strlen.o |
10 | lib-y += checksum_$(BITS).o | 10 | lib-y += checksum_$(BITS).o |
@@ -13,7 +13,7 @@ lib-y += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o | |||
13 | lib-y += strncpy_from_user_$(BITS).o strlen_user_$(BITS).o | 13 | lib-y += strncpy_from_user_$(BITS).o strlen_user_$(BITS).o |
14 | lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o | 14 | lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o |
15 | lib-$(CONFIG_SPARC32) += copy_user.o locks.o | 15 | lib-$(CONFIG_SPARC32) += copy_user.o locks.o |
16 | lib-y += atomic_$(BITS).o | 16 | lib-$(CONFIG_SPARC64) += atomic_64.o |
17 | lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o | 17 | lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o |
18 | lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o | 18 | lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o |
19 | 19 | ||
@@ -40,7 +40,7 @@ lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o | |||
40 | lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o | 40 | lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o |
41 | 41 | ||
42 | obj-y += iomap.o | 42 | obj-y += iomap.o |
43 | obj-$(CONFIG_SPARC32) += atomic32.o | 43 | obj-$(CONFIG_SPARC32) += atomic32.o ucmpdi2.o |
44 | obj-y += ksyms.o | 44 | obj-y += ksyms.o |
45 | obj-$(CONFIG_SPARC64) += PeeCeeI.o | 45 | obj-$(CONFIG_SPARC64) += PeeCeeI.o |
46 | obj-y += usercopy.o | 46 | obj-y += usercopy.o |
diff --git a/arch/sparc/lib/ashldi3.S b/arch/sparc/lib/ashldi3.S index 17912e608716..86f60de07b0a 100644 --- a/arch/sparc/lib/ashldi3.S +++ b/arch/sparc/lib/ashldi3.S | |||
@@ -5,10 +5,10 @@ | |||
5 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) | 5 | * Copyright (C) 1999 David S. Miller (davem@redhat.com) |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/linkage.h> | ||
9 | |||
8 | .text | 10 | .text |
9 | .align 4 | 11 | ENTRY(__ashldi3) |
10 | .globl __ashldi3 | ||
11 | __ashldi3: | ||
12 | cmp %o2, 0 | 12 | cmp %o2, 0 |
13 | be 9f | 13 | be 9f |
14 | mov 0x20, %g2 | 14 | mov 0x20, %g2 |
@@ -32,3 +32,4 @@ __ashldi3: | |||
32 | 9: | 32 | 9: |
33 | retl | 33 | retl |
34 | nop | 34 | nop |
35 | ENDPROC(__ashldi3) | ||
diff --git a/arch/sparc/lib/ashrdi3.S b/arch/sparc/lib/ashrdi3.S index 85398fd6dcc9..6eb8ba2dd50e 100644 --- a/arch/sparc/lib/ashrdi3.S +++ b/arch/sparc/lib/ashrdi3.S | |||
@@ -5,10 +5,10 @@ | |||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | 5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/linkage.h> | ||
9 | |||
8 | .text | 10 | .text |
9 | .align 4 | 11 | ENTRY(__ashrdi3) |
10 | .globl __ashrdi3 | ||
11 | __ashrdi3: | ||
12 | tst %o2 | 12 | tst %o2 |
13 | be 3f | 13 | be 3f |
14 | or %g0, 32, %g2 | 14 | or %g0, 32, %g2 |
@@ -34,3 +34,4 @@ __ashrdi3: | |||
34 | 3: | 34 | 3: |
35 | jmpl %o7 + 8, %g0 | 35 | jmpl %o7 + 8, %g0 |
36 | nop | 36 | nop |
37 | ENDPROC(__ashrdi3) | ||
diff --git a/arch/sparc/lib/atomic_32.S b/arch/sparc/lib/atomic_32.S deleted file mode 100644 index eb6c7359cbd1..000000000000 --- a/arch/sparc/lib/atomic_32.S +++ /dev/null | |||
@@ -1,44 +0,0 @@ | |||
1 | /* atomic.S: Move this stuff here for better ICACHE hit rates. | ||
2 | * | ||
3 | * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) | ||
4 | */ | ||
5 | |||
6 | #include <asm/ptrace.h> | ||
7 | #include <asm/psr.h> | ||
8 | |||
9 | .text | ||
10 | .align 4 | ||
11 | |||
12 | .globl __atomic_begin | ||
13 | __atomic_begin: | ||
14 | |||
15 | #ifndef CONFIG_SMP | ||
16 | .globl ___xchg32_sun4c | ||
17 | ___xchg32_sun4c: | ||
18 | rd %psr, %g3 | ||
19 | andcc %g3, PSR_PIL, %g0 | ||
20 | bne 1f | ||
21 | nop | ||
22 | wr %g3, PSR_PIL, %psr | ||
23 | nop; nop; nop | ||
24 | 1: | ||
25 | andcc %g3, PSR_PIL, %g0 | ||
26 | ld [%g1], %g7 | ||
27 | bne 1f | ||
28 | st %g2, [%g1] | ||
29 | wr %g3, 0x0, %psr | ||
30 | nop; nop; nop | ||
31 | 1: | ||
32 | mov %g7, %g2 | ||
33 | jmpl %o7 + 8, %g0 | ||
34 | mov %g4, %o7 | ||
35 | |||
36 | .globl ___xchg32_sun4md | ||
37 | ___xchg32_sun4md: | ||
38 | swap [%g1], %g2 | ||
39 | jmpl %o7 + 8, %g0 | ||
40 | mov %g4, %o7 | ||
41 | #endif | ||
42 | |||
43 | .globl __atomic_end | ||
44 | __atomic_end: | ||
diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 59186e0fcf39..4d502da3de78 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S | |||
@@ -3,6 +3,7 @@ | |||
3 | * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/linkage.h> | ||
6 | #include <asm/asi.h> | 7 | #include <asm/asi.h> |
7 | #include <asm/backoff.h> | 8 | #include <asm/backoff.h> |
8 | 9 | ||
@@ -13,9 +14,7 @@ | |||
13 | * memory barriers, and a second which returns | 14 | * memory barriers, and a second which returns |
14 | * a value and does the barriers. | 15 | * a value and does the barriers. |
15 | */ | 16 | */ |
16 | .globl atomic_add | 17 | ENTRY(atomic_add) /* %o0 = increment, %o1 = atomic_ptr */ |
17 | .type atomic_add,#function | ||
18 | atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ | ||
19 | BACKOFF_SETUP(%o2) | 18 | BACKOFF_SETUP(%o2) |
20 | 1: lduw [%o1], %g1 | 19 | 1: lduw [%o1], %g1 |
21 | add %g1, %o0, %g7 | 20 | add %g1, %o0, %g7 |
@@ -26,11 +25,9 @@ atomic_add: /* %o0 = increment, %o1 = atomic_ptr */ | |||
26 | retl | 25 | retl |
27 | nop | 26 | nop |
28 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 27 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
29 | .size atomic_add, .-atomic_add | 28 | ENDPROC(atomic_add) |
30 | 29 | ||
31 | .globl atomic_sub | 30 | ENTRY(atomic_sub) /* %o0 = decrement, %o1 = atomic_ptr */ |
32 | .type atomic_sub,#function | ||
33 | atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */ | ||
34 | BACKOFF_SETUP(%o2) | 31 | BACKOFF_SETUP(%o2) |
35 | 1: lduw [%o1], %g1 | 32 | 1: lduw [%o1], %g1 |
36 | sub %g1, %o0, %g7 | 33 | sub %g1, %o0, %g7 |
@@ -41,11 +38,9 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */ | |||
41 | retl | 38 | retl |
42 | nop | 39 | nop |
43 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 40 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
44 | .size atomic_sub, .-atomic_sub | 41 | ENDPROC(atomic_sub) |
45 | 42 | ||
46 | .globl atomic_add_ret | 43 | ENTRY(atomic_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ |
47 | .type atomic_add_ret,#function | ||
48 | atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ | ||
49 | BACKOFF_SETUP(%o2) | 44 | BACKOFF_SETUP(%o2) |
50 | 1: lduw [%o1], %g1 | 45 | 1: lduw [%o1], %g1 |
51 | add %g1, %o0, %g7 | 46 | add %g1, %o0, %g7 |
@@ -56,11 +51,9 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ | |||
56 | retl | 51 | retl |
57 | sra %g1, 0, %o0 | 52 | sra %g1, 0, %o0 |
58 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 53 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
59 | .size atomic_add_ret, .-atomic_add_ret | 54 | ENDPROC(atomic_add_ret) |
60 | 55 | ||
61 | .globl atomic_sub_ret | 56 | ENTRY(atomic_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ |
62 | .type atomic_sub_ret,#function | ||
63 | atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ | ||
64 | BACKOFF_SETUP(%o2) | 57 | BACKOFF_SETUP(%o2) |
65 | 1: lduw [%o1], %g1 | 58 | 1: lduw [%o1], %g1 |
66 | sub %g1, %o0, %g7 | 59 | sub %g1, %o0, %g7 |
@@ -71,11 +64,9 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ | |||
71 | retl | 64 | retl |
72 | sra %g1, 0, %o0 | 65 | sra %g1, 0, %o0 |
73 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 66 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
74 | .size atomic_sub_ret, .-atomic_sub_ret | 67 | ENDPROC(atomic_sub_ret) |
75 | 68 | ||
76 | .globl atomic64_add | 69 | ENTRY(atomic64_add) /* %o0 = increment, %o1 = atomic_ptr */ |
77 | .type atomic64_add,#function | ||
78 | atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ | ||
79 | BACKOFF_SETUP(%o2) | 70 | BACKOFF_SETUP(%o2) |
80 | 1: ldx [%o1], %g1 | 71 | 1: ldx [%o1], %g1 |
81 | add %g1, %o0, %g7 | 72 | add %g1, %o0, %g7 |
@@ -86,11 +77,9 @@ atomic64_add: /* %o0 = increment, %o1 = atomic_ptr */ | |||
86 | retl | 77 | retl |
87 | nop | 78 | nop |
88 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 79 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
89 | .size atomic64_add, .-atomic64_add | 80 | ENDPROC(atomic64_add) |
90 | 81 | ||
91 | .globl atomic64_sub | 82 | ENTRY(atomic64_sub) /* %o0 = decrement, %o1 = atomic_ptr */ |
92 | .type atomic64_sub,#function | ||
93 | atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */ | ||
94 | BACKOFF_SETUP(%o2) | 83 | BACKOFF_SETUP(%o2) |
95 | 1: ldx [%o1], %g1 | 84 | 1: ldx [%o1], %g1 |
96 | sub %g1, %o0, %g7 | 85 | sub %g1, %o0, %g7 |
@@ -101,11 +90,9 @@ atomic64_sub: /* %o0 = decrement, %o1 = atomic_ptr */ | |||
101 | retl | 90 | retl |
102 | nop | 91 | nop |
103 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 92 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
104 | .size atomic64_sub, .-atomic64_sub | 93 | ENDPROC(atomic64_sub) |
105 | 94 | ||
106 | .globl atomic64_add_ret | 95 | ENTRY(atomic64_add_ret) /* %o0 = increment, %o1 = atomic_ptr */ |
107 | .type atomic64_add_ret,#function | ||
108 | atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ | ||
109 | BACKOFF_SETUP(%o2) | 96 | BACKOFF_SETUP(%o2) |
110 | 1: ldx [%o1], %g1 | 97 | 1: ldx [%o1], %g1 |
111 | add %g1, %o0, %g7 | 98 | add %g1, %o0, %g7 |
@@ -116,11 +103,9 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */ | |||
116 | retl | 103 | retl |
117 | add %g1, %o0, %o0 | 104 | add %g1, %o0, %o0 |
118 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 105 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
119 | .size atomic64_add_ret, .-atomic64_add_ret | 106 | ENDPROC(atomic64_add_ret) |
120 | 107 | ||
121 | .globl atomic64_sub_ret | 108 | ENTRY(atomic64_sub_ret) /* %o0 = decrement, %o1 = atomic_ptr */ |
122 | .type atomic64_sub_ret,#function | ||
123 | atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ | ||
124 | BACKOFF_SETUP(%o2) | 109 | BACKOFF_SETUP(%o2) |
125 | 1: ldx [%o1], %g1 | 110 | 1: ldx [%o1], %g1 |
126 | sub %g1, %o0, %g7 | 111 | sub %g1, %o0, %g7 |
@@ -131,4 +116,4 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */ | |||
131 | retl | 116 | retl |
132 | sub %g1, %o0, %o0 | 117 | sub %g1, %o0, %o0 |
133 | 2: BACKOFF_SPIN(%o2, %o3, 1b) | 118 | 2: BACKOFF_SPIN(%o2, %o3, 1b) |
134 | .size atomic64_sub_ret, .-atomic64_sub_ret | 119 | ENDPROC(atomic64_sub_ret) |
diff --git a/arch/sparc/lib/bitops.S b/arch/sparc/lib/bitops.S index 3dc61d5537c0..36f72cc0e67e 100644 --- a/arch/sparc/lib/bitops.S +++ b/arch/sparc/lib/bitops.S | |||
@@ -3,14 +3,13 @@ | |||
3 | * Copyright (C) 2000, 2007 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 2000, 2007 David S. Miller (davem@davemloft.net) |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/linkage.h> | ||
6 | #include <asm/asi.h> | 7 | #include <asm/asi.h> |
7 | #include <asm/backoff.h> | 8 | #include <asm/backoff.h> |
8 | 9 | ||
9 | .text | 10 | .text |
10 | 11 | ||
11 | .globl test_and_set_bit | 12 | ENTRY(test_and_set_bit) /* %o0=nr, %o1=addr */ |
12 | .type test_and_set_bit,#function | ||
13 | test_and_set_bit: /* %o0=nr, %o1=addr */ | ||
14 | BACKOFF_SETUP(%o3) | 13 | BACKOFF_SETUP(%o3) |
15 | srlx %o0, 6, %g1 | 14 | srlx %o0, 6, %g1 |
16 | mov 1, %o2 | 15 | mov 1, %o2 |
@@ -29,11 +28,9 @@ test_and_set_bit: /* %o0=nr, %o1=addr */ | |||
29 | retl | 28 | retl |
30 | nop | 29 | nop |
31 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 30 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
32 | .size test_and_set_bit, .-test_and_set_bit | 31 | ENDPROC(test_and_set_bit) |
33 | 32 | ||
34 | .globl test_and_clear_bit | 33 | ENTRY(test_and_clear_bit) /* %o0=nr, %o1=addr */ |
35 | .type test_and_clear_bit,#function | ||
36 | test_and_clear_bit: /* %o0=nr, %o1=addr */ | ||
37 | BACKOFF_SETUP(%o3) | 34 | BACKOFF_SETUP(%o3) |
38 | srlx %o0, 6, %g1 | 35 | srlx %o0, 6, %g1 |
39 | mov 1, %o2 | 36 | mov 1, %o2 |
@@ -52,11 +49,9 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */ | |||
52 | retl | 49 | retl |
53 | nop | 50 | nop |
54 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 51 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
55 | .size test_and_clear_bit, .-test_and_clear_bit | 52 | ENDPROC(test_and_clear_bit) |
56 | 53 | ||
57 | .globl test_and_change_bit | 54 | ENTRY(test_and_change_bit) /* %o0=nr, %o1=addr */ |
58 | .type test_and_change_bit,#function | ||
59 | test_and_change_bit: /* %o0=nr, %o1=addr */ | ||
60 | BACKOFF_SETUP(%o3) | 55 | BACKOFF_SETUP(%o3) |
61 | srlx %o0, 6, %g1 | 56 | srlx %o0, 6, %g1 |
62 | mov 1, %o2 | 57 | mov 1, %o2 |
@@ -75,11 +70,9 @@ test_and_change_bit: /* %o0=nr, %o1=addr */ | |||
75 | retl | 70 | retl |
76 | nop | 71 | nop |
77 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 72 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
78 | .size test_and_change_bit, .-test_and_change_bit | 73 | ENDPROC(test_and_change_bit) |
79 | 74 | ||
80 | .globl set_bit | 75 | ENTRY(set_bit) /* %o0=nr, %o1=addr */ |
81 | .type set_bit,#function | ||
82 | set_bit: /* %o0=nr, %o1=addr */ | ||
83 | BACKOFF_SETUP(%o3) | 76 | BACKOFF_SETUP(%o3) |
84 | srlx %o0, 6, %g1 | 77 | srlx %o0, 6, %g1 |
85 | mov 1, %o2 | 78 | mov 1, %o2 |
@@ -96,11 +89,9 @@ set_bit: /* %o0=nr, %o1=addr */ | |||
96 | retl | 89 | retl |
97 | nop | 90 | nop |
98 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 91 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
99 | .size set_bit, .-set_bit | 92 | ENDPROC(set_bit) |
100 | 93 | ||
101 | .globl clear_bit | 94 | ENTRY(clear_bit) /* %o0=nr, %o1=addr */ |
102 | .type clear_bit,#function | ||
103 | clear_bit: /* %o0=nr, %o1=addr */ | ||
104 | BACKOFF_SETUP(%o3) | 95 | BACKOFF_SETUP(%o3) |
105 | srlx %o0, 6, %g1 | 96 | srlx %o0, 6, %g1 |
106 | mov 1, %o2 | 97 | mov 1, %o2 |
@@ -117,11 +108,9 @@ clear_bit: /* %o0=nr, %o1=addr */ | |||
117 | retl | 108 | retl |
118 | nop | 109 | nop |
119 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 110 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
120 | .size clear_bit, .-clear_bit | 111 | ENDPROC(clear_bit) |
121 | 112 | ||
122 | .globl change_bit | 113 | ENTRY(change_bit) /* %o0=nr, %o1=addr */ |
123 | .type change_bit,#function | ||
124 | change_bit: /* %o0=nr, %o1=addr */ | ||
125 | BACKOFF_SETUP(%o3) | 114 | BACKOFF_SETUP(%o3) |
126 | srlx %o0, 6, %g1 | 115 | srlx %o0, 6, %g1 |
127 | mov 1, %o2 | 116 | mov 1, %o2 |
@@ -138,4 +127,4 @@ change_bit: /* %o0=nr, %o1=addr */ | |||
138 | retl | 127 | retl |
139 | nop | 128 | nop |
140 | 2: BACKOFF_SPIN(%o3, %o4, 1b) | 129 | 2: BACKOFF_SPIN(%o3, %o4, 1b) |
141 | .size change_bit, .-change_bit | 130 | ENDPROC(change_bit) |
diff --git a/arch/sparc/lib/blockops.S b/arch/sparc/lib/blockops.S index 804be87f9a42..3c771011ff4b 100644 --- a/arch/sparc/lib/blockops.S +++ b/arch/sparc/lib/blockops.S | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | 4 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/linkage.h> | ||
7 | #include <asm/page.h> | 8 | #include <asm/page.h> |
8 | 9 | ||
9 | /* Zero out 64 bytes of memory at (buf + offset). | 10 | /* Zero out 64 bytes of memory at (buf + offset). |
@@ -44,10 +45,7 @@ | |||
44 | */ | 45 | */ |
45 | 46 | ||
46 | .text | 47 | .text |
47 | .align 4 | 48 | ENTRY(bzero_1page) |
48 | .globl bzero_1page, __copy_1page | ||
49 | |||
50 | bzero_1page: | ||
51 | /* NOTE: If you change the number of insns of this routine, please check | 49 | /* NOTE: If you change the number of insns of this routine, please check |
52 | * arch/sparc/mm/hypersparc.S */ | 50 | * arch/sparc/mm/hypersparc.S */ |
53 | /* %o0 = buf */ | 51 | /* %o0 = buf */ |
@@ -65,8 +63,9 @@ bzero_1page: | |||
65 | 63 | ||
66 | retl | 64 | retl |
67 | nop | 65 | nop |
66 | ENDPROC(bzero_1page) | ||
68 | 67 | ||
69 | __copy_1page: | 68 | ENTRY(__copy_1page) |
70 | /* NOTE: If you change the number of insns of this routine, please check | 69 | /* NOTE: If you change the number of insns of this routine, please check |
71 | * arch/sparc/mm/hypersparc.S */ | 70 | * arch/sparc/mm/hypersparc.S */ |
72 | /* %o0 = dst, %o1 = src */ | 71 | /* %o0 = dst, %o1 = src */ |
@@ -87,3 +86,4 @@ __copy_1page: | |||
87 | 86 | ||
88 | retl | 87 | retl |
89 | nop | 88 | nop |
89 | ENDPROC(__copy_1page) | ||
diff --git a/arch/sparc/lib/bzero.S b/arch/sparc/lib/bzero.S index 615f401edf69..8c058114b649 100644 --- a/arch/sparc/lib/bzero.S +++ b/arch/sparc/lib/bzero.S | |||
@@ -4,11 +4,11 @@ | |||
4 | * Copyright (C) 2005 David S. Miller <davem@davemloft.net> | 4 | * Copyright (C) 2005 David S. Miller <davem@davemloft.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/linkage.h> | ||
8 | |||
7 | .text | 9 | .text |
8 | 10 | ||
9 | .globl memset | 11 | ENTRY(memset) /* %o0=buf, %o1=pat, %o2=len */ |
10 | .type memset, #function | ||
11 | memset: /* %o0=buf, %o1=pat, %o2=len */ | ||
12 | and %o1, 0xff, %o3 | 12 | and %o1, 0xff, %o3 |
13 | mov %o2, %o1 | 13 | mov %o2, %o1 |
14 | sllx %o3, 8, %g1 | 14 | sllx %o3, 8, %g1 |
@@ -19,9 +19,7 @@ memset: /* %o0=buf, %o1=pat, %o2=len */ | |||
19 | ba,pt %xcc, 1f | 19 | ba,pt %xcc, 1f |
20 | or %g1, %o2, %o2 | 20 | or %g1, %o2, %o2 |
21 | 21 | ||
22 | .globl __bzero | 22 | ENTRY(__bzero) /* %o0=buf, %o1=len */ |
23 | .type __bzero, #function | ||
24 | __bzero: /* %o0=buf, %o1=len */ | ||
25 | clr %o2 | 23 | clr %o2 |
26 | 1: mov %o0, %o3 | 24 | 1: mov %o0, %o3 |
27 | brz,pn %o1, __bzero_done | 25 | brz,pn %o1, __bzero_done |
@@ -78,8 +76,8 @@ __bzero_tiny: | |||
78 | __bzero_done: | 76 | __bzero_done: |
79 | retl | 77 | retl |
80 | mov %o3, %o0 | 78 | mov %o3, %o0 |
81 | .size __bzero, .-__bzero | 79 | ENDPROC(__bzero) |
82 | .size memset, .-memset | 80 | ENDPROC(memset) |
83 | 81 | ||
84 | #define EX_ST(x,y) \ | 82 | #define EX_ST(x,y) \ |
85 | 98: x,y; \ | 83 | 98: x,y; \ |
@@ -89,9 +87,7 @@ __bzero_done: | |||
89 | .text; \ | 87 | .text; \ |
90 | .align 4; | 88 | .align 4; |
91 | 89 | ||
92 | .globl __clear_user | 90 | ENTRY(__clear_user) /* %o0=buf, %o1=len */ |
93 | .type __clear_user, #function | ||
94 | __clear_user: /* %o0=buf, %o1=len */ | ||
95 | brz,pn %o1, __clear_user_done | 91 | brz,pn %o1, __clear_user_done |
96 | cmp %o1, 16 | 92 | cmp %o1, 16 |
97 | bl,pn %icc, __clear_user_tiny | 93 | bl,pn %icc, __clear_user_tiny |
@@ -146,4 +142,4 @@ __clear_user_tiny: | |||
146 | __clear_user_done: | 142 | __clear_user_done: |
147 | retl | 143 | retl |
148 | clr %o0 | 144 | clr %o0 |
149 | .size __clear_user, .-__clear_user | 145 | ENDPROC(__clear_user) |
diff --git a/arch/sparc/lib/divdi3.S b/arch/sparc/lib/divdi3.S index d74bc0925f2d..9614b48b6ef8 100644 --- a/arch/sparc/lib/divdi3.S +++ b/arch/sparc/lib/divdi3.S | |||
@@ -19,7 +19,6 @@ Boston, MA 02111-1307, USA. */ | |||
19 | 19 | ||
20 | .text | 20 | .text |
21 | .align 4 | 21 | .align 4 |
22 | .global .udiv | ||
23 | .globl __divdi3 | 22 | .globl __divdi3 |
24 | __divdi3: | 23 | __divdi3: |
25 | save %sp,-104,%sp | 24 | save %sp,-104,%sp |
@@ -83,8 +82,9 @@ __divdi3: | |||
83 | bne .LL85 | 82 | bne .LL85 |
84 | mov %i0,%o2 | 83 | mov %i0,%o2 |
85 | mov 1,%o0 | 84 | mov 1,%o0 |
86 | call .udiv,0 | ||
87 | mov 0,%o1 | 85 | mov 0,%o1 |
86 | wr %g0, 0, %y | ||
87 | udiv %o0, %o1, %o0 | ||
88 | mov %o0,%o4 | 88 | mov %o0,%o4 |
89 | mov %i0,%o2 | 89 | mov %i0,%o2 |
90 | .LL85: | 90 | .LL85: |
diff --git a/arch/sparc/lib/ipcsum.S b/arch/sparc/lib/ipcsum.S index 58ca5b9a8778..4742d59029ee 100644 --- a/arch/sparc/lib/ipcsum.S +++ b/arch/sparc/lib/ipcsum.S | |||
@@ -1,8 +1,7 @@ | |||
1 | #include <linux/linkage.h> | ||
2 | |||
1 | .text | 3 | .text |
2 | .align 32 | 4 | ENTRY(ip_fast_csum) /* %o0 = iph, %o1 = ihl */ |
3 | .globl ip_fast_csum | ||
4 | .type ip_fast_csum,#function | ||
5 | ip_fast_csum: /* %o0 = iph, %o1 = ihl */ | ||
6 | sub %o1, 4, %g7 | 5 | sub %o1, 4, %g7 |
7 | lduw [%o0 + 0x00], %o2 | 6 | lduw [%o0 + 0x00], %o2 |
8 | lduw [%o0 + 0x04], %g2 | 7 | lduw [%o0 + 0x04], %g2 |
@@ -31,4 +30,4 @@ ip_fast_csum: /* %o0 = iph, %o1 = ihl */ | |||
31 | set 0xffff, %o1 | 30 | set 0xffff, %o1 |
32 | retl | 31 | retl |
33 | and %o2, %o1, %o0 | 32 | and %o2, %o1, %o0 |
34 | .size ip_fast_csum, .-ip_fast_csum | 33 | ENDPROC(ip_fast_csum) |
diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index f73c2240fe60..2dc30875c8bc 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c | |||
@@ -56,23 +56,11 @@ extern int __divdi3(int, int); | |||
56 | extern void (*__copy_1page)(void *, const void *); | 56 | extern void (*__copy_1page)(void *, const void *); |
57 | extern void (*bzero_1page)(void *); | 57 | extern void (*bzero_1page)(void *); |
58 | 58 | ||
59 | extern int __strncmp(const char *, const char *, __kernel_size_t); | ||
60 | |||
61 | extern void ___rw_read_enter(void); | 59 | extern void ___rw_read_enter(void); |
62 | extern void ___rw_read_try(void); | 60 | extern void ___rw_read_try(void); |
63 | extern void ___rw_read_exit(void); | 61 | extern void ___rw_read_exit(void); |
64 | extern void ___rw_write_enter(void); | 62 | extern void ___rw_write_enter(void); |
65 | 63 | ||
66 | /* Alias functions whose names begin with "." and export the aliases. | ||
67 | * The module references will be fixed up by module_frob_arch_sections. | ||
68 | */ | ||
69 | extern int _Div(int, int); | ||
70 | extern int _Mul(int, int); | ||
71 | extern int _Rem(int, int); | ||
72 | extern unsigned _Udiv(unsigned, unsigned); | ||
73 | extern unsigned _Umul(unsigned, unsigned); | ||
74 | extern unsigned _Urem(unsigned, unsigned); | ||
75 | |||
76 | /* Networking helper routines. */ | 64 | /* Networking helper routines. */ |
77 | EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); | 65 | EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); |
78 | 66 | ||
@@ -81,9 +69,6 @@ EXPORT_SYMBOL(__copy_1page); | |||
81 | EXPORT_SYMBOL(__memmove); | 69 | EXPORT_SYMBOL(__memmove); |
82 | EXPORT_SYMBOL(bzero_1page); | 70 | EXPORT_SYMBOL(bzero_1page); |
83 | 71 | ||
84 | /* string functions */ | ||
85 | EXPORT_SYMBOL(__strncmp); | ||
86 | |||
87 | /* Moving data to/from/in userspace. */ | 72 | /* Moving data to/from/in userspace. */ |
88 | EXPORT_SYMBOL(__copy_user); | 73 | EXPORT_SYMBOL(__copy_user); |
89 | 74 | ||
@@ -100,13 +85,6 @@ EXPORT_SYMBOL(__ashldi3); | |||
100 | EXPORT_SYMBOL(__lshrdi3); | 85 | EXPORT_SYMBOL(__lshrdi3); |
101 | EXPORT_SYMBOL(__muldi3); | 86 | EXPORT_SYMBOL(__muldi3); |
102 | EXPORT_SYMBOL(__divdi3); | 87 | EXPORT_SYMBOL(__divdi3); |
103 | |||
104 | EXPORT_SYMBOL(_Rem); | ||
105 | EXPORT_SYMBOL(_Urem); | ||
106 | EXPORT_SYMBOL(_Mul); | ||
107 | EXPORT_SYMBOL(_Umul); | ||
108 | EXPORT_SYMBOL(_Div); | ||
109 | EXPORT_SYMBOL(_Udiv); | ||
110 | #endif | 88 | #endif |
111 | 89 | ||
112 | /* | 90 | /* |
diff --git a/arch/sparc/lib/lshrdi3.S b/arch/sparc/lib/lshrdi3.S index 47a1354c1602..60ebc7cdbee0 100644 --- a/arch/sparc/lib/lshrdi3.S +++ b/arch/sparc/lib/lshrdi3.S | |||
@@ -1,6 +1,6 @@ | |||
1 | #include <linux/linkage.h> | ||
1 | 2 | ||
2 | .globl __lshrdi3 | 3 | ENTRY(__lshrdi3) |
3 | __lshrdi3: | ||
4 | cmp %o2, 0 | 4 | cmp %o2, 0 |
5 | be 3f | 5 | be 3f |
6 | mov 0x20, %g2 | 6 | mov 0x20, %g2 |
@@ -24,3 +24,4 @@ __lshrdi3: | |||
24 | 3: | 24 | 3: |
25 | retl | 25 | retl |
26 | nop | 26 | nop |
27 | ENDPROC(__lshrdi3) | ||
diff --git a/arch/sparc/lib/memmove.S b/arch/sparc/lib/memmove.S index 97395802c23c..b7f6334e159f 100644 --- a/arch/sparc/lib/memmove.S +++ b/arch/sparc/lib/memmove.S | |||
@@ -4,11 +4,10 @@ | |||
4 | * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) | 4 | * Copyright (C) 1996, 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/linkage.h> | ||
8 | |||
7 | .text | 9 | .text |
8 | .align 32 | 10 | ENTRY(memmove) /* o0=dst o1=src o2=len */ |
9 | .globl memmove | ||
10 | .type memmove,#function | ||
11 | memmove: /* o0=dst o1=src o2=len */ | ||
12 | mov %o0, %g1 | 11 | mov %o0, %g1 |
13 | cmp %o0, %o1 | 12 | cmp %o0, %o1 |
14 | bleu,pt %xcc, memcpy | 13 | bleu,pt %xcc, memcpy |
@@ -28,4 +27,4 @@ memmove: /* o0=dst o1=src o2=len */ | |||
28 | 27 | ||
29 | retl | 28 | retl |
30 | mov %g1, %o0 | 29 | mov %g1, %o0 |
31 | .size memmove, .-memmove | 30 | ENDPROC(memmove) |
diff --git a/arch/sparc/lib/mul.S b/arch/sparc/lib/mul.S deleted file mode 100644 index c45470d0b0ce..000000000000 --- a/arch/sparc/lib/mul.S +++ /dev/null | |||
@@ -1,137 +0,0 @@ | |||
1 | /* | ||
2 | * mul.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * Signed multiply, from Appendix E of the Sparc Version 8 | ||
8 | * Architecture Manual. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the upper 32 bits of | ||
13 | * the 64-bit product). | ||
14 | * | ||
15 | * This code optimizes short (less than 13-bit) multiplies. | ||
16 | */ | ||
17 | |||
18 | .globl .mul | ||
19 | .globl _Mul | ||
20 | .mul: | ||
21 | _Mul: /* needed for export */ | ||
22 | mov %o0, %y ! multiplier -> Y | ||
23 | andncc %o0, 0xfff, %g0 ! test bits 12..31 | ||
24 | be Lmul_shortway ! if zero, can do it the short way | ||
25 | andcc %g0, %g0, %o4 ! zero the partial product and clear N and V | ||
26 | |||
27 | /* | ||
28 | * Long multiply. 32 steps, followed by a final shift step. | ||
29 | */ | ||
30 | mulscc %o4, %o1, %o4 ! 1 | ||
31 | mulscc %o4, %o1, %o4 ! 2 | ||
32 | mulscc %o4, %o1, %o4 ! 3 | ||
33 | mulscc %o4, %o1, %o4 ! 4 | ||
34 | mulscc %o4, %o1, %o4 ! 5 | ||
35 | mulscc %o4, %o1, %o4 ! 6 | ||
36 | mulscc %o4, %o1, %o4 ! 7 | ||
37 | mulscc %o4, %o1, %o4 ! 8 | ||
38 | mulscc %o4, %o1, %o4 ! 9 | ||
39 | mulscc %o4, %o1, %o4 ! 10 | ||
40 | mulscc %o4, %o1, %o4 ! 11 | ||
41 | mulscc %o4, %o1, %o4 ! 12 | ||
42 | mulscc %o4, %o1, %o4 ! 13 | ||
43 | mulscc %o4, %o1, %o4 ! 14 | ||
44 | mulscc %o4, %o1, %o4 ! 15 | ||
45 | mulscc %o4, %o1, %o4 ! 16 | ||
46 | mulscc %o4, %o1, %o4 ! 17 | ||
47 | mulscc %o4, %o1, %o4 ! 18 | ||
48 | mulscc %o4, %o1, %o4 ! 19 | ||
49 | mulscc %o4, %o1, %o4 ! 20 | ||
50 | mulscc %o4, %o1, %o4 ! 21 | ||
51 | mulscc %o4, %o1, %o4 ! 22 | ||
52 | mulscc %o4, %o1, %o4 ! 23 | ||
53 | mulscc %o4, %o1, %o4 ! 24 | ||
54 | mulscc %o4, %o1, %o4 ! 25 | ||
55 | mulscc %o4, %o1, %o4 ! 26 | ||
56 | mulscc %o4, %o1, %o4 ! 27 | ||
57 | mulscc %o4, %o1, %o4 ! 28 | ||
58 | mulscc %o4, %o1, %o4 ! 29 | ||
59 | mulscc %o4, %o1, %o4 ! 30 | ||
60 | mulscc %o4, %o1, %o4 ! 31 | ||
61 | mulscc %o4, %o1, %o4 ! 32 | ||
62 | mulscc %o4, %g0, %o4 ! final shift | ||
63 | |||
64 | ! If %o0 was negative, the result is | ||
65 | ! (%o0 * %o1) + (%o1 << 32)) | ||
66 | ! We fix that here. | ||
67 | |||
68 | #if 0 | ||
69 | tst %o0 | ||
70 | bge 1f | ||
71 | rd %y, %o0 | ||
72 | |||
73 | ! %o0 was indeed negative; fix upper 32 bits of result by subtracting | ||
74 | ! %o1 (i.e., return %o4 - %o1 in %o1). | ||
75 | retl | ||
76 | sub %o4, %o1, %o1 | ||
77 | |||
78 | 1: | ||
79 | retl | ||
80 | mov %o4, %o1 | ||
81 | #else | ||
82 | /* Faster code adapted from tege@sics.se's code for umul.S. */ | ||
83 | sra %o0, 31, %o2 ! make mask from sign bit | ||
84 | and %o1, %o2, %o2 ! %o2 = 0 or %o1, depending on sign of %o0 | ||
85 | rd %y, %o0 ! get lower half of product | ||
86 | retl | ||
87 | sub %o4, %o2, %o1 ! subtract compensation | ||
88 | ! and put upper half in place | ||
89 | #endif | ||
90 | |||
91 | Lmul_shortway: | ||
92 | /* | ||
93 | * Short multiply. 12 steps, followed by a final shift step. | ||
94 | * The resulting bits are off by 12 and (32-12) = 20 bit positions, | ||
95 | * but there is no problem with %o0 being negative (unlike above). | ||
96 | */ | ||
97 | mulscc %o4, %o1, %o4 ! 1 | ||
98 | mulscc %o4, %o1, %o4 ! 2 | ||
99 | mulscc %o4, %o1, %o4 ! 3 | ||
100 | mulscc %o4, %o1, %o4 ! 4 | ||
101 | mulscc %o4, %o1, %o4 ! 5 | ||
102 | mulscc %o4, %o1, %o4 ! 6 | ||
103 | mulscc %o4, %o1, %o4 ! 7 | ||
104 | mulscc %o4, %o1, %o4 ! 8 | ||
105 | mulscc %o4, %o1, %o4 ! 9 | ||
106 | mulscc %o4, %o1, %o4 ! 10 | ||
107 | mulscc %o4, %o1, %o4 ! 11 | ||
108 | mulscc %o4, %o1, %o4 ! 12 | ||
109 | mulscc %o4, %g0, %o4 ! final shift | ||
110 | |||
111 | /* | ||
112 | * %o4 has 20 of the bits that should be in the low part of the | ||
113 | * result; %y has the bottom 12 (as %y's top 12). That is: | ||
114 | * | ||
115 | * %o4 %y | ||
116 | * +----------------+----------------+ | ||
117 | * | -12- | -20- | -12- | -20- | | ||
118 | * +------(---------+------)---------+ | ||
119 | * --hi-- ----low-part---- | ||
120 | * | ||
121 | * The upper 12 bits of %o4 should be sign-extended to form the | ||
122 | * high part of the product (i.e., highpart = %o4 >> 20). | ||
123 | */ | ||
124 | |||
125 | rd %y, %o5 | ||
126 | sll %o4, 12, %o0 ! shift middle bits left 12 | ||
127 | srl %o5, 20, %o5 ! shift low bits right 20, zero fill at left | ||
128 | or %o5, %o0, %o0 ! construct low part of result | ||
129 | retl | ||
130 | sra %o4, 20, %o1 ! ... and extract high part of result | ||
131 | |||
132 | .globl .mul_patch | ||
133 | .mul_patch: | ||
134 | smul %o0, %o1, %o0 | ||
135 | retl | ||
136 | rd %y, %o1 | ||
137 | nop | ||
diff --git a/arch/sparc/lib/muldi3.S b/arch/sparc/lib/muldi3.S index 7f17872d0603..9794939d1c12 100644 --- a/arch/sparc/lib/muldi3.S +++ b/arch/sparc/lib/muldi3.S | |||
@@ -63,12 +63,12 @@ __muldi3: | |||
63 | rd %y, %o1 | 63 | rd %y, %o1 |
64 | mov %o1, %l3 | 64 | mov %o1, %l3 |
65 | mov %i1, %o0 | 65 | mov %i1, %o0 |
66 | call .umul | ||
67 | mov %i2, %o1 | 66 | mov %i2, %o1 |
67 | umul %o0, %o1, %o0 | ||
68 | mov %o0, %l0 | 68 | mov %o0, %l0 |
69 | mov %i0, %o0 | 69 | mov %i0, %o0 |
70 | call .umul | ||
71 | mov %i3, %o1 | 70 | mov %i3, %o1 |
71 | umul %o0, %o1, %o0 | ||
72 | add %l0, %o0, %l0 | 72 | add %l0, %o0, %l0 |
73 | mov %l2, %i0 | 73 | mov %l2, %i0 |
74 | add %l2, %l0, %i0 | 74 | add %l2, %l0, %i0 |
diff --git a/arch/sparc/lib/rem.S b/arch/sparc/lib/rem.S deleted file mode 100644 index 42fb86252815..000000000000 --- a/arch/sparc/lib/rem.S +++ /dev/null | |||
@@ -1,384 +0,0 @@ | |||
1 | /* | ||
2 | * rem.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | |||
7 | /* This file is generated from divrem.m4; DO NOT EDIT! */ | ||
8 | /* | ||
9 | * Division and remainder, from Appendix E of the Sparc Version 8 | ||
10 | * Architecture Manual, with fixes from Gordon Irlam. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Input: dividend and divisor in %o0 and %o1 respectively. | ||
15 | * | ||
16 | * m4 parameters: | ||
17 | * .rem name of function to generate | ||
18 | * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1 | ||
19 | * true true=true => signed; true=false => unsigned | ||
20 | * | ||
21 | * Algorithm parameters: | ||
22 | * N how many bits per iteration we try to get (4) | ||
23 | * WORDSIZE total number of bits (32) | ||
24 | * | ||
25 | * Derived constants: | ||
26 | * TOPBITS number of bits in the top decade of a number | ||
27 | * | ||
28 | * Important variables: | ||
29 | * Q the partial quotient under development (initially 0) | ||
30 | * R the remainder so far, initially the dividend | ||
31 | * ITER number of main division loop iterations required; | ||
32 | * equal to ceil(log2(quotient) / N). Note that this | ||
33 | * is the log base (2^N) of the quotient. | ||
34 | * V the current comparand, initially divisor*2^(ITER*N-1) | ||
35 | * | ||
36 | * Cost: | ||
37 | * Current estimate for non-large dividend is | ||
38 | * ceil(log2(quotient) / N) * (10 + 7N/2) + C | ||
39 | * A large dividend is one greater than 2^(31-TOPBITS) and takes a | ||
40 | * different path, as the upper bits of the quotient must be developed | ||
41 | * one bit at a time. | ||
42 | */ | ||
43 | |||
44 | |||
45 | .globl .rem | ||
46 | .globl _Rem | ||
47 | .rem: | ||
48 | _Rem: /* needed for export */ | ||
49 | ! compute sign of result; if neither is negative, no problem | ||
50 | orcc %o1, %o0, %g0 ! either negative? | ||
51 | bge 2f ! no, go do the divide | ||
52 | mov %o0, %g2 ! compute sign in any case | ||
53 | |||
54 | tst %o1 | ||
55 | bge 1f | ||
56 | tst %o0 | ||
57 | ! %o1 is definitely negative; %o0 might also be negative | ||
58 | bge 2f ! if %o0 not negative... | ||
59 | sub %g0, %o1, %o1 ! in any case, make %o1 nonneg | ||
60 | 1: ! %o0 is negative, %o1 is nonnegative | ||
61 | sub %g0, %o0, %o0 ! make %o0 nonnegative | ||
62 | 2: | ||
63 | |||
64 | ! Ready to divide. Compute size of quotient; scale comparand. | ||
65 | orcc %o1, %g0, %o5 | ||
66 | bne 1f | ||
67 | mov %o0, %o3 | ||
68 | |||
69 | ! Divide by zero trap. If it returns, return 0 (about as | ||
70 | ! wrong as possible, but that is what SunOS does...). | ||
71 | ta ST_DIV0 | ||
72 | retl | ||
73 | clr %o0 | ||
74 | |||
75 | 1: | ||
76 | cmp %o3, %o5 ! if %o1 exceeds %o0, done | ||
77 | blu Lgot_result ! (and algorithm fails otherwise) | ||
78 | clr %o2 | ||
79 | |||
80 | sethi %hi(1 << (32 - 4 - 1)), %g1 | ||
81 | |||
82 | cmp %o3, %g1 | ||
83 | blu Lnot_really_big | ||
84 | clr %o4 | ||
85 | |||
86 | ! Here the dividend is >= 2**(31-N) or so. We must be careful here, | ||
87 | ! as our usual N-at-a-shot divide step will cause overflow and havoc. | ||
88 | ! The number of bits in the result here is N*ITER+SC, where SC <= N. | ||
89 | ! Compute ITER in an unorthodox manner: know we need to shift V into | ||
90 | ! the top decade: so do not even bother to compare to R. | ||
91 | 1: | ||
92 | cmp %o5, %g1 | ||
93 | bgeu 3f | ||
94 | mov 1, %g7 | ||
95 | |||
96 | sll %o5, 4, %o5 | ||
97 | |||
98 | b 1b | ||
99 | add %o4, 1, %o4 | ||
100 | |||
101 | ! Now compute %g7. | ||
102 | 2: | ||
103 | addcc %o5, %o5, %o5 | ||
104 | |||
105 | bcc Lnot_too_big | ||
106 | add %g7, 1, %g7 | ||
107 | |||
108 | ! We get here if the %o1 overflowed while shifting. | ||
109 | ! This means that %o3 has the high-order bit set. | ||
110 | ! Restore %o5 and subtract from %o3. | ||
111 | sll %g1, 4, %g1 ! high order bit | ||
112 | srl %o5, 1, %o5 ! rest of %o5 | ||
113 | add %o5, %g1, %o5 | ||
114 | |||
115 | b Ldo_single_div | ||
116 | sub %g7, 1, %g7 | ||
117 | |||
118 | Lnot_too_big: | ||
119 | 3: | ||
120 | cmp %o5, %o3 | ||
121 | blu 2b | ||
122 | nop | ||
123 | |||
124 | be Ldo_single_div | ||
125 | nop | ||
126 | /* NB: these are commented out in the V8-Sparc manual as well */ | ||
127 | /* (I do not understand this) */ | ||
128 | ! %o5 > %o3: went too far: back up 1 step | ||
129 | ! srl %o5, 1, %o5 | ||
130 | ! dec %g7 | ||
131 | ! do single-bit divide steps | ||
132 | ! | ||
133 | ! We have to be careful here. We know that %o3 >= %o5, so we can do the | ||
134 | ! first divide step without thinking. BUT, the others are conditional, | ||
135 | ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- | ||
136 | ! order bit set in the first step, just falling into the regular | ||
137 | ! division loop will mess up the first time around. | ||
138 | ! So we unroll slightly... | ||
139 | Ldo_single_div: | ||
140 | subcc %g7, 1, %g7 | ||
141 | bl Lend_regular_divide | ||
142 | nop | ||
143 | |||
144 | sub %o3, %o5, %o3 | ||
145 | mov 1, %o2 | ||
146 | |||
147 | b Lend_single_divloop | ||
148 | nop | ||
149 | Lsingle_divloop: | ||
150 | sll %o2, 1, %o2 | ||
151 | |||
152 | bl 1f | ||
153 | srl %o5, 1, %o5 | ||
154 | ! %o3 >= 0 | ||
155 | sub %o3, %o5, %o3 | ||
156 | |||
157 | b 2f | ||
158 | add %o2, 1, %o2 | ||
159 | 1: ! %o3 < 0 | ||
160 | add %o3, %o5, %o3 | ||
161 | sub %o2, 1, %o2 | ||
162 | 2: | ||
163 | Lend_single_divloop: | ||
164 | subcc %g7, 1, %g7 | ||
165 | bge Lsingle_divloop | ||
166 | tst %o3 | ||
167 | |||
168 | b,a Lend_regular_divide | ||
169 | |||
170 | Lnot_really_big: | ||
171 | 1: | ||
172 | sll %o5, 4, %o5 | ||
173 | cmp %o5, %o3 | ||
174 | bleu 1b | ||
175 | addcc %o4, 1, %o4 | ||
176 | be Lgot_result | ||
177 | sub %o4, 1, %o4 | ||
178 | |||
179 | tst %o3 ! set up for initial iteration | ||
180 | Ldivloop: | ||
181 | sll %o2, 4, %o2 | ||
182 | ! depth 1, accumulated bits 0 | ||
183 | bl L.1.16 | ||
184 | srl %o5,1,%o5 | ||
185 | ! remainder is positive | ||
186 | subcc %o3,%o5,%o3 | ||
187 | ! depth 2, accumulated bits 1 | ||
188 | bl L.2.17 | ||
189 | srl %o5,1,%o5 | ||
190 | ! remainder is positive | ||
191 | subcc %o3,%o5,%o3 | ||
192 | ! depth 3, accumulated bits 3 | ||
193 | bl L.3.19 | ||
194 | srl %o5,1,%o5 | ||
195 | ! remainder is positive | ||
196 | subcc %o3,%o5,%o3 | ||
197 | ! depth 4, accumulated bits 7 | ||
198 | bl L.4.23 | ||
199 | srl %o5,1,%o5 | ||
200 | ! remainder is positive | ||
201 | subcc %o3,%o5,%o3 | ||
202 | |||
203 | b 9f | ||
204 | add %o2, (7*2+1), %o2 | ||
205 | |||
206 | L.4.23: | ||
207 | ! remainder is negative | ||
208 | addcc %o3,%o5,%o3 | ||
209 | b 9f | ||
210 | add %o2, (7*2-1), %o2 | ||
211 | |||
212 | L.3.19: | ||
213 | ! remainder is negative | ||
214 | addcc %o3,%o5,%o3 | ||
215 | ! depth 4, accumulated bits 5 | ||
216 | bl L.4.21 | ||
217 | srl %o5,1,%o5 | ||
218 | ! remainder is positive | ||
219 | subcc %o3,%o5,%o3 | ||
220 | b 9f | ||
221 | add %o2, (5*2+1), %o2 | ||
222 | |||
223 | L.4.21: | ||
224 | ! remainder is negative | ||
225 | addcc %o3,%o5,%o3 | ||
226 | b 9f | ||
227 | add %o2, (5*2-1), %o2 | ||
228 | |||
229 | L.2.17: | ||
230 | ! remainder is negative | ||
231 | addcc %o3,%o5,%o3 | ||
232 | ! depth 3, accumulated bits 1 | ||
233 | bl L.3.17 | ||
234 | srl %o5,1,%o5 | ||
235 | ! remainder is positive | ||
236 | subcc %o3,%o5,%o3 | ||
237 | ! depth 4, accumulated bits 3 | ||
238 | bl L.4.19 | ||
239 | srl %o5,1,%o5 | ||
240 | ! remainder is positive | ||
241 | subcc %o3,%o5,%o3 | ||
242 | b 9f | ||
243 | add %o2, (3*2+1), %o2 | ||
244 | |||
245 | L.4.19: | ||
246 | ! remainder is negative | ||
247 | addcc %o3,%o5,%o3 | ||
248 | b 9f | ||
249 | add %o2, (3*2-1), %o2 | ||
250 | |||
251 | L.3.17: | ||
252 | ! remainder is negative | ||
253 | addcc %o3,%o5,%o3 | ||
254 | ! depth 4, accumulated bits 1 | ||
255 | bl L.4.17 | ||
256 | srl %o5,1,%o5 | ||
257 | ! remainder is positive | ||
258 | subcc %o3,%o5,%o3 | ||
259 | b 9f | ||
260 | add %o2, (1*2+1), %o2 | ||
261 | |||
262 | L.4.17: | ||
263 | ! remainder is negative | ||
264 | addcc %o3,%o5,%o3 | ||
265 | b 9f | ||
266 | add %o2, (1*2-1), %o2 | ||
267 | |||
268 | L.1.16: | ||
269 | ! remainder is negative | ||
270 | addcc %o3,%o5,%o3 | ||
271 | ! depth 2, accumulated bits -1 | ||
272 | bl L.2.15 | ||
273 | srl %o5,1,%o5 | ||
274 | ! remainder is positive | ||
275 | subcc %o3,%o5,%o3 | ||
276 | ! depth 3, accumulated bits -1 | ||
277 | bl L.3.15 | ||
278 | srl %o5,1,%o5 | ||
279 | ! remainder is positive | ||
280 | subcc %o3,%o5,%o3 | ||
281 | ! depth 4, accumulated bits -1 | ||
282 | bl L.4.15 | ||
283 | srl %o5,1,%o5 | ||
284 | ! remainder is positive | ||
285 | subcc %o3,%o5,%o3 | ||
286 | b 9f | ||
287 | add %o2, (-1*2+1), %o2 | ||
288 | |||
289 | L.4.15: | ||
290 | ! remainder is negative | ||
291 | addcc %o3,%o5,%o3 | ||
292 | b 9f | ||
293 | add %o2, (-1*2-1), %o2 | ||
294 | |||
295 | L.3.15: | ||
296 | ! remainder is negative | ||
297 | addcc %o3,%o5,%o3 | ||
298 | ! depth 4, accumulated bits -3 | ||
299 | bl L.4.13 | ||
300 | srl %o5,1,%o5 | ||
301 | ! remainder is positive | ||
302 | subcc %o3,%o5,%o3 | ||
303 | b 9f | ||
304 | add %o2, (-3*2+1), %o2 | ||
305 | |||
306 | L.4.13: | ||
307 | ! remainder is negative | ||
308 | addcc %o3,%o5,%o3 | ||
309 | b 9f | ||
310 | add %o2, (-3*2-1), %o2 | ||
311 | |||
312 | L.2.15: | ||
313 | ! remainder is negative | ||
314 | addcc %o3,%o5,%o3 | ||
315 | ! depth 3, accumulated bits -3 | ||
316 | bl L.3.13 | ||
317 | srl %o5,1,%o5 | ||
318 | ! remainder is positive | ||
319 | subcc %o3,%o5,%o3 | ||
320 | ! depth 4, accumulated bits -5 | ||
321 | bl L.4.11 | ||
322 | srl %o5,1,%o5 | ||
323 | ! remainder is positive | ||
324 | subcc %o3,%o5,%o3 | ||
325 | b 9f | ||
326 | add %o2, (-5*2+1), %o2 | ||
327 | |||
328 | L.4.11: | ||
329 | ! remainder is negative | ||
330 | addcc %o3,%o5,%o3 | ||
331 | b 9f | ||
332 | add %o2, (-5*2-1), %o2 | ||
333 | |||
334 | |||
335 | L.3.13: | ||
336 | ! remainder is negative | ||
337 | addcc %o3,%o5,%o3 | ||
338 | ! depth 4, accumulated bits -7 | ||
339 | bl L.4.9 | ||
340 | srl %o5,1,%o5 | ||
341 | ! remainder is positive | ||
342 | subcc %o3,%o5,%o3 | ||
343 | b 9f | ||
344 | add %o2, (-7*2+1), %o2 | ||
345 | |||
346 | L.4.9: | ||
347 | ! remainder is negative | ||
348 | addcc %o3,%o5,%o3 | ||
349 | b 9f | ||
350 | add %o2, (-7*2-1), %o2 | ||
351 | |||
352 | 9: | ||
353 | Lend_regular_divide: | ||
354 | subcc %o4, 1, %o4 | ||
355 | bge Ldivloop | ||
356 | tst %o3 | ||
357 | |||
358 | bl,a Lgot_result | ||
359 | ! non-restoring fixup here (one instruction only!) | ||
360 | add %o3, %o1, %o3 | ||
361 | |||
362 | Lgot_result: | ||
363 | ! check to see if answer should be < 0 | ||
364 | tst %g2 | ||
365 | bl,a 1f | ||
366 | sub %g0, %o3, %o3 | ||
367 | 1: | ||
368 | retl | ||
369 | mov %o3, %o0 | ||
370 | |||
371 | .globl .rem_patch | ||
372 | .rem_patch: | ||
373 | sra %o0, 0x1f, %o4 | ||
374 | wr %o4, 0x0, %y | ||
375 | nop | ||
376 | nop | ||
377 | nop | ||
378 | sdivcc %o0, %o1, %o2 | ||
379 | bvs,a 1f | ||
380 | xnor %o2, %g0, %o2 | ||
381 | 1: smul %o2, %o1, %o2 | ||
382 | retl | ||
383 | sub %o0, %o2, %o0 | ||
384 | nop | ||
diff --git a/arch/sparc/lib/sdiv.S b/arch/sparc/lib/sdiv.S deleted file mode 100644 index f0a0d4e4db78..000000000000 --- a/arch/sparc/lib/sdiv.S +++ /dev/null | |||
@@ -1,381 +0,0 @@ | |||
1 | /* | ||
2 | * sdiv.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | |||
7 | /* This file is generated from divrem.m4; DO NOT EDIT! */ | ||
8 | /* | ||
9 | * Division and remainder, from Appendix E of the Sparc Version 8 | ||
10 | * Architecture Manual, with fixes from Gordon Irlam. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Input: dividend and divisor in %o0 and %o1 respectively. | ||
15 | * | ||
16 | * m4 parameters: | ||
17 | * .div name of function to generate | ||
18 | * div div=div => %o0 / %o1; div=rem => %o0 % %o1 | ||
19 | * true true=true => signed; true=false => unsigned | ||
20 | * | ||
21 | * Algorithm parameters: | ||
22 | * N how many bits per iteration we try to get (4) | ||
23 | * WORDSIZE total number of bits (32) | ||
24 | * | ||
25 | * Derived constants: | ||
26 | * TOPBITS number of bits in the top decade of a number | ||
27 | * | ||
28 | * Important variables: | ||
29 | * Q the partial quotient under development (initially 0) | ||
30 | * R the remainder so far, initially the dividend | ||
31 | * ITER number of main division loop iterations required; | ||
32 | * equal to ceil(log2(quotient) / N). Note that this | ||
33 | * is the log base (2^N) of the quotient. | ||
34 | * V the current comparand, initially divisor*2^(ITER*N-1) | ||
35 | * | ||
36 | * Cost: | ||
37 | * Current estimate for non-large dividend is | ||
38 | * ceil(log2(quotient) / N) * (10 + 7N/2) + C | ||
39 | * A large dividend is one greater than 2^(31-TOPBITS) and takes a | ||
40 | * different path, as the upper bits of the quotient must be developed | ||
41 | * one bit at a time. | ||
42 | */ | ||
43 | |||
44 | |||
45 | .globl .div | ||
46 | .globl _Div | ||
47 | .div: | ||
48 | _Div: /* needed for export */ | ||
49 | ! compute sign of result; if neither is negative, no problem | ||
50 | orcc %o1, %o0, %g0 ! either negative? | ||
51 | bge 2f ! no, go do the divide | ||
52 | xor %o1, %o0, %g2 ! compute sign in any case | ||
53 | |||
54 | tst %o1 | ||
55 | bge 1f | ||
56 | tst %o0 | ||
57 | ! %o1 is definitely negative; %o0 might also be negative | ||
58 | bge 2f ! if %o0 not negative... | ||
59 | sub %g0, %o1, %o1 ! in any case, make %o1 nonneg | ||
60 | 1: ! %o0 is negative, %o1 is nonnegative | ||
61 | sub %g0, %o0, %o0 ! make %o0 nonnegative | ||
62 | 2: | ||
63 | |||
64 | ! Ready to divide. Compute size of quotient; scale comparand. | ||
65 | orcc %o1, %g0, %o5 | ||
66 | bne 1f | ||
67 | mov %o0, %o3 | ||
68 | |||
69 | ! Divide by zero trap. If it returns, return 0 (about as | ||
70 | ! wrong as possible, but that is what SunOS does...). | ||
71 | ta ST_DIV0 | ||
72 | retl | ||
73 | clr %o0 | ||
74 | |||
75 | 1: | ||
76 | cmp %o3, %o5 ! if %o1 exceeds %o0, done | ||
77 | blu Lgot_result ! (and algorithm fails otherwise) | ||
78 | clr %o2 | ||
79 | |||
80 | sethi %hi(1 << (32 - 4 - 1)), %g1 | ||
81 | |||
82 | cmp %o3, %g1 | ||
83 | blu Lnot_really_big | ||
84 | clr %o4 | ||
85 | |||
86 | ! Here the dividend is >= 2**(31-N) or so. We must be careful here, | ||
87 | ! as our usual N-at-a-shot divide step will cause overflow and havoc. | ||
88 | ! The number of bits in the result here is N*ITER+SC, where SC <= N. | ||
89 | ! Compute ITER in an unorthodox manner: know we need to shift V into | ||
90 | ! the top decade: so do not even bother to compare to R. | ||
91 | 1: | ||
92 | cmp %o5, %g1 | ||
93 | bgeu 3f | ||
94 | mov 1, %g7 | ||
95 | |||
96 | sll %o5, 4, %o5 | ||
97 | |||
98 | b 1b | ||
99 | add %o4, 1, %o4 | ||
100 | |||
101 | ! Now compute %g7. | ||
102 | 2: | ||
103 | addcc %o5, %o5, %o5 | ||
104 | bcc Lnot_too_big | ||
105 | add %g7, 1, %g7 | ||
106 | |||
107 | ! We get here if the %o1 overflowed while shifting. | ||
108 | ! This means that %o3 has the high-order bit set. | ||
109 | ! Restore %o5 and subtract from %o3. | ||
110 | sll %g1, 4, %g1 ! high order bit | ||
111 | srl %o5, 1, %o5 ! rest of %o5 | ||
112 | add %o5, %g1, %o5 | ||
113 | |||
114 | b Ldo_single_div | ||
115 | sub %g7, 1, %g7 | ||
116 | |||
117 | Lnot_too_big: | ||
118 | 3: | ||
119 | cmp %o5, %o3 | ||
120 | blu 2b | ||
121 | nop | ||
122 | |||
123 | be Ldo_single_div | ||
124 | nop | ||
125 | /* NB: these are commented out in the V8-Sparc manual as well */ | ||
126 | /* (I do not understand this) */ | ||
127 | ! %o5 > %o3: went too far: back up 1 step | ||
128 | ! srl %o5, 1, %o5 | ||
129 | ! dec %g7 | ||
130 | ! do single-bit divide steps | ||
131 | ! | ||
132 | ! We have to be careful here. We know that %o3 >= %o5, so we can do the | ||
133 | ! first divide step without thinking. BUT, the others are conditional, | ||
134 | ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- | ||
135 | ! order bit set in the first step, just falling into the regular | ||
136 | ! division loop will mess up the first time around. | ||
137 | ! So we unroll slightly... | ||
138 | Ldo_single_div: | ||
139 | subcc %g7, 1, %g7 | ||
140 | bl Lend_regular_divide | ||
141 | nop | ||
142 | |||
143 | sub %o3, %o5, %o3 | ||
144 | mov 1, %o2 | ||
145 | |||
146 | b Lend_single_divloop | ||
147 | nop | ||
148 | Lsingle_divloop: | ||
149 | sll %o2, 1, %o2 | ||
150 | |||
151 | bl 1f | ||
152 | srl %o5, 1, %o5 | ||
153 | ! %o3 >= 0 | ||
154 | sub %o3, %o5, %o3 | ||
155 | |||
156 | b 2f | ||
157 | add %o2, 1, %o2 | ||
158 | 1: ! %o3 < 0 | ||
159 | add %o3, %o5, %o3 | ||
160 | sub %o2, 1, %o2 | ||
161 | 2: | ||
162 | Lend_single_divloop: | ||
163 | subcc %g7, 1, %g7 | ||
164 | bge Lsingle_divloop | ||
165 | tst %o3 | ||
166 | |||
167 | b,a Lend_regular_divide | ||
168 | |||
169 | Lnot_really_big: | ||
170 | 1: | ||
171 | sll %o5, 4, %o5 | ||
172 | cmp %o5, %o3 | ||
173 | bleu 1b | ||
174 | addcc %o4, 1, %o4 | ||
175 | |||
176 | be Lgot_result | ||
177 | sub %o4, 1, %o4 | ||
178 | |||
179 | tst %o3 ! set up for initial iteration | ||
180 | Ldivloop: | ||
181 | sll %o2, 4, %o2 | ||
182 | ! depth 1, accumulated bits 0 | ||
183 | bl L.1.16 | ||
184 | srl %o5,1,%o5 | ||
185 | ! remainder is positive | ||
186 | subcc %o3,%o5,%o3 | ||
187 | ! depth 2, accumulated bits 1 | ||
188 | bl L.2.17 | ||
189 | srl %o5,1,%o5 | ||
190 | ! remainder is positive | ||
191 | subcc %o3,%o5,%o3 | ||
192 | ! depth 3, accumulated bits 3 | ||
193 | bl L.3.19 | ||
194 | srl %o5,1,%o5 | ||
195 | ! remainder is positive | ||
196 | subcc %o3,%o5,%o3 | ||
197 | ! depth 4, accumulated bits 7 | ||
198 | bl L.4.23 | ||
199 | srl %o5,1,%o5 | ||
200 | ! remainder is positive | ||
201 | subcc %o3,%o5,%o3 | ||
202 | b 9f | ||
203 | add %o2, (7*2+1), %o2 | ||
204 | |||
205 | L.4.23: | ||
206 | ! remainder is negative | ||
207 | addcc %o3,%o5,%o3 | ||
208 | b 9f | ||
209 | add %o2, (7*2-1), %o2 | ||
210 | |||
211 | L.3.19: | ||
212 | ! remainder is negative | ||
213 | addcc %o3,%o5,%o3 | ||
214 | ! depth 4, accumulated bits 5 | ||
215 | bl L.4.21 | ||
216 | srl %o5,1,%o5 | ||
217 | ! remainder is positive | ||
218 | subcc %o3,%o5,%o3 | ||
219 | b 9f | ||
220 | add %o2, (5*2+1), %o2 | ||
221 | |||
222 | L.4.21: | ||
223 | ! remainder is negative | ||
224 | addcc %o3,%o5,%o3 | ||
225 | b 9f | ||
226 | add %o2, (5*2-1), %o2 | ||
227 | |||
228 | L.2.17: | ||
229 | ! remainder is negative | ||
230 | addcc %o3,%o5,%o3 | ||
231 | ! depth 3, accumulated bits 1 | ||
232 | bl L.3.17 | ||
233 | srl %o5,1,%o5 | ||
234 | ! remainder is positive | ||
235 | subcc %o3,%o5,%o3 | ||
236 | ! depth 4, accumulated bits 3 | ||
237 | bl L.4.19 | ||
238 | srl %o5,1,%o5 | ||
239 | ! remainder is positive | ||
240 | subcc %o3,%o5,%o3 | ||
241 | b 9f | ||
242 | add %o2, (3*2+1), %o2 | ||
243 | |||
244 | L.4.19: | ||
245 | ! remainder is negative | ||
246 | addcc %o3,%o5,%o3 | ||
247 | b 9f | ||
248 | add %o2, (3*2-1), %o2 | ||
249 | |||
250 | |||
251 | L.3.17: | ||
252 | ! remainder is negative | ||
253 | addcc %o3,%o5,%o3 | ||
254 | ! depth 4, accumulated bits 1 | ||
255 | bl L.4.17 | ||
256 | srl %o5,1,%o5 | ||
257 | ! remainder is positive | ||
258 | subcc %o3,%o5,%o3 | ||
259 | b 9f | ||
260 | add %o2, (1*2+1), %o2 | ||
261 | |||
262 | L.4.17: | ||
263 | ! remainder is negative | ||
264 | addcc %o3,%o5,%o3 | ||
265 | b 9f | ||
266 | add %o2, (1*2-1), %o2 | ||
267 | |||
268 | L.1.16: | ||
269 | ! remainder is negative | ||
270 | addcc %o3,%o5,%o3 | ||
271 | ! depth 2, accumulated bits -1 | ||
272 | bl L.2.15 | ||
273 | srl %o5,1,%o5 | ||
274 | ! remainder is positive | ||
275 | subcc %o3,%o5,%o3 | ||
276 | ! depth 3, accumulated bits -1 | ||
277 | bl L.3.15 | ||
278 | srl %o5,1,%o5 | ||
279 | ! remainder is positive | ||
280 | subcc %o3,%o5,%o3 | ||
281 | ! depth 4, accumulated bits -1 | ||
282 | bl L.4.15 | ||
283 | srl %o5,1,%o5 | ||
284 | ! remainder is positive | ||
285 | subcc %o3,%o5,%o3 | ||
286 | b 9f | ||
287 | add %o2, (-1*2+1), %o2 | ||
288 | |||
289 | L.4.15: | ||
290 | ! remainder is negative | ||
291 | addcc %o3,%o5,%o3 | ||
292 | b 9f | ||
293 | add %o2, (-1*2-1), %o2 | ||
294 | |||
295 | L.3.15: | ||
296 | ! remainder is negative | ||
297 | addcc %o3,%o5,%o3 | ||
298 | ! depth 4, accumulated bits -3 | ||
299 | bl L.4.13 | ||
300 | srl %o5,1,%o5 | ||
301 | ! remainder is positive | ||
302 | subcc %o3,%o5,%o3 | ||
303 | b 9f | ||
304 | add %o2, (-3*2+1), %o2 | ||
305 | |||
306 | L.4.13: | ||
307 | ! remainder is negative | ||
308 | addcc %o3,%o5,%o3 | ||
309 | b 9f | ||
310 | add %o2, (-3*2-1), %o2 | ||
311 | |||
312 | L.2.15: | ||
313 | ! remainder is negative | ||
314 | addcc %o3,%o5,%o3 | ||
315 | ! depth 3, accumulated bits -3 | ||
316 | bl L.3.13 | ||
317 | srl %o5,1,%o5 | ||
318 | ! remainder is positive | ||
319 | subcc %o3,%o5,%o3 | ||
320 | ! depth 4, accumulated bits -5 | ||
321 | bl L.4.11 | ||
322 | srl %o5,1,%o5 | ||
323 | ! remainder is positive | ||
324 | subcc %o3,%o5,%o3 | ||
325 | b 9f | ||
326 | add %o2, (-5*2+1), %o2 | ||
327 | |||
328 | L.4.11: | ||
329 | ! remainder is negative | ||
330 | addcc %o3,%o5,%o3 | ||
331 | b 9f | ||
332 | add %o2, (-5*2-1), %o2 | ||
333 | |||
334 | L.3.13: | ||
335 | ! remainder is negative | ||
336 | addcc %o3,%o5,%o3 | ||
337 | ! depth 4, accumulated bits -7 | ||
338 | bl L.4.9 | ||
339 | srl %o5,1,%o5 | ||
340 | ! remainder is positive | ||
341 | subcc %o3,%o5,%o3 | ||
342 | b 9f | ||
343 | add %o2, (-7*2+1), %o2 | ||
344 | |||
345 | L.4.9: | ||
346 | ! remainder is negative | ||
347 | addcc %o3,%o5,%o3 | ||
348 | b 9f | ||
349 | add %o2, (-7*2-1), %o2 | ||
350 | |||
351 | 9: | ||
352 | Lend_regular_divide: | ||
353 | subcc %o4, 1, %o4 | ||
354 | bge Ldivloop | ||
355 | tst %o3 | ||
356 | |||
357 | bl,a Lgot_result | ||
358 | ! non-restoring fixup here (one instruction only!) | ||
359 | sub %o2, 1, %o2 | ||
360 | |||
361 | Lgot_result: | ||
362 | ! check to see if answer should be < 0 | ||
363 | tst %g2 | ||
364 | bl,a 1f | ||
365 | sub %g0, %o2, %o2 | ||
366 | 1: | ||
367 | retl | ||
368 | mov %o2, %o0 | ||
369 | |||
370 | .globl .div_patch | ||
371 | .div_patch: | ||
372 | sra %o0, 0x1f, %o2 | ||
373 | wr %o2, 0x0, %y | ||
374 | nop | ||
375 | nop | ||
376 | nop | ||
377 | sdivcc %o0, %o1, %o0 | ||
378 | bvs,a 1f | ||
379 | xnor %o0, %g0, %o0 | ||
380 | 1: retl | ||
381 | nop | ||
diff --git a/arch/sparc/lib/strlen_user_64.S b/arch/sparc/lib/strlen_user_64.S index 114ed111e251..c3df71fa4928 100644 --- a/arch/sparc/lib/strlen_user_64.S +++ b/arch/sparc/lib/strlen_user_64.S | |||
@@ -8,16 +8,16 @@ | |||
8 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 8 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/linkage.h> | ||
11 | #include <asm/asi.h> | 12 | #include <asm/asi.h> |
12 | 13 | ||
13 | #define LO_MAGIC 0x01010101 | 14 | #define LO_MAGIC 0x01010101 |
14 | #define HI_MAGIC 0x80808080 | 15 | #define HI_MAGIC 0x80808080 |
15 | 16 | ||
16 | .align 4 | 17 | .align 4 |
17 | .global __strlen_user, __strnlen_user | 18 | ENTRY(__strlen_user) |
18 | __strlen_user: | ||
19 | sethi %hi(32768), %o1 | 19 | sethi %hi(32768), %o1 |
20 | __strnlen_user: | 20 | ENTRY(__strnlen_user) |
21 | mov %o1, %g1 | 21 | mov %o1, %g1 |
22 | mov %o0, %o1 | 22 | mov %o0, %o1 |
23 | andcc %o0, 3, %g0 | 23 | andcc %o0, 3, %g0 |
@@ -78,6 +78,8 @@ __strnlen_user: | |||
78 | mov 2, %o0 | 78 | mov 2, %o0 |
79 | 23: retl | 79 | 23: retl |
80 | mov 3, %o0 | 80 | mov 3, %o0 |
81 | ENDPROC(__strlen_user) | ||
82 | ENDPROC(__strnlen_user) | ||
81 | 83 | ||
82 | .section .fixup,#alloc,#execinstr | 84 | .section .fixup,#alloc,#execinstr |
83 | .align 4 | 85 | .align 4 |
diff --git a/arch/sparc/lib/strncmp_32.S b/arch/sparc/lib/strncmp_32.S index 494ec664537a..c0d1b568c1c5 100644 --- a/arch/sparc/lib/strncmp_32.S +++ b/arch/sparc/lib/strncmp_32.S | |||
@@ -3,11 +3,10 @@ | |||
3 | * generic strncmp routine. | 3 | * generic strncmp routine. |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/linkage.h> | ||
7 | |||
6 | .text | 8 | .text |
7 | .align 4 | 9 | ENTRY(strncmp) |
8 | .global __strncmp, strncmp | ||
9 | __strncmp: | ||
10 | strncmp: | ||
11 | mov %o0, %g3 | 10 | mov %o0, %g3 |
12 | mov 0, %o3 | 11 | mov 0, %o3 |
13 | 12 | ||
@@ -116,3 +115,4 @@ strncmp: | |||
116 | and %g2, 0xff, %o0 | 115 | and %g2, 0xff, %o0 |
117 | retl | 116 | retl |
118 | sub %o3, %o0, %o0 | 117 | sub %o3, %o0, %o0 |
118 | ENDPROC(strncmp) | ||
diff --git a/arch/sparc/lib/strncmp_64.S b/arch/sparc/lib/strncmp_64.S index 980e83751556..0656627166f3 100644 --- a/arch/sparc/lib/strncmp_64.S +++ b/arch/sparc/lib/strncmp_64.S | |||
@@ -4,13 +4,11 @@ | |||
4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | 4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/linkage.h> | ||
7 | #include <asm/asi.h> | 8 | #include <asm/asi.h> |
8 | 9 | ||
9 | .text | 10 | .text |
10 | .align 32 | 11 | ENTRY(strncmp) |
11 | .globl strncmp | ||
12 | .type strncmp,#function | ||
13 | strncmp: | ||
14 | brlez,pn %o2, 3f | 12 | brlez,pn %o2, 3f |
15 | lduba [%o0] (ASI_PNF), %o3 | 13 | lduba [%o0] (ASI_PNF), %o3 |
16 | 1: | 14 | 1: |
@@ -29,4 +27,4 @@ strncmp: | |||
29 | 3: | 27 | 3: |
30 | retl | 28 | retl |
31 | clr %o0 | 29 | clr %o0 |
32 | .size strncmp, .-strncmp | 30 | ENDPROC(strncmp) |
diff --git a/arch/sparc/lib/strncpy_from_user_32.S b/arch/sparc/lib/strncpy_from_user_32.S index d77198976a66..db0ed2964bdb 100644 --- a/arch/sparc/lib/strncpy_from_user_32.S +++ b/arch/sparc/lib/strncpy_from_user_32.S | |||
@@ -3,11 +3,11 @@ | |||
3 | * Copyright(C) 1996 David S. Miller | 3 | * Copyright(C) 1996 David S. Miller |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/linkage.h> | ||
6 | #include <asm/ptrace.h> | 7 | #include <asm/ptrace.h> |
7 | #include <asm/errno.h> | 8 | #include <asm/errno.h> |
8 | 9 | ||
9 | .text | 10 | .text |
10 | .align 4 | ||
11 | 11 | ||
12 | /* Must return: | 12 | /* Must return: |
13 | * | 13 | * |
@@ -16,8 +16,7 @@ | |||
16 | * bytes copied if we hit a null byte | 16 | * bytes copied if we hit a null byte |
17 | */ | 17 | */ |
18 | 18 | ||
19 | .globl __strncpy_from_user | 19 | ENTRY(__strncpy_from_user) |
20 | __strncpy_from_user: | ||
21 | /* %o0=dest, %o1=src, %o2=count */ | 20 | /* %o0=dest, %o1=src, %o2=count */ |
22 | mov %o2, %o3 | 21 | mov %o2, %o3 |
23 | 1: | 22 | 1: |
@@ -35,6 +34,7 @@ __strncpy_from_user: | |||
35 | add %o2, 1, %o0 | 34 | add %o2, 1, %o0 |
36 | retl | 35 | retl |
37 | sub %o3, %o0, %o0 | 36 | sub %o3, %o0, %o0 |
37 | ENDPROC(__strncpy_from_user) | ||
38 | 38 | ||
39 | .section .fixup,#alloc,#execinstr | 39 | .section .fixup,#alloc,#execinstr |
40 | .align 4 | 40 | .align 4 |
diff --git a/arch/sparc/lib/strncpy_from_user_64.S b/arch/sparc/lib/strncpy_from_user_64.S index 511c8f136f95..d1246b713077 100644 --- a/arch/sparc/lib/strncpy_from_user_64.S +++ b/arch/sparc/lib/strncpy_from_user_64.S | |||
@@ -4,6 +4,7 @@ | |||
4 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) | 4 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/linkage.h> | ||
7 | #include <asm/asi.h> | 8 | #include <asm/asi.h> |
8 | #include <asm/errno.h> | 9 | #include <asm/errno.h> |
9 | 10 | ||
@@ -12,7 +13,6 @@ | |||
12 | 0: .xword 0x0101010101010101 | 13 | 0: .xword 0x0101010101010101 |
13 | 14 | ||
14 | .text | 15 | .text |
15 | .align 32 | ||
16 | 16 | ||
17 | /* Must return: | 17 | /* Must return: |
18 | * | 18 | * |
@@ -30,9 +30,7 @@ | |||
30 | * and average length is 18 or so. | 30 | * and average length is 18 or so. |
31 | */ | 31 | */ |
32 | 32 | ||
33 | .globl __strncpy_from_user | 33 | ENTRY(__strncpy_from_user) |
34 | .type __strncpy_from_user,#function | ||
35 | __strncpy_from_user: | ||
36 | /* %o0=dest, %o1=src, %o2=count */ | 34 | /* %o0=dest, %o1=src, %o2=count */ |
37 | andcc %o1, 7, %g0 ! IEU1 Group | 35 | andcc %o1, 7, %g0 ! IEU1 Group |
38 | bne,pn %icc, 30f ! CTI | 36 | bne,pn %icc, 30f ! CTI |
@@ -123,7 +121,7 @@ __strncpy_from_user: | |||
123 | mov %o2, %o0 | 121 | mov %o2, %o0 |
124 | 2: retl | 122 | 2: retl |
125 | add %o2, %o3, %o0 | 123 | add %o2, %o3, %o0 |
126 | .size __strncpy_from_user, .-__strncpy_from_user | 124 | ENDPROC(__strncpy_from_user) |
127 | 125 | ||
128 | .section __ex_table,"a" | 126 | .section __ex_table,"a" |
129 | .align 4 | 127 | .align 4 |
diff --git a/arch/sparc/lib/ucmpdi2.c b/arch/sparc/lib/ucmpdi2.c new file mode 100644 index 000000000000..1e06ed500682 --- /dev/null +++ b/arch/sparc/lib/ucmpdi2.c | |||
@@ -0,0 +1,19 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include "libgcc.h" | ||
3 | |||
4 | word_type __ucmpdi2(unsigned long long a, unsigned long long b) | ||
5 | { | ||
6 | const DWunion au = {.ll = a}; | ||
7 | const DWunion bu = {.ll = b}; | ||
8 | |||
9 | if ((unsigned int) au.s.high < (unsigned int) bu.s.high) | ||
10 | return 0; | ||
11 | else if ((unsigned int) au.s.high > (unsigned int) bu.s.high) | ||
12 | return 2; | ||
13 | if ((unsigned int) au.s.low < (unsigned int) bu.s.low) | ||
14 | return 0; | ||
15 | else if ((unsigned int) au.s.low > (unsigned int) bu.s.low) | ||
16 | return 2; | ||
17 | return 1; | ||
18 | } | ||
19 | EXPORT_SYMBOL(__ucmpdi2); | ||
diff --git a/arch/sparc/lib/udiv.S b/arch/sparc/lib/udiv.S deleted file mode 100644 index 2101405bdfcb..000000000000 --- a/arch/sparc/lib/udiv.S +++ /dev/null | |||
@@ -1,357 +0,0 @@ | |||
1 | /* | ||
2 | * udiv.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | |||
7 | /* This file is generated from divrem.m4; DO NOT EDIT! */ | ||
8 | /* | ||
9 | * Division and remainder, from Appendix E of the Sparc Version 8 | ||
10 | * Architecture Manual, with fixes from Gordon Irlam. | ||
11 | */ | ||
12 | |||
13 | /* | ||
14 | * Input: dividend and divisor in %o0 and %o1 respectively. | ||
15 | * | ||
16 | * m4 parameters: | ||
17 | * .udiv name of function to generate | ||
18 | * div div=div => %o0 / %o1; div=rem => %o0 % %o1 | ||
19 | * false false=true => signed; false=false => unsigned | ||
20 | * | ||
21 | * Algorithm parameters: | ||
22 | * N how many bits per iteration we try to get (4) | ||
23 | * WORDSIZE total number of bits (32) | ||
24 | * | ||
25 | * Derived constants: | ||
26 | * TOPBITS number of bits in the top decade of a number | ||
27 | * | ||
28 | * Important variables: | ||
29 | * Q the partial quotient under development (initially 0) | ||
30 | * R the remainder so far, initially the dividend | ||
31 | * ITER number of main division loop iterations required; | ||
32 | * equal to ceil(log2(quotient) / N). Note that this | ||
33 | * is the log base (2^N) of the quotient. | ||
34 | * V the current comparand, initially divisor*2^(ITER*N-1) | ||
35 | * | ||
36 | * Cost: | ||
37 | * Current estimate for non-large dividend is | ||
38 | * ceil(log2(quotient) / N) * (10 + 7N/2) + C | ||
39 | * A large dividend is one greater than 2^(31-TOPBITS) and takes a | ||
40 | * different path, as the upper bits of the quotient must be developed | ||
41 | * one bit at a time. | ||
42 | */ | ||
43 | |||
44 | |||
45 | .globl .udiv | ||
46 | .globl _Udiv | ||
47 | .udiv: | ||
48 | _Udiv: /* needed for export */ | ||
49 | |||
50 | ! Ready to divide. Compute size of quotient; scale comparand. | ||
51 | orcc %o1, %g0, %o5 | ||
52 | bne 1f | ||
53 | mov %o0, %o3 | ||
54 | |||
55 | ! Divide by zero trap. If it returns, return 0 (about as | ||
56 | ! wrong as possible, but that is what SunOS does...). | ||
57 | ta ST_DIV0 | ||
58 | retl | ||
59 | clr %o0 | ||
60 | |||
61 | 1: | ||
62 | cmp %o3, %o5 ! if %o1 exceeds %o0, done | ||
63 | blu Lgot_result ! (and algorithm fails otherwise) | ||
64 | clr %o2 | ||
65 | |||
66 | sethi %hi(1 << (32 - 4 - 1)), %g1 | ||
67 | |||
68 | cmp %o3, %g1 | ||
69 | blu Lnot_really_big | ||
70 | clr %o4 | ||
71 | |||
72 | ! Here the dividend is >= 2**(31-N) or so. We must be careful here, | ||
73 | ! as our usual N-at-a-shot divide step will cause overflow and havoc. | ||
74 | ! The number of bits in the result here is N*ITER+SC, where SC <= N. | ||
75 | ! Compute ITER in an unorthodox manner: know we need to shift V into | ||
76 | ! the top decade: so do not even bother to compare to R. | ||
77 | 1: | ||
78 | cmp %o5, %g1 | ||
79 | bgeu 3f | ||
80 | mov 1, %g7 | ||
81 | |||
82 | sll %o5, 4, %o5 | ||
83 | |||
84 | b 1b | ||
85 | add %o4, 1, %o4 | ||
86 | |||
87 | ! Now compute %g7. | ||
88 | 2: | ||
89 | addcc %o5, %o5, %o5 | ||
90 | bcc Lnot_too_big | ||
91 | add %g7, 1, %g7 | ||
92 | |||
93 | ! We get here if the %o1 overflowed while shifting. | ||
94 | ! This means that %o3 has the high-order bit set. | ||
95 | ! Restore %o5 and subtract from %o3. | ||
96 | sll %g1, 4, %g1 ! high order bit | ||
97 | srl %o5, 1, %o5 ! rest of %o5 | ||
98 | add %o5, %g1, %o5 | ||
99 | |||
100 | b Ldo_single_div | ||
101 | sub %g7, 1, %g7 | ||
102 | |||
103 | Lnot_too_big: | ||
104 | 3: | ||
105 | cmp %o5, %o3 | ||
106 | blu 2b | ||
107 | nop | ||
108 | |||
109 | be Ldo_single_div | ||
110 | nop | ||
111 | /* NB: these are commented out in the V8-Sparc manual as well */ | ||
112 | /* (I do not understand this) */ | ||
113 | ! %o5 > %o3: went too far: back up 1 step | ||
114 | ! srl %o5, 1, %o5 | ||
115 | ! dec %g7 | ||
116 | ! do single-bit divide steps | ||
117 | ! | ||
118 | ! We have to be careful here. We know that %o3 >= %o5, so we can do the | ||
119 | ! first divide step without thinking. BUT, the others are conditional, | ||
120 | ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- | ||
121 | ! order bit set in the first step, just falling into the regular | ||
122 | ! division loop will mess up the first time around. | ||
123 | ! So we unroll slightly... | ||
124 | Ldo_single_div: | ||
125 | subcc %g7, 1, %g7 | ||
126 | bl Lend_regular_divide | ||
127 | nop | ||
128 | |||
129 | sub %o3, %o5, %o3 | ||
130 | mov 1, %o2 | ||
131 | |||
132 | b Lend_single_divloop | ||
133 | nop | ||
134 | Lsingle_divloop: | ||
135 | sll %o2, 1, %o2 | ||
136 | bl 1f | ||
137 | srl %o5, 1, %o5 | ||
138 | ! %o3 >= 0 | ||
139 | sub %o3, %o5, %o3 | ||
140 | b 2f | ||
141 | add %o2, 1, %o2 | ||
142 | 1: ! %o3 < 0 | ||
143 | add %o3, %o5, %o3 | ||
144 | sub %o2, 1, %o2 | ||
145 | 2: | ||
146 | Lend_single_divloop: | ||
147 | subcc %g7, 1, %g7 | ||
148 | bge Lsingle_divloop | ||
149 | tst %o3 | ||
150 | |||
151 | b,a Lend_regular_divide | ||
152 | |||
153 | Lnot_really_big: | ||
154 | 1: | ||
155 | sll %o5, 4, %o5 | ||
156 | |||
157 | cmp %o5, %o3 | ||
158 | bleu 1b | ||
159 | addcc %o4, 1, %o4 | ||
160 | |||
161 | be Lgot_result | ||
162 | sub %o4, 1, %o4 | ||
163 | |||
164 | tst %o3 ! set up for initial iteration | ||
165 | Ldivloop: | ||
166 | sll %o2, 4, %o2 | ||
167 | ! depth 1, accumulated bits 0 | ||
168 | bl L.1.16 | ||
169 | srl %o5,1,%o5 | ||
170 | ! remainder is positive | ||
171 | subcc %o3,%o5,%o3 | ||
172 | ! depth 2, accumulated bits 1 | ||
173 | bl L.2.17 | ||
174 | srl %o5,1,%o5 | ||
175 | ! remainder is positive | ||
176 | subcc %o3,%o5,%o3 | ||
177 | ! depth 3, accumulated bits 3 | ||
178 | bl L.3.19 | ||
179 | srl %o5,1,%o5 | ||
180 | ! remainder is positive | ||
181 | subcc %o3,%o5,%o3 | ||
182 | ! depth 4, accumulated bits 7 | ||
183 | bl L.4.23 | ||
184 | srl %o5,1,%o5 | ||
185 | ! remainder is positive | ||
186 | subcc %o3,%o5,%o3 | ||
187 | b 9f | ||
188 | add %o2, (7*2+1), %o2 | ||
189 | |||
190 | L.4.23: | ||
191 | ! remainder is negative | ||
192 | addcc %o3,%o5,%o3 | ||
193 | b 9f | ||
194 | add %o2, (7*2-1), %o2 | ||
195 | |||
196 | L.3.19: | ||
197 | ! remainder is negative | ||
198 | addcc %o3,%o5,%o3 | ||
199 | ! depth 4, accumulated bits 5 | ||
200 | bl L.4.21 | ||
201 | srl %o5,1,%o5 | ||
202 | ! remainder is positive | ||
203 | subcc %o3,%o5,%o3 | ||
204 | b 9f | ||
205 | add %o2, (5*2+1), %o2 | ||
206 | |||
207 | L.4.21: | ||
208 | ! remainder is negative | ||
209 | addcc %o3,%o5,%o3 | ||
210 | b 9f | ||
211 | add %o2, (5*2-1), %o2 | ||
212 | |||
213 | L.2.17: | ||
214 | ! remainder is negative | ||
215 | addcc %o3,%o5,%o3 | ||
216 | ! depth 3, accumulated bits 1 | ||
217 | bl L.3.17 | ||
218 | srl %o5,1,%o5 | ||
219 | ! remainder is positive | ||
220 | subcc %o3,%o5,%o3 | ||
221 | ! depth 4, accumulated bits 3 | ||
222 | bl L.4.19 | ||
223 | srl %o5,1,%o5 | ||
224 | ! remainder is positive | ||
225 | subcc %o3,%o5,%o3 | ||
226 | b 9f | ||
227 | add %o2, (3*2+1), %o2 | ||
228 | |||
229 | L.4.19: | ||
230 | ! remainder is negative | ||
231 | addcc %o3,%o5,%o3 | ||
232 | b 9f | ||
233 | add %o2, (3*2-1), %o2 | ||
234 | |||
235 | L.3.17: | ||
236 | ! remainder is negative | ||
237 | addcc %o3,%o5,%o3 | ||
238 | ! depth 4, accumulated bits 1 | ||
239 | bl L.4.17 | ||
240 | srl %o5,1,%o5 | ||
241 | ! remainder is positive | ||
242 | subcc %o3,%o5,%o3 | ||
243 | b 9f | ||
244 | add %o2, (1*2+1), %o2 | ||
245 | |||
246 | L.4.17: | ||
247 | ! remainder is negative | ||
248 | addcc %o3,%o5,%o3 | ||
249 | b 9f | ||
250 | add %o2, (1*2-1), %o2 | ||
251 | |||
252 | L.1.16: | ||
253 | ! remainder is negative | ||
254 | addcc %o3,%o5,%o3 | ||
255 | ! depth 2, accumulated bits -1 | ||
256 | bl L.2.15 | ||
257 | srl %o5,1,%o5 | ||
258 | ! remainder is positive | ||
259 | subcc %o3,%o5,%o3 | ||
260 | ! depth 3, accumulated bits -1 | ||
261 | bl L.3.15 | ||
262 | srl %o5,1,%o5 | ||
263 | ! remainder is positive | ||
264 | subcc %o3,%o5,%o3 | ||
265 | ! depth 4, accumulated bits -1 | ||
266 | bl L.4.15 | ||
267 | srl %o5,1,%o5 | ||
268 | ! remainder is positive | ||
269 | subcc %o3,%o5,%o3 | ||
270 | b 9f | ||
271 | add %o2, (-1*2+1), %o2 | ||
272 | |||
273 | L.4.15: | ||
274 | ! remainder is negative | ||
275 | addcc %o3,%o5,%o3 | ||
276 | b 9f | ||
277 | add %o2, (-1*2-1), %o2 | ||
278 | |||
279 | L.3.15: | ||
280 | ! remainder is negative | ||
281 | addcc %o3,%o5,%o3 | ||
282 | ! depth 4, accumulated bits -3 | ||
283 | bl L.4.13 | ||
284 | srl %o5,1,%o5 | ||
285 | ! remainder is positive | ||
286 | subcc %o3,%o5,%o3 | ||
287 | b 9f | ||
288 | add %o2, (-3*2+1), %o2 | ||
289 | |||
290 | L.4.13: | ||
291 | ! remainder is negative | ||
292 | addcc %o3,%o5,%o3 | ||
293 | b 9f | ||
294 | add %o2, (-3*2-1), %o2 | ||
295 | |||
296 | L.2.15: | ||
297 | ! remainder is negative | ||
298 | addcc %o3,%o5,%o3 | ||
299 | ! depth 3, accumulated bits -3 | ||
300 | bl L.3.13 | ||
301 | srl %o5,1,%o5 | ||
302 | ! remainder is positive | ||
303 | subcc %o3,%o5,%o3 | ||
304 | ! depth 4, accumulated bits -5 | ||
305 | bl L.4.11 | ||
306 | srl %o5,1,%o5 | ||
307 | ! remainder is positive | ||
308 | subcc %o3,%o5,%o3 | ||
309 | b 9f | ||
310 | add %o2, (-5*2+1), %o2 | ||
311 | |||
312 | L.4.11: | ||
313 | ! remainder is negative | ||
314 | addcc %o3,%o5,%o3 | ||
315 | b 9f | ||
316 | add %o2, (-5*2-1), %o2 | ||
317 | |||
318 | L.3.13: | ||
319 | ! remainder is negative | ||
320 | addcc %o3,%o5,%o3 | ||
321 | ! depth 4, accumulated bits -7 | ||
322 | bl L.4.9 | ||
323 | srl %o5,1,%o5 | ||
324 | ! remainder is positive | ||
325 | subcc %o3,%o5,%o3 | ||
326 | b 9f | ||
327 | add %o2, (-7*2+1), %o2 | ||
328 | |||
329 | L.4.9: | ||
330 | ! remainder is negative | ||
331 | addcc %o3,%o5,%o3 | ||
332 | b 9f | ||
333 | add %o2, (-7*2-1), %o2 | ||
334 | |||
335 | 9: | ||
336 | Lend_regular_divide: | ||
337 | subcc %o4, 1, %o4 | ||
338 | bge Ldivloop | ||
339 | tst %o3 | ||
340 | |||
341 | bl,a Lgot_result | ||
342 | ! non-restoring fixup here (one instruction only!) | ||
343 | sub %o2, 1, %o2 | ||
344 | |||
345 | Lgot_result: | ||
346 | |||
347 | retl | ||
348 | mov %o2, %o0 | ||
349 | |||
350 | .globl .udiv_patch | ||
351 | .udiv_patch: | ||
352 | wr %g0, 0x0, %y | ||
353 | nop | ||
354 | nop | ||
355 | retl | ||
356 | udiv %o0, %o1, %o0 | ||
357 | nop | ||
diff --git a/arch/sparc/lib/udivdi3.S b/arch/sparc/lib/udivdi3.S index b430f1f0ef62..24e0a355e2e8 100644 --- a/arch/sparc/lib/udivdi3.S +++ b/arch/sparc/lib/udivdi3.S | |||
@@ -60,8 +60,9 @@ __udivdi3: | |||
60 | bne .LL77 | 60 | bne .LL77 |
61 | mov %i0,%o2 | 61 | mov %i0,%o2 |
62 | mov 1,%o0 | 62 | mov 1,%o0 |
63 | call .udiv,0 | ||
64 | mov 0,%o1 | 63 | mov 0,%o1 |
64 | wr %g0, 0, %y | ||
65 | udiv %o0, %o1, %o0 | ||
65 | mov %o0,%o3 | 66 | mov %o0,%o3 |
66 | mov %i0,%o2 | 67 | mov %i0,%o2 |
67 | .LL77: | 68 | .LL77: |
diff --git a/arch/sparc/lib/umul.S b/arch/sparc/lib/umul.S deleted file mode 100644 index 1f36ae682529..000000000000 --- a/arch/sparc/lib/umul.S +++ /dev/null | |||
@@ -1,171 +0,0 @@ | |||
1 | /* | ||
2 | * umul.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | |||
7 | /* | ||
8 | * Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the | ||
9 | * upper 32 bits of the 64-bit product). | ||
10 | * | ||
11 | * This code optimizes short (less than 13-bit) multiplies. Short | ||
12 | * multiplies require 25 instruction cycles, and long ones require | ||
13 | * 45 instruction cycles. | ||
14 | * | ||
15 | * On return, overflow has occurred (%o1 is not zero) if and only if | ||
16 | * the Z condition code is clear, allowing, e.g., the following: | ||
17 | * | ||
18 | * call .umul | ||
19 | * nop | ||
20 | * bnz overflow (or tnz) | ||
21 | */ | ||
22 | |||
23 | .globl .umul | ||
24 | .globl _Umul | ||
25 | .umul: | ||
26 | _Umul: /* needed for export */ | ||
27 | or %o0, %o1, %o4 | ||
28 | mov %o0, %y ! multiplier -> Y | ||
29 | |||
30 | andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args | ||
31 | be Lmul_shortway ! if zero, can do it the short way | ||
32 | andcc %g0, %g0, %o4 ! zero the partial product and clear N and V | ||
33 | |||
34 | /* | ||
35 | * Long multiply. 32 steps, followed by a final shift step. | ||
36 | */ | ||
37 | mulscc %o4, %o1, %o4 ! 1 | ||
38 | mulscc %o4, %o1, %o4 ! 2 | ||
39 | mulscc %o4, %o1, %o4 ! 3 | ||
40 | mulscc %o4, %o1, %o4 ! 4 | ||
41 | mulscc %o4, %o1, %o4 ! 5 | ||
42 | mulscc %o4, %o1, %o4 ! 6 | ||
43 | mulscc %o4, %o1, %o4 ! 7 | ||
44 | mulscc %o4, %o1, %o4 ! 8 | ||
45 | mulscc %o4, %o1, %o4 ! 9 | ||
46 | mulscc %o4, %o1, %o4 ! 10 | ||
47 | mulscc %o4, %o1, %o4 ! 11 | ||
48 | mulscc %o4, %o1, %o4 ! 12 | ||
49 | mulscc %o4, %o1, %o4 ! 13 | ||
50 | mulscc %o4, %o1, %o4 ! 14 | ||
51 | mulscc %o4, %o1, %o4 ! 15 | ||
52 | mulscc %o4, %o1, %o4 ! 16 | ||
53 | mulscc %o4, %o1, %o4 ! 17 | ||
54 | mulscc %o4, %o1, %o4 ! 18 | ||
55 | mulscc %o4, %o1, %o4 ! 19 | ||
56 | mulscc %o4, %o1, %o4 ! 20 | ||
57 | mulscc %o4, %o1, %o4 ! 21 | ||
58 | mulscc %o4, %o1, %o4 ! 22 | ||
59 | mulscc %o4, %o1, %o4 ! 23 | ||
60 | mulscc %o4, %o1, %o4 ! 24 | ||
61 | mulscc %o4, %o1, %o4 ! 25 | ||
62 | mulscc %o4, %o1, %o4 ! 26 | ||
63 | mulscc %o4, %o1, %o4 ! 27 | ||
64 | mulscc %o4, %o1, %o4 ! 28 | ||
65 | mulscc %o4, %o1, %o4 ! 29 | ||
66 | mulscc %o4, %o1, %o4 ! 30 | ||
67 | mulscc %o4, %o1, %o4 ! 31 | ||
68 | mulscc %o4, %o1, %o4 ! 32 | ||
69 | mulscc %o4, %g0, %o4 ! final shift | ||
70 | |||
71 | |||
72 | /* | ||
73 | * Normally, with the shift-and-add approach, if both numbers are | ||
74 | * positive you get the correct result. With 32-bit two's-complement | ||
75 | * numbers, -x is represented as | ||
76 | * | ||
77 | * x 32 | ||
78 | * ( 2 - ------ ) mod 2 * 2 | ||
79 | * 32 | ||
80 | * 2 | ||
81 | * | ||
82 | * (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s, | ||
83 | * we can treat this as if the radix point were just to the left | ||
84 | * of the sign bit (multiply by 2^32), and get | ||
85 | * | ||
86 | * -x = (2 - x) mod 2 | ||
87 | * | ||
88 | * Then, ignoring the `mod 2's for convenience: | ||
89 | * | ||
90 | * x * y = xy | ||
91 | * -x * y = 2y - xy | ||
92 | * x * -y = 2x - xy | ||
93 | * -x * -y = 4 - 2x - 2y + xy | ||
94 | * | ||
95 | * For signed multiplies, we subtract (x << 32) from the partial | ||
96 | * product to fix this problem for negative multipliers (see mul.s). | ||
97 | * Because of the way the shift into the partial product is calculated | ||
98 | * (N xor V), this term is automatically removed for the multiplicand, | ||
99 | * so we don't have to adjust. | ||
100 | * | ||
101 | * But for unsigned multiplies, the high order bit wasn't a sign bit, | ||
102 | * and the correction is wrong. So for unsigned multiplies where the | ||
103 | * high order bit is one, we end up with xy - (y << 32). To fix it | ||
104 | * we add y << 32. | ||
105 | */ | ||
106 | #if 0 | ||
107 | tst %o1 | ||
108 | bl,a 1f ! if %o1 < 0 (high order bit = 1), | ||
109 | add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half) | ||
110 | |||
111 | 1: | ||
112 | rd %y, %o0 ! get lower half of product | ||
113 | retl | ||
114 | addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0 | ||
115 | #else | ||
116 | /* Faster code from tege@sics.se. */ | ||
117 | sra %o1, 31, %o2 ! make mask from sign bit | ||
118 | and %o0, %o2, %o2 ! %o2 = 0 or %o0, depending on sign of %o1 | ||
119 | rd %y, %o0 ! get lower half of product | ||
120 | retl | ||
121 | addcc %o4, %o2, %o1 ! add compensation and put upper half in place | ||
122 | #endif | ||
123 | |||
124 | Lmul_shortway: | ||
125 | /* | ||
126 | * Short multiply. 12 steps, followed by a final shift step. | ||
127 | * The resulting bits are off by 12 and (32-12) = 20 bit positions, | ||
128 | * but there is no problem with %o0 being negative (unlike above), | ||
129 | * and overflow is impossible (the answer is at most 24 bits long). | ||
130 | */ | ||
131 | mulscc %o4, %o1, %o4 ! 1 | ||
132 | mulscc %o4, %o1, %o4 ! 2 | ||
133 | mulscc %o4, %o1, %o4 ! 3 | ||
134 | mulscc %o4, %o1, %o4 ! 4 | ||
135 | mulscc %o4, %o1, %o4 ! 5 | ||
136 | mulscc %o4, %o1, %o4 ! 6 | ||
137 | mulscc %o4, %o1, %o4 ! 7 | ||
138 | mulscc %o4, %o1, %o4 ! 8 | ||
139 | mulscc %o4, %o1, %o4 ! 9 | ||
140 | mulscc %o4, %o1, %o4 ! 10 | ||
141 | mulscc %o4, %o1, %o4 ! 11 | ||
142 | mulscc %o4, %o1, %o4 ! 12 | ||
143 | mulscc %o4, %g0, %o4 ! final shift | ||
144 | |||
145 | /* | ||
146 | * %o4 has 20 of the bits that should be in the result; %y has | ||
147 | * the bottom 12 (as %y's top 12). That is: | ||
148 | * | ||
149 | * %o4 %y | ||
150 | * +----------------+----------------+ | ||
151 | * | -12- | -20- | -12- | -20- | | ||
152 | * +------(---------+------)---------+ | ||
153 | * -----result----- | ||
154 | * | ||
155 | * The 12 bits of %o4 left of the `result' area are all zero; | ||
156 | * in fact, all top 20 bits of %o4 are zero. | ||
157 | */ | ||
158 | |||
159 | rd %y, %o5 | ||
160 | sll %o4, 12, %o0 ! shift middle bits left 12 | ||
161 | srl %o5, 20, %o5 ! shift low bits right 20 | ||
162 | or %o5, %o0, %o0 | ||
163 | retl | ||
164 | addcc %g0, %g0, %o1 ! %o1 = zero, and set Z | ||
165 | |||
166 | .globl .umul_patch | ||
167 | .umul_patch: | ||
168 | umul %o0, %o1, %o0 | ||
169 | retl | ||
170 | rd %y, %o1 | ||
171 | nop | ||
diff --git a/arch/sparc/lib/urem.S b/arch/sparc/lib/urem.S deleted file mode 100644 index 77123eb83c44..000000000000 --- a/arch/sparc/lib/urem.S +++ /dev/null | |||
@@ -1,357 +0,0 @@ | |||
1 | /* | ||
2 | * urem.S: This routine was taken from glibc-1.09 and is covered | ||
3 | * by the GNU Library General Public License Version 2. | ||
4 | */ | ||
5 | |||
6 | /* This file is generated from divrem.m4; DO NOT EDIT! */ | ||
7 | /* | ||
8 | * Division and remainder, from Appendix E of the Sparc Version 8 | ||
9 | * Architecture Manual, with fixes from Gordon Irlam. | ||
10 | */ | ||
11 | |||
12 | /* | ||
13 | * Input: dividend and divisor in %o0 and %o1 respectively. | ||
14 | * | ||
15 | * m4 parameters: | ||
16 | * .urem name of function to generate | ||
17 | * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1 | ||
18 | * false false=true => signed; false=false => unsigned | ||
19 | * | ||
20 | * Algorithm parameters: | ||
21 | * N how many bits per iteration we try to get (4) | ||
22 | * WORDSIZE total number of bits (32) | ||
23 | * | ||
24 | * Derived constants: | ||
25 | * TOPBITS number of bits in the top decade of a number | ||
26 | * | ||
27 | * Important variables: | ||
28 | * Q the partial quotient under development (initially 0) | ||
29 | * R the remainder so far, initially the dividend | ||
30 | * ITER number of main division loop iterations required; | ||
31 | * equal to ceil(log2(quotient) / N). Note that this | ||
32 | * is the log base (2^N) of the quotient. | ||
33 | * V the current comparand, initially divisor*2^(ITER*N-1) | ||
34 | * | ||
35 | * Cost: | ||
36 | * Current estimate for non-large dividend is | ||
37 | * ceil(log2(quotient) / N) * (10 + 7N/2) + C | ||
38 | * A large dividend is one greater than 2^(31-TOPBITS) and takes a | ||
39 | * different path, as the upper bits of the quotient must be developed | ||
40 | * one bit at a time. | ||
41 | */ | ||
42 | |||
43 | .globl .urem | ||
44 | .globl _Urem | ||
45 | .urem: | ||
46 | _Urem: /* needed for export */ | ||
47 | |||
48 | ! Ready to divide. Compute size of quotient; scale comparand. | ||
49 | orcc %o1, %g0, %o5 | ||
50 | bne 1f | ||
51 | mov %o0, %o3 | ||
52 | |||
53 | ! Divide by zero trap. If it returns, return 0 (about as | ||
54 | ! wrong as possible, but that is what SunOS does...). | ||
55 | ta ST_DIV0 | ||
56 | retl | ||
57 | clr %o0 | ||
58 | |||
59 | 1: | ||
60 | cmp %o3, %o5 ! if %o1 exceeds %o0, done | ||
61 | blu Lgot_result ! (and algorithm fails otherwise) | ||
62 | clr %o2 | ||
63 | |||
64 | sethi %hi(1 << (32 - 4 - 1)), %g1 | ||
65 | |||
66 | cmp %o3, %g1 | ||
67 | blu Lnot_really_big | ||
68 | clr %o4 | ||
69 | |||
70 | ! Here the dividend is >= 2**(31-N) or so. We must be careful here, | ||
71 | ! as our usual N-at-a-shot divide step will cause overflow and havoc. | ||
72 | ! The number of bits in the result here is N*ITER+SC, where SC <= N. | ||
73 | ! Compute ITER in an unorthodox manner: know we need to shift V into | ||
74 | ! the top decade: so do not even bother to compare to R. | ||
75 | 1: | ||
76 | cmp %o5, %g1 | ||
77 | bgeu 3f | ||
78 | mov 1, %g7 | ||
79 | |||
80 | sll %o5, 4, %o5 | ||
81 | |||
82 | b 1b | ||
83 | add %o4, 1, %o4 | ||
84 | |||
85 | ! Now compute %g7. | ||
86 | 2: | ||
87 | addcc %o5, %o5, %o5 | ||
88 | bcc Lnot_too_big | ||
89 | add %g7, 1, %g7 | ||
90 | |||
91 | ! We get here if the %o1 overflowed while shifting. | ||
92 | ! This means that %o3 has the high-order bit set. | ||
93 | ! Restore %o5 and subtract from %o3. | ||
94 | sll %g1, 4, %g1 ! high order bit | ||
95 | srl %o5, 1, %o5 ! rest of %o5 | ||
96 | add %o5, %g1, %o5 | ||
97 | |||
98 | b Ldo_single_div | ||
99 | sub %g7, 1, %g7 | ||
100 | |||
101 | Lnot_too_big: | ||
102 | 3: | ||
103 | cmp %o5, %o3 | ||
104 | blu 2b | ||
105 | nop | ||
106 | |||
107 | be Ldo_single_div | ||
108 | nop | ||
109 | /* NB: these are commented out in the V8-Sparc manual as well */ | ||
110 | /* (I do not understand this) */ | ||
111 | ! %o5 > %o3: went too far: back up 1 step | ||
112 | ! srl %o5, 1, %o5 | ||
113 | ! dec %g7 | ||
114 | ! do single-bit divide steps | ||
115 | ! | ||
116 | ! We have to be careful here. We know that %o3 >= %o5, so we can do the | ||
117 | ! first divide step without thinking. BUT, the others are conditional, | ||
118 | ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- | ||
119 | ! order bit set in the first step, just falling into the regular | ||
120 | ! division loop will mess up the first time around. | ||
121 | ! So we unroll slightly... | ||
122 | Ldo_single_div: | ||
123 | subcc %g7, 1, %g7 | ||
124 | bl Lend_regular_divide | ||
125 | nop | ||
126 | |||
127 | sub %o3, %o5, %o3 | ||
128 | mov 1, %o2 | ||
129 | |||
130 | b Lend_single_divloop | ||
131 | nop | ||
132 | Lsingle_divloop: | ||
133 | sll %o2, 1, %o2 | ||
134 | bl 1f | ||
135 | srl %o5, 1, %o5 | ||
136 | ! %o3 >= 0 | ||
137 | sub %o3, %o5, %o3 | ||
138 | b 2f | ||
139 | add %o2, 1, %o2 | ||
140 | 1: ! %o3 < 0 | ||
141 | add %o3, %o5, %o3 | ||
142 | sub %o2, 1, %o2 | ||
143 | 2: | ||
144 | Lend_single_divloop: | ||
145 | subcc %g7, 1, %g7 | ||
146 | bge Lsingle_divloop | ||
147 | tst %o3 | ||
148 | |||
149 | b,a Lend_regular_divide | ||
150 | |||
151 | Lnot_really_big: | ||
152 | 1: | ||
153 | sll %o5, 4, %o5 | ||
154 | |||
155 | cmp %o5, %o3 | ||
156 | bleu 1b | ||
157 | addcc %o4, 1, %o4 | ||
158 | |||
159 | be Lgot_result | ||
160 | sub %o4, 1, %o4 | ||
161 | |||
162 | tst %o3 ! set up for initial iteration | ||
163 | Ldivloop: | ||
164 | sll %o2, 4, %o2 | ||
165 | ! depth 1, accumulated bits 0 | ||
166 | bl L.1.16 | ||
167 | srl %o5,1,%o5 | ||
168 | ! remainder is positive | ||
169 | subcc %o3,%o5,%o3 | ||
170 | ! depth 2, accumulated bits 1 | ||
171 | bl L.2.17 | ||
172 | srl %o5,1,%o5 | ||
173 | ! remainder is positive | ||
174 | subcc %o3,%o5,%o3 | ||
175 | ! depth 3, accumulated bits 3 | ||
176 | bl L.3.19 | ||
177 | srl %o5,1,%o5 | ||
178 | ! remainder is positive | ||
179 | subcc %o3,%o5,%o3 | ||
180 | ! depth 4, accumulated bits 7 | ||
181 | bl L.4.23 | ||
182 | srl %o5,1,%o5 | ||
183 | ! remainder is positive | ||
184 | subcc %o3,%o5,%o3 | ||
185 | b 9f | ||
186 | add %o2, (7*2+1), %o2 | ||
187 | |||
188 | L.4.23: | ||
189 | ! remainder is negative | ||
190 | addcc %o3,%o5,%o3 | ||
191 | b 9f | ||
192 | add %o2, (7*2-1), %o2 | ||
193 | |||
194 | L.3.19: | ||
195 | ! remainder is negative | ||
196 | addcc %o3,%o5,%o3 | ||
197 | ! depth 4, accumulated bits 5 | ||
198 | bl L.4.21 | ||
199 | srl %o5,1,%o5 | ||
200 | ! remainder is positive | ||
201 | subcc %o3,%o5,%o3 | ||
202 | b 9f | ||
203 | add %o2, (5*2+1), %o2 | ||
204 | |||
205 | L.4.21: | ||
206 | ! remainder is negative | ||
207 | addcc %o3,%o5,%o3 | ||
208 | b 9f | ||
209 | add %o2, (5*2-1), %o2 | ||
210 | |||
211 | L.2.17: | ||
212 | ! remainder is negative | ||
213 | addcc %o3,%o5,%o3 | ||
214 | ! depth 3, accumulated bits 1 | ||
215 | bl L.3.17 | ||
216 | srl %o5,1,%o5 | ||
217 | ! remainder is positive | ||
218 | subcc %o3,%o5,%o3 | ||
219 | ! depth 4, accumulated bits 3 | ||
220 | bl L.4.19 | ||
221 | srl %o5,1,%o5 | ||
222 | ! remainder is positive | ||
223 | subcc %o3,%o5,%o3 | ||
224 | b 9f | ||
225 | add %o2, (3*2+1), %o2 | ||
226 | |||
227 | L.4.19: | ||
228 | ! remainder is negative | ||
229 | addcc %o3,%o5,%o3 | ||
230 | b 9f | ||
231 | add %o2, (3*2-1), %o2 | ||
232 | |||
233 | L.3.17: | ||
234 | ! remainder is negative | ||
235 | addcc %o3,%o5,%o3 | ||
236 | ! depth 4, accumulated bits 1 | ||
237 | bl L.4.17 | ||
238 | srl %o5,1,%o5 | ||
239 | ! remainder is positive | ||
240 | subcc %o3,%o5,%o3 | ||
241 | b 9f | ||
242 | add %o2, (1*2+1), %o2 | ||
243 | |||
244 | L.4.17: | ||
245 | ! remainder is negative | ||
246 | addcc %o3,%o5,%o3 | ||
247 | b 9f | ||
248 | add %o2, (1*2-1), %o2 | ||
249 | |||
250 | L.1.16: | ||
251 | ! remainder is negative | ||
252 | addcc %o3,%o5,%o3 | ||
253 | ! depth 2, accumulated bits -1 | ||
254 | bl L.2.15 | ||
255 | srl %o5,1,%o5 | ||
256 | ! remainder is positive | ||
257 | subcc %o3,%o5,%o3 | ||
258 | ! depth 3, accumulated bits -1 | ||
259 | bl L.3.15 | ||
260 | srl %o5,1,%o5 | ||
261 | ! remainder is positive | ||
262 | subcc %o3,%o5,%o3 | ||
263 | ! depth 4, accumulated bits -1 | ||
264 | bl L.4.15 | ||
265 | srl %o5,1,%o5 | ||
266 | ! remainder is positive | ||
267 | subcc %o3,%o5,%o3 | ||
268 | b 9f | ||
269 | add %o2, (-1*2+1), %o2 | ||
270 | |||
271 | L.4.15: | ||
272 | ! remainder is negative | ||
273 | addcc %o3,%o5,%o3 | ||
274 | b 9f | ||
275 | add %o2, (-1*2-1), %o2 | ||
276 | |||
277 | L.3.15: | ||
278 | ! remainder is negative | ||
279 | addcc %o3,%o5,%o3 | ||
280 | ! depth 4, accumulated bits -3 | ||
281 | bl L.4.13 | ||
282 | srl %o5,1,%o5 | ||
283 | ! remainder is positive | ||
284 | subcc %o3,%o5,%o3 | ||
285 | b 9f | ||
286 | add %o2, (-3*2+1), %o2 | ||
287 | |||
288 | L.4.13: | ||
289 | ! remainder is negative | ||
290 | addcc %o3,%o5,%o3 | ||
291 | b 9f | ||
292 | add %o2, (-3*2-1), %o2 | ||
293 | |||
294 | L.2.15: | ||
295 | ! remainder is negative | ||
296 | addcc %o3,%o5,%o3 | ||
297 | ! depth 3, accumulated bits -3 | ||
298 | bl L.3.13 | ||
299 | srl %o5,1,%o5 | ||
300 | ! remainder is positive | ||
301 | subcc %o3,%o5,%o3 | ||
302 | ! depth 4, accumulated bits -5 | ||
303 | bl L.4.11 | ||
304 | srl %o5,1,%o5 | ||
305 | ! remainder is positive | ||
306 | subcc %o3,%o5,%o3 | ||
307 | b 9f | ||
308 | add %o2, (-5*2+1), %o2 | ||
309 | |||
310 | L.4.11: | ||
311 | ! remainder is negative | ||
312 | addcc %o3,%o5,%o3 | ||
313 | b 9f | ||
314 | add %o2, (-5*2-1), %o2 | ||
315 | |||
316 | L.3.13: | ||
317 | ! remainder is negative | ||
318 | addcc %o3,%o5,%o3 | ||
319 | ! depth 4, accumulated bits -7 | ||
320 | bl L.4.9 | ||
321 | srl %o5,1,%o5 | ||
322 | ! remainder is positive | ||
323 | subcc %o3,%o5,%o3 | ||
324 | b 9f | ||
325 | add %o2, (-7*2+1), %o2 | ||
326 | |||
327 | L.4.9: | ||
328 | ! remainder is negative | ||
329 | addcc %o3,%o5,%o3 | ||
330 | b 9f | ||
331 | add %o2, (-7*2-1), %o2 | ||
332 | |||
333 | 9: | ||
334 | Lend_regular_divide: | ||
335 | subcc %o4, 1, %o4 | ||
336 | bge Ldivloop | ||
337 | tst %o3 | ||
338 | |||
339 | bl,a Lgot_result | ||
340 | ! non-restoring fixup here (one instruction only!) | ||
341 | add %o3, %o1, %o3 | ||
342 | |||
343 | Lgot_result: | ||
344 | |||
345 | retl | ||
346 | mov %o3, %o0 | ||
347 | |||
348 | .globl .urem_patch | ||
349 | .urem_patch: | ||
350 | wr %g0, 0x0, %y | ||
351 | nop | ||
352 | nop | ||
353 | nop | ||
354 | udiv %o0, %o1, %o2 | ||
355 | umul %o2, %o1, %o2 | ||
356 | retl | ||
357 | sub %o0, %o2, %o0 | ||
diff --git a/arch/sparc/lib/xor.S b/arch/sparc/lib/xor.S index f44f58f40234..2c05641c3263 100644 --- a/arch/sparc/lib/xor.S +++ b/arch/sparc/lib/xor.S | |||
@@ -8,6 +8,7 @@ | |||
8 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> | 8 | * Copyright (C) 2006 David S. Miller <davem@davemloft.net> |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/linkage.h> | ||
11 | #include <asm/visasm.h> | 12 | #include <asm/visasm.h> |
12 | #include <asm/asi.h> | 13 | #include <asm/asi.h> |
13 | #include <asm/dcu.h> | 14 | #include <asm/dcu.h> |
@@ -19,12 +20,9 @@ | |||
19 | * !(len & 127) && len >= 256 | 20 | * !(len & 127) && len >= 256 |
20 | */ | 21 | */ |
21 | .text | 22 | .text |
22 | .align 32 | ||
23 | 23 | ||
24 | /* VIS versions. */ | 24 | /* VIS versions. */ |
25 | .globl xor_vis_2 | 25 | ENTRY(xor_vis_2) |
26 | .type xor_vis_2,#function | ||
27 | xor_vis_2: | ||
28 | rd %fprs, %o5 | 26 | rd %fprs, %o5 |
29 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 | 27 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 |
30 | be,pt %icc, 0f | 28 | be,pt %icc, 0f |
@@ -91,11 +89,9 @@ xor_vis_2: | |||
91 | wr %g1, %g0, %asi | 89 | wr %g1, %g0, %asi |
92 | retl | 90 | retl |
93 | wr %g0, 0, %fprs | 91 | wr %g0, 0, %fprs |
94 | .size xor_vis_2, .-xor_vis_2 | 92 | ENDPROC(xor_vis_2) |
95 | 93 | ||
96 | .globl xor_vis_3 | 94 | ENTRY(xor_vis_3) |
97 | .type xor_vis_3,#function | ||
98 | xor_vis_3: | ||
99 | rd %fprs, %o5 | 95 | rd %fprs, %o5 |
100 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 | 96 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 |
101 | be,pt %icc, 0f | 97 | be,pt %icc, 0f |
@@ -159,11 +155,9 @@ xor_vis_3: | |||
159 | wr %g1, %g0, %asi | 155 | wr %g1, %g0, %asi |
160 | retl | 156 | retl |
161 | wr %g0, 0, %fprs | 157 | wr %g0, 0, %fprs |
162 | .size xor_vis_3, .-xor_vis_3 | 158 | ENDPROC(xor_vis_3) |
163 | 159 | ||
164 | .globl xor_vis_4 | 160 | ENTRY(xor_vis_4) |
165 | .type xor_vis_4,#function | ||
166 | xor_vis_4: | ||
167 | rd %fprs, %o5 | 161 | rd %fprs, %o5 |
168 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 | 162 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 |
169 | be,pt %icc, 0f | 163 | be,pt %icc, 0f |
@@ -246,11 +240,9 @@ xor_vis_4: | |||
246 | wr %g1, %g0, %asi | 240 | wr %g1, %g0, %asi |
247 | retl | 241 | retl |
248 | wr %g0, 0, %fprs | 242 | wr %g0, 0, %fprs |
249 | .size xor_vis_4, .-xor_vis_4 | 243 | ENDPROC(xor_vis_4) |
250 | 244 | ||
251 | .globl xor_vis_5 | 245 | ENTRY(xor_vis_5) |
252 | .type xor_vis_5,#function | ||
253 | xor_vis_5: | ||
254 | save %sp, -192, %sp | 246 | save %sp, -192, %sp |
255 | rd %fprs, %o5 | 247 | rd %fprs, %o5 |
256 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 | 248 | andcc %o5, FPRS_FEF|FPRS_DU, %g0 |
@@ -354,12 +346,10 @@ xor_vis_5: | |||
354 | wr %g0, 0, %fprs | 346 | wr %g0, 0, %fprs |
355 | ret | 347 | ret |
356 | restore | 348 | restore |
357 | .size xor_vis_5, .-xor_vis_5 | 349 | ENDPROC(xor_vis_5) |
358 | 350 | ||
359 | /* Niagara versions. */ | 351 | /* Niagara versions. */ |
360 | .globl xor_niagara_2 | 352 | ENTRY(xor_niagara_2) /* %o0=bytes, %o1=dest, %o2=src */ |
361 | .type xor_niagara_2,#function | ||
362 | xor_niagara_2: /* %o0=bytes, %o1=dest, %o2=src */ | ||
363 | save %sp, -192, %sp | 353 | save %sp, -192, %sp |
364 | prefetch [%i1], #n_writes | 354 | prefetch [%i1], #n_writes |
365 | prefetch [%i2], #one_read | 355 | prefetch [%i2], #one_read |
@@ -402,11 +392,9 @@ xor_niagara_2: /* %o0=bytes, %o1=dest, %o2=src */ | |||
402 | wr %g7, 0x0, %asi | 392 | wr %g7, 0x0, %asi |
403 | ret | 393 | ret |
404 | restore | 394 | restore |
405 | .size xor_niagara_2, .-xor_niagara_2 | 395 | ENDPROC(xor_niagara_2) |
406 | 396 | ||
407 | .globl xor_niagara_3 | 397 | ENTRY(xor_niagara_3) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ |
408 | .type xor_niagara_3,#function | ||
409 | xor_niagara_3: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ | ||
410 | save %sp, -192, %sp | 398 | save %sp, -192, %sp |
411 | prefetch [%i1], #n_writes | 399 | prefetch [%i1], #n_writes |
412 | prefetch [%i2], #one_read | 400 | prefetch [%i2], #one_read |
@@ -465,11 +453,9 @@ xor_niagara_3: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2 */ | |||
465 | wr %g7, 0x0, %asi | 453 | wr %g7, 0x0, %asi |
466 | ret | 454 | ret |
467 | restore | 455 | restore |
468 | .size xor_niagara_3, .-xor_niagara_3 | 456 | ENDPROC(xor_niagara_3) |
469 | 457 | ||
470 | .globl xor_niagara_4 | 458 | ENTRY(xor_niagara_4) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ |
471 | .type xor_niagara_4,#function | ||
472 | xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ | ||
473 | save %sp, -192, %sp | 459 | save %sp, -192, %sp |
474 | prefetch [%i1], #n_writes | 460 | prefetch [%i1], #n_writes |
475 | prefetch [%i2], #one_read | 461 | prefetch [%i2], #one_read |
@@ -549,11 +535,9 @@ xor_niagara_4: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3 */ | |||
549 | wr %g7, 0x0, %asi | 535 | wr %g7, 0x0, %asi |
550 | ret | 536 | ret |
551 | restore | 537 | restore |
552 | .size xor_niagara_4, .-xor_niagara_4 | 538 | ENDPROC(xor_niagara_4) |
553 | 539 | ||
554 | .globl xor_niagara_5 | 540 | ENTRY(xor_niagara_5) /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=src4 */ |
555 | .type xor_niagara_5,#function | ||
556 | xor_niagara_5: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=src4 */ | ||
557 | save %sp, -192, %sp | 541 | save %sp, -192, %sp |
558 | prefetch [%i1], #n_writes | 542 | prefetch [%i1], #n_writes |
559 | prefetch [%i2], #one_read | 543 | prefetch [%i2], #one_read |
@@ -649,4 +633,4 @@ xor_niagara_5: /* %o0=bytes, %o1=dest, %o2=src1, %o3=src2, %o4=src3, %o5=src4 * | |||
649 | wr %g7, 0x0, %asi | 633 | wr %g7, 0x0, %asi |
650 | ret | 634 | ret |
651 | restore | 635 | restore |
652 | .size xor_niagara_5, .-xor_niagara_5 | 636 | ENDPROC(xor_niagara_5) |
diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 301421c11291..69ffd3112fed 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile | |||
@@ -7,8 +7,7 @@ ccflags-y := -Werror | |||
7 | obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o | 7 | obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o gup.o |
8 | obj-y += fault_$(BITS).o | 8 | obj-y += fault_$(BITS).o |
9 | obj-y += init_$(BITS).o | 9 | obj-y += init_$(BITS).o |
10 | obj-$(CONFIG_SPARC32) += loadmmu.o | 10 | obj-$(CONFIG_SPARC32) += extable.o srmmu.o iommu.o io-unit.o |
11 | obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o | ||
12 | obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o | 11 | obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o |
13 | obj-$(CONFIG_SPARC_LEON)+= leon_mm.o | 12 | obj-$(CONFIG_SPARC_LEON)+= leon_mm.o |
14 | 13 | ||
@@ -17,9 +16,3 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | |||
17 | 16 | ||
18 | # Only used by sparc32 | 17 | # Only used by sparc32 |
19 | obj-$(CONFIG_HIGHMEM) += highmem.o | 18 | obj-$(CONFIG_HIGHMEM) += highmem.o |
20 | |||
21 | ifdef CONFIG_SMP | ||
22 | obj-$(CONFIG_SPARC32) += nosun4c.o | ||
23 | else | ||
24 | obj-$(CONFIG_SPARC32) += sun4c.o | ||
25 | endif | ||
diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c deleted file mode 100644 index 09d6af22db2d..000000000000 --- a/arch/sparc/mm/btfixup.c +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | /* btfixup.c: Boot time code fixup and relocator, so that | ||
2 | * we can get rid of most indirect calls to achieve single | ||
3 | * image sun4c and srmmu kernel. | ||
4 | * | ||
5 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <asm/btfixup.h> | ||
11 | #include <asm/page.h> | ||
12 | #include <asm/pgalloc.h> | ||
13 | #include <asm/pgtable.h> | ||
14 | #include <asm/oplib.h> | ||
15 | #include <asm/cacheflush.h> | ||
16 | |||
17 | #define BTFIXUP_OPTIMIZE_NOP | ||
18 | #define BTFIXUP_OPTIMIZE_OTHER | ||
19 | |||
20 | extern char *srmmu_name; | ||
21 | static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for "; | ||
22 | static char str_sun4c[] __initdata = "sun4c\n"; | ||
23 | static char str_srmmu[] __initdata = "srmmu[%s]/"; | ||
24 | static char str_iommu[] __initdata = "iommu\n"; | ||
25 | static char str_iounit[] __initdata = "io-unit\n"; | ||
26 | |||
27 | static int visited __initdata = 0; | ||
28 | extern unsigned int ___btfixup_start[], ___btfixup_end[], __init_begin[], __init_end[], __init_text_end[]; | ||
29 | extern unsigned int _stext[], _end[], __start___ksymtab[], __stop___ksymtab[]; | ||
30 | static char wrong_f[] __initdata = "Trying to set f fixup %p to invalid function %08x\n"; | ||
31 | static char wrong_b[] __initdata = "Trying to set b fixup %p to invalid function %08x\n"; | ||
32 | static char wrong_s[] __initdata = "Trying to set s fixup %p to invalid value %08x\n"; | ||
33 | static char wrong_h[] __initdata = "Trying to set h fixup %p to invalid value %08x\n"; | ||
34 | static char wrong_a[] __initdata = "Trying to set a fixup %p to invalid value %08x\n"; | ||
35 | static char wrong[] __initdata = "Wrong address for %c fixup %p\n"; | ||
36 | static char insn_f[] __initdata = "Fixup f %p refers to weird instructions at %p[%08x,%08x]\n"; | ||
37 | static char insn_b[] __initdata = "Fixup b %p doesn't refer to a SETHI at %p[%08x]\n"; | ||
38 | static char insn_s[] __initdata = "Fixup s %p doesn't refer to an OR at %p[%08x]\n"; | ||
39 | static char insn_h[] __initdata = "Fixup h %p doesn't refer to a SETHI at %p[%08x]\n"; | ||
40 | static char insn_a[] __initdata = "Fixup a %p doesn't refer to a SETHI nor OR at %p[%08x]\n"; | ||
41 | static char insn_i[] __initdata = "Fixup i %p doesn't refer to a valid instruction at %p[%08x]\n"; | ||
42 | static char fca_und[] __initdata = "flush_cache_all undefined in btfixup()\n"; | ||
43 | static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n"; | ||
44 | |||
45 | #ifdef BTFIXUP_OPTIMIZE_OTHER | ||
46 | static void __init set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) | ||
47 | { | ||
48 | if (!fmangled) | ||
49 | *addr = value; | ||
50 | else { | ||
51 | unsigned int *q = (unsigned int *)q1; | ||
52 | if (*addr == 0x01000000) { | ||
53 | /* Noped */ | ||
54 | *q = value; | ||
55 | } else if (addr[-1] == *q) { | ||
56 | /* Moved */ | ||
57 | addr[-1] = value; | ||
58 | *q = value; | ||
59 | } else { | ||
60 | prom_printf(wrong_setaddr, addr-1, addr[-1], *addr, *q, value); | ||
61 | prom_halt(); | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | #else | ||
66 | static inline void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) | ||
67 | { | ||
68 | *addr = value; | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | void __init btfixup(void) | ||
73 | { | ||
74 | unsigned int *p, *q; | ||
75 | int type, count; | ||
76 | unsigned insn; | ||
77 | unsigned *addr; | ||
78 | int fmangled = 0; | ||
79 | void (*flush_cacheall)(void); | ||
80 | |||
81 | if (!visited) { | ||
82 | visited++; | ||
83 | printk(version); | ||
84 | if (ARCH_SUN4C) | ||
85 | printk(str_sun4c); | ||
86 | else { | ||
87 | printk(str_srmmu, srmmu_name); | ||
88 | if (sparc_cpu_model == sun4d) | ||
89 | printk(str_iounit); | ||
90 | else | ||
91 | printk(str_iommu); | ||
92 | } | ||
93 | } | ||
94 | for (p = ___btfixup_start; p < ___btfixup_end; ) { | ||
95 | count = p[2]; | ||
96 | q = p + 3; | ||
97 | switch (type = *(unsigned char *)p) { | ||
98 | case 'f': | ||
99 | count = p[3]; | ||
100 | q = p + 4; | ||
101 | if (((p[0] & 1) || p[1]) | ||
102 | && ((p[1] & 3) || (unsigned *)(p[1]) < _stext || (unsigned *)(p[1]) >= _end)) { | ||
103 | prom_printf(wrong_f, p, p[1]); | ||
104 | prom_halt(); | ||
105 | } | ||
106 | break; | ||
107 | case 'b': | ||
108 | if (p[1] < (unsigned long)__init_begin || p[1] >= (unsigned long)__init_text_end || (p[1] & 3)) { | ||
109 | prom_printf(wrong_b, p, p[1]); | ||
110 | prom_halt(); | ||
111 | } | ||
112 | break; | ||
113 | case 's': | ||
114 | if (p[1] + 0x1000 >= 0x2000) { | ||
115 | prom_printf(wrong_s, p, p[1]); | ||
116 | prom_halt(); | ||
117 | } | ||
118 | break; | ||
119 | case 'h': | ||
120 | if (p[1] & 0x3ff) { | ||
121 | prom_printf(wrong_h, p, p[1]); | ||
122 | prom_halt(); | ||
123 | } | ||
124 | break; | ||
125 | case 'a': | ||
126 | if (p[1] + 0x1000 >= 0x2000 && (p[1] & 0x3ff)) { | ||
127 | prom_printf(wrong_a, p, p[1]); | ||
128 | prom_halt(); | ||
129 | } | ||
130 | break; | ||
131 | } | ||
132 | if (p[0] & 1) { | ||
133 | p[0] &= ~1; | ||
134 | while (count) { | ||
135 | fmangled = 0; | ||
136 | addr = (unsigned *)*q; | ||
137 | if (addr < _stext || addr >= _end) { | ||
138 | prom_printf(wrong, type, p); | ||
139 | prom_halt(); | ||
140 | } | ||
141 | insn = *addr; | ||
142 | #ifdef BTFIXUP_OPTIMIZE_OTHER | ||
143 | if (type != 'f' && q[1]) { | ||
144 | insn = *(unsigned int *)q[1]; | ||
145 | if (!insn || insn == 1) | ||
146 | insn = *addr; | ||
147 | else | ||
148 | fmangled = 1; | ||
149 | } | ||
150 | #endif | ||
151 | switch (type) { | ||
152 | case 'f': /* CALL */ | ||
153 | if (addr >= __start___ksymtab && addr < __stop___ksymtab) { | ||
154 | *addr = p[1]; | ||
155 | break; | ||
156 | } else if (!q[1]) { | ||
157 | if ((insn & 0xc1c00000) == 0x01000000) { /* SETHI */ | ||
158 | *addr = (insn & 0xffc00000) | (p[1] >> 10); break; | ||
159 | } else if ((insn & 0xc1f82000) == 0x80102000) { /* OR X, %LO(i), Y */ | ||
160 | *addr = (insn & 0xffffe000) | (p[1] & 0x3ff); break; | ||
161 | } else if ((insn & 0xc0000000) != 0x40000000) { /* !CALL */ | ||
162 | bad_f: | ||
163 | prom_printf(insn_f, p, addr, insn, addr[1]); | ||
164 | prom_halt(); | ||
165 | } | ||
166 | } else if (q[1] != 1) | ||
167 | addr[1] = q[1]; | ||
168 | if (p[2] == BTFIXUPCALL_NORM) { | ||
169 | norm_f: | ||
170 | *addr = 0x40000000 | ((p[1] - (unsigned)addr) >> 2); | ||
171 | q[1] = 0; | ||
172 | break; | ||
173 | } | ||
174 | #ifndef BTFIXUP_OPTIMIZE_NOP | ||
175 | goto norm_f; | ||
176 | #else | ||
177 | if (!(addr[1] & 0x80000000)) { | ||
178 | if ((addr[1] & 0xc1c00000) != 0x01000000) /* !SETHI */ | ||
179 | goto bad_f; /* CALL, Bicc, FBfcc, CBccc are weird in delay slot, aren't they? */ | ||
180 | } else { | ||
181 | if ((addr[1] & 0x01800000) == 0x01800000) { | ||
182 | if ((addr[1] & 0x01f80000) == 0x01e80000) { | ||
183 | /* RESTORE */ | ||
184 | goto norm_f; /* It is dangerous to patch that */ | ||
185 | } | ||
186 | goto bad_f; | ||
187 | } | ||
188 | if ((addr[1] & 0xffffe003) == 0x9e03e000) { | ||
189 | /* ADD %O7, XX, %o7 */ | ||
190 | int displac = (addr[1] << 19); | ||
191 | |||
192 | displac = (displac >> 21) + 2; | ||
193 | *addr = (0x10800000) + (displac & 0x3fffff); | ||
194 | q[1] = addr[1]; | ||
195 | addr[1] = p[2]; | ||
196 | break; | ||
197 | } | ||
198 | if ((addr[1] & 0x201f) == 0x200f || (addr[1] & 0x7c000) == 0x3c000) | ||
199 | goto norm_f; /* Someone is playing bad tricks with us: rs1 or rs2 is o7 */ | ||
200 | if ((addr[1] & 0x3e000000) == 0x1e000000) | ||
201 | goto norm_f; /* rd is %o7. We'd better take care. */ | ||
202 | } | ||
203 | if (p[2] == BTFIXUPCALL_NOP) { | ||
204 | *addr = 0x01000000; | ||
205 | q[1] = 1; | ||
206 | break; | ||
207 | } | ||
208 | #ifndef BTFIXUP_OPTIMIZE_OTHER | ||
209 | goto norm_f; | ||
210 | #else | ||
211 | if (addr[1] == 0x01000000) { /* NOP in the delay slot */ | ||
212 | q[1] = addr[1]; | ||
213 | *addr = p[2]; | ||
214 | break; | ||
215 | } | ||
216 | if ((addr[1] & 0xc0000000) != 0xc0000000) { | ||
217 | /* Not a memory operation */ | ||
218 | if ((addr[1] & 0x30000000) == 0x10000000) { | ||
219 | /* Ok, non-memory op with rd %oX */ | ||
220 | if ((addr[1] & 0x3e000000) == 0x1c000000) | ||
221 | goto bad_f; /* Aiee. Someone is playing strange %sp tricks */ | ||
222 | if ((addr[1] & 0x3e000000) > 0x12000000 || | ||
223 | ((addr[1] & 0x3e000000) == 0x12000000 && | ||
224 | p[2] != BTFIXUPCALL_STO1O0 && p[2] != BTFIXUPCALL_SWAPO0O1) || | ||
225 | ((p[2] & 0xffffe000) == BTFIXUPCALL_RETINT(0))) { | ||
226 | /* Nobody uses the result. We can nop it out. */ | ||
227 | *addr = p[2]; | ||
228 | q[1] = addr[1]; | ||
229 | addr[1] = 0x01000000; | ||
230 | break; | ||
231 | } | ||
232 | if ((addr[1] & 0xf1ffffe0) == 0x90100000) { | ||
233 | /* MOV %reg, %Ox */ | ||
234 | if ((addr[1] & 0x3e000000) == 0x10000000 && | ||
235 | (p[2] & 0x7c000) == 0x20000) { | ||
236 | /* Ok, it is call xx; mov reg, %o0 and call optimizes | ||
237 | to doing something on %o0. Patch the patch. */ | ||
238 | *addr = (p[2] & ~0x7c000) | ((addr[1] & 0x1f) << 14); | ||
239 | q[1] = addr[1]; | ||
240 | addr[1] = 0x01000000; | ||
241 | break; | ||
242 | } | ||
243 | if ((addr[1] & 0x3e000000) == 0x12000000 && | ||
244 | p[2] == BTFIXUPCALL_STO1O0) { | ||
245 | *addr = (p[2] & ~0x3e000000) | ((addr[1] & 0x1f) << 25); | ||
246 | q[1] = addr[1]; | ||
247 | addr[1] = 0x01000000; | ||
248 | break; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | *addr = addr[1]; | ||
254 | q[1] = addr[1]; | ||
255 | addr[1] = p[2]; | ||
256 | break; | ||
257 | #endif /* BTFIXUP_OPTIMIZE_OTHER */ | ||
258 | #endif /* BTFIXUP_OPTIMIZE_NOP */ | ||
259 | case 'b': /* BLACKBOX */ | ||
260 | /* Has to be sethi i, xx */ | ||
261 | if ((insn & 0xc1c00000) != 0x01000000) { | ||
262 | prom_printf(insn_b, p, addr, insn); | ||
263 | prom_halt(); | ||
264 | } else { | ||
265 | void (*do_fixup)(unsigned *); | ||
266 | |||
267 | do_fixup = (void (*)(unsigned *))p[1]; | ||
268 | do_fixup(addr); | ||
269 | } | ||
270 | break; | ||
271 | case 's': /* SIMM13 */ | ||
272 | /* Has to be or %g0, i, xx */ | ||
273 | if ((insn & 0xc1ffe000) != 0x80102000) { | ||
274 | prom_printf(insn_s, p, addr, insn); | ||
275 | prom_halt(); | ||
276 | } | ||
277 | set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x1fff)); | ||
278 | break; | ||
279 | case 'h': /* SETHI */ | ||
280 | /* Has to be sethi i, xx */ | ||
281 | if ((insn & 0xc1c00000) != 0x01000000) { | ||
282 | prom_printf(insn_h, p, addr, insn); | ||
283 | prom_halt(); | ||
284 | } | ||
285 | set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); | ||
286 | break; | ||
287 | case 'a': /* HALF */ | ||
288 | /* Has to be sethi i, xx or or %g0, i, xx */ | ||
289 | if ((insn & 0xc1c00000) != 0x01000000 && | ||
290 | (insn & 0xc1ffe000) != 0x80102000) { | ||
291 | prom_printf(insn_a, p, addr, insn); | ||
292 | prom_halt(); | ||
293 | } | ||
294 | if (p[1] & 0x3ff) | ||
295 | set_addr(addr, q[1], fmangled, | ||
296 | (insn & 0x3e000000) | 0x80102000 | (p[1] & 0x1fff)); | ||
297 | else | ||
298 | set_addr(addr, q[1], fmangled, | ||
299 | (insn & 0x3e000000) | 0x01000000 | (p[1] >> 10)); | ||
300 | break; | ||
301 | case 'i': /* INT */ | ||
302 | if ((insn & 0xc1c00000) == 0x01000000) /* %HI */ | ||
303 | set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); | ||
304 | else if ((insn & 0x80002000) == 0x80002000) /* %LO */ | ||
305 | set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff)); | ||
306 | else { | ||
307 | prom_printf(insn_i, p, addr, insn); | ||
308 | prom_halt(); | ||
309 | } | ||
310 | break; | ||
311 | } | ||
312 | count -= 2; | ||
313 | q += 2; | ||
314 | } | ||
315 | } else | ||
316 | p = q + count; | ||
317 | } | ||
318 | #ifdef CONFIG_SMP | ||
319 | flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all); | ||
320 | #else | ||
321 | flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all); | ||
322 | #endif | ||
323 | if (!flush_cacheall) { | ||
324 | prom_printf(fca_und); | ||
325 | prom_halt(); | ||
326 | } | ||
327 | (*flush_cacheall)(); | ||
328 | } | ||
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c index df3155a17991..f46cf6be3370 100644 --- a/arch/sparc/mm/fault_32.c +++ b/arch/sparc/mm/fault_32.c | |||
@@ -24,29 +24,19 @@ | |||
24 | 24 | ||
25 | #include <asm/page.h> | 25 | #include <asm/page.h> |
26 | #include <asm/pgtable.h> | 26 | #include <asm/pgtable.h> |
27 | #include <asm/memreg.h> | ||
28 | #include <asm/openprom.h> | 27 | #include <asm/openprom.h> |
29 | #include <asm/oplib.h> | 28 | #include <asm/oplib.h> |
30 | #include <asm/smp.h> | 29 | #include <asm/smp.h> |
31 | #include <asm/traps.h> | 30 | #include <asm/traps.h> |
32 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
33 | 32 | ||
34 | extern int prom_node_root; | ||
35 | |||
36 | int show_unhandled_signals = 1; | 33 | int show_unhandled_signals = 1; |
37 | 34 | ||
38 | /* At boot time we determine these two values necessary for setting | 35 | /* At boot time we determine these two values necessary for setting |
39 | * up the segment maps and page table entries (pte's). | 36 | * up the segment maps and page table entries (pte's). |
40 | */ | 37 | */ |
41 | 38 | ||
42 | int num_segmaps, num_contexts; | 39 | int num_contexts; |
43 | int invalid_segment; | ||
44 | |||
45 | /* various Virtual Address Cache parameters we find at boot time... */ | ||
46 | |||
47 | int vac_size, vac_linesize, vac_do_hw_vac_flushes; | ||
48 | int vac_entries_per_context, vac_entries_per_segment; | ||
49 | int vac_entries_per_page; | ||
50 | 40 | ||
51 | /* Return how much physical memory we have. */ | 41 | /* Return how much physical memory we have. */ |
52 | unsigned long probe_memory(void) | 42 | unsigned long probe_memory(void) |
@@ -60,55 +50,36 @@ unsigned long probe_memory(void) | |||
60 | return total; | 50 | return total; |
61 | } | 51 | } |
62 | 52 | ||
63 | extern void sun4c_complete_all_stores(void); | ||
64 | |||
65 | /* Whee, a level 15 NMI interrupt memory error. Let's have fun... */ | ||
66 | asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr, | ||
67 | unsigned long svaddr, unsigned long aerr, | ||
68 | unsigned long avaddr) | ||
69 | { | ||
70 | sun4c_complete_all_stores(); | ||
71 | printk("FAULT: NMI received\n"); | ||
72 | printk("SREGS: Synchronous Error %08lx\n", serr); | ||
73 | printk(" Synchronous Vaddr %08lx\n", svaddr); | ||
74 | printk(" Asynchronous Error %08lx\n", aerr); | ||
75 | printk(" Asynchronous Vaddr %08lx\n", avaddr); | ||
76 | if (sun4c_memerr_reg) | ||
77 | printk(" Memory Parity Error %08lx\n", *sun4c_memerr_reg); | ||
78 | printk("REGISTER DUMP:\n"); | ||
79 | show_regs(regs); | ||
80 | prom_halt(); | ||
81 | } | ||
82 | |||
83 | static void unhandled_fault(unsigned long, struct task_struct *, | 53 | static void unhandled_fault(unsigned long, struct task_struct *, |
84 | struct pt_regs *) __attribute__ ((noreturn)); | 54 | struct pt_regs *) __attribute__ ((noreturn)); |
85 | 55 | ||
86 | static void unhandled_fault(unsigned long address, struct task_struct *tsk, | 56 | static void __noreturn unhandled_fault(unsigned long address, |
87 | struct pt_regs *regs) | 57 | struct task_struct *tsk, |
58 | struct pt_regs *regs) | ||
88 | { | 59 | { |
89 | if((unsigned long) address < PAGE_SIZE) { | 60 | if ((unsigned long) address < PAGE_SIZE) { |
90 | printk(KERN_ALERT | 61 | printk(KERN_ALERT |
91 | "Unable to handle kernel NULL pointer dereference\n"); | 62 | "Unable to handle kernel NULL pointer dereference\n"); |
92 | } else { | 63 | } else { |
93 | printk(KERN_ALERT "Unable to handle kernel paging request " | 64 | printk(KERN_ALERT "Unable to handle kernel paging request at virtual address %08lx\n", |
94 | "at virtual address %08lx\n", address); | 65 | address); |
95 | } | 66 | } |
96 | printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", | 67 | printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n", |
97 | (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); | 68 | (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); |
98 | printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", | 69 | printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n", |
99 | (tsk->mm ? (unsigned long) tsk->mm->pgd : | 70 | (tsk->mm ? (unsigned long) tsk->mm->pgd : |
100 | (unsigned long) tsk->active_mm->pgd)); | 71 | (unsigned long) tsk->active_mm->pgd)); |
101 | die_if_kernel("Oops", regs); | 72 | die_if_kernel("Oops", regs); |
102 | } | 73 | } |
103 | 74 | ||
104 | asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, | 75 | asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, |
105 | unsigned long address) | 76 | unsigned long address) |
106 | { | 77 | { |
107 | struct pt_regs regs; | 78 | struct pt_regs regs; |
108 | unsigned long g2; | 79 | unsigned long g2; |
109 | unsigned int insn; | 80 | unsigned int insn; |
110 | int i; | 81 | int i; |
111 | 82 | ||
112 | i = search_extables_range(ret_pc, &g2); | 83 | i = search_extables_range(ret_pc, &g2); |
113 | switch (i) { | 84 | switch (i) { |
114 | case 3: | 85 | case 3: |
@@ -128,14 +99,14 @@ asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, | |||
128 | /* for _from_ macros */ | 99 | /* for _from_ macros */ |
129 | insn = *((unsigned int *) pc); | 100 | insn = *((unsigned int *) pc); |
130 | if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) | 101 | if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) |
131 | return 2; | 102 | return 2; |
132 | break; | 103 | break; |
133 | 104 | ||
134 | default: | 105 | default: |
135 | break; | 106 | break; |
136 | } | 107 | } |
137 | 108 | ||
138 | memset(®s, 0, sizeof (regs)); | 109 | memset(®s, 0, sizeof(regs)); |
139 | regs.pc = pc; | 110 | regs.pc = pc; |
140 | regs.npc = pc + 4; | 111 | regs.npc = pc + 4; |
141 | __asm__ __volatile__( | 112 | __asm__ __volatile__( |
@@ -198,11 +169,10 @@ static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault) | |||
198 | if (text_fault) | 169 | if (text_fault) |
199 | return regs->pc; | 170 | return regs->pc; |
200 | 171 | ||
201 | if (regs->psr & PSR_PS) { | 172 | if (regs->psr & PSR_PS) |
202 | insn = *(unsigned int *) regs->pc; | 173 | insn = *(unsigned int *) regs->pc; |
203 | } else { | 174 | else |
204 | __get_user(insn, (unsigned int *) regs->pc); | 175 | __get_user(insn, (unsigned int *) regs->pc); |
205 | } | ||
206 | 176 | ||
207 | return safe_compute_effective_address(regs, insn); | 177 | return safe_compute_effective_address(regs, insn); |
208 | } | 178 | } |
@@ -228,7 +198,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, | |||
228 | unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | | 198 | unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | |
229 | (write ? FAULT_FLAG_WRITE : 0)); | 199 | (write ? FAULT_FLAG_WRITE : 0)); |
230 | 200 | ||
231 | if(text_fault) | 201 | if (text_fault) |
232 | address = regs->pc; | 202 | address = regs->pc; |
233 | 203 | ||
234 | /* | 204 | /* |
@@ -241,36 +211,32 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, | |||
241 | * nothing more. | 211 | * nothing more. |
242 | */ | 212 | */ |
243 | code = SEGV_MAPERR; | 213 | code = SEGV_MAPERR; |
244 | if (!ARCH_SUN4C && address >= TASK_SIZE) | 214 | if (address >= TASK_SIZE) |
245 | goto vmalloc_fault; | 215 | goto vmalloc_fault; |
246 | 216 | ||
247 | /* | 217 | /* |
248 | * If we're in an interrupt or have no user | 218 | * If we're in an interrupt or have no user |
249 | * context, we must not take the fault.. | 219 | * context, we must not take the fault.. |
250 | */ | 220 | */ |
251 | if (in_atomic() || !mm) | 221 | if (in_atomic() || !mm) |
252 | goto no_context; | 222 | goto no_context; |
253 | 223 | ||
254 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); | 224 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address); |
255 | 225 | ||
256 | retry: | 226 | retry: |
257 | down_read(&mm->mmap_sem); | 227 | down_read(&mm->mmap_sem); |
258 | 228 | ||
259 | /* | 229 | if (!from_user && address >= PAGE_OFFSET) |
260 | * The kernel referencing a bad kernel pointer can lock up | ||
261 | * a sun4c machine completely, so we must attempt recovery. | ||
262 | */ | ||
263 | if(!from_user && address >= PAGE_OFFSET) | ||
264 | goto bad_area; | 230 | goto bad_area; |
265 | 231 | ||
266 | vma = find_vma(mm, address); | 232 | vma = find_vma(mm, address); |
267 | if(!vma) | 233 | if (!vma) |
268 | goto bad_area; | 234 | goto bad_area; |
269 | if(vma->vm_start <= address) | 235 | if (vma->vm_start <= address) |
270 | goto good_area; | 236 | goto good_area; |
271 | if(!(vma->vm_flags & VM_GROWSDOWN)) | 237 | if (!(vma->vm_flags & VM_GROWSDOWN)) |
272 | goto bad_area; | 238 | goto bad_area; |
273 | if(expand_stack(vma, address)) | 239 | if (expand_stack(vma, address)) |
274 | goto bad_area; | 240 | goto bad_area; |
275 | /* | 241 | /* |
276 | * Ok, we have a good vm_area for this memory access, so | 242 | * Ok, we have a good vm_area for this memory access, so |
@@ -278,12 +244,12 @@ retry: | |||
278 | */ | 244 | */ |
279 | good_area: | 245 | good_area: |
280 | code = SEGV_ACCERR; | 246 | code = SEGV_ACCERR; |
281 | if(write) { | 247 | if (write) { |
282 | if(!(vma->vm_flags & VM_WRITE)) | 248 | if (!(vma->vm_flags & VM_WRITE)) |
283 | goto bad_area; | 249 | goto bad_area; |
284 | } else { | 250 | } else { |
285 | /* Allow reads even for write-only mappings */ | 251 | /* Allow reads even for write-only mappings */ |
286 | if(!(vma->vm_flags & (VM_READ | VM_EXEC))) | 252 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) |
287 | goto bad_area; | 253 | goto bad_area; |
288 | } | 254 | } |
289 | 255 | ||
@@ -349,14 +315,16 @@ no_context: | |||
349 | g2 = regs->u_regs[UREG_G2]; | 315 | g2 = regs->u_regs[UREG_G2]; |
350 | if (!from_user) { | 316 | if (!from_user) { |
351 | fixup = search_extables_range(regs->pc, &g2); | 317 | fixup = search_extables_range(regs->pc, &g2); |
352 | if (fixup > 10) { /* Values below are reserved for other things */ | 318 | /* Values below 10 are reserved for other things */ |
319 | if (fixup > 10) { | ||
353 | extern const unsigned __memset_start[]; | 320 | extern const unsigned __memset_start[]; |
354 | extern const unsigned __memset_end[]; | 321 | extern const unsigned __memset_end[]; |
355 | extern const unsigned __csum_partial_copy_start[]; | 322 | extern const unsigned __csum_partial_copy_start[]; |
356 | extern const unsigned __csum_partial_copy_end[]; | 323 | extern const unsigned __csum_partial_copy_end[]; |
357 | 324 | ||
358 | #ifdef DEBUG_EXCEPTIONS | 325 | #ifdef DEBUG_EXCEPTIONS |
359 | printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address); | 326 | printk("Exception: PC<%08lx> faddr<%08lx>\n", |
327 | regs->pc, address); | ||
360 | printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", | 328 | printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n", |
361 | regs->pc, fixup, g2); | 329 | regs->pc, fixup, g2); |
362 | #endif | 330 | #endif |
@@ -364,7 +332,7 @@ no_context: | |||
364 | regs->pc < (unsigned long)__memset_end) || | 332 | regs->pc < (unsigned long)__memset_end) || |
365 | (regs->pc >= (unsigned long)__csum_partial_copy_start && | 333 | (regs->pc >= (unsigned long)__csum_partial_copy_start && |
366 | regs->pc < (unsigned long)__csum_partial_copy_end)) { | 334 | regs->pc < (unsigned long)__csum_partial_copy_end)) { |
367 | regs->u_regs[UREG_I4] = address; | 335 | regs->u_regs[UREG_I4] = address; |
368 | regs->u_regs[UREG_I5] = regs->pc; | 336 | regs->u_regs[UREG_I5] = regs->pc; |
369 | } | 337 | } |
370 | regs->u_regs[UREG_G2] = g2; | 338 | regs->u_regs[UREG_G2] = g2; |
@@ -373,8 +341,8 @@ no_context: | |||
373 | return; | 341 | return; |
374 | } | 342 | } |
375 | } | 343 | } |
376 | 344 | ||
377 | unhandled_fault (address, tsk, regs); | 345 | unhandled_fault(address, tsk, regs); |
378 | do_exit(SIGKILL); | 346 | do_exit(SIGKILL); |
379 | 347 | ||
380 | /* | 348 | /* |
@@ -420,97 +388,12 @@ vmalloc_fault: | |||
420 | 388 | ||
421 | if (pmd_present(*pmd) || !pmd_present(*pmd_k)) | 389 | if (pmd_present(*pmd) || !pmd_present(*pmd_k)) |
422 | goto bad_area_nosemaphore; | 390 | goto bad_area_nosemaphore; |
391 | |||
423 | *pmd = *pmd_k; | 392 | *pmd = *pmd_k; |
424 | return; | 393 | return; |
425 | } | 394 | } |
426 | } | 395 | } |
427 | 396 | ||
428 | asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write, | ||
429 | unsigned long address) | ||
430 | { | ||
431 | extern void sun4c_update_mmu_cache(struct vm_area_struct *, | ||
432 | unsigned long,pte_t *); | ||
433 | extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long); | ||
434 | struct task_struct *tsk = current; | ||
435 | struct mm_struct *mm = tsk->mm; | ||
436 | pgd_t *pgdp; | ||
437 | pte_t *ptep; | ||
438 | |||
439 | if (text_fault) { | ||
440 | address = regs->pc; | ||
441 | } else if (!write && | ||
442 | !(regs->psr & PSR_PS)) { | ||
443 | unsigned int insn, __user *ip; | ||
444 | |||
445 | ip = (unsigned int __user *)regs->pc; | ||
446 | if (!get_user(insn, ip)) { | ||
447 | if ((insn & 0xc1680000) == 0xc0680000) | ||
448 | write = 1; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | if (!mm) { | ||
453 | /* We are oopsing. */ | ||
454 | do_sparc_fault(regs, text_fault, write, address); | ||
455 | BUG(); /* P3 Oops already, you bitch */ | ||
456 | } | ||
457 | |||
458 | pgdp = pgd_offset(mm, address); | ||
459 | ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address); | ||
460 | |||
461 | if (pgd_val(*pgdp)) { | ||
462 | if (write) { | ||
463 | if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) | ||
464 | == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) { | ||
465 | unsigned long flags; | ||
466 | |||
467 | *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | | ||
468 | _SUN4C_PAGE_MODIFIED | | ||
469 | _SUN4C_PAGE_VALID | | ||
470 | _SUN4C_PAGE_DIRTY); | ||
471 | |||
472 | local_irq_save(flags); | ||
473 | if (sun4c_get_segmap(address) != invalid_segment) { | ||
474 | sun4c_put_pte(address, pte_val(*ptep)); | ||
475 | local_irq_restore(flags); | ||
476 | return; | ||
477 | } | ||
478 | local_irq_restore(flags); | ||
479 | } | ||
480 | } else { | ||
481 | if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) | ||
482 | == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) { | ||
483 | unsigned long flags; | ||
484 | |||
485 | *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED | | ||
486 | _SUN4C_PAGE_VALID); | ||
487 | |||
488 | local_irq_save(flags); | ||
489 | if (sun4c_get_segmap(address) != invalid_segment) { | ||
490 | sun4c_put_pte(address, pte_val(*ptep)); | ||
491 | local_irq_restore(flags); | ||
492 | return; | ||
493 | } | ||
494 | local_irq_restore(flags); | ||
495 | } | ||
496 | } | ||
497 | } | ||
498 | |||
499 | /* This conditional is 'interesting'. */ | ||
500 | if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE)) | ||
501 | && (pte_val(*ptep) & _SUN4C_PAGE_VALID)) | ||
502 | /* Note: It is safe to not grab the MMAP semaphore here because | ||
503 | * we know that update_mmu_cache() will not sleep for | ||
504 | * any reason (at least not in the current implementation) | ||
505 | * and therefore there is no danger of another thread getting | ||
506 | * on the CPU and doing a shrink_mmap() on this vma. | ||
507 | */ | ||
508 | sun4c_update_mmu_cache (find_vma(current->mm, address), address, | ||
509 | ptep); | ||
510 | else | ||
511 | do_sparc_fault(regs, text_fault, write, address); | ||
512 | } | ||
513 | |||
514 | /* This always deals with user addresses. */ | 397 | /* This always deals with user addresses. */ |
515 | static void force_user_fault(unsigned long address, int write) | 398 | static void force_user_fault(unsigned long address, int write) |
516 | { | 399 | { |
@@ -523,21 +406,21 @@ static void force_user_fault(unsigned long address, int write) | |||
523 | 406 | ||
524 | down_read(&mm->mmap_sem); | 407 | down_read(&mm->mmap_sem); |
525 | vma = find_vma(mm, address); | 408 | vma = find_vma(mm, address); |
526 | if(!vma) | 409 | if (!vma) |
527 | goto bad_area; | 410 | goto bad_area; |
528 | if(vma->vm_start <= address) | 411 | if (vma->vm_start <= address) |
529 | goto good_area; | 412 | goto good_area; |
530 | if(!(vma->vm_flags & VM_GROWSDOWN)) | 413 | if (!(vma->vm_flags & VM_GROWSDOWN)) |
531 | goto bad_area; | 414 | goto bad_area; |
532 | if(expand_stack(vma, address)) | 415 | if (expand_stack(vma, address)) |
533 | goto bad_area; | 416 | goto bad_area; |
534 | good_area: | 417 | good_area: |
535 | code = SEGV_ACCERR; | 418 | code = SEGV_ACCERR; |
536 | if(write) { | 419 | if (write) { |
537 | if(!(vma->vm_flags & VM_WRITE)) | 420 | if (!(vma->vm_flags & VM_WRITE)) |
538 | goto bad_area; | 421 | goto bad_area; |
539 | } else { | 422 | } else { |
540 | if(!(vma->vm_flags & (VM_READ | VM_EXEC))) | 423 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) |
541 | goto bad_area; | 424 | goto bad_area; |
542 | } | 425 | } |
543 | switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) { | 426 | switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) { |
@@ -568,7 +451,7 @@ void window_overflow_fault(void) | |||
568 | unsigned long sp; | 451 | unsigned long sp; |
569 | 452 | ||
570 | sp = current_thread_info()->rwbuf_stkptrs[0]; | 453 | sp = current_thread_info()->rwbuf_stkptrs[0]; |
571 | if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) | 454 | if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) |
572 | force_user_fault(sp + 0x38, 1); | 455 | force_user_fault(sp + 0x38, 1); |
573 | force_user_fault(sp, 1); | 456 | force_user_fault(sp, 1); |
574 | 457 | ||
@@ -577,7 +460,7 @@ void window_overflow_fault(void) | |||
577 | 460 | ||
578 | void window_underflow_fault(unsigned long sp) | 461 | void window_underflow_fault(unsigned long sp) |
579 | { | 462 | { |
580 | if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) | 463 | if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) |
581 | force_user_fault(sp + 0x38, 0); | 464 | force_user_fault(sp + 0x38, 0); |
582 | force_user_fault(sp, 0); | 465 | force_user_fault(sp, 0); |
583 | 466 | ||
@@ -589,7 +472,7 @@ void window_ret_fault(struct pt_regs *regs) | |||
589 | unsigned long sp; | 472 | unsigned long sp; |
590 | 473 | ||
591 | sp = regs->u_regs[UREG_FP]; | 474 | sp = regs->u_regs[UREG_FP]; |
592 | if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) | 475 | if (((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK)) |
593 | force_user_fault(sp + 0x38, 0); | 476 | force_user_fault(sp + 0x38, 0); |
594 | force_user_fault(sp, 0); | 477 | force_user_fault(sp, 0); |
595 | 478 | ||
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c index c5f9021b1a01..ef5c779ec855 100644 --- a/arch/sparc/mm/init_32.c +++ b/arch/sparc/mm/init_32.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/gfp.h> | 27 | #include <linux/gfp.h> |
28 | 28 | ||
29 | #include <asm/sections.h> | 29 | #include <asm/sections.h> |
30 | #include <asm/vac-ops.h> | ||
31 | #include <asm/page.h> | 30 | #include <asm/page.h> |
32 | #include <asm/pgtable.h> | 31 | #include <asm/pgtable.h> |
33 | #include <asm/vaddrs.h> | 32 | #include <asm/vaddrs.h> |
@@ -45,9 +44,6 @@ EXPORT_SYMBOL(phys_base); | |||
45 | unsigned long pfn_base; | 44 | unsigned long pfn_base; |
46 | EXPORT_SYMBOL(pfn_base); | 45 | EXPORT_SYMBOL(pfn_base); |
47 | 46 | ||
48 | unsigned long page_kernel; | ||
49 | EXPORT_SYMBOL(page_kernel); | ||
50 | |||
51 | struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1]; | 47 | struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1]; |
52 | unsigned long sparc_unmapped_base; | 48 | unsigned long sparc_unmapped_base; |
53 | 49 | ||
@@ -287,44 +283,16 @@ unsigned long __init bootmem_init(unsigned long *pages_avail) | |||
287 | } | 283 | } |
288 | 284 | ||
289 | /* | 285 | /* |
290 | * check_pgt_cache | ||
291 | * | ||
292 | * This is called at the end of unmapping of VMA (zap_page_range), | ||
293 | * to rescan the page cache for architecture specific things, | ||
294 | * presumably something like sun4/sun4c PMEGs. Most architectures | ||
295 | * define check_pgt_cache empty. | ||
296 | * | ||
297 | * We simply copy the 2.4 implementation for now. | ||
298 | */ | ||
299 | static int pgt_cache_water[2] = { 25, 50 }; | ||
300 | |||
301 | void check_pgt_cache(void) | ||
302 | { | ||
303 | do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * paging_init() sets up the page tables: We call the MMU specific | 286 | * paging_init() sets up the page tables: We call the MMU specific |
308 | * init routine based upon the Sun model type on the Sparc. | 287 | * init routine based upon the Sun model type on the Sparc. |
309 | * | 288 | * |
310 | */ | 289 | */ |
311 | extern void sun4c_paging_init(void); | ||
312 | extern void srmmu_paging_init(void); | 290 | extern void srmmu_paging_init(void); |
313 | extern void device_scan(void); | 291 | extern void device_scan(void); |
314 | 292 | ||
315 | pgprot_t PAGE_SHARED __read_mostly; | ||
316 | EXPORT_SYMBOL(PAGE_SHARED); | ||
317 | |||
318 | void __init paging_init(void) | 293 | void __init paging_init(void) |
319 | { | 294 | { |
320 | switch(sparc_cpu_model) { | 295 | switch(sparc_cpu_model) { |
321 | case sun4c: | ||
322 | case sun4e: | ||
323 | case sun4: | ||
324 | sun4c_paging_init(); | ||
325 | sparc_unmapped_base = 0xe0000000; | ||
326 | BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000); | ||
327 | break; | ||
328 | case sparc_leon: | 296 | case sparc_leon: |
329 | leon_init(); | 297 | leon_init(); |
330 | /* fall through */ | 298 | /* fall through */ |
@@ -332,7 +300,6 @@ void __init paging_init(void) | |||
332 | case sun4d: | 300 | case sun4d: |
333 | srmmu_paging_init(); | 301 | srmmu_paging_init(); |
334 | sparc_unmapped_base = 0x50000000; | 302 | sparc_unmapped_base = 0x50000000; |
335 | BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000); | ||
336 | break; | 303 | break; |
337 | default: | 304 | default: |
338 | prom_printf("paging_init: Cannot init paging on this Sparc\n"); | 305 | prom_printf("paging_init: Cannot init paging on this Sparc\n"); |
@@ -341,24 +308,6 @@ void __init paging_init(void) | |||
341 | prom_halt(); | 308 | prom_halt(); |
342 | } | 309 | } |
343 | 310 | ||
344 | /* Initialize the protection map with non-constant, MMU dependent values. */ | ||
345 | protection_map[0] = PAGE_NONE; | ||
346 | protection_map[1] = PAGE_READONLY; | ||
347 | protection_map[2] = PAGE_COPY; | ||
348 | protection_map[3] = PAGE_COPY; | ||
349 | protection_map[4] = PAGE_READONLY; | ||
350 | protection_map[5] = PAGE_READONLY; | ||
351 | protection_map[6] = PAGE_COPY; | ||
352 | protection_map[7] = PAGE_COPY; | ||
353 | protection_map[8] = PAGE_NONE; | ||
354 | protection_map[9] = PAGE_READONLY; | ||
355 | protection_map[10] = PAGE_SHARED; | ||
356 | protection_map[11] = PAGE_SHARED; | ||
357 | protection_map[12] = PAGE_READONLY; | ||
358 | protection_map[13] = PAGE_READONLY; | ||
359 | protection_map[14] = PAGE_SHARED; | ||
360 | protection_map[15] = PAGE_SHARED; | ||
361 | btfixup(); | ||
362 | prom_build_devicetree(); | 311 | prom_build_devicetree(); |
363 | of_fill_in_cpu_data(); | 312 | of_fill_in_cpu_data(); |
364 | device_scan(); | 313 | device_scan(); |
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 21faaeea85de..6026fdd1b2ed 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -741,7 +741,6 @@ static void __init find_ramdisk(unsigned long phys_base) | |||
741 | struct node_mem_mask { | 741 | struct node_mem_mask { |
742 | unsigned long mask; | 742 | unsigned long mask; |
743 | unsigned long val; | 743 | unsigned long val; |
744 | unsigned long bootmem_paddr; | ||
745 | }; | 744 | }; |
746 | static struct node_mem_mask node_masks[MAX_NUMNODES]; | 745 | static struct node_mem_mask node_masks[MAX_NUMNODES]; |
747 | static int num_node_masks; | 746 | static int num_node_masks; |
@@ -806,12 +805,6 @@ static u64 memblock_nid_range(u64 start, u64 end, int *nid) | |||
806 | 805 | ||
807 | return start; | 806 | return start; |
808 | } | 807 | } |
809 | #else | ||
810 | static u64 memblock_nid_range(u64 start, u64 end, int *nid) | ||
811 | { | ||
812 | *nid = 0; | ||
813 | return end; | ||
814 | } | ||
815 | #endif | 808 | #endif |
816 | 809 | ||
817 | /* This must be invoked after performing all of the necessary | 810 | /* This must be invoked after performing all of the necessary |
@@ -820,10 +813,11 @@ static u64 memblock_nid_range(u64 start, u64 end, int *nid) | |||
820 | */ | 813 | */ |
821 | static void __init allocate_node_data(int nid) | 814 | static void __init allocate_node_data(int nid) |
822 | { | 815 | { |
823 | unsigned long paddr, num_pages, start_pfn, end_pfn; | ||
824 | struct pglist_data *p; | 816 | struct pglist_data *p; |
825 | 817 | unsigned long start_pfn, end_pfn; | |
826 | #ifdef CONFIG_NEED_MULTIPLE_NODES | 818 | #ifdef CONFIG_NEED_MULTIPLE_NODES |
819 | unsigned long paddr; | ||
820 | |||
827 | paddr = memblock_alloc_try_nid(sizeof(struct pglist_data), SMP_CACHE_BYTES, nid); | 821 | paddr = memblock_alloc_try_nid(sizeof(struct pglist_data), SMP_CACHE_BYTES, nid); |
828 | if (!paddr) { | 822 | if (!paddr) { |
829 | prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid); | 823 | prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid); |
@@ -832,7 +826,7 @@ static void __init allocate_node_data(int nid) | |||
832 | NODE_DATA(nid) = __va(paddr); | 826 | NODE_DATA(nid) = __va(paddr); |
833 | memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); | 827 | memset(NODE_DATA(nid), 0, sizeof(struct pglist_data)); |
834 | 828 | ||
835 | NODE_DATA(nid)->bdata = &bootmem_node_data[nid]; | 829 | NODE_DATA(nid)->node_id = nid; |
836 | #endif | 830 | #endif |
837 | 831 | ||
838 | p = NODE_DATA(nid); | 832 | p = NODE_DATA(nid); |
@@ -840,18 +834,6 @@ static void __init allocate_node_data(int nid) | |||
840 | get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); | 834 | get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); |
841 | p->node_start_pfn = start_pfn; | 835 | p->node_start_pfn = start_pfn; |
842 | p->node_spanned_pages = end_pfn - start_pfn; | 836 | p->node_spanned_pages = end_pfn - start_pfn; |
843 | |||
844 | if (p->node_spanned_pages) { | ||
845 | num_pages = bootmem_bootmap_pages(p->node_spanned_pages); | ||
846 | |||
847 | paddr = memblock_alloc_try_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid); | ||
848 | if (!paddr) { | ||
849 | prom_printf("Cannot allocate bootmap for nid[%d]\n", | ||
850 | nid); | ||
851 | prom_halt(); | ||
852 | } | ||
853 | node_masks[nid].bootmem_paddr = paddr; | ||
854 | } | ||
855 | } | 837 | } |
856 | 838 | ||
857 | static void init_node_masks_nonnuma(void) | 839 | static void init_node_masks_nonnuma(void) |
@@ -1292,75 +1274,9 @@ static void __init bootmem_init_nonnuma(void) | |||
1292 | node_set_online(0); | 1274 | node_set_online(0); |
1293 | } | 1275 | } |
1294 | 1276 | ||
1295 | static void __init reserve_range_in_node(int nid, unsigned long start, | ||
1296 | unsigned long end) | ||
1297 | { | ||
1298 | numadbg(" reserve_range_in_node(nid[%d],start[%lx],end[%lx]\n", | ||
1299 | nid, start, end); | ||
1300 | while (start < end) { | ||
1301 | unsigned long this_end; | ||
1302 | int n; | ||
1303 | |||
1304 | this_end = memblock_nid_range(start, end, &n); | ||
1305 | if (n == nid) { | ||
1306 | numadbg(" MATCH reserving range [%lx:%lx]\n", | ||
1307 | start, this_end); | ||
1308 | reserve_bootmem_node(NODE_DATA(nid), start, | ||
1309 | (this_end - start), BOOTMEM_DEFAULT); | ||
1310 | } else | ||
1311 | numadbg(" NO MATCH, advancing start to %lx\n", | ||
1312 | this_end); | ||
1313 | |||
1314 | start = this_end; | ||
1315 | } | ||
1316 | } | ||
1317 | |||
1318 | static void __init trim_reserved_in_node(int nid) | ||
1319 | { | ||
1320 | struct memblock_region *reg; | ||
1321 | |||
1322 | numadbg(" trim_reserved_in_node(%d)\n", nid); | ||
1323 | |||
1324 | for_each_memblock(reserved, reg) | ||
1325 | reserve_range_in_node(nid, reg->base, reg->base + reg->size); | ||
1326 | } | ||
1327 | |||
1328 | static void __init bootmem_init_one_node(int nid) | ||
1329 | { | ||
1330 | struct pglist_data *p; | ||
1331 | |||
1332 | numadbg("bootmem_init_one_node(%d)\n", nid); | ||
1333 | |||
1334 | p = NODE_DATA(nid); | ||
1335 | |||
1336 | if (p->node_spanned_pages) { | ||
1337 | unsigned long paddr = node_masks[nid].bootmem_paddr; | ||
1338 | unsigned long end_pfn; | ||
1339 | |||
1340 | end_pfn = p->node_start_pfn + p->node_spanned_pages; | ||
1341 | |||
1342 | numadbg(" init_bootmem_node(%d, %lx, %lx, %lx)\n", | ||
1343 | nid, paddr >> PAGE_SHIFT, p->node_start_pfn, end_pfn); | ||
1344 | |||
1345 | init_bootmem_node(p, paddr >> PAGE_SHIFT, | ||
1346 | p->node_start_pfn, end_pfn); | ||
1347 | |||
1348 | numadbg(" free_bootmem_with_active_regions(%d, %lx)\n", | ||
1349 | nid, end_pfn); | ||
1350 | free_bootmem_with_active_regions(nid, end_pfn); | ||
1351 | |||
1352 | trim_reserved_in_node(nid); | ||
1353 | |||
1354 | numadbg(" sparse_memory_present_with_active_regions(%d)\n", | ||
1355 | nid); | ||
1356 | sparse_memory_present_with_active_regions(nid); | ||
1357 | } | ||
1358 | } | ||
1359 | |||
1360 | static unsigned long __init bootmem_init(unsigned long phys_base) | 1277 | static unsigned long __init bootmem_init(unsigned long phys_base) |
1361 | { | 1278 | { |
1362 | unsigned long end_pfn; | 1279 | unsigned long end_pfn; |
1363 | int nid; | ||
1364 | 1280 | ||
1365 | end_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT; | 1281 | end_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT; |
1366 | max_pfn = max_low_pfn = end_pfn; | 1282 | max_pfn = max_low_pfn = end_pfn; |
@@ -1369,11 +1285,12 @@ static unsigned long __init bootmem_init(unsigned long phys_base) | |||
1369 | if (bootmem_init_numa() < 0) | 1285 | if (bootmem_init_numa() < 0) |
1370 | bootmem_init_nonnuma(); | 1286 | bootmem_init_nonnuma(); |
1371 | 1287 | ||
1372 | /* XXX cpu notifier XXX */ | 1288 | /* Dump memblock with node info. */ |
1289 | memblock_dump_all(); | ||
1373 | 1290 | ||
1374 | for_each_online_node(nid) | 1291 | /* XXX cpu notifier XXX */ |
1375 | bootmem_init_one_node(nid); | ||
1376 | 1292 | ||
1293 | sparse_memory_present_with_active_regions(MAX_NUMNODES); | ||
1377 | sparse_init(); | 1294 | sparse_init(); |
1378 | 1295 | ||
1379 | return end_pfn; | 1296 | return end_pfn; |
@@ -1701,6 +1618,7 @@ void __init paging_init(void) | |||
1701 | { | 1618 | { |
1702 | unsigned long end_pfn, shift, phys_base; | 1619 | unsigned long end_pfn, shift, phys_base; |
1703 | unsigned long real_end, i; | 1620 | unsigned long real_end, i; |
1621 | int node; | ||
1704 | 1622 | ||
1705 | /* These build time checkes make sure that the dcache_dirty_cpu() | 1623 | /* These build time checkes make sure that the dcache_dirty_cpu() |
1706 | * page->flags usage will work. | 1624 | * page->flags usage will work. |
@@ -1826,22 +1744,24 @@ void __init paging_init(void) | |||
1826 | #endif | 1744 | #endif |
1827 | } | 1745 | } |
1828 | 1746 | ||
1747 | /* Setup bootmem... */ | ||
1748 | last_valid_pfn = end_pfn = bootmem_init(phys_base); | ||
1749 | |||
1829 | /* Once the OF device tree and MDESC have been setup, we know | 1750 | /* Once the OF device tree and MDESC have been setup, we know |
1830 | * the list of possible cpus. Therefore we can allocate the | 1751 | * the list of possible cpus. Therefore we can allocate the |
1831 | * IRQ stacks. | 1752 | * IRQ stacks. |
1832 | */ | 1753 | */ |
1833 | for_each_possible_cpu(i) { | 1754 | for_each_possible_cpu(i) { |
1834 | /* XXX Use node local allocations... XXX */ | 1755 | node = cpu_to_node(i); |
1835 | softirq_stack[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
1836 | hardirq_stack[i] = __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
1837 | } | ||
1838 | 1756 | ||
1839 | /* Setup bootmem... */ | 1757 | softirq_stack[i] = __alloc_bootmem_node(NODE_DATA(node), |
1840 | last_valid_pfn = end_pfn = bootmem_init(phys_base); | 1758 | THREAD_SIZE, |
1759 | THREAD_SIZE, 0); | ||
1760 | hardirq_stack[i] = __alloc_bootmem_node(NODE_DATA(node), | ||
1761 | THREAD_SIZE, | ||
1762 | THREAD_SIZE, 0); | ||
1763 | } | ||
1841 | 1764 | ||
1842 | #ifndef CONFIG_NEED_MULTIPLE_NODES | ||
1843 | max_mapnr = last_valid_pfn; | ||
1844 | #endif | ||
1845 | kernel_physical_mapping_init(); | 1765 | kernel_physical_mapping_init(); |
1846 | 1766 | ||
1847 | { | 1767 | { |
@@ -1973,6 +1893,7 @@ void __init mem_init(void) | |||
1973 | free_all_bootmem_node(NODE_DATA(i)); | 1893 | free_all_bootmem_node(NODE_DATA(i)); |
1974 | } | 1894 | } |
1975 | } | 1895 | } |
1896 | totalram_pages += free_low_memory_core_early(MAX_NUMNODES); | ||
1976 | } | 1897 | } |
1977 | #else | 1898 | #else |
1978 | totalram_pages = free_all_bootmem(); | 1899 | totalram_pages = free_all_bootmem(); |
diff --git a/arch/sparc/mm/io-unit.c b/arch/sparc/mm/io-unit.c index fc58c3e917df..eb99862e9654 100644 --- a/arch/sparc/mm/io-unit.c +++ b/arch/sparc/mm/io-unit.c | |||
@@ -197,7 +197,7 @@ static void iounit_release_scsi_sgl(struct device *dev, struct scatterlist *sg, | |||
197 | } | 197 | } |
198 | 198 | ||
199 | #ifdef CONFIG_SBUS | 199 | #ifdef CONFIG_SBUS |
200 | static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, __u32 addr, int len) | 200 | static int iounit_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, unsigned long addr, int len) |
201 | { | 201 | { |
202 | struct iounit_struct *iounit = dev->archdata.iommu; | 202 | struct iounit_struct *iounit = dev->archdata.iommu; |
203 | unsigned long page, end; | 203 | unsigned long page, end; |
@@ -242,29 +242,18 @@ static void iounit_unmap_dma_area(struct device *dev, unsigned long addr, int le | |||
242 | } | 242 | } |
243 | #endif | 243 | #endif |
244 | 244 | ||
245 | static char *iounit_lockarea(char *vaddr, unsigned long len) | 245 | static const struct sparc32_dma_ops iounit_dma_ops = { |
246 | { | 246 | .get_scsi_one = iounit_get_scsi_one, |
247 | /* FIXME: Write this */ | 247 | .get_scsi_sgl = iounit_get_scsi_sgl, |
248 | return vaddr; | 248 | .release_scsi_one = iounit_release_scsi_one, |
249 | } | 249 | .release_scsi_sgl = iounit_release_scsi_sgl, |
250 | 250 | #ifdef CONFIG_SBUS | |
251 | static void iounit_unlockarea(char *vaddr, unsigned long len) | 251 | .map_dma_area = iounit_map_dma_area, |
252 | { | 252 | .unmap_dma_area = iounit_unmap_dma_area, |
253 | /* FIXME: Write this */ | 253 | #endif |
254 | } | 254 | }; |
255 | 255 | ||
256 | void __init ld_mmu_iounit(void) | 256 | void __init ld_mmu_iounit(void) |
257 | { | 257 | { |
258 | BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0); | 258 | sparc32_dma_ops = &iounit_dma_ops; |
259 | BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP); | ||
260 | |||
261 | BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM); | ||
262 | BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM); | ||
263 | BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM); | ||
264 | BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM); | ||
265 | |||
266 | #ifdef CONFIG_SBUS | ||
267 | BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM); | ||
268 | BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM); | ||
269 | #endif | ||
270 | } | 259 | } |
diff --git a/arch/sparc/mm/iommu.c b/arch/sparc/mm/iommu.c index 07fc6a65d9b6..a8a58cad9d2b 100644 --- a/arch/sparc/mm/iommu.c +++ b/arch/sparc/mm/iommu.c | |||
@@ -39,8 +39,6 @@ | |||
39 | 39 | ||
40 | /* srmmu.c */ | 40 | /* srmmu.c */ |
41 | extern int viking_mxcc_present; | 41 | extern int viking_mxcc_present; |
42 | BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long) | ||
43 | #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page) | ||
44 | extern int flush_page_for_dma_global; | 42 | extern int flush_page_for_dma_global; |
45 | static int viking_flush; | 43 | static int viking_flush; |
46 | /* viking.S */ | 44 | /* viking.S */ |
@@ -143,7 +141,6 @@ static int __init iommu_init(void) | |||
143 | 141 | ||
144 | subsys_initcall(iommu_init); | 142 | subsys_initcall(iommu_init); |
145 | 143 | ||
146 | /* This begs to be btfixup-ed by srmmu. */ | ||
147 | /* Flush the iotlb entries to ram. */ | 144 | /* Flush the iotlb entries to ram. */ |
148 | /* This could be better if we didn't have to flush whole pages. */ | 145 | /* This could be better if we didn't have to flush whole pages. */ |
149 | static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) | 146 | static void iommu_flush_iotlb(iopte_t *iopte, unsigned int niopte) |
@@ -216,11 +213,6 @@ static u32 iommu_get_scsi_one(struct device *dev, char *vaddr, unsigned int len) | |||
216 | return busa + off; | 213 | return busa + off; |
217 | } | 214 | } |
218 | 215 | ||
219 | static __u32 iommu_get_scsi_one_noflush(struct device *dev, char *vaddr, unsigned long len) | ||
220 | { | ||
221 | return iommu_get_scsi_one(dev, vaddr, len); | ||
222 | } | ||
223 | |||
224 | static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len) | 216 | static __u32 iommu_get_scsi_one_gflush(struct device *dev, char *vaddr, unsigned long len) |
225 | { | 217 | { |
226 | flush_page_for_dma(0); | 218 | flush_page_for_dma(0); |
@@ -238,19 +230,6 @@ static __u32 iommu_get_scsi_one_pflush(struct device *dev, char *vaddr, unsigned | |||
238 | return iommu_get_scsi_one(dev, vaddr, len); | 230 | return iommu_get_scsi_one(dev, vaddr, len); |
239 | } | 231 | } |
240 | 232 | ||
241 | static void iommu_get_scsi_sgl_noflush(struct device *dev, struct scatterlist *sg, int sz) | ||
242 | { | ||
243 | int n; | ||
244 | |||
245 | while (sz != 0) { | ||
246 | --sz; | ||
247 | n = (sg->length + sg->offset + PAGE_SIZE-1) >> PAGE_SHIFT; | ||
248 | sg->dma_address = iommu_get_one(dev, sg_page(sg), n) + sg->offset; | ||
249 | sg->dma_length = sg->length; | ||
250 | sg = sg_next(sg); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz) | 233 | static void iommu_get_scsi_sgl_gflush(struct device *dev, struct scatterlist *sg, int sz) |
255 | { | 234 | { |
256 | int n; | 235 | int n; |
@@ -426,40 +405,36 @@ static void iommu_unmap_dma_area(struct device *dev, unsigned long busa, int len | |||
426 | } | 405 | } |
427 | #endif | 406 | #endif |
428 | 407 | ||
429 | static char *iommu_lockarea(char *vaddr, unsigned long len) | 408 | static const struct sparc32_dma_ops iommu_dma_gflush_ops = { |
430 | { | 409 | .get_scsi_one = iommu_get_scsi_one_gflush, |
431 | return vaddr; | 410 | .get_scsi_sgl = iommu_get_scsi_sgl_gflush, |
432 | } | 411 | .release_scsi_one = iommu_release_scsi_one, |
412 | .release_scsi_sgl = iommu_release_scsi_sgl, | ||
413 | #ifdef CONFIG_SBUS | ||
414 | .map_dma_area = iommu_map_dma_area, | ||
415 | .unmap_dma_area = iommu_unmap_dma_area, | ||
416 | #endif | ||
417 | }; | ||
433 | 418 | ||
434 | static void iommu_unlockarea(char *vaddr, unsigned long len) | 419 | static const struct sparc32_dma_ops iommu_dma_pflush_ops = { |
435 | { | 420 | .get_scsi_one = iommu_get_scsi_one_pflush, |
436 | } | 421 | .get_scsi_sgl = iommu_get_scsi_sgl_pflush, |
422 | .release_scsi_one = iommu_release_scsi_one, | ||
423 | .release_scsi_sgl = iommu_release_scsi_sgl, | ||
424 | #ifdef CONFIG_SBUS | ||
425 | .map_dma_area = iommu_map_dma_area, | ||
426 | .unmap_dma_area = iommu_unmap_dma_area, | ||
427 | #endif | ||
428 | }; | ||
437 | 429 | ||
438 | void __init ld_mmu_iommu(void) | 430 | void __init ld_mmu_iommu(void) |
439 | { | 431 | { |
440 | viking_flush = (BTFIXUPVAL_CALL(flush_page_for_dma) == (unsigned long)viking_flush_page); | 432 | if (flush_page_for_dma_global) { |
441 | BTFIXUPSET_CALL(mmu_lockarea, iommu_lockarea, BTFIXUPCALL_RETO0); | ||
442 | BTFIXUPSET_CALL(mmu_unlockarea, iommu_unlockarea, BTFIXUPCALL_NOP); | ||
443 | |||
444 | if (!BTFIXUPVAL_CALL(flush_page_for_dma)) { | ||
445 | /* IO coherent chip */ | ||
446 | BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_noflush, BTFIXUPCALL_RETO0); | ||
447 | BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_noflush, BTFIXUPCALL_NORM); | ||
448 | } else if (flush_page_for_dma_global) { | ||
449 | /* flush_page_for_dma flushes everything, no matter of what page is it */ | 433 | /* flush_page_for_dma flushes everything, no matter of what page is it */ |
450 | BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_gflush, BTFIXUPCALL_NORM); | 434 | sparc32_dma_ops = &iommu_dma_gflush_ops; |
451 | BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_gflush, BTFIXUPCALL_NORM); | ||
452 | } else { | 435 | } else { |
453 | BTFIXUPSET_CALL(mmu_get_scsi_one, iommu_get_scsi_one_pflush, BTFIXUPCALL_NORM); | 436 | sparc32_dma_ops = &iommu_dma_pflush_ops; |
454 | BTFIXUPSET_CALL(mmu_get_scsi_sgl, iommu_get_scsi_sgl_pflush, BTFIXUPCALL_NORM); | ||
455 | } | 437 | } |
456 | BTFIXUPSET_CALL(mmu_release_scsi_one, iommu_release_scsi_one, BTFIXUPCALL_NORM); | ||
457 | BTFIXUPSET_CALL(mmu_release_scsi_sgl, iommu_release_scsi_sgl, BTFIXUPCALL_NORM); | ||
458 | |||
459 | #ifdef CONFIG_SBUS | ||
460 | BTFIXUPSET_CALL(mmu_map_dma_area, iommu_map_dma_area, BTFIXUPCALL_NORM); | ||
461 | BTFIXUPSET_CALL(mmu_unmap_dma_area, iommu_unmap_dma_area, BTFIXUPCALL_NORM); | ||
462 | #endif | ||
463 | 438 | ||
464 | if (viking_mxcc_present || srmmu_modtype == HyperSparc) { | 439 | if (viking_mxcc_present || srmmu_modtype == HyperSparc) { |
465 | dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); | 440 | dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV); |
diff --git a/arch/sparc/mm/leon_mm.c b/arch/sparc/mm/leon_mm.c index 13c2169822a8..4c67ae6e5023 100644 --- a/arch/sparc/mm/leon_mm.c +++ b/arch/sparc/mm/leon_mm.c | |||
@@ -15,9 +15,23 @@ | |||
15 | #include <asm/leon.h> | 15 | #include <asm/leon.h> |
16 | #include <asm/tlbflush.h> | 16 | #include <asm/tlbflush.h> |
17 | 17 | ||
18 | #include "srmmu.h" | ||
19 | |||
18 | int leon_flush_during_switch = 1; | 20 | int leon_flush_during_switch = 1; |
19 | int srmmu_swprobe_trace; | 21 | int srmmu_swprobe_trace; |
20 | 22 | ||
23 | static inline unsigned long leon_get_ctable_ptr(void) | ||
24 | { | ||
25 | unsigned int retval; | ||
26 | |||
27 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
28 | "=r" (retval) : | ||
29 | "r" (SRMMU_CTXTBL_PTR), | ||
30 | "i" (ASI_LEON_MMUREGS)); | ||
31 | return (retval & SRMMU_CTX_PMASK) << 4; | ||
32 | } | ||
33 | |||
34 | |||
21 | unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) | 35 | unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) |
22 | { | 36 | { |
23 | 37 | ||
@@ -33,10 +47,10 @@ unsigned long srmmu_swprobe(unsigned long vaddr, unsigned long *paddr) | |||
33 | if (srmmu_swprobe_trace) | 47 | if (srmmu_swprobe_trace) |
34 | printk(KERN_INFO "swprobe: trace on\n"); | 48 | printk(KERN_INFO "swprobe: trace on\n"); |
35 | 49 | ||
36 | ctxtbl = srmmu_get_ctable_ptr(); | 50 | ctxtbl = leon_get_ctable_ptr(); |
37 | if (!(ctxtbl)) { | 51 | if (!(ctxtbl)) { |
38 | if (srmmu_swprobe_trace) | 52 | if (srmmu_swprobe_trace) |
39 | printk(KERN_INFO "swprobe: srmmu_get_ctable_ptr returned 0=>0\n"); | 53 | printk(KERN_INFO "swprobe: leon_get_ctable_ptr returned 0=>0\n"); |
40 | return 0; | 54 | return 0; |
41 | } | 55 | } |
42 | if (!_pfn_valid(PFN(ctxtbl))) { | 56 | if (!_pfn_valid(PFN(ctxtbl))) { |
@@ -258,3 +272,80 @@ void leon_switch_mm(void) | |||
258 | if (leon_flush_during_switch) | 272 | if (leon_flush_during_switch) |
259 | leon_flush_cache_all(); | 273 | leon_flush_cache_all(); |
260 | } | 274 | } |
275 | |||
276 | static void leon_flush_cache_mm(struct mm_struct *mm) | ||
277 | { | ||
278 | leon_flush_cache_all(); | ||
279 | } | ||
280 | |||
281 | static void leon_flush_cache_page(struct vm_area_struct *vma, unsigned long page) | ||
282 | { | ||
283 | leon_flush_pcache_all(vma, page); | ||
284 | } | ||
285 | |||
286 | static void leon_flush_cache_range(struct vm_area_struct *vma, | ||
287 | unsigned long start, | ||
288 | unsigned long end) | ||
289 | { | ||
290 | leon_flush_cache_all(); | ||
291 | } | ||
292 | |||
293 | static void leon_flush_tlb_mm(struct mm_struct *mm) | ||
294 | { | ||
295 | leon_flush_tlb_all(); | ||
296 | } | ||
297 | |||
298 | static void leon_flush_tlb_page(struct vm_area_struct *vma, | ||
299 | unsigned long page) | ||
300 | { | ||
301 | leon_flush_tlb_all(); | ||
302 | } | ||
303 | |||
304 | static void leon_flush_tlb_range(struct vm_area_struct *vma, | ||
305 | unsigned long start, | ||
306 | unsigned long end) | ||
307 | { | ||
308 | leon_flush_tlb_all(); | ||
309 | } | ||
310 | |||
311 | static void leon_flush_page_to_ram(unsigned long page) | ||
312 | { | ||
313 | leon_flush_cache_all(); | ||
314 | } | ||
315 | |||
316 | static void leon_flush_sig_insns(struct mm_struct *mm, unsigned long page) | ||
317 | { | ||
318 | leon_flush_cache_all(); | ||
319 | } | ||
320 | |||
321 | static void leon_flush_page_for_dma(unsigned long page) | ||
322 | { | ||
323 | leon_flush_dcache_all(); | ||
324 | } | ||
325 | |||
326 | void __init poke_leonsparc(void) | ||
327 | { | ||
328 | } | ||
329 | |||
330 | static const struct sparc32_cachetlb_ops leon_ops = { | ||
331 | .cache_all = leon_flush_cache_all, | ||
332 | .cache_mm = leon_flush_cache_mm, | ||
333 | .cache_page = leon_flush_cache_page, | ||
334 | .cache_range = leon_flush_cache_range, | ||
335 | .tlb_all = leon_flush_tlb_all, | ||
336 | .tlb_mm = leon_flush_tlb_mm, | ||
337 | .tlb_page = leon_flush_tlb_page, | ||
338 | .tlb_range = leon_flush_tlb_range, | ||
339 | .page_to_ram = leon_flush_page_to_ram, | ||
340 | .sig_insns = leon_flush_sig_insns, | ||
341 | .page_for_dma = leon_flush_page_for_dma, | ||
342 | }; | ||
343 | |||
344 | void __init init_leon(void) | ||
345 | { | ||
346 | srmmu_name = "LEON"; | ||
347 | sparc32_cachetlb_ops = &leon_ops; | ||
348 | poke_srmmu = poke_leonsparc; | ||
349 | |||
350 | leon_flush_during_switch = leon_flush_needed(); | ||
351 | } | ||
diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c deleted file mode 100644 index c5bf2a6c3858..000000000000 --- a/arch/sparc/mm/loadmmu.c +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | /* | ||
2 | * loadmmu.c: This code loads up all the mm function pointers once the | ||
3 | * machine type has been determined. It also sets the static | ||
4 | * mmu values such as PAGE_NONE, etc. | ||
5 | * | ||
6 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
7 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/init.h> | ||
13 | |||
14 | #include <asm/page.h> | ||
15 | #include <asm/pgtable.h> | ||
16 | #include <asm/mmu_context.h> | ||
17 | #include <asm/oplib.h> | ||
18 | |||
19 | struct ctx_list *ctx_list_pool; | ||
20 | struct ctx_list ctx_free; | ||
21 | struct ctx_list ctx_used; | ||
22 | |||
23 | extern void ld_mmu_sun4c(void); | ||
24 | extern void ld_mmu_srmmu(void); | ||
25 | |||
26 | void __init load_mmu(void) | ||
27 | { | ||
28 | switch(sparc_cpu_model) { | ||
29 | case sun4c: | ||
30 | case sun4: | ||
31 | ld_mmu_sun4c(); | ||
32 | break; | ||
33 | case sun4m: | ||
34 | case sun4d: | ||
35 | case sparc_leon: | ||
36 | ld_mmu_srmmu(); | ||
37 | break; | ||
38 | default: | ||
39 | prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model); | ||
40 | prom_halt(); | ||
41 | } | ||
42 | btfixup(); | ||
43 | } | ||
diff --git a/arch/sparc/mm/nosun4c.c b/arch/sparc/mm/nosun4c.c deleted file mode 100644 index 4e62c27147c4..000000000000 --- a/arch/sparc/mm/nosun4c.c +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | /* | ||
2 | * nosun4c.c: This file is a bunch of dummies for SMP compiles, | ||
3 | * so that it does not need sun4c and avoid ifdefs. | ||
4 | * | ||
5 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <asm/pgtable.h> | ||
12 | |||
13 | static char shouldnothappen[] __initdata = "32bit SMP kernel only supports sun4m and sun4d\n"; | ||
14 | |||
15 | /* Dummies */ | ||
16 | struct sun4c_mmu_ring { | ||
17 | unsigned long xxx1[3]; | ||
18 | unsigned char xxx2[2]; | ||
19 | int xxx3; | ||
20 | }; | ||
21 | struct sun4c_mmu_ring sun4c_kernel_ring; | ||
22 | struct sun4c_mmu_ring sun4c_kfree_ring; | ||
23 | unsigned long sun4c_kernel_faults; | ||
24 | unsigned long *sun4c_memerr_reg; | ||
25 | |||
26 | static void __init should_not_happen(void) | ||
27 | { | ||
28 | prom_printf(shouldnothappen); | ||
29 | prom_halt(); | ||
30 | } | ||
31 | |||
32 | unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) | ||
33 | { | ||
34 | should_not_happen(); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | void __init ld_mmu_sun4c(void) | ||
39 | { | ||
40 | should_not_happen(); | ||
41 | } | ||
42 | |||
43 | void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) | ||
44 | { | ||
45 | } | ||
46 | |||
47 | void sun4c_unmapioaddr(unsigned long virt_addr) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | void sun4c_complete_all_stores(void) | ||
52 | { | ||
53 | } | ||
54 | |||
55 | pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address) | ||
56 | { | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address) | ||
61 | { | ||
62 | return NULL; | ||
63 | } | ||
64 | |||
65 | void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) | ||
66 | { | ||
67 | } | ||
68 | |||
69 | void __init sun4c_probe_vac(void) | ||
70 | { | ||
71 | should_not_happen(); | ||
72 | } | ||
73 | |||
74 | void __init sun4c_probe_memerr_reg(void) | ||
75 | { | ||
76 | should_not_happen(); | ||
77 | } | ||
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index cbef74e793b8..8e97e0305b01 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c | |||
@@ -48,39 +48,37 @@ | |||
48 | #include <asm/turbosparc.h> | 48 | #include <asm/turbosparc.h> |
49 | #include <asm/leon.h> | 49 | #include <asm/leon.h> |
50 | 50 | ||
51 | #include <asm/btfixup.h> | 51 | #include "srmmu.h" |
52 | 52 | ||
53 | enum mbus_module srmmu_modtype; | 53 | enum mbus_module srmmu_modtype; |
54 | static unsigned int hwbug_bitmask; | 54 | static unsigned int hwbug_bitmask; |
55 | int vac_cache_size; | 55 | int vac_cache_size; |
56 | int vac_line_size; | 56 | int vac_line_size; |
57 | 57 | ||
58 | struct ctx_list *ctx_list_pool; | ||
59 | struct ctx_list ctx_free; | ||
60 | struct ctx_list ctx_used; | ||
61 | |||
58 | extern struct resource sparc_iomap; | 62 | extern struct resource sparc_iomap; |
59 | 63 | ||
60 | extern unsigned long last_valid_pfn; | 64 | extern unsigned long last_valid_pfn; |
61 | 65 | ||
62 | extern unsigned long page_kernel; | ||
63 | |||
64 | static pgd_t *srmmu_swapper_pg_dir; | 66 | static pgd_t *srmmu_swapper_pg_dir; |
65 | 67 | ||
68 | const struct sparc32_cachetlb_ops *sparc32_cachetlb_ops; | ||
69 | |||
66 | #ifdef CONFIG_SMP | 70 | #ifdef CONFIG_SMP |
71 | const struct sparc32_cachetlb_ops *local_ops; | ||
72 | |||
67 | #define FLUSH_BEGIN(mm) | 73 | #define FLUSH_BEGIN(mm) |
68 | #define FLUSH_END | 74 | #define FLUSH_END |
69 | #else | 75 | #else |
70 | #define FLUSH_BEGIN(mm) if((mm)->context != NO_CONTEXT) { | 76 | #define FLUSH_BEGIN(mm) if ((mm)->context != NO_CONTEXT) { |
71 | #define FLUSH_END } | 77 | #define FLUSH_END } |
72 | #endif | 78 | #endif |
73 | 79 | ||
74 | BTFIXUPDEF_CALL(void, flush_page_for_dma, unsigned long) | ||
75 | #define flush_page_for_dma(page) BTFIXUP_CALL(flush_page_for_dma)(page) | ||
76 | |||
77 | int flush_page_for_dma_global = 1; | 80 | int flush_page_for_dma_global = 1; |
78 | 81 | ||
79 | #ifdef CONFIG_SMP | ||
80 | BTFIXUPDEF_CALL(void, local_flush_page_for_dma, unsigned long) | ||
81 | #define local_flush_page_for_dma(page) BTFIXUP_CALL(local_flush_page_for_dma)(page) | ||
82 | #endif | ||
83 | |||
84 | char *srmmu_name; | 82 | char *srmmu_name; |
85 | 83 | ||
86 | ctxd_t *srmmu_ctx_table_phys; | 84 | ctxd_t *srmmu_ctx_table_phys; |
@@ -91,28 +89,6 @@ static DEFINE_SPINLOCK(srmmu_context_spinlock); | |||
91 | 89 | ||
92 | static int is_hypersparc; | 90 | static int is_hypersparc; |
93 | 91 | ||
94 | /* | ||
95 | * In general all page table modifications should use the V8 atomic | ||
96 | * swap instruction. This insures the mmu and the cpu are in sync | ||
97 | * with respect to ref/mod bits in the page tables. | ||
98 | */ | ||
99 | static inline unsigned long srmmu_swap(unsigned long *addr, unsigned long value) | ||
100 | { | ||
101 | __asm__ __volatile__("swap [%2], %0" : "=&r" (value) : "0" (value), "r" (addr)); | ||
102 | return value; | ||
103 | } | ||
104 | |||
105 | static inline void srmmu_set_pte(pte_t *ptep, pte_t pteval) | ||
106 | { | ||
107 | srmmu_swap((unsigned long *)ptep, pte_val(pteval)); | ||
108 | } | ||
109 | |||
110 | /* The very generic SRMMU page table operations. */ | ||
111 | static inline int srmmu_device_memory(unsigned long x) | ||
112 | { | ||
113 | return ((x & 0xF0000000) != 0); | ||
114 | } | ||
115 | |||
116 | static int srmmu_cache_pagetables; | 92 | static int srmmu_cache_pagetables; |
117 | 93 | ||
118 | /* these will be initialized in srmmu_nocache_calcsize() */ | 94 | /* these will be initialized in srmmu_nocache_calcsize() */ |
@@ -129,145 +105,39 @@ void *srmmu_nocache_pool; | |||
129 | void *srmmu_nocache_bitmap; | 105 | void *srmmu_nocache_bitmap; |
130 | static struct bit_map srmmu_nocache_map; | 106 | static struct bit_map srmmu_nocache_map; |
131 | 107 | ||
132 | static unsigned long srmmu_pte_pfn(pte_t pte) | ||
133 | { | ||
134 | if (srmmu_device_memory(pte_val(pte))) { | ||
135 | /* Just return something that will cause | ||
136 | * pfn_valid() to return false. This makes | ||
137 | * copy_one_pte() to just directly copy to | ||
138 | * PTE over. | ||
139 | */ | ||
140 | return ~0UL; | ||
141 | } | ||
142 | return (pte_val(pte) & SRMMU_PTE_PMASK) >> (PAGE_SHIFT-4); | ||
143 | } | ||
144 | |||
145 | static struct page *srmmu_pmd_page(pmd_t pmd) | ||
146 | { | ||
147 | |||
148 | if (srmmu_device_memory(pmd_val(pmd))) | ||
149 | BUG(); | ||
150 | return pfn_to_page((pmd_val(pmd) & SRMMU_PTD_PMASK) >> (PAGE_SHIFT-4)); | ||
151 | } | ||
152 | |||
153 | static inline unsigned long srmmu_pgd_page(pgd_t pgd) | ||
154 | { return srmmu_device_memory(pgd_val(pgd))?~0:(unsigned long)__nocache_va((pgd_val(pgd) & SRMMU_PTD_PMASK) << 4); } | ||
155 | |||
156 | |||
157 | static inline int srmmu_pte_none(pte_t pte) | ||
158 | { return !(pte_val(pte) & 0xFFFFFFF); } | ||
159 | |||
160 | static inline int srmmu_pte_present(pte_t pte) | ||
161 | { return ((pte_val(pte) & SRMMU_ET_MASK) == SRMMU_ET_PTE); } | ||
162 | |||
163 | static inline void srmmu_pte_clear(pte_t *ptep) | ||
164 | { srmmu_set_pte(ptep, __pte(0)); } | ||
165 | |||
166 | static inline int srmmu_pmd_none(pmd_t pmd) | 108 | static inline int srmmu_pmd_none(pmd_t pmd) |
167 | { return !(pmd_val(pmd) & 0xFFFFFFF); } | 109 | { return !(pmd_val(pmd) & 0xFFFFFFF); } |
168 | 110 | ||
169 | static inline int srmmu_pmd_bad(pmd_t pmd) | ||
170 | { return (pmd_val(pmd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; } | ||
171 | |||
172 | static inline int srmmu_pmd_present(pmd_t pmd) | ||
173 | { return ((pmd_val(pmd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } | ||
174 | |||
175 | static inline void srmmu_pmd_clear(pmd_t *pmdp) { | ||
176 | int i; | ||
177 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) | ||
178 | srmmu_set_pte((pte_t *)&pmdp->pmdv[i], __pte(0)); | ||
179 | } | ||
180 | |||
181 | static inline int srmmu_pgd_none(pgd_t pgd) | ||
182 | { return !(pgd_val(pgd) & 0xFFFFFFF); } | ||
183 | |||
184 | static inline int srmmu_pgd_bad(pgd_t pgd) | ||
185 | { return (pgd_val(pgd) & SRMMU_ET_MASK) != SRMMU_ET_PTD; } | ||
186 | |||
187 | static inline int srmmu_pgd_present(pgd_t pgd) | ||
188 | { return ((pgd_val(pgd) & SRMMU_ET_MASK) == SRMMU_ET_PTD); } | ||
189 | |||
190 | static inline void srmmu_pgd_clear(pgd_t * pgdp) | ||
191 | { srmmu_set_pte((pte_t *)pgdp, __pte(0)); } | ||
192 | |||
193 | static inline pte_t srmmu_pte_wrprotect(pte_t pte) | ||
194 | { return __pte(pte_val(pte) & ~SRMMU_WRITE);} | ||
195 | |||
196 | static inline pte_t srmmu_pte_mkclean(pte_t pte) | ||
197 | { return __pte(pte_val(pte) & ~SRMMU_DIRTY);} | ||
198 | |||
199 | static inline pte_t srmmu_pte_mkold(pte_t pte) | ||
200 | { return __pte(pte_val(pte) & ~SRMMU_REF);} | ||
201 | |||
202 | static inline pte_t srmmu_pte_mkwrite(pte_t pte) | ||
203 | { return __pte(pte_val(pte) | SRMMU_WRITE);} | ||
204 | |||
205 | static inline pte_t srmmu_pte_mkdirty(pte_t pte) | ||
206 | { return __pte(pte_val(pte) | SRMMU_DIRTY);} | ||
207 | |||
208 | static inline pte_t srmmu_pte_mkyoung(pte_t pte) | ||
209 | { return __pte(pte_val(pte) | SRMMU_REF);} | ||
210 | |||
211 | /* | ||
212 | * Conversion functions: convert a page and protection to a page entry, | ||
213 | * and a page entry and page directory to the page they refer to. | ||
214 | */ | ||
215 | static pte_t srmmu_mk_pte(struct page *page, pgprot_t pgprot) | ||
216 | { return __pte((page_to_pfn(page) << (PAGE_SHIFT-4)) | pgprot_val(pgprot)); } | ||
217 | |||
218 | static pte_t srmmu_mk_pte_phys(unsigned long page, pgprot_t pgprot) | ||
219 | { return __pte(((page) >> 4) | pgprot_val(pgprot)); } | ||
220 | |||
221 | static pte_t srmmu_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) | ||
222 | { return __pte(((page) >> 4) | (space << 28) | pgprot_val(pgprot)); } | ||
223 | |||
224 | /* XXX should we hyper_flush_whole_icache here - Anton */ | 111 | /* XXX should we hyper_flush_whole_icache here - Anton */ |
225 | static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) | 112 | static inline void srmmu_ctxd_set(ctxd_t *ctxp, pgd_t *pgdp) |
226 | { srmmu_set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); } | 113 | { set_pte((pte_t *)ctxp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pgdp) >> 4))); } |
227 | 114 | ||
228 | static inline void srmmu_pgd_set(pgd_t * pgdp, pmd_t * pmdp) | 115 | void pmd_set(pmd_t *pmdp, pte_t *ptep) |
229 | { srmmu_set_pte((pte_t *)pgdp, (SRMMU_ET_PTD | (__nocache_pa((unsigned long) pmdp) >> 4))); } | ||
230 | |||
231 | static void srmmu_pmd_set(pmd_t *pmdp, pte_t *ptep) | ||
232 | { | 116 | { |
233 | unsigned long ptp; /* Physical address, shifted right by 4 */ | 117 | unsigned long ptp; /* Physical address, shifted right by 4 */ |
234 | int i; | 118 | int i; |
235 | 119 | ||
236 | ptp = __nocache_pa((unsigned long) ptep) >> 4; | 120 | ptp = __nocache_pa((unsigned long) ptep) >> 4; |
237 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { | 121 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { |
238 | srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); | 122 | set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); |
239 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); | 123 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); |
240 | } | 124 | } |
241 | } | 125 | } |
242 | 126 | ||
243 | static void srmmu_pmd_populate(pmd_t *pmdp, struct page *ptep) | 127 | void pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *ptep) |
244 | { | 128 | { |
245 | unsigned long ptp; /* Physical address, shifted right by 4 */ | 129 | unsigned long ptp; /* Physical address, shifted right by 4 */ |
246 | int i; | 130 | int i; |
247 | 131 | ||
248 | ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */ | 132 | ptp = page_to_pfn(ptep) << (PAGE_SHIFT-4); /* watch for overflow */ |
249 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { | 133 | for (i = 0; i < PTRS_PER_PTE/SRMMU_REAL_PTRS_PER_PTE; i++) { |
250 | srmmu_set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); | 134 | set_pte((pte_t *)&pmdp->pmdv[i], SRMMU_ET_PTD | ptp); |
251 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); | 135 | ptp += (SRMMU_REAL_PTRS_PER_PTE*sizeof(pte_t) >> 4); |
252 | } | 136 | } |
253 | } | 137 | } |
254 | 138 | ||
255 | static inline pte_t srmmu_pte_modify(pte_t pte, pgprot_t newprot) | ||
256 | { return __pte((pte_val(pte) & SRMMU_CHG_MASK) | pgprot_val(newprot)); } | ||
257 | |||
258 | /* to find an entry in a top-level page table... */ | ||
259 | static inline pgd_t *srmmu_pgd_offset(struct mm_struct * mm, unsigned long address) | ||
260 | { return mm->pgd + (address >> SRMMU_PGDIR_SHIFT); } | ||
261 | |||
262 | /* Find an entry in the second-level page table.. */ | ||
263 | static inline pmd_t *srmmu_pmd_offset(pgd_t * dir, unsigned long address) | ||
264 | { | ||
265 | return (pmd_t *) srmmu_pgd_page(*dir) + | ||
266 | ((address >> PMD_SHIFT) & (PTRS_PER_PMD - 1)); | ||
267 | } | ||
268 | |||
269 | /* Find an entry in the third-level page table.. */ | 139 | /* Find an entry in the third-level page table.. */ |
270 | static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) | 140 | pte_t *pte_offset_kernel(pmd_t * dir, unsigned long address) |
271 | { | 141 | { |
272 | void *pte; | 142 | void *pte; |
273 | 143 | ||
@@ -276,23 +146,6 @@ static inline pte_t *srmmu_pte_offset(pmd_t * dir, unsigned long address) | |||
276 | ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); | 146 | ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)); |
277 | } | 147 | } |
278 | 148 | ||
279 | static unsigned long srmmu_swp_type(swp_entry_t entry) | ||
280 | { | ||
281 | return (entry.val >> SRMMU_SWP_TYPE_SHIFT) & SRMMU_SWP_TYPE_MASK; | ||
282 | } | ||
283 | |||
284 | static unsigned long srmmu_swp_offset(swp_entry_t entry) | ||
285 | { | ||
286 | return (entry.val >> SRMMU_SWP_OFF_SHIFT) & SRMMU_SWP_OFF_MASK; | ||
287 | } | ||
288 | |||
289 | static swp_entry_t srmmu_swp_entry(unsigned long type, unsigned long offset) | ||
290 | { | ||
291 | return (swp_entry_t) { | ||
292 | (type & SRMMU_SWP_TYPE_MASK) << SRMMU_SWP_TYPE_SHIFT | ||
293 | | (offset & SRMMU_SWP_OFF_MASK) << SRMMU_SWP_OFF_SHIFT }; | ||
294 | } | ||
295 | |||
296 | /* | 149 | /* |
297 | * size: bytes to allocate in the nocache area. | 150 | * size: bytes to allocate in the nocache area. |
298 | * align: bytes, number to align at. | 151 | * align: bytes, number to align at. |
@@ -325,7 +178,7 @@ static unsigned long __srmmu_get_nocache(int size, int align) | |||
325 | return (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); | 178 | return (SRMMU_NOCACHE_VADDR + (offset << SRMMU_NOCACHE_BITMAP_SHIFT)); |
326 | } | 179 | } |
327 | 180 | ||
328 | static unsigned long srmmu_get_nocache(int size, int align) | 181 | unsigned long srmmu_get_nocache(int size, int align) |
329 | { | 182 | { |
330 | unsigned long tmp; | 183 | unsigned long tmp; |
331 | 184 | ||
@@ -337,7 +190,7 @@ static unsigned long srmmu_get_nocache(int size, int align) | |||
337 | return tmp; | 190 | return tmp; |
338 | } | 191 | } |
339 | 192 | ||
340 | static void srmmu_free_nocache(unsigned long vaddr, int size) | 193 | void srmmu_free_nocache(unsigned long vaddr, int size) |
341 | { | 194 | { |
342 | int offset; | 195 | int offset; |
343 | 196 | ||
@@ -429,15 +282,15 @@ static void __init srmmu_nocache_init(void) | |||
429 | 282 | ||
430 | while (vaddr < srmmu_nocache_end) { | 283 | while (vaddr < srmmu_nocache_end) { |
431 | pgd = pgd_offset_k(vaddr); | 284 | pgd = pgd_offset_k(vaddr); |
432 | pmd = srmmu_pmd_offset(__nocache_fix(pgd), vaddr); | 285 | pmd = pmd_offset(__nocache_fix(pgd), vaddr); |
433 | pte = srmmu_pte_offset(__nocache_fix(pmd), vaddr); | 286 | pte = pte_offset_kernel(__nocache_fix(pmd), vaddr); |
434 | 287 | ||
435 | pteval = ((paddr >> 4) | SRMMU_ET_PTE | SRMMU_PRIV); | 288 | pteval = ((paddr >> 4) | SRMMU_ET_PTE | SRMMU_PRIV); |
436 | 289 | ||
437 | if (srmmu_cache_pagetables) | 290 | if (srmmu_cache_pagetables) |
438 | pteval |= SRMMU_CACHE; | 291 | pteval |= SRMMU_CACHE; |
439 | 292 | ||
440 | srmmu_set_pte(__nocache_fix(pte), __pte(pteval)); | 293 | set_pte(__nocache_fix(pte), __pte(pteval)); |
441 | 294 | ||
442 | vaddr += PAGE_SIZE; | 295 | vaddr += PAGE_SIZE; |
443 | paddr += PAGE_SIZE; | 296 | paddr += PAGE_SIZE; |
@@ -447,7 +300,7 @@ static void __init srmmu_nocache_init(void) | |||
447 | flush_tlb_all(); | 300 | flush_tlb_all(); |
448 | } | 301 | } |
449 | 302 | ||
450 | static inline pgd_t *srmmu_get_pgd_fast(void) | 303 | pgd_t *get_pgd_fast(void) |
451 | { | 304 | { |
452 | pgd_t *pgd = NULL; | 305 | pgd_t *pgd = NULL; |
453 | 306 | ||
@@ -462,21 +315,6 @@ static inline pgd_t *srmmu_get_pgd_fast(void) | |||
462 | return pgd; | 315 | return pgd; |
463 | } | 316 | } |
464 | 317 | ||
465 | static void srmmu_free_pgd_fast(pgd_t *pgd) | ||
466 | { | ||
467 | srmmu_free_nocache((unsigned long)pgd, SRMMU_PGD_TABLE_SIZE); | ||
468 | } | ||
469 | |||
470 | static pmd_t *srmmu_pmd_alloc_one(struct mm_struct *mm, unsigned long address) | ||
471 | { | ||
472 | return (pmd_t *)srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); | ||
473 | } | ||
474 | |||
475 | static void srmmu_pmd_free(pmd_t * pmd) | ||
476 | { | ||
477 | srmmu_free_nocache((unsigned long)pmd, SRMMU_PMD_TABLE_SIZE); | ||
478 | } | ||
479 | |||
480 | /* | 318 | /* |
481 | * Hardware needs alignment to 256 only, but we align to whole page size | 319 | * Hardware needs alignment to 256 only, but we align to whole page size |
482 | * to reduce fragmentation problems due to the buddy principle. | 320 | * to reduce fragmentation problems due to the buddy principle. |
@@ -485,31 +323,19 @@ static void srmmu_pmd_free(pmd_t * pmd) | |||
485 | * Alignments up to the page size are the same for physical and virtual | 323 | * Alignments up to the page size are the same for physical and virtual |
486 | * addresses of the nocache area. | 324 | * addresses of the nocache area. |
487 | */ | 325 | */ |
488 | static pte_t * | 326 | pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address) |
489 | srmmu_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
490 | { | ||
491 | return (pte_t *)srmmu_get_nocache(PTE_SIZE, PTE_SIZE); | ||
492 | } | ||
493 | |||
494 | static pgtable_t | ||
495 | srmmu_pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
496 | { | 327 | { |
497 | unsigned long pte; | 328 | unsigned long pte; |
498 | struct page *page; | 329 | struct page *page; |
499 | 330 | ||
500 | if ((pte = (unsigned long)srmmu_pte_alloc_one_kernel(mm, address)) == 0) | 331 | if ((pte = (unsigned long)pte_alloc_one_kernel(mm, address)) == 0) |
501 | return NULL; | 332 | return NULL; |
502 | page = pfn_to_page( __nocache_pa(pte) >> PAGE_SHIFT ); | 333 | page = pfn_to_page( __nocache_pa(pte) >> PAGE_SHIFT ); |
503 | pgtable_page_ctor(page); | 334 | pgtable_page_ctor(page); |
504 | return page; | 335 | return page; |
505 | } | 336 | } |
506 | 337 | ||
507 | static void srmmu_free_pte_fast(pte_t *pte) | 338 | void pte_free(struct mm_struct *mm, pgtable_t pte) |
508 | { | ||
509 | srmmu_free_nocache((unsigned long)pte, PTE_SIZE); | ||
510 | } | ||
511 | |||
512 | static void srmmu_pte_free(pgtable_t pte) | ||
513 | { | 339 | { |
514 | unsigned long p; | 340 | unsigned long p; |
515 | 341 | ||
@@ -560,8 +386,8 @@ static inline void free_context(int context) | |||
560 | } | 386 | } |
561 | 387 | ||
562 | 388 | ||
563 | static void srmmu_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, | 389 | void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, |
564 | struct task_struct *tsk, int cpu) | 390 | struct task_struct *tsk) |
565 | { | 391 | { |
566 | if(mm->context == NO_CONTEXT) { | 392 | if(mm->context == NO_CONTEXT) { |
567 | spin_lock(&srmmu_context_spinlock); | 393 | spin_lock(&srmmu_context_spinlock); |
@@ -590,8 +416,8 @@ static inline void srmmu_mapioaddr(unsigned long physaddr, | |||
590 | 416 | ||
591 | physaddr &= PAGE_MASK; | 417 | physaddr &= PAGE_MASK; |
592 | pgdp = pgd_offset_k(virt_addr); | 418 | pgdp = pgd_offset_k(virt_addr); |
593 | pmdp = srmmu_pmd_offset(pgdp, virt_addr); | 419 | pmdp = pmd_offset(pgdp, virt_addr); |
594 | ptep = srmmu_pte_offset(pmdp, virt_addr); | 420 | ptep = pte_offset_kernel(pmdp, virt_addr); |
595 | tmp = (physaddr >> 4) | SRMMU_ET_PTE; | 421 | tmp = (physaddr >> 4) | SRMMU_ET_PTE; |
596 | 422 | ||
597 | /* | 423 | /* |
@@ -602,11 +428,11 @@ static inline void srmmu_mapioaddr(unsigned long physaddr, | |||
602 | tmp |= (bus_type << 28); | 428 | tmp |= (bus_type << 28); |
603 | tmp |= SRMMU_PRIV; | 429 | tmp |= SRMMU_PRIV; |
604 | __flush_page_to_ram(virt_addr); | 430 | __flush_page_to_ram(virt_addr); |
605 | srmmu_set_pte(ptep, __pte(tmp)); | 431 | set_pte(ptep, __pte(tmp)); |
606 | } | 432 | } |
607 | 433 | ||
608 | static void srmmu_mapiorange(unsigned int bus, unsigned long xpa, | 434 | void srmmu_mapiorange(unsigned int bus, unsigned long xpa, |
609 | unsigned long xva, unsigned int len) | 435 | unsigned long xva, unsigned int len) |
610 | { | 436 | { |
611 | while (len != 0) { | 437 | while (len != 0) { |
612 | len -= PAGE_SIZE; | 438 | len -= PAGE_SIZE; |
@@ -624,14 +450,14 @@ static inline void srmmu_unmapioaddr(unsigned long virt_addr) | |||
624 | pte_t *ptep; | 450 | pte_t *ptep; |
625 | 451 | ||
626 | pgdp = pgd_offset_k(virt_addr); | 452 | pgdp = pgd_offset_k(virt_addr); |
627 | pmdp = srmmu_pmd_offset(pgdp, virt_addr); | 453 | pmdp = pmd_offset(pgdp, virt_addr); |
628 | ptep = srmmu_pte_offset(pmdp, virt_addr); | 454 | ptep = pte_offset_kernel(pmdp, virt_addr); |
629 | 455 | ||
630 | /* No need to flush uncacheable page. */ | 456 | /* No need to flush uncacheable page. */ |
631 | srmmu_pte_clear(ptep); | 457 | __pte_clear(ptep); |
632 | } | 458 | } |
633 | 459 | ||
634 | static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len) | 460 | void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len) |
635 | { | 461 | { |
636 | while (len != 0) { | 462 | while (len != 0) { |
637 | len -= PAGE_SIZE; | 463 | len -= PAGE_SIZE; |
@@ -647,10 +473,9 @@ static void srmmu_unmapiorange(unsigned long virt_addr, unsigned int len) | |||
647 | * pool. As a side effect we are putting a little too much pressure | 473 | * pool. As a side effect we are putting a little too much pressure |
648 | * on the gfp() subsystem. This setup also makes the logic of the | 474 | * on the gfp() subsystem. This setup also makes the logic of the |
649 | * iommu mapping code a lot easier as we can transparently handle | 475 | * iommu mapping code a lot easier as we can transparently handle |
650 | * mappings on the kernel stack without any special code as we did | 476 | * mappings on the kernel stack without any special code. |
651 | * need on the sun4c. | ||
652 | */ | 477 | */ |
653 | static struct thread_info *srmmu_alloc_thread_info_node(int node) | 478 | struct thread_info *alloc_thread_info_node(struct task_struct *tsk, int node) |
654 | { | 479 | { |
655 | struct thread_info *ret; | 480 | struct thread_info *ret; |
656 | 481 | ||
@@ -664,7 +489,7 @@ static struct thread_info *srmmu_alloc_thread_info_node(int node) | |||
664 | return ret; | 489 | return ret; |
665 | } | 490 | } |
666 | 491 | ||
667 | static void srmmu_free_thread_info(struct thread_info *ti) | 492 | void free_thread_info(struct thread_info *ti) |
668 | { | 493 | { |
669 | free_pages((unsigned long)ti, THREAD_INFO_ORDER); | 494 | free_pages((unsigned long)ti, THREAD_INFO_ORDER); |
670 | } | 495 | } |
@@ -683,38 +508,6 @@ extern void tsunami_flush_tlb_range(struct vm_area_struct *vma, unsigned long st | |||
683 | extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); | 508 | extern void tsunami_flush_tlb_page(struct vm_area_struct *vma, unsigned long page); |
684 | extern void tsunami_setup_blockops(void); | 509 | extern void tsunami_setup_blockops(void); |
685 | 510 | ||
686 | /* | ||
687 | * Workaround, until we find what's going on with Swift. When low on memory, | ||
688 | * it sometimes loops in fault/handle_mm_fault incl. flush_tlb_page to find | ||
689 | * out it is already in page tables/ fault again on the same instruction. | ||
690 | * I really don't understand it, have checked it and contexts | ||
691 | * are right, flush_tlb_all is done as well, and it faults again... | ||
692 | * Strange. -jj | ||
693 | * | ||
694 | * The following code is a deadwood that may be necessary when | ||
695 | * we start to make precise page flushes again. --zaitcev | ||
696 | */ | ||
697 | static void swift_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t *ptep) | ||
698 | { | ||
699 | #if 0 | ||
700 | static unsigned long last; | ||
701 | unsigned int val; | ||
702 | /* unsigned int n; */ | ||
703 | |||
704 | if (address == last) { | ||
705 | val = srmmu_hwprobe(address); | ||
706 | if (val != 0 && pte_val(*ptep) != val) { | ||
707 | printk("swift_update_mmu_cache: " | ||
708 | "addr %lx put %08x probed %08x from %p\n", | ||
709 | address, pte_val(*ptep), val, | ||
710 | __builtin_return_address(0)); | ||
711 | srmmu_flush_whole_tlb(); | ||
712 | } | ||
713 | } | ||
714 | last = address; | ||
715 | #endif | ||
716 | } | ||
717 | |||
718 | /* swift.S */ | 511 | /* swift.S */ |
719 | extern void swift_flush_cache_all(void); | 512 | extern void swift_flush_cache_all(void); |
720 | extern void swift_flush_cache_mm(struct mm_struct *mm); | 513 | extern void swift_flush_cache_mm(struct mm_struct *mm); |
@@ -767,244 +560,6 @@ void swift_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | |||
767 | * with respect to cache coherency. | 560 | * with respect to cache coherency. |
768 | */ | 561 | */ |
769 | 562 | ||
770 | /* Cypress flushes. */ | ||
771 | static void cypress_flush_cache_all(void) | ||
772 | { | ||
773 | volatile unsigned long cypress_sucks; | ||
774 | unsigned long faddr, tagval; | ||
775 | |||
776 | flush_user_windows(); | ||
777 | for(faddr = 0; faddr < 0x10000; faddr += 0x20) { | ||
778 | __asm__ __volatile__("lda [%1 + %2] %3, %0\n\t" : | ||
779 | "=r" (tagval) : | ||
780 | "r" (faddr), "r" (0x40000), | ||
781 | "i" (ASI_M_DATAC_TAG)); | ||
782 | |||
783 | /* If modified and valid, kick it. */ | ||
784 | if((tagval & 0x60) == 0x60) | ||
785 | cypress_sucks = *(unsigned long *)(0xf0020000 + faddr); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static void cypress_flush_cache_mm(struct mm_struct *mm) | ||
790 | { | ||
791 | register unsigned long a, b, c, d, e, f, g; | ||
792 | unsigned long flags, faddr; | ||
793 | int octx; | ||
794 | |||
795 | FLUSH_BEGIN(mm) | ||
796 | flush_user_windows(); | ||
797 | local_irq_save(flags); | ||
798 | octx = srmmu_get_context(); | ||
799 | srmmu_set_context(mm->context); | ||
800 | a = 0x20; b = 0x40; c = 0x60; | ||
801 | d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; | ||
802 | |||
803 | faddr = (0x10000 - 0x100); | ||
804 | goto inside; | ||
805 | do { | ||
806 | faddr -= 0x100; | ||
807 | inside: | ||
808 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" | ||
809 | "sta %%g0, [%0 + %2] %1\n\t" | ||
810 | "sta %%g0, [%0 + %3] %1\n\t" | ||
811 | "sta %%g0, [%0 + %4] %1\n\t" | ||
812 | "sta %%g0, [%0 + %5] %1\n\t" | ||
813 | "sta %%g0, [%0 + %6] %1\n\t" | ||
814 | "sta %%g0, [%0 + %7] %1\n\t" | ||
815 | "sta %%g0, [%0 + %8] %1\n\t" : : | ||
816 | "r" (faddr), "i" (ASI_M_FLUSH_CTX), | ||
817 | "r" (a), "r" (b), "r" (c), "r" (d), | ||
818 | "r" (e), "r" (f), "r" (g)); | ||
819 | } while(faddr); | ||
820 | srmmu_set_context(octx); | ||
821 | local_irq_restore(flags); | ||
822 | FLUSH_END | ||
823 | } | ||
824 | |||
825 | static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) | ||
826 | { | ||
827 | struct mm_struct *mm = vma->vm_mm; | ||
828 | register unsigned long a, b, c, d, e, f, g; | ||
829 | unsigned long flags, faddr; | ||
830 | int octx; | ||
831 | |||
832 | FLUSH_BEGIN(mm) | ||
833 | flush_user_windows(); | ||
834 | local_irq_save(flags); | ||
835 | octx = srmmu_get_context(); | ||
836 | srmmu_set_context(mm->context); | ||
837 | a = 0x20; b = 0x40; c = 0x60; | ||
838 | d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; | ||
839 | |||
840 | start &= SRMMU_REAL_PMD_MASK; | ||
841 | while(start < end) { | ||
842 | faddr = (start + (0x10000 - 0x100)); | ||
843 | goto inside; | ||
844 | do { | ||
845 | faddr -= 0x100; | ||
846 | inside: | ||
847 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" | ||
848 | "sta %%g0, [%0 + %2] %1\n\t" | ||
849 | "sta %%g0, [%0 + %3] %1\n\t" | ||
850 | "sta %%g0, [%0 + %4] %1\n\t" | ||
851 | "sta %%g0, [%0 + %5] %1\n\t" | ||
852 | "sta %%g0, [%0 + %6] %1\n\t" | ||
853 | "sta %%g0, [%0 + %7] %1\n\t" | ||
854 | "sta %%g0, [%0 + %8] %1\n\t" : : | ||
855 | "r" (faddr), | ||
856 | "i" (ASI_M_FLUSH_SEG), | ||
857 | "r" (a), "r" (b), "r" (c), "r" (d), | ||
858 | "r" (e), "r" (f), "r" (g)); | ||
859 | } while (faddr != start); | ||
860 | start += SRMMU_REAL_PMD_SIZE; | ||
861 | } | ||
862 | srmmu_set_context(octx); | ||
863 | local_irq_restore(flags); | ||
864 | FLUSH_END | ||
865 | } | ||
866 | |||
867 | static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long page) | ||
868 | { | ||
869 | register unsigned long a, b, c, d, e, f, g; | ||
870 | struct mm_struct *mm = vma->vm_mm; | ||
871 | unsigned long flags, line; | ||
872 | int octx; | ||
873 | |||
874 | FLUSH_BEGIN(mm) | ||
875 | flush_user_windows(); | ||
876 | local_irq_save(flags); | ||
877 | octx = srmmu_get_context(); | ||
878 | srmmu_set_context(mm->context); | ||
879 | a = 0x20; b = 0x40; c = 0x60; | ||
880 | d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; | ||
881 | |||
882 | page &= PAGE_MASK; | ||
883 | line = (page + PAGE_SIZE) - 0x100; | ||
884 | goto inside; | ||
885 | do { | ||
886 | line -= 0x100; | ||
887 | inside: | ||
888 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" | ||
889 | "sta %%g0, [%0 + %2] %1\n\t" | ||
890 | "sta %%g0, [%0 + %3] %1\n\t" | ||
891 | "sta %%g0, [%0 + %4] %1\n\t" | ||
892 | "sta %%g0, [%0 + %5] %1\n\t" | ||
893 | "sta %%g0, [%0 + %6] %1\n\t" | ||
894 | "sta %%g0, [%0 + %7] %1\n\t" | ||
895 | "sta %%g0, [%0 + %8] %1\n\t" : : | ||
896 | "r" (line), | ||
897 | "i" (ASI_M_FLUSH_PAGE), | ||
898 | "r" (a), "r" (b), "r" (c), "r" (d), | ||
899 | "r" (e), "r" (f), "r" (g)); | ||
900 | } while(line != page); | ||
901 | srmmu_set_context(octx); | ||
902 | local_irq_restore(flags); | ||
903 | FLUSH_END | ||
904 | } | ||
905 | |||
906 | /* Cypress is copy-back, at least that is how we configure it. */ | ||
907 | static void cypress_flush_page_to_ram(unsigned long page) | ||
908 | { | ||
909 | register unsigned long a, b, c, d, e, f, g; | ||
910 | unsigned long line; | ||
911 | |||
912 | a = 0x20; b = 0x40; c = 0x60; d = 0x80; e = 0xa0; f = 0xc0; g = 0xe0; | ||
913 | page &= PAGE_MASK; | ||
914 | line = (page + PAGE_SIZE) - 0x100; | ||
915 | goto inside; | ||
916 | do { | ||
917 | line -= 0x100; | ||
918 | inside: | ||
919 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" | ||
920 | "sta %%g0, [%0 + %2] %1\n\t" | ||
921 | "sta %%g0, [%0 + %3] %1\n\t" | ||
922 | "sta %%g0, [%0 + %4] %1\n\t" | ||
923 | "sta %%g0, [%0 + %5] %1\n\t" | ||
924 | "sta %%g0, [%0 + %6] %1\n\t" | ||
925 | "sta %%g0, [%0 + %7] %1\n\t" | ||
926 | "sta %%g0, [%0 + %8] %1\n\t" : : | ||
927 | "r" (line), | ||
928 | "i" (ASI_M_FLUSH_PAGE), | ||
929 | "r" (a), "r" (b), "r" (c), "r" (d), | ||
930 | "r" (e), "r" (f), "r" (g)); | ||
931 | } while(line != page); | ||
932 | } | ||
933 | |||
934 | /* Cypress is also IO cache coherent. */ | ||
935 | static void cypress_flush_page_for_dma(unsigned long page) | ||
936 | { | ||
937 | } | ||
938 | |||
939 | /* Cypress has unified L2 VIPT, from which both instructions and data | ||
940 | * are stored. It does not have an onboard icache of any sort, therefore | ||
941 | * no flush is necessary. | ||
942 | */ | ||
943 | static void cypress_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) | ||
944 | { | ||
945 | } | ||
946 | |||
947 | static void cypress_flush_tlb_all(void) | ||
948 | { | ||
949 | srmmu_flush_whole_tlb(); | ||
950 | } | ||
951 | |||
952 | static void cypress_flush_tlb_mm(struct mm_struct *mm) | ||
953 | { | ||
954 | FLUSH_BEGIN(mm) | ||
955 | __asm__ __volatile__( | ||
956 | "lda [%0] %3, %%g5\n\t" | ||
957 | "sta %2, [%0] %3\n\t" | ||
958 | "sta %%g0, [%1] %4\n\t" | ||
959 | "sta %%g5, [%0] %3\n" | ||
960 | : /* no outputs */ | ||
961 | : "r" (SRMMU_CTX_REG), "r" (0x300), "r" (mm->context), | ||
962 | "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) | ||
963 | : "g5"); | ||
964 | FLUSH_END | ||
965 | } | ||
966 | |||
967 | static void cypress_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) | ||
968 | { | ||
969 | struct mm_struct *mm = vma->vm_mm; | ||
970 | unsigned long size; | ||
971 | |||
972 | FLUSH_BEGIN(mm) | ||
973 | start &= SRMMU_PGDIR_MASK; | ||
974 | size = SRMMU_PGDIR_ALIGN(end) - start; | ||
975 | __asm__ __volatile__( | ||
976 | "lda [%0] %5, %%g5\n\t" | ||
977 | "sta %1, [%0] %5\n" | ||
978 | "1:\n\t" | ||
979 | "subcc %3, %4, %3\n\t" | ||
980 | "bne 1b\n\t" | ||
981 | " sta %%g0, [%2 + %3] %6\n\t" | ||
982 | "sta %%g5, [%0] %5\n" | ||
983 | : /* no outputs */ | ||
984 | : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (start | 0x200), | ||
985 | "r" (size), "r" (SRMMU_PGDIR_SIZE), "i" (ASI_M_MMUREGS), | ||
986 | "i" (ASI_M_FLUSH_PROBE) | ||
987 | : "g5", "cc"); | ||
988 | FLUSH_END | ||
989 | } | ||
990 | |||
991 | static void cypress_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | ||
992 | { | ||
993 | struct mm_struct *mm = vma->vm_mm; | ||
994 | |||
995 | FLUSH_BEGIN(mm) | ||
996 | __asm__ __volatile__( | ||
997 | "lda [%0] %3, %%g5\n\t" | ||
998 | "sta %1, [%0] %3\n\t" | ||
999 | "sta %%g0, [%2] %4\n\t" | ||
1000 | "sta %%g5, [%0] %3\n" | ||
1001 | : /* no outputs */ | ||
1002 | : "r" (SRMMU_CTX_REG), "r" (mm->context), "r" (page & PAGE_MASK), | ||
1003 | "i" (ASI_M_MMUREGS), "i" (ASI_M_FLUSH_PROBE) | ||
1004 | : "g5"); | ||
1005 | FLUSH_END | ||
1006 | } | ||
1007 | |||
1008 | /* viking.S */ | 563 | /* viking.S */ |
1009 | extern void viking_flush_cache_all(void); | 564 | extern void viking_flush_cache_all(void); |
1010 | extern void viking_flush_cache_mm(struct mm_struct *mm); | 565 | extern void viking_flush_cache_mm(struct mm_struct *mm); |
@@ -1065,21 +620,21 @@ static void __init srmmu_early_allocate_ptable_skeleton(unsigned long start, | |||
1065 | 620 | ||
1066 | while(start < end) { | 621 | while(start < end) { |
1067 | pgdp = pgd_offset_k(start); | 622 | pgdp = pgd_offset_k(start); |
1068 | if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { | 623 | if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { |
1069 | pmdp = (pmd_t *) __srmmu_get_nocache( | 624 | pmdp = (pmd_t *) __srmmu_get_nocache( |
1070 | SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); | 625 | SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); |
1071 | if (pmdp == NULL) | 626 | if (pmdp == NULL) |
1072 | early_pgtable_allocfail("pmd"); | 627 | early_pgtable_allocfail("pmd"); |
1073 | memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); | 628 | memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); |
1074 | srmmu_pgd_set(__nocache_fix(pgdp), pmdp); | 629 | pgd_set(__nocache_fix(pgdp), pmdp); |
1075 | } | 630 | } |
1076 | pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); | 631 | pmdp = pmd_offset(__nocache_fix(pgdp), start); |
1077 | if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { | 632 | if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { |
1078 | ptep = (pte_t *)__srmmu_get_nocache(PTE_SIZE, PTE_SIZE); | 633 | ptep = (pte_t *)__srmmu_get_nocache(PTE_SIZE, PTE_SIZE); |
1079 | if (ptep == NULL) | 634 | if (ptep == NULL) |
1080 | early_pgtable_allocfail("pte"); | 635 | early_pgtable_allocfail("pte"); |
1081 | memset(__nocache_fix(ptep), 0, PTE_SIZE); | 636 | memset(__nocache_fix(ptep), 0, PTE_SIZE); |
1082 | srmmu_pmd_set(__nocache_fix(pmdp), ptep); | 637 | pmd_set(__nocache_fix(pmdp), ptep); |
1083 | } | 638 | } |
1084 | if (start > (0xffffffffUL - PMD_SIZE)) | 639 | if (start > (0xffffffffUL - PMD_SIZE)) |
1085 | break; | 640 | break; |
@@ -1096,21 +651,21 @@ static void __init srmmu_allocate_ptable_skeleton(unsigned long start, | |||
1096 | 651 | ||
1097 | while(start < end) { | 652 | while(start < end) { |
1098 | pgdp = pgd_offset_k(start); | 653 | pgdp = pgd_offset_k(start); |
1099 | if(srmmu_pgd_none(*pgdp)) { | 654 | if (pgd_none(*pgdp)) { |
1100 | pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); | 655 | pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); |
1101 | if (pmdp == NULL) | 656 | if (pmdp == NULL) |
1102 | early_pgtable_allocfail("pmd"); | 657 | early_pgtable_allocfail("pmd"); |
1103 | memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); | 658 | memset(pmdp, 0, SRMMU_PMD_TABLE_SIZE); |
1104 | srmmu_pgd_set(pgdp, pmdp); | 659 | pgd_set(pgdp, pmdp); |
1105 | } | 660 | } |
1106 | pmdp = srmmu_pmd_offset(pgdp, start); | 661 | pmdp = pmd_offset(pgdp, start); |
1107 | if(srmmu_pmd_none(*pmdp)) { | 662 | if(srmmu_pmd_none(*pmdp)) { |
1108 | ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, | 663 | ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, |
1109 | PTE_SIZE); | 664 | PTE_SIZE); |
1110 | if (ptep == NULL) | 665 | if (ptep == NULL) |
1111 | early_pgtable_allocfail("pte"); | 666 | early_pgtable_allocfail("pte"); |
1112 | memset(ptep, 0, PTE_SIZE); | 667 | memset(ptep, 0, PTE_SIZE); |
1113 | srmmu_pmd_set(pmdp, ptep); | 668 | pmd_set(pmdp, ptep); |
1114 | } | 669 | } |
1115 | if (start > (0xffffffffUL - PMD_SIZE)) | 670 | if (start > (0xffffffffUL - PMD_SIZE)) |
1116 | break; | 671 | break; |
@@ -1162,21 +717,21 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start, | |||
1162 | start += SRMMU_PGDIR_SIZE; | 717 | start += SRMMU_PGDIR_SIZE; |
1163 | continue; | 718 | continue; |
1164 | } | 719 | } |
1165 | if(srmmu_pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { | 720 | if (pgd_none(*(pgd_t *)__nocache_fix(pgdp))) { |
1166 | pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); | 721 | pmdp = (pmd_t *)__srmmu_get_nocache(SRMMU_PMD_TABLE_SIZE, SRMMU_PMD_TABLE_SIZE); |
1167 | if (pmdp == NULL) | 722 | if (pmdp == NULL) |
1168 | early_pgtable_allocfail("pmd"); | 723 | early_pgtable_allocfail("pmd"); |
1169 | memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); | 724 | memset(__nocache_fix(pmdp), 0, SRMMU_PMD_TABLE_SIZE); |
1170 | srmmu_pgd_set(__nocache_fix(pgdp), pmdp); | 725 | pgd_set(__nocache_fix(pgdp), pmdp); |
1171 | } | 726 | } |
1172 | pmdp = srmmu_pmd_offset(__nocache_fix(pgdp), start); | 727 | pmdp = pmd_offset(__nocache_fix(pgdp), start); |
1173 | if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { | 728 | if(srmmu_pmd_none(*(pmd_t *)__nocache_fix(pmdp))) { |
1174 | ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, | 729 | ptep = (pte_t *) __srmmu_get_nocache(PTE_SIZE, |
1175 | PTE_SIZE); | 730 | PTE_SIZE); |
1176 | if (ptep == NULL) | 731 | if (ptep == NULL) |
1177 | early_pgtable_allocfail("pte"); | 732 | early_pgtable_allocfail("pte"); |
1178 | memset(__nocache_fix(ptep), 0, PTE_SIZE); | 733 | memset(__nocache_fix(ptep), 0, PTE_SIZE); |
1179 | srmmu_pmd_set(__nocache_fix(pmdp), ptep); | 734 | pmd_set(__nocache_fix(pmdp), ptep); |
1180 | } | 735 | } |
1181 | if(what == 1) { | 736 | if(what == 1) { |
1182 | /* | 737 | /* |
@@ -1190,7 +745,7 @@ static void __init srmmu_inherit_prom_mappings(unsigned long start, | |||
1190 | start += SRMMU_REAL_PMD_SIZE; | 745 | start += SRMMU_REAL_PMD_SIZE; |
1191 | continue; | 746 | continue; |
1192 | } | 747 | } |
1193 | ptep = srmmu_pte_offset(__nocache_fix(pmdp), start); | 748 | ptep = pte_offset_kernel(__nocache_fix(pmdp), start); |
1194 | *(pte_t *)__nocache_fix(ptep) = __pte(prompte); | 749 | *(pte_t *)__nocache_fix(ptep) = __pte(prompte); |
1195 | start += PAGE_SIZE; | 750 | start += PAGE_SIZE; |
1196 | } | 751 | } |
@@ -1231,13 +786,6 @@ static unsigned long __init map_spbank(unsigned long vbase, int sp_entry) | |||
1231 | return vstart; | 786 | return vstart; |
1232 | } | 787 | } |
1233 | 788 | ||
1234 | static inline void memprobe_error(char *msg) | ||
1235 | { | ||
1236 | prom_printf(msg); | ||
1237 | prom_printf("Halting now...\n"); | ||
1238 | prom_halt(); | ||
1239 | } | ||
1240 | |||
1241 | static inline void map_kernel(void) | 789 | static inline void map_kernel(void) |
1242 | { | 790 | { |
1243 | int i; | 791 | int i; |
@@ -1249,8 +797,6 @@ static inline void map_kernel(void) | |||
1249 | for (i = 0; sp_banks[i].num_bytes != 0; i++) { | 797 | for (i = 0; sp_banks[i].num_bytes != 0; i++) { |
1250 | map_spbank((unsigned long)__va(sp_banks[i].base_addr), i); | 798 | map_spbank((unsigned long)__va(sp_banks[i].base_addr), i); |
1251 | } | 799 | } |
1252 | |||
1253 | BTFIXUPSET_SIMM13(user_ptrs_per_pgd, PAGE_OFFSET / SRMMU_PGDIR_SIZE); | ||
1254 | } | 800 | } |
1255 | 801 | ||
1256 | /* Paging initialization on the Sparc Reference MMU. */ | 802 | /* Paging initialization on the Sparc Reference MMU. */ |
@@ -1312,7 +858,7 @@ void __init srmmu_paging_init(void) | |||
1312 | srmmu_set_ctable_ptr((unsigned long)srmmu_ctx_table_phys); | 858 | srmmu_set_ctable_ptr((unsigned long)srmmu_ctx_table_phys); |
1313 | #ifdef CONFIG_SMP | 859 | #ifdef CONFIG_SMP |
1314 | /* Stop from hanging here... */ | 860 | /* Stop from hanging here... */ |
1315 | local_flush_tlb_all(); | 861 | local_ops->tlb_all(); |
1316 | #else | 862 | #else |
1317 | flush_tlb_all(); | 863 | flush_tlb_all(); |
1318 | #endif | 864 | #endif |
@@ -1326,8 +872,8 @@ void __init srmmu_paging_init(void) | |||
1326 | srmmu_allocate_ptable_skeleton(PKMAP_BASE, PKMAP_END); | 872 | srmmu_allocate_ptable_skeleton(PKMAP_BASE, PKMAP_END); |
1327 | 873 | ||
1328 | pgd = pgd_offset_k(PKMAP_BASE); | 874 | pgd = pgd_offset_k(PKMAP_BASE); |
1329 | pmd = srmmu_pmd_offset(pgd, PKMAP_BASE); | 875 | pmd = pmd_offset(pgd, PKMAP_BASE); |
1330 | pte = srmmu_pte_offset(pmd, PKMAP_BASE); | 876 | pte = pte_offset_kernel(pmd, PKMAP_BASE); |
1331 | pkmap_page_table = pte; | 877 | pkmap_page_table = pte; |
1332 | 878 | ||
1333 | flush_cache_all(); | 879 | flush_cache_all(); |
@@ -1359,7 +905,7 @@ void __init srmmu_paging_init(void) | |||
1359 | } | 905 | } |
1360 | } | 906 | } |
1361 | 907 | ||
1362 | static void srmmu_mmu_info(struct seq_file *m) | 908 | void mmu_info(struct seq_file *m) |
1363 | { | 909 | { |
1364 | seq_printf(m, | 910 | seq_printf(m, |
1365 | "MMU type\t: %s\n" | 911 | "MMU type\t: %s\n" |
@@ -1372,11 +918,7 @@ static void srmmu_mmu_info(struct seq_file *m) | |||
1372 | srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); | 918 | srmmu_nocache_map.used << SRMMU_NOCACHE_BITMAP_SHIFT); |
1373 | } | 919 | } |
1374 | 920 | ||
1375 | static void srmmu_update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte) | 921 | void destroy_context(struct mm_struct *mm) |
1376 | { | ||
1377 | } | ||
1378 | |||
1379 | static void srmmu_destroy_context(struct mm_struct *mm) | ||
1380 | { | 922 | { |
1381 | 923 | ||
1382 | if(mm->context != NO_CONTEXT) { | 924 | if(mm->context != NO_CONTEXT) { |
@@ -1474,6 +1016,20 @@ static void __cpuinit poke_hypersparc(void) | |||
1474 | clear = srmmu_get_fstatus(); | 1016 | clear = srmmu_get_fstatus(); |
1475 | } | 1017 | } |
1476 | 1018 | ||
1019 | static const struct sparc32_cachetlb_ops hypersparc_ops = { | ||
1020 | .cache_all = hypersparc_flush_cache_all, | ||
1021 | .cache_mm = hypersparc_flush_cache_mm, | ||
1022 | .cache_page = hypersparc_flush_cache_page, | ||
1023 | .cache_range = hypersparc_flush_cache_range, | ||
1024 | .tlb_all = hypersparc_flush_tlb_all, | ||
1025 | .tlb_mm = hypersparc_flush_tlb_mm, | ||
1026 | .tlb_page = hypersparc_flush_tlb_page, | ||
1027 | .tlb_range = hypersparc_flush_tlb_range, | ||
1028 | .page_to_ram = hypersparc_flush_page_to_ram, | ||
1029 | .sig_insns = hypersparc_flush_sig_insns, | ||
1030 | .page_for_dma = hypersparc_flush_page_for_dma, | ||
1031 | }; | ||
1032 | |||
1477 | static void __init init_hypersparc(void) | 1033 | static void __init init_hypersparc(void) |
1478 | { | 1034 | { |
1479 | srmmu_name = "ROSS HyperSparc"; | 1035 | srmmu_name = "ROSS HyperSparc"; |
@@ -1482,118 +1038,13 @@ static void __init init_hypersparc(void) | |||
1482 | init_vac_layout(); | 1038 | init_vac_layout(); |
1483 | 1039 | ||
1484 | is_hypersparc = 1; | 1040 | is_hypersparc = 1; |
1485 | 1041 | sparc32_cachetlb_ops = &hypersparc_ops; | |
1486 | BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); | ||
1487 | BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); | ||
1488 | BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); | ||
1489 | BTFIXUPSET_CALL(flush_cache_all, hypersparc_flush_cache_all, BTFIXUPCALL_NORM); | ||
1490 | BTFIXUPSET_CALL(flush_cache_mm, hypersparc_flush_cache_mm, BTFIXUPCALL_NORM); | ||
1491 | BTFIXUPSET_CALL(flush_cache_range, hypersparc_flush_cache_range, BTFIXUPCALL_NORM); | ||
1492 | BTFIXUPSET_CALL(flush_cache_page, hypersparc_flush_cache_page, BTFIXUPCALL_NORM); | ||
1493 | |||
1494 | BTFIXUPSET_CALL(flush_tlb_all, hypersparc_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1495 | BTFIXUPSET_CALL(flush_tlb_mm, hypersparc_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1496 | BTFIXUPSET_CALL(flush_tlb_range, hypersparc_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1497 | BTFIXUPSET_CALL(flush_tlb_page, hypersparc_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1498 | |||
1499 | BTFIXUPSET_CALL(__flush_page_to_ram, hypersparc_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
1500 | BTFIXUPSET_CALL(flush_sig_insns, hypersparc_flush_sig_insns, BTFIXUPCALL_NORM); | ||
1501 | BTFIXUPSET_CALL(flush_page_for_dma, hypersparc_flush_page_for_dma, BTFIXUPCALL_NOP); | ||
1502 | |||
1503 | 1042 | ||
1504 | poke_srmmu = poke_hypersparc; | 1043 | poke_srmmu = poke_hypersparc; |
1505 | 1044 | ||
1506 | hypersparc_setup_blockops(); | 1045 | hypersparc_setup_blockops(); |
1507 | } | 1046 | } |
1508 | 1047 | ||
1509 | static void __cpuinit poke_cypress(void) | ||
1510 | { | ||
1511 | unsigned long mreg = srmmu_get_mmureg(); | ||
1512 | unsigned long faddr, tagval; | ||
1513 | volatile unsigned long cypress_sucks; | ||
1514 | volatile unsigned long clear; | ||
1515 | |||
1516 | clear = srmmu_get_faddr(); | ||
1517 | clear = srmmu_get_fstatus(); | ||
1518 | |||
1519 | if (!(mreg & CYPRESS_CENABLE)) { | ||
1520 | for(faddr = 0x0; faddr < 0x10000; faddr += 20) { | ||
1521 | __asm__ __volatile__("sta %%g0, [%0 + %1] %2\n\t" | ||
1522 | "sta %%g0, [%0] %2\n\t" : : | ||
1523 | "r" (faddr), "r" (0x40000), | ||
1524 | "i" (ASI_M_DATAC_TAG)); | ||
1525 | } | ||
1526 | } else { | ||
1527 | for(faddr = 0; faddr < 0x10000; faddr += 0x20) { | ||
1528 | __asm__ __volatile__("lda [%1 + %2] %3, %0\n\t" : | ||
1529 | "=r" (tagval) : | ||
1530 | "r" (faddr), "r" (0x40000), | ||
1531 | "i" (ASI_M_DATAC_TAG)); | ||
1532 | |||
1533 | /* If modified and valid, kick it. */ | ||
1534 | if((tagval & 0x60) == 0x60) | ||
1535 | cypress_sucks = *(unsigned long *) | ||
1536 | (0xf0020000 + faddr); | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | /* And one more, for our good neighbor, Mr. Broken Cypress. */ | ||
1541 | clear = srmmu_get_faddr(); | ||
1542 | clear = srmmu_get_fstatus(); | ||
1543 | |||
1544 | mreg |= (CYPRESS_CENABLE | CYPRESS_CMODE); | ||
1545 | srmmu_set_mmureg(mreg); | ||
1546 | } | ||
1547 | |||
1548 | static void __init init_cypress_common(void) | ||
1549 | { | ||
1550 | init_vac_layout(); | ||
1551 | |||
1552 | BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); | ||
1553 | BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); | ||
1554 | BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); | ||
1555 | BTFIXUPSET_CALL(flush_cache_all, cypress_flush_cache_all, BTFIXUPCALL_NORM); | ||
1556 | BTFIXUPSET_CALL(flush_cache_mm, cypress_flush_cache_mm, BTFIXUPCALL_NORM); | ||
1557 | BTFIXUPSET_CALL(flush_cache_range, cypress_flush_cache_range, BTFIXUPCALL_NORM); | ||
1558 | BTFIXUPSET_CALL(flush_cache_page, cypress_flush_cache_page, BTFIXUPCALL_NORM); | ||
1559 | |||
1560 | BTFIXUPSET_CALL(flush_tlb_all, cypress_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1561 | BTFIXUPSET_CALL(flush_tlb_mm, cypress_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1562 | BTFIXUPSET_CALL(flush_tlb_page, cypress_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1563 | BTFIXUPSET_CALL(flush_tlb_range, cypress_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1564 | |||
1565 | |||
1566 | BTFIXUPSET_CALL(__flush_page_to_ram, cypress_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
1567 | BTFIXUPSET_CALL(flush_sig_insns, cypress_flush_sig_insns, BTFIXUPCALL_NOP); | ||
1568 | BTFIXUPSET_CALL(flush_page_for_dma, cypress_flush_page_for_dma, BTFIXUPCALL_NOP); | ||
1569 | |||
1570 | poke_srmmu = poke_cypress; | ||
1571 | } | ||
1572 | |||
1573 | static void __init init_cypress_604(void) | ||
1574 | { | ||
1575 | srmmu_name = "ROSS Cypress-604(UP)"; | ||
1576 | srmmu_modtype = Cypress; | ||
1577 | init_cypress_common(); | ||
1578 | } | ||
1579 | |||
1580 | static void __init init_cypress_605(unsigned long mrev) | ||
1581 | { | ||
1582 | srmmu_name = "ROSS Cypress-605(MP)"; | ||
1583 | if(mrev == 0xe) { | ||
1584 | srmmu_modtype = Cypress_vE; | ||
1585 | hwbug_bitmask |= HWBUG_COPYBACK_BROKEN; | ||
1586 | } else { | ||
1587 | if(mrev == 0xd) { | ||
1588 | srmmu_modtype = Cypress_vD; | ||
1589 | hwbug_bitmask |= HWBUG_ASIFLUSH_BROKEN; | ||
1590 | } else { | ||
1591 | srmmu_modtype = Cypress; | ||
1592 | } | ||
1593 | } | ||
1594 | init_cypress_common(); | ||
1595 | } | ||
1596 | |||
1597 | static void __cpuinit poke_swift(void) | 1048 | static void __cpuinit poke_swift(void) |
1598 | { | 1049 | { |
1599 | unsigned long mreg; | 1050 | unsigned long mreg; |
@@ -1617,6 +1068,20 @@ static void __cpuinit poke_swift(void) | |||
1617 | srmmu_set_mmureg(mreg); | 1068 | srmmu_set_mmureg(mreg); |
1618 | } | 1069 | } |
1619 | 1070 | ||
1071 | static const struct sparc32_cachetlb_ops swift_ops = { | ||
1072 | .cache_all = swift_flush_cache_all, | ||
1073 | .cache_mm = swift_flush_cache_mm, | ||
1074 | .cache_page = swift_flush_cache_page, | ||
1075 | .cache_range = swift_flush_cache_range, | ||
1076 | .tlb_all = swift_flush_tlb_all, | ||
1077 | .tlb_mm = swift_flush_tlb_mm, | ||
1078 | .tlb_page = swift_flush_tlb_page, | ||
1079 | .tlb_range = swift_flush_tlb_range, | ||
1080 | .page_to_ram = swift_flush_page_to_ram, | ||
1081 | .sig_insns = swift_flush_sig_insns, | ||
1082 | .page_for_dma = swift_flush_page_for_dma, | ||
1083 | }; | ||
1084 | |||
1620 | #define SWIFT_MASKID_ADDR 0x10003018 | 1085 | #define SWIFT_MASKID_ADDR 0x10003018 |
1621 | static void __init init_swift(void) | 1086 | static void __init init_swift(void) |
1622 | { | 1087 | { |
@@ -1667,23 +1132,7 @@ static void __init init_swift(void) | |||
1667 | break; | 1132 | break; |
1668 | } | 1133 | } |
1669 | 1134 | ||
1670 | BTFIXUPSET_CALL(flush_cache_all, swift_flush_cache_all, BTFIXUPCALL_NORM); | 1135 | sparc32_cachetlb_ops = &swift_ops; |
1671 | BTFIXUPSET_CALL(flush_cache_mm, swift_flush_cache_mm, BTFIXUPCALL_NORM); | ||
1672 | BTFIXUPSET_CALL(flush_cache_page, swift_flush_cache_page, BTFIXUPCALL_NORM); | ||
1673 | BTFIXUPSET_CALL(flush_cache_range, swift_flush_cache_range, BTFIXUPCALL_NORM); | ||
1674 | |||
1675 | |||
1676 | BTFIXUPSET_CALL(flush_tlb_all, swift_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1677 | BTFIXUPSET_CALL(flush_tlb_mm, swift_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1678 | BTFIXUPSET_CALL(flush_tlb_page, swift_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1679 | BTFIXUPSET_CALL(flush_tlb_range, swift_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1680 | |||
1681 | BTFIXUPSET_CALL(__flush_page_to_ram, swift_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
1682 | BTFIXUPSET_CALL(flush_sig_insns, swift_flush_sig_insns, BTFIXUPCALL_NORM); | ||
1683 | BTFIXUPSET_CALL(flush_page_for_dma, swift_flush_page_for_dma, BTFIXUPCALL_NORM); | ||
1684 | |||
1685 | BTFIXUPSET_CALL(update_mmu_cache, swift_update_mmu_cache, BTFIXUPCALL_NORM); | ||
1686 | |||
1687 | flush_page_for_dma_global = 0; | 1136 | flush_page_for_dma_global = 0; |
1688 | 1137 | ||
1689 | /* | 1138 | /* |
@@ -1816,26 +1265,25 @@ static void __cpuinit poke_turbosparc(void) | |||
1816 | srmmu_set_mmureg(mreg); | 1265 | srmmu_set_mmureg(mreg); |
1817 | } | 1266 | } |
1818 | 1267 | ||
1268 | static const struct sparc32_cachetlb_ops turbosparc_ops = { | ||
1269 | .cache_all = turbosparc_flush_cache_all, | ||
1270 | .cache_mm = turbosparc_flush_cache_mm, | ||
1271 | .cache_page = turbosparc_flush_cache_page, | ||
1272 | .cache_range = turbosparc_flush_cache_range, | ||
1273 | .tlb_all = turbosparc_flush_tlb_all, | ||
1274 | .tlb_mm = turbosparc_flush_tlb_mm, | ||
1275 | .tlb_page = turbosparc_flush_tlb_page, | ||
1276 | .tlb_range = turbosparc_flush_tlb_range, | ||
1277 | .page_to_ram = turbosparc_flush_page_to_ram, | ||
1278 | .sig_insns = turbosparc_flush_sig_insns, | ||
1279 | .page_for_dma = turbosparc_flush_page_for_dma, | ||
1280 | }; | ||
1281 | |||
1819 | static void __init init_turbosparc(void) | 1282 | static void __init init_turbosparc(void) |
1820 | { | 1283 | { |
1821 | srmmu_name = "Fujitsu TurboSparc"; | 1284 | srmmu_name = "Fujitsu TurboSparc"; |
1822 | srmmu_modtype = TurboSparc; | 1285 | srmmu_modtype = TurboSparc; |
1823 | 1286 | sparc32_cachetlb_ops = &turbosparc_ops; | |
1824 | BTFIXUPSET_CALL(flush_cache_all, turbosparc_flush_cache_all, BTFIXUPCALL_NORM); | ||
1825 | BTFIXUPSET_CALL(flush_cache_mm, turbosparc_flush_cache_mm, BTFIXUPCALL_NORM); | ||
1826 | BTFIXUPSET_CALL(flush_cache_page, turbosparc_flush_cache_page, BTFIXUPCALL_NORM); | ||
1827 | BTFIXUPSET_CALL(flush_cache_range, turbosparc_flush_cache_range, BTFIXUPCALL_NORM); | ||
1828 | |||
1829 | BTFIXUPSET_CALL(flush_tlb_all, turbosparc_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1830 | BTFIXUPSET_CALL(flush_tlb_mm, turbosparc_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1831 | BTFIXUPSET_CALL(flush_tlb_page, turbosparc_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1832 | BTFIXUPSET_CALL(flush_tlb_range, turbosparc_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1833 | |||
1834 | BTFIXUPSET_CALL(__flush_page_to_ram, turbosparc_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
1835 | |||
1836 | BTFIXUPSET_CALL(flush_sig_insns, turbosparc_flush_sig_insns, BTFIXUPCALL_NOP); | ||
1837 | BTFIXUPSET_CALL(flush_page_for_dma, turbosparc_flush_page_for_dma, BTFIXUPCALL_NORM); | ||
1838 | |||
1839 | poke_srmmu = poke_turbosparc; | 1287 | poke_srmmu = poke_turbosparc; |
1840 | } | 1288 | } |
1841 | 1289 | ||
@@ -1850,6 +1298,20 @@ static void __cpuinit poke_tsunami(void) | |||
1850 | srmmu_set_mmureg(mreg); | 1298 | srmmu_set_mmureg(mreg); |
1851 | } | 1299 | } |
1852 | 1300 | ||
1301 | static const struct sparc32_cachetlb_ops tsunami_ops = { | ||
1302 | .cache_all = tsunami_flush_cache_all, | ||
1303 | .cache_mm = tsunami_flush_cache_mm, | ||
1304 | .cache_page = tsunami_flush_cache_page, | ||
1305 | .cache_range = tsunami_flush_cache_range, | ||
1306 | .tlb_all = tsunami_flush_tlb_all, | ||
1307 | .tlb_mm = tsunami_flush_tlb_mm, | ||
1308 | .tlb_page = tsunami_flush_tlb_page, | ||
1309 | .tlb_range = tsunami_flush_tlb_range, | ||
1310 | .page_to_ram = tsunami_flush_page_to_ram, | ||
1311 | .sig_insns = tsunami_flush_sig_insns, | ||
1312 | .page_for_dma = tsunami_flush_page_for_dma, | ||
1313 | }; | ||
1314 | |||
1853 | static void __init init_tsunami(void) | 1315 | static void __init init_tsunami(void) |
1854 | { | 1316 | { |
1855 | /* | 1317 | /* |
@@ -1860,22 +1322,7 @@ static void __init init_tsunami(void) | |||
1860 | 1322 | ||
1861 | srmmu_name = "TI Tsunami"; | 1323 | srmmu_name = "TI Tsunami"; |
1862 | srmmu_modtype = Tsunami; | 1324 | srmmu_modtype = Tsunami; |
1863 | 1325 | sparc32_cachetlb_ops = &tsunami_ops; | |
1864 | BTFIXUPSET_CALL(flush_cache_all, tsunami_flush_cache_all, BTFIXUPCALL_NORM); | ||
1865 | BTFIXUPSET_CALL(flush_cache_mm, tsunami_flush_cache_mm, BTFIXUPCALL_NORM); | ||
1866 | BTFIXUPSET_CALL(flush_cache_page, tsunami_flush_cache_page, BTFIXUPCALL_NORM); | ||
1867 | BTFIXUPSET_CALL(flush_cache_range, tsunami_flush_cache_range, BTFIXUPCALL_NORM); | ||
1868 | |||
1869 | |||
1870 | BTFIXUPSET_CALL(flush_tlb_all, tsunami_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1871 | BTFIXUPSET_CALL(flush_tlb_mm, tsunami_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1872 | BTFIXUPSET_CALL(flush_tlb_page, tsunami_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1873 | BTFIXUPSET_CALL(flush_tlb_range, tsunami_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1874 | |||
1875 | BTFIXUPSET_CALL(__flush_page_to_ram, tsunami_flush_page_to_ram, BTFIXUPCALL_NOP); | ||
1876 | BTFIXUPSET_CALL(flush_sig_insns, tsunami_flush_sig_insns, BTFIXUPCALL_NORM); | ||
1877 | BTFIXUPSET_CALL(flush_page_for_dma, tsunami_flush_page_for_dma, BTFIXUPCALL_NORM); | ||
1878 | |||
1879 | poke_srmmu = poke_tsunami; | 1326 | poke_srmmu = poke_tsunami; |
1880 | 1327 | ||
1881 | tsunami_setup_blockops(); | 1328 | tsunami_setup_blockops(); |
@@ -1886,7 +1333,7 @@ static void __cpuinit poke_viking(void) | |||
1886 | unsigned long mreg = srmmu_get_mmureg(); | 1333 | unsigned long mreg = srmmu_get_mmureg(); |
1887 | static int smp_catch; | 1334 | static int smp_catch; |
1888 | 1335 | ||
1889 | if(viking_mxcc_present) { | 1336 | if (viking_mxcc_present) { |
1890 | unsigned long mxcc_control = mxcc_get_creg(); | 1337 | unsigned long mxcc_control = mxcc_get_creg(); |
1891 | 1338 | ||
1892 | mxcc_control |= (MXCC_CTL_ECE | MXCC_CTL_PRE | MXCC_CTL_MCE); | 1339 | mxcc_control |= (MXCC_CTL_ECE | MXCC_CTL_PRE | MXCC_CTL_MCE); |
@@ -1923,6 +1370,52 @@ static void __cpuinit poke_viking(void) | |||
1923 | srmmu_set_mmureg(mreg); | 1370 | srmmu_set_mmureg(mreg); |
1924 | } | 1371 | } |
1925 | 1372 | ||
1373 | static struct sparc32_cachetlb_ops viking_ops = { | ||
1374 | .cache_all = viking_flush_cache_all, | ||
1375 | .cache_mm = viking_flush_cache_mm, | ||
1376 | .cache_page = viking_flush_cache_page, | ||
1377 | .cache_range = viking_flush_cache_range, | ||
1378 | .tlb_all = viking_flush_tlb_all, | ||
1379 | .tlb_mm = viking_flush_tlb_mm, | ||
1380 | .tlb_page = viking_flush_tlb_page, | ||
1381 | .tlb_range = viking_flush_tlb_range, | ||
1382 | .page_to_ram = viking_flush_page_to_ram, | ||
1383 | .sig_insns = viking_flush_sig_insns, | ||
1384 | .page_for_dma = viking_flush_page_for_dma, | ||
1385 | }; | ||
1386 | |||
1387 | #ifdef CONFIG_SMP | ||
1388 | /* On sun4d the cpu broadcasts local TLB flushes, so we can just | ||
1389 | * perform the local TLB flush and all the other cpus will see it. | ||
1390 | * But, unfortunately, there is a bug in the sun4d XBUS backplane | ||
1391 | * that requires that we add some synchronization to these flushes. | ||
1392 | * | ||
1393 | * The bug is that the fifo which keeps track of all the pending TLB | ||
1394 | * broadcasts in the system is an entry or two too small, so if we | ||
1395 | * have too many going at once we'll overflow that fifo and lose a TLB | ||
1396 | * flush resulting in corruption. | ||
1397 | * | ||
1398 | * Our workaround is to take a global spinlock around the TLB flushes, | ||
1399 | * which guarentees we won't ever have too many pending. It's a big | ||
1400 | * hammer, but a semaphore like system to make sure we only have N TLB | ||
1401 | * flushes going at once will require SMP locking anyways so there's | ||
1402 | * no real value in trying any harder than this. | ||
1403 | */ | ||
1404 | static struct sparc32_cachetlb_ops viking_sun4d_smp_ops = { | ||
1405 | .cache_all = viking_flush_cache_all, | ||
1406 | .cache_mm = viking_flush_cache_mm, | ||
1407 | .cache_page = viking_flush_cache_page, | ||
1408 | .cache_range = viking_flush_cache_range, | ||
1409 | .tlb_all = sun4dsmp_flush_tlb_all, | ||
1410 | .tlb_mm = sun4dsmp_flush_tlb_mm, | ||
1411 | .tlb_page = sun4dsmp_flush_tlb_page, | ||
1412 | .tlb_range = sun4dsmp_flush_tlb_range, | ||
1413 | .page_to_ram = viking_flush_page_to_ram, | ||
1414 | .sig_insns = viking_flush_sig_insns, | ||
1415 | .page_for_dma = viking_flush_page_for_dma, | ||
1416 | }; | ||
1417 | #endif | ||
1418 | |||
1926 | static void __init init_viking(void) | 1419 | static void __init init_viking(void) |
1927 | { | 1420 | { |
1928 | unsigned long mreg = srmmu_get_mmureg(); | 1421 | unsigned long mreg = srmmu_get_mmureg(); |
@@ -1933,10 +1426,6 @@ static void __init init_viking(void) | |||
1933 | viking_mxcc_present = 0; | 1426 | viking_mxcc_present = 0; |
1934 | msi_set_sync(); | 1427 | msi_set_sync(); |
1935 | 1428 | ||
1936 | BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_NORM); | ||
1937 | BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_NORM); | ||
1938 | BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_NORM); | ||
1939 | |||
1940 | /* | 1429 | /* |
1941 | * We need this to make sure old viking takes no hits | 1430 | * We need this to make sure old viking takes no hits |
1942 | * on it's cache for dma snoops to workaround the | 1431 | * on it's cache for dma snoops to workaround the |
@@ -1944,84 +1433,28 @@ static void __init init_viking(void) | |||
1944 | * This is only necessary because of the new way in | 1433 | * This is only necessary because of the new way in |
1945 | * which we use the IOMMU. | 1434 | * which we use the IOMMU. |
1946 | */ | 1435 | */ |
1947 | BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page, BTFIXUPCALL_NORM); | 1436 | viking_ops.page_for_dma = viking_flush_page; |
1948 | 1437 | #ifdef CONFIG_SMP | |
1438 | viking_sun4d_smp_ops.page_for_dma = viking_flush_page; | ||
1439 | #endif | ||
1949 | flush_page_for_dma_global = 0; | 1440 | flush_page_for_dma_global = 0; |
1950 | } else { | 1441 | } else { |
1951 | srmmu_name = "TI Viking/MXCC"; | 1442 | srmmu_name = "TI Viking/MXCC"; |
1952 | viking_mxcc_present = 1; | 1443 | viking_mxcc_present = 1; |
1953 | |||
1954 | srmmu_cache_pagetables = 1; | 1444 | srmmu_cache_pagetables = 1; |
1955 | |||
1956 | /* MXCC vikings lack the DMA snooping bug. */ | ||
1957 | BTFIXUPSET_CALL(flush_page_for_dma, viking_flush_page_for_dma, BTFIXUPCALL_NOP); | ||
1958 | } | 1445 | } |
1959 | 1446 | ||
1960 | BTFIXUPSET_CALL(flush_cache_all, viking_flush_cache_all, BTFIXUPCALL_NORM); | 1447 | sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *) |
1961 | BTFIXUPSET_CALL(flush_cache_mm, viking_flush_cache_mm, BTFIXUPCALL_NORM); | 1448 | &viking_ops; |
1962 | BTFIXUPSET_CALL(flush_cache_page, viking_flush_cache_page, BTFIXUPCALL_NORM); | ||
1963 | BTFIXUPSET_CALL(flush_cache_range, viking_flush_cache_range, BTFIXUPCALL_NORM); | ||
1964 | |||
1965 | #ifdef CONFIG_SMP | 1449 | #ifdef CONFIG_SMP |
1966 | if (sparc_cpu_model == sun4d) { | 1450 | if (sparc_cpu_model == sun4d) |
1967 | BTFIXUPSET_CALL(flush_tlb_all, sun4dsmp_flush_tlb_all, BTFIXUPCALL_NORM); | 1451 | sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *) |
1968 | BTFIXUPSET_CALL(flush_tlb_mm, sun4dsmp_flush_tlb_mm, BTFIXUPCALL_NORM); | 1452 | &viking_sun4d_smp_ops; |
1969 | BTFIXUPSET_CALL(flush_tlb_page, sun4dsmp_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1970 | BTFIXUPSET_CALL(flush_tlb_range, sun4dsmp_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1971 | } else | ||
1972 | #endif | 1453 | #endif |
1973 | { | ||
1974 | BTFIXUPSET_CALL(flush_tlb_all, viking_flush_tlb_all, BTFIXUPCALL_NORM); | ||
1975 | BTFIXUPSET_CALL(flush_tlb_mm, viking_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
1976 | BTFIXUPSET_CALL(flush_tlb_page, viking_flush_tlb_page, BTFIXUPCALL_NORM); | ||
1977 | BTFIXUPSET_CALL(flush_tlb_range, viking_flush_tlb_range, BTFIXUPCALL_NORM); | ||
1978 | } | ||
1979 | |||
1980 | BTFIXUPSET_CALL(__flush_page_to_ram, viking_flush_page_to_ram, BTFIXUPCALL_NOP); | ||
1981 | BTFIXUPSET_CALL(flush_sig_insns, viking_flush_sig_insns, BTFIXUPCALL_NOP); | ||
1982 | 1454 | ||
1983 | poke_srmmu = poke_viking; | 1455 | poke_srmmu = poke_viking; |
1984 | } | 1456 | } |
1985 | 1457 | ||
1986 | #ifdef CONFIG_SPARC_LEON | ||
1987 | |||
1988 | void __init poke_leonsparc(void) | ||
1989 | { | ||
1990 | } | ||
1991 | |||
1992 | void __init init_leon(void) | ||
1993 | { | ||
1994 | |||
1995 | srmmu_name = "LEON"; | ||
1996 | |||
1997 | BTFIXUPSET_CALL(flush_cache_all, leon_flush_cache_all, | ||
1998 | BTFIXUPCALL_NORM); | ||
1999 | BTFIXUPSET_CALL(flush_cache_mm, leon_flush_cache_all, | ||
2000 | BTFIXUPCALL_NORM); | ||
2001 | BTFIXUPSET_CALL(flush_cache_page, leon_flush_pcache_all, | ||
2002 | BTFIXUPCALL_NORM); | ||
2003 | BTFIXUPSET_CALL(flush_cache_range, leon_flush_cache_all, | ||
2004 | BTFIXUPCALL_NORM); | ||
2005 | BTFIXUPSET_CALL(flush_page_for_dma, leon_flush_dcache_all, | ||
2006 | BTFIXUPCALL_NORM); | ||
2007 | |||
2008 | BTFIXUPSET_CALL(flush_tlb_all, leon_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2009 | BTFIXUPSET_CALL(flush_tlb_mm, leon_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2010 | BTFIXUPSET_CALL(flush_tlb_page, leon_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2011 | BTFIXUPSET_CALL(flush_tlb_range, leon_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2012 | |||
2013 | BTFIXUPSET_CALL(__flush_page_to_ram, leon_flush_cache_all, | ||
2014 | BTFIXUPCALL_NOP); | ||
2015 | BTFIXUPSET_CALL(flush_sig_insns, leon_flush_cache_all, BTFIXUPCALL_NOP); | ||
2016 | |||
2017 | poke_srmmu = poke_leonsparc; | ||
2018 | |||
2019 | srmmu_cache_pagetables = 0; | ||
2020 | |||
2021 | leon_flush_during_switch = leon_flush_needed(); | ||
2022 | } | ||
2023 | #endif | ||
2024 | |||
2025 | /* Probe for the srmmu chip version. */ | 1458 | /* Probe for the srmmu chip version. */ |
2026 | static void __init get_srmmu_type(void) | 1459 | static void __init get_srmmu_type(void) |
2027 | { | 1460 | { |
@@ -2052,22 +1485,15 @@ static void __init get_srmmu_type(void) | |||
2052 | break; | 1485 | break; |
2053 | case 0: | 1486 | case 0: |
2054 | case 2: | 1487 | case 2: |
2055 | /* Uniprocessor Cypress */ | ||
2056 | init_cypress_604(); | ||
2057 | break; | ||
2058 | case 10: | 1488 | case 10: |
2059 | case 11: | 1489 | case 11: |
2060 | case 12: | 1490 | case 12: |
2061 | /* _REALLY OLD_ Cypress MP chips... */ | ||
2062 | case 13: | 1491 | case 13: |
2063 | case 14: | 1492 | case 14: |
2064 | case 15: | 1493 | case 15: |
2065 | /* MP Cypress mmu/cache-controller */ | ||
2066 | init_cypress_605(mod_rev); | ||
2067 | break; | ||
2068 | default: | 1494 | default: |
2069 | /* Some other Cypress revision, assume a 605. */ | 1495 | prom_printf("Sparc-Linux Cypress support does not longer exit.\n"); |
2070 | init_cypress_605(mod_rev); | 1496 | prom_halt(); |
2071 | break; | 1497 | break; |
2072 | } | 1498 | } |
2073 | return; | 1499 | return; |
@@ -2123,203 +1549,193 @@ static void __init get_srmmu_type(void) | |||
2123 | srmmu_is_bad(); | 1549 | srmmu_is_bad(); |
2124 | } | 1550 | } |
2125 | 1551 | ||
2126 | /* don't laugh, static pagetables */ | 1552 | #ifdef CONFIG_SMP |
2127 | static void srmmu_check_pgt_cache(int low, int high) | 1553 | /* Local cross-calls. */ |
1554 | static void smp_flush_page_for_dma(unsigned long page) | ||
2128 | { | 1555 | { |
1556 | xc1((smpfunc_t) local_ops->page_for_dma, page); | ||
1557 | local_ops->page_for_dma(page); | ||
2129 | } | 1558 | } |
2130 | 1559 | ||
2131 | extern unsigned long spwin_mmu_patchme, fwin_mmu_patchme, | 1560 | static void smp_flush_cache_all(void) |
2132 | tsetup_mmu_patchme, rtrap_mmu_patchme; | ||
2133 | |||
2134 | extern unsigned long spwin_srmmu_stackchk, srmmu_fwin_stackchk, | ||
2135 | tsetup_srmmu_stackchk, srmmu_rett_stackchk; | ||
2136 | |||
2137 | extern unsigned long srmmu_fault; | ||
2138 | |||
2139 | #define PATCH_BRANCH(insn, dest) do { \ | ||
2140 | iaddr = &(insn); \ | ||
2141 | daddr = &(dest); \ | ||
2142 | *iaddr = SPARC_BRANCH((unsigned long) daddr, (unsigned long) iaddr); \ | ||
2143 | } while(0) | ||
2144 | |||
2145 | static void __init patch_window_trap_handlers(void) | ||
2146 | { | 1561 | { |
2147 | unsigned long *iaddr, *daddr; | 1562 | xc0((smpfunc_t) local_ops->cache_all); |
2148 | 1563 | local_ops->cache_all(); | |
2149 | PATCH_BRANCH(spwin_mmu_patchme, spwin_srmmu_stackchk); | ||
2150 | PATCH_BRANCH(fwin_mmu_patchme, srmmu_fwin_stackchk); | ||
2151 | PATCH_BRANCH(tsetup_mmu_patchme, tsetup_srmmu_stackchk); | ||
2152 | PATCH_BRANCH(rtrap_mmu_patchme, srmmu_rett_stackchk); | ||
2153 | PATCH_BRANCH(sparc_ttable[SP_TRAP_TFLT].inst_three, srmmu_fault); | ||
2154 | PATCH_BRANCH(sparc_ttable[SP_TRAP_DFLT].inst_three, srmmu_fault); | ||
2155 | PATCH_BRANCH(sparc_ttable[SP_TRAP_DACC].inst_three, srmmu_fault); | ||
2156 | } | 1564 | } |
2157 | 1565 | ||
2158 | #ifdef CONFIG_SMP | 1566 | static void smp_flush_tlb_all(void) |
2159 | /* Local cross-calls. */ | ||
2160 | static void smp_flush_page_for_dma(unsigned long page) | ||
2161 | { | 1567 | { |
2162 | xc1((smpfunc_t) BTFIXUP_CALL(local_flush_page_for_dma), page); | 1568 | xc0((smpfunc_t) local_ops->tlb_all); |
2163 | local_flush_page_for_dma(page); | 1569 | local_ops->tlb_all(); |
2164 | } | 1570 | } |
2165 | 1571 | ||
2166 | #endif | 1572 | static void smp_flush_cache_mm(struct mm_struct *mm) |
2167 | |||
2168 | static pte_t srmmu_pgoff_to_pte(unsigned long pgoff) | ||
2169 | { | 1573 | { |
2170 | return __pte((pgoff << SRMMU_PTE_FILE_SHIFT) | SRMMU_FILE); | 1574 | if (mm->context != NO_CONTEXT) { |
1575 | cpumask_t cpu_mask; | ||
1576 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
1577 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1578 | if (!cpumask_empty(&cpu_mask)) | ||
1579 | xc1((smpfunc_t) local_ops->cache_mm, (unsigned long) mm); | ||
1580 | local_ops->cache_mm(mm); | ||
1581 | } | ||
2171 | } | 1582 | } |
2172 | 1583 | ||
2173 | static unsigned long srmmu_pte_to_pgoff(pte_t pte) | 1584 | static void smp_flush_tlb_mm(struct mm_struct *mm) |
2174 | { | 1585 | { |
2175 | return pte_val(pte) >> SRMMU_PTE_FILE_SHIFT; | 1586 | if (mm->context != NO_CONTEXT) { |
1587 | cpumask_t cpu_mask; | ||
1588 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
1589 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1590 | if (!cpumask_empty(&cpu_mask)) { | ||
1591 | xc1((smpfunc_t) local_ops->tlb_mm, (unsigned long) mm); | ||
1592 | if (atomic_read(&mm->mm_users) == 1 && current->active_mm == mm) | ||
1593 | cpumask_copy(mm_cpumask(mm), | ||
1594 | cpumask_of(smp_processor_id())); | ||
1595 | } | ||
1596 | local_ops->tlb_mm(mm); | ||
1597 | } | ||
2176 | } | 1598 | } |
2177 | 1599 | ||
2178 | static pgprot_t srmmu_pgprot_noncached(pgprot_t prot) | 1600 | static void smp_flush_cache_range(struct vm_area_struct *vma, |
1601 | unsigned long start, | ||
1602 | unsigned long end) | ||
2179 | { | 1603 | { |
2180 | prot &= ~__pgprot(SRMMU_CACHE); | 1604 | struct mm_struct *mm = vma->vm_mm; |
2181 | 1605 | ||
2182 | return prot; | 1606 | if (mm->context != NO_CONTEXT) { |
1607 | cpumask_t cpu_mask; | ||
1608 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
1609 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1610 | if (!cpumask_empty(&cpu_mask)) | ||
1611 | xc3((smpfunc_t) local_ops->cache_range, | ||
1612 | (unsigned long) vma, start, end); | ||
1613 | local_ops->cache_range(vma, start, end); | ||
1614 | } | ||
2183 | } | 1615 | } |
2184 | 1616 | ||
2185 | /* Load up routines and constants for sun4m and sun4d mmu */ | 1617 | static void smp_flush_tlb_range(struct vm_area_struct *vma, |
2186 | void __init ld_mmu_srmmu(void) | 1618 | unsigned long start, |
1619 | unsigned long end) | ||
2187 | { | 1620 | { |
2188 | extern void ld_mmu_iommu(void); | 1621 | struct mm_struct *mm = vma->vm_mm; |
2189 | extern void ld_mmu_iounit(void); | ||
2190 | extern void ___xchg32_sun4md(void); | ||
2191 | |||
2192 | BTFIXUPSET_SIMM13(pgdir_shift, SRMMU_PGDIR_SHIFT); | ||
2193 | BTFIXUPSET_SETHI(pgdir_size, SRMMU_PGDIR_SIZE); | ||
2194 | BTFIXUPSET_SETHI(pgdir_mask, SRMMU_PGDIR_MASK); | ||
2195 | |||
2196 | BTFIXUPSET_SIMM13(ptrs_per_pmd, SRMMU_PTRS_PER_PMD); | ||
2197 | BTFIXUPSET_SIMM13(ptrs_per_pgd, SRMMU_PTRS_PER_PGD); | ||
2198 | |||
2199 | BTFIXUPSET_INT(page_none, pgprot_val(SRMMU_PAGE_NONE)); | ||
2200 | PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED); | ||
2201 | BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY)); | ||
2202 | BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY)); | ||
2203 | BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL)); | ||
2204 | page_kernel = pgprot_val(SRMMU_PAGE_KERNEL); | ||
2205 | 1622 | ||
2206 | /* Functions */ | 1623 | if (mm->context != NO_CONTEXT) { |
2207 | BTFIXUPSET_CALL(pgprot_noncached, srmmu_pgprot_noncached, BTFIXUPCALL_NORM); | 1624 | cpumask_t cpu_mask; |
2208 | #ifndef CONFIG_SMP | 1625 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); |
2209 | BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4md, BTFIXUPCALL_SWAPG1G2); | 1626 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); |
2210 | #endif | 1627 | if (!cpumask_empty(&cpu_mask)) |
2211 | BTFIXUPSET_CALL(do_check_pgt_cache, srmmu_check_pgt_cache, BTFIXUPCALL_NOP); | 1628 | xc3((smpfunc_t) local_ops->tlb_range, |
1629 | (unsigned long) vma, start, end); | ||
1630 | local_ops->tlb_range(vma, start, end); | ||
1631 | } | ||
1632 | } | ||
2212 | 1633 | ||
2213 | BTFIXUPSET_CALL(set_pte, srmmu_set_pte, BTFIXUPCALL_SWAPO0O1); | 1634 | static void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page) |
2214 | BTFIXUPSET_CALL(switch_mm, srmmu_switch_mm, BTFIXUPCALL_NORM); | 1635 | { |
1636 | struct mm_struct *mm = vma->vm_mm; | ||
2215 | 1637 | ||
2216 | BTFIXUPSET_CALL(pte_pfn, srmmu_pte_pfn, BTFIXUPCALL_NORM); | 1638 | if (mm->context != NO_CONTEXT) { |
2217 | BTFIXUPSET_CALL(pmd_page, srmmu_pmd_page, BTFIXUPCALL_NORM); | 1639 | cpumask_t cpu_mask; |
2218 | BTFIXUPSET_CALL(pgd_page_vaddr, srmmu_pgd_page, BTFIXUPCALL_NORM); | 1640 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); |
1641 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1642 | if (!cpumask_empty(&cpu_mask)) | ||
1643 | xc2((smpfunc_t) local_ops->cache_page, | ||
1644 | (unsigned long) vma, page); | ||
1645 | local_ops->cache_page(vma, page); | ||
1646 | } | ||
1647 | } | ||
2219 | 1648 | ||
2220 | BTFIXUPSET_CALL(pte_present, srmmu_pte_present, BTFIXUPCALL_NORM); | 1649 | static void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) |
2221 | BTFIXUPSET_CALL(pte_clear, srmmu_pte_clear, BTFIXUPCALL_SWAPO0G0); | 1650 | { |
1651 | struct mm_struct *mm = vma->vm_mm; | ||
2222 | 1652 | ||
2223 | BTFIXUPSET_CALL(pmd_bad, srmmu_pmd_bad, BTFIXUPCALL_NORM); | 1653 | if (mm->context != NO_CONTEXT) { |
2224 | BTFIXUPSET_CALL(pmd_present, srmmu_pmd_present, BTFIXUPCALL_NORM); | 1654 | cpumask_t cpu_mask; |
2225 | BTFIXUPSET_CALL(pmd_clear, srmmu_pmd_clear, BTFIXUPCALL_SWAPO0G0); | 1655 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); |
1656 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1657 | if (!cpumask_empty(&cpu_mask)) | ||
1658 | xc2((smpfunc_t) local_ops->tlb_page, | ||
1659 | (unsigned long) vma, page); | ||
1660 | local_ops->tlb_page(vma, page); | ||
1661 | } | ||
1662 | } | ||
2226 | 1663 | ||
2227 | BTFIXUPSET_CALL(pgd_none, srmmu_pgd_none, BTFIXUPCALL_NORM); | 1664 | static void smp_flush_page_to_ram(unsigned long page) |
2228 | BTFIXUPSET_CALL(pgd_bad, srmmu_pgd_bad, BTFIXUPCALL_NORM); | 1665 | { |
2229 | BTFIXUPSET_CALL(pgd_present, srmmu_pgd_present, BTFIXUPCALL_NORM); | 1666 | /* Current theory is that those who call this are the one's |
2230 | BTFIXUPSET_CALL(pgd_clear, srmmu_pgd_clear, BTFIXUPCALL_SWAPO0G0); | 1667 | * who have just dirtied their cache with the pages contents |
1668 | * in kernel space, therefore we only run this on local cpu. | ||
1669 | * | ||
1670 | * XXX This experiment failed, research further... -DaveM | ||
1671 | */ | ||
1672 | #if 1 | ||
1673 | xc1((smpfunc_t) local_ops->page_to_ram, page); | ||
1674 | #endif | ||
1675 | local_ops->page_to_ram(page); | ||
1676 | } | ||
1677 | |||
1678 | static void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) | ||
1679 | { | ||
1680 | cpumask_t cpu_mask; | ||
1681 | cpumask_copy(&cpu_mask, mm_cpumask(mm)); | ||
1682 | cpumask_clear_cpu(smp_processor_id(), &cpu_mask); | ||
1683 | if (!cpumask_empty(&cpu_mask)) | ||
1684 | xc2((smpfunc_t) local_ops->sig_insns, | ||
1685 | (unsigned long) mm, insn_addr); | ||
1686 | local_ops->sig_insns(mm, insn_addr); | ||
1687 | } | ||
1688 | |||
1689 | static struct sparc32_cachetlb_ops smp_cachetlb_ops = { | ||
1690 | .cache_all = smp_flush_cache_all, | ||
1691 | .cache_mm = smp_flush_cache_mm, | ||
1692 | .cache_page = smp_flush_cache_page, | ||
1693 | .cache_range = smp_flush_cache_range, | ||
1694 | .tlb_all = smp_flush_tlb_all, | ||
1695 | .tlb_mm = smp_flush_tlb_mm, | ||
1696 | .tlb_page = smp_flush_tlb_page, | ||
1697 | .tlb_range = smp_flush_tlb_range, | ||
1698 | .page_to_ram = smp_flush_page_to_ram, | ||
1699 | .sig_insns = smp_flush_sig_insns, | ||
1700 | .page_for_dma = smp_flush_page_for_dma, | ||
1701 | }; | ||
1702 | #endif | ||
2231 | 1703 | ||
2232 | BTFIXUPSET_CALL(mk_pte, srmmu_mk_pte, BTFIXUPCALL_NORM); | 1704 | /* Load up routines and constants for sun4m and sun4d mmu */ |
2233 | BTFIXUPSET_CALL(mk_pte_phys, srmmu_mk_pte_phys, BTFIXUPCALL_NORM); | 1705 | void __init load_mmu(void) |
2234 | BTFIXUPSET_CALL(mk_pte_io, srmmu_mk_pte_io, BTFIXUPCALL_NORM); | 1706 | { |
2235 | BTFIXUPSET_CALL(pgd_set, srmmu_pgd_set, BTFIXUPCALL_NORM); | 1707 | extern void ld_mmu_iommu(void); |
2236 | BTFIXUPSET_CALL(pmd_set, srmmu_pmd_set, BTFIXUPCALL_NORM); | 1708 | extern void ld_mmu_iounit(void); |
2237 | BTFIXUPSET_CALL(pmd_populate, srmmu_pmd_populate, BTFIXUPCALL_NORM); | ||
2238 | |||
2239 | BTFIXUPSET_INT(pte_modify_mask, SRMMU_CHG_MASK); | ||
2240 | BTFIXUPSET_CALL(pmd_offset, srmmu_pmd_offset, BTFIXUPCALL_NORM); | ||
2241 | BTFIXUPSET_CALL(pte_offset_kernel, srmmu_pte_offset, BTFIXUPCALL_NORM); | ||
2242 | |||
2243 | BTFIXUPSET_CALL(free_pte_fast, srmmu_free_pte_fast, BTFIXUPCALL_NORM); | ||
2244 | BTFIXUPSET_CALL(pte_free, srmmu_pte_free, BTFIXUPCALL_NORM); | ||
2245 | BTFIXUPSET_CALL(pte_alloc_one_kernel, srmmu_pte_alloc_one_kernel, BTFIXUPCALL_NORM); | ||
2246 | BTFIXUPSET_CALL(pte_alloc_one, srmmu_pte_alloc_one, BTFIXUPCALL_NORM); | ||
2247 | BTFIXUPSET_CALL(free_pmd_fast, srmmu_pmd_free, BTFIXUPCALL_NORM); | ||
2248 | BTFIXUPSET_CALL(pmd_alloc_one, srmmu_pmd_alloc_one, BTFIXUPCALL_NORM); | ||
2249 | BTFIXUPSET_CALL(free_pgd_fast, srmmu_free_pgd_fast, BTFIXUPCALL_NORM); | ||
2250 | BTFIXUPSET_CALL(get_pgd_fast, srmmu_get_pgd_fast, BTFIXUPCALL_NORM); | ||
2251 | |||
2252 | BTFIXUPSET_HALF(pte_writei, SRMMU_WRITE); | ||
2253 | BTFIXUPSET_HALF(pte_dirtyi, SRMMU_DIRTY); | ||
2254 | BTFIXUPSET_HALF(pte_youngi, SRMMU_REF); | ||
2255 | BTFIXUPSET_HALF(pte_filei, SRMMU_FILE); | ||
2256 | BTFIXUPSET_HALF(pte_wrprotecti, SRMMU_WRITE); | ||
2257 | BTFIXUPSET_HALF(pte_mkcleani, SRMMU_DIRTY); | ||
2258 | BTFIXUPSET_HALF(pte_mkoldi, SRMMU_REF); | ||
2259 | BTFIXUPSET_CALL(pte_mkwrite, srmmu_pte_mkwrite, BTFIXUPCALL_ORINT(SRMMU_WRITE)); | ||
2260 | BTFIXUPSET_CALL(pte_mkdirty, srmmu_pte_mkdirty, BTFIXUPCALL_ORINT(SRMMU_DIRTY)); | ||
2261 | BTFIXUPSET_CALL(pte_mkyoung, srmmu_pte_mkyoung, BTFIXUPCALL_ORINT(SRMMU_REF)); | ||
2262 | BTFIXUPSET_CALL(update_mmu_cache, srmmu_update_mmu_cache, BTFIXUPCALL_NOP); | ||
2263 | BTFIXUPSET_CALL(destroy_context, srmmu_destroy_context, BTFIXUPCALL_NORM); | ||
2264 | |||
2265 | BTFIXUPSET_CALL(sparc_mapiorange, srmmu_mapiorange, BTFIXUPCALL_NORM); | ||
2266 | BTFIXUPSET_CALL(sparc_unmapiorange, srmmu_unmapiorange, BTFIXUPCALL_NORM); | ||
2267 | |||
2268 | BTFIXUPSET_CALL(__swp_type, srmmu_swp_type, BTFIXUPCALL_NORM); | ||
2269 | BTFIXUPSET_CALL(__swp_offset, srmmu_swp_offset, BTFIXUPCALL_NORM); | ||
2270 | BTFIXUPSET_CALL(__swp_entry, srmmu_swp_entry, BTFIXUPCALL_NORM); | ||
2271 | |||
2272 | BTFIXUPSET_CALL(mmu_info, srmmu_mmu_info, BTFIXUPCALL_NORM); | ||
2273 | |||
2274 | BTFIXUPSET_CALL(alloc_thread_info_node, srmmu_alloc_thread_info_node, BTFIXUPCALL_NORM); | ||
2275 | BTFIXUPSET_CALL(free_thread_info, srmmu_free_thread_info, BTFIXUPCALL_NORM); | ||
2276 | |||
2277 | BTFIXUPSET_CALL(pte_to_pgoff, srmmu_pte_to_pgoff, BTFIXUPCALL_NORM); | ||
2278 | BTFIXUPSET_CALL(pgoff_to_pte, srmmu_pgoff_to_pte, BTFIXUPCALL_NORM); | ||
2279 | 1709 | ||
1710 | /* Functions */ | ||
2280 | get_srmmu_type(); | 1711 | get_srmmu_type(); |
2281 | patch_window_trap_handlers(); | ||
2282 | 1712 | ||
2283 | #ifdef CONFIG_SMP | 1713 | #ifdef CONFIG_SMP |
2284 | /* El switcheroo... */ | 1714 | /* El switcheroo... */ |
1715 | local_ops = sparc32_cachetlb_ops; | ||
2285 | 1716 | ||
2286 | BTFIXUPCOPY_CALL(local_flush_cache_all, flush_cache_all); | 1717 | if (sparc_cpu_model == sun4d || sparc_cpu_model == sparc_leon) { |
2287 | BTFIXUPCOPY_CALL(local_flush_cache_mm, flush_cache_mm); | 1718 | smp_cachetlb_ops.tlb_all = local_ops->tlb_all; |
2288 | BTFIXUPCOPY_CALL(local_flush_cache_range, flush_cache_range); | 1719 | smp_cachetlb_ops.tlb_mm = local_ops->tlb_mm; |
2289 | BTFIXUPCOPY_CALL(local_flush_cache_page, flush_cache_page); | 1720 | smp_cachetlb_ops.tlb_range = local_ops->tlb_range; |
2290 | BTFIXUPCOPY_CALL(local_flush_tlb_all, flush_tlb_all); | 1721 | smp_cachetlb_ops.tlb_page = local_ops->tlb_page; |
2291 | BTFIXUPCOPY_CALL(local_flush_tlb_mm, flush_tlb_mm); | ||
2292 | BTFIXUPCOPY_CALL(local_flush_tlb_range, flush_tlb_range); | ||
2293 | BTFIXUPCOPY_CALL(local_flush_tlb_page, flush_tlb_page); | ||
2294 | BTFIXUPCOPY_CALL(local_flush_page_to_ram, __flush_page_to_ram); | ||
2295 | BTFIXUPCOPY_CALL(local_flush_sig_insns, flush_sig_insns); | ||
2296 | BTFIXUPCOPY_CALL(local_flush_page_for_dma, flush_page_for_dma); | ||
2297 | |||
2298 | BTFIXUPSET_CALL(flush_cache_all, smp_flush_cache_all, BTFIXUPCALL_NORM); | ||
2299 | BTFIXUPSET_CALL(flush_cache_mm, smp_flush_cache_mm, BTFIXUPCALL_NORM); | ||
2300 | BTFIXUPSET_CALL(flush_cache_range, smp_flush_cache_range, BTFIXUPCALL_NORM); | ||
2301 | BTFIXUPSET_CALL(flush_cache_page, smp_flush_cache_page, BTFIXUPCALL_NORM); | ||
2302 | if (sparc_cpu_model != sun4d && | ||
2303 | sparc_cpu_model != sparc_leon) { | ||
2304 | BTFIXUPSET_CALL(flush_tlb_all, smp_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2305 | BTFIXUPSET_CALL(flush_tlb_mm, smp_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
2306 | BTFIXUPSET_CALL(flush_tlb_range, smp_flush_tlb_range, BTFIXUPCALL_NORM); | ||
2307 | BTFIXUPSET_CALL(flush_tlb_page, smp_flush_tlb_page, BTFIXUPCALL_NORM); | ||
2308 | } | 1722 | } |
2309 | BTFIXUPSET_CALL(__flush_page_to_ram, smp_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
2310 | BTFIXUPSET_CALL(flush_sig_insns, smp_flush_sig_insns, BTFIXUPCALL_NORM); | ||
2311 | BTFIXUPSET_CALL(flush_page_for_dma, smp_flush_page_for_dma, BTFIXUPCALL_NORM); | ||
2312 | 1723 | ||
2313 | if (poke_srmmu == poke_viking) { | 1724 | if (poke_srmmu == poke_viking) { |
2314 | /* Avoid unnecessary cross calls. */ | 1725 | /* Avoid unnecessary cross calls. */ |
2315 | BTFIXUPCOPY_CALL(flush_cache_all, local_flush_cache_all); | 1726 | smp_cachetlb_ops.cache_all = local_ops->cache_all; |
2316 | BTFIXUPCOPY_CALL(flush_cache_mm, local_flush_cache_mm); | 1727 | smp_cachetlb_ops.cache_mm = local_ops->cache_mm; |
2317 | BTFIXUPCOPY_CALL(flush_cache_range, local_flush_cache_range); | 1728 | smp_cachetlb_ops.cache_range = local_ops->cache_range; |
2318 | BTFIXUPCOPY_CALL(flush_cache_page, local_flush_cache_page); | 1729 | smp_cachetlb_ops.cache_page = local_ops->cache_page; |
2319 | BTFIXUPCOPY_CALL(__flush_page_to_ram, local_flush_page_to_ram); | 1730 | |
2320 | BTFIXUPCOPY_CALL(flush_sig_insns, local_flush_sig_insns); | 1731 | smp_cachetlb_ops.page_to_ram = local_ops->page_to_ram; |
2321 | BTFIXUPCOPY_CALL(flush_page_for_dma, local_flush_page_for_dma); | 1732 | smp_cachetlb_ops.sig_insns = local_ops->sig_insns; |
1733 | smp_cachetlb_ops.page_for_dma = local_ops->page_for_dma; | ||
2322 | } | 1734 | } |
1735 | |||
1736 | /* It really is const after this point. */ | ||
1737 | sparc32_cachetlb_ops = (const struct sparc32_cachetlb_ops *) | ||
1738 | &smp_cachetlb_ops; | ||
2323 | #endif | 1739 | #endif |
2324 | 1740 | ||
2325 | if (sparc_cpu_model == sun4d) | 1741 | if (sparc_cpu_model == sun4d) |
diff --git a/arch/sparc/mm/srmmu.h b/arch/sparc/mm/srmmu.h new file mode 100644 index 000000000000..5703274ccf89 --- /dev/null +++ b/arch/sparc/mm/srmmu.h | |||
@@ -0,0 +1,4 @@ | |||
1 | /* srmmu.c */ | ||
2 | extern char *srmmu_name; | ||
3 | |||
4 | extern void (*poke_srmmu)(void); | ||
diff --git a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c deleted file mode 100644 index 1cf4f198709a..000000000000 --- a/arch/sparc/mm/sun4c.c +++ /dev/null | |||
@@ -1,2166 +0,0 @@ | |||
1 | /* sun4c.c: Doing in software what should be done in hardware. | ||
2 | * | ||
3 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) | ||
4 | * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) | ||
5 | * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) | ||
6 | * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org) | ||
7 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
8 | */ | ||
9 | |||
10 | #define NR_TASK_BUCKETS 512 | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/mm.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/bootmem.h> | ||
17 | #include <linux/highmem.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/seq_file.h> | ||
20 | #include <linux/scatterlist.h> | ||
21 | #include <linux/bitmap.h> | ||
22 | |||
23 | #include <asm/sections.h> | ||
24 | #include <asm/page.h> | ||
25 | #include <asm/pgalloc.h> | ||
26 | #include <asm/pgtable.h> | ||
27 | #include <asm/vaddrs.h> | ||
28 | #include <asm/idprom.h> | ||
29 | #include <asm/machines.h> | ||
30 | #include <asm/memreg.h> | ||
31 | #include <asm/processor.h> | ||
32 | #include <asm/auxio.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/oplib.h> | ||
35 | #include <asm/openprom.h> | ||
36 | #include <asm/mmu_context.h> | ||
37 | #include <asm/highmem.h> | ||
38 | #include <asm/btfixup.h> | ||
39 | #include <asm/cacheflush.h> | ||
40 | #include <asm/tlbflush.h> | ||
41 | |||
42 | /* Because of our dynamic kernel TLB miss strategy, and how | ||
43 | * our DVMA mapping allocation works, you _MUST_: | ||
44 | * | ||
45 | * 1) Disable interrupts _and_ not touch any dynamic kernel | ||
46 | * memory while messing with kernel MMU state. By | ||
47 | * dynamic memory I mean any object which is not in | ||
48 | * the kernel image itself or a thread_union (both of | ||
49 | * which are locked into the MMU). | ||
50 | * 2) Disable interrupts while messing with user MMU state. | ||
51 | */ | ||
52 | |||
53 | extern int num_segmaps, num_contexts; | ||
54 | |||
55 | extern unsigned long page_kernel; | ||
56 | |||
57 | /* That's it, we prom_halt() on sun4c if the cache size is something other than 65536. | ||
58 | * So let's save some cycles and just use that everywhere except for that bootup | ||
59 | * sanity check. | ||
60 | */ | ||
61 | #define SUN4C_VAC_SIZE 65536 | ||
62 | |||
63 | #define SUN4C_KERNEL_BUCKETS 32 | ||
64 | |||
65 | /* Flushing the cache. */ | ||
66 | struct sun4c_vac_props sun4c_vacinfo; | ||
67 | unsigned long sun4c_kernel_faults; | ||
68 | |||
69 | /* Invalidate every sun4c cache line tag. */ | ||
70 | static void __init sun4c_flush_all(void) | ||
71 | { | ||
72 | unsigned long begin, end; | ||
73 | |||
74 | if (sun4c_vacinfo.on) | ||
75 | panic("SUN4C: AIEEE, trying to invalidate vac while it is on."); | ||
76 | |||
77 | /* Clear 'valid' bit in all cache line tags */ | ||
78 | begin = AC_CACHETAGS; | ||
79 | end = (AC_CACHETAGS + SUN4C_VAC_SIZE); | ||
80 | while (begin < end) { | ||
81 | __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : | ||
82 | "r" (begin), "i" (ASI_CONTROL)); | ||
83 | begin += sun4c_vacinfo.linesize; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static void sun4c_flush_context_hw(void) | ||
88 | { | ||
89 | unsigned long end = SUN4C_VAC_SIZE; | ||
90 | |||
91 | __asm__ __volatile__( | ||
92 | "1: addcc %0, -4096, %0\n\t" | ||
93 | " bne 1b\n\t" | ||
94 | " sta %%g0, [%0] %2" | ||
95 | : "=&r" (end) | ||
96 | : "0" (end), "i" (ASI_HWFLUSHCONTEXT) | ||
97 | : "cc"); | ||
98 | } | ||
99 | |||
100 | /* Must be called minimally with IRQs disabled. */ | ||
101 | static void sun4c_flush_segment_hw(unsigned long addr) | ||
102 | { | ||
103 | if (sun4c_get_segmap(addr) != invalid_segment) { | ||
104 | unsigned long vac_size = SUN4C_VAC_SIZE; | ||
105 | |||
106 | __asm__ __volatile__( | ||
107 | "1: addcc %0, -4096, %0\n\t" | ||
108 | " bne 1b\n\t" | ||
109 | " sta %%g0, [%2 + %0] %3" | ||
110 | : "=&r" (vac_size) | ||
111 | : "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG) | ||
112 | : "cc"); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* File local boot time fixups. */ | ||
117 | BTFIXUPDEF_CALL(void, sun4c_flush_page, unsigned long) | ||
118 | BTFIXUPDEF_CALL(void, sun4c_flush_segment, unsigned long) | ||
119 | BTFIXUPDEF_CALL(void, sun4c_flush_context, void) | ||
120 | |||
121 | #define sun4c_flush_page(addr) BTFIXUP_CALL(sun4c_flush_page)(addr) | ||
122 | #define sun4c_flush_segment(addr) BTFIXUP_CALL(sun4c_flush_segment)(addr) | ||
123 | #define sun4c_flush_context() BTFIXUP_CALL(sun4c_flush_context)() | ||
124 | |||
125 | /* Must be called minimally with interrupts disabled. */ | ||
126 | static void sun4c_flush_page_hw(unsigned long addr) | ||
127 | { | ||
128 | addr &= PAGE_MASK; | ||
129 | if ((int)sun4c_get_pte(addr) < 0) | ||
130 | __asm__ __volatile__("sta %%g0, [%0] %1" | ||
131 | : : "r" (addr), "i" (ASI_HWFLUSHPAGE)); | ||
132 | } | ||
133 | |||
134 | /* Don't inline the software version as it eats too many cache lines if expanded. */ | ||
135 | static void sun4c_flush_context_sw(void) | ||
136 | { | ||
137 | unsigned long nbytes = SUN4C_VAC_SIZE; | ||
138 | unsigned long lsize = sun4c_vacinfo.linesize; | ||
139 | |||
140 | __asm__ __volatile__( | ||
141 | "add %2, %2, %%g1\n\t" | ||
142 | "add %2, %%g1, %%g2\n\t" | ||
143 | "add %2, %%g2, %%g3\n\t" | ||
144 | "add %2, %%g3, %%g4\n\t" | ||
145 | "add %2, %%g4, %%g5\n\t" | ||
146 | "add %2, %%g5, %%o4\n\t" | ||
147 | "add %2, %%o4, %%o5\n" | ||
148 | "1:\n\t" | ||
149 | "subcc %0, %%o5, %0\n\t" | ||
150 | "sta %%g0, [%0] %3\n\t" | ||
151 | "sta %%g0, [%0 + %2] %3\n\t" | ||
152 | "sta %%g0, [%0 + %%g1] %3\n\t" | ||
153 | "sta %%g0, [%0 + %%g2] %3\n\t" | ||
154 | "sta %%g0, [%0 + %%g3] %3\n\t" | ||
155 | "sta %%g0, [%0 + %%g4] %3\n\t" | ||
156 | "sta %%g0, [%0 + %%g5] %3\n\t" | ||
157 | "bg 1b\n\t" | ||
158 | " sta %%g0, [%1 + %%o4] %3\n" | ||
159 | : "=&r" (nbytes) | ||
160 | : "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX) | ||
161 | : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); | ||
162 | } | ||
163 | |||
164 | /* Don't inline the software version as it eats too many cache lines if expanded. */ | ||
165 | static void sun4c_flush_segment_sw(unsigned long addr) | ||
166 | { | ||
167 | if (sun4c_get_segmap(addr) != invalid_segment) { | ||
168 | unsigned long nbytes = SUN4C_VAC_SIZE; | ||
169 | unsigned long lsize = sun4c_vacinfo.linesize; | ||
170 | |||
171 | __asm__ __volatile__( | ||
172 | "add %2, %2, %%g1\n\t" | ||
173 | "add %2, %%g1, %%g2\n\t" | ||
174 | "add %2, %%g2, %%g3\n\t" | ||
175 | "add %2, %%g3, %%g4\n\t" | ||
176 | "add %2, %%g4, %%g5\n\t" | ||
177 | "add %2, %%g5, %%o4\n\t" | ||
178 | "add %2, %%o4, %%o5\n" | ||
179 | "1:\n\t" | ||
180 | "subcc %1, %%o5, %1\n\t" | ||
181 | "sta %%g0, [%0] %6\n\t" | ||
182 | "sta %%g0, [%0 + %2] %6\n\t" | ||
183 | "sta %%g0, [%0 + %%g1] %6\n\t" | ||
184 | "sta %%g0, [%0 + %%g2] %6\n\t" | ||
185 | "sta %%g0, [%0 + %%g3] %6\n\t" | ||
186 | "sta %%g0, [%0 + %%g4] %6\n\t" | ||
187 | "sta %%g0, [%0 + %%g5] %6\n\t" | ||
188 | "sta %%g0, [%0 + %%o4] %6\n\t" | ||
189 | "bg 1b\n\t" | ||
190 | " add %0, %%o5, %0\n" | ||
191 | : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize) | ||
192 | : "0" (addr), "1" (nbytes), "2" (lsize), | ||
193 | "i" (ASI_FLUSHSEG) | ||
194 | : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /* Don't inline the software version as it eats too many cache lines if expanded. */ | ||
199 | static void sun4c_flush_page_sw(unsigned long addr) | ||
200 | { | ||
201 | addr &= PAGE_MASK; | ||
202 | if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) == | ||
203 | _SUN4C_PAGE_VALID) { | ||
204 | unsigned long left = PAGE_SIZE; | ||
205 | unsigned long lsize = sun4c_vacinfo.linesize; | ||
206 | |||
207 | __asm__ __volatile__( | ||
208 | "add %2, %2, %%g1\n\t" | ||
209 | "add %2, %%g1, %%g2\n\t" | ||
210 | "add %2, %%g2, %%g3\n\t" | ||
211 | "add %2, %%g3, %%g4\n\t" | ||
212 | "add %2, %%g4, %%g5\n\t" | ||
213 | "add %2, %%g5, %%o4\n\t" | ||
214 | "add %2, %%o4, %%o5\n" | ||
215 | "1:\n\t" | ||
216 | "subcc %1, %%o5, %1\n\t" | ||
217 | "sta %%g0, [%0] %6\n\t" | ||
218 | "sta %%g0, [%0 + %2] %6\n\t" | ||
219 | "sta %%g0, [%0 + %%g1] %6\n\t" | ||
220 | "sta %%g0, [%0 + %%g2] %6\n\t" | ||
221 | "sta %%g0, [%0 + %%g3] %6\n\t" | ||
222 | "sta %%g0, [%0 + %%g4] %6\n\t" | ||
223 | "sta %%g0, [%0 + %%g5] %6\n\t" | ||
224 | "sta %%g0, [%0 + %%o4] %6\n\t" | ||
225 | "bg 1b\n\t" | ||
226 | " add %0, %%o5, %0\n" | ||
227 | : "=&r" (addr), "=&r" (left), "=&r" (lsize) | ||
228 | : "0" (addr), "1" (left), "2" (lsize), | ||
229 | "i" (ASI_FLUSHPG) | ||
230 | : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | /* The sun4c's do have an on chip store buffer. And the way you | ||
235 | * clear them out isn't so obvious. The only way I can think of | ||
236 | * to accomplish this is to read the current context register, | ||
237 | * store the same value there, then read an external hardware | ||
238 | * register. | ||
239 | */ | ||
240 | void sun4c_complete_all_stores(void) | ||
241 | { | ||
242 | volatile int _unused; | ||
243 | |||
244 | _unused = sun4c_get_context(); | ||
245 | sun4c_set_context(_unused); | ||
246 | _unused = get_auxio(); | ||
247 | } | ||
248 | |||
249 | /* Bootup utility functions. */ | ||
250 | static inline void sun4c_init_clean_segmap(unsigned char pseg) | ||
251 | { | ||
252 | unsigned long vaddr; | ||
253 | |||
254 | sun4c_put_segmap(0, pseg); | ||
255 | for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE) | ||
256 | sun4c_put_pte(vaddr, 0); | ||
257 | sun4c_put_segmap(0, invalid_segment); | ||
258 | } | ||
259 | |||
260 | static inline void sun4c_init_clean_mmu(unsigned long kernel_end) | ||
261 | { | ||
262 | unsigned long vaddr; | ||
263 | unsigned char savectx, ctx; | ||
264 | |||
265 | savectx = sun4c_get_context(); | ||
266 | for (ctx = 0; ctx < num_contexts; ctx++) { | ||
267 | sun4c_set_context(ctx); | ||
268 | for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE) | ||
269 | sun4c_put_segmap(vaddr, invalid_segment); | ||
270 | for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE) | ||
271 | sun4c_put_segmap(vaddr, invalid_segment); | ||
272 | for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE) | ||
273 | sun4c_put_segmap(vaddr, invalid_segment); | ||
274 | for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE) | ||
275 | sun4c_put_segmap(vaddr, invalid_segment); | ||
276 | } | ||
277 | sun4c_set_context(savectx); | ||
278 | } | ||
279 | |||
280 | void __init sun4c_probe_vac(void) | ||
281 | { | ||
282 | sun4c_disable_vac(); | ||
283 | |||
284 | if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || | ||
285 | (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { | ||
286 | /* PROM on SS1 lacks this info, to be super safe we | ||
287 | * hard code it here since this arch is cast in stone. | ||
288 | */ | ||
289 | sun4c_vacinfo.num_bytes = 65536; | ||
290 | sun4c_vacinfo.linesize = 16; | ||
291 | } else { | ||
292 | sun4c_vacinfo.num_bytes = | ||
293 | prom_getintdefault(prom_root_node, "vac-size", 65536); | ||
294 | sun4c_vacinfo.linesize = | ||
295 | prom_getintdefault(prom_root_node, "vac-linesize", 16); | ||
296 | } | ||
297 | sun4c_vacinfo.do_hwflushes = | ||
298 | prom_getintdefault(prom_root_node, "vac-hwflush", 0); | ||
299 | |||
300 | if (sun4c_vacinfo.do_hwflushes == 0) | ||
301 | sun4c_vacinfo.do_hwflushes = | ||
302 | prom_getintdefault(prom_root_node, "vac_hwflush", 0); | ||
303 | |||
304 | if (sun4c_vacinfo.num_bytes != 65536) { | ||
305 | prom_printf("WEIRD Sun4C VAC cache size, " | ||
306 | "tell sparclinux@vger.kernel.org"); | ||
307 | prom_halt(); | ||
308 | } | ||
309 | |||
310 | switch (sun4c_vacinfo.linesize) { | ||
311 | case 16: | ||
312 | sun4c_vacinfo.log2lsize = 4; | ||
313 | break; | ||
314 | case 32: | ||
315 | sun4c_vacinfo.log2lsize = 5; | ||
316 | break; | ||
317 | default: | ||
318 | prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n", | ||
319 | sun4c_vacinfo.linesize); | ||
320 | prom_halt(); | ||
321 | } | ||
322 | |||
323 | sun4c_flush_all(); | ||
324 | sun4c_enable_vac(); | ||
325 | } | ||
326 | |||
327 | /* Patch instructions for the low level kernel fault handler. */ | ||
328 | extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff; | ||
329 | extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff; | ||
330 | extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff; | ||
331 | extern unsigned long num_context_patch1, num_context_patch1_16; | ||
332 | extern unsigned long num_context_patch2_16; | ||
333 | extern unsigned long vac_linesize_patch, vac_linesize_patch_32; | ||
334 | extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on; | ||
335 | extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on; | ||
336 | |||
337 | #define PATCH_INSN(src, dst) do { \ | ||
338 | daddr = &(dst); \ | ||
339 | iaddr = &(src); \ | ||
340 | *daddr = *iaddr; \ | ||
341 | } while (0) | ||
342 | |||
343 | static void __init patch_kernel_fault_handler(void) | ||
344 | { | ||
345 | unsigned long *iaddr, *daddr; | ||
346 | |||
347 | switch (num_segmaps) { | ||
348 | case 128: | ||
349 | /* Default, nothing to do. */ | ||
350 | break; | ||
351 | case 256: | ||
352 | PATCH_INSN(invalid_segment_patch1_ff, | ||
353 | invalid_segment_patch1); | ||
354 | PATCH_INSN(invalid_segment_patch2_ff, | ||
355 | invalid_segment_patch2); | ||
356 | break; | ||
357 | case 512: | ||
358 | PATCH_INSN(invalid_segment_patch1_1ff, | ||
359 | invalid_segment_patch1); | ||
360 | PATCH_INSN(invalid_segment_patch2_1ff, | ||
361 | invalid_segment_patch2); | ||
362 | break; | ||
363 | default: | ||
364 | prom_printf("Unhandled number of segmaps: %d\n", | ||
365 | num_segmaps); | ||
366 | prom_halt(); | ||
367 | } | ||
368 | switch (num_contexts) { | ||
369 | case 8: | ||
370 | /* Default, nothing to do. */ | ||
371 | break; | ||
372 | case 16: | ||
373 | PATCH_INSN(num_context_patch1_16, | ||
374 | num_context_patch1); | ||
375 | break; | ||
376 | default: | ||
377 | prom_printf("Unhandled number of contexts: %d\n", | ||
378 | num_contexts); | ||
379 | prom_halt(); | ||
380 | } | ||
381 | |||
382 | if (sun4c_vacinfo.do_hwflushes != 0) { | ||
383 | PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1); | ||
384 | PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2); | ||
385 | } else { | ||
386 | switch (sun4c_vacinfo.linesize) { | ||
387 | case 16: | ||
388 | /* Default, nothing to do. */ | ||
389 | break; | ||
390 | case 32: | ||
391 | PATCH_INSN(vac_linesize_patch_32, vac_linesize_patch); | ||
392 | break; | ||
393 | default: | ||
394 | prom_printf("Impossible VAC linesize %d, halting...\n", | ||
395 | sun4c_vacinfo.linesize); | ||
396 | prom_halt(); | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | static void __init sun4c_probe_mmu(void) | ||
402 | { | ||
403 | if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || | ||
404 | (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { | ||
405 | /* Hardcode these just to be safe, PROM on SS1 does | ||
406 | * not have this info available in the root node. | ||
407 | */ | ||
408 | num_segmaps = 128; | ||
409 | num_contexts = 8; | ||
410 | } else { | ||
411 | num_segmaps = | ||
412 | prom_getintdefault(prom_root_node, "mmu-npmg", 128); | ||
413 | num_contexts = | ||
414 | prom_getintdefault(prom_root_node, "mmu-nctx", 0x8); | ||
415 | } | ||
416 | patch_kernel_fault_handler(); | ||
417 | } | ||
418 | |||
419 | volatile unsigned long __iomem *sun4c_memerr_reg = NULL; | ||
420 | |||
421 | void __init sun4c_probe_memerr_reg(void) | ||
422 | { | ||
423 | phandle node; | ||
424 | struct linux_prom_registers regs[1]; | ||
425 | |||
426 | node = prom_getchild(prom_root_node); | ||
427 | node = prom_searchsiblings(prom_root_node, "memory-error"); | ||
428 | if (!node) | ||
429 | return; | ||
430 | if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0) | ||
431 | return; | ||
432 | /* hmm I think regs[0].which_io is zero here anyways */ | ||
433 | sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size); | ||
434 | } | ||
435 | |||
436 | static inline void sun4c_init_ss2_cache_bug(void) | ||
437 | { | ||
438 | if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) || | ||
439 | (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) || | ||
440 | (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) { | ||
441 | /* Whee.. */ | ||
442 | printk("SS2 cache bug detected, uncaching trap table page\n"); | ||
443 | sun4c_flush_page((unsigned int) &_start); | ||
444 | sun4c_put_pte(((unsigned long) &_start), | ||
445 | (sun4c_get_pte((unsigned long) &_start) | _SUN4C_PAGE_NOCACHE)); | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* Addr is always aligned on a page boundary for us already. */ | ||
450 | static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, | ||
451 | unsigned long addr, int len) | ||
452 | { | ||
453 | unsigned long page, end; | ||
454 | |||
455 | *pba = addr; | ||
456 | |||
457 | end = PAGE_ALIGN((addr + len)); | ||
458 | while (addr < end) { | ||
459 | page = va; | ||
460 | sun4c_flush_page(page); | ||
461 | page -= PAGE_OFFSET; | ||
462 | page >>= PAGE_SHIFT; | ||
463 | page |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_DIRTY | | ||
464 | _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV); | ||
465 | sun4c_put_pte(addr, page); | ||
466 | addr += PAGE_SIZE; | ||
467 | va += PAGE_SIZE; | ||
468 | } | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len) | ||
474 | { | ||
475 | /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ | ||
476 | /* XXX Implement this */ | ||
477 | } | ||
478 | |||
479 | /* TLB management. */ | ||
480 | |||
481 | /* Don't change this struct without changing entry.S. This is used | ||
482 | * in the in-window kernel fault handler, and you don't want to mess | ||
483 | * with that. (See sun4c_fault in entry.S). | ||
484 | */ | ||
485 | struct sun4c_mmu_entry { | ||
486 | struct sun4c_mmu_entry *next; | ||
487 | struct sun4c_mmu_entry *prev; | ||
488 | unsigned long vaddr; | ||
489 | unsigned char pseg; | ||
490 | unsigned char locked; | ||
491 | |||
492 | /* For user mappings only, and completely hidden from kernel | ||
493 | * TLB miss code. | ||
494 | */ | ||
495 | unsigned char ctx; | ||
496 | struct sun4c_mmu_entry *lru_next; | ||
497 | struct sun4c_mmu_entry *lru_prev; | ||
498 | }; | ||
499 | |||
500 | static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS]; | ||
501 | |||
502 | static void __init sun4c_init_mmu_entry_pool(void) | ||
503 | { | ||
504 | int i; | ||
505 | |||
506 | for (i=0; i < SUN4C_MAX_SEGMAPS; i++) { | ||
507 | mmu_entry_pool[i].pseg = i; | ||
508 | mmu_entry_pool[i].next = NULL; | ||
509 | mmu_entry_pool[i].prev = NULL; | ||
510 | mmu_entry_pool[i].vaddr = 0; | ||
511 | mmu_entry_pool[i].locked = 0; | ||
512 | mmu_entry_pool[i].ctx = 0; | ||
513 | mmu_entry_pool[i].lru_next = NULL; | ||
514 | mmu_entry_pool[i].lru_prev = NULL; | ||
515 | } | ||
516 | mmu_entry_pool[invalid_segment].locked = 1; | ||
517 | } | ||
518 | |||
519 | static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on, | ||
520 | unsigned long bits_off) | ||
521 | { | ||
522 | unsigned long start, end; | ||
523 | |||
524 | end = vaddr + SUN4C_REAL_PGDIR_SIZE; | ||
525 | for (start = vaddr; start < end; start += PAGE_SIZE) | ||
526 | if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID) | ||
527 | sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) & | ||
528 | ~bits_off); | ||
529 | } | ||
530 | |||
531 | static inline void sun4c_init_map_kernelprom(unsigned long kernel_end) | ||
532 | { | ||
533 | unsigned long vaddr; | ||
534 | unsigned char pseg, ctx; | ||
535 | |||
536 | for (vaddr = KADB_DEBUGGER_BEGVM; | ||
537 | vaddr < LINUX_OPPROM_ENDVM; | ||
538 | vaddr += SUN4C_REAL_PGDIR_SIZE) { | ||
539 | pseg = sun4c_get_segmap(vaddr); | ||
540 | if (pseg != invalid_segment) { | ||
541 | mmu_entry_pool[pseg].locked = 1; | ||
542 | for (ctx = 0; ctx < num_contexts; ctx++) | ||
543 | prom_putsegment(ctx, vaddr, pseg); | ||
544 | fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) { | ||
549 | pseg = sun4c_get_segmap(vaddr); | ||
550 | mmu_entry_pool[pseg].locked = 1; | ||
551 | for (ctx = 0; ctx < num_contexts; ctx++) | ||
552 | prom_putsegment(ctx, vaddr, pseg); | ||
553 | fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE); | ||
554 | } | ||
555 | } | ||
556 | |||
557 | static void __init sun4c_init_lock_area(unsigned long start, unsigned long end) | ||
558 | { | ||
559 | int i, ctx; | ||
560 | |||
561 | while (start < end) { | ||
562 | for (i = 0; i < invalid_segment; i++) | ||
563 | if (!mmu_entry_pool[i].locked) | ||
564 | break; | ||
565 | mmu_entry_pool[i].locked = 1; | ||
566 | sun4c_init_clean_segmap(i); | ||
567 | for (ctx = 0; ctx < num_contexts; ctx++) | ||
568 | prom_putsegment(ctx, start, mmu_entry_pool[i].pseg); | ||
569 | start += SUN4C_REAL_PGDIR_SIZE; | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* Don't change this struct without changing entry.S. This is used | ||
574 | * in the in-window kernel fault handler, and you don't want to mess | ||
575 | * with that. (See sun4c_fault in entry.S). | ||
576 | */ | ||
577 | struct sun4c_mmu_ring { | ||
578 | struct sun4c_mmu_entry ringhd; | ||
579 | int num_entries; | ||
580 | }; | ||
581 | |||
582 | static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */ | ||
583 | static struct sun4c_mmu_ring sun4c_ufree_ring; /* free user entries */ | ||
584 | static struct sun4c_mmu_ring sun4c_ulru_ring; /* LRU user entries */ | ||
585 | struct sun4c_mmu_ring sun4c_kernel_ring; /* used kernel entries */ | ||
586 | struct sun4c_mmu_ring sun4c_kfree_ring; /* free kernel entries */ | ||
587 | |||
588 | static inline void sun4c_init_rings(void) | ||
589 | { | ||
590 | int i; | ||
591 | |||
592 | for (i = 0; i < SUN4C_MAX_CONTEXTS; i++) { | ||
593 | sun4c_context_ring[i].ringhd.next = | ||
594 | sun4c_context_ring[i].ringhd.prev = | ||
595 | &sun4c_context_ring[i].ringhd; | ||
596 | sun4c_context_ring[i].num_entries = 0; | ||
597 | } | ||
598 | sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev = | ||
599 | &sun4c_ufree_ring.ringhd; | ||
600 | sun4c_ufree_ring.num_entries = 0; | ||
601 | sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev = | ||
602 | &sun4c_ulru_ring.ringhd; | ||
603 | sun4c_ulru_ring.num_entries = 0; | ||
604 | sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev = | ||
605 | &sun4c_kernel_ring.ringhd; | ||
606 | sun4c_kernel_ring.num_entries = 0; | ||
607 | sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev = | ||
608 | &sun4c_kfree_ring.ringhd; | ||
609 | sun4c_kfree_ring.num_entries = 0; | ||
610 | } | ||
611 | |||
612 | static void add_ring(struct sun4c_mmu_ring *ring, | ||
613 | struct sun4c_mmu_entry *entry) | ||
614 | { | ||
615 | struct sun4c_mmu_entry *head = &ring->ringhd; | ||
616 | |||
617 | entry->prev = head; | ||
618 | (entry->next = head->next)->prev = entry; | ||
619 | head->next = entry; | ||
620 | ring->num_entries++; | ||
621 | } | ||
622 | |||
623 | static inline void add_lru(struct sun4c_mmu_entry *entry) | ||
624 | { | ||
625 | struct sun4c_mmu_ring *ring = &sun4c_ulru_ring; | ||
626 | struct sun4c_mmu_entry *head = &ring->ringhd; | ||
627 | |||
628 | entry->lru_next = head; | ||
629 | (entry->lru_prev = head->lru_prev)->lru_next = entry; | ||
630 | head->lru_prev = entry; | ||
631 | } | ||
632 | |||
633 | static void add_ring_ordered(struct sun4c_mmu_ring *ring, | ||
634 | struct sun4c_mmu_entry *entry) | ||
635 | { | ||
636 | struct sun4c_mmu_entry *head = &ring->ringhd; | ||
637 | unsigned long addr = entry->vaddr; | ||
638 | |||
639 | while ((head->next != &ring->ringhd) && (head->next->vaddr < addr)) | ||
640 | head = head->next; | ||
641 | |||
642 | entry->prev = head; | ||
643 | (entry->next = head->next)->prev = entry; | ||
644 | head->next = entry; | ||
645 | ring->num_entries++; | ||
646 | |||
647 | add_lru(entry); | ||
648 | } | ||
649 | |||
650 | static inline void remove_ring(struct sun4c_mmu_ring *ring, | ||
651 | struct sun4c_mmu_entry *entry) | ||
652 | { | ||
653 | struct sun4c_mmu_entry *next = entry->next; | ||
654 | |||
655 | (next->prev = entry->prev)->next = next; | ||
656 | ring->num_entries--; | ||
657 | } | ||
658 | |||
659 | static void remove_lru(struct sun4c_mmu_entry *entry) | ||
660 | { | ||
661 | struct sun4c_mmu_entry *next = entry->lru_next; | ||
662 | |||
663 | (next->lru_prev = entry->lru_prev)->lru_next = next; | ||
664 | } | ||
665 | |||
666 | static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry) | ||
667 | { | ||
668 | remove_ring(sun4c_context_ring+ctx, entry); | ||
669 | remove_lru(entry); | ||
670 | add_ring(&sun4c_ufree_ring, entry); | ||
671 | } | ||
672 | |||
673 | static void free_kernel_entry(struct sun4c_mmu_entry *entry, | ||
674 | struct sun4c_mmu_ring *ring) | ||
675 | { | ||
676 | remove_ring(ring, entry); | ||
677 | add_ring(&sun4c_kfree_ring, entry); | ||
678 | } | ||
679 | |||
680 | static void __init sun4c_init_fill_kernel_ring(int howmany) | ||
681 | { | ||
682 | int i; | ||
683 | |||
684 | while (howmany) { | ||
685 | for (i = 0; i < invalid_segment; i++) | ||
686 | if (!mmu_entry_pool[i].locked) | ||
687 | break; | ||
688 | mmu_entry_pool[i].locked = 1; | ||
689 | sun4c_init_clean_segmap(i); | ||
690 | add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]); | ||
691 | howmany--; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | static void __init sun4c_init_fill_user_ring(void) | ||
696 | { | ||
697 | int i; | ||
698 | |||
699 | for (i = 0; i < invalid_segment; i++) { | ||
700 | if (mmu_entry_pool[i].locked) | ||
701 | continue; | ||
702 | sun4c_init_clean_segmap(i); | ||
703 | add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry) | ||
708 | { | ||
709 | int savectx, ctx; | ||
710 | |||
711 | savectx = sun4c_get_context(); | ||
712 | for (ctx = 0; ctx < num_contexts; ctx++) { | ||
713 | sun4c_set_context(ctx); | ||
714 | sun4c_put_segmap(kentry->vaddr, invalid_segment); | ||
715 | } | ||
716 | sun4c_set_context(savectx); | ||
717 | } | ||
718 | |||
719 | static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry) | ||
720 | { | ||
721 | int savectx, ctx; | ||
722 | |||
723 | savectx = sun4c_get_context(); | ||
724 | for (ctx = 0; ctx < num_contexts; ctx++) { | ||
725 | sun4c_set_context(ctx); | ||
726 | sun4c_put_segmap(kentry->vaddr, kentry->pseg); | ||
727 | } | ||
728 | sun4c_set_context(savectx); | ||
729 | } | ||
730 | |||
731 | #define sun4c_user_unmap(__entry) \ | ||
732 | sun4c_put_segmap((__entry)->vaddr, invalid_segment) | ||
733 | |||
734 | static void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx) | ||
735 | { | ||
736 | struct sun4c_mmu_entry *head = &crp->ringhd; | ||
737 | unsigned long flags; | ||
738 | |||
739 | local_irq_save(flags); | ||
740 | if (head->next != head) { | ||
741 | struct sun4c_mmu_entry *entry = head->next; | ||
742 | int savectx = sun4c_get_context(); | ||
743 | |||
744 | flush_user_windows(); | ||
745 | sun4c_set_context(ctx); | ||
746 | sun4c_flush_context(); | ||
747 | do { | ||
748 | struct sun4c_mmu_entry *next = entry->next; | ||
749 | |||
750 | sun4c_user_unmap(entry); | ||
751 | free_user_entry(ctx, entry); | ||
752 | |||
753 | entry = next; | ||
754 | } while (entry != head); | ||
755 | sun4c_set_context(savectx); | ||
756 | } | ||
757 | local_irq_restore(flags); | ||
758 | } | ||
759 | |||
760 | static int sun4c_user_taken_entries; /* This is how much we have. */ | ||
761 | static int max_user_taken_entries; /* This limits us and prevents deadlock. */ | ||
762 | |||
763 | static struct sun4c_mmu_entry *sun4c_kernel_strategy(void) | ||
764 | { | ||
765 | struct sun4c_mmu_entry *this_entry; | ||
766 | |||
767 | /* If some are free, return first one. */ | ||
768 | if (sun4c_kfree_ring.num_entries) { | ||
769 | this_entry = sun4c_kfree_ring.ringhd.next; | ||
770 | return this_entry; | ||
771 | } | ||
772 | |||
773 | /* Else free one up. */ | ||
774 | this_entry = sun4c_kernel_ring.ringhd.prev; | ||
775 | sun4c_flush_segment(this_entry->vaddr); | ||
776 | sun4c_kernel_unmap(this_entry); | ||
777 | free_kernel_entry(this_entry, &sun4c_kernel_ring); | ||
778 | this_entry = sun4c_kfree_ring.ringhd.next; | ||
779 | |||
780 | return this_entry; | ||
781 | } | ||
782 | |||
783 | /* Using this method to free up mmu entries eliminates a lot of | ||
784 | * potential races since we have a kernel that incurs tlb | ||
785 | * replacement faults. There may be performance penalties. | ||
786 | * | ||
787 | * NOTE: Must be called with interrupts disabled. | ||
788 | */ | ||
789 | static struct sun4c_mmu_entry *sun4c_user_strategy(void) | ||
790 | { | ||
791 | struct sun4c_mmu_entry *entry; | ||
792 | unsigned char ctx; | ||
793 | int savectx; | ||
794 | |||
795 | /* If some are free, return first one. */ | ||
796 | if (sun4c_ufree_ring.num_entries) { | ||
797 | entry = sun4c_ufree_ring.ringhd.next; | ||
798 | goto unlink_out; | ||
799 | } | ||
800 | |||
801 | if (sun4c_user_taken_entries) { | ||
802 | entry = sun4c_kernel_strategy(); | ||
803 | sun4c_user_taken_entries--; | ||
804 | goto kunlink_out; | ||
805 | } | ||
806 | |||
807 | /* Grab from the beginning of the LRU list. */ | ||
808 | entry = sun4c_ulru_ring.ringhd.lru_next; | ||
809 | ctx = entry->ctx; | ||
810 | |||
811 | savectx = sun4c_get_context(); | ||
812 | flush_user_windows(); | ||
813 | sun4c_set_context(ctx); | ||
814 | sun4c_flush_segment(entry->vaddr); | ||
815 | sun4c_user_unmap(entry); | ||
816 | remove_ring(sun4c_context_ring + ctx, entry); | ||
817 | remove_lru(entry); | ||
818 | sun4c_set_context(savectx); | ||
819 | |||
820 | return entry; | ||
821 | |||
822 | unlink_out: | ||
823 | remove_ring(&sun4c_ufree_ring, entry); | ||
824 | return entry; | ||
825 | kunlink_out: | ||
826 | remove_ring(&sun4c_kfree_ring, entry); | ||
827 | return entry; | ||
828 | } | ||
829 | |||
830 | /* NOTE: Must be called with interrupts disabled. */ | ||
831 | void sun4c_grow_kernel_ring(void) | ||
832 | { | ||
833 | struct sun4c_mmu_entry *entry; | ||
834 | |||
835 | /* Prevent deadlock condition. */ | ||
836 | if (sun4c_user_taken_entries >= max_user_taken_entries) | ||
837 | return; | ||
838 | |||
839 | if (sun4c_ufree_ring.num_entries) { | ||
840 | entry = sun4c_ufree_ring.ringhd.next; | ||
841 | remove_ring(&sun4c_ufree_ring, entry); | ||
842 | add_ring(&sun4c_kfree_ring, entry); | ||
843 | sun4c_user_taken_entries++; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | /* 2 page buckets for task struct and kernel stack allocation. | ||
848 | * | ||
849 | * TASK_STACK_BEGIN | ||
850 | * bucket[0] | ||
851 | * bucket[1] | ||
852 | * [ ... ] | ||
853 | * bucket[NR_TASK_BUCKETS-1] | ||
854 | * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASK_BUCKETS) | ||
855 | * | ||
856 | * Each slot looks like: | ||
857 | * | ||
858 | * page 1 -- task struct + beginning of kernel stack | ||
859 | * page 2 -- rest of kernel stack | ||
860 | */ | ||
861 | |||
862 | union task_union *sun4c_bucket[NR_TASK_BUCKETS]; | ||
863 | |||
864 | static int sun4c_lowbucket_avail; | ||
865 | |||
866 | #define BUCKET_EMPTY ((union task_union *) 0) | ||
867 | #define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */ | ||
868 | #define BUCKET_SIZE (1 << BUCKET_SHIFT) | ||
869 | #define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT)) | ||
870 | #define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR) | ||
871 | #define BUCKET_PTE(page) \ | ||
872 | ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL)) | ||
873 | #define BUCKET_PTE_PAGE(pte) \ | ||
874 | (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT)) | ||
875 | |||
876 | static void get_locked_segment(unsigned long addr) | ||
877 | { | ||
878 | struct sun4c_mmu_entry *stolen; | ||
879 | unsigned long flags; | ||
880 | |||
881 | local_irq_save(flags); | ||
882 | addr &= SUN4C_REAL_PGDIR_MASK; | ||
883 | stolen = sun4c_user_strategy(); | ||
884 | max_user_taken_entries--; | ||
885 | stolen->vaddr = addr; | ||
886 | flush_user_windows(); | ||
887 | sun4c_kernel_map(stolen); | ||
888 | local_irq_restore(flags); | ||
889 | } | ||
890 | |||
891 | static void free_locked_segment(unsigned long addr) | ||
892 | { | ||
893 | struct sun4c_mmu_entry *entry; | ||
894 | unsigned long flags; | ||
895 | unsigned char pseg; | ||
896 | |||
897 | local_irq_save(flags); | ||
898 | addr &= SUN4C_REAL_PGDIR_MASK; | ||
899 | pseg = sun4c_get_segmap(addr); | ||
900 | entry = &mmu_entry_pool[pseg]; | ||
901 | |||
902 | flush_user_windows(); | ||
903 | sun4c_flush_segment(addr); | ||
904 | sun4c_kernel_unmap(entry); | ||
905 | add_ring(&sun4c_ufree_ring, entry); | ||
906 | max_user_taken_entries++; | ||
907 | local_irq_restore(flags); | ||
908 | } | ||
909 | |||
910 | static inline void garbage_collect(int entry) | ||
911 | { | ||
912 | int start, end; | ||
913 | |||
914 | /* 32 buckets per segment... */ | ||
915 | entry &= ~31; | ||
916 | start = entry; | ||
917 | for (end = (start + 32); start < end; start++) | ||
918 | if (sun4c_bucket[start] != BUCKET_EMPTY) | ||
919 | return; | ||
920 | |||
921 | /* Entire segment empty, release it. */ | ||
922 | free_locked_segment(BUCKET_ADDR(entry)); | ||
923 | } | ||
924 | |||
925 | static struct thread_info *sun4c_alloc_thread_info_node(int node) | ||
926 | { | ||
927 | unsigned long addr, pages; | ||
928 | int entry; | ||
929 | |||
930 | pages = __get_free_pages(GFP_KERNEL, THREAD_INFO_ORDER); | ||
931 | if (!pages) | ||
932 | return NULL; | ||
933 | |||
934 | for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++) | ||
935 | if (sun4c_bucket[entry] == BUCKET_EMPTY) | ||
936 | break; | ||
937 | if (entry == NR_TASK_BUCKETS) { | ||
938 | free_pages(pages, THREAD_INFO_ORDER); | ||
939 | return NULL; | ||
940 | } | ||
941 | if (entry >= sun4c_lowbucket_avail) | ||
942 | sun4c_lowbucket_avail = entry + 1; | ||
943 | |||
944 | addr = BUCKET_ADDR(entry); | ||
945 | sun4c_bucket[entry] = (union task_union *) addr; | ||
946 | if(sun4c_get_segmap(addr) == invalid_segment) | ||
947 | get_locked_segment(addr); | ||
948 | |||
949 | /* We are changing the virtual color of the page(s) | ||
950 | * so we must flush the cache to guarantee consistency. | ||
951 | */ | ||
952 | sun4c_flush_page(pages); | ||
953 | sun4c_flush_page(pages + PAGE_SIZE); | ||
954 | |||
955 | sun4c_put_pte(addr, BUCKET_PTE(pages)); | ||
956 | sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); | ||
957 | |||
958 | #ifdef CONFIG_DEBUG_STACK_USAGE | ||
959 | memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER); | ||
960 | #endif /* DEBUG_STACK_USAGE */ | ||
961 | |||
962 | return (struct thread_info *) addr; | ||
963 | } | ||
964 | |||
965 | static void sun4c_free_thread_info(struct thread_info *ti) | ||
966 | { | ||
967 | unsigned long tiaddr = (unsigned long) ti; | ||
968 | unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tiaddr)); | ||
969 | int entry = BUCKET_NUM(tiaddr); | ||
970 | |||
971 | /* We are deleting a mapping, so the flush here is mandatory. */ | ||
972 | sun4c_flush_page(tiaddr); | ||
973 | sun4c_flush_page(tiaddr + PAGE_SIZE); | ||
974 | |||
975 | sun4c_put_pte(tiaddr, 0); | ||
976 | sun4c_put_pte(tiaddr + PAGE_SIZE, 0); | ||
977 | |||
978 | sun4c_bucket[entry] = BUCKET_EMPTY; | ||
979 | if (entry < sun4c_lowbucket_avail) | ||
980 | sun4c_lowbucket_avail = entry; | ||
981 | |||
982 | free_pages(pages, THREAD_INFO_ORDER); | ||
983 | garbage_collect(entry); | ||
984 | } | ||
985 | |||
986 | static void __init sun4c_init_buckets(void) | ||
987 | { | ||
988 | int entry; | ||
989 | |||
990 | if (sizeof(union thread_union) != (PAGE_SIZE << THREAD_INFO_ORDER)) { | ||
991 | extern void thread_info_size_is_bolixed_pete(void); | ||
992 | thread_info_size_is_bolixed_pete(); | ||
993 | } | ||
994 | |||
995 | for (entry = 0; entry < NR_TASK_BUCKETS; entry++) | ||
996 | sun4c_bucket[entry] = BUCKET_EMPTY; | ||
997 | sun4c_lowbucket_avail = 0; | ||
998 | } | ||
999 | |||
1000 | static unsigned long sun4c_iobuffer_start; | ||
1001 | static unsigned long sun4c_iobuffer_end; | ||
1002 | static unsigned long sun4c_iobuffer_high; | ||
1003 | static unsigned long *sun4c_iobuffer_map; | ||
1004 | static int iobuffer_map_size; | ||
1005 | |||
1006 | /* | ||
1007 | * Alias our pages so they do not cause a trap. | ||
1008 | * Also one page may be aliased into several I/O areas and we may | ||
1009 | * finish these I/O separately. | ||
1010 | */ | ||
1011 | static char *sun4c_lockarea(char *vaddr, unsigned long size) | ||
1012 | { | ||
1013 | unsigned long base, scan; | ||
1014 | unsigned long npages; | ||
1015 | unsigned long vpage; | ||
1016 | unsigned long pte; | ||
1017 | unsigned long apage; | ||
1018 | unsigned long high; | ||
1019 | unsigned long flags; | ||
1020 | |||
1021 | npages = (((unsigned long)vaddr & ~PAGE_MASK) + | ||
1022 | size + (PAGE_SIZE-1)) >> PAGE_SHIFT; | ||
1023 | |||
1024 | local_irq_save(flags); | ||
1025 | base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size, | ||
1026 | 0, npages, 0); | ||
1027 | if (base >= iobuffer_map_size) | ||
1028 | goto abend; | ||
1029 | |||
1030 | high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start; | ||
1031 | high = SUN4C_REAL_PGDIR_ALIGN(high); | ||
1032 | while (high > sun4c_iobuffer_high) { | ||
1033 | get_locked_segment(sun4c_iobuffer_high); | ||
1034 | sun4c_iobuffer_high += SUN4C_REAL_PGDIR_SIZE; | ||
1035 | } | ||
1036 | |||
1037 | vpage = ((unsigned long) vaddr) & PAGE_MASK; | ||
1038 | for (scan = base; scan < base+npages; scan++) { | ||
1039 | pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT); | ||
1040 | pte |= pgprot_val(SUN4C_PAGE_KERNEL); | ||
1041 | pte |= _SUN4C_PAGE_NOCACHE; | ||
1042 | set_bit(scan, sun4c_iobuffer_map); | ||
1043 | apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start; | ||
1044 | |||
1045 | /* Flush original mapping so we see the right things later. */ | ||
1046 | sun4c_flush_page(vpage); | ||
1047 | |||
1048 | sun4c_put_pte(apage, pte); | ||
1049 | vpage += PAGE_SIZE; | ||
1050 | } | ||
1051 | local_irq_restore(flags); | ||
1052 | return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start + | ||
1053 | (((unsigned long) vaddr) & ~PAGE_MASK)); | ||
1054 | |||
1055 | abend: | ||
1056 | local_irq_restore(flags); | ||
1057 | printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size); | ||
1058 | panic("Out of iobuffer table"); | ||
1059 | return NULL; | ||
1060 | } | ||
1061 | |||
1062 | static void sun4c_unlockarea(char *vaddr, unsigned long size) | ||
1063 | { | ||
1064 | unsigned long vpage, npages; | ||
1065 | unsigned long flags; | ||
1066 | int scan, high; | ||
1067 | |||
1068 | vpage = (unsigned long)vaddr & PAGE_MASK; | ||
1069 | npages = (((unsigned long)vaddr & ~PAGE_MASK) + | ||
1070 | size + (PAGE_SIZE-1)) >> PAGE_SHIFT; | ||
1071 | |||
1072 | local_irq_save(flags); | ||
1073 | while (npages != 0) { | ||
1074 | --npages; | ||
1075 | |||
1076 | /* This mapping is marked non-cachable, no flush necessary. */ | ||
1077 | sun4c_put_pte(vpage, 0); | ||
1078 | clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT, | ||
1079 | sun4c_iobuffer_map); | ||
1080 | vpage += PAGE_SIZE; | ||
1081 | } | ||
1082 | |||
1083 | /* garbage collect */ | ||
1084 | scan = (sun4c_iobuffer_high - sun4c_iobuffer_start) >> PAGE_SHIFT; | ||
1085 | while (scan >= 0 && !sun4c_iobuffer_map[scan >> 5]) | ||
1086 | scan -= 32; | ||
1087 | scan += 32; | ||
1088 | high = sun4c_iobuffer_start + (scan << PAGE_SHIFT); | ||
1089 | high = SUN4C_REAL_PGDIR_ALIGN(high) + SUN4C_REAL_PGDIR_SIZE; | ||
1090 | while (high < sun4c_iobuffer_high) { | ||
1091 | sun4c_iobuffer_high -= SUN4C_REAL_PGDIR_SIZE; | ||
1092 | free_locked_segment(sun4c_iobuffer_high); | ||
1093 | } | ||
1094 | local_irq_restore(flags); | ||
1095 | } | ||
1096 | |||
1097 | /* Note the scsi code at init time passes to here buffers | ||
1098 | * which sit on the kernel stack, those are already locked | ||
1099 | * by implication and fool the page locking code above | ||
1100 | * if passed to by mistake. | ||
1101 | */ | ||
1102 | static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len) | ||
1103 | { | ||
1104 | unsigned long page; | ||
1105 | |||
1106 | page = ((unsigned long)bufptr) & PAGE_MASK; | ||
1107 | if (!virt_addr_valid(page)) { | ||
1108 | sun4c_flush_page(page); | ||
1109 | return (__u32)bufptr; /* already locked */ | ||
1110 | } | ||
1111 | return (__u32)sun4c_lockarea(bufptr, len); | ||
1112 | } | ||
1113 | |||
1114 | static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) | ||
1115 | { | ||
1116 | while (sz != 0) { | ||
1117 | --sz; | ||
1118 | sg->dma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length); | ||
1119 | sg->dma_length = sg->length; | ||
1120 | sg = sg_next(sg); | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len) | ||
1125 | { | ||
1126 | if (bufptr < sun4c_iobuffer_start) | ||
1127 | return; /* On kernel stack or similar, see above */ | ||
1128 | sun4c_unlockarea((char *)bufptr, len); | ||
1129 | } | ||
1130 | |||
1131 | static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) | ||
1132 | { | ||
1133 | while (sz != 0) { | ||
1134 | --sz; | ||
1135 | sun4c_unlockarea((char *)sg->dma_address, sg->length); | ||
1136 | sg = sg_next(sg); | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | #define TASK_ENTRY_SIZE BUCKET_SIZE /* see above */ | ||
1141 | #define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) | ||
1142 | |||
1143 | struct vm_area_struct sun4c_kstack_vma; | ||
1144 | |||
1145 | static void __init sun4c_init_lock_areas(void) | ||
1146 | { | ||
1147 | unsigned long sun4c_taskstack_start; | ||
1148 | unsigned long sun4c_taskstack_end; | ||
1149 | int bitmap_size; | ||
1150 | |||
1151 | sun4c_init_buckets(); | ||
1152 | sun4c_taskstack_start = SUN4C_LOCK_VADDR; | ||
1153 | sun4c_taskstack_end = (sun4c_taskstack_start + | ||
1154 | (TASK_ENTRY_SIZE * NR_TASK_BUCKETS)); | ||
1155 | if (sun4c_taskstack_end >= SUN4C_LOCK_END) { | ||
1156 | prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n"); | ||
1157 | prom_halt(); | ||
1158 | } | ||
1159 | |||
1160 | sun4c_iobuffer_start = sun4c_iobuffer_high = | ||
1161 | SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end); | ||
1162 | sun4c_iobuffer_end = SUN4C_LOCK_END; | ||
1163 | bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT; | ||
1164 | bitmap_size = (bitmap_size + 7) >> 3; | ||
1165 | bitmap_size = LONG_ALIGN(bitmap_size); | ||
1166 | iobuffer_map_size = bitmap_size << 3; | ||
1167 | sun4c_iobuffer_map = __alloc_bootmem(bitmap_size, SMP_CACHE_BYTES, 0UL); | ||
1168 | memset((void *) sun4c_iobuffer_map, 0, bitmap_size); | ||
1169 | |||
1170 | sun4c_kstack_vma.vm_mm = &init_mm; | ||
1171 | sun4c_kstack_vma.vm_start = sun4c_taskstack_start; | ||
1172 | sun4c_kstack_vma.vm_end = sun4c_taskstack_end; | ||
1173 | sun4c_kstack_vma.vm_page_prot = PAGE_SHARED; | ||
1174 | sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC; | ||
1175 | insert_vm_struct(&init_mm, &sun4c_kstack_vma); | ||
1176 | } | ||
1177 | |||
1178 | /* Cache flushing on the sun4c. */ | ||
1179 | static void sun4c_flush_cache_all(void) | ||
1180 | { | ||
1181 | unsigned long begin, end; | ||
1182 | |||
1183 | flush_user_windows(); | ||
1184 | begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE); | ||
1185 | end = (begin + SUN4C_VAC_SIZE); | ||
1186 | |||
1187 | if (sun4c_vacinfo.linesize == 32) { | ||
1188 | while (begin < end) { | ||
1189 | __asm__ __volatile__( | ||
1190 | "ld [%0 + 0x00], %%g0\n\t" | ||
1191 | "ld [%0 + 0x20], %%g0\n\t" | ||
1192 | "ld [%0 + 0x40], %%g0\n\t" | ||
1193 | "ld [%0 + 0x60], %%g0\n\t" | ||
1194 | "ld [%0 + 0x80], %%g0\n\t" | ||
1195 | "ld [%0 + 0xa0], %%g0\n\t" | ||
1196 | "ld [%0 + 0xc0], %%g0\n\t" | ||
1197 | "ld [%0 + 0xe0], %%g0\n\t" | ||
1198 | "ld [%0 + 0x100], %%g0\n\t" | ||
1199 | "ld [%0 + 0x120], %%g0\n\t" | ||
1200 | "ld [%0 + 0x140], %%g0\n\t" | ||
1201 | "ld [%0 + 0x160], %%g0\n\t" | ||
1202 | "ld [%0 + 0x180], %%g0\n\t" | ||
1203 | "ld [%0 + 0x1a0], %%g0\n\t" | ||
1204 | "ld [%0 + 0x1c0], %%g0\n\t" | ||
1205 | "ld [%0 + 0x1e0], %%g0\n" | ||
1206 | : : "r" (begin)); | ||
1207 | begin += 512; | ||
1208 | } | ||
1209 | } else { | ||
1210 | while (begin < end) { | ||
1211 | __asm__ __volatile__( | ||
1212 | "ld [%0 + 0x00], %%g0\n\t" | ||
1213 | "ld [%0 + 0x10], %%g0\n\t" | ||
1214 | "ld [%0 + 0x20], %%g0\n\t" | ||
1215 | "ld [%0 + 0x30], %%g0\n\t" | ||
1216 | "ld [%0 + 0x40], %%g0\n\t" | ||
1217 | "ld [%0 + 0x50], %%g0\n\t" | ||
1218 | "ld [%0 + 0x60], %%g0\n\t" | ||
1219 | "ld [%0 + 0x70], %%g0\n\t" | ||
1220 | "ld [%0 + 0x80], %%g0\n\t" | ||
1221 | "ld [%0 + 0x90], %%g0\n\t" | ||
1222 | "ld [%0 + 0xa0], %%g0\n\t" | ||
1223 | "ld [%0 + 0xb0], %%g0\n\t" | ||
1224 | "ld [%0 + 0xc0], %%g0\n\t" | ||
1225 | "ld [%0 + 0xd0], %%g0\n\t" | ||
1226 | "ld [%0 + 0xe0], %%g0\n\t" | ||
1227 | "ld [%0 + 0xf0], %%g0\n" | ||
1228 | : : "r" (begin)); | ||
1229 | begin += 256; | ||
1230 | } | ||
1231 | } | ||
1232 | } | ||
1233 | |||
1234 | static void sun4c_flush_cache_mm(struct mm_struct *mm) | ||
1235 | { | ||
1236 | int new_ctx = mm->context; | ||
1237 | |||
1238 | if (new_ctx != NO_CONTEXT) { | ||
1239 | flush_user_windows(); | ||
1240 | |||
1241 | if (sun4c_context_ring[new_ctx].num_entries) { | ||
1242 | struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; | ||
1243 | unsigned long flags; | ||
1244 | |||
1245 | local_irq_save(flags); | ||
1246 | if (head->next != head) { | ||
1247 | struct sun4c_mmu_entry *entry = head->next; | ||
1248 | int savectx = sun4c_get_context(); | ||
1249 | |||
1250 | sun4c_set_context(new_ctx); | ||
1251 | sun4c_flush_context(); | ||
1252 | do { | ||
1253 | struct sun4c_mmu_entry *next = entry->next; | ||
1254 | |||
1255 | sun4c_user_unmap(entry); | ||
1256 | free_user_entry(new_ctx, entry); | ||
1257 | |||
1258 | entry = next; | ||
1259 | } while (entry != head); | ||
1260 | sun4c_set_context(savectx); | ||
1261 | } | ||
1262 | local_irq_restore(flags); | ||
1263 | } | ||
1264 | } | ||
1265 | } | ||
1266 | |||
1267 | static void sun4c_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) | ||
1268 | { | ||
1269 | struct mm_struct *mm = vma->vm_mm; | ||
1270 | int new_ctx = mm->context; | ||
1271 | |||
1272 | if (new_ctx != NO_CONTEXT) { | ||
1273 | struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; | ||
1274 | struct sun4c_mmu_entry *entry; | ||
1275 | unsigned long flags; | ||
1276 | |||
1277 | flush_user_windows(); | ||
1278 | |||
1279 | local_irq_save(flags); | ||
1280 | /* All user segmap chains are ordered on entry->vaddr. */ | ||
1281 | for (entry = head->next; | ||
1282 | (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); | ||
1283 | entry = entry->next) | ||
1284 | ; | ||
1285 | |||
1286 | /* Tracing various job mixtures showed that this conditional | ||
1287 | * only passes ~35% of the time for most worse case situations, | ||
1288 | * therefore we avoid all of this gross overhead ~65% of the time. | ||
1289 | */ | ||
1290 | if ((entry != head) && (entry->vaddr < end)) { | ||
1291 | int octx = sun4c_get_context(); | ||
1292 | sun4c_set_context(new_ctx); | ||
1293 | |||
1294 | /* At this point, always, (start >= entry->vaddr) and | ||
1295 | * (entry->vaddr < end), once the latter condition | ||
1296 | * ceases to hold, or we hit the end of the list, we | ||
1297 | * exit the loop. The ordering of all user allocated | ||
1298 | * segmaps makes this all work out so beautifully. | ||
1299 | */ | ||
1300 | do { | ||
1301 | struct sun4c_mmu_entry *next = entry->next; | ||
1302 | unsigned long realend; | ||
1303 | |||
1304 | /* "realstart" is always >= entry->vaddr */ | ||
1305 | realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; | ||
1306 | if (end < realend) | ||
1307 | realend = end; | ||
1308 | if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { | ||
1309 | unsigned long page = entry->vaddr; | ||
1310 | while (page < realend) { | ||
1311 | sun4c_flush_page(page); | ||
1312 | page += PAGE_SIZE; | ||
1313 | } | ||
1314 | } else { | ||
1315 | sun4c_flush_segment(entry->vaddr); | ||
1316 | sun4c_user_unmap(entry); | ||
1317 | free_user_entry(new_ctx, entry); | ||
1318 | } | ||
1319 | entry = next; | ||
1320 | } while ((entry != head) && (entry->vaddr < end)); | ||
1321 | sun4c_set_context(octx); | ||
1322 | } | ||
1323 | local_irq_restore(flags); | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page) | ||
1328 | { | ||
1329 | struct mm_struct *mm = vma->vm_mm; | ||
1330 | int new_ctx = mm->context; | ||
1331 | |||
1332 | /* Sun4c has no separate I/D caches so cannot optimize for non | ||
1333 | * text page flushes. | ||
1334 | */ | ||
1335 | if (new_ctx != NO_CONTEXT) { | ||
1336 | int octx = sun4c_get_context(); | ||
1337 | unsigned long flags; | ||
1338 | |||
1339 | flush_user_windows(); | ||
1340 | local_irq_save(flags); | ||
1341 | sun4c_set_context(new_ctx); | ||
1342 | sun4c_flush_page(page); | ||
1343 | sun4c_set_context(octx); | ||
1344 | local_irq_restore(flags); | ||
1345 | } | ||
1346 | } | ||
1347 | |||
1348 | static void sun4c_flush_page_to_ram(unsigned long page) | ||
1349 | { | ||
1350 | unsigned long flags; | ||
1351 | |||
1352 | local_irq_save(flags); | ||
1353 | sun4c_flush_page(page); | ||
1354 | local_irq_restore(flags); | ||
1355 | } | ||
1356 | |||
1357 | /* Sun4c cache is unified, both instructions and data live there, so | ||
1358 | * no need to flush the on-stack instructions for new signal handlers. | ||
1359 | */ | ||
1360 | static void sun4c_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) | ||
1361 | { | ||
1362 | } | ||
1363 | |||
1364 | /* TLB flushing on the sun4c. These routines count on the cache | ||
1365 | * flushing code to flush the user register windows so that we need | ||
1366 | * not do so when we get here. | ||
1367 | */ | ||
1368 | |||
1369 | static void sun4c_flush_tlb_all(void) | ||
1370 | { | ||
1371 | struct sun4c_mmu_entry *this_entry, *next_entry; | ||
1372 | unsigned long flags; | ||
1373 | int savectx, ctx; | ||
1374 | |||
1375 | local_irq_save(flags); | ||
1376 | this_entry = sun4c_kernel_ring.ringhd.next; | ||
1377 | savectx = sun4c_get_context(); | ||
1378 | flush_user_windows(); | ||
1379 | while (sun4c_kernel_ring.num_entries) { | ||
1380 | next_entry = this_entry->next; | ||
1381 | sun4c_flush_segment(this_entry->vaddr); | ||
1382 | for (ctx = 0; ctx < num_contexts; ctx++) { | ||
1383 | sun4c_set_context(ctx); | ||
1384 | sun4c_put_segmap(this_entry->vaddr, invalid_segment); | ||
1385 | } | ||
1386 | free_kernel_entry(this_entry, &sun4c_kernel_ring); | ||
1387 | this_entry = next_entry; | ||
1388 | } | ||
1389 | sun4c_set_context(savectx); | ||
1390 | local_irq_restore(flags); | ||
1391 | } | ||
1392 | |||
1393 | static void sun4c_flush_tlb_mm(struct mm_struct *mm) | ||
1394 | { | ||
1395 | int new_ctx = mm->context; | ||
1396 | |||
1397 | if (new_ctx != NO_CONTEXT) { | ||
1398 | struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; | ||
1399 | unsigned long flags; | ||
1400 | |||
1401 | local_irq_save(flags); | ||
1402 | if (head->next != head) { | ||
1403 | struct sun4c_mmu_entry *entry = head->next; | ||
1404 | int savectx = sun4c_get_context(); | ||
1405 | |||
1406 | sun4c_set_context(new_ctx); | ||
1407 | sun4c_flush_context(); | ||
1408 | do { | ||
1409 | struct sun4c_mmu_entry *next = entry->next; | ||
1410 | |||
1411 | sun4c_user_unmap(entry); | ||
1412 | free_user_entry(new_ctx, entry); | ||
1413 | |||
1414 | entry = next; | ||
1415 | } while (entry != head); | ||
1416 | sun4c_set_context(savectx); | ||
1417 | } | ||
1418 | local_irq_restore(flags); | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | static void sun4c_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) | ||
1423 | { | ||
1424 | struct mm_struct *mm = vma->vm_mm; | ||
1425 | int new_ctx = mm->context; | ||
1426 | |||
1427 | if (new_ctx != NO_CONTEXT) { | ||
1428 | struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; | ||
1429 | struct sun4c_mmu_entry *entry; | ||
1430 | unsigned long flags; | ||
1431 | |||
1432 | local_irq_save(flags); | ||
1433 | /* See commentary in sun4c_flush_cache_range(). */ | ||
1434 | for (entry = head->next; | ||
1435 | (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); | ||
1436 | entry = entry->next) | ||
1437 | ; | ||
1438 | |||
1439 | if ((entry != head) && (entry->vaddr < end)) { | ||
1440 | int octx = sun4c_get_context(); | ||
1441 | |||
1442 | sun4c_set_context(new_ctx); | ||
1443 | do { | ||
1444 | struct sun4c_mmu_entry *next = entry->next; | ||
1445 | |||
1446 | sun4c_flush_segment(entry->vaddr); | ||
1447 | sun4c_user_unmap(entry); | ||
1448 | free_user_entry(new_ctx, entry); | ||
1449 | |||
1450 | entry = next; | ||
1451 | } while ((entry != head) && (entry->vaddr < end)); | ||
1452 | sun4c_set_context(octx); | ||
1453 | } | ||
1454 | local_irq_restore(flags); | ||
1455 | } | ||
1456 | } | ||
1457 | |||
1458 | static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) | ||
1459 | { | ||
1460 | struct mm_struct *mm = vma->vm_mm; | ||
1461 | int new_ctx = mm->context; | ||
1462 | |||
1463 | if (new_ctx != NO_CONTEXT) { | ||
1464 | int savectx = sun4c_get_context(); | ||
1465 | unsigned long flags; | ||
1466 | |||
1467 | local_irq_save(flags); | ||
1468 | sun4c_set_context(new_ctx); | ||
1469 | page &= PAGE_MASK; | ||
1470 | sun4c_flush_page(page); | ||
1471 | sun4c_put_pte(page, 0); | ||
1472 | sun4c_set_context(savectx); | ||
1473 | local_irq_restore(flags); | ||
1474 | } | ||
1475 | } | ||
1476 | |||
1477 | static inline void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr) | ||
1478 | { | ||
1479 | unsigned long page_entry, pg_iobits; | ||
1480 | |||
1481 | pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE | | ||
1482 | _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE; | ||
1483 | |||
1484 | page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK); | ||
1485 | page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT)); | ||
1486 | sun4c_put_pte(virt_addr, page_entry); | ||
1487 | } | ||
1488 | |||
1489 | static void sun4c_mapiorange(unsigned int bus, unsigned long xpa, | ||
1490 | unsigned long xva, unsigned int len) | ||
1491 | { | ||
1492 | while (len != 0) { | ||
1493 | len -= PAGE_SIZE; | ||
1494 | sun4c_mapioaddr(xpa, xva); | ||
1495 | xva += PAGE_SIZE; | ||
1496 | xpa += PAGE_SIZE; | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | static void sun4c_unmapiorange(unsigned long virt_addr, unsigned int len) | ||
1501 | { | ||
1502 | while (len != 0) { | ||
1503 | len -= PAGE_SIZE; | ||
1504 | sun4c_put_pte(virt_addr, 0); | ||
1505 | virt_addr += PAGE_SIZE; | ||
1506 | } | ||
1507 | } | ||
1508 | |||
1509 | static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm) | ||
1510 | { | ||
1511 | struct ctx_list *ctxp; | ||
1512 | |||
1513 | ctxp = ctx_free.next; | ||
1514 | if (ctxp != &ctx_free) { | ||
1515 | remove_from_ctx_list(ctxp); | ||
1516 | add_to_used_ctxlist(ctxp); | ||
1517 | mm->context = ctxp->ctx_number; | ||
1518 | ctxp->ctx_mm = mm; | ||
1519 | return; | ||
1520 | } | ||
1521 | ctxp = ctx_used.next; | ||
1522 | if (ctxp->ctx_mm == old_mm) | ||
1523 | ctxp = ctxp->next; | ||
1524 | remove_from_ctx_list(ctxp); | ||
1525 | add_to_used_ctxlist(ctxp); | ||
1526 | ctxp->ctx_mm->context = NO_CONTEXT; | ||
1527 | ctxp->ctx_mm = mm; | ||
1528 | mm->context = ctxp->ctx_number; | ||
1529 | sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], | ||
1530 | ctxp->ctx_number); | ||
1531 | } | ||
1532 | |||
1533 | /* Switch the current MM context. */ | ||
1534 | static void sun4c_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) | ||
1535 | { | ||
1536 | struct ctx_list *ctx; | ||
1537 | int dirty = 0; | ||
1538 | |||
1539 | if (mm->context == NO_CONTEXT) { | ||
1540 | dirty = 1; | ||
1541 | sun4c_alloc_context(old_mm, mm); | ||
1542 | } else { | ||
1543 | /* Update the LRU ring of contexts. */ | ||
1544 | ctx = ctx_list_pool + mm->context; | ||
1545 | remove_from_ctx_list(ctx); | ||
1546 | add_to_used_ctxlist(ctx); | ||
1547 | } | ||
1548 | if (dirty || old_mm != mm) | ||
1549 | sun4c_set_context(mm->context); | ||
1550 | } | ||
1551 | |||
1552 | static void sun4c_destroy_context(struct mm_struct *mm) | ||
1553 | { | ||
1554 | struct ctx_list *ctx_old; | ||
1555 | |||
1556 | if (mm->context != NO_CONTEXT) { | ||
1557 | sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context); | ||
1558 | ctx_old = ctx_list_pool + mm->context; | ||
1559 | remove_from_ctx_list(ctx_old); | ||
1560 | add_to_free_ctxlist(ctx_old); | ||
1561 | mm->context = NO_CONTEXT; | ||
1562 | } | ||
1563 | } | ||
1564 | |||
1565 | static void sun4c_mmu_info(struct seq_file *m) | ||
1566 | { | ||
1567 | int used_user_entries, i; | ||
1568 | |||
1569 | used_user_entries = 0; | ||
1570 | for (i = 0; i < num_contexts; i++) | ||
1571 | used_user_entries += sun4c_context_ring[i].num_entries; | ||
1572 | |||
1573 | seq_printf(m, | ||
1574 | "vacsize\t\t: %d bytes\n" | ||
1575 | "vachwflush\t: %s\n" | ||
1576 | "vaclinesize\t: %d bytes\n" | ||
1577 | "mmuctxs\t\t: %d\n" | ||
1578 | "mmupsegs\t: %d\n" | ||
1579 | "kernelpsegs\t: %d\n" | ||
1580 | "kfreepsegs\t: %d\n" | ||
1581 | "usedpsegs\t: %d\n" | ||
1582 | "ufreepsegs\t: %d\n" | ||
1583 | "user_taken\t: %d\n" | ||
1584 | "max_taken\t: %d\n", | ||
1585 | sun4c_vacinfo.num_bytes, | ||
1586 | (sun4c_vacinfo.do_hwflushes ? "yes" : "no"), | ||
1587 | sun4c_vacinfo.linesize, | ||
1588 | num_contexts, | ||
1589 | (invalid_segment + 1), | ||
1590 | sun4c_kernel_ring.num_entries, | ||
1591 | sun4c_kfree_ring.num_entries, | ||
1592 | used_user_entries, | ||
1593 | sun4c_ufree_ring.num_entries, | ||
1594 | sun4c_user_taken_entries, | ||
1595 | max_user_taken_entries); | ||
1596 | } | ||
1597 | |||
1598 | /* Nothing below here should touch the mmu hardware nor the mmu_entry | ||
1599 | * data structures. | ||
1600 | */ | ||
1601 | |||
1602 | /* First the functions which the mid-level code uses to directly | ||
1603 | * manipulate the software page tables. Some defines since we are | ||
1604 | * emulating the i386 page directory layout. | ||
1605 | */ | ||
1606 | #define PGD_PRESENT 0x001 | ||
1607 | #define PGD_RW 0x002 | ||
1608 | #define PGD_USER 0x004 | ||
1609 | #define PGD_ACCESSED 0x020 | ||
1610 | #define PGD_DIRTY 0x040 | ||
1611 | #define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY) | ||
1612 | |||
1613 | static void sun4c_set_pte(pte_t *ptep, pte_t pte) | ||
1614 | { | ||
1615 | *ptep = pte; | ||
1616 | } | ||
1617 | |||
1618 | static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp) | ||
1619 | { | ||
1620 | } | ||
1621 | |||
1622 | static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep) | ||
1623 | { | ||
1624 | pmdp->pmdv[0] = PGD_TABLE | (unsigned long) ptep; | ||
1625 | } | ||
1626 | |||
1627 | static void sun4c_pmd_populate(pmd_t * pmdp, struct page * ptep) | ||
1628 | { | ||
1629 | if (page_address(ptep) == NULL) BUG(); /* No highmem on sun4c */ | ||
1630 | pmdp->pmdv[0] = PGD_TABLE | (unsigned long) page_address(ptep); | ||
1631 | } | ||
1632 | |||
1633 | static int sun4c_pte_present(pte_t pte) | ||
1634 | { | ||
1635 | return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0); | ||
1636 | } | ||
1637 | static void sun4c_pte_clear(pte_t *ptep) { *ptep = __pte(0); } | ||
1638 | |||
1639 | static int sun4c_pmd_bad(pmd_t pmd) | ||
1640 | { | ||
1641 | return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) || | ||
1642 | (!virt_addr_valid(pmd_val(pmd)))); | ||
1643 | } | ||
1644 | |||
1645 | static int sun4c_pmd_present(pmd_t pmd) | ||
1646 | { | ||
1647 | return ((pmd_val(pmd) & PGD_PRESENT) != 0); | ||
1648 | } | ||
1649 | |||
1650 | #if 0 /* if PMD takes one word */ | ||
1651 | static void sun4c_pmd_clear(pmd_t *pmdp) { *pmdp = __pmd(0); } | ||
1652 | #else /* if pmd_t is a longish aggregate */ | ||
1653 | static void sun4c_pmd_clear(pmd_t *pmdp) { | ||
1654 | memset((void *)pmdp, 0, sizeof(pmd_t)); | ||
1655 | } | ||
1656 | #endif | ||
1657 | |||
1658 | static int sun4c_pgd_none(pgd_t pgd) { return 0; } | ||
1659 | static int sun4c_pgd_bad(pgd_t pgd) { return 0; } | ||
1660 | static int sun4c_pgd_present(pgd_t pgd) { return 1; } | ||
1661 | static void sun4c_pgd_clear(pgd_t * pgdp) { } | ||
1662 | |||
1663 | /* | ||
1664 | * The following only work if pte_present() is true. | ||
1665 | * Undefined behaviour if not.. | ||
1666 | */ | ||
1667 | static pte_t sun4c_pte_mkwrite(pte_t pte) | ||
1668 | { | ||
1669 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE); | ||
1670 | if (pte_val(pte) & _SUN4C_PAGE_MODIFIED) | ||
1671 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE); | ||
1672 | return pte; | ||
1673 | } | ||
1674 | |||
1675 | static pte_t sun4c_pte_mkdirty(pte_t pte) | ||
1676 | { | ||
1677 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_MODIFIED); | ||
1678 | if (pte_val(pte) & _SUN4C_PAGE_WRITE) | ||
1679 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE); | ||
1680 | return pte; | ||
1681 | } | ||
1682 | |||
1683 | static pte_t sun4c_pte_mkyoung(pte_t pte) | ||
1684 | { | ||
1685 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_ACCESSED); | ||
1686 | if (pte_val(pte) & _SUN4C_PAGE_READ) | ||
1687 | pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_READ); | ||
1688 | return pte; | ||
1689 | } | ||
1690 | |||
1691 | /* | ||
1692 | * Conversion functions: convert a page and protection to a page entry, | ||
1693 | * and a page entry and page directory to the page they refer to. | ||
1694 | */ | ||
1695 | static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot) | ||
1696 | { | ||
1697 | return __pte(page_to_pfn(page) | pgprot_val(pgprot)); | ||
1698 | } | ||
1699 | |||
1700 | static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot) | ||
1701 | { | ||
1702 | return __pte((phys_page >> PAGE_SHIFT) | pgprot_val(pgprot)); | ||
1703 | } | ||
1704 | |||
1705 | static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) | ||
1706 | { | ||
1707 | return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); | ||
1708 | } | ||
1709 | |||
1710 | static unsigned long sun4c_pte_pfn(pte_t pte) | ||
1711 | { | ||
1712 | return pte_val(pte) & SUN4C_PFN_MASK; | ||
1713 | } | ||
1714 | |||
1715 | static pte_t sun4c_pgoff_to_pte(unsigned long pgoff) | ||
1716 | { | ||
1717 | return __pte(pgoff | _SUN4C_PAGE_FILE); | ||
1718 | } | ||
1719 | |||
1720 | static unsigned long sun4c_pte_to_pgoff(pte_t pte) | ||
1721 | { | ||
1722 | return pte_val(pte) & ((1UL << PTE_FILE_MAX_BITS) - 1); | ||
1723 | } | ||
1724 | |||
1725 | |||
1726 | static inline unsigned long sun4c_pmd_page_v(pmd_t pmd) | ||
1727 | { | ||
1728 | return (pmd_val(pmd) & PAGE_MASK); | ||
1729 | } | ||
1730 | |||
1731 | static struct page *sun4c_pmd_page(pmd_t pmd) | ||
1732 | { | ||
1733 | return virt_to_page(sun4c_pmd_page_v(pmd)); | ||
1734 | } | ||
1735 | |||
1736 | static unsigned long sun4c_pgd_page(pgd_t pgd) { return 0; } | ||
1737 | |||
1738 | /* to find an entry in a page-table-directory */ | ||
1739 | static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) | ||
1740 | { | ||
1741 | return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); | ||
1742 | } | ||
1743 | |||
1744 | /* Find an entry in the second-level page table.. */ | ||
1745 | static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address) | ||
1746 | { | ||
1747 | return (pmd_t *) dir; | ||
1748 | } | ||
1749 | |||
1750 | /* Find an entry in the third-level page table.. */ | ||
1751 | pte_t *sun4c_pte_offset_kernel(pmd_t * dir, unsigned long address) | ||
1752 | { | ||
1753 | return (pte_t *) sun4c_pmd_page_v(*dir) + | ||
1754 | ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)); | ||
1755 | } | ||
1756 | |||
1757 | static unsigned long sun4c_swp_type(swp_entry_t entry) | ||
1758 | { | ||
1759 | return (entry.val & SUN4C_SWP_TYPE_MASK); | ||
1760 | } | ||
1761 | |||
1762 | static unsigned long sun4c_swp_offset(swp_entry_t entry) | ||
1763 | { | ||
1764 | return (entry.val >> SUN4C_SWP_OFF_SHIFT) & SUN4C_SWP_OFF_MASK; | ||
1765 | } | ||
1766 | |||
1767 | static swp_entry_t sun4c_swp_entry(unsigned long type, unsigned long offset) | ||
1768 | { | ||
1769 | return (swp_entry_t) { | ||
1770 | (offset & SUN4C_SWP_OFF_MASK) << SUN4C_SWP_OFF_SHIFT | ||
1771 | | (type & SUN4C_SWP_TYPE_MASK) }; | ||
1772 | } | ||
1773 | |||
1774 | static void sun4c_free_pte_slow(pte_t *pte) | ||
1775 | { | ||
1776 | free_page((unsigned long)pte); | ||
1777 | } | ||
1778 | |||
1779 | static void sun4c_free_pgd_slow(pgd_t *pgd) | ||
1780 | { | ||
1781 | free_page((unsigned long)pgd); | ||
1782 | } | ||
1783 | |||
1784 | static pgd_t *sun4c_get_pgd_fast(void) | ||
1785 | { | ||
1786 | unsigned long *ret; | ||
1787 | |||
1788 | if ((ret = pgd_quicklist) != NULL) { | ||
1789 | pgd_quicklist = (unsigned long *)(*ret); | ||
1790 | ret[0] = ret[1]; | ||
1791 | pgtable_cache_size--; | ||
1792 | } else { | ||
1793 | pgd_t *init; | ||
1794 | |||
1795 | ret = (unsigned long *)__get_free_page(GFP_KERNEL); | ||
1796 | memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t)); | ||
1797 | init = sun4c_pgd_offset(&init_mm, 0); | ||
1798 | memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, | ||
1799 | (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); | ||
1800 | } | ||
1801 | return (pgd_t *)ret; | ||
1802 | } | ||
1803 | |||
1804 | static void sun4c_free_pgd_fast(pgd_t *pgd) | ||
1805 | { | ||
1806 | *(unsigned long *)pgd = (unsigned long) pgd_quicklist; | ||
1807 | pgd_quicklist = (unsigned long *) pgd; | ||
1808 | pgtable_cache_size++; | ||
1809 | } | ||
1810 | |||
1811 | |||
1812 | static inline pte_t * | ||
1813 | sun4c_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) | ||
1814 | { | ||
1815 | unsigned long *ret; | ||
1816 | |||
1817 | if ((ret = (unsigned long *)pte_quicklist) != NULL) { | ||
1818 | pte_quicklist = (unsigned long *)(*ret); | ||
1819 | ret[0] = ret[1]; | ||
1820 | pgtable_cache_size--; | ||
1821 | } | ||
1822 | return (pte_t *)ret; | ||
1823 | } | ||
1824 | |||
1825 | static pte_t *sun4c_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) | ||
1826 | { | ||
1827 | pte_t *pte; | ||
1828 | |||
1829 | if ((pte = sun4c_pte_alloc_one_fast(mm, address)) != NULL) | ||
1830 | return pte; | ||
1831 | |||
1832 | pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); | ||
1833 | return pte; | ||
1834 | } | ||
1835 | |||
1836 | static pgtable_t sun4c_pte_alloc_one(struct mm_struct *mm, unsigned long address) | ||
1837 | { | ||
1838 | pte_t *pte; | ||
1839 | struct page *page; | ||
1840 | |||
1841 | pte = sun4c_pte_alloc_one_kernel(mm, address); | ||
1842 | if (pte == NULL) | ||
1843 | return NULL; | ||
1844 | page = virt_to_page(pte); | ||
1845 | pgtable_page_ctor(page); | ||
1846 | return page; | ||
1847 | } | ||
1848 | |||
1849 | static inline void sun4c_free_pte_fast(pte_t *pte) | ||
1850 | { | ||
1851 | *(unsigned long *)pte = (unsigned long) pte_quicklist; | ||
1852 | pte_quicklist = (unsigned long *) pte; | ||
1853 | pgtable_cache_size++; | ||
1854 | } | ||
1855 | |||
1856 | static void sun4c_pte_free(pgtable_t pte) | ||
1857 | { | ||
1858 | pgtable_page_dtor(pte); | ||
1859 | sun4c_free_pte_fast(page_address(pte)); | ||
1860 | } | ||
1861 | |||
1862 | /* | ||
1863 | * allocating and freeing a pmd is trivial: the 1-entry pmd is | ||
1864 | * inside the pgd, so has no extra memory associated with it. | ||
1865 | */ | ||
1866 | static pmd_t *sun4c_pmd_alloc_one(struct mm_struct *mm, unsigned long address) | ||
1867 | { | ||
1868 | BUG(); | ||
1869 | return NULL; | ||
1870 | } | ||
1871 | |||
1872 | static void sun4c_free_pmd_fast(pmd_t * pmd) { } | ||
1873 | |||
1874 | static void sun4c_check_pgt_cache(int low, int high) | ||
1875 | { | ||
1876 | if (pgtable_cache_size > high) { | ||
1877 | do { | ||
1878 | if (pgd_quicklist) | ||
1879 | sun4c_free_pgd_slow(sun4c_get_pgd_fast()); | ||
1880 | if (pte_quicklist) | ||
1881 | sun4c_free_pte_slow(sun4c_pte_alloc_one_fast(NULL, 0)); | ||
1882 | } while (pgtable_cache_size > low); | ||
1883 | } | ||
1884 | } | ||
1885 | |||
1886 | /* An experiment, turn off by default for now... -DaveM */ | ||
1887 | #define SUN4C_PRELOAD_PSEG | ||
1888 | |||
1889 | void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) | ||
1890 | { | ||
1891 | unsigned long flags; | ||
1892 | int pseg; | ||
1893 | |||
1894 | if (vma->vm_mm->context == NO_CONTEXT) | ||
1895 | return; | ||
1896 | |||
1897 | local_irq_save(flags); | ||
1898 | address &= PAGE_MASK; | ||
1899 | if ((pseg = sun4c_get_segmap(address)) == invalid_segment) { | ||
1900 | struct sun4c_mmu_entry *entry = sun4c_user_strategy(); | ||
1901 | struct mm_struct *mm = vma->vm_mm; | ||
1902 | unsigned long start, end; | ||
1903 | |||
1904 | entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK); | ||
1905 | entry->ctx = mm->context; | ||
1906 | add_ring_ordered(sun4c_context_ring + mm->context, entry); | ||
1907 | sun4c_put_segmap(entry->vaddr, entry->pseg); | ||
1908 | end = start + SUN4C_REAL_PGDIR_SIZE; | ||
1909 | while (start < end) { | ||
1910 | #ifdef SUN4C_PRELOAD_PSEG | ||
1911 | pgd_t *pgdp = sun4c_pgd_offset(mm, start); | ||
1912 | pte_t *ptep; | ||
1913 | |||
1914 | if (!pgdp) | ||
1915 | goto no_mapping; | ||
1916 | ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, start); | ||
1917 | if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT)) | ||
1918 | goto no_mapping; | ||
1919 | sun4c_put_pte(start, pte_val(*ptep)); | ||
1920 | goto next; | ||
1921 | |||
1922 | no_mapping: | ||
1923 | #endif | ||
1924 | sun4c_put_pte(start, 0); | ||
1925 | #ifdef SUN4C_PRELOAD_PSEG | ||
1926 | next: | ||
1927 | #endif | ||
1928 | start += PAGE_SIZE; | ||
1929 | } | ||
1930 | #ifndef SUN4C_PRELOAD_PSEG | ||
1931 | sun4c_put_pte(address, pte_val(*ptep)); | ||
1932 | #endif | ||
1933 | local_irq_restore(flags); | ||
1934 | return; | ||
1935 | } else { | ||
1936 | struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg]; | ||
1937 | |||
1938 | remove_lru(entry); | ||
1939 | add_lru(entry); | ||
1940 | } | ||
1941 | |||
1942 | sun4c_put_pte(address, pte_val(*ptep)); | ||
1943 | local_irq_restore(flags); | ||
1944 | } | ||
1945 | |||
1946 | extern void sparc_context_init(int); | ||
1947 | extern unsigned long bootmem_init(unsigned long *pages_avail); | ||
1948 | extern unsigned long last_valid_pfn; | ||
1949 | |||
1950 | void __init sun4c_paging_init(void) | ||
1951 | { | ||
1952 | int i, cnt; | ||
1953 | unsigned long kernel_end, vaddr; | ||
1954 | extern struct resource sparc_iomap; | ||
1955 | unsigned long end_pfn, pages_avail; | ||
1956 | |||
1957 | kernel_end = (unsigned long) &_end; | ||
1958 | kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); | ||
1959 | |||
1960 | pages_avail = 0; | ||
1961 | last_valid_pfn = bootmem_init(&pages_avail); | ||
1962 | end_pfn = last_valid_pfn; | ||
1963 | |||
1964 | sun4c_probe_mmu(); | ||
1965 | invalid_segment = (num_segmaps - 1); | ||
1966 | sun4c_init_mmu_entry_pool(); | ||
1967 | sun4c_init_rings(); | ||
1968 | sun4c_init_map_kernelprom(kernel_end); | ||
1969 | sun4c_init_clean_mmu(kernel_end); | ||
1970 | sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS); | ||
1971 | sun4c_init_lock_area(sparc_iomap.start, IOBASE_END); | ||
1972 | sun4c_init_lock_area(DVMA_VADDR, DVMA_END); | ||
1973 | sun4c_init_lock_areas(); | ||
1974 | sun4c_init_fill_user_ring(); | ||
1975 | |||
1976 | sun4c_set_context(0); | ||
1977 | memset(swapper_pg_dir, 0, PAGE_SIZE); | ||
1978 | memset(pg0, 0, PAGE_SIZE); | ||
1979 | memset(pg1, 0, PAGE_SIZE); | ||
1980 | memset(pg2, 0, PAGE_SIZE); | ||
1981 | memset(pg3, 0, PAGE_SIZE); | ||
1982 | |||
1983 | /* Save work later. */ | ||
1984 | vaddr = VMALLOC_START; | ||
1985 | swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg0); | ||
1986 | vaddr += SUN4C_PGDIR_SIZE; | ||
1987 | swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg1); | ||
1988 | vaddr += SUN4C_PGDIR_SIZE; | ||
1989 | swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg2); | ||
1990 | vaddr += SUN4C_PGDIR_SIZE; | ||
1991 | swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); | ||
1992 | sun4c_init_ss2_cache_bug(); | ||
1993 | sparc_context_init(num_contexts); | ||
1994 | |||
1995 | { | ||
1996 | unsigned long zones_size[MAX_NR_ZONES]; | ||
1997 | unsigned long zholes_size[MAX_NR_ZONES]; | ||
1998 | unsigned long npages; | ||
1999 | int znum; | ||
2000 | |||
2001 | for (znum = 0; znum < MAX_NR_ZONES; znum++) | ||
2002 | zones_size[znum] = zholes_size[znum] = 0; | ||
2003 | |||
2004 | npages = max_low_pfn - pfn_base; | ||
2005 | |||
2006 | zones_size[ZONE_DMA] = npages; | ||
2007 | zholes_size[ZONE_DMA] = npages - pages_avail; | ||
2008 | |||
2009 | npages = highend_pfn - max_low_pfn; | ||
2010 | zones_size[ZONE_HIGHMEM] = npages; | ||
2011 | zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); | ||
2012 | |||
2013 | free_area_init_node(0, zones_size, pfn_base, zholes_size); | ||
2014 | } | ||
2015 | |||
2016 | cnt = 0; | ||
2017 | for (i = 0; i < num_segmaps; i++) | ||
2018 | if (mmu_entry_pool[i].locked) | ||
2019 | cnt++; | ||
2020 | |||
2021 | max_user_taken_entries = num_segmaps - cnt - 40 - 1; | ||
2022 | |||
2023 | printk("SUN4C: %d mmu entries for the kernel\n", cnt); | ||
2024 | } | ||
2025 | |||
2026 | static pgprot_t sun4c_pgprot_noncached(pgprot_t prot) | ||
2027 | { | ||
2028 | prot |= __pgprot(_SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE); | ||
2029 | |||
2030 | return prot; | ||
2031 | } | ||
2032 | |||
2033 | /* Load up routines and constants for sun4c mmu */ | ||
2034 | void __init ld_mmu_sun4c(void) | ||
2035 | { | ||
2036 | extern void ___xchg32_sun4c(void); | ||
2037 | |||
2038 | printk("Loading sun4c MMU routines\n"); | ||
2039 | |||
2040 | /* First the constants */ | ||
2041 | BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT); | ||
2042 | BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE); | ||
2043 | BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK); | ||
2044 | |||
2045 | BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD); | ||
2046 | BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD); | ||
2047 | BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE); | ||
2048 | |||
2049 | BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE)); | ||
2050 | PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED); | ||
2051 | BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY)); | ||
2052 | BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY)); | ||
2053 | BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL)); | ||
2054 | page_kernel = pgprot_val(SUN4C_PAGE_KERNEL); | ||
2055 | |||
2056 | /* Functions */ | ||
2057 | BTFIXUPSET_CALL(pgprot_noncached, sun4c_pgprot_noncached, BTFIXUPCALL_NORM); | ||
2058 | BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM); | ||
2059 | BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM); | ||
2060 | |||
2061 | BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM); | ||
2062 | |||
2063 | if (sun4c_vacinfo.do_hwflushes) { | ||
2064 | BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_hw, BTFIXUPCALL_NORM); | ||
2065 | BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_hw, BTFIXUPCALL_NORM); | ||
2066 | BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_hw, BTFIXUPCALL_NORM); | ||
2067 | } else { | ||
2068 | BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_sw, BTFIXUPCALL_NORM); | ||
2069 | BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_sw, BTFIXUPCALL_NORM); | ||
2070 | BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_sw, BTFIXUPCALL_NORM); | ||
2071 | } | ||
2072 | |||
2073 | BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm, BTFIXUPCALL_NORM); | ||
2074 | BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm, BTFIXUPCALL_NORM); | ||
2075 | BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context, BTFIXUPCALL_NORM); | ||
2076 | BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm, BTFIXUPCALL_NORM); | ||
2077 | BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page, BTFIXUPCALL_NORM); | ||
2078 | BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page, BTFIXUPCALL_NORM); | ||
2079 | BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range, BTFIXUPCALL_NORM); | ||
2080 | BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range, BTFIXUPCALL_NORM); | ||
2081 | BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram, BTFIXUPCALL_NORM); | ||
2082 | BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM); | ||
2083 | |||
2084 | BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP); | ||
2085 | |||
2086 | BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0); | ||
2087 | |||
2088 | BTFIXUPSET_CALL(pte_pfn, sun4c_pte_pfn, BTFIXUPCALL_NORM); | ||
2089 | #if 0 /* PAGE_SHIFT <= 12 */ /* Eek. Investigate. XXX */ | ||
2090 | BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1)); | ||
2091 | #else | ||
2092 | BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM); | ||
2093 | #endif | ||
2094 | BTFIXUPSET_CALL(pmd_set, sun4c_pmd_set, BTFIXUPCALL_NORM); | ||
2095 | BTFIXUPSET_CALL(pmd_populate, sun4c_pmd_populate, BTFIXUPCALL_NORM); | ||
2096 | |||
2097 | BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM); | ||
2098 | BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0); | ||
2099 | |||
2100 | BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM); | ||
2101 | BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM); | ||
2102 | BTFIXUPSET_CALL(pmd_clear, sun4c_pmd_clear, BTFIXUPCALL_STG0O0); | ||
2103 | |||
2104 | BTFIXUPSET_CALL(pgd_none, sun4c_pgd_none, BTFIXUPCALL_RETINT(0)); | ||
2105 | BTFIXUPSET_CALL(pgd_bad, sun4c_pgd_bad, BTFIXUPCALL_RETINT(0)); | ||
2106 | BTFIXUPSET_CALL(pgd_present, sun4c_pgd_present, BTFIXUPCALL_RETINT(1)); | ||
2107 | BTFIXUPSET_CALL(pgd_clear, sun4c_pgd_clear, BTFIXUPCALL_NOP); | ||
2108 | |||
2109 | BTFIXUPSET_CALL(mk_pte, sun4c_mk_pte, BTFIXUPCALL_NORM); | ||
2110 | BTFIXUPSET_CALL(mk_pte_phys, sun4c_mk_pte_phys, BTFIXUPCALL_NORM); | ||
2111 | BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM); | ||
2112 | |||
2113 | BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); | ||
2114 | BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM); | ||
2115 | BTFIXUPSET_CALL(pte_offset_kernel, sun4c_pte_offset_kernel, BTFIXUPCALL_NORM); | ||
2116 | BTFIXUPSET_CALL(free_pte_fast, sun4c_free_pte_fast, BTFIXUPCALL_NORM); | ||
2117 | BTFIXUPSET_CALL(pte_free, sun4c_pte_free, BTFIXUPCALL_NORM); | ||
2118 | BTFIXUPSET_CALL(pte_alloc_one_kernel, sun4c_pte_alloc_one_kernel, BTFIXUPCALL_NORM); | ||
2119 | BTFIXUPSET_CALL(pte_alloc_one, sun4c_pte_alloc_one, BTFIXUPCALL_NORM); | ||
2120 | BTFIXUPSET_CALL(free_pmd_fast, sun4c_free_pmd_fast, BTFIXUPCALL_NOP); | ||
2121 | BTFIXUPSET_CALL(pmd_alloc_one, sun4c_pmd_alloc_one, BTFIXUPCALL_RETO0); | ||
2122 | BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM); | ||
2123 | BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM); | ||
2124 | |||
2125 | BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE); | ||
2126 | BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED); | ||
2127 | BTFIXUPSET_HALF(pte_youngi, _SUN4C_PAGE_ACCESSED); | ||
2128 | BTFIXUPSET_HALF(pte_filei, _SUN4C_PAGE_FILE); | ||
2129 | BTFIXUPSET_HALF(pte_wrprotecti, _SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE); | ||
2130 | BTFIXUPSET_HALF(pte_mkcleani, _SUN4C_PAGE_MODIFIED|_SUN4C_PAGE_SILENT_WRITE); | ||
2131 | BTFIXUPSET_HALF(pte_mkoldi, _SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_SILENT_READ); | ||
2132 | BTFIXUPSET_CALL(pte_mkwrite, sun4c_pte_mkwrite, BTFIXUPCALL_NORM); | ||
2133 | BTFIXUPSET_CALL(pte_mkdirty, sun4c_pte_mkdirty, BTFIXUPCALL_NORM); | ||
2134 | BTFIXUPSET_CALL(pte_mkyoung, sun4c_pte_mkyoung, BTFIXUPCALL_NORM); | ||
2135 | BTFIXUPSET_CALL(update_mmu_cache, sun4c_update_mmu_cache, BTFIXUPCALL_NORM); | ||
2136 | |||
2137 | BTFIXUPSET_CALL(pte_to_pgoff, sun4c_pte_to_pgoff, BTFIXUPCALL_NORM); | ||
2138 | BTFIXUPSET_CALL(pgoff_to_pte, sun4c_pgoff_to_pte, BTFIXUPCALL_NORM); | ||
2139 | |||
2140 | BTFIXUPSET_CALL(mmu_lockarea, sun4c_lockarea, BTFIXUPCALL_NORM); | ||
2141 | BTFIXUPSET_CALL(mmu_unlockarea, sun4c_unlockarea, BTFIXUPCALL_NORM); | ||
2142 | |||
2143 | BTFIXUPSET_CALL(mmu_get_scsi_one, sun4c_get_scsi_one, BTFIXUPCALL_NORM); | ||
2144 | BTFIXUPSET_CALL(mmu_get_scsi_sgl, sun4c_get_scsi_sgl, BTFIXUPCALL_NORM); | ||
2145 | BTFIXUPSET_CALL(mmu_release_scsi_one, sun4c_release_scsi_one, BTFIXUPCALL_NORM); | ||
2146 | BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM); | ||
2147 | |||
2148 | BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); | ||
2149 | BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); | ||
2150 | |||
2151 | BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM); | ||
2152 | BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM); | ||
2153 | |||
2154 | BTFIXUPSET_CALL(__swp_type, sun4c_swp_type, BTFIXUPCALL_NORM); | ||
2155 | BTFIXUPSET_CALL(__swp_offset, sun4c_swp_offset, BTFIXUPCALL_NORM); | ||
2156 | BTFIXUPSET_CALL(__swp_entry, sun4c_swp_entry, BTFIXUPCALL_NORM); | ||
2157 | |||
2158 | BTFIXUPSET_CALL(alloc_thread_info_node, sun4c_alloc_thread_info_node, BTFIXUPCALL_NORM); | ||
2159 | BTFIXUPSET_CALL(free_thread_info, sun4c_free_thread_info, BTFIXUPCALL_NORM); | ||
2160 | |||
2161 | BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM); | ||
2162 | |||
2163 | /* These should _never_ get called with two level tables. */ | ||
2164 | BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP); | ||
2165 | BTFIXUPSET_CALL(pgd_page_vaddr, sun4c_pgd_page, BTFIXUPCALL_RETO0); | ||
2166 | } | ||
diff --git a/arch/sparc/mm/ultra.S b/arch/sparc/mm/ultra.S index b57a5942ba64..874162a11ceb 100644 --- a/arch/sparc/mm/ultra.S +++ b/arch/sparc/mm/ultra.S | |||
@@ -495,11 +495,11 @@ xcall_fetch_glob_regs: | |||
495 | stx %o7, [%g1 + GR_SNAP_O7] | 495 | stx %o7, [%g1 + GR_SNAP_O7] |
496 | stx %i7, [%g1 + GR_SNAP_I7] | 496 | stx %i7, [%g1 + GR_SNAP_I7] |
497 | /* Don't try this at home kids... */ | 497 | /* Don't try this at home kids... */ |
498 | rdpr %cwp, %g2 | 498 | rdpr %cwp, %g3 |
499 | sub %g2, 1, %g7 | 499 | sub %g3, 1, %g7 |
500 | wrpr %g7, %cwp | 500 | wrpr %g7, %cwp |
501 | mov %i7, %g7 | 501 | mov %i7, %g7 |
502 | wrpr %g2, %cwp | 502 | wrpr %g3, %cwp |
503 | stx %g7, [%g1 + GR_SNAP_RPC] | 503 | stx %g7, [%g1 + GR_SNAP_RPC] |
504 | sethi %hi(trap_block), %g7 | 504 | sethi %hi(trap_block), %g7 |
505 | or %g7, %lo(trap_block), %g7 | 505 | or %g7, %lo(trap_block), %g7 |
diff --git a/arch/sparc/mm/viking.S b/arch/sparc/mm/viking.S index 6dfcc13d3100..bf8ee0613ae7 100644 --- a/arch/sparc/mm/viking.S +++ b/arch/sparc/mm/viking.S | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <asm/page.h> | 14 | #include <asm/page.h> |
15 | #include <asm/pgtsrmmu.h> | 15 | #include <asm/pgtsrmmu.h> |
16 | #include <asm/viking.h> | 16 | #include <asm/viking.h> |
17 | #include <asm/btfixup.h> | ||
18 | 17 | ||
19 | #ifdef CONFIG_SMP | 18 | #ifdef CONFIG_SMP |
20 | .data | 19 | .data |
diff --git a/arch/sparc/net/Makefile b/arch/sparc/net/Makefile new file mode 100644 index 000000000000..1306a58ac541 --- /dev/null +++ b/arch/sparc/net/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | # | ||
2 | # Arch-specific network modules | ||
3 | # | ||
4 | obj-$(CONFIG_BPF_JIT) += bpf_jit_asm.o bpf_jit_comp.o | ||
diff --git a/arch/sparc/net/bpf_jit.h b/arch/sparc/net/bpf_jit.h new file mode 100644 index 000000000000..33d6b375ff12 --- /dev/null +++ b/arch/sparc/net/bpf_jit.h | |||
@@ -0,0 +1,68 @@ | |||
1 | #ifndef _BPF_JIT_H | ||
2 | #define _BPF_JIT_H | ||
3 | |||
4 | /* Conventions: | ||
5 | * %g1 : temporary | ||
6 | * %g2 : Secondary temporary used by SKB data helper stubs. | ||
7 | * %g3 : packet offset passed into SKB data helper stubs. | ||
8 | * %o0 : pointer to skb (first argument given to JIT function) | ||
9 | * %o1 : BPF A accumulator | ||
10 | * %o2 : BPF X accumulator | ||
11 | * %o3 : Holds saved %o7 so we can call helper functions without needing | ||
12 | * to allocate a register window. | ||
13 | * %o4 : skb->len - skb->data_len | ||
14 | * %o5 : skb->data | ||
15 | */ | ||
16 | |||
17 | #ifndef __ASSEMBLER__ | ||
18 | #define G0 0x00 | ||
19 | #define G1 0x01 | ||
20 | #define G3 0x03 | ||
21 | #define G6 0x06 | ||
22 | #define O0 0x08 | ||
23 | #define O1 0x09 | ||
24 | #define O2 0x0a | ||
25 | #define O3 0x0b | ||
26 | #define O4 0x0c | ||
27 | #define O5 0x0d | ||
28 | #define SP 0x0e | ||
29 | #define O7 0x0f | ||
30 | #define FP 0x1e | ||
31 | |||
32 | #define r_SKB O0 | ||
33 | #define r_A O1 | ||
34 | #define r_X O2 | ||
35 | #define r_saved_O7 O3 | ||
36 | #define r_HEADLEN O4 | ||
37 | #define r_SKB_DATA O5 | ||
38 | #define r_TMP G1 | ||
39 | #define r_TMP2 G2 | ||
40 | #define r_OFF G3 | ||
41 | |||
42 | /* assembly code in arch/sparc/net/bpf_jit_asm.S */ | ||
43 | extern u32 bpf_jit_load_word[]; | ||
44 | extern u32 bpf_jit_load_half[]; | ||
45 | extern u32 bpf_jit_load_byte[]; | ||
46 | extern u32 bpf_jit_load_byte_msh[]; | ||
47 | extern u32 bpf_jit_load_word_positive_offset[]; | ||
48 | extern u32 bpf_jit_load_half_positive_offset[]; | ||
49 | extern u32 bpf_jit_load_byte_positive_offset[]; | ||
50 | extern u32 bpf_jit_load_byte_msh_positive_offset[]; | ||
51 | extern u32 bpf_jit_load_word_negative_offset[]; | ||
52 | extern u32 bpf_jit_load_half_negative_offset[]; | ||
53 | extern u32 bpf_jit_load_byte_negative_offset[]; | ||
54 | extern u32 bpf_jit_load_byte_msh_negative_offset[]; | ||
55 | |||
56 | #else | ||
57 | #define r_SKB %o0 | ||
58 | #define r_A %o1 | ||
59 | #define r_X %o2 | ||
60 | #define r_saved_O7 %o3 | ||
61 | #define r_HEADLEN %o4 | ||
62 | #define r_SKB_DATA %o5 | ||
63 | #define r_TMP %g1 | ||
64 | #define r_TMP2 %g2 | ||
65 | #define r_OFF %g3 | ||
66 | #endif | ||
67 | |||
68 | #endif /* _BPF_JIT_H */ | ||
diff --git a/arch/sparc/net/bpf_jit_asm.S b/arch/sparc/net/bpf_jit_asm.S new file mode 100644 index 000000000000..9d016c7017f7 --- /dev/null +++ b/arch/sparc/net/bpf_jit_asm.S | |||
@@ -0,0 +1,205 @@ | |||
1 | #include <asm/ptrace.h> | ||
2 | |||
3 | #include "bpf_jit.h" | ||
4 | |||
5 | #ifdef CONFIG_SPARC64 | ||
6 | #define SAVE_SZ 176 | ||
7 | #define SCRATCH_OFF STACK_BIAS + 128 | ||
8 | #define BE_PTR(label) be,pn %xcc, label | ||
9 | #else | ||
10 | #define SAVE_SZ 96 | ||
11 | #define SCRATCH_OFF 72 | ||
12 | #define BE_PTR(label) be label | ||
13 | #endif | ||
14 | |||
15 | #define SKF_MAX_NEG_OFF (-0x200000) /* SKF_LL_OFF from filter.h */ | ||
16 | |||
17 | .text | ||
18 | .globl bpf_jit_load_word | ||
19 | bpf_jit_load_word: | ||
20 | cmp r_OFF, 0 | ||
21 | bl bpf_slow_path_word_neg | ||
22 | nop | ||
23 | .globl bpf_jit_load_word_positive_offset | ||
24 | bpf_jit_load_word_positive_offset: | ||
25 | sub r_HEADLEN, r_OFF, r_TMP | ||
26 | cmp r_TMP, 3 | ||
27 | ble bpf_slow_path_word | ||
28 | add r_SKB_DATA, r_OFF, r_TMP | ||
29 | andcc r_TMP, 3, %g0 | ||
30 | bne load_word_unaligned | ||
31 | nop | ||
32 | retl | ||
33 | ld [r_TMP], r_A | ||
34 | load_word_unaligned: | ||
35 | ldub [r_TMP + 0x0], r_OFF | ||
36 | ldub [r_TMP + 0x1], r_TMP2 | ||
37 | sll r_OFF, 8, r_OFF | ||
38 | or r_OFF, r_TMP2, r_OFF | ||
39 | ldub [r_TMP + 0x2], r_TMP2 | ||
40 | sll r_OFF, 8, r_OFF | ||
41 | or r_OFF, r_TMP2, r_OFF | ||
42 | ldub [r_TMP + 0x3], r_TMP2 | ||
43 | sll r_OFF, 8, r_OFF | ||
44 | retl | ||
45 | or r_OFF, r_TMP2, r_A | ||
46 | |||
47 | .globl bpf_jit_load_half | ||
48 | bpf_jit_load_half: | ||
49 | cmp r_OFF, 0 | ||
50 | bl bpf_slow_path_half_neg | ||
51 | nop | ||
52 | .globl bpf_jit_load_half_positive_offset | ||
53 | bpf_jit_load_half_positive_offset: | ||
54 | sub r_HEADLEN, r_OFF, r_TMP | ||
55 | cmp r_TMP, 1 | ||
56 | ble bpf_slow_path_half | ||
57 | add r_SKB_DATA, r_OFF, r_TMP | ||
58 | andcc r_TMP, 1, %g0 | ||
59 | bne load_half_unaligned | ||
60 | nop | ||
61 | retl | ||
62 | lduh [r_TMP], r_A | ||
63 | load_half_unaligned: | ||
64 | ldub [r_TMP + 0x0], r_OFF | ||
65 | ldub [r_TMP + 0x1], r_TMP2 | ||
66 | sll r_OFF, 8, r_OFF | ||
67 | retl | ||
68 | or r_OFF, r_TMP2, r_A | ||
69 | |||
70 | .globl bpf_jit_load_byte | ||
71 | bpf_jit_load_byte: | ||
72 | cmp r_OFF, 0 | ||
73 | bl bpf_slow_path_byte_neg | ||
74 | nop | ||
75 | .globl bpf_jit_load_byte_positive_offset | ||
76 | bpf_jit_load_byte_positive_offset: | ||
77 | cmp r_OFF, r_HEADLEN | ||
78 | bge bpf_slow_path_byte | ||
79 | nop | ||
80 | retl | ||
81 | ldub [r_SKB_DATA + r_OFF], r_A | ||
82 | |||
83 | .globl bpf_jit_load_byte_msh | ||
84 | bpf_jit_load_byte_msh: | ||
85 | cmp r_OFF, 0 | ||
86 | bl bpf_slow_path_byte_msh_neg | ||
87 | nop | ||
88 | .globl bpf_jit_load_byte_msh_positive_offset | ||
89 | bpf_jit_load_byte_msh_positive_offset: | ||
90 | cmp r_OFF, r_HEADLEN | ||
91 | bge bpf_slow_path_byte_msh | ||
92 | nop | ||
93 | ldub [r_SKB_DATA + r_OFF], r_OFF | ||
94 | and r_OFF, 0xf, r_OFF | ||
95 | retl | ||
96 | sll r_OFF, 2, r_X | ||
97 | |||
98 | #define bpf_slow_path_common(LEN) \ | ||
99 | save %sp, -SAVE_SZ, %sp; \ | ||
100 | mov %i0, %o0; \ | ||
101 | mov r_OFF, %o1; \ | ||
102 | add %fp, SCRATCH_OFF, %o2; \ | ||
103 | call skb_copy_bits; \ | ||
104 | mov (LEN), %o3; \ | ||
105 | cmp %o0, 0; \ | ||
106 | restore; | ||
107 | |||
108 | bpf_slow_path_word: | ||
109 | bpf_slow_path_common(4) | ||
110 | bl bpf_error | ||
111 | ld [%sp + SCRATCH_OFF], r_A | ||
112 | retl | ||
113 | nop | ||
114 | bpf_slow_path_half: | ||
115 | bpf_slow_path_common(2) | ||
116 | bl bpf_error | ||
117 | lduh [%sp + SCRATCH_OFF], r_A | ||
118 | retl | ||
119 | nop | ||
120 | bpf_slow_path_byte: | ||
121 | bpf_slow_path_common(1) | ||
122 | bl bpf_error | ||
123 | ldub [%sp + SCRATCH_OFF], r_A | ||
124 | retl | ||
125 | nop | ||
126 | bpf_slow_path_byte_msh: | ||
127 | bpf_slow_path_common(1) | ||
128 | bl bpf_error | ||
129 | ldub [%sp + SCRATCH_OFF], r_A | ||
130 | and r_OFF, 0xf, r_OFF | ||
131 | retl | ||
132 | sll r_OFF, 2, r_X | ||
133 | |||
134 | #define bpf_negative_common(LEN) \ | ||
135 | save %sp, -SAVE_SZ, %sp; \ | ||
136 | mov %i0, %o0; \ | ||
137 | mov r_OFF, %o1; \ | ||
138 | call bpf_internal_load_pointer_neg_helper; \ | ||
139 | mov (LEN), %o2; \ | ||
140 | mov %o0, r_TMP; \ | ||
141 | cmp %o0, 0; \ | ||
142 | BE_PTR(bpf_error); \ | ||
143 | restore; | ||
144 | |||
145 | bpf_slow_path_word_neg: | ||
146 | sethi %hi(SKF_MAX_NEG_OFF), r_TMP | ||
147 | cmp r_OFF, r_TMP | ||
148 | bl bpf_error | ||
149 | nop | ||
150 | .globl bpf_jit_load_word_negative_offset | ||
151 | bpf_jit_load_word_negative_offset: | ||
152 | bpf_negative_common(4) | ||
153 | andcc r_TMP, 3, %g0 | ||
154 | bne load_word_unaligned | ||
155 | nop | ||
156 | retl | ||
157 | ld [r_TMP], r_A | ||
158 | |||
159 | bpf_slow_path_half_neg: | ||
160 | sethi %hi(SKF_MAX_NEG_OFF), r_TMP | ||
161 | cmp r_OFF, r_TMP | ||
162 | bl bpf_error | ||
163 | nop | ||
164 | .globl bpf_jit_load_half_negative_offset | ||
165 | bpf_jit_load_half_negative_offset: | ||
166 | bpf_negative_common(2) | ||
167 | andcc r_TMP, 1, %g0 | ||
168 | bne load_half_unaligned | ||
169 | nop | ||
170 | retl | ||
171 | lduh [r_TMP], r_A | ||
172 | |||
173 | bpf_slow_path_byte_neg: | ||
174 | sethi %hi(SKF_MAX_NEG_OFF), r_TMP | ||
175 | cmp r_OFF, r_TMP | ||
176 | bl bpf_error | ||
177 | nop | ||
178 | .globl bpf_jit_load_byte_negative_offset | ||
179 | bpf_jit_load_byte_negative_offset: | ||
180 | bpf_negative_common(1) | ||
181 | retl | ||
182 | ldub [r_TMP], r_A | ||
183 | |||
184 | bpf_slow_path_byte_msh_neg: | ||
185 | sethi %hi(SKF_MAX_NEG_OFF), r_TMP | ||
186 | cmp r_OFF, r_TMP | ||
187 | bl bpf_error | ||
188 | nop | ||
189 | .globl bpf_jit_load_byte_msh_negative_offset | ||
190 | bpf_jit_load_byte_msh_negative_offset: | ||
191 | bpf_negative_common(1) | ||
192 | ldub [r_TMP], r_OFF | ||
193 | and r_OFF, 0xf, r_OFF | ||
194 | retl | ||
195 | sll r_OFF, 2, r_X | ||
196 | |||
197 | bpf_error: | ||
198 | /* Make the JIT program return zero. The JIT epilogue | ||
199 | * stores away the original %o7 into r_saved_O7. The | ||
200 | * normal leaf function return is to use "retl" which | ||
201 | * would evalute to "jmpl %o7 + 8, %g0" but we want to | ||
202 | * use the saved value thus the sequence you see here. | ||
203 | */ | ||
204 | jmpl r_saved_O7 + 8, %g0 | ||
205 | clr %o0 | ||
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c new file mode 100644 index 000000000000..1a69244e785b --- /dev/null +++ b/arch/sparc/net/bpf_jit_comp.c | |||
@@ -0,0 +1,802 @@ | |||
1 | #include <linux/moduleloader.h> | ||
2 | #include <linux/workqueue.h> | ||
3 | #include <linux/netdevice.h> | ||
4 | #include <linux/filter.h> | ||
5 | #include <linux/cache.h> | ||
6 | |||
7 | #include <asm/cacheflush.h> | ||
8 | #include <asm/ptrace.h> | ||
9 | |||
10 | #include "bpf_jit.h" | ||
11 | |||
12 | int bpf_jit_enable __read_mostly; | ||
13 | |||
14 | static inline bool is_simm13(unsigned int value) | ||
15 | { | ||
16 | return value + 0x1000 < 0x2000; | ||
17 | } | ||
18 | |||
19 | static void bpf_flush_icache(void *start_, void *end_) | ||
20 | { | ||
21 | #ifdef CONFIG_SPARC64 | ||
22 | /* Cheetah's I-cache is fully coherent. */ | ||
23 | if (tlb_type == spitfire) { | ||
24 | unsigned long start = (unsigned long) start_; | ||
25 | unsigned long end = (unsigned long) end_; | ||
26 | |||
27 | start &= ~7UL; | ||
28 | end = (end + 7UL) & ~7UL; | ||
29 | while (start < end) { | ||
30 | flushi(start); | ||
31 | start += 32; | ||
32 | } | ||
33 | } | ||
34 | #endif | ||
35 | } | ||
36 | |||
37 | #define SEEN_DATAREF 1 /* might call external helpers */ | ||
38 | #define SEEN_XREG 2 /* ebx is used */ | ||
39 | #define SEEN_MEM 4 /* use mem[] for temporary storage */ | ||
40 | |||
41 | #define S13(X) ((X) & 0x1fff) | ||
42 | #define IMMED 0x00002000 | ||
43 | #define RD(X) ((X) << 25) | ||
44 | #define RS1(X) ((X) << 14) | ||
45 | #define RS2(X) ((X)) | ||
46 | #define OP(X) ((X) << 30) | ||
47 | #define OP2(X) ((X) << 22) | ||
48 | #define OP3(X) ((X) << 19) | ||
49 | #define COND(X) ((X) << 25) | ||
50 | #define F1(X) OP(X) | ||
51 | #define F2(X, Y) (OP(X) | OP2(Y)) | ||
52 | #define F3(X, Y) (OP(X) | OP3(Y)) | ||
53 | |||
54 | #define CONDN COND(0x0) | ||
55 | #define CONDE COND(0x1) | ||
56 | #define CONDLE COND(0x2) | ||
57 | #define CONDL COND(0x3) | ||
58 | #define CONDLEU COND(0x4) | ||
59 | #define CONDCS COND(0x5) | ||
60 | #define CONDNEG COND(0x6) | ||
61 | #define CONDVC COND(0x7) | ||
62 | #define CONDA COND(0x8) | ||
63 | #define CONDNE COND(0x9) | ||
64 | #define CONDG COND(0xa) | ||
65 | #define CONDGE COND(0xb) | ||
66 | #define CONDGU COND(0xc) | ||
67 | #define CONDCC COND(0xd) | ||
68 | #define CONDPOS COND(0xe) | ||
69 | #define CONDVS COND(0xf) | ||
70 | |||
71 | #define CONDGEU CONDCC | ||
72 | #define CONDLU CONDCS | ||
73 | |||
74 | #define WDISP22(X) (((X) >> 2) & 0x3fffff) | ||
75 | |||
76 | #define BA (F2(0, 2) | CONDA) | ||
77 | #define BGU (F2(0, 2) | CONDGU) | ||
78 | #define BLEU (F2(0, 2) | CONDLEU) | ||
79 | #define BGEU (F2(0, 2) | CONDGEU) | ||
80 | #define BLU (F2(0, 2) | CONDLU) | ||
81 | #define BE (F2(0, 2) | CONDE) | ||
82 | #define BNE (F2(0, 2) | CONDNE) | ||
83 | |||
84 | #ifdef CONFIG_SPARC64 | ||
85 | #define BNE_PTR (F2(0, 1) | CONDNE | (2 << 20)) | ||
86 | #else | ||
87 | #define BNE_PTR BNE | ||
88 | #endif | ||
89 | |||
90 | #define SETHI(K, REG) \ | ||
91 | (F2(0, 0x4) | RD(REG) | (((K) >> 10) & 0x3fffff)) | ||
92 | #define OR_LO(K, REG) \ | ||
93 | (F3(2, 0x02) | IMMED | RS1(REG) | ((K) & 0x3ff) | RD(REG)) | ||
94 | |||
95 | #define ADD F3(2, 0x00) | ||
96 | #define AND F3(2, 0x01) | ||
97 | #define ANDCC F3(2, 0x11) | ||
98 | #define OR F3(2, 0x02) | ||
99 | #define SUB F3(2, 0x04) | ||
100 | #define SUBCC F3(2, 0x14) | ||
101 | #define MUL F3(2, 0x0a) /* umul */ | ||
102 | #define DIV F3(2, 0x0e) /* udiv */ | ||
103 | #define SLL F3(2, 0x25) | ||
104 | #define SRL F3(2, 0x26) | ||
105 | #define JMPL F3(2, 0x38) | ||
106 | #define CALL F1(1) | ||
107 | #define BR F2(0, 0x01) | ||
108 | #define RD_Y F3(2, 0x28) | ||
109 | #define WR_Y F3(2, 0x30) | ||
110 | |||
111 | #define LD32 F3(3, 0x00) | ||
112 | #define LD8 F3(3, 0x01) | ||
113 | #define LD16 F3(3, 0x02) | ||
114 | #define LD64 F3(3, 0x0b) | ||
115 | #define ST32 F3(3, 0x04) | ||
116 | |||
117 | #ifdef CONFIG_SPARC64 | ||
118 | #define LDPTR LD64 | ||
119 | #define BASE_STACKFRAME 176 | ||
120 | #else | ||
121 | #define LDPTR LD32 | ||
122 | #define BASE_STACKFRAME 96 | ||
123 | #endif | ||
124 | |||
125 | #define LD32I (LD32 | IMMED) | ||
126 | #define LD8I (LD8 | IMMED) | ||
127 | #define LD16I (LD16 | IMMED) | ||
128 | #define LD64I (LD64 | IMMED) | ||
129 | #define LDPTRI (LDPTR | IMMED) | ||
130 | #define ST32I (ST32 | IMMED) | ||
131 | |||
132 | #define emit_nop() \ | ||
133 | do { \ | ||
134 | *prog++ = SETHI(0, G0); \ | ||
135 | } while (0) | ||
136 | |||
137 | #define emit_neg() \ | ||
138 | do { /* sub %g0, r_A, r_A */ \ | ||
139 | *prog++ = SUB | RS1(G0) | RS2(r_A) | RD(r_A); \ | ||
140 | } while (0) | ||
141 | |||
142 | #define emit_reg_move(FROM, TO) \ | ||
143 | do { /* or %g0, FROM, TO */ \ | ||
144 | *prog++ = OR | RS1(G0) | RS2(FROM) | RD(TO); \ | ||
145 | } while (0) | ||
146 | |||
147 | #define emit_clear(REG) \ | ||
148 | do { /* or %g0, %g0, REG */ \ | ||
149 | *prog++ = OR | RS1(G0) | RS2(G0) | RD(REG); \ | ||
150 | } while (0) | ||
151 | |||
152 | #define emit_set_const(K, REG) \ | ||
153 | do { /* sethi %hi(K), REG */ \ | ||
154 | *prog++ = SETHI(K, REG); \ | ||
155 | /* or REG, %lo(K), REG */ \ | ||
156 | *prog++ = OR_LO(K, REG); \ | ||
157 | } while (0) | ||
158 | |||
159 | /* Emit | ||
160 | * | ||
161 | * OP r_A, r_X, r_A | ||
162 | */ | ||
163 | #define emit_alu_X(OPCODE) \ | ||
164 | do { \ | ||
165 | seen |= SEEN_XREG; \ | ||
166 | *prog++ = OPCODE | RS1(r_A) | RS2(r_X) | RD(r_A); \ | ||
167 | } while (0) | ||
168 | |||
169 | /* Emit either: | ||
170 | * | ||
171 | * OP r_A, K, r_A | ||
172 | * | ||
173 | * or | ||
174 | * | ||
175 | * sethi %hi(K), r_TMP | ||
176 | * or r_TMP, %lo(K), r_TMP | ||
177 | * OP r_A, r_TMP, r_A | ||
178 | * | ||
179 | * depending upon whether K fits in a signed 13-bit | ||
180 | * immediate instruction field. Emit nothing if K | ||
181 | * is zero. | ||
182 | */ | ||
183 | #define emit_alu_K(OPCODE, K) \ | ||
184 | do { \ | ||
185 | if (K) { \ | ||
186 | unsigned int _insn = OPCODE; \ | ||
187 | _insn |= RS1(r_A) | RD(r_A); \ | ||
188 | if (is_simm13(K)) { \ | ||
189 | *prog++ = _insn | IMMED | S13(K); \ | ||
190 | } else { \ | ||
191 | emit_set_const(K, r_TMP); \ | ||
192 | *prog++ = _insn | RS2(r_TMP); \ | ||
193 | } \ | ||
194 | } \ | ||
195 | } while (0) | ||
196 | |||
197 | #define emit_loadimm(K, DEST) \ | ||
198 | do { \ | ||
199 | if (is_simm13(K)) { \ | ||
200 | /* or %g0, K, DEST */ \ | ||
201 | *prog++ = OR | IMMED | RS1(G0) | S13(K) | RD(DEST); \ | ||
202 | } else { \ | ||
203 | emit_set_const(K, DEST); \ | ||
204 | } \ | ||
205 | } while (0) | ||
206 | |||
207 | #define emit_loadptr(BASE, STRUCT, FIELD, DEST) \ | ||
208 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | ||
209 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(void *)); \ | ||
210 | *prog++ = LDPTRI | RS1(BASE) | S13(_off) | RD(DEST); \ | ||
211 | } while (0) | ||
212 | |||
213 | #define emit_load32(BASE, STRUCT, FIELD, DEST) \ | ||
214 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | ||
215 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u32)); \ | ||
216 | *prog++ = LD32I | RS1(BASE) | S13(_off) | RD(DEST); \ | ||
217 | } while (0) | ||
218 | |||
219 | #define emit_load16(BASE, STRUCT, FIELD, DEST) \ | ||
220 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | ||
221 | BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u16)); \ | ||
222 | *prog++ = LD16I | RS1(BASE) | S13(_off) | RD(DEST); \ | ||
223 | } while (0) | ||
224 | |||
225 | #define __emit_load8(BASE, STRUCT, FIELD, DEST) \ | ||
226 | do { unsigned int _off = offsetof(STRUCT, FIELD); \ | ||
227 | *prog++ = LD8I | RS1(BASE) | S13(_off) | RD(DEST); \ | ||
228 | } while (0) | ||
229 | |||
230 | #define emit_load8(BASE, STRUCT, FIELD, DEST) \ | ||
231 | do { BUILD_BUG_ON(FIELD_SIZEOF(STRUCT, FIELD) != sizeof(u8)); \ | ||
232 | __emit_load8(BASE, STRUCT, FIELD, DEST); \ | ||
233 | } while (0) | ||
234 | |||
235 | #define emit_ldmem(OFF, DEST) \ | ||
236 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(DEST); \ | ||
237 | } while (0) | ||
238 | |||
239 | #define emit_stmem(OFF, SRC) \ | ||
240 | do { *prog++ = LD32I | RS1(FP) | S13(-(OFF)) | RD(SRC); \ | ||
241 | } while (0) | ||
242 | |||
243 | #ifdef CONFIG_SMP | ||
244 | #ifdef CONFIG_SPARC64 | ||
245 | #define emit_load_cpu(REG) \ | ||
246 | emit_load16(G6, struct thread_info, cpu, REG) | ||
247 | #else | ||
248 | #define emit_load_cpu(REG) \ | ||
249 | emit_load32(G6, struct thread_info, cpu, REG) | ||
250 | #endif | ||
251 | #else | ||
252 | #define emit_load_cpu(REG) emit_clear(REG) | ||
253 | #endif | ||
254 | |||
255 | #define emit_skb_loadptr(FIELD, DEST) \ | ||
256 | emit_loadptr(r_SKB, struct sk_buff, FIELD, DEST) | ||
257 | #define emit_skb_load32(FIELD, DEST) \ | ||
258 | emit_load32(r_SKB, struct sk_buff, FIELD, DEST) | ||
259 | #define emit_skb_load16(FIELD, DEST) \ | ||
260 | emit_load16(r_SKB, struct sk_buff, FIELD, DEST) | ||
261 | #define __emit_skb_load8(FIELD, DEST) \ | ||
262 | __emit_load8(r_SKB, struct sk_buff, FIELD, DEST) | ||
263 | #define emit_skb_load8(FIELD, DEST) \ | ||
264 | emit_load8(r_SKB, struct sk_buff, FIELD, DEST) | ||
265 | |||
266 | #define emit_jmpl(BASE, IMM_OFF, LREG) \ | ||
267 | *prog++ = (JMPL | IMMED | RS1(BASE) | S13(IMM_OFF) | RD(LREG)) | ||
268 | |||
269 | #define emit_call(FUNC) \ | ||
270 | do { void *_here = image + addrs[i] - 8; \ | ||
271 | unsigned int _off = (void *)(FUNC) - _here; \ | ||
272 | *prog++ = CALL | (((_off) >> 2) & 0x3fffffff); \ | ||
273 | emit_nop(); \ | ||
274 | } while (0) | ||
275 | |||
276 | #define emit_branch(BR_OPC, DEST) \ | ||
277 | do { unsigned int _here = addrs[i] - 8; \ | ||
278 | *prog++ = BR_OPC | WDISP22((DEST) - _here); \ | ||
279 | } while (0) | ||
280 | |||
281 | #define emit_branch_off(BR_OPC, OFF) \ | ||
282 | do { *prog++ = BR_OPC | WDISP22(OFF); \ | ||
283 | } while (0) | ||
284 | |||
285 | #define emit_jump(DEST) emit_branch(BA, DEST) | ||
286 | |||
287 | #define emit_read_y(REG) *prog++ = RD_Y | RD(REG) | ||
288 | #define emit_write_y(REG) *prog++ = WR_Y | IMMED | RS1(REG) | S13(0) | ||
289 | |||
290 | #define emit_cmp(R1, R2) \ | ||
291 | *prog++ = (SUBCC | RS1(R1) | RS2(R2) | RD(G0)) | ||
292 | |||
293 | #define emit_cmpi(R1, IMM) \ | ||
294 | *prog++ = (SUBCC | IMMED | RS1(R1) | S13(IMM) | RD(G0)); | ||
295 | |||
296 | #define emit_btst(R1, R2) \ | ||
297 | *prog++ = (ANDCC | RS1(R1) | RS2(R2) | RD(G0)) | ||
298 | |||
299 | #define emit_btsti(R1, IMM) \ | ||
300 | *prog++ = (ANDCC | IMMED | RS1(R1) | S13(IMM) | RD(G0)); | ||
301 | |||
302 | #define emit_sub(R1, R2, R3) \ | ||
303 | *prog++ = (SUB | RS1(R1) | RS2(R2) | RD(R3)) | ||
304 | |||
305 | #define emit_subi(R1, IMM, R3) \ | ||
306 | *prog++ = (SUB | IMMED | RS1(R1) | S13(IMM) | RD(R3)) | ||
307 | |||
308 | #define emit_add(R1, R2, R3) \ | ||
309 | *prog++ = (ADD | RS1(R1) | RS2(R2) | RD(R3)) | ||
310 | |||
311 | #define emit_addi(R1, IMM, R3) \ | ||
312 | *prog++ = (ADD | IMMED | RS1(R1) | S13(IMM) | RD(R3)) | ||
313 | |||
314 | #define emit_alloc_stack(SZ) \ | ||
315 | *prog++ = (SUB | IMMED | RS1(SP) | S13(SZ) | RD(SP)) | ||
316 | |||
317 | #define emit_release_stack(SZ) \ | ||
318 | *prog++ = (ADD | IMMED | RS1(SP) | S13(SZ) | RD(SP)) | ||
319 | |||
320 | /* A note about branch offset calculations. The addrs[] array, | ||
321 | * indexed by BPF instruction, records the address after all the | ||
322 | * sparc instructions emitted for that BPF instruction. | ||
323 | * | ||
324 | * The most common case is to emit a branch at the end of such | ||
325 | * a code sequence. So this would be two instructions, the | ||
326 | * branch and it's delay slot. | ||
327 | * | ||
328 | * Therefore by default the branch emitters calculate the branch | ||
329 | * offset field as: | ||
330 | * | ||
331 | * destination - (addrs[i] - 8) | ||
332 | * | ||
333 | * This "addrs[i] - 8" is the address of the branch itself or | ||
334 | * what "." would be in assembler notation. The "8" part is | ||
335 | * how we take into consideration the branch and it's delay | ||
336 | * slot mentioned above. | ||
337 | * | ||
338 | * Sometimes we need to emit a branch earlier in the code | ||
339 | * sequence. And in these situations we adjust "destination" | ||
340 | * to accomodate this difference. For example, if we needed | ||
341 | * to emit a branch (and it's delay slot) right before the | ||
342 | * final instruction emitted for a BPF opcode, we'd use | ||
343 | * "destination + 4" instead of just plain "destination" above. | ||
344 | * | ||
345 | * This is why you see all of these funny emit_branch() and | ||
346 | * emit_jump() calls with adjusted offsets. | ||
347 | */ | ||
348 | |||
349 | void bpf_jit_compile(struct sk_filter *fp) | ||
350 | { | ||
351 | unsigned int cleanup_addr, proglen, oldproglen = 0; | ||
352 | u32 temp[8], *prog, *func, seen = 0, pass; | ||
353 | const struct sock_filter *filter = fp->insns; | ||
354 | int i, flen = fp->len, pc_ret0 = -1; | ||
355 | unsigned int *addrs; | ||
356 | void *image; | ||
357 | |||
358 | if (!bpf_jit_enable) | ||
359 | return; | ||
360 | |||
361 | addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL); | ||
362 | if (addrs == NULL) | ||
363 | return; | ||
364 | |||
365 | /* Before first pass, make a rough estimation of addrs[] | ||
366 | * each bpf instruction is translated to less than 64 bytes | ||
367 | */ | ||
368 | for (proglen = 0, i = 0; i < flen; i++) { | ||
369 | proglen += 64; | ||
370 | addrs[i] = proglen; | ||
371 | } | ||
372 | cleanup_addr = proglen; /* epilogue address */ | ||
373 | image = NULL; | ||
374 | for (pass = 0; pass < 10; pass++) { | ||
375 | u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen; | ||
376 | |||
377 | /* no prologue/epilogue for trivial filters (RET something) */ | ||
378 | proglen = 0; | ||
379 | prog = temp; | ||
380 | |||
381 | /* Prologue */ | ||
382 | if (seen_or_pass0) { | ||
383 | if (seen_or_pass0 & SEEN_MEM) { | ||
384 | unsigned int sz = BASE_STACKFRAME; | ||
385 | sz += BPF_MEMWORDS * sizeof(u32); | ||
386 | emit_alloc_stack(sz); | ||
387 | } | ||
388 | |||
389 | /* Make sure we dont leek kernel memory. */ | ||
390 | if (seen_or_pass0 & SEEN_XREG) | ||
391 | emit_clear(r_X); | ||
392 | |||
393 | /* If this filter needs to access skb data, | ||
394 | * load %o4 and %o5 with: | ||
395 | * %o4 = skb->len - skb->data_len | ||
396 | * %o5 = skb->data | ||
397 | * And also back up %o7 into r_saved_O7 so we can | ||
398 | * invoke the stubs using 'call'. | ||
399 | */ | ||
400 | if (seen_or_pass0 & SEEN_DATAREF) { | ||
401 | emit_load32(r_SKB, struct sk_buff, len, r_HEADLEN); | ||
402 | emit_load32(r_SKB, struct sk_buff, data_len, r_TMP); | ||
403 | emit_sub(r_HEADLEN, r_TMP, r_HEADLEN); | ||
404 | emit_loadptr(r_SKB, struct sk_buff, data, r_SKB_DATA); | ||
405 | } | ||
406 | } | ||
407 | emit_reg_move(O7, r_saved_O7); | ||
408 | |||
409 | switch (filter[0].code) { | ||
410 | case BPF_S_RET_K: | ||
411 | case BPF_S_LD_W_LEN: | ||
412 | case BPF_S_ANC_PROTOCOL: | ||
413 | case BPF_S_ANC_PKTTYPE: | ||
414 | case BPF_S_ANC_IFINDEX: | ||
415 | case BPF_S_ANC_MARK: | ||
416 | case BPF_S_ANC_RXHASH: | ||
417 | case BPF_S_ANC_CPU: | ||
418 | case BPF_S_ANC_QUEUE: | ||
419 | case BPF_S_LD_W_ABS: | ||
420 | case BPF_S_LD_H_ABS: | ||
421 | case BPF_S_LD_B_ABS: | ||
422 | /* The first instruction sets the A register (or is | ||
423 | * a "RET 'constant'") | ||
424 | */ | ||
425 | break; | ||
426 | default: | ||
427 | /* Make sure we dont leak kernel information to the | ||
428 | * user. | ||
429 | */ | ||
430 | emit_clear(r_A); /* A = 0 */ | ||
431 | } | ||
432 | |||
433 | for (i = 0; i < flen; i++) { | ||
434 | unsigned int K = filter[i].k; | ||
435 | unsigned int t_offset; | ||
436 | unsigned int f_offset; | ||
437 | u32 t_op, f_op; | ||
438 | int ilen; | ||
439 | |||
440 | switch (filter[i].code) { | ||
441 | case BPF_S_ALU_ADD_X: /* A += X; */ | ||
442 | emit_alu_X(ADD); | ||
443 | break; | ||
444 | case BPF_S_ALU_ADD_K: /* A += K; */ | ||
445 | emit_alu_K(ADD, K); | ||
446 | break; | ||
447 | case BPF_S_ALU_SUB_X: /* A -= X; */ | ||
448 | emit_alu_X(SUB); | ||
449 | break; | ||
450 | case BPF_S_ALU_SUB_K: /* A -= K */ | ||
451 | emit_alu_K(SUB, K); | ||
452 | break; | ||
453 | case BPF_S_ALU_AND_X: /* A &= X */ | ||
454 | emit_alu_X(AND); | ||
455 | break; | ||
456 | case BPF_S_ALU_AND_K: /* A &= K */ | ||
457 | emit_alu_K(AND, K); | ||
458 | break; | ||
459 | case BPF_S_ALU_OR_X: /* A |= X */ | ||
460 | emit_alu_X(OR); | ||
461 | break; | ||
462 | case BPF_S_ALU_OR_K: /* A |= K */ | ||
463 | emit_alu_K(OR, K); | ||
464 | break; | ||
465 | case BPF_S_ALU_LSH_X: /* A <<= X */ | ||
466 | emit_alu_X(SLL); | ||
467 | break; | ||
468 | case BPF_S_ALU_LSH_K: /* A <<= K */ | ||
469 | emit_alu_K(SLL, K); | ||
470 | break; | ||
471 | case BPF_S_ALU_RSH_X: /* A >>= X */ | ||
472 | emit_alu_X(SRL); | ||
473 | break; | ||
474 | case BPF_S_ALU_RSH_K: /* A >>= K */ | ||
475 | emit_alu_K(SRL, K); | ||
476 | break; | ||
477 | case BPF_S_ALU_MUL_X: /* A *= X; */ | ||
478 | emit_alu_X(MUL); | ||
479 | break; | ||
480 | case BPF_S_ALU_MUL_K: /* A *= K */ | ||
481 | emit_alu_K(MUL, K); | ||
482 | break; | ||
483 | case BPF_S_ALU_DIV_K: /* A /= K */ | ||
484 | emit_alu_K(MUL, K); | ||
485 | emit_read_y(r_A); | ||
486 | break; | ||
487 | case BPF_S_ALU_DIV_X: /* A /= X; */ | ||
488 | emit_cmpi(r_X, 0); | ||
489 | if (pc_ret0 > 0) { | ||
490 | t_offset = addrs[pc_ret0 - 1]; | ||
491 | #ifdef CONFIG_SPARC32 | ||
492 | emit_branch(BE, t_offset + 20); | ||
493 | #else | ||
494 | emit_branch(BE, t_offset + 8); | ||
495 | #endif | ||
496 | emit_nop(); /* delay slot */ | ||
497 | } else { | ||
498 | emit_branch_off(BNE, 16); | ||
499 | emit_nop(); | ||
500 | #ifdef CONFIG_SPARC32 | ||
501 | emit_jump(cleanup_addr + 20); | ||
502 | #else | ||
503 | emit_jump(cleanup_addr + 8); | ||
504 | #endif | ||
505 | emit_clear(r_A); | ||
506 | } | ||
507 | emit_write_y(G0); | ||
508 | #ifdef CONFIG_SPARC32 | ||
509 | /* The Sparc v8 architecture requires | ||
510 | * three instructions between a %y | ||
511 | * register write and the first use. | ||
512 | */ | ||
513 | emit_nop(); | ||
514 | emit_nop(); | ||
515 | emit_nop(); | ||
516 | #endif | ||
517 | emit_alu_X(DIV); | ||
518 | break; | ||
519 | case BPF_S_ALU_NEG: | ||
520 | emit_neg(); | ||
521 | break; | ||
522 | case BPF_S_RET_K: | ||
523 | if (!K) { | ||
524 | if (pc_ret0 == -1) | ||
525 | pc_ret0 = i; | ||
526 | emit_clear(r_A); | ||
527 | } else { | ||
528 | emit_loadimm(K, r_A); | ||
529 | } | ||
530 | /* Fallthrough */ | ||
531 | case BPF_S_RET_A: | ||
532 | if (seen_or_pass0) { | ||
533 | if (i != flen - 1) { | ||
534 | emit_jump(cleanup_addr); | ||
535 | emit_nop(); | ||
536 | break; | ||
537 | } | ||
538 | if (seen_or_pass0 & SEEN_MEM) { | ||
539 | unsigned int sz = BASE_STACKFRAME; | ||
540 | sz += BPF_MEMWORDS * sizeof(u32); | ||
541 | emit_release_stack(sz); | ||
542 | } | ||
543 | } | ||
544 | /* jmpl %r_saved_O7 + 8, %g0 */ | ||
545 | emit_jmpl(r_saved_O7, 8, G0); | ||
546 | emit_reg_move(r_A, O0); /* delay slot */ | ||
547 | break; | ||
548 | case BPF_S_MISC_TAX: | ||
549 | seen |= SEEN_XREG; | ||
550 | emit_reg_move(r_A, r_X); | ||
551 | break; | ||
552 | case BPF_S_MISC_TXA: | ||
553 | seen |= SEEN_XREG; | ||
554 | emit_reg_move(r_X, r_A); | ||
555 | break; | ||
556 | case BPF_S_ANC_CPU: | ||
557 | emit_load_cpu(r_A); | ||
558 | break; | ||
559 | case BPF_S_ANC_PROTOCOL: | ||
560 | emit_skb_load16(protocol, r_A); | ||
561 | break; | ||
562 | #if 0 | ||
563 | /* GCC won't let us take the address of | ||
564 | * a bit field even though we very much | ||
565 | * know what we are doing here. | ||
566 | */ | ||
567 | case BPF_S_ANC_PKTTYPE: | ||
568 | __emit_skb_load8(pkt_type, r_A); | ||
569 | emit_alu_K(SRL, 5); | ||
570 | break; | ||
571 | #endif | ||
572 | case BPF_S_ANC_IFINDEX: | ||
573 | emit_skb_loadptr(dev, r_A); | ||
574 | emit_cmpi(r_A, 0); | ||
575 | emit_branch(BNE_PTR, cleanup_addr + 4); | ||
576 | emit_nop(); | ||
577 | emit_load32(r_A, struct net_device, ifindex, r_A); | ||
578 | break; | ||
579 | case BPF_S_ANC_MARK: | ||
580 | emit_skb_load32(mark, r_A); | ||
581 | break; | ||
582 | case BPF_S_ANC_QUEUE: | ||
583 | emit_skb_load16(queue_mapping, r_A); | ||
584 | break; | ||
585 | case BPF_S_ANC_HATYPE: | ||
586 | emit_skb_loadptr(dev, r_A); | ||
587 | emit_cmpi(r_A, 0); | ||
588 | emit_branch(BNE_PTR, cleanup_addr + 4); | ||
589 | emit_nop(); | ||
590 | emit_load16(r_A, struct net_device, type, r_A); | ||
591 | break; | ||
592 | case BPF_S_ANC_RXHASH: | ||
593 | emit_skb_load32(rxhash, r_A); | ||
594 | break; | ||
595 | |||
596 | case BPF_S_LD_IMM: | ||
597 | emit_loadimm(K, r_A); | ||
598 | break; | ||
599 | case BPF_S_LDX_IMM: | ||
600 | emit_loadimm(K, r_X); | ||
601 | break; | ||
602 | case BPF_S_LD_MEM: | ||
603 | emit_ldmem(K * 4, r_A); | ||
604 | break; | ||
605 | case BPF_S_LDX_MEM: | ||
606 | emit_ldmem(K * 4, r_X); | ||
607 | break; | ||
608 | case BPF_S_ST: | ||
609 | emit_stmem(K * 4, r_A); | ||
610 | break; | ||
611 | case BPF_S_STX: | ||
612 | emit_stmem(K * 4, r_X); | ||
613 | break; | ||
614 | |||
615 | #define CHOOSE_LOAD_FUNC(K, func) \ | ||
616 | ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative_offset : func) : func##_positive_offset) | ||
617 | |||
618 | case BPF_S_LD_W_ABS: | ||
619 | func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_word); | ||
620 | common_load: seen |= SEEN_DATAREF; | ||
621 | emit_loadimm(K, r_OFF); | ||
622 | emit_call(func); | ||
623 | break; | ||
624 | case BPF_S_LD_H_ABS: | ||
625 | func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_half); | ||
626 | goto common_load; | ||
627 | case BPF_S_LD_B_ABS: | ||
628 | func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_byte); | ||
629 | goto common_load; | ||
630 | case BPF_S_LDX_B_MSH: | ||
631 | func = CHOOSE_LOAD_FUNC(K, bpf_jit_load_byte_msh); | ||
632 | goto common_load; | ||
633 | case BPF_S_LD_W_IND: | ||
634 | func = bpf_jit_load_word; | ||
635 | common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG; | ||
636 | if (K) { | ||
637 | if (is_simm13(K)) { | ||
638 | emit_addi(r_X, K, r_OFF); | ||
639 | } else { | ||
640 | emit_loadimm(K, r_TMP); | ||
641 | emit_add(r_X, r_TMP, r_OFF); | ||
642 | } | ||
643 | } else { | ||
644 | emit_reg_move(r_X, r_OFF); | ||
645 | } | ||
646 | emit_call(func); | ||
647 | break; | ||
648 | case BPF_S_LD_H_IND: | ||
649 | func = bpf_jit_load_half; | ||
650 | goto common_load_ind; | ||
651 | case BPF_S_LD_B_IND: | ||
652 | func = bpf_jit_load_byte; | ||
653 | goto common_load_ind; | ||
654 | case BPF_S_JMP_JA: | ||
655 | emit_jump(addrs[i + K]); | ||
656 | emit_nop(); | ||
657 | break; | ||
658 | |||
659 | #define COND_SEL(CODE, TOP, FOP) \ | ||
660 | case CODE: \ | ||
661 | t_op = TOP; \ | ||
662 | f_op = FOP; \ | ||
663 | goto cond_branch | ||
664 | |||
665 | COND_SEL(BPF_S_JMP_JGT_K, BGU, BLEU); | ||
666 | COND_SEL(BPF_S_JMP_JGE_K, BGEU, BLU); | ||
667 | COND_SEL(BPF_S_JMP_JEQ_K, BE, BNE); | ||
668 | COND_SEL(BPF_S_JMP_JSET_K, BNE, BE); | ||
669 | COND_SEL(BPF_S_JMP_JGT_X, BGU, BLEU); | ||
670 | COND_SEL(BPF_S_JMP_JGE_X, BGEU, BLU); | ||
671 | COND_SEL(BPF_S_JMP_JEQ_X, BE, BNE); | ||
672 | COND_SEL(BPF_S_JMP_JSET_X, BNE, BE); | ||
673 | |||
674 | cond_branch: f_offset = addrs[i + filter[i].jf]; | ||
675 | t_offset = addrs[i + filter[i].jt]; | ||
676 | |||
677 | /* same targets, can avoid doing the test :) */ | ||
678 | if (filter[i].jt == filter[i].jf) { | ||
679 | emit_jump(t_offset); | ||
680 | emit_nop(); | ||
681 | break; | ||
682 | } | ||
683 | |||
684 | switch (filter[i].code) { | ||
685 | case BPF_S_JMP_JGT_X: | ||
686 | case BPF_S_JMP_JGE_X: | ||
687 | case BPF_S_JMP_JEQ_X: | ||
688 | seen |= SEEN_XREG; | ||
689 | emit_cmp(r_A, r_X); | ||
690 | break; | ||
691 | case BPF_S_JMP_JSET_X: | ||
692 | seen |= SEEN_XREG; | ||
693 | emit_btst(r_A, r_X); | ||
694 | break; | ||
695 | case BPF_S_JMP_JEQ_K: | ||
696 | case BPF_S_JMP_JGT_K: | ||
697 | case BPF_S_JMP_JGE_K: | ||
698 | if (is_simm13(K)) { | ||
699 | emit_cmpi(r_A, K); | ||
700 | } else { | ||
701 | emit_loadimm(K, r_TMP); | ||
702 | emit_cmp(r_A, r_TMP); | ||
703 | } | ||
704 | break; | ||
705 | case BPF_S_JMP_JSET_K: | ||
706 | if (is_simm13(K)) { | ||
707 | emit_btsti(r_A, K); | ||
708 | } else { | ||
709 | emit_loadimm(K, r_TMP); | ||
710 | emit_btst(r_A, r_TMP); | ||
711 | } | ||
712 | break; | ||
713 | } | ||
714 | if (filter[i].jt != 0) { | ||
715 | if (filter[i].jf) | ||
716 | t_offset += 8; | ||
717 | emit_branch(t_op, t_offset); | ||
718 | emit_nop(); /* delay slot */ | ||
719 | if (filter[i].jf) { | ||
720 | emit_jump(f_offset); | ||
721 | emit_nop(); | ||
722 | } | ||
723 | break; | ||
724 | } | ||
725 | emit_branch(f_op, f_offset); | ||
726 | emit_nop(); /* delay slot */ | ||
727 | break; | ||
728 | |||
729 | default: | ||
730 | /* hmm, too complex filter, give up with jit compiler */ | ||
731 | goto out; | ||
732 | } | ||
733 | ilen = (void *) prog - (void *) temp; | ||
734 | if (image) { | ||
735 | if (unlikely(proglen + ilen > oldproglen)) { | ||
736 | pr_err("bpb_jit_compile fatal error\n"); | ||
737 | kfree(addrs); | ||
738 | module_free(NULL, image); | ||
739 | return; | ||
740 | } | ||
741 | memcpy(image + proglen, temp, ilen); | ||
742 | } | ||
743 | proglen += ilen; | ||
744 | addrs[i] = proglen; | ||
745 | prog = temp; | ||
746 | } | ||
747 | /* last bpf instruction is always a RET : | ||
748 | * use it to give the cleanup instruction(s) addr | ||
749 | */ | ||
750 | cleanup_addr = proglen - 8; /* jmpl; mov r_A,%o0; */ | ||
751 | if (seen_or_pass0 & SEEN_MEM) | ||
752 | cleanup_addr -= 4; /* add %sp, X, %sp; */ | ||
753 | |||
754 | if (image) { | ||
755 | if (proglen != oldproglen) | ||
756 | pr_err("bpb_jit_compile proglen=%u != oldproglen=%u\n", | ||
757 | proglen, oldproglen); | ||
758 | break; | ||
759 | } | ||
760 | if (proglen == oldproglen) { | ||
761 | image = module_alloc(max_t(unsigned int, | ||
762 | proglen, | ||
763 | sizeof(struct work_struct))); | ||
764 | if (!image) | ||
765 | goto out; | ||
766 | } | ||
767 | oldproglen = proglen; | ||
768 | } | ||
769 | |||
770 | if (bpf_jit_enable > 1) | ||
771 | pr_err("flen=%d proglen=%u pass=%d image=%p\n", | ||
772 | flen, proglen, pass, image); | ||
773 | |||
774 | if (image) { | ||
775 | if (bpf_jit_enable > 1) | ||
776 | print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS, | ||
777 | 16, 1, image, proglen, false); | ||
778 | bpf_flush_icache(image, image + proglen); | ||
779 | fp->bpf_func = (void *)image; | ||
780 | } | ||
781 | out: | ||
782 | kfree(addrs); | ||
783 | return; | ||
784 | } | ||
785 | |||
786 | static void jit_free_defer(struct work_struct *arg) | ||
787 | { | ||
788 | module_free(NULL, arg); | ||
789 | } | ||
790 | |||
791 | /* run from softirq, we must use a work_struct to call | ||
792 | * module_free() from process context | ||
793 | */ | ||
794 | void bpf_jit_free(struct sk_filter *fp) | ||
795 | { | ||
796 | if (fp->bpf_func != sk_run_filter) { | ||
797 | struct work_struct *work = (struct work_struct *)fp->bpf_func; | ||
798 | |||
799 | INIT_WORK(work, jit_free_defer); | ||
800 | schedule_work(work); | ||
801 | } | ||
802 | } | ||
diff --git a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile index 8287bbe88768..020300b18c0b 100644 --- a/arch/sparc/prom/Makefile +++ b/arch/sparc/prom/Makefile | |||
@@ -10,7 +10,6 @@ lib-$(CONFIG_SPARC32) += memory.o | |||
10 | lib-y += misc_$(BITS).o | 10 | lib-y += misc_$(BITS).o |
11 | lib-$(CONFIG_SPARC32) += mp.o | 11 | lib-$(CONFIG_SPARC32) += mp.o |
12 | lib-$(CONFIG_SPARC32) += ranges.o | 12 | lib-$(CONFIG_SPARC32) += ranges.o |
13 | lib-$(CONFIG_SPARC32) += segment.o | ||
14 | lib-y += console_$(BITS).o | 13 | lib-y += console_$(BITS).o |
15 | lib-y += printf.o | 14 | lib-y += printf.o |
16 | lib-y += tree_$(BITS).o | 15 | lib-y += tree_$(BITS).o |
diff --git a/arch/sparc/prom/segment.c b/arch/sparc/prom/segment.c deleted file mode 100644 index 86a663f1d3c5..000000000000 --- a/arch/sparc/prom/segment.c +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | /* | ||
2 | * segment.c: Prom routine to map segments in other contexts before | ||
3 | * a standalone is completely mapped. This is for sun4 and | ||
4 | * sun4c architectures only. | ||
5 | * | ||
6 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <asm/openprom.h> | ||
13 | #include <asm/oplib.h> | ||
14 | |||
15 | extern void restore_current(void); | ||
16 | |||
17 | /* Set physical segment 'segment' at virtual address 'vaddr' in | ||
18 | * context 'ctx'. | ||
19 | */ | ||
20 | void | ||
21 | prom_putsegment(int ctx, unsigned long vaddr, int segment) | ||
22 | { | ||
23 | unsigned long flags; | ||
24 | spin_lock_irqsave(&prom_lock, flags); | ||
25 | (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); | ||
26 | restore_current(); | ||
27 | spin_unlock_irqrestore(&prom_lock, flags); | ||
28 | } | ||