diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /arch/sparc | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'arch/sparc')
69 files changed, 9827 insertions, 0 deletions
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c new file mode 100644 index 00000000000..da031159e2b --- /dev/null +++ b/arch/sparc/boot/btfixupprep.c | |||
@@ -0,0 +1,386 @@ | |||
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/apc.h b/arch/sparc/include/asm/apc.h new file mode 100644 index 00000000000..24e9a7d4d97 --- /dev/null +++ b/arch/sparc/include/asm/apc.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* apc - Driver definitions for power management functions | ||
2 | * of Aurora Personality Chip (APC) on SPARCstation-4/5 and | ||
3 | * derivatives | ||
4 | * | ||
5 | * Copyright (c) 2001 Eric Brower (ebrower@usa.net) | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #ifndef _SPARC_APC_H | ||
10 | #define _SPARC_APC_H | ||
11 | |||
12 | #include <linux/ioctl.h> | ||
13 | |||
14 | #define APC_IOC 'A' | ||
15 | |||
16 | #define APCIOCGFANCTL _IOR(APC_IOC, 0x00, int) /* Get fan speed */ | ||
17 | #define APCIOCSFANCTL _IOW(APC_IOC, 0x01, int) /* Set fan speed */ | ||
18 | |||
19 | #define APCIOCGCPWR _IOR(APC_IOC, 0x02, int) /* Get CPOWER state */ | ||
20 | #define APCIOCSCPWR _IOW(APC_IOC, 0x03, int) /* Set CPOWER state */ | ||
21 | |||
22 | #define APCIOCGBPORT _IOR(APC_IOC, 0x04, int) /* Get BPORT state */ | ||
23 | #define APCIOCSBPORT _IOW(APC_IOC, 0x05, int) /* Set BPORT state */ | ||
24 | |||
25 | /* | ||
26 | * Register offsets | ||
27 | */ | ||
28 | #define APC_IDLE_REG 0x00 | ||
29 | #define APC_FANCTL_REG 0x20 | ||
30 | #define APC_CPOWER_REG 0x24 | ||
31 | #define APC_BPORT_REG 0x30 | ||
32 | |||
33 | #define APC_REGMASK 0x01 | ||
34 | #define APC_BPMASK 0x03 | ||
35 | |||
36 | /* | ||
37 | * IDLE - CPU standby values (set to initiate standby) | ||
38 | */ | ||
39 | #define APC_IDLE_ON 0x01 | ||
40 | |||
41 | /* | ||
42 | * FANCTL - Fan speed control state values | ||
43 | */ | ||
44 | #define APC_FANCTL_HI 0x00 /* Fan speed high */ | ||
45 | #define APC_FANCTL_LO 0x01 /* Fan speed low */ | ||
46 | |||
47 | /* | ||
48 | * CPWR - Convenience power outlet state values | ||
49 | */ | ||
50 | #define APC_CPOWER_ON 0x00 /* Conv power on */ | ||
51 | #define APC_CPOWER_OFF 0x01 /* Conv power off */ | ||
52 | |||
53 | /* | ||
54 | * BPA/BPB - Read-Write "Bit Ports" state values (reset to 0 at power-on) | ||
55 | * | ||
56 | * WARNING: Internal usage of bit ports is platform dependent-- | ||
57 | * don't modify BPORT settings unless you know what you are doing. | ||
58 | * | ||
59 | * On SS5 BPA seems to toggle onboard ethernet loopback... -E | ||
60 | */ | ||
61 | #define APC_BPORT_A 0x01 /* Bit Port A */ | ||
62 | #define APC_BPORT_B 0x02 /* Bit Port B */ | ||
63 | |||
64 | #endif /* !(_SPARC_APC_H) */ | ||
diff --git a/arch/sparc/include/asm/asi.h b/arch/sparc/include/asm/asi.h new file mode 100644 index 00000000000..b2e3db63a64 --- /dev/null +++ b/arch/sparc/include/asm/asi.h | |||
@@ -0,0 +1,266 @@ | |||
1 | #ifndef _SPARC_ASI_H | ||
2 | #define _SPARC_ASI_H | ||
3 | |||
4 | /* asi.h: Address Space Identifier values for the sparc. | ||
5 | * | ||
6 | * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) | ||
7 | * | ||
8 | * Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au) | ||
9 | * Joint edition for sun4c+sun4m: Pete A. Zaitcev <zaitcev@ipmce.su> | ||
10 | */ | ||
11 | |||
12 | /* The first batch are for the sun4c. */ | ||
13 | |||
14 | #define ASI_NULL1 0x00 | ||
15 | #define ASI_NULL2 0x01 | ||
16 | |||
17 | /* sun4c and sun4 control registers and mmu/vac ops */ | ||
18 | #define ASI_CONTROL 0x02 | ||
19 | #define ASI_SEGMAP 0x03 | ||
20 | #define ASI_PTE 0x04 | ||
21 | #define ASI_HWFLUSHSEG 0x05 | ||
22 | #define ASI_HWFLUSHPAGE 0x06 | ||
23 | #define ASI_REGMAP 0x06 | ||
24 | #define ASI_HWFLUSHCONTEXT 0x07 | ||
25 | |||
26 | #define ASI_USERTXT 0x08 | ||
27 | #define ASI_KERNELTXT 0x09 | ||
28 | #define ASI_USERDATA 0x0a | ||
29 | #define ASI_KERNELDATA 0x0b | ||
30 | |||
31 | /* VAC Cache flushing on sun4c and sun4 */ | ||
32 | #define ASI_FLUSHSEG 0x0c | ||
33 | #define ASI_FLUSHPG 0x0d | ||
34 | #define ASI_FLUSHCTX 0x0e | ||
35 | |||
36 | /* SPARCstation-5: only 6 bits are decoded. */ | ||
37 | /* wo = Write Only, rw = Read Write; */ | ||
38 | /* ss = Single Size, as = All Sizes; */ | ||
39 | #define ASI_M_RES00 0x00 /* Don't touch... */ | ||
40 | #define ASI_M_UNA01 0x01 /* Same here... */ | ||
41 | #define ASI_M_MXCC 0x02 /* Access to TI VIKING MXCC registers */ | ||
42 | #define ASI_M_FLUSH_PROBE 0x03 /* Reference MMU Flush/Probe; rw, ss */ | ||
43 | #ifndef CONFIG_SPARC_LEON | ||
44 | #define ASI_M_MMUREGS 0x04 /* MMU Registers; rw, ss */ | ||
45 | #else | ||
46 | #define ASI_M_MMUREGS 0x19 | ||
47 | #endif /* CONFIG_SPARC_LEON */ | ||
48 | #define ASI_M_TLBDIAG 0x05 /* MMU TLB only Diagnostics */ | ||
49 | #define ASI_M_DIAGS 0x06 /* Reference MMU Diagnostics */ | ||
50 | #define ASI_M_IODIAG 0x07 /* MMU I/O TLB only Diagnostics */ | ||
51 | #define ASI_M_USERTXT 0x08 /* Same as ASI_USERTXT; rw, as */ | ||
52 | #define ASI_M_KERNELTXT 0x09 /* Same as ASI_KERNELTXT; rw, as */ | ||
53 | #define ASI_M_USERDATA 0x0A /* Same as ASI_USERDATA; rw, as */ | ||
54 | #define ASI_M_KERNELDATA 0x0B /* Same as ASI_KERNELDATA; rw, as */ | ||
55 | #define ASI_M_TXTC_TAG 0x0C /* Instruction Cache Tag; rw, ss */ | ||
56 | #define ASI_M_TXTC_DATA 0x0D /* Instruction Cache Data; rw, ss */ | ||
57 | #define ASI_M_DATAC_TAG 0x0E /* Data Cache Tag; rw, ss */ | ||
58 | #define ASI_M_DATAC_DATA 0x0F /* Data Cache Data; rw, ss */ | ||
59 | |||
60 | /* The following cache flushing ASIs work only with the 'sta' | ||
61 | * instruction. Results are unpredictable for 'swap' and 'ldstuba', | ||
62 | * so don't do it. | ||
63 | */ | ||
64 | |||
65 | /* These ASI flushes affect external caches too. */ | ||
66 | #define ASI_M_FLUSH_PAGE 0x10 /* Flush I&D Cache Line (page); wo, ss */ | ||
67 | #define ASI_M_FLUSH_SEG 0x11 /* Flush I&D Cache Line (seg); wo, ss */ | ||
68 | #define ASI_M_FLUSH_REGION 0x12 /* Flush I&D Cache Line (region); wo, ss */ | ||
69 | #define ASI_M_FLUSH_CTX 0x13 /* Flush I&D Cache Line (context); wo, ss */ | ||
70 | #define ASI_M_FLUSH_USER 0x14 /* Flush I&D Cache Line (user); wo, ss */ | ||
71 | |||
72 | /* Block-copy operations are available only on certain V8 cpus. */ | ||
73 | #define ASI_M_BCOPY 0x17 /* Block copy */ | ||
74 | |||
75 | /* These affect only the ICACHE and are Ross HyperSparc and TurboSparc specific. */ | ||
76 | #define ASI_M_IFLUSH_PAGE 0x18 /* Flush I Cache Line (page); wo, ss */ | ||
77 | #define ASI_M_IFLUSH_SEG 0x19 /* Flush I Cache Line (seg); wo, ss */ | ||
78 | #define ASI_M_IFLUSH_REGION 0x1A /* Flush I Cache Line (region); wo, ss */ | ||
79 | #define ASI_M_IFLUSH_CTX 0x1B /* Flush I Cache Line (context); wo, ss */ | ||
80 | #define ASI_M_IFLUSH_USER 0x1C /* Flush I Cache Line (user); wo, ss */ | ||
81 | |||
82 | /* Block-fill operations are available on certain V8 cpus */ | ||
83 | #define ASI_M_BFILL 0x1F | ||
84 | |||
85 | /* This allows direct access to main memory, actually 0x20 to 0x2f are | ||
86 | * the available ASI's for physical ram pass-through, but I don't have | ||
87 | * any idea what the other ones do.... | ||
88 | */ | ||
89 | |||
90 | #define ASI_M_BYPASS 0x20 /* Reference MMU bypass; rw, as */ | ||
91 | #define ASI_M_FBMEM 0x29 /* Graphics card frame buffer access */ | ||
92 | #define ASI_M_VMEUS 0x2A /* VME user 16-bit access */ | ||
93 | #define ASI_M_VMEPS 0x2B /* VME priv 16-bit access */ | ||
94 | #define ASI_M_VMEUT 0x2C /* VME user 32-bit access */ | ||
95 | #define ASI_M_VMEPT 0x2D /* VME priv 32-bit access */ | ||
96 | #define ASI_M_SBUS 0x2E /* Direct SBus access */ | ||
97 | #define ASI_M_CTL 0x2F /* Control Space (ECC and MXCC are here) */ | ||
98 | |||
99 | |||
100 | /* This is ROSS HyperSparc only. */ | ||
101 | #define ASI_M_FLUSH_IWHOLE 0x31 /* Flush entire ICACHE; wo, ss */ | ||
102 | |||
103 | /* Tsunami/Viking/TurboSparc i/d cache flash clear. */ | ||
104 | #define ASI_M_IC_FLCLEAR 0x36 | ||
105 | #define ASI_M_DC_FLCLEAR 0x37 | ||
106 | |||
107 | #define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Register rw, ss */ | ||
108 | |||
109 | #define ASI_M_VIKING_TMP1 0x40 /* Emulation temporary 1 on Viking */ | ||
110 | /* only available on SuperSparc I */ | ||
111 | /* #define ASI_M_VIKING_TMP2 0x41 */ /* Emulation temporary 2 on Viking */ | ||
112 | |||
113 | #define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */ | ||
114 | |||
115 | /* V9 Architecture mandary ASIs. */ | ||
116 | #define ASI_N 0x04 /* Nucleus */ | ||
117 | #define ASI_NL 0x0c /* Nucleus, little endian */ | ||
118 | #define ASI_AIUP 0x10 /* Primary, user */ | ||
119 | #define ASI_AIUS 0x11 /* Secondary, user */ | ||
120 | #define ASI_AIUPL 0x18 /* Primary, user, little endian */ | ||
121 | #define ASI_AIUSL 0x19 /* Secondary, user, little endian */ | ||
122 | #define ASI_P 0x80 /* Primary, implicit */ | ||
123 | #define ASI_S 0x81 /* Secondary, implicit */ | ||
124 | #define ASI_PNF 0x82 /* Primary, no fault */ | ||
125 | #define ASI_SNF 0x83 /* Secondary, no fault */ | ||
126 | #define ASI_PL 0x88 /* Primary, implicit, l-endian */ | ||
127 | #define ASI_SL 0x89 /* Secondary, implicit, l-endian */ | ||
128 | #define ASI_PNFL 0x8a /* Primary, no fault, l-endian */ | ||
129 | #define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */ | ||
130 | |||
131 | /* SpitFire and later extended ASIs. The "(III)" marker designates | ||
132 | * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates | ||
133 | * Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific | ||
134 | * ASIs, "(4V)" designates SUN4V specific ASIs. | ||
135 | */ | ||
136 | #define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ | ||
137 | #define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ | ||
138 | #define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */ | ||
139 | #define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */ | ||
140 | #define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ | ||
141 | #define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ | ||
142 | #define ASI_BLK_AIUP_L_4V 0x1e /* (4V) Prim, user, block, l-endian*/ | ||
143 | #define ASI_BLK_AIUS_L_4V 0x1f /* (4V) Sec, user, block, l-endian */ | ||
144 | #define ASI_SCRATCHPAD 0x20 /* (4V) Scratch Pad Registers */ | ||
145 | #define ASI_MMU 0x21 /* (4V) MMU Context Registers */ | ||
146 | #define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load, | ||
147 | * secondary, user | ||
148 | */ | ||
149 | #define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ | ||
150 | #define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */ | ||
151 | #define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */ | ||
152 | #define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ | ||
153 | #define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */ | ||
154 | #define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ | ||
155 | #define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ | ||
156 | #define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ | ||
157 | #define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ | ||
158 | #define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ | ||
159 | #define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ | ||
160 | #define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ | ||
161 | #define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ | ||
162 | #define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ | ||
163 | #define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */ | ||
164 | #define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ | ||
165 | #define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */ | ||
166 | #define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */ | ||
167 | #define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */ | ||
168 | #define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */ | ||
169 | #define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */ | ||
170 | #define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */ | ||
171 | #define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */ | ||
172 | #define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */ | ||
173 | #define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */ | ||
174 | #define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ | ||
175 | #define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ | ||
176 | #define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ | ||
177 | #define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ | ||
178 | #define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */ | ||
179 | #define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */ | ||
180 | #define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/ | ||
181 | #define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ | ||
182 | #define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ | ||
183 | #define ASI_UPA_CONFIG 0x4a /* UPA config space */ | ||
184 | #define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ | ||
185 | #define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ | ||
186 | #define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ | ||
187 | #define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ | ||
188 | #define ASI_AFSR 0x4c /* Async fault status register */ | ||
189 | #define ASI_AFAR 0x4d /* Async fault address register */ | ||
190 | #define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ | ||
191 | #define ASI_IMMU 0x50 /* Insn-MMU main register space */ | ||
192 | #define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ | ||
193 | #define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ | ||
194 | #define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */ | ||
195 | #define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */ | ||
196 | #define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */ | ||
197 | #define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ | ||
198 | #define ASI_DMMU 0x58 /* Data-MMU main register space */ | ||
199 | #define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */ | ||
200 | #define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */ | ||
201 | #define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */ | ||
202 | #define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */ | ||
203 | #define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */ | ||
204 | #define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */ | ||
205 | #define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ | ||
206 | #define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */ | ||
207 | #define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */ | ||
208 | #define ASI_CORE_ID 0x63 /* (CMT) LP ID register */ | ||
209 | #define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */ | ||
210 | #define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */ | ||
211 | #define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */ | ||
212 | #define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */ | ||
213 | #define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */ | ||
214 | #define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */ | ||
215 | #define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/ | ||
216 | #define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ | ||
217 | #define ASI_BLK_AIUS 0x71 /* Secondary, user, block ld/st */ | ||
218 | #define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */ | ||
219 | #define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */ | ||
220 | #define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */ | ||
221 | #define ASI_EC_W 0x76 /* E-cache diag write access */ | ||
222 | #define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */ | ||
223 | #define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */ | ||
224 | #define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ | ||
225 | #define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */ | ||
226 | #define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ | ||
227 | #define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/ | ||
228 | #define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/ | ||
229 | #define ASI_EC_R 0x7e /* E-cache diag read access */ | ||
230 | #define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */ | ||
231 | #define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */ | ||
232 | #define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */ | ||
233 | #define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ | ||
234 | #define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ | ||
235 | #define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ | ||
236 | #define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ | ||
237 | #define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ | ||
238 | #define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ | ||
239 | #define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ | ||
240 | #define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ | ||
241 | #define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ | ||
242 | #define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */ | ||
243 | #define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */ | ||
244 | #define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */ | ||
245 | #define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */ | ||
246 | #define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */ | ||
247 | #define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */ | ||
248 | #define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ | ||
249 | #define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ | ||
250 | #define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ | ||
251 | #define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ | ||
252 | #define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */ | ||
253 | #define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/ | ||
254 | #define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */ | ||
255 | #define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ | ||
256 | #define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ | ||
257 | #define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ | ||
258 | #define ASI_BLK_INIT_QUAD_LDD_P 0xe2 /* (NG) init-store, twin load, | ||
259 | * primary, implicit | ||
260 | */ | ||
261 | #define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ | ||
262 | #define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ | ||
263 | #define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ | ||
264 | #define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ | ||
265 | |||
266 | #endif /* _SPARC_ASI_H */ | ||
diff --git a/arch/sparc/include/asm/auxvec.h b/arch/sparc/include/asm/auxvec.h new file mode 100644 index 00000000000..ad6f360261f --- /dev/null +++ b/arch/sparc/include/asm/auxvec.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef __ASMSPARC_AUXVEC_H | ||
2 | #define __ASMSPARC_AUXVEC_H | ||
3 | |||
4 | #endif /* !(__ASMSPARC_AUXVEC_H) */ | ||
diff --git a/arch/sparc/include/asm/bitsperlong.h b/arch/sparc/include/asm/bitsperlong.h new file mode 100644 index 00000000000..40dcaa3aaa5 --- /dev/null +++ b/arch/sparc/include/asm/bitsperlong.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef __ASM_ALPHA_BITSPERLONG_H | ||
2 | #define __ASM_ALPHA_BITSPERLONG_H | ||
3 | |||
4 | #if defined(__sparc__) && defined(__arch64__) | ||
5 | #define __BITS_PER_LONG 64 | ||
6 | #else | ||
7 | #define __BITS_PER_LONG 32 | ||
8 | #endif | ||
9 | |||
10 | #include <asm-generic/bitsperlong.h> | ||
11 | |||
12 | #endif /* __ASM_ALPHA_BITSPERLONG_H */ | ||
13 | |||
diff --git a/arch/sparc/include/asm/btfixup.h b/arch/sparc/include/asm/btfixup.h new file mode 100644 index 00000000000..797722cf69f --- /dev/null +++ b/arch/sparc/include/asm/btfixup.h | |||
@@ -0,0 +1,208 @@ | |||
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/byteorder.h b/arch/sparc/include/asm/byteorder.h new file mode 100644 index 00000000000..ccc1b6b7de6 --- /dev/null +++ b/arch/sparc/include/asm/byteorder.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _SPARC_BYTEORDER_H | ||
2 | #define _SPARC_BYTEORDER_H | ||
3 | |||
4 | #include <linux/byteorder/big_endian.h> | ||
5 | |||
6 | #endif /* _SPARC_BYTEORDER_H */ | ||
diff --git a/arch/sparc/include/asm/cmt.h b/arch/sparc/include/asm/cmt.h new file mode 100644 index 00000000000..870db592857 --- /dev/null +++ b/arch/sparc/include/asm/cmt.h | |||
@@ -0,0 +1,59 @@ | |||
1 | #ifndef _SPARC64_CMT_H | ||
2 | #define _SPARC64_CMT_H | ||
3 | |||
4 | /* cmt.h: Chip Multi-Threading register definitions | ||
5 | * | ||
6 | * Copyright (C) 2004 David S. Miller (davem@redhat.com) | ||
7 | */ | ||
8 | |||
9 | /* ASI_CORE_ID - private */ | ||
10 | #define LP_ID 0x0000000000000010UL | ||
11 | #define LP_ID_MAX 0x00000000003f0000UL | ||
12 | #define LP_ID_ID 0x000000000000003fUL | ||
13 | |||
14 | /* ASI_INTR_ID - private */ | ||
15 | #define LP_INTR_ID 0x0000000000000000UL | ||
16 | #define LP_INTR_ID_ID 0x00000000000003ffUL | ||
17 | |||
18 | /* ASI_CESR_ID - private */ | ||
19 | #define CESR_ID 0x0000000000000040UL | ||
20 | #define CESR_ID_ID 0x00000000000000ffUL | ||
21 | |||
22 | /* ASI_CORE_AVAILABLE - shared */ | ||
23 | #define LP_AVAIL 0x0000000000000000UL | ||
24 | #define LP_AVAIL_1 0x0000000000000002UL | ||
25 | #define LP_AVAIL_0 0x0000000000000001UL | ||
26 | |||
27 | /* ASI_CORE_ENABLE_STATUS - shared */ | ||
28 | #define LP_ENAB_STAT 0x0000000000000010UL | ||
29 | #define LP_ENAB_STAT_1 0x0000000000000002UL | ||
30 | #define LP_ENAB_STAT_0 0x0000000000000001UL | ||
31 | |||
32 | /* ASI_CORE_ENABLE - shared */ | ||
33 | #define LP_ENAB 0x0000000000000020UL | ||
34 | #define LP_ENAB_1 0x0000000000000002UL | ||
35 | #define LP_ENAB_0 0x0000000000000001UL | ||
36 | |||
37 | /* ASI_CORE_RUNNING - shared */ | ||
38 | #define LP_RUNNING_RW 0x0000000000000050UL | ||
39 | #define LP_RUNNING_W1S 0x0000000000000060UL | ||
40 | #define LP_RUNNING_W1C 0x0000000000000068UL | ||
41 | #define LP_RUNNING_1 0x0000000000000002UL | ||
42 | #define LP_RUNNING_0 0x0000000000000001UL | ||
43 | |||
44 | /* ASI_CORE_RUNNING_STAT - shared */ | ||
45 | #define LP_RUN_STAT 0x0000000000000058UL | ||
46 | #define LP_RUN_STAT_1 0x0000000000000002UL | ||
47 | #define LP_RUN_STAT_0 0x0000000000000001UL | ||
48 | |||
49 | /* ASI_XIR_STEERING - shared */ | ||
50 | #define LP_XIR_STEER 0x0000000000000030UL | ||
51 | #define LP_XIR_STEER_1 0x0000000000000002UL | ||
52 | #define LP_XIR_STEER_0 0x0000000000000001UL | ||
53 | |||
54 | /* ASI_CMT_ERROR_STEERING - shared */ | ||
55 | #define CMT_ER_STEER 0x0000000000000040UL | ||
56 | #define CMT_ER_STEER_1 0x0000000000000002UL | ||
57 | #define CMT_ER_STEER_0 0x0000000000000001UL | ||
58 | |||
59 | #endif /* _SPARC64_CMT_H */ | ||
diff --git a/arch/sparc/include/asm/cypress.h b/arch/sparc/include/asm/cypress.h new file mode 100644 index 00000000000..95e9772ea39 --- /dev/null +++ b/arch/sparc/include/asm/cypress.h | |||
@@ -0,0 +1,79 @@ | |||
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/display7seg.h b/arch/sparc/include/asm/display7seg.h new file mode 100644 index 00000000000..86d4a901df2 --- /dev/null +++ b/arch/sparc/include/asm/display7seg.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * | ||
3 | * display7seg - Driver interface for the 7-segment display | ||
4 | * present on Sun Microsystems CP1400 and CP1500 | ||
5 | * | ||
6 | * Copyright (c) 2000 Eric Brower <ebrower@usa.net> | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef __display7seg_h__ | ||
11 | #define __display7seg_h__ | ||
12 | |||
13 | #define D7S_IOC 'p' | ||
14 | |||
15 | #define D7SIOCRD _IOR(D7S_IOC, 0x45, int) /* Read device state */ | ||
16 | #define D7SIOCWR _IOW(D7S_IOC, 0x46, int) /* Write device state */ | ||
17 | #define D7SIOCTM _IO (D7S_IOC, 0x47) /* Translate mode (FLIP)*/ | ||
18 | |||
19 | /* | ||
20 | * ioctl flag definitions | ||
21 | * | ||
22 | * POINT - Toggle decimal point (0=absent 1=present) | ||
23 | * ALARM - Toggle alarm LED (0=green 1=red) | ||
24 | * FLIP - Toggle inverted mode (0=normal 1=flipped) | ||
25 | * bits 0-4 - Character displayed (see definitions below) | ||
26 | * | ||
27 | * Display segments are defined as follows, | ||
28 | * subject to D7S_FLIP register state: | ||
29 | * | ||
30 | * a | ||
31 | * --- | ||
32 | * f| |b | ||
33 | * -g- | ||
34 | * e| |c | ||
35 | * --- | ||
36 | * d | ||
37 | */ | ||
38 | |||
39 | #define D7S_POINT (1 << 7) /* Decimal point*/ | ||
40 | #define D7S_ALARM (1 << 6) /* Alarm LED */ | ||
41 | #define D7S_FLIP (1 << 5) /* Flip display */ | ||
42 | |||
43 | #define D7S_0 0x00 /* Numerals 0-9 */ | ||
44 | #define D7S_1 0x01 | ||
45 | #define D7S_2 0x02 | ||
46 | #define D7S_3 0x03 | ||
47 | #define D7S_4 0x04 | ||
48 | #define D7S_5 0x05 | ||
49 | #define D7S_6 0x06 | ||
50 | #define D7S_7 0x07 | ||
51 | #define D7S_8 0x08 | ||
52 | #define D7S_9 0x09 | ||
53 | #define D7S_A 0x0A /* Letters A-F, H, L, P */ | ||
54 | #define D7S_B 0x0B | ||
55 | #define D7S_C 0x0C | ||
56 | #define D7S_D 0x0D | ||
57 | #define D7S_E 0x0E | ||
58 | #define D7S_F 0x0F | ||
59 | #define D7S_H 0x10 | ||
60 | #define D7S_E2 0x11 | ||
61 | #define D7S_L 0x12 | ||
62 | #define D7S_P 0x13 | ||
63 | #define D7S_SEGA 0x14 /* Individual segments */ | ||
64 | #define D7S_SEGB 0x15 | ||
65 | #define D7S_SEGC 0x16 | ||
66 | #define D7S_SEGD 0x17 | ||
67 | #define D7S_SEGE 0x18 | ||
68 | #define D7S_SEGF 0x19 | ||
69 | #define D7S_SEGG 0x1A | ||
70 | #define D7S_SEGABFG 0x1B /* Segment groupings */ | ||
71 | #define D7S_SEGCDEG 0x1C | ||
72 | #define D7S_SEGBCEF 0x1D | ||
73 | #define D7S_SEGADG 0x1E | ||
74 | #define D7S_BLANK 0x1F /* Clear all segments */ | ||
75 | |||
76 | #define D7S_MIN_VAL 0x0 | ||
77 | #define D7S_MAX_VAL 0x1F | ||
78 | |||
79 | #endif /* ifndef __display7seg_h__ */ | ||
diff --git a/arch/sparc/include/asm/envctrl.h b/arch/sparc/include/asm/envctrl.h new file mode 100644 index 00000000000..624fa7e2da8 --- /dev/null +++ b/arch/sparc/include/asm/envctrl.h | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * | ||
3 | * envctrl.h: Definitions for access to the i2c environment | ||
4 | * monitoring on Ultrasparc systems. | ||
5 | * | ||
6 | * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) | ||
7 | * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) | ||
8 | * VT - Add all ioctl commands and environment status definitions | ||
9 | * VT - Add application note | ||
10 | */ | ||
11 | #ifndef _SPARC64_ENVCTRL_H | ||
12 | #define _SPARC64_ENVCTRL_H 1 | ||
13 | |||
14 | #include <linux/ioctl.h> | ||
15 | |||
16 | /* Application note: | ||
17 | * | ||
18 | * The driver supports 4 operations: open(), close(), ioctl(), read() | ||
19 | * The device name is /dev/envctrl. | ||
20 | * Below is sample usage: | ||
21 | * | ||
22 | * fd = open("/dev/envtrl", O_RDONLY); | ||
23 | * if (ioctl(fd, ENVCTRL_READ_SHUTDOWN_TEMPERATURE, 0) < 0) | ||
24 | * printf("error\n"); | ||
25 | * ret = read(fd, buf, 10); | ||
26 | * close(fd); | ||
27 | * | ||
28 | * Notice in the case of cpu voltage and temperature, the default is | ||
29 | * cpu0. If we need to know the info of cpu1, cpu2, cpu3, we need to | ||
30 | * pass in cpu number in ioctl() last parameter. For example, to | ||
31 | * get the voltage of cpu2: | ||
32 | * | ||
33 | * ioctlbuf[0] = 2; | ||
34 | * if (ioctl(fd, ENVCTRL_READ_CPU_VOLTAGE, ioctlbuf) < 0) | ||
35 | * printf("error\n"); | ||
36 | * ret = read(fd, buf, 10); | ||
37 | * | ||
38 | * All the return values are in ascii. So check read return value | ||
39 | * and do appropriate conversions in your application. | ||
40 | */ | ||
41 | |||
42 | /* IOCTL commands */ | ||
43 | |||
44 | /* Note: these commands reflect possible monitor features. | ||
45 | * Some boards choose to support some of the features only. | ||
46 | */ | ||
47 | #define ENVCTRL_RD_CPU_TEMPERATURE _IOR('p', 0x40, int) | ||
48 | #define ENVCTRL_RD_CPU_VOLTAGE _IOR('p', 0x41, int) | ||
49 | #define ENVCTRL_RD_FAN_STATUS _IOR('p', 0x42, int) | ||
50 | #define ENVCTRL_RD_WARNING_TEMPERATURE _IOR('p', 0x43, int) | ||
51 | #define ENVCTRL_RD_SHUTDOWN_TEMPERATURE _IOR('p', 0x44, int) | ||
52 | #define ENVCTRL_RD_VOLTAGE_STATUS _IOR('p', 0x45, int) | ||
53 | #define ENVCTRL_RD_SCSI_TEMPERATURE _IOR('p', 0x46, int) | ||
54 | #define ENVCTRL_RD_ETHERNET_TEMPERATURE _IOR('p', 0x47, int) | ||
55 | #define ENVCTRL_RD_MTHRBD_TEMPERATURE _IOR('p', 0x48, int) | ||
56 | |||
57 | #define ENVCTRL_RD_GLOBALADDRESS _IOR('p', 0x49, int) | ||
58 | |||
59 | /* Read return values for a voltage status request. */ | ||
60 | #define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD 0x01 | ||
61 | #define ENVCTRL_VOLTAGE_BAD 0x02 | ||
62 | #define ENVCTRL_POWERSUPPLY_BAD 0x03 | ||
63 | #define ENVCTRL_VOLTAGE_POWERSUPPLY_BAD 0x04 | ||
64 | |||
65 | /* Read return values for a fan status request. | ||
66 | * A failure match means either the fan fails or | ||
67 | * the fan is not connected. Some boards have optional | ||
68 | * connectors to connect extra fans. | ||
69 | * | ||
70 | * There are maximum 8 monitor fans. Some are cpu fans | ||
71 | * some are system fans. The mask below only indicates | ||
72 | * fan by order number. | ||
73 | * Below is a sample application: | ||
74 | * | ||
75 | * if (ioctl(fd, ENVCTRL_READ_FAN_STATUS, 0) < 0) { | ||
76 | * printf("ioctl fan failed\n"); | ||
77 | * } | ||
78 | * if (read(fd, rslt, 1) <= 0) { | ||
79 | * printf("error or fan not monitored\n"); | ||
80 | * } else { | ||
81 | * if (rslt[0] == ENVCTRL_ALL_FANS_GOOD) { | ||
82 | * printf("all fans good\n"); | ||
83 | * } else if (rslt[0] == ENVCTRL_ALL_FANS_BAD) { | ||
84 | * printf("all fans bad\n"); | ||
85 | * } else { | ||
86 | * if (rslt[0] & ENVCTRL_FAN0_FAILURE_MASK) { | ||
87 | * printf("fan 0 failed or not connected\n"); | ||
88 | * } | ||
89 | * ...... | ||
90 | */ | ||
91 | |||
92 | #define ENVCTRL_ALL_FANS_GOOD 0x00 | ||
93 | #define ENVCTRL_FAN0_FAILURE_MASK 0x01 | ||
94 | #define ENVCTRL_FAN1_FAILURE_MASK 0x02 | ||
95 | #define ENVCTRL_FAN2_FAILURE_MASK 0x04 | ||
96 | #define ENVCTRL_FAN3_FAILURE_MASK 0x08 | ||
97 | #define ENVCTRL_FAN4_FAILURE_MASK 0x10 | ||
98 | #define ENVCTRL_FAN5_FAILURE_MASK 0x20 | ||
99 | #define ENVCTRL_FAN6_FAILURE_MASK 0x40 | ||
100 | #define ENVCTRL_FAN7_FAILURE_MASK 0x80 | ||
101 | #define ENVCTRL_ALL_FANS_BAD 0xFF | ||
102 | |||
103 | #endif /* !(_SPARC64_ENVCTRL_H) */ | ||
diff --git a/arch/sparc/include/asm/errno.h b/arch/sparc/include/asm/errno.h new file mode 100644 index 00000000000..c351aba997b --- /dev/null +++ b/arch/sparc/include/asm/errno.h | |||
@@ -0,0 +1,117 @@ | |||
1 | #ifndef _SPARC_ERRNO_H | ||
2 | #define _SPARC_ERRNO_H | ||
3 | |||
4 | /* These match the SunOS error numbering scheme. */ | ||
5 | |||
6 | #include <asm-generic/errno-base.h> | ||
7 | |||
8 | #define EWOULDBLOCK EAGAIN /* Operation would block */ | ||
9 | #define EINPROGRESS 36 /* Operation now in progress */ | ||
10 | #define EALREADY 37 /* Operation already in progress */ | ||
11 | #define ENOTSOCK 38 /* Socket operation on non-socket */ | ||
12 | #define EDESTADDRREQ 39 /* Destination address required */ | ||
13 | #define EMSGSIZE 40 /* Message too long */ | ||
14 | #define EPROTOTYPE 41 /* Protocol wrong type for socket */ | ||
15 | #define ENOPROTOOPT 42 /* Protocol not available */ | ||
16 | #define EPROTONOSUPPORT 43 /* Protocol not supported */ | ||
17 | #define ESOCKTNOSUPPORT 44 /* Socket type not supported */ | ||
18 | #define EOPNOTSUPP 45 /* Op not supported on transport endpoint */ | ||
19 | #define EPFNOSUPPORT 46 /* Protocol family not supported */ | ||
20 | #define EAFNOSUPPORT 47 /* Address family not supported by protocol */ | ||
21 | #define EADDRINUSE 48 /* Address already in use */ | ||
22 | #define EADDRNOTAVAIL 49 /* Cannot assign requested address */ | ||
23 | #define ENETDOWN 50 /* Network is down */ | ||
24 | #define ENETUNREACH 51 /* Network is unreachable */ | ||
25 | #define ENETRESET 52 /* Net dropped connection because of reset */ | ||
26 | #define ECONNABORTED 53 /* Software caused connection abort */ | ||
27 | #define ECONNRESET 54 /* Connection reset by peer */ | ||
28 | #define ENOBUFS 55 /* No buffer space available */ | ||
29 | #define EISCONN 56 /* Transport endpoint is already connected */ | ||
30 | #define ENOTCONN 57 /* Transport endpoint is not connected */ | ||
31 | #define ESHUTDOWN 58 /* No send after transport endpoint shutdown */ | ||
32 | #define ETOOMANYREFS 59 /* Too many references: cannot splice */ | ||
33 | #define ETIMEDOUT 60 /* Connection timed out */ | ||
34 | #define ECONNREFUSED 61 /* Connection refused */ | ||
35 | #define ELOOP 62 /* Too many symbolic links encountered */ | ||
36 | #define ENAMETOOLONG 63 /* File name too long */ | ||
37 | #define EHOSTDOWN 64 /* Host is down */ | ||
38 | #define EHOSTUNREACH 65 /* No route to host */ | ||
39 | #define ENOTEMPTY 66 /* Directory not empty */ | ||
40 | #define EPROCLIM 67 /* SUNOS: Too many processes */ | ||
41 | #define EUSERS 68 /* Too many users */ | ||
42 | #define EDQUOT 69 /* Quota exceeded */ | ||
43 | #define ESTALE 70 /* Stale NFS file handle */ | ||
44 | #define EREMOTE 71 /* Object is remote */ | ||
45 | #define ENOSTR 72 /* Device not a stream */ | ||
46 | #define ETIME 73 /* Timer expired */ | ||
47 | #define ENOSR 74 /* Out of streams resources */ | ||
48 | #define ENOMSG 75 /* No message of desired type */ | ||
49 | #define EBADMSG 76 /* Not a data message */ | ||
50 | #define EIDRM 77 /* Identifier removed */ | ||
51 | #define EDEADLK 78 /* Resource deadlock would occur */ | ||
52 | #define ENOLCK 79 /* No record locks available */ | ||
53 | #define ENONET 80 /* Machine is not on the network */ | ||
54 | #define ERREMOTE 81 /* SunOS: Too many lvls of remote in path */ | ||
55 | #define ENOLINK 82 /* Link has been severed */ | ||
56 | #define EADV 83 /* Advertise error */ | ||
57 | #define ESRMNT 84 /* Srmount error */ | ||
58 | #define ECOMM 85 /* Communication error on send */ | ||
59 | #define EPROTO 86 /* Protocol error */ | ||
60 | #define EMULTIHOP 87 /* Multihop attempted */ | ||
61 | #define EDOTDOT 88 /* RFS specific error */ | ||
62 | #define EREMCHG 89 /* Remote address changed */ | ||
63 | #define ENOSYS 90 /* Function not implemented */ | ||
64 | |||
65 | /* The rest have no SunOS equivalent. */ | ||
66 | #define ESTRPIPE 91 /* Streams pipe error */ | ||
67 | #define EOVERFLOW 92 /* Value too large for defined data type */ | ||
68 | #define EBADFD 93 /* File descriptor in bad state */ | ||
69 | #define ECHRNG 94 /* Channel number out of range */ | ||
70 | #define EL2NSYNC 95 /* Level 2 not synchronized */ | ||
71 | #define EL3HLT 96 /* Level 3 halted */ | ||
72 | #define EL3RST 97 /* Level 3 reset */ | ||
73 | #define ELNRNG 98 /* Link number out of range */ | ||
74 | #define EUNATCH 99 /* Protocol driver not attached */ | ||
75 | #define ENOCSI 100 /* No CSI structure available */ | ||
76 | #define EL2HLT 101 /* Level 2 halted */ | ||
77 | #define EBADE 102 /* Invalid exchange */ | ||
78 | #define EBADR 103 /* Invalid request descriptor */ | ||
79 | #define EXFULL 104 /* Exchange full */ | ||
80 | #define ENOANO 105 /* No anode */ | ||
81 | #define EBADRQC 106 /* Invalid request code */ | ||
82 | #define EBADSLT 107 /* Invalid slot */ | ||
83 | #define EDEADLOCK 108 /* File locking deadlock error */ | ||
84 | #define EBFONT 109 /* Bad font file format */ | ||
85 | #define ELIBEXEC 110 /* Cannot exec a shared library directly */ | ||
86 | #define ENODATA 111 /* No data available */ | ||
87 | #define ELIBBAD 112 /* Accessing a corrupted shared library */ | ||
88 | #define ENOPKG 113 /* Package not installed */ | ||
89 | #define ELIBACC 114 /* Can not access a needed shared library */ | ||
90 | #define ENOTUNIQ 115 /* Name not unique on network */ | ||
91 | #define ERESTART 116 /* Interrupted syscall should be restarted */ | ||
92 | #define EUCLEAN 117 /* Structure needs cleaning */ | ||
93 | #define ENOTNAM 118 /* Not a XENIX named type file */ | ||
94 | #define ENAVAIL 119 /* No XENIX semaphores available */ | ||
95 | #define EISNAM 120 /* Is a named type file */ | ||
96 | #define EREMOTEIO 121 /* Remote I/O error */ | ||
97 | #define EILSEQ 122 /* Illegal byte sequence */ | ||
98 | #define ELIBMAX 123 /* Atmpt to link in too many shared libs */ | ||
99 | #define ELIBSCN 124 /* .lib section in a.out corrupted */ | ||
100 | |||
101 | #define ENOMEDIUM 125 /* No medium found */ | ||
102 | #define EMEDIUMTYPE 126 /* Wrong medium type */ | ||
103 | #define ECANCELED 127 /* Operation Cancelled */ | ||
104 | #define ENOKEY 128 /* Required key not available */ | ||
105 | #define EKEYEXPIRED 129 /* Key has expired */ | ||
106 | #define EKEYREVOKED 130 /* Key has been revoked */ | ||
107 | #define EKEYREJECTED 131 /* Key was rejected by service */ | ||
108 | |||
109 | /* for robust mutexes */ | ||
110 | #define EOWNERDEAD 132 /* Owner died */ | ||
111 | #define ENOTRECOVERABLE 133 /* State not recoverable */ | ||
112 | |||
113 | #define ERFKILL 134 /* Operation not possible due to RF-kill */ | ||
114 | |||
115 | #define EHWPOISON 135 /* Memory page has hardware error */ | ||
116 | |||
117 | #endif | ||
diff --git a/arch/sparc/include/asm/fcntl.h b/arch/sparc/include/asm/fcntl.h new file mode 100644 index 00000000000..d0b83f66f35 --- /dev/null +++ b/arch/sparc/include/asm/fcntl.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef _SPARC_FCNTL_H | ||
2 | #define _SPARC_FCNTL_H | ||
3 | |||
4 | #define O_APPEND 0x0008 | ||
5 | #define FASYNC 0x0040 /* fcntl, for BSD compatibility */ | ||
6 | #define O_CREAT 0x0200 /* not fcntl */ | ||
7 | #define O_TRUNC 0x0400 /* not fcntl */ | ||
8 | #define O_EXCL 0x0800 /* not fcntl */ | ||
9 | #define O_DSYNC 0x2000 /* used to be O_SYNC, see below */ | ||
10 | #define O_NONBLOCK 0x4000 | ||
11 | #if defined(__sparc__) && defined(__arch64__) | ||
12 | #define O_NDELAY 0x0004 | ||
13 | #else | ||
14 | #define O_NDELAY (0x0004 | O_NONBLOCK) | ||
15 | #endif | ||
16 | #define O_NOCTTY 0x8000 /* not fcntl */ | ||
17 | #define O_LARGEFILE 0x40000 | ||
18 | #define O_DIRECT 0x100000 /* direct disk access hint */ | ||
19 | #define O_NOATIME 0x200000 | ||
20 | #define O_CLOEXEC 0x400000 | ||
21 | /* | ||
22 | * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using | ||
23 | * the O_SYNC flag. We continue to use the existing numerical value | ||
24 | * for O_DSYNC semantics now, but using the correct symbolic name for it. | ||
25 | * This new value is used to request true Posix O_SYNC semantics. It is | ||
26 | * defined in this strange way to make sure applications compiled against | ||
27 | * new headers get at least O_DSYNC semantics on older kernels. | ||
28 | * | ||
29 | * This has the nice side-effect that we can simply test for O_DSYNC | ||
30 | * wherever we do not care if O_DSYNC or O_SYNC is used. | ||
31 | * | ||
32 | * Note: __O_SYNC must never be used directly. | ||
33 | */ | ||
34 | #define __O_SYNC 0x800000 | ||
35 | #define O_SYNC (__O_SYNC|O_DSYNC) | ||
36 | |||
37 | #define O_PATH 0x1000000 | ||
38 | |||
39 | #define F_GETOWN 5 /* for sockets. */ | ||
40 | #define F_SETOWN 6 /* for sockets. */ | ||
41 | #define F_GETLK 7 | ||
42 | #define F_SETLK 8 | ||
43 | #define F_SETLKW 9 | ||
44 | |||
45 | /* for posix fcntl() and lockf() */ | ||
46 | #define F_RDLCK 1 | ||
47 | #define F_WRLCK 2 | ||
48 | #define F_UNLCK 3 | ||
49 | |||
50 | #define __ARCH_FLOCK_PAD short __unused; | ||
51 | #define __ARCH_FLOCK64_PAD short __unused; | ||
52 | |||
53 | #include <asm-generic/fcntl.h> | ||
54 | |||
55 | #endif | ||
diff --git a/arch/sparc/include/asm/fixmap.h b/arch/sparc/include/asm/fixmap.h new file mode 100644 index 00000000000..f18fc0755ad --- /dev/null +++ b/arch/sparc/include/asm/fixmap.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * fixmap.h: compile-time virtual memory allocation | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * Copyright (C) 1998 Ingo Molnar | ||
9 | * | ||
10 | * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 | ||
11 | */ | ||
12 | |||
13 | #ifndef _ASM_FIXMAP_H | ||
14 | #define _ASM_FIXMAP_H | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <asm/page.h> | ||
18 | #ifdef CONFIG_HIGHMEM | ||
19 | #include <linux/threads.h> | ||
20 | #include <asm/kmap_types.h> | ||
21 | #endif | ||
22 | |||
23 | /* | ||
24 | * Here we define all the compile-time 'special' virtual | ||
25 | * addresses. The point is to have a constant address at | ||
26 | * compile time, but to set the physical address only | ||
27 | * in the boot process. We allocate these special addresses | ||
28 | * from the top of unused virtual memory (0xfd000000 - 1 page) backwards. | ||
29 | * Also this lets us do fail-safe vmalloc(), we | ||
30 | * can guarantee that these special addresses and | ||
31 | * vmalloc()-ed addresses never overlap. | ||
32 | * | ||
33 | * these 'compile-time allocated' memory buffers are | ||
34 | * fixed-size 4k pages. (or larger if used with an increment | ||
35 | * highger than 1) use fixmap_set(idx,phys) to associate | ||
36 | * physical memory with fixmap indices. | ||
37 | * | ||
38 | * TLB entries of such buffers will not be flushed across | ||
39 | * task switches. | ||
40 | */ | ||
41 | |||
42 | /* | ||
43 | * on UP currently we will have no trace of the fixmap mechanism, | ||
44 | * no page table allocations, etc. This might change in the | ||
45 | * future, say framebuffers for the console driver(s) could be | ||
46 | * fix-mapped? | ||
47 | */ | ||
48 | enum fixed_addresses { | ||
49 | FIX_HOLE, | ||
50 | #ifdef CONFIG_HIGHMEM | ||
51 | FIX_KMAP_BEGIN, | ||
52 | FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, | ||
53 | #endif | ||
54 | __end_of_fixed_addresses | ||
55 | }; | ||
56 | |||
57 | extern void __set_fixmap (enum fixed_addresses idx, | ||
58 | unsigned long phys, pgprot_t flags); | ||
59 | |||
60 | #define set_fixmap(idx, phys) \ | ||
61 | __set_fixmap(idx, phys, PAGE_KERNEL) | ||
62 | /* | ||
63 | * Some hardware wants to get fixmapped without caching. | ||
64 | */ | ||
65 | #define set_fixmap_nocache(idx, phys) \ | ||
66 | __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) | ||
67 | /* | ||
68 | * used by vmalloc.c. | ||
69 | * | ||
70 | * Leave one empty page between IO pages at 0xfd000000 and | ||
71 | * the start of the fixmap. | ||
72 | */ | ||
73 | #define FIXADDR_TOP (0xfcfff000UL) | ||
74 | #define FIXADDR_SIZE ((__end_of_fixed_addresses) << PAGE_SHIFT) | ||
75 | #define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) | ||
76 | |||
77 | #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) | ||
78 | #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) | ||
79 | |||
80 | extern void __this_fixmap_does_not_exist(void); | ||
81 | |||
82 | /* | ||
83 | * 'index to address' translation. If anyone tries to use the idx | ||
84 | * directly without tranlation, we catch the bug with a NULL-deference | ||
85 | * kernel oops. Illegal ranges of incoming indices are caught too. | ||
86 | */ | ||
87 | static inline unsigned long fix_to_virt(const unsigned int idx) | ||
88 | { | ||
89 | /* | ||
90 | * this branch gets completely eliminated after inlining, | ||
91 | * except when someone tries to use fixaddr indices in an | ||
92 | * illegal way. (such as mixing up address types or using | ||
93 | * out-of-range indices). | ||
94 | * | ||
95 | * If it doesn't get removed, the linker will complain | ||
96 | * loudly with a reasonably clear error message.. | ||
97 | */ | ||
98 | if (idx >= __end_of_fixed_addresses) | ||
99 | __this_fixmap_does_not_exist(); | ||
100 | |||
101 | return __fix_to_virt(idx); | ||
102 | } | ||
103 | |||
104 | static inline unsigned long virt_to_fix(const unsigned long vaddr) | ||
105 | { | ||
106 | BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); | ||
107 | return __virt_to_fix(vaddr); | ||
108 | } | ||
109 | |||
110 | #endif | ||
diff --git a/arch/sparc/include/asm/ioctl.h b/arch/sparc/include/asm/ioctl.h new file mode 100644 index 00000000000..7d6bd51321b --- /dev/null +++ b/arch/sparc/include/asm/ioctl.h | |||
@@ -0,0 +1,67 @@ | |||
1 | #ifndef _SPARC_IOCTL_H | ||
2 | #define _SPARC_IOCTL_H | ||
3 | |||
4 | /* | ||
5 | * Our DIR and SIZE overlap in order to simulteneously provide | ||
6 | * a non-zero _IOC_NONE (for binary compatibility) and | ||
7 | * 14 bits of size as on i386. Here's the layout: | ||
8 | * | ||
9 | * 0xE0000000 DIR | ||
10 | * 0x80000000 DIR = WRITE | ||
11 | * 0x40000000 DIR = READ | ||
12 | * 0x20000000 DIR = NONE | ||
13 | * 0x3FFF0000 SIZE (overlaps NONE bit) | ||
14 | * 0x0000FF00 TYPE | ||
15 | * 0x000000FF NR (CMD) | ||
16 | */ | ||
17 | |||
18 | #define _IOC_NRBITS 8 | ||
19 | #define _IOC_TYPEBITS 8 | ||
20 | #define _IOC_SIZEBITS 13 /* Actually 14, see below. */ | ||
21 | #define _IOC_DIRBITS 3 | ||
22 | |||
23 | #define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) | ||
24 | #define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) | ||
25 | #define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) | ||
26 | #define _IOC_XSIZEMASK ((1 << (_IOC_SIZEBITS+1))-1) | ||
27 | #define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) | ||
28 | |||
29 | #define _IOC_NRSHIFT 0 | ||
30 | #define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) | ||
31 | #define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) | ||
32 | #define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) | ||
33 | |||
34 | #define _IOC_NONE 1U | ||
35 | #define _IOC_READ 2U | ||
36 | #define _IOC_WRITE 4U | ||
37 | |||
38 | #define _IOC(dir,type,nr,size) \ | ||
39 | (((dir) << _IOC_DIRSHIFT) | \ | ||
40 | ((type) << _IOC_TYPESHIFT) | \ | ||
41 | ((nr) << _IOC_NRSHIFT) | \ | ||
42 | ((size) << _IOC_SIZESHIFT)) | ||
43 | |||
44 | #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) | ||
45 | #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) | ||
46 | #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) | ||
47 | #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) | ||
48 | |||
49 | /* Used to decode ioctl numbers in drivers despite the leading underscore... */ | ||
50 | #define _IOC_DIR(nr) \ | ||
51 | ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)? \ | ||
52 | (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)): \ | ||
53 | (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) ) | ||
54 | #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) | ||
55 | #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) | ||
56 | #define _IOC_SIZE(nr) \ | ||
57 | ((((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) == 0)? \ | ||
58 | 0: (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)) | ||
59 | |||
60 | /* ...and for the PCMCIA and sound. */ | ||
61 | #define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) | ||
62 | #define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) | ||
63 | #define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) | ||
64 | #define IOCSIZE_MASK (_IOC_XSIZEMASK << _IOC_SIZESHIFT) | ||
65 | #define IOCSIZE_SHIFT (_IOC_SIZESHIFT) | ||
66 | |||
67 | #endif /* !(_SPARC_IOCTL_H) */ | ||
diff --git a/arch/sparc/include/asm/ipcbuf.h b/arch/sparc/include/asm/ipcbuf.h new file mode 100644 index 00000000000..66013b4fe10 --- /dev/null +++ b/arch/sparc/include/asm/ipcbuf.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef __SPARC_IPCBUF_H | ||
2 | #define __SPARC_IPCBUF_H | ||
3 | |||
4 | /* | ||
5 | * The ipc64_perm structure for sparc/sparc64 architecture. | ||
6 | * Note extra padding because this structure is passed back and forth | ||
7 | * between kernel and user space. | ||
8 | * | ||
9 | * Pad space is left for: | ||
10 | * - 32-bit seq | ||
11 | * - on sparc for 32 bit mode (it is 32 bit on sparc64) | ||
12 | * - 2 miscellaneous 64-bit values | ||
13 | */ | ||
14 | |||
15 | struct ipc64_perm | ||
16 | { | ||
17 | __kernel_key_t key; | ||
18 | __kernel_uid_t uid; | ||
19 | __kernel_gid_t gid; | ||
20 | __kernel_uid_t cuid; | ||
21 | __kernel_gid_t cgid; | ||
22 | #ifndef __arch64__ | ||
23 | unsigned short __pad0; | ||
24 | #endif | ||
25 | __kernel_mode_t mode; | ||
26 | unsigned short __pad1; | ||
27 | unsigned short seq; | ||
28 | unsigned long long __unused1; | ||
29 | unsigned long long __unused2; | ||
30 | }; | ||
31 | |||
32 | #endif /* __SPARC_IPCBUF_H */ | ||
diff --git a/arch/sparc/include/asm/jsflash.h b/arch/sparc/include/asm/jsflash.h new file mode 100644 index 00000000000..0717d9e39d2 --- /dev/null +++ b/arch/sparc/include/asm/jsflash.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * jsflash.h: OS Flash SIMM support for JavaStations. | ||
3 | * | ||
4 | * Copyright (C) 1999 Pete Zaitcev | ||
5 | */ | ||
6 | |||
7 | #ifndef _SPARC_JSFLASH_H | ||
8 | #define _SPARC_JSFLASH_H | ||
9 | |||
10 | #ifndef _SPARC_TYPES_H | ||
11 | #include <linux/types.h> | ||
12 | #endif | ||
13 | |||
14 | /* | ||
15 | * Semantics of the offset is a full address. | ||
16 | * Hardcode it or get it from probe ioctl. | ||
17 | * | ||
18 | * We use full bus address, so that we would be | ||
19 | * automatically compatible with possible future systems. | ||
20 | */ | ||
21 | |||
22 | #define JSFLASH_IDENT (('F'<<8)|54) | ||
23 | struct jsflash_ident_arg { | ||
24 | __u64 off; /* 0x20000000 is included */ | ||
25 | __u32 size; | ||
26 | char name[32]; /* With trailing zero */ | ||
27 | }; | ||
28 | |||
29 | #define JSFLASH_ERASE (('F'<<8)|55) | ||
30 | /* Put 0 as argument, may be flags or sector number... */ | ||
31 | |||
32 | #define JSFLASH_PROGRAM (('F'<<8)|56) | ||
33 | struct jsflash_program_arg { | ||
34 | __u64 data; /* char* for sparc and sparc64 */ | ||
35 | __u64 off; | ||
36 | __u32 size; | ||
37 | }; | ||
38 | |||
39 | #endif /* _SPARC_JSFLASH_H */ | ||
diff --git a/arch/sparc/include/asm/memblock.h b/arch/sparc/include/asm/memblock.h new file mode 100644 index 00000000000..c67b047ef85 --- /dev/null +++ b/arch/sparc/include/asm/memblock.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef _SPARC64_MEMBLOCK_H | ||
2 | #define _SPARC64_MEMBLOCK_H | ||
3 | |||
4 | #include <asm/oplib.h> | ||
5 | |||
6 | #define MEMBLOCK_DBG(fmt...) prom_printf(fmt) | ||
7 | |||
8 | #endif /* !(_SPARC64_MEMBLOCK_H) */ | ||
diff --git a/arch/sparc/include/asm/memreg.h b/arch/sparc/include/asm/memreg.h new file mode 100644 index 00000000000..845ad2b3918 --- /dev/null +++ b/arch/sparc/include/asm/memreg.h | |||
@@ -0,0 +1,51 @@ | |||
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/module.h b/arch/sparc/include/asm/module.h new file mode 100644 index 00000000000..ff8e02d8033 --- /dev/null +++ b/arch/sparc/include/asm/module.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #ifndef __SPARC_MODULE_H | ||
2 | #define __SPARC_MODULE_H | ||
3 | struct mod_arch_specific { }; | ||
4 | |||
5 | /* | ||
6 | * Use some preprocessor magic to define the correct symbol | ||
7 | * for sparc32 and sparc64. | ||
8 | * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64 | ||
9 | */ | ||
10 | #define ___ELF(a, b, c) a##b##c | ||
11 | #define __ELF(a, b, c) ___ELF(a, b, c) | ||
12 | #define _Elf(t) __ELF(Elf, CONFIG_BITS, t) | ||
13 | #define _ELF(t) __ELF(ELF, CONFIG_BITS, t) | ||
14 | |||
15 | #define Elf_Shdr _Elf(_Shdr) | ||
16 | #define Elf_Sym _Elf(_Sym) | ||
17 | #define Elf_Ehdr _Elf(_Ehdr) | ||
18 | #define Elf_Rela _Elf(_Rela) | ||
19 | #define Elf_Addr _Elf(_Addr) | ||
20 | |||
21 | #define ELF_R_SYM _ELF(_R_SYM) | ||
22 | #define ELF_R_TYPE _ELF(_R_TYPE) | ||
23 | |||
24 | #endif /* __SPARC_MODULE_H */ | ||
diff --git a/arch/sparc/include/asm/mpmbox.h b/arch/sparc/include/asm/mpmbox.h new file mode 100644 index 00000000000..f8423039b24 --- /dev/null +++ b/arch/sparc/include/asm/mpmbox.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * mpmbox.h: Interface and defines for the OpenProm mailbox | ||
3 | * facilities for MP machines under Linux. | ||
4 | * | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | */ | ||
7 | |||
8 | #ifndef _SPARC_MPMBOX_H | ||
9 | #define _SPARC_MPMBOX_H | ||
10 | |||
11 | /* The prom allocates, for each CPU on the machine an unsigned | ||
12 | * byte in physical ram. You probe the device tree prom nodes | ||
13 | * for these values. The purpose of this byte is to be able to | ||
14 | * pass messages from one cpu to another. | ||
15 | */ | ||
16 | |||
17 | /* These are the main message types we have to look for in our | ||
18 | * Cpu mailboxes, based upon these values we decide what course | ||
19 | * of action to take. | ||
20 | */ | ||
21 | |||
22 | /* The CPU is executing code in the kernel. */ | ||
23 | #define MAILBOX_ISRUNNING 0xf0 | ||
24 | |||
25 | /* Another CPU called romvec->pv_exit(), you should call | ||
26 | * prom_stopcpu() when you see this in your mailbox. | ||
27 | */ | ||
28 | #define MAILBOX_EXIT 0xfb | ||
29 | |||
30 | /* Another CPU called romvec->pv_enter(), you should call | ||
31 | * prom_cpuidle() when this is seen. | ||
32 | */ | ||
33 | #define MAILBOX_GOSPIN 0xfc | ||
34 | |||
35 | /* Another CPU has hit a breakpoint either into kadb or the prom | ||
36 | * itself. Just like MAILBOX_GOSPIN, you should call prom_cpuidle() | ||
37 | * at this point. | ||
38 | */ | ||
39 | #define MAILBOX_BPT_SPIN 0xfd | ||
40 | |||
41 | /* Oh geese, some other nitwit got a damn watchdog reset. The party's | ||
42 | * over so go call prom_stopcpu(). | ||
43 | */ | ||
44 | #define MAILBOX_WDOG_STOP 0xfe | ||
45 | |||
46 | #ifndef __ASSEMBLY__ | ||
47 | |||
48 | /* Handy macro's to determine a cpu's state. */ | ||
49 | |||
50 | /* Is the cpu still in Power On Self Test? */ | ||
51 | #define MBOX_POST_P(letter) ((letter) >= 0x00 && (letter) <= 0x7f) | ||
52 | |||
53 | /* Is the cpu at the 'ok' prompt of the PROM? */ | ||
54 | #define MBOX_PROMPROMPT_P(letter) ((letter) >= 0x80 && (letter) <= 0x8f) | ||
55 | |||
56 | /* Is the cpu spinning in the PROM? */ | ||
57 | #define MBOX_PROMSPIN_P(letter) ((letter) >= 0x90 && (letter) <= 0xef) | ||
58 | |||
59 | /* Sanity check... This is junk mail, throw it out. */ | ||
60 | #define MBOX_BOGON_P(letter) ((letter) >= 0xf1 && (letter) <= 0xfa) | ||
61 | |||
62 | /* Is the cpu actively running an application/kernel-code? */ | ||
63 | #define MBOX_RUNNING_P(letter) ((letter) == MAILBOX_ISRUNNING) | ||
64 | |||
65 | #endif /* !(__ASSEMBLY__) */ | ||
66 | |||
67 | #endif /* !(_SPARC_MPMBOX_H) */ | ||
diff --git a/arch/sparc/include/asm/msgbuf.h b/arch/sparc/include/asm/msgbuf.h new file mode 100644 index 00000000000..efc7cbe9788 --- /dev/null +++ b/arch/sparc/include/asm/msgbuf.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #ifndef _SPARC_MSGBUF_H | ||
2 | #define _SPARC_MSGBUF_H | ||
3 | |||
4 | /* | ||
5 | * The msqid64_ds structure for sparc64 architecture. | ||
6 | * Note extra padding because this structure is passed back and forth | ||
7 | * between kernel and user space. | ||
8 | * | ||
9 | * Pad space is left for: | ||
10 | * - 64-bit time_t to solve y2038 problem | ||
11 | * - 2 miscellaneous 32-bit values | ||
12 | */ | ||
13 | |||
14 | #if defined(__sparc__) && defined(__arch64__) | ||
15 | # define PADDING(x) | ||
16 | #else | ||
17 | # define PADDING(x) unsigned int x; | ||
18 | #endif | ||
19 | |||
20 | |||
21 | struct msqid64_ds { | ||
22 | struct ipc64_perm msg_perm; | ||
23 | PADDING(__pad1) | ||
24 | __kernel_time_t msg_stime; /* last msgsnd time */ | ||
25 | PADDING(__pad2) | ||
26 | __kernel_time_t msg_rtime; /* last msgrcv time */ | ||
27 | PADDING(__pad3) | ||
28 | __kernel_time_t msg_ctime; /* last change time */ | ||
29 | unsigned long msg_cbytes; /* current number of bytes on queue */ | ||
30 | unsigned long msg_qnum; /* number of messages in queue */ | ||
31 | unsigned long msg_qbytes; /* max number of bytes on queue */ | ||
32 | __kernel_pid_t msg_lspid; /* pid of last msgsnd */ | ||
33 | __kernel_pid_t msg_lrpid; /* last receive pid */ | ||
34 | unsigned long __unused1; | ||
35 | unsigned long __unused2; | ||
36 | }; | ||
37 | #undef PADDING | ||
38 | #endif /* _SPARC_MSGBUF_H */ | ||
diff --git a/arch/sparc/include/asm/openpromio.h b/arch/sparc/include/asm/openpromio.h new file mode 100644 index 00000000000..917fb8e9c63 --- /dev/null +++ b/arch/sparc/include/asm/openpromio.h | |||
@@ -0,0 +1,69 @@ | |||
1 | #ifndef _SPARC_OPENPROMIO_H | ||
2 | #define _SPARC_OPENPROMIO_H | ||
3 | |||
4 | #include <linux/compiler.h> | ||
5 | #include <linux/ioctl.h> | ||
6 | #include <linux/types.h> | ||
7 | |||
8 | /* | ||
9 | * SunOS and Solaris /dev/openprom definitions. The ioctl values | ||
10 | * were chosen to be exactly equal to the SunOS equivalents. | ||
11 | */ | ||
12 | |||
13 | struct openpromio | ||
14 | { | ||
15 | u_int oprom_size; /* Actual size of the oprom_array. */ | ||
16 | char oprom_array[1]; /* Holds property names and values. */ | ||
17 | }; | ||
18 | |||
19 | #define OPROMMAXPARAM 4096 /* Maximum size of oprom_array. */ | ||
20 | |||
21 | #define OPROMGETOPT 0x20004F01 | ||
22 | #define OPROMSETOPT 0x20004F02 | ||
23 | #define OPROMNXTOPT 0x20004F03 | ||
24 | #define OPROMSETOPT2 0x20004F04 | ||
25 | #define OPROMNEXT 0x20004F05 | ||
26 | #define OPROMCHILD 0x20004F06 | ||
27 | #define OPROMGETPROP 0x20004F07 | ||
28 | #define OPROMNXTPROP 0x20004F08 | ||
29 | #define OPROMU2P 0x20004F09 | ||
30 | #define OPROMGETCONS 0x20004F0A | ||
31 | #define OPROMGETFBNAME 0x20004F0B | ||
32 | #define OPROMGETBOOTARGS 0x20004F0C | ||
33 | /* Linux extensions */ /* Arguments in oprom_array: */ | ||
34 | #define OPROMSETCUR 0x20004FF0 /* int node - Sets current node */ | ||
35 | #define OPROMPCI2NODE 0x20004FF1 /* int pci_bus, pci_devfn - Sets current node to PCI device's node */ | ||
36 | #define OPROMPATH2NODE 0x20004FF2 /* char path[] - Set current node from fully qualified PROM path */ | ||
37 | |||
38 | /* | ||
39 | * Return values from OPROMGETCONS: | ||
40 | */ | ||
41 | |||
42 | #define OPROMCONS_NOT_WSCONS 0 | ||
43 | #define OPROMCONS_STDIN_IS_KBD 0x1 /* stdin device is kbd */ | ||
44 | #define OPROMCONS_STDOUT_IS_FB 0x2 /* stdout is a framebuffer */ | ||
45 | #define OPROMCONS_OPENPROM 0x4 /* supports openboot */ | ||
46 | |||
47 | |||
48 | /* | ||
49 | * NetBSD/OpenBSD /dev/openprom definitions. | ||
50 | */ | ||
51 | |||
52 | struct opiocdesc | ||
53 | { | ||
54 | int op_nodeid; /* PROM Node ID (value-result) */ | ||
55 | int op_namelen; /* Length of op_name. */ | ||
56 | char __user *op_name; /* Pointer to the property name. */ | ||
57 | int op_buflen; /* Length of op_buf (value-result) */ | ||
58 | char __user *op_buf; /* Pointer to buffer. */ | ||
59 | }; | ||
60 | |||
61 | #define OPIOCGET _IOWR('O', 1, struct opiocdesc) | ||
62 | #define OPIOCSET _IOW('O', 2, struct opiocdesc) | ||
63 | #define OPIOCNEXTPROP _IOWR('O', 3, struct opiocdesc) | ||
64 | #define OPIOCGETOPTNODE _IOR('O', 4, int) | ||
65 | #define OPIOCGETNEXT _IOWR('O', 5, int) | ||
66 | #define OPIOCGETCHILD _IOWR('O', 6, int) | ||
67 | |||
68 | #endif /* _SPARC_OPENPROMIO_H */ | ||
69 | |||
diff --git a/arch/sparc/include/asm/param.h b/arch/sparc/include/asm/param.h new file mode 100644 index 00000000000..0bc356bf8c5 --- /dev/null +++ b/arch/sparc/include/asm/param.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef _ASMSPARC_PARAM_H | ||
2 | #define _ASMSPARC_PARAM_H | ||
3 | |||
4 | #define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */ | ||
5 | #include <asm-generic/param.h> | ||
6 | |||
7 | #endif /* _ASMSPARC_PARAM_H */ | ||
diff --git a/arch/sparc/include/asm/perfctr.h b/arch/sparc/include/asm/perfctr.h new file mode 100644 index 00000000000..8d8720a8770 --- /dev/null +++ b/arch/sparc/include/asm/perfctr.h | |||
@@ -0,0 +1,173 @@ | |||
1 | /*---------------------------------------- | ||
2 | PERFORMANCE INSTRUMENTATION | ||
3 | Guillaume Thouvenin 08/10/98 | ||
4 | David S. Miller 10/06/98 | ||
5 | ---------------------------------------*/ | ||
6 | #ifndef PERF_COUNTER_API | ||
7 | #define PERF_COUNTER_API | ||
8 | |||
9 | /* sys_perfctr() interface. First arg is operation code | ||
10 | * from enumeration below. The meaning of further arguments | ||
11 | * are determined by the operation code. | ||
12 | * | ||
13 | * NOTE: This system call is no longer provided, use the perf_events | ||
14 | * infrastructure. | ||
15 | * | ||
16 | * Pointers which are passed by the user are pointers to 64-bit | ||
17 | * integers. | ||
18 | * | ||
19 | * Once enabled, performance counter state is retained until the | ||
20 | * process either exits or performs an exec. That is, performance | ||
21 | * counters remain enabled for fork/clone children. | ||
22 | */ | ||
23 | enum perfctr_opcode { | ||
24 | /* Enable UltraSparc performance counters, ARG0 is pointer | ||
25 | * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer | ||
26 | * to 64-bit accumulator for D1 counter. ARG2 is a pointer to | ||
27 | * the initial PCR register value to use. | ||
28 | */ | ||
29 | PERFCTR_ON, | ||
30 | |||
31 | /* Disable UltraSparc performance counters. The PCR is written | ||
32 | * with zero and the user counter accumulator pointers and | ||
33 | * working PCR register value are forgotten. | ||
34 | */ | ||
35 | PERFCTR_OFF, | ||
36 | |||
37 | /* Add current D0 and D1 PIC values into user pointers given | ||
38 | * in PERFCTR_ON operation. The PIC is cleared before returning. | ||
39 | */ | ||
40 | PERFCTR_READ, | ||
41 | |||
42 | /* Clear the PIC register. */ | ||
43 | PERFCTR_CLRPIC, | ||
44 | |||
45 | /* Begin using a new PCR value, the pointer to which is passed | ||
46 | * in ARG0. The PIC is also cleared after the new PCR value is | ||
47 | * written. | ||
48 | */ | ||
49 | PERFCTR_SETPCR, | ||
50 | |||
51 | /* Store in pointer given in ARG0 the current PCR register value | ||
52 | * being used. | ||
53 | */ | ||
54 | PERFCTR_GETPCR | ||
55 | }; | ||
56 | |||
57 | /* I don't want the kernel's namespace to be polluted with this | ||
58 | * stuff when this file is included. --DaveM | ||
59 | */ | ||
60 | #ifndef __KERNEL__ | ||
61 | |||
62 | #define PRIV 0x00000001 | ||
63 | #define SYS 0x00000002 | ||
64 | #define USR 0x00000004 | ||
65 | |||
66 | /* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ | ||
67 | #define CYCLE_CNT 0x00000000 | ||
68 | #define INSTR_CNT 0x00000010 | ||
69 | #define DISPATCH0_IC_MISS 0x00000020 | ||
70 | #define DISPATCH0_STOREBUF 0x00000030 | ||
71 | #define IC_REF 0x00000080 | ||
72 | #define DC_RD 0x00000090 | ||
73 | #define DC_WR 0x000000A0 | ||
74 | #define LOAD_USE 0x000000B0 | ||
75 | #define EC_REF 0x000000C0 | ||
76 | #define EC_WRITE_HIT_RDO 0x000000D0 | ||
77 | #define EC_SNOOP_INV 0x000000E0 | ||
78 | #define EC_RD_HIT 0x000000F0 | ||
79 | |||
80 | /* Pic.S0 Selection Bit Field Encoding, Ultra-III */ | ||
81 | #define US3_CYCLE_CNT 0x00000000 | ||
82 | #define US3_INSTR_CNT 0x00000010 | ||
83 | #define US3_DISPATCH0_IC_MISS 0x00000020 | ||
84 | #define US3_DISPATCH0_BR_TGT 0x00000030 | ||
85 | #define US3_DISPATCH0_2ND_BR 0x00000040 | ||
86 | #define US3_RSTALL_STOREQ 0x00000050 | ||
87 | #define US3_RSTALL_IU_USE 0x00000060 | ||
88 | #define US3_IC_REF 0x00000080 | ||
89 | #define US3_DC_RD 0x00000090 | ||
90 | #define US3_DC_WR 0x000000a0 | ||
91 | #define US3_EC_REF 0x000000c0 | ||
92 | #define US3_EC_WR_HIT_RTO 0x000000d0 | ||
93 | #define US3_EC_SNOOP_INV 0x000000e0 | ||
94 | #define US3_EC_RD_MISS 0x000000f0 | ||
95 | #define US3_PC_PORT0_RD 0x00000100 | ||
96 | #define US3_SI_SNOOP 0x00000110 | ||
97 | #define US3_SI_CIQ_FLOW 0x00000120 | ||
98 | #define US3_SI_OWNED 0x00000130 | ||
99 | #define US3_SW_COUNT_0 0x00000140 | ||
100 | #define US3_IU_BR_MISS_TAKEN 0x00000150 | ||
101 | #define US3_IU_BR_COUNT_TAKEN 0x00000160 | ||
102 | #define US3_DISP_RS_MISPRED 0x00000170 | ||
103 | #define US3_FA_PIPE_COMPL 0x00000180 | ||
104 | #define US3_MC_READS_0 0x00000200 | ||
105 | #define US3_MC_READS_1 0x00000210 | ||
106 | #define US3_MC_READS_2 0x00000220 | ||
107 | #define US3_MC_READS_3 0x00000230 | ||
108 | #define US3_MC_STALLS_0 0x00000240 | ||
109 | #define US3_MC_STALLS_2 0x00000250 | ||
110 | |||
111 | /* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ | ||
112 | #define CYCLE_CNT_D1 0x00000000 | ||
113 | #define INSTR_CNT_D1 0x00000800 | ||
114 | #define DISPATCH0_IC_MISPRED 0x00001000 | ||
115 | #define DISPATCH0_FP_USE 0x00001800 | ||
116 | #define IC_HIT 0x00004000 | ||
117 | #define DC_RD_HIT 0x00004800 | ||
118 | #define DC_WR_HIT 0x00005000 | ||
119 | #define LOAD_USE_RAW 0x00005800 | ||
120 | #define EC_HIT 0x00006000 | ||
121 | #define EC_WB 0x00006800 | ||
122 | #define EC_SNOOP_CB 0x00007000 | ||
123 | #define EC_IT_HIT 0x00007800 | ||
124 | |||
125 | /* Pic.S1 Selection Bit Field Encoding, Ultra-III */ | ||
126 | #define US3_CYCLE_CNT_D1 0x00000000 | ||
127 | #define US3_INSTR_CNT_D1 0x00000800 | ||
128 | #define US3_DISPATCH0_MISPRED 0x00001000 | ||
129 | #define US3_IC_MISS_CANCELLED 0x00001800 | ||
130 | #define US3_RE_ENDIAN_MISS 0x00002000 | ||
131 | #define US3_RE_FPU_BYPASS 0x00002800 | ||
132 | #define US3_RE_DC_MISS 0x00003000 | ||
133 | #define US3_RE_EC_MISS 0x00003800 | ||
134 | #define US3_IC_MISS 0x00004000 | ||
135 | #define US3_DC_RD_MISS 0x00004800 | ||
136 | #define US3_DC_WR_MISS 0x00005000 | ||
137 | #define US3_RSTALL_FP_USE 0x00005800 | ||
138 | #define US3_EC_MISSES 0x00006000 | ||
139 | #define US3_EC_WB 0x00006800 | ||
140 | #define US3_EC_SNOOP_CB 0x00007000 | ||
141 | #define US3_EC_IC_MISS 0x00007800 | ||
142 | #define US3_RE_PC_MISS 0x00008000 | ||
143 | #define US3_ITLB_MISS 0x00008800 | ||
144 | #define US3_DTLB_MISS 0x00009000 | ||
145 | #define US3_WC_MISS 0x00009800 | ||
146 | #define US3_WC_SNOOP_CB 0x0000a000 | ||
147 | #define US3_WC_SCRUBBED 0x0000a800 | ||
148 | #define US3_WC_WB_WO_READ 0x0000b000 | ||
149 | #define US3_PC_SOFT_HIT 0x0000c000 | ||
150 | #define US3_PC_SNOOP_INV 0x0000c800 | ||
151 | #define US3_PC_HARD_HIT 0x0000d000 | ||
152 | #define US3_PC_PORT1_RD 0x0000d800 | ||
153 | #define US3_SW_COUNT_1 0x0000e000 | ||
154 | #define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 | ||
155 | #define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 | ||
156 | #define US3_PC_MS_MISSES 0x0000f800 | ||
157 | #define US3_MC_WRITES_0 0x00010800 | ||
158 | #define US3_MC_WRITES_1 0x00011000 | ||
159 | #define US3_MC_WRITES_2 0x00011800 | ||
160 | #define US3_MC_WRITES_3 0x00012000 | ||
161 | #define US3_MC_STALLS_1 0x00012800 | ||
162 | #define US3_MC_STALLS_3 0x00013000 | ||
163 | #define US3_RE_RAW_MISS 0x00013800 | ||
164 | #define US3_FM_PIPE_COMPLETION 0x00014000 | ||
165 | |||
166 | struct vcounter_struct { | ||
167 | unsigned long long vcnt0; | ||
168 | unsigned long long vcnt1; | ||
169 | }; | ||
170 | |||
171 | #endif /* !(__KERNEL__) */ | ||
172 | |||
173 | #endif /* !(PERF_COUNTER_API) */ | ||
diff --git a/arch/sparc/include/asm/pgtsun4.h b/arch/sparc/include/asm/pgtsun4.h new file mode 100644 index 00000000000..5a0d661fb82 --- /dev/null +++ b/arch/sparc/include/asm/pgtsun4.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * pgtsun4.h: Sun4 specific pgtable.h defines and code. | ||
3 | * | ||
4 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
5 | * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
6 | */ | ||
7 | #ifndef _SPARC_PGTSUN4C_H | ||
8 | #define _SPARC_PGTSUN4C_H | ||
9 | |||
10 | #include <asm/contregs.h> | ||
11 | |||
12 | /* PMD_SHIFT determines the size of the area a second-level page table can map */ | ||
13 | #define SUN4C_PMD_SHIFT 23 | ||
14 | |||
15 | /* PGDIR_SHIFT determines what a third-level page table entry can map */ | ||
16 | #define SUN4C_PGDIR_SHIFT 23 | ||
17 | #define SUN4C_PGDIR_SIZE (1UL << SUN4C_PGDIR_SHIFT) | ||
18 | #define SUN4C_PGDIR_MASK (~(SUN4C_PGDIR_SIZE-1)) | ||
19 | #define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK) | ||
20 | |||
21 | /* To represent how the sun4c mmu really lays things out. */ | ||
22 | #define SUN4C_REAL_PGDIR_SHIFT 18 | ||
23 | #define SUN4C_REAL_PGDIR_SIZE (1UL << SUN4C_REAL_PGDIR_SHIFT) | ||
24 | #define SUN4C_REAL_PGDIR_MASK (~(SUN4C_REAL_PGDIR_SIZE-1)) | ||
25 | #define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK) | ||
26 | |||
27 | /* 19 bit PFN on sun4 */ | ||
28 | #define SUN4C_PFN_MASK 0x7ffff | ||
29 | |||
30 | /* Don't increase these unless the structures in sun4c.c are fixed */ | ||
31 | #define SUN4C_MAX_SEGMAPS 256 | ||
32 | #define SUN4C_MAX_CONTEXTS 16 | ||
33 | |||
34 | /* | ||
35 | * To be efficient, and not have to worry about allocating such | ||
36 | * a huge pgd, we make the kernel sun4c tables each hold 1024 | ||
37 | * entries and the pgd similarly just like the i386 tables. | ||
38 | */ | ||
39 | #define SUN4C_PTRS_PER_PTE 1024 | ||
40 | #define SUN4C_PTRS_PER_PMD 1 | ||
41 | #define SUN4C_PTRS_PER_PGD 1024 | ||
42 | |||
43 | /* | ||
44 | * Sparc SUN4C pte fields. | ||
45 | */ | ||
46 | #define _SUN4C_PAGE_VALID 0x80000000 | ||
47 | #define _SUN4C_PAGE_SILENT_READ 0x80000000 /* synonym */ | ||
48 | #define _SUN4C_PAGE_DIRTY 0x40000000 | ||
49 | #define _SUN4C_PAGE_SILENT_WRITE 0x40000000 /* synonym */ | ||
50 | #define _SUN4C_PAGE_PRIV 0x20000000 /* privileged page */ | ||
51 | #define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ | ||
52 | #define _SUN4C_PAGE_PRESENT 0x08000000 /* implemented in software */ | ||
53 | #define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ | ||
54 | #define _SUN4C_PAGE_FILE 0x02000000 /* implemented in software */ | ||
55 | #define _SUN4C_PAGE_READ 0x00800000 /* implemented in software */ | ||
56 | #define _SUN4C_PAGE_WRITE 0x00400000 /* implemented in software */ | ||
57 | #define _SUN4C_PAGE_ACCESSED 0x00200000 /* implemented in software */ | ||
58 | #define _SUN4C_PAGE_MODIFIED 0x00100000 /* implemented in software */ | ||
59 | |||
60 | #define _SUN4C_READABLE (_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\ | ||
61 | _SUN4C_PAGE_ACCESSED) | ||
62 | #define _SUN4C_WRITEABLE (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\ | ||
63 | _SUN4C_PAGE_MODIFIED) | ||
64 | |||
65 | #define _SUN4C_PAGE_CHG_MASK (0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED) | ||
66 | |||
67 | #define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_PRESENT) | ||
68 | #define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\ | ||
69 | _SUN4C_PAGE_WRITE) | ||
70 | #define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) | ||
71 | #define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) | ||
72 | #define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\ | ||
73 | _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV) | ||
74 | |||
75 | /* SUN4C swap entry encoding | ||
76 | * | ||
77 | * We use 5 bits for the type and 19 for the offset. This gives us | ||
78 | * 32 swapfiles of 4GB each. Encoding looks like: | ||
79 | * | ||
80 | * RRRRRRRRooooooooooooooooooottttt | ||
81 | * fedcba9876543210fedcba9876543210 | ||
82 | * | ||
83 | * The top 8 bits are reserved for protection and status bits, especially | ||
84 | * FILE and PRESENT. | ||
85 | */ | ||
86 | #define SUN4C_SWP_TYPE_MASK 0x1f | ||
87 | #define SUN4C_SWP_OFF_MASK 0x7ffff | ||
88 | #define SUN4C_SWP_OFF_SHIFT 5 | ||
89 | |||
90 | #ifndef __ASSEMBLY__ | ||
91 | |||
92 | static inline unsigned long sun4c_get_synchronous_error(void) | ||
93 | { | ||
94 | unsigned long sync_err; | ||
95 | |||
96 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
97 | "=r" (sync_err) : | ||
98 | "r" (AC_SYNC_ERR), "i" (ASI_CONTROL)); | ||
99 | return sync_err; | ||
100 | } | ||
101 | |||
102 | static inline unsigned long sun4c_get_synchronous_address(void) | ||
103 | { | ||
104 | unsigned long sync_addr; | ||
105 | |||
106 | __asm__ __volatile__("lda [%1] %2, %0\n\t" : | ||
107 | "=r" (sync_addr) : | ||
108 | "r" (AC_SYNC_VA), "i" (ASI_CONTROL)); | ||
109 | return sync_addr; | ||
110 | } | ||
111 | |||
112 | /* SUN4 pte, segmap, and context manipulation */ | ||
113 | static inline unsigned long sun4c_get_segmap(unsigned long addr) | ||
114 | { | ||
115 | register unsigned long entry; | ||
116 | |||
117 | __asm__ __volatile__("\n\tlduha [%1] %2, %0\n\t" : | ||
118 | "=r" (entry) : | ||
119 | "r" (addr), "i" (ASI_SEGMAP)); | ||
120 | return entry; | ||
121 | } | ||
122 | |||
123 | static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry) | ||
124 | { | ||
125 | __asm__ __volatile__("\n\tstha %1, [%0] %2; nop; nop; nop;\n\t" : : | ||
126 | "r" (addr), "r" (entry), | ||
127 | "i" (ASI_SEGMAP) | ||
128 | : "memory"); | ||
129 | } | ||
130 | |||
131 | static inline unsigned long sun4c_get_pte(unsigned long addr) | ||
132 | { | ||
133 | register unsigned long entry; | ||
134 | |||
135 | __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : | ||
136 | "=r" (entry) : | ||
137 | "r" (addr), "i" (ASI_PTE)); | ||
138 | return entry; | ||
139 | } | ||
140 | |||
141 | static inline void sun4c_put_pte(unsigned long addr, unsigned long entry) | ||
142 | { | ||
143 | __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : : | ||
144 | "r" (addr), | ||
145 | "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE) | ||
146 | : "memory"); | ||
147 | } | ||
148 | |||
149 | static inline int sun4c_get_context(void) | ||
150 | { | ||
151 | register int ctx; | ||
152 | |||
153 | __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : | ||
154 | "=r" (ctx) : | ||
155 | "r" (AC_CONTEXT), "i" (ASI_CONTROL)); | ||
156 | |||
157 | return ctx; | ||
158 | } | ||
159 | |||
160 | static inline int sun4c_set_context(int ctx) | ||
161 | { | ||
162 | __asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : : | ||
163 | "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL) | ||
164 | : "memory"); | ||
165 | |||
166 | return ctx; | ||
167 | } | ||
168 | |||
169 | #endif /* !(__ASSEMBLY__) */ | ||
170 | |||
171 | #endif /* !(_SPARC_PGTSUN4_H) */ | ||
diff --git a/arch/sparc/include/asm/pgtsun4c.h b/arch/sparc/include/asm/pgtsun4c.h new file mode 100644 index 00000000000..aeb25e91217 --- /dev/null +++ b/arch/sparc/include/asm/pgtsun4c.h | |||
@@ -0,0 +1,172 @@ | |||
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/poll.h b/arch/sparc/include/asm/poll.h new file mode 100644 index 00000000000..091d3ad2e83 --- /dev/null +++ b/arch/sparc/include/asm/poll.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef __SPARC_POLL_H | ||
2 | #define __SPARC_POLL_H | ||
3 | |||
4 | #define POLLWRNORM POLLOUT | ||
5 | #define POLLWRBAND 256 | ||
6 | #define POLLMSG 512 | ||
7 | #define POLLREMOVE 1024 | ||
8 | #define POLLRDHUP 2048 | ||
9 | |||
10 | #include <asm-generic/poll.h> | ||
11 | |||
12 | #endif | ||
diff --git a/arch/sparc/include/asm/posix_types.h b/arch/sparc/include/asm/posix_types.h new file mode 100644 index 00000000000..98d6ebb922f --- /dev/null +++ b/arch/sparc/include/asm/posix_types.h | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * This file is generally used by user-level software, so you need to | ||
3 | * be a little careful about namespace pollution etc. Also, we cannot | ||
4 | * assume GCC is being used. | ||
5 | */ | ||
6 | |||
7 | #ifndef __SPARC_POSIX_TYPES_H | ||
8 | #define __SPARC_POSIX_TYPES_H | ||
9 | |||
10 | #if defined(__sparc__) && defined(__arch64__) | ||
11 | /* sparc 64 bit */ | ||
12 | typedef unsigned long __kernel_size_t; | ||
13 | typedef long __kernel_ssize_t; | ||
14 | typedef long __kernel_ptrdiff_t; | ||
15 | typedef long __kernel_time_t; | ||
16 | typedef long __kernel_clock_t; | ||
17 | typedef int __kernel_pid_t; | ||
18 | typedef int __kernel_ipc_pid_t; | ||
19 | typedef unsigned int __kernel_uid_t; | ||
20 | typedef unsigned int __kernel_gid_t; | ||
21 | typedef unsigned long __kernel_ino_t; | ||
22 | typedef unsigned int __kernel_mode_t; | ||
23 | typedef unsigned short __kernel_umode_t; | ||
24 | typedef unsigned int __kernel_nlink_t; | ||
25 | typedef int __kernel_daddr_t; | ||
26 | typedef long __kernel_off_t; | ||
27 | typedef char * __kernel_caddr_t; | ||
28 | typedef unsigned short __kernel_uid16_t; | ||
29 | typedef unsigned short __kernel_gid16_t; | ||
30 | typedef int __kernel_clockid_t; | ||
31 | typedef int __kernel_timer_t; | ||
32 | |||
33 | typedef unsigned short __kernel_old_uid_t; | ||
34 | typedef unsigned short __kernel_old_gid_t; | ||
35 | typedef __kernel_uid_t __kernel_uid32_t; | ||
36 | typedef __kernel_gid_t __kernel_gid32_t; | ||
37 | |||
38 | typedef unsigned int __kernel_old_dev_t; | ||
39 | |||
40 | /* Note this piece of asymmetry from the v9 ABI. */ | ||
41 | typedef int __kernel_suseconds_t; | ||
42 | |||
43 | #else | ||
44 | /* sparc 32 bit */ | ||
45 | |||
46 | typedef unsigned int __kernel_size_t; | ||
47 | typedef int __kernel_ssize_t; | ||
48 | typedef long int __kernel_ptrdiff_t; | ||
49 | typedef long __kernel_time_t; | ||
50 | typedef long __kernel_suseconds_t; | ||
51 | typedef long __kernel_clock_t; | ||
52 | typedef int __kernel_pid_t; | ||
53 | typedef unsigned short __kernel_ipc_pid_t; | ||
54 | typedef unsigned short __kernel_uid_t; | ||
55 | typedef unsigned short __kernel_gid_t; | ||
56 | typedef unsigned long __kernel_ino_t; | ||
57 | typedef unsigned short __kernel_mode_t; | ||
58 | typedef unsigned short __kernel_umode_t; | ||
59 | typedef short __kernel_nlink_t; | ||
60 | typedef long __kernel_daddr_t; | ||
61 | typedef long __kernel_off_t; | ||
62 | typedef char * __kernel_caddr_t; | ||
63 | typedef unsigned short __kernel_uid16_t; | ||
64 | typedef unsigned short __kernel_gid16_t; | ||
65 | typedef unsigned int __kernel_uid32_t; | ||
66 | typedef unsigned int __kernel_gid32_t; | ||
67 | typedef unsigned short __kernel_old_uid_t; | ||
68 | typedef unsigned short __kernel_old_gid_t; | ||
69 | typedef unsigned short __kernel_old_dev_t; | ||
70 | typedef int __kernel_clockid_t; | ||
71 | typedef int __kernel_timer_t; | ||
72 | |||
73 | #endif /* defined(__sparc__) && defined(__arch64__) */ | ||
74 | |||
75 | #ifdef __GNUC__ | ||
76 | typedef long long __kernel_loff_t; | ||
77 | #endif | ||
78 | |||
79 | typedef struct { | ||
80 | int val[2]; | ||
81 | } __kernel_fsid_t; | ||
82 | |||
83 | #ifdef __KERNEL__ | ||
84 | |||
85 | #undef __FD_SET | ||
86 | static inline void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) | ||
87 | { | ||
88 | unsigned long _tmp = fd / __NFDBITS; | ||
89 | unsigned long _rem = fd % __NFDBITS; | ||
90 | fdsetp->fds_bits[_tmp] |= (1UL<<_rem); | ||
91 | } | ||
92 | |||
93 | #undef __FD_CLR | ||
94 | static inline void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) | ||
95 | { | ||
96 | unsigned long _tmp = fd / __NFDBITS; | ||
97 | unsigned long _rem = fd % __NFDBITS; | ||
98 | fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); | ||
99 | } | ||
100 | |||
101 | #undef __FD_ISSET | ||
102 | static inline int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p) | ||
103 | { | ||
104 | unsigned long _tmp = fd / __NFDBITS; | ||
105 | unsigned long _rem = fd % __NFDBITS; | ||
106 | return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * This will unroll the loop for the normal constant cases (8 or 32 longs, | ||
111 | * for 256 and 1024-bit fd_sets respectively) | ||
112 | */ | ||
113 | #undef __FD_ZERO | ||
114 | static inline void __FD_ZERO(__kernel_fd_set *p) | ||
115 | { | ||
116 | unsigned long *tmp = p->fds_bits; | ||
117 | int i; | ||
118 | |||
119 | if (__builtin_constant_p(__FDSET_LONGS)) { | ||
120 | switch (__FDSET_LONGS) { | ||
121 | case 32: | ||
122 | tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; | ||
123 | tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; | ||
124 | tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; | ||
125 | tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; | ||
126 | tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0; | ||
127 | tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0; | ||
128 | tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0; | ||
129 | tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0; | ||
130 | return; | ||
131 | case 16: | ||
132 | tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; | ||
133 | tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; | ||
134 | tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; | ||
135 | tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; | ||
136 | return; | ||
137 | case 8: | ||
138 | tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; | ||
139 | tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; | ||
140 | return; | ||
141 | case 4: | ||
142 | tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; | ||
143 | return; | ||
144 | } | ||
145 | } | ||
146 | i = __FDSET_LONGS; | ||
147 | while (i) { | ||
148 | i--; | ||
149 | *tmp = 0; | ||
150 | tmp++; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | #endif /* __KERNEL__ */ | ||
155 | #endif /* __SPARC_POSIX_TYPES_H */ | ||
diff --git a/arch/sparc/include/asm/psrcompat.h b/arch/sparc/include/asm/psrcompat.h new file mode 100644 index 00000000000..44b6327dbbf --- /dev/null +++ b/arch/sparc/include/asm/psrcompat.h | |||
@@ -0,0 +1,45 @@ | |||
1 | #ifndef _SPARC64_PSRCOMPAT_H | ||
2 | #define _SPARC64_PSRCOMPAT_H | ||
3 | |||
4 | #include <asm/pstate.h> | ||
5 | |||
6 | /* Old 32-bit PSR fields for the compatibility conversion code. */ | ||
7 | #define PSR_CWP 0x0000001f /* current window pointer */ | ||
8 | #define PSR_ET 0x00000020 /* enable traps field */ | ||
9 | #define PSR_PS 0x00000040 /* previous privilege level */ | ||
10 | #define PSR_S 0x00000080 /* current privilege level */ | ||
11 | #define PSR_PIL 0x00000f00 /* processor interrupt level */ | ||
12 | #define PSR_EF 0x00001000 /* enable floating point */ | ||
13 | #define PSR_EC 0x00002000 /* enable co-processor */ | ||
14 | #define PSR_SYSCALL 0x00004000 /* inside of a syscall */ | ||
15 | #define PSR_LE 0x00008000 /* SuperSparcII little-endian */ | ||
16 | #define PSR_ICC 0x00f00000 /* integer condition codes */ | ||
17 | #define PSR_C 0x00100000 /* carry bit */ | ||
18 | #define PSR_V 0x00200000 /* overflow bit */ | ||
19 | #define PSR_Z 0x00400000 /* zero bit */ | ||
20 | #define PSR_N 0x00800000 /* negative bit */ | ||
21 | #define PSR_VERS 0x0f000000 /* cpu-version field */ | ||
22 | #define PSR_IMPL 0xf0000000 /* cpu-implementation field */ | ||
23 | |||
24 | #define PSR_V8PLUS 0xff000000 /* fake impl/ver, meaning a 64bit CPU is present */ | ||
25 | #define PSR_XCC 0x000f0000 /* if PSR_V8PLUS, this is %xcc */ | ||
26 | |||
27 | static inline unsigned int tstate_to_psr(unsigned long tstate) | ||
28 | { | ||
29 | return ((tstate & TSTATE_CWP) | | ||
30 | PSR_S | | ||
31 | ((tstate & TSTATE_ICC) >> 12) | | ||
32 | ((tstate & TSTATE_XCC) >> 20) | | ||
33 | ((tstate & TSTATE_SYSCALL) ? PSR_SYSCALL : 0) | | ||
34 | PSR_V8PLUS); | ||
35 | } | ||
36 | |||
37 | static inline unsigned long psr_to_tstate_icc(unsigned int psr) | ||
38 | { | ||
39 | unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12; | ||
40 | if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) | ||
41 | tstate |= ((unsigned long)(psr & PSR_XCC)) << 20; | ||
42 | return tstate; | ||
43 | } | ||
44 | |||
45 | #endif /* !(_SPARC64_PSRCOMPAT_H) */ | ||
diff --git a/arch/sparc/include/asm/pstate.h b/arch/sparc/include/asm/pstate.h new file mode 100644 index 00000000000..a26a53777bb --- /dev/null +++ b/arch/sparc/include/asm/pstate.h | |||
@@ -0,0 +1,91 @@ | |||
1 | #ifndef _SPARC64_PSTATE_H | ||
2 | #define _SPARC64_PSTATE_H | ||
3 | |||
4 | #include <linux/const.h> | ||
5 | |||
6 | /* The V9 PSTATE Register (with SpitFire extensions). | ||
7 | * | ||
8 | * ----------------------------------------------------------------------- | ||
9 | * | Resv | IG | MG | CLE | TLE | MM | RED | PEF | AM | PRIV | IE | AG | | ||
10 | * ----------------------------------------------------------------------- | ||
11 | * 63 12 11 10 9 8 7 6 5 4 3 2 1 0 | ||
12 | */ | ||
13 | #define PSTATE_IG _AC(0x0000000000000800,UL) /* Interrupt Globals. */ | ||
14 | #define PSTATE_MG _AC(0x0000000000000400,UL) /* MMU Globals. */ | ||
15 | #define PSTATE_CLE _AC(0x0000000000000200,UL) /* Current Little Endian.*/ | ||
16 | #define PSTATE_TLE _AC(0x0000000000000100,UL) /* Trap Little Endian. */ | ||
17 | #define PSTATE_MM _AC(0x00000000000000c0,UL) /* Memory Model. */ | ||
18 | #define PSTATE_TSO _AC(0x0000000000000000,UL) /* MM: TotalStoreOrder */ | ||
19 | #define PSTATE_PSO _AC(0x0000000000000040,UL) /* MM: PartialStoreOrder */ | ||
20 | #define PSTATE_RMO _AC(0x0000000000000080,UL) /* MM: RelaxedMemoryOrder*/ | ||
21 | #define PSTATE_RED _AC(0x0000000000000020,UL) /* Reset Error Debug. */ | ||
22 | #define PSTATE_PEF _AC(0x0000000000000010,UL) /* Floating Point Enable.*/ | ||
23 | #define PSTATE_AM _AC(0x0000000000000008,UL) /* Address Mask. */ | ||
24 | #define PSTATE_PRIV _AC(0x0000000000000004,UL) /* Privilege. */ | ||
25 | #define PSTATE_IE _AC(0x0000000000000002,UL) /* Interrupt Enable. */ | ||
26 | #define PSTATE_AG _AC(0x0000000000000001,UL) /* Alternate Globals. */ | ||
27 | |||
28 | /* The V9 TSTATE Register (with SpitFire and Linux extensions). | ||
29 | * | ||
30 | * --------------------------------------------------------------------- | ||
31 | * | Resv | GL | CCR | ASI | %pil | PSTATE | Resv | CWP | | ||
32 | * --------------------------------------------------------------------- | ||
33 | * 63 43 42 40 39 32 31 24 23 20 19 8 7 5 4 0 | ||
34 | */ | ||
35 | #define TSTATE_GL _AC(0x0000070000000000,UL) /* Global reg level */ | ||
36 | #define TSTATE_CCR _AC(0x000000ff00000000,UL) /* Condition Codes. */ | ||
37 | #define TSTATE_XCC _AC(0x000000f000000000,UL) /* Condition Codes. */ | ||
38 | #define TSTATE_XNEG _AC(0x0000008000000000,UL) /* %xcc Negative. */ | ||
39 | #define TSTATE_XZERO _AC(0x0000004000000000,UL) /* %xcc Zero. */ | ||
40 | #define TSTATE_XOVFL _AC(0x0000002000000000,UL) /* %xcc Overflow. */ | ||
41 | #define TSTATE_XCARRY _AC(0x0000001000000000,UL) /* %xcc Carry. */ | ||
42 | #define TSTATE_ICC _AC(0x0000000f00000000,UL) /* Condition Codes. */ | ||
43 | #define TSTATE_INEG _AC(0x0000000800000000,UL) /* %icc Negative. */ | ||
44 | #define TSTATE_IZERO _AC(0x0000000400000000,UL) /* %icc Zero. */ | ||
45 | #define TSTATE_IOVFL _AC(0x0000000200000000,UL) /* %icc Overflow. */ | ||
46 | #define TSTATE_ICARRY _AC(0x0000000100000000,UL) /* %icc Carry. */ | ||
47 | #define TSTATE_ASI _AC(0x00000000ff000000,UL) /* AddrSpace ID. */ | ||
48 | #define TSTATE_PIL _AC(0x0000000000f00000,UL) /* %pil (Linux traps)*/ | ||
49 | #define TSTATE_PSTATE _AC(0x00000000000fff00,UL) /* PSTATE. */ | ||
50 | #define TSTATE_IG _AC(0x0000000000080000,UL) /* Interrupt Globals.*/ | ||
51 | #define TSTATE_MG _AC(0x0000000000040000,UL) /* MMU Globals. */ | ||
52 | #define TSTATE_CLE _AC(0x0000000000020000,UL) /* CurrLittleEndian. */ | ||
53 | #define TSTATE_TLE _AC(0x0000000000010000,UL) /* TrapLittleEndian. */ | ||
54 | #define TSTATE_MM _AC(0x000000000000c000,UL) /* Memory Model. */ | ||
55 | #define TSTATE_TSO _AC(0x0000000000000000,UL) /* MM: TSO */ | ||
56 | #define TSTATE_PSO _AC(0x0000000000004000,UL) /* MM: PSO */ | ||
57 | #define TSTATE_RMO _AC(0x0000000000008000,UL) /* MM: RMO */ | ||
58 | #define TSTATE_RED _AC(0x0000000000002000,UL) /* Reset Error Debug.*/ | ||
59 | #define TSTATE_PEF _AC(0x0000000000001000,UL) /* FPU Enable. */ | ||
60 | #define TSTATE_AM _AC(0x0000000000000800,UL) /* Address Mask. */ | ||
61 | #define TSTATE_PRIV _AC(0x0000000000000400,UL) /* Privilege. */ | ||
62 | #define TSTATE_IE _AC(0x0000000000000200,UL) /* Interrupt Enable. */ | ||
63 | #define TSTATE_AG _AC(0x0000000000000100,UL) /* Alternate Globals.*/ | ||
64 | #define TSTATE_SYSCALL _AC(0x0000000000000020,UL) /* in syscall trap */ | ||
65 | #define TSTATE_CWP _AC(0x000000000000001f,UL) /* Curr Win-Pointer. */ | ||
66 | |||
67 | /* Floating-Point Registers State Register. | ||
68 | * | ||
69 | * -------------------------------- | ||
70 | * | Resv | FEF | DU | DL | | ||
71 | * -------------------------------- | ||
72 | * 63 3 2 1 0 | ||
73 | */ | ||
74 | #define FPRS_FEF _AC(0x0000000000000004,UL) /* FPU Enable. */ | ||
75 | #define FPRS_DU _AC(0x0000000000000002,UL) /* Dirty Upper. */ | ||
76 | #define FPRS_DL _AC(0x0000000000000001,UL) /* Dirty Lower. */ | ||
77 | |||
78 | /* Version Register. | ||
79 | * | ||
80 | * ------------------------------------------------------ | ||
81 | * | MANUF | IMPL | MASK | Resv | MAXTL | Resv | MAXWIN | | ||
82 | * ------------------------------------------------------ | ||
83 | * 63 48 47 32 31 24 23 16 15 8 7 5 4 0 | ||
84 | */ | ||
85 | #define VERS_MANUF _AC(0xffff000000000000,UL) /* Manufacturer. */ | ||
86 | #define VERS_IMPL _AC(0x0000ffff00000000,UL) /* Implementation. */ | ||
87 | #define VERS_MASK _AC(0x00000000ff000000,UL) /* Mask Set Revision.*/ | ||
88 | #define VERS_MAXTL _AC(0x000000000000ff00,UL) /* Max Trap Level. */ | ||
89 | #define VERS_MAXWIN _AC(0x000000000000001f,UL) /* Max RegWindow Idx.*/ | ||
90 | |||
91 | #endif /* !(_SPARC64_PSTATE_H) */ | ||
diff --git a/arch/sparc/include/asm/resource.h b/arch/sparc/include/asm/resource.h new file mode 100644 index 00000000000..fe163cafb4c --- /dev/null +++ b/arch/sparc/include/asm/resource.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * resource.h: Resource definitions. | ||
3 | * | ||
4 | * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #ifndef _SPARC_RESOURCE_H | ||
8 | #define _SPARC_RESOURCE_H | ||
9 | |||
10 | /* | ||
11 | * These two resource limit IDs have a Sparc/Linux-specific ordering, | ||
12 | * the rest comes from the generic header: | ||
13 | */ | ||
14 | #define RLIMIT_NOFILE 6 /* max number of open files */ | ||
15 | #define RLIMIT_NPROC 7 /* max number of processes */ | ||
16 | |||
17 | #if defined(__sparc__) && defined(__arch64__) | ||
18 | /* Use generic version */ | ||
19 | #else | ||
20 | /* | ||
21 | * SuS says limits have to be unsigned. | ||
22 | * We make this unsigned, but keep the | ||
23 | * old value for compatibility: | ||
24 | */ | ||
25 | #define RLIM_INFINITY 0x7fffffff | ||
26 | #endif | ||
27 | |||
28 | #include <asm-generic/resource.h> | ||
29 | |||
30 | #endif /* !(_SPARC_RESOURCE_H) */ | ||
diff --git a/arch/sparc/include/asm/sembuf.h b/arch/sparc/include/asm/sembuf.h new file mode 100644 index 00000000000..faee1be08d6 --- /dev/null +++ b/arch/sparc/include/asm/sembuf.h | |||
@@ -0,0 +1,31 @@ | |||
1 | #ifndef _SPARC_SEMBUF_H | ||
2 | #define _SPARC_SEMBUF_H | ||
3 | |||
4 | /* | ||
5 | * The semid64_ds structure for sparc architecture. | ||
6 | * Note extra padding because this structure is passed back and forth | ||
7 | * between kernel and user space. | ||
8 | * | ||
9 | * Pad space is left for: | ||
10 | * - 64-bit time_t to solve y2038 problem | ||
11 | * - 2 miscellaneous 32-bit values | ||
12 | */ | ||
13 | #if defined(__sparc__) && defined(__arch64__) | ||
14 | # define PADDING(x) | ||
15 | #else | ||
16 | # define PADDING(x) unsigned int x; | ||
17 | #endif | ||
18 | |||
19 | struct semid64_ds { | ||
20 | struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ | ||
21 | PADDING(__pad1) | ||
22 | __kernel_time_t sem_otime; /* last semop time */ | ||
23 | PADDING(__pad2) | ||
24 | __kernel_time_t sem_ctime; /* last change time */ | ||
25 | unsigned long sem_nsems; /* no. of semaphores in array */ | ||
26 | unsigned long __unused1; | ||
27 | unsigned long __unused2; | ||
28 | }; | ||
29 | #undef PADDING | ||
30 | |||
31 | #endif /* _SPARC64_SEMBUF_H */ | ||
diff --git a/arch/sparc/include/asm/shmbuf.h b/arch/sparc/include/asm/shmbuf.h new file mode 100644 index 00000000000..83a16055363 --- /dev/null +++ b/arch/sparc/include/asm/shmbuf.h | |||
@@ -0,0 +1,50 @@ | |||
1 | #ifndef _SPARC_SHMBUF_H | ||
2 | #define _SPARC_SHMBUF_H | ||
3 | |||
4 | /* | ||
5 | * The shmid64_ds structure for sparc architecture. | ||
6 | * Note extra padding because this structure is passed back and forth | ||
7 | * between kernel and user space. | ||
8 | * | ||
9 | * Pad space is left for: | ||
10 | * - 64-bit time_t to solve y2038 problem | ||
11 | * - 2 miscellaneous 32-bit values | ||
12 | */ | ||
13 | |||
14 | #if defined(__sparc__) && defined(__arch64__) | ||
15 | # define PADDING(x) | ||
16 | #else | ||
17 | # define PADDING(x) unsigned int x; | ||
18 | #endif | ||
19 | |||
20 | struct shmid64_ds { | ||
21 | struct ipc64_perm shm_perm; /* operation perms */ | ||
22 | PADDING(__pad1) | ||
23 | __kernel_time_t shm_atime; /* last attach time */ | ||
24 | PADDING(__pad2) | ||
25 | __kernel_time_t shm_dtime; /* last detach time */ | ||
26 | PADDING(__pad3) | ||
27 | __kernel_time_t shm_ctime; /* last change time */ | ||
28 | size_t shm_segsz; /* size of segment (bytes) */ | ||
29 | __kernel_pid_t shm_cpid; /* pid of creator */ | ||
30 | __kernel_pid_t shm_lpid; /* pid of last operator */ | ||
31 | unsigned long shm_nattch; /* no. of current attaches */ | ||
32 | unsigned long __unused1; | ||
33 | unsigned long __unused2; | ||
34 | }; | ||
35 | |||
36 | struct shminfo64 { | ||
37 | unsigned long shmmax; | ||
38 | unsigned long shmmin; | ||
39 | unsigned long shmmni; | ||
40 | unsigned long shmseg; | ||
41 | unsigned long shmall; | ||
42 | unsigned long __unused1; | ||
43 | unsigned long __unused2; | ||
44 | unsigned long __unused3; | ||
45 | unsigned long __unused4; | ||
46 | }; | ||
47 | |||
48 | #undef PADDING | ||
49 | |||
50 | #endif /* _SPARC_SHMBUF_H */ | ||
diff --git a/arch/sparc/include/asm/smpprim.h b/arch/sparc/include/asm/smpprim.h new file mode 100644 index 00000000000..eb849d862c6 --- /dev/null +++ b/arch/sparc/include/asm/smpprim.h | |||
@@ -0,0 +1,54 @@ | |||
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/socket.h b/arch/sparc/include/asm/socket.h new file mode 100644 index 00000000000..9d3fefcff2f --- /dev/null +++ b/arch/sparc/include/asm/socket.h | |||
@@ -0,0 +1,66 @@ | |||
1 | #ifndef _ASM_SOCKET_H | ||
2 | #define _ASM_SOCKET_H | ||
3 | |||
4 | #include <asm/sockios.h> | ||
5 | |||
6 | /* For setsockopt(2) */ | ||
7 | #define SOL_SOCKET 0xffff | ||
8 | |||
9 | #define SO_DEBUG 0x0001 | ||
10 | #define SO_PASSCRED 0x0002 | ||
11 | #define SO_REUSEADDR 0x0004 | ||
12 | #define SO_KEEPALIVE 0x0008 | ||
13 | #define SO_DONTROUTE 0x0010 | ||
14 | #define SO_BROADCAST 0x0020 | ||
15 | #define SO_PEERCRED 0x0040 | ||
16 | #define SO_LINGER 0x0080 | ||
17 | #define SO_OOBINLINE 0x0100 | ||
18 | /* To add :#define SO_REUSEPORT 0x0200 */ | ||
19 | #define SO_BSDCOMPAT 0x0400 | ||
20 | #define SO_RCVLOWAT 0x0800 | ||
21 | #define SO_SNDLOWAT 0x1000 | ||
22 | #define SO_RCVTIMEO 0x2000 | ||
23 | #define SO_SNDTIMEO 0x4000 | ||
24 | #define SO_ACCEPTCONN 0x8000 | ||
25 | |||
26 | #define SO_SNDBUF 0x1001 | ||
27 | #define SO_RCVBUF 0x1002 | ||
28 | #define SO_SNDBUFFORCE 0x100a | ||
29 | #define SO_RCVBUFFORCE 0x100b | ||
30 | #define SO_ERROR 0x1007 | ||
31 | #define SO_TYPE 0x1008 | ||
32 | #define SO_PROTOCOL 0x1028 | ||
33 | #define SO_DOMAIN 0x1029 | ||
34 | |||
35 | |||
36 | /* Linux specific, keep the same. */ | ||
37 | #define SO_NO_CHECK 0x000b | ||
38 | #define SO_PRIORITY 0x000c | ||
39 | |||
40 | #define SO_BINDTODEVICE 0x000d | ||
41 | |||
42 | #define SO_ATTACH_FILTER 0x001a | ||
43 | #define SO_DETACH_FILTER 0x001b | ||
44 | |||
45 | #define SO_PEERNAME 0x001c | ||
46 | #define SO_TIMESTAMP 0x001d | ||
47 | #define SCM_TIMESTAMP SO_TIMESTAMP | ||
48 | |||
49 | #define SO_PEERSEC 0x001e | ||
50 | #define SO_PASSSEC 0x001f | ||
51 | #define SO_TIMESTAMPNS 0x0021 | ||
52 | #define SCM_TIMESTAMPNS SO_TIMESTAMPNS | ||
53 | |||
54 | #define SO_MARK 0x0022 | ||
55 | |||
56 | #define SO_TIMESTAMPING 0x0023 | ||
57 | #define SCM_TIMESTAMPING SO_TIMESTAMPING | ||
58 | |||
59 | #define SO_RXQ_OVFL 0x0024 | ||
60 | |||
61 | /* Security levels - as per NRL IPv6 - don't actually do anything */ | ||
62 | #define SO_SECURITY_AUTHENTICATION 0x5001 | ||
63 | #define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 | ||
64 | #define SO_SECURITY_ENCRYPTION_NETWORK 0x5004 | ||
65 | |||
66 | #endif /* _ASM_SOCKET_H */ | ||
diff --git a/arch/sparc/include/asm/sockios.h b/arch/sparc/include/asm/sockios.h new file mode 100644 index 00000000000..990ea746486 --- /dev/null +++ b/arch/sparc/include/asm/sockios.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef _ASM_SPARC_SOCKIOS_H | ||
2 | #define _ASM_SPARC_SOCKIOS_H | ||
3 | |||
4 | /* Socket-level I/O control calls. */ | ||
5 | #define FIOSETOWN 0x8901 | ||
6 | #define SIOCSPGRP 0x8902 | ||
7 | #define FIOGETOWN 0x8903 | ||
8 | #define SIOCGPGRP 0x8904 | ||
9 | #define SIOCATMARK 0x8905 | ||
10 | #define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ | ||
11 | #define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ | ||
12 | |||
13 | #endif /* !(_ASM_SPARC_SOCKIOS_H) */ | ||
14 | |||
diff --git a/arch/sparc/include/asm/stat.h b/arch/sparc/include/asm/stat.h new file mode 100644 index 00000000000..a232e9e1f4e --- /dev/null +++ b/arch/sparc/include/asm/stat.h | |||
@@ -0,0 +1,107 @@ | |||
1 | #ifndef __SPARC_STAT_H | ||
2 | #define __SPARC_STAT_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | #if defined(__sparc__) && defined(__arch64__) | ||
7 | /* 64 bit sparc */ | ||
8 | struct stat { | ||
9 | unsigned st_dev; | ||
10 | ino_t st_ino; | ||
11 | mode_t st_mode; | ||
12 | short st_nlink; | ||
13 | uid_t st_uid; | ||
14 | gid_t st_gid; | ||
15 | unsigned st_rdev; | ||
16 | off_t st_size; | ||
17 | time_t st_atime; | ||
18 | time_t st_mtime; | ||
19 | time_t st_ctime; | ||
20 | off_t st_blksize; | ||
21 | off_t st_blocks; | ||
22 | unsigned long __unused4[2]; | ||
23 | }; | ||
24 | |||
25 | struct stat64 { | ||
26 | unsigned long st_dev; | ||
27 | unsigned long st_ino; | ||
28 | unsigned long st_nlink; | ||
29 | |||
30 | unsigned int st_mode; | ||
31 | unsigned int st_uid; | ||
32 | unsigned int st_gid; | ||
33 | unsigned int __pad0; | ||
34 | |||
35 | unsigned long st_rdev; | ||
36 | long st_size; | ||
37 | long st_blksize; | ||
38 | long st_blocks; | ||
39 | |||
40 | unsigned long st_atime; | ||
41 | unsigned long st_atime_nsec; | ||
42 | unsigned long st_mtime; | ||
43 | unsigned long st_mtime_nsec; | ||
44 | unsigned long st_ctime; | ||
45 | unsigned long st_ctime_nsec; | ||
46 | long __unused[3]; | ||
47 | }; | ||
48 | |||
49 | #else | ||
50 | /* 32 bit sparc */ | ||
51 | struct stat { | ||
52 | unsigned short st_dev; | ||
53 | ino_t st_ino; | ||
54 | mode_t st_mode; | ||
55 | short st_nlink; | ||
56 | unsigned short st_uid; | ||
57 | unsigned short st_gid; | ||
58 | unsigned short st_rdev; | ||
59 | off_t st_size; | ||
60 | time_t st_atime; | ||
61 | unsigned long st_atime_nsec; | ||
62 | time_t st_mtime; | ||
63 | unsigned long st_mtime_nsec; | ||
64 | time_t st_ctime; | ||
65 | unsigned long st_ctime_nsec; | ||
66 | off_t st_blksize; | ||
67 | off_t st_blocks; | ||
68 | unsigned long __unused4[2]; | ||
69 | }; | ||
70 | |||
71 | #define STAT_HAVE_NSEC 1 | ||
72 | |||
73 | struct stat64 { | ||
74 | unsigned long long st_dev; | ||
75 | |||
76 | unsigned long long st_ino; | ||
77 | |||
78 | unsigned int st_mode; | ||
79 | unsigned int st_nlink; | ||
80 | |||
81 | unsigned int st_uid; | ||
82 | unsigned int st_gid; | ||
83 | |||
84 | unsigned long long st_rdev; | ||
85 | |||
86 | unsigned char __pad3[8]; | ||
87 | |||
88 | long long st_size; | ||
89 | unsigned int st_blksize; | ||
90 | |||
91 | unsigned char __pad4[8]; | ||
92 | unsigned int st_blocks; | ||
93 | |||
94 | unsigned int st_atime; | ||
95 | unsigned int st_atime_nsec; | ||
96 | |||
97 | unsigned int st_mtime; | ||
98 | unsigned int st_mtime_nsec; | ||
99 | |||
100 | unsigned int st_ctime; | ||
101 | unsigned int st_ctime_nsec; | ||
102 | |||
103 | unsigned int __unused4; | ||
104 | unsigned int __unused5; | ||
105 | }; | ||
106 | #endif /* defined(__sparc__) && defined(__arch64__) */ | ||
107 | #endif /* __SPARC_STAT_H */ | ||
diff --git a/arch/sparc/include/asm/statfs.h b/arch/sparc/include/asm/statfs.h new file mode 100644 index 00000000000..55e607ad461 --- /dev/null +++ b/arch/sparc/include/asm/statfs.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef ___ASM_SPARC_STATFS_H | ||
2 | #define ___ASM_SPARC_STATFS_H | ||
3 | |||
4 | #include <asm-generic/statfs.h> | ||
5 | |||
6 | #endif | ||
diff --git a/arch/sparc/include/asm/swab.h b/arch/sparc/include/asm/swab.h new file mode 100644 index 00000000000..a34ad079487 --- /dev/null +++ b/arch/sparc/include/asm/swab.h | |||
@@ -0,0 +1,45 @@ | |||
1 | #ifndef _SPARC_SWAB_H | ||
2 | #define _SPARC_SWAB_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <asm/asi.h> | ||
6 | |||
7 | #if defined(__sparc__) && defined(__arch64__) | ||
8 | static inline __u16 __arch_swab16p(const __u16 *addr) | ||
9 | { | ||
10 | __u16 ret; | ||
11 | |||
12 | __asm__ __volatile__ ("lduha [%1] %2, %0" | ||
13 | : "=r" (ret) | ||
14 | : "r" (addr), "i" (ASI_PL)); | ||
15 | return ret; | ||
16 | } | ||
17 | #define __arch_swab16p __arch_swab16p | ||
18 | |||
19 | static inline __u32 __arch_swab32p(const __u32 *addr) | ||
20 | { | ||
21 | __u32 ret; | ||
22 | |||
23 | __asm__ __volatile__ ("lduwa [%1] %2, %0" | ||
24 | : "=r" (ret) | ||
25 | : "r" (addr), "i" (ASI_PL)); | ||
26 | return ret; | ||
27 | } | ||
28 | #define __arch_swab32p __arch_swab32p | ||
29 | |||
30 | static inline __u64 __arch_swab64p(const __u64 *addr) | ||
31 | { | ||
32 | __u64 ret; | ||
33 | |||
34 | __asm__ __volatile__ ("ldxa [%1] %2, %0" | ||
35 | : "=r" (ret) | ||
36 | : "r" (addr), "i" (ASI_PL)); | ||
37 | return ret; | ||
38 | } | ||
39 | #define __arch_swab64p __arch_swab64p | ||
40 | |||
41 | #else | ||
42 | #define __SWAB_64_THRU_32__ | ||
43 | #endif /* defined(__sparc__) && defined(__arch64__) */ | ||
44 | |||
45 | #endif /* _SPARC_SWAB_H */ | ||
diff --git a/arch/sparc/include/asm/sysen.h b/arch/sparc/include/asm/sysen.h new file mode 100644 index 00000000000..6af34abde6e --- /dev/null +++ b/arch/sparc/include/asm/sysen.h | |||
@@ -0,0 +1,15 @@ | |||
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/system.h b/arch/sparc/include/asm/system.h new file mode 100644 index 00000000000..7944a7cfc99 --- /dev/null +++ b/arch/sparc/include/asm/system.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #ifndef ___ASM_SPARC_SYSTEM_H | ||
2 | #define ___ASM_SPARC_SYSTEM_H | ||
3 | #if defined(__sparc__) && defined(__arch64__) | ||
4 | #include <asm/system_64.h> | ||
5 | #else | ||
6 | #include <asm/system_32.h> | ||
7 | #endif | ||
8 | #endif | ||
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h new file mode 100644 index 00000000000..aba16092a81 --- /dev/null +++ b/arch/sparc/include/asm/system_32.h | |||
@@ -0,0 +1,284 @@ | |||
1 | #ifndef __SPARC_SYSTEM_H | ||
2 | #define __SPARC_SYSTEM_H | ||
3 | |||
4 | #include <linux/kernel.h> | ||
5 | #include <linux/threads.h> /* NR_CPUS */ | ||
6 | #include <linux/thread_info.h> | ||
7 | |||
8 | #include <asm/page.h> | ||
9 | #include <asm/psr.h> | ||
10 | #include <asm/ptrace.h> | ||
11 | #include <asm/btfixup.h> | ||
12 | #include <asm/smp.h> | ||
13 | |||
14 | #ifndef __ASSEMBLY__ | ||
15 | |||
16 | #include <linux/irqflags.h> | ||
17 | |||
18 | /* | ||
19 | * Sparc (general) CPU types | ||
20 | */ | ||
21 | enum sparc_cpu { | ||
22 | sun4 = 0x00, | ||
23 | sun4c = 0x01, | ||
24 | sun4m = 0x02, | ||
25 | sun4d = 0x03, | ||
26 | sun4e = 0x04, | ||
27 | sun4u = 0x05, /* V8 ploos ploos */ | ||
28 | sun_unknown = 0x06, | ||
29 | ap1000 = 0x07, /* almost a sun4m */ | ||
30 | sparc_leon = 0x08, /* Leon SoC */ | ||
31 | }; | ||
32 | |||
33 | /* Really, userland should not be looking at any of this... */ | ||
34 | #ifdef __KERNEL__ | ||
35 | |||
36 | extern enum sparc_cpu sparc_cpu_model; | ||
37 | |||
38 | #define ARCH_SUN4C (sparc_cpu_model==sun4c) | ||
39 | |||
40 | #define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */ | ||
41 | |||
42 | extern char reboot_command[]; | ||
43 | |||
44 | extern struct thread_info *current_set[NR_CPUS]; | ||
45 | |||
46 | extern unsigned long empty_bad_page; | ||
47 | extern unsigned long empty_bad_page_table; | ||
48 | extern unsigned long empty_zero_page; | ||
49 | |||
50 | extern void sun_do_break(void); | ||
51 | extern int serial_console; | ||
52 | extern int stop_a_enabled; | ||
53 | extern int scons_pwroff; | ||
54 | |||
55 | static inline int con_is_present(void) | ||
56 | { | ||
57 | return serial_console ? 0 : 1; | ||
58 | } | ||
59 | |||
60 | /* When a context switch happens we must flush all user windows so that | ||
61 | * the windows of the current process are flushed onto its stack. This | ||
62 | * way the windows are all clean for the next process and the stack | ||
63 | * frames are up to date. | ||
64 | */ | ||
65 | extern void flush_user_windows(void); | ||
66 | extern void kill_user_windows(void); | ||
67 | extern void synchronize_user_stack(void); | ||
68 | extern void fpsave(unsigned long *fpregs, unsigned long *fsr, | ||
69 | void *fpqueue, unsigned long *fpqdepth); | ||
70 | |||
71 | #ifdef CONFIG_SMP | ||
72 | #define SWITCH_ENTER(prv) \ | ||
73 | do { \ | ||
74 | if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \ | ||
75 | put_psr(get_psr() | PSR_EF); \ | ||
76 | fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \ | ||
77 | &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \ | ||
78 | clear_tsk_thread_flag(prv, TIF_USEDFPU); \ | ||
79 | (prv)->thread.kregs->psr &= ~PSR_EF; \ | ||
80 | } \ | ||
81 | } while(0) | ||
82 | |||
83 | #define SWITCH_DO_LAZY_FPU(next) /* */ | ||
84 | #else | ||
85 | #define SWITCH_ENTER(prv) /* */ | ||
86 | #define SWITCH_DO_LAZY_FPU(nxt) \ | ||
87 | do { \ | ||
88 | if (last_task_used_math != (nxt)) \ | ||
89 | (nxt)->thread.kregs->psr&=~PSR_EF; \ | ||
90 | } while(0) | ||
91 | #endif | ||
92 | |||
93 | extern void flushw_all(void); | ||
94 | |||
95 | /* | ||
96 | * Flush windows so that the VM switch which follows | ||
97 | * would not pull the stack from under us. | ||
98 | * | ||
99 | * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work) | ||
100 | * XXX WTF is the above comment? Found in late teen 2.4.x. | ||
101 | */ | ||
102 | #define prepare_arch_switch(next) do { \ | ||
103 | __asm__ __volatile__( \ | ||
104 | ".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \ | ||
105 | "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \ | ||
106 | "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \ | ||
107 | "save %sp, -0x40, %sp\n\t" \ | ||
108 | "restore; restore; restore; restore; restore; restore; restore"); \ | ||
109 | } while(0) | ||
110 | |||
111 | /* Much care has gone into this code, do not touch it. | ||
112 | * | ||
113 | * We need to loadup regs l0/l1 for the newly forked child | ||
114 | * case because the trap return path relies on those registers | ||
115 | * holding certain values, gcc is told that they are clobbered. | ||
116 | * Gcc needs registers for 3 values in and 1 value out, so we | ||
117 | * clobber every non-fixed-usage register besides l2/l3/o4/o5. -DaveM | ||
118 | * | ||
119 | * Hey Dave, that do not touch sign is too much of an incentive | ||
120 | * - Anton & Pete | ||
121 | */ | ||
122 | #define switch_to(prev, next, last) do { \ | ||
123 | SWITCH_ENTER(prev); \ | ||
124 | SWITCH_DO_LAZY_FPU(next); \ | ||
125 | cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm)); \ | ||
126 | __asm__ __volatile__( \ | ||
127 | "sethi %%hi(here - 0x8), %%o7\n\t" \ | ||
128 | "mov %%g6, %%g3\n\t" \ | ||
129 | "or %%o7, %%lo(here - 0x8), %%o7\n\t" \ | ||
130 | "rd %%psr, %%g4\n\t" \ | ||
131 | "std %%sp, [%%g6 + %4]\n\t" \ | ||
132 | "rd %%wim, %%g5\n\t" \ | ||
133 | "wr %%g4, 0x20, %%psr\n\t" \ | ||
134 | "nop\n\t" \ | ||
135 | "std %%g4, [%%g6 + %3]\n\t" \ | ||
136 | "ldd [%2 + %3], %%g4\n\t" \ | ||
137 | "mov %2, %%g6\n\t" \ | ||
138 | ".globl patchme_store_new_current\n" \ | ||
139 | "patchme_store_new_current:\n\t" \ | ||
140 | "st %2, [%1]\n\t" \ | ||
141 | "wr %%g4, 0x20, %%psr\n\t" \ | ||
142 | "nop\n\t" \ | ||
143 | "nop\n\t" \ | ||
144 | "nop\n\t" /* LEON needs all 3 nops: load to %sp depends on CWP. */ \ | ||
145 | "ldd [%%g6 + %4], %%sp\n\t" \ | ||
146 | "wr %%g5, 0x0, %%wim\n\t" \ | ||
147 | "ldd [%%sp + 0x00], %%l0\n\t" \ | ||
148 | "ldd [%%sp + 0x38], %%i6\n\t" \ | ||
149 | "wr %%g4, 0x0, %%psr\n\t" \ | ||
150 | "nop\n\t" \ | ||
151 | "nop\n\t" \ | ||
152 | "jmpl %%o7 + 0x8, %%g0\n\t" \ | ||
153 | " ld [%%g3 + %5], %0\n\t" \ | ||
154 | "here:\n" \ | ||
155 | : "=&r" (last) \ | ||
156 | : "r" (&(current_set[hard_smp_processor_id()])), \ | ||
157 | "r" (task_thread_info(next)), \ | ||
158 | "i" (TI_KPSR), \ | ||
159 | "i" (TI_KSP), \ | ||
160 | "i" (TI_TASK) \ | ||
161 | : "g1", "g2", "g3", "g4", "g5", "g7", \ | ||
162 | "l0", "l1", "l3", "l4", "l5", "l6", "l7", \ | ||
163 | "i0", "i1", "i2", "i3", "i4", "i5", \ | ||
164 | "o0", "o1", "o2", "o3", "o7"); \ | ||
165 | } while(0) | ||
166 | |||
167 | /* XXX Change this if we ever use a PSO mode kernel. */ | ||
168 | #define mb() __asm__ __volatile__ ("" : : : "memory") | ||
169 | #define rmb() mb() | ||
170 | #define wmb() mb() | ||
171 | #define read_barrier_depends() do { } while(0) | ||
172 | #define set_mb(__var, __value) do { __var = __value; mb(); } while(0) | ||
173 | #define smp_mb() __asm__ __volatile__("":::"memory") | ||
174 | #define smp_rmb() __asm__ __volatile__("":::"memory") | ||
175 | #define smp_wmb() __asm__ __volatile__("":::"memory") | ||
176 | #define smp_read_barrier_depends() do { } while(0) | ||
177 | |||
178 | #define nop() __asm__ __volatile__ ("nop") | ||
179 | |||
180 | /* This has special calling conventions */ | ||
181 | #ifndef CONFIG_SMP | ||
182 | BTFIXUPDEF_CALL(void, ___xchg32, void) | ||
183 | #endif | ||
184 | |||
185 | static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) | ||
186 | { | ||
187 | #ifdef CONFIG_SMP | ||
188 | __asm__ __volatile__("swap [%2], %0" | ||
189 | : "=&r" (val) | ||
190 | : "0" (val), "r" (m) | ||
191 | : "memory"); | ||
192 | return val; | ||
193 | #else | ||
194 | register unsigned long *ptr asm("g1"); | ||
195 | register unsigned long ret asm("g2"); | ||
196 | |||
197 | ptr = (unsigned long *) m; | ||
198 | ret = val; | ||
199 | |||
200 | /* Note: this is magic and the nop there is | ||
201 | really needed. */ | ||
202 | __asm__ __volatile__( | ||
203 | "mov %%o7, %%g4\n\t" | ||
204 | "call ___f____xchg32\n\t" | ||
205 | " nop\n\t" | ||
206 | : "=&r" (ret) | ||
207 | : "0" (ret), "r" (ptr) | ||
208 | : "g3", "g4", "g7", "memory", "cc"); | ||
209 | |||
210 | return ret; | ||
211 | #endif | ||
212 | } | ||
213 | |||
214 | #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | ||
215 | |||
216 | extern void __xchg_called_with_bad_pointer(void); | ||
217 | |||
218 | static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) | ||
219 | { | ||
220 | switch (size) { | ||
221 | case 4: | ||
222 | return xchg_u32(ptr, x); | ||
223 | } | ||
224 | __xchg_called_with_bad_pointer(); | ||
225 | return x; | ||
226 | } | ||
227 | |||
228 | /* Emulate cmpxchg() the same way we emulate atomics, | ||
229 | * by hashing the object address and indexing into an array | ||
230 | * of spinlocks to get a bit of performance... | ||
231 | * | ||
232 | * See arch/sparc/lib/atomic32.c for implementation. | ||
233 | * | ||
234 | * Cribbed from <asm-parisc/atomic.h> | ||
235 | */ | ||
236 | #define __HAVE_ARCH_CMPXCHG 1 | ||
237 | |||
238 | /* bug catcher for when unsupported size is used - won't link */ | ||
239 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
240 | /* we only need to support cmpxchg of a u32 on sparc */ | ||
241 | extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_); | ||
242 | |||
243 | /* don't worry...optimizer will get rid of most of this */ | ||
244 | static inline unsigned long | ||
245 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size) | ||
246 | { | ||
247 | switch (size) { | ||
248 | case 4: | ||
249 | return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_); | ||
250 | default: | ||
251 | __cmpxchg_called_with_bad_pointer(); | ||
252 | break; | ||
253 | } | ||
254 | return old; | ||
255 | } | ||
256 | |||
257 | #define cmpxchg(ptr, o, n) \ | ||
258 | ({ \ | ||
259 | __typeof__(*(ptr)) _o_ = (o); \ | ||
260 | __typeof__(*(ptr)) _n_ = (n); \ | ||
261 | (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ | ||
262 | (unsigned long)_n_, sizeof(*(ptr))); \ | ||
263 | }) | ||
264 | |||
265 | #include <asm-generic/cmpxchg-local.h> | ||
266 | |||
267 | /* | ||
268 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
269 | * them available. | ||
270 | */ | ||
271 | #define cmpxchg_local(ptr, o, n) \ | ||
272 | ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ | ||
273 | (unsigned long)(n), sizeof(*(ptr)))) | ||
274 | #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) | ||
275 | |||
276 | extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); | ||
277 | |||
278 | #endif /* __KERNEL__ */ | ||
279 | |||
280 | #endif /* __ASSEMBLY__ */ | ||
281 | |||
282 | #define arch_align_stack(x) (x) | ||
283 | |||
284 | #endif /* !(__SPARC_SYSTEM_H) */ | ||
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h new file mode 100644 index 00000000000..10bcabce97b --- /dev/null +++ b/arch/sparc/include/asm/system_64.h | |||
@@ -0,0 +1,331 @@ | |||
1 | #ifndef __SPARC64_SYSTEM_H | ||
2 | #define __SPARC64_SYSTEM_H | ||
3 | |||
4 | #include <asm/ptrace.h> | ||
5 | #include <asm/processor.h> | ||
6 | #include <asm/visasm.h> | ||
7 | |||
8 | #ifndef __ASSEMBLY__ | ||
9 | |||
10 | #include <linux/irqflags.h> | ||
11 | #include <asm-generic/cmpxchg-local.h> | ||
12 | |||
13 | /* | ||
14 | * Sparc (general) CPU types | ||
15 | */ | ||
16 | enum sparc_cpu { | ||
17 | sun4 = 0x00, | ||
18 | sun4c = 0x01, | ||
19 | sun4m = 0x02, | ||
20 | sun4d = 0x03, | ||
21 | sun4e = 0x04, | ||
22 | sun4u = 0x05, /* V8 ploos ploos */ | ||
23 | sun_unknown = 0x06, | ||
24 | ap1000 = 0x07, /* almost a sun4m */ | ||
25 | }; | ||
26 | |||
27 | #define sparc_cpu_model sun4u | ||
28 | |||
29 | /* This cannot ever be a sun4c :) That's just history. */ | ||
30 | #define ARCH_SUN4C 0 | ||
31 | |||
32 | extern char reboot_command[]; | ||
33 | |||
34 | /* These are here in an effort to more fully work around Spitfire Errata | ||
35 | * #51. Essentially, if a memory barrier occurs soon after a mispredicted | ||
36 | * branch, the chip can stop executing instructions until a trap occurs. | ||
37 | * Therefore, if interrupts are disabled, the chip can hang forever. | ||
38 | * | ||
39 | * It used to be believed that the memory barrier had to be right in the | ||
40 | * delay slot, but a case has been traced recently wherein the memory barrier | ||
41 | * was one instruction after the branch delay slot and the chip still hung. | ||
42 | * The offending sequence was the following in sym_wakeup_done() of the | ||
43 | * sym53c8xx_2 driver: | ||
44 | * | ||
45 | * call sym_ccb_from_dsa, 0 | ||
46 | * movge %icc, 0, %l0 | ||
47 | * brz,pn %o0, .LL1303 | ||
48 | * mov %o0, %l2 | ||
49 | * membar #LoadLoad | ||
50 | * | ||
51 | * The branch has to be mispredicted for the bug to occur. Therefore, we put | ||
52 | * the memory barrier explicitly into a "branch always, predicted taken" | ||
53 | * delay slot to avoid the problem case. | ||
54 | */ | ||
55 | #define membar_safe(type) \ | ||
56 | do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ | ||
57 | " membar " type "\n" \ | ||
58 | "1:\n" \ | ||
59 | : : : "memory"); \ | ||
60 | } while (0) | ||
61 | |||
62 | /* The kernel always executes in TSO memory model these days, | ||
63 | * and furthermore most sparc64 chips implement more stringent | ||
64 | * memory ordering than required by the specifications. | ||
65 | */ | ||
66 | #define mb() membar_safe("#StoreLoad") | ||
67 | #define rmb() __asm__ __volatile__("":::"memory") | ||
68 | #define wmb() __asm__ __volatile__("":::"memory") | ||
69 | |||
70 | #endif | ||
71 | |||
72 | #define nop() __asm__ __volatile__ ("nop") | ||
73 | |||
74 | #define read_barrier_depends() do { } while(0) | ||
75 | #define set_mb(__var, __value) \ | ||
76 | do { __var = __value; membar_safe("#StoreLoad"); } while(0) | ||
77 | |||
78 | #ifdef CONFIG_SMP | ||
79 | #define smp_mb() mb() | ||
80 | #define smp_rmb() rmb() | ||
81 | #define smp_wmb() wmb() | ||
82 | #else | ||
83 | #define smp_mb() __asm__ __volatile__("":::"memory") | ||
84 | #define smp_rmb() __asm__ __volatile__("":::"memory") | ||
85 | #define smp_wmb() __asm__ __volatile__("":::"memory") | ||
86 | #endif | ||
87 | |||
88 | #define smp_read_barrier_depends() do { } while(0) | ||
89 | |||
90 | #define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") | ||
91 | |||
92 | #define flushw_all() __asm__ __volatile__("flushw") | ||
93 | |||
94 | /* Performance counter register access. */ | ||
95 | #define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p)) | ||
96 | #define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)) | ||
97 | #define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) | ||
98 | |||
99 | /* Blackbird errata workaround. See commentary in | ||
100 | * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() | ||
101 | * for more information. | ||
102 | */ | ||
103 | #define write_pic(__p) \ | ||
104 | __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ | ||
105 | " nop\n\t" \ | ||
106 | ".align 64\n" \ | ||
107 | "99:wr %0, 0x0, %%pic\n\t" \ | ||
108 | "rd %%pic, %%g0" : : "r" (__p)) | ||
109 | #define reset_pic() write_pic(0) | ||
110 | |||
111 | #ifndef __ASSEMBLY__ | ||
112 | |||
113 | extern void sun_do_break(void); | ||
114 | extern int stop_a_enabled; | ||
115 | extern int scons_pwroff; | ||
116 | |||
117 | extern void fault_in_user_windows(void); | ||
118 | extern void synchronize_user_stack(void); | ||
119 | |||
120 | extern void __flushw_user(void); | ||
121 | #define flushw_user() __flushw_user() | ||
122 | |||
123 | #define flush_user_windows flushw_user | ||
124 | #define flush_register_windows flushw_all | ||
125 | |||
126 | /* Don't hold the runqueue lock over context switch */ | ||
127 | #define __ARCH_WANT_UNLOCKED_CTXSW | ||
128 | #define prepare_arch_switch(next) \ | ||
129 | do { \ | ||
130 | flushw_all(); \ | ||
131 | } while (0) | ||
132 | |||
133 | /* See what happens when you design the chip correctly? | ||
134 | * | ||
135 | * We tell gcc we clobber all non-fixed-usage registers except | ||
136 | * for l0/l1. It will use one for 'next' and the other to hold | ||
137 | * the output value of 'last'. 'next' is not referenced again | ||
138 | * past the invocation of switch_to in the scheduler, so we need | ||
139 | * not preserve it's value. Hairy, but it lets us remove 2 loads | ||
140 | * and 2 stores in this critical code path. -DaveM | ||
141 | */ | ||
142 | #define switch_to(prev, next, last) \ | ||
143 | do { flush_tlb_pending(); \ | ||
144 | save_and_clear_fpu(); \ | ||
145 | /* If you are tempted to conditionalize the following */ \ | ||
146 | /* so that ASI is only written if it changes, think again. */ \ | ||
147 | __asm__ __volatile__("wr %%g0, %0, %%asi" \ | ||
148 | : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ | ||
149 | trap_block[current_thread_info()->cpu].thread = \ | ||
150 | task_thread_info(next); \ | ||
151 | __asm__ __volatile__( \ | ||
152 | "mov %%g4, %%g7\n\t" \ | ||
153 | "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ | ||
154 | "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ | ||
155 | "rdpr %%wstate, %%o5\n\t" \ | ||
156 | "stx %%o6, [%%g6 + %6]\n\t" \ | ||
157 | "stb %%o5, [%%g6 + %5]\n\t" \ | ||
158 | "rdpr %%cwp, %%o5\n\t" \ | ||
159 | "stb %%o5, [%%g6 + %8]\n\t" \ | ||
160 | "wrpr %%g0, 15, %%pil\n\t" \ | ||
161 | "mov %4, %%g6\n\t" \ | ||
162 | "ldub [%4 + %8], %%g1\n\t" \ | ||
163 | "wrpr %%g1, %%cwp\n\t" \ | ||
164 | "ldx [%%g6 + %6], %%o6\n\t" \ | ||
165 | "ldub [%%g6 + %5], %%o5\n\t" \ | ||
166 | "ldub [%%g6 + %7], %%o7\n\t" \ | ||
167 | "wrpr %%o5, 0x0, %%wstate\n\t" \ | ||
168 | "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ | ||
169 | "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ | ||
170 | "ldx [%%g6 + %9], %%g4\n\t" \ | ||
171 | "wrpr %%g0, 14, %%pil\n\t" \ | ||
172 | "brz,pt %%o7, switch_to_pc\n\t" \ | ||
173 | " mov %%g7, %0\n\t" \ | ||
174 | "sethi %%hi(ret_from_syscall), %%g1\n\t" \ | ||
175 | "jmpl %%g1 + %%lo(ret_from_syscall), %%g0\n\t" \ | ||
176 | " nop\n\t" \ | ||
177 | ".globl switch_to_pc\n\t" \ | ||
178 | "switch_to_pc:\n\t" \ | ||
179 | : "=&r" (last), "=r" (current), "=r" (current_thread_info_reg), \ | ||
180 | "=r" (__local_per_cpu_offset) \ | ||
181 | : "0" (task_thread_info(next)), \ | ||
182 | "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_NEW_CHILD), \ | ||
183 | "i" (TI_CWP), "i" (TI_TASK) \ | ||
184 | : "cc", \ | ||
185 | "g1", "g2", "g3", "g7", \ | ||
186 | "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ | ||
187 | "i0", "i1", "i2", "i3", "i4", "i5", \ | ||
188 | "o0", "o1", "o2", "o3", "o4", "o5", "o7"); \ | ||
189 | } while(0) | ||
190 | |||
191 | static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) | ||
192 | { | ||
193 | unsigned long tmp1, tmp2; | ||
194 | |||
195 | __asm__ __volatile__( | ||
196 | " mov %0, %1\n" | ||
197 | "1: lduw [%4], %2\n" | ||
198 | " cas [%4], %2, %0\n" | ||
199 | " cmp %2, %0\n" | ||
200 | " bne,a,pn %%icc, 1b\n" | ||
201 | " mov %1, %0\n" | ||
202 | : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) | ||
203 | : "0" (val), "r" (m) | ||
204 | : "cc", "memory"); | ||
205 | return val; | ||
206 | } | ||
207 | |||
208 | static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val) | ||
209 | { | ||
210 | unsigned long tmp1, tmp2; | ||
211 | |||
212 | __asm__ __volatile__( | ||
213 | " mov %0, %1\n" | ||
214 | "1: ldx [%4], %2\n" | ||
215 | " casx [%4], %2, %0\n" | ||
216 | " cmp %2, %0\n" | ||
217 | " bne,a,pn %%xcc, 1b\n" | ||
218 | " mov %1, %0\n" | ||
219 | : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) | ||
220 | : "0" (val), "r" (m) | ||
221 | : "cc", "memory"); | ||
222 | return val; | ||
223 | } | ||
224 | |||
225 | #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | ||
226 | |||
227 | extern void __xchg_called_with_bad_pointer(void); | ||
228 | |||
229 | static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, | ||
230 | int size) | ||
231 | { | ||
232 | switch (size) { | ||
233 | case 4: | ||
234 | return xchg32(ptr, x); | ||
235 | case 8: | ||
236 | return xchg64(ptr, x); | ||
237 | } | ||
238 | __xchg_called_with_bad_pointer(); | ||
239 | return x; | ||
240 | } | ||
241 | |||
242 | extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); | ||
243 | |||
244 | /* | ||
245 | * Atomic compare and exchange. Compare OLD with MEM, if identical, | ||
246 | * store NEW in MEM. Return the initial value in MEM. Success is | ||
247 | * indicated by comparing RETURN with OLD. | ||
248 | */ | ||
249 | |||
250 | #define __HAVE_ARCH_CMPXCHG 1 | ||
251 | |||
252 | static inline unsigned long | ||
253 | __cmpxchg_u32(volatile int *m, int old, int new) | ||
254 | { | ||
255 | __asm__ __volatile__("cas [%2], %3, %0" | ||
256 | : "=&r" (new) | ||
257 | : "0" (new), "r" (m), "r" (old) | ||
258 | : "memory"); | ||
259 | |||
260 | return new; | ||
261 | } | ||
262 | |||
263 | static inline unsigned long | ||
264 | __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) | ||
265 | { | ||
266 | __asm__ __volatile__("casx [%2], %3, %0" | ||
267 | : "=&r" (new) | ||
268 | : "0" (new), "r" (m), "r" (old) | ||
269 | : "memory"); | ||
270 | |||
271 | return new; | ||
272 | } | ||
273 | |||
274 | /* This function doesn't exist, so you'll get a linker error | ||
275 | if something tries to do an invalid cmpxchg(). */ | ||
276 | extern void __cmpxchg_called_with_bad_pointer(void); | ||
277 | |||
278 | static inline unsigned long | ||
279 | __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | ||
280 | { | ||
281 | switch (size) { | ||
282 | case 4: | ||
283 | return __cmpxchg_u32(ptr, old, new); | ||
284 | case 8: | ||
285 | return __cmpxchg_u64(ptr, old, new); | ||
286 | } | ||
287 | __cmpxchg_called_with_bad_pointer(); | ||
288 | return old; | ||
289 | } | ||
290 | |||
291 | #define cmpxchg(ptr,o,n) \ | ||
292 | ({ \ | ||
293 | __typeof__(*(ptr)) _o_ = (o); \ | ||
294 | __typeof__(*(ptr)) _n_ = (n); \ | ||
295 | (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ | ||
296 | (unsigned long)_n_, sizeof(*(ptr))); \ | ||
297 | }) | ||
298 | |||
299 | /* | ||
300 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
301 | * them available. | ||
302 | */ | ||
303 | |||
304 | static inline unsigned long __cmpxchg_local(volatile void *ptr, | ||
305 | unsigned long old, | ||
306 | unsigned long new, int size) | ||
307 | { | ||
308 | switch (size) { | ||
309 | case 4: | ||
310 | case 8: return __cmpxchg(ptr, old, new, size); | ||
311 | default: | ||
312 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
313 | } | ||
314 | |||
315 | return old; | ||
316 | } | ||
317 | |||
318 | #define cmpxchg_local(ptr, o, n) \ | ||
319 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ | ||
320 | (unsigned long)(n), sizeof(*(ptr)))) | ||
321 | #define cmpxchg64_local(ptr, o, n) \ | ||
322 | ({ \ | ||
323 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
324 | cmpxchg_local((ptr), (o), (n)); \ | ||
325 | }) | ||
326 | |||
327 | #endif /* !(__ASSEMBLY__) */ | ||
328 | |||
329 | #define arch_align_stack(x) (x) | ||
330 | |||
331 | #endif /* !(__SPARC64_SYSTEM_H) */ | ||
diff --git a/arch/sparc/include/asm/types.h b/arch/sparc/include/asm/types.h new file mode 100644 index 00000000000..91e5a034f98 --- /dev/null +++ b/arch/sparc/include/asm/types.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef _SPARC_TYPES_H | ||
2 | #define _SPARC_TYPES_H | ||
3 | /* | ||
4 | * This file is never included by application software unless | ||
5 | * explicitly requested (e.g., via linux/types.h) in which case the | ||
6 | * application is Linux specific so (user-) name space pollution is | ||
7 | * not a major issue. However, for interoperability, libraries still | ||
8 | * need to be careful to avoid a name clashes. | ||
9 | */ | ||
10 | |||
11 | #if defined(__sparc__) | ||
12 | |||
13 | #include <asm-generic/int-ll64.h> | ||
14 | |||
15 | #ifndef __ASSEMBLY__ | ||
16 | |||
17 | typedef unsigned short umode_t; | ||
18 | |||
19 | #endif /* __ASSEMBLY__ */ | ||
20 | |||
21 | #endif /* defined(__sparc__) */ | ||
22 | |||
23 | #endif /* defined(_SPARC_TYPES_H) */ | ||
diff --git a/arch/sparc/include/asm/uctx.h b/arch/sparc/include/asm/uctx.h new file mode 100644 index 00000000000..dc937c75ffd --- /dev/null +++ b/arch/sparc/include/asm/uctx.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * uctx.h: Sparc64 {set,get}context() register state layouts. | ||
3 | * | ||
4 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | ||
5 | */ | ||
6 | |||
7 | #ifndef __SPARC64_UCTX_H | ||
8 | #define __SPARC64_UCTX_H | ||
9 | |||
10 | #define MC_TSTATE 0 | ||
11 | #define MC_PC 1 | ||
12 | #define MC_NPC 2 | ||
13 | #define MC_Y 3 | ||
14 | #define MC_G1 4 | ||
15 | #define MC_G2 5 | ||
16 | #define MC_G3 6 | ||
17 | #define MC_G4 7 | ||
18 | #define MC_G5 8 | ||
19 | #define MC_G6 9 | ||
20 | #define MC_G7 10 | ||
21 | #define MC_O0 11 | ||
22 | #define MC_O1 12 | ||
23 | #define MC_O2 13 | ||
24 | #define MC_O3 14 | ||
25 | #define MC_O4 15 | ||
26 | #define MC_O5 16 | ||
27 | #define MC_O6 17 | ||
28 | #define MC_O7 18 | ||
29 | #define MC_NGREG 19 | ||
30 | |||
31 | typedef unsigned long mc_greg_t; | ||
32 | typedef mc_greg_t mc_gregset_t[MC_NGREG]; | ||
33 | |||
34 | #define MC_MAXFPQ 16 | ||
35 | struct mc_fq { | ||
36 | unsigned long *mcfq_addr; | ||
37 | unsigned int mcfq_insn; | ||
38 | }; | ||
39 | |||
40 | struct mc_fpu { | ||
41 | union { | ||
42 | unsigned int sregs[32]; | ||
43 | unsigned long dregs[32]; | ||
44 | long double qregs[16]; | ||
45 | } mcfpu_fregs; | ||
46 | unsigned long mcfpu_fsr; | ||
47 | unsigned long mcfpu_fprs; | ||
48 | unsigned long mcfpu_gsr; | ||
49 | struct mc_fq *mcfpu_fq; | ||
50 | unsigned char mcfpu_qcnt; | ||
51 | unsigned char mcfpu_qentsz; | ||
52 | unsigned char mcfpu_enab; | ||
53 | }; | ||
54 | typedef struct mc_fpu mc_fpu_t; | ||
55 | |||
56 | typedef struct { | ||
57 | mc_gregset_t mc_gregs; | ||
58 | mc_greg_t mc_fp; | ||
59 | mc_greg_t mc_i7; | ||
60 | mc_fpu_t mc_fpregs; | ||
61 | } mcontext_t; | ||
62 | |||
63 | struct ucontext { | ||
64 | struct ucontext *uc_link; | ||
65 | unsigned long uc_flags; | ||
66 | sigset_t uc_sigmask; | ||
67 | mcontext_t uc_mcontext; | ||
68 | }; | ||
69 | typedef struct ucontext ucontext_t; | ||
70 | |||
71 | #endif /* __SPARC64_UCTX_H */ | ||
diff --git a/arch/sparc/include/asm/utrap.h b/arch/sparc/include/asm/utrap.h new file mode 100644 index 00000000000..b10e527c22d --- /dev/null +++ b/arch/sparc/include/asm/utrap.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * include/asm/utrap.h | ||
3 | * | ||
4 | * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
5 | */ | ||
6 | |||
7 | #ifndef __ASM_SPARC64_UTRAP_H | ||
8 | #define __ASM_SPARC64_UTRAP_H | ||
9 | |||
10 | #define UT_INSTRUCTION_EXCEPTION 1 | ||
11 | #define UT_INSTRUCTION_ERROR 2 | ||
12 | #define UT_INSTRUCTION_PROTECTION 3 | ||
13 | #define UT_ILLTRAP_INSTRUCTION 4 | ||
14 | #define UT_ILLEGAL_INSTRUCTION 5 | ||
15 | #define UT_PRIVILEGED_OPCODE 6 | ||
16 | #define UT_FP_DISABLED 7 | ||
17 | #define UT_FP_EXCEPTION_IEEE_754 8 | ||
18 | #define UT_FP_EXCEPTION_OTHER 9 | ||
19 | #define UT_TAG_OVERVIEW 10 | ||
20 | #define UT_DIVISION_BY_ZERO 11 | ||
21 | #define UT_DATA_EXCEPTION 12 | ||
22 | #define UT_DATA_ERROR 13 | ||
23 | #define UT_DATA_PROTECTION 14 | ||
24 | #define UT_MEM_ADDRESS_NOT_ALIGNED 15 | ||
25 | #define UT_PRIVILEGED_ACTION 16 | ||
26 | #define UT_ASYNC_DATA_ERROR 17 | ||
27 | #define UT_TRAP_INSTRUCTION_16 18 | ||
28 | #define UT_TRAP_INSTRUCTION_17 19 | ||
29 | #define UT_TRAP_INSTRUCTION_18 20 | ||
30 | #define UT_TRAP_INSTRUCTION_19 21 | ||
31 | #define UT_TRAP_INSTRUCTION_20 22 | ||
32 | #define UT_TRAP_INSTRUCTION_21 23 | ||
33 | #define UT_TRAP_INSTRUCTION_22 24 | ||
34 | #define UT_TRAP_INSTRUCTION_23 25 | ||
35 | #define UT_TRAP_INSTRUCTION_24 26 | ||
36 | #define UT_TRAP_INSTRUCTION_25 27 | ||
37 | #define UT_TRAP_INSTRUCTION_26 28 | ||
38 | #define UT_TRAP_INSTRUCTION_27 29 | ||
39 | #define UT_TRAP_INSTRUCTION_28 30 | ||
40 | #define UT_TRAP_INSTRUCTION_29 31 | ||
41 | #define UT_TRAP_INSTRUCTION_30 32 | ||
42 | #define UT_TRAP_INSTRUCTION_31 33 | ||
43 | |||
44 | #define UTH_NOCHANGE (-1) | ||
45 | |||
46 | #ifndef __ASSEMBLY__ | ||
47 | typedef int utrap_entry_t; | ||
48 | typedef void *utrap_handler_t; | ||
49 | #endif /* __ASSEMBLY__ */ | ||
50 | |||
51 | #endif /* !(__ASM_SPARC64_PROCESSOR_H) */ | ||
diff --git a/arch/sparc/include/asm/vac-ops.h b/arch/sparc/include/asm/vac-ops.h new file mode 100644 index 00000000000..a63e88ef042 --- /dev/null +++ b/arch/sparc/include/asm/vac-ops.h | |||
@@ -0,0 +1,127 @@ | |||
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/watchdog.h b/arch/sparc/include/asm/watchdog.h new file mode 100644 index 00000000000..5baf2d3919c --- /dev/null +++ b/arch/sparc/include/asm/watchdog.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * | ||
3 | * watchdog - Driver interface for the hardware watchdog timers | ||
4 | * present on Sun Microsystems boardsets | ||
5 | * | ||
6 | * Copyright (c) 2000 Eric Brower <ebrower@usa.net> | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #ifndef _SPARC64_WATCHDOG_H | ||
11 | #define _SPARC64_WATCHDOG_H | ||
12 | |||
13 | #include <linux/watchdog.h> | ||
14 | |||
15 | /* Solaris compatibility ioctls-- | ||
16 | * Ref. <linux/watchdog.h> for standard linux watchdog ioctls | ||
17 | */ | ||
18 | #define WIOCSTART _IO (WATCHDOG_IOCTL_BASE, 10) /* Start Timer */ | ||
19 | #define WIOCSTOP _IO (WATCHDOG_IOCTL_BASE, 11) /* Stop Timer */ | ||
20 | #define WIOCGSTAT _IOR(WATCHDOG_IOCTL_BASE, 12, int)/* Get Timer Status */ | ||
21 | |||
22 | /* Status flags from WIOCGSTAT ioctl | ||
23 | */ | ||
24 | #define WD_FREERUN 0x01 /* timer is running, interrupts disabled */ | ||
25 | #define WD_EXPIRED 0x02 /* timer has expired */ | ||
26 | #define WD_RUNNING 0x04 /* timer is running, interrupts enabled */ | ||
27 | #define WD_STOPPED 0x08 /* timer has not been started */ | ||
28 | #define WD_SERVICED 0x10 /* timer interrupt was serviced */ | ||
29 | |||
30 | #endif /* ifndef _SPARC64_WATCHDOG_H */ | ||
31 | |||
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c new file mode 100644 index 00000000000..35f141a9f50 --- /dev/null +++ b/arch/sparc/kernel/init_task.c | |||
@@ -0,0 +1,22 @@ | |||
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/muldiv.c b/arch/sparc/kernel/muldiv.c new file mode 100644 index 00000000000..6ce1021d487 --- /dev/null +++ b/arch/sparc/kernel/muldiv.c | |||
@@ -0,0 +1,239 @@ | |||
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/system.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | |||
20 | #include "kernel.h" | ||
21 | |||
22 | /* #define DEBUG_MULDIV */ | ||
23 | |||
24 | static inline int has_imm13(int insn) | ||
25 | { | ||
26 | return (insn & 0x2000); | ||
27 | } | ||
28 | |||
29 | static inline int is_foocc(int insn) | ||
30 | { | ||
31 | return (insn & 0x800000); | ||
32 | } | ||
33 | |||
34 | static inline int sign_extend_imm13(int imm) | ||
35 | { | ||
36 | return imm << 19 >> 19; | ||
37 | } | ||
38 | |||
39 | static inline void advance(struct pt_regs *regs) | ||
40 | { | ||
41 | regs->pc = regs->npc; | ||
42 | regs->npc += 4; | ||
43 | } | ||
44 | |||
45 | static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, | ||
46 | unsigned int rd) | ||
47 | { | ||
48 | if(rs2 >= 16 || rs1 >= 16 || rd >= 16) { | ||
49 | /* Wheee... */ | ||
50 | __asm__ __volatile__("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 | "save %sp, -0x40, %sp\n\t" | ||
57 | "restore; restore; restore; restore;\n\t" | ||
58 | "restore; restore; restore;\n\t"); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | #define fetch_reg(reg, regs) ({ \ | ||
63 | struct reg_window32 __user *win; \ | ||
64 | register unsigned long ret; \ | ||
65 | \ | ||
66 | if (!(reg)) ret = 0; \ | ||
67 | else if ((reg) < 16) { \ | ||
68 | ret = regs->u_regs[(reg)]; \ | ||
69 | } else { \ | ||
70 | /* Ho hum, the slightly complicated case. */ \ | ||
71 | win = (struct reg_window32 __user *)regs->u_regs[UREG_FP];\ | ||
72 | if (get_user (ret, &win->locals[(reg) - 16])) return -1;\ | ||
73 | } \ | ||
74 | ret; \ | ||
75 | }) | ||
76 | |||
77 | static inline int | ||
78 | store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs) | ||
79 | { | ||
80 | struct reg_window32 __user *win; | ||
81 | |||
82 | if (!reg) | ||
83 | return 0; | ||
84 | if (reg < 16) { | ||
85 | regs->u_regs[reg] = result; | ||
86 | return 0; | ||
87 | } else { | ||
88 | /* need to use put_user() in this case: */ | ||
89 | win = (struct reg_window32 __user *) regs->u_regs[UREG_FP]; | ||
90 | return (put_user(result, &win->locals[reg - 16])); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | /* Should return 0 if mul/div emulation succeeded and SIGILL should | ||
95 | * not be issued. | ||
96 | */ | ||
97 | int do_user_muldiv(struct pt_regs *regs, unsigned long pc) | ||
98 | { | ||
99 | unsigned int insn; | ||
100 | int inst; | ||
101 | unsigned int rs1, rs2, rdv; | ||
102 | |||
103 | if (!pc) | ||
104 | return -1; /* This happens to often, I think */ | ||
105 | if (get_user (insn, (unsigned int __user *)pc)) | ||
106 | return -1; | ||
107 | if ((insn & 0xc1400000) != 0x80400000) | ||
108 | return -1; | ||
109 | inst = ((insn >> 19) & 0xf); | ||
110 | if ((inst & 0xe) != 10 && (inst & 0xe) != 14) | ||
111 | return -1; | ||
112 | |||
113 | /* Now we know we have to do something with umul, smul, udiv or sdiv */ | ||
114 | rs1 = (insn >> 14) & 0x1f; | ||
115 | rs2 = insn & 0x1f; | ||
116 | rdv = (insn >> 25) & 0x1f; | ||
117 | if (has_imm13(insn)) { | ||
118 | maybe_flush_windows(rs1, 0, rdv); | ||
119 | rs2 = sign_extend_imm13(insn); | ||
120 | } else { | ||
121 | maybe_flush_windows(rs1, rs2, rdv); | ||
122 | rs2 = fetch_reg(rs2, regs); | ||
123 | } | ||
124 | rs1 = fetch_reg(rs1, regs); | ||
125 | switch (inst) { | ||
126 | case 10: /* umul */ | ||
127 | #ifdef DEBUG_MULDIV | ||
128 | printk ("unsigned muldiv: 0x%x * 0x%x = ", rs1, rs2); | ||
129 | #endif | ||
130 | __asm__ __volatile__ ("\n\t" | ||
131 | "mov %0, %%o0\n\t" | ||
132 | "call .umul\n\t" | ||
133 | " mov %1, %%o1\n\t" | ||
134 | "mov %%o0, %0\n\t" | ||
135 | "mov %%o1, %1\n\t" | ||
136 | : "=r" (rs1), "=r" (rs2) | ||
137 | : "0" (rs1), "1" (rs2) | ||
138 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); | ||
139 | #ifdef DEBUG_MULDIV | ||
140 | printk ("0x%x%08x\n", rs2, rs1); | ||
141 | #endif | ||
142 | if (store_reg(rs1, rdv, regs)) | ||
143 | return -1; | ||
144 | regs->y = rs2; | ||
145 | break; | ||
146 | case 11: /* smul */ | ||
147 | #ifdef DEBUG_MULDIV | ||
148 | printk ("signed muldiv: 0x%x * 0x%x = ", rs1, rs2); | ||
149 | #endif | ||
150 | __asm__ __volatile__ ("\n\t" | ||
151 | "mov %0, %%o0\n\t" | ||
152 | "call .mul\n\t" | ||
153 | " mov %1, %%o1\n\t" | ||
154 | "mov %%o0, %0\n\t" | ||
155 | "mov %%o1, %1\n\t" | ||
156 | : "=r" (rs1), "=r" (rs2) | ||
157 | : "0" (rs1), "1" (rs2) | ||
158 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); | ||
159 | #ifdef DEBUG_MULDIV | ||
160 | printk ("0x%x%08x\n", rs2, rs1); | ||
161 | #endif | ||
162 | if (store_reg(rs1, rdv, regs)) | ||
163 | return -1; | ||
164 | regs->y = rs2; | ||
165 | break; | ||
166 | case 14: /* udiv */ | ||
167 | #ifdef DEBUG_MULDIV | ||
168 | printk ("unsigned muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); | ||
169 | #endif | ||
170 | if (!rs2) { | ||
171 | #ifdef DEBUG_MULDIV | ||
172 | printk ("DIVISION BY ZERO\n"); | ||
173 | #endif | ||
174 | handle_hw_divzero (regs, pc, regs->npc, regs->psr); | ||
175 | return 0; | ||
176 | } | ||
177 | __asm__ __volatile__ ("\n\t" | ||
178 | "mov %2, %%o0\n\t" | ||
179 | "mov %0, %%o1\n\t" | ||
180 | "mov %%g0, %%o2\n\t" | ||
181 | "call __udivdi3\n\t" | ||
182 | " mov %1, %%o3\n\t" | ||
183 | "mov %%o1, %0\n\t" | ||
184 | "mov %%o0, %1\n\t" | ||
185 | : "=r" (rs1), "=r" (rs2) | ||
186 | : "r" (regs->y), "0" (rs1), "1" (rs2) | ||
187 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", | ||
188 | "g1", "g2", "g3", "cc"); | ||
189 | #ifdef DEBUG_MULDIV | ||
190 | printk ("0x%x\n", rs1); | ||
191 | #endif | ||
192 | if (store_reg(rs1, rdv, regs)) | ||
193 | return -1; | ||
194 | break; | ||
195 | case 15: /* sdiv */ | ||
196 | #ifdef DEBUG_MULDIV | ||
197 | printk ("signed muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); | ||
198 | #endif | ||
199 | if (!rs2) { | ||
200 | #ifdef DEBUG_MULDIV | ||
201 | printk ("DIVISION BY ZERO\n"); | ||
202 | #endif | ||
203 | handle_hw_divzero (regs, pc, regs->npc, regs->psr); | ||
204 | return 0; | ||
205 | } | ||
206 | __asm__ __volatile__ ("\n\t" | ||
207 | "mov %2, %%o0\n\t" | ||
208 | "mov %0, %%o1\n\t" | ||
209 | "mov %%g0, %%o2\n\t" | ||
210 | "call __divdi3\n\t" | ||
211 | " mov %1, %%o3\n\t" | ||
212 | "mov %%o1, %0\n\t" | ||
213 | "mov %%o0, %1\n\t" | ||
214 | : "=r" (rs1), "=r" (rs2) | ||
215 | : "r" (regs->y), "0" (rs1), "1" (rs2) | ||
216 | : "o0", "o1", "o2", "o3", "o4", "o5", "o7", | ||
217 | "g1", "g2", "g3", "cc"); | ||
218 | #ifdef DEBUG_MULDIV | ||
219 | printk ("0x%x\n", rs1); | ||
220 | #endif | ||
221 | if (store_reg(rs1, rdv, regs)) | ||
222 | return -1; | ||
223 | break; | ||
224 | } | ||
225 | if (is_foocc (insn)) { | ||
226 | regs->psr &= ~PSR_ICC; | ||
227 | if ((inst & 0xe) == 14) { | ||
228 | /* ?div */ | ||
229 | if (rs2) regs->psr |= PSR_V; | ||
230 | } | ||
231 | if (!rs1) regs->psr |= PSR_Z; | ||
232 | if (((int)rs1) < 0) regs->psr |= PSR_N; | ||
233 | #ifdef DEBUG_MULDIV | ||
234 | printk ("psr muldiv: %08x\n", regs->psr); | ||
235 | #endif | ||
236 | } | ||
237 | advance(regs); | ||
238 | return 0; | ||
239 | } | ||
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c new file mode 100644 index 00000000000..f6bf25a2ff8 --- /dev/null +++ b/arch/sparc/kernel/sun4c_irq.c | |||
@@ -0,0 +1,264 @@ | |||
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/ttable.S b/arch/sparc/kernel/ttable.S new file mode 100644 index 00000000000..c6dfdaa29e2 --- /dev/null +++ b/arch/sparc/kernel/ttable.S | |||
@@ -0,0 +1,272 @@ | |||
1 | /* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah/SUN4V extensions. | ||
2 | * | ||
3 | * Copyright (C) 1996, 2001, 2006 David S. Miller (davem@davemloft.net) | ||
4 | */ | ||
5 | |||
6 | |||
7 | .globl sparc64_ttable_tl0, sparc64_ttable_tl1 | ||
8 | .globl tl0_icpe, tl1_icpe | ||
9 | .globl tl0_dcpe, tl1_dcpe | ||
10 | .globl tl0_fecc, tl1_fecc | ||
11 | .globl tl0_cee, tl1_cee | ||
12 | .globl tl0_iae, tl1_iae | ||
13 | .globl tl0_dae, tl1_dae | ||
14 | |||
15 | sparc64_ttable_tl0: | ||
16 | tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) | ||
17 | tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) | ||
18 | tl0_iax: membar #Sync | ||
19 | TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception) | ||
20 | tl0_itsb_4v: SUN4V_ITSB_MISS | ||
21 | tl0_iae: membar #Sync | ||
22 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | ||
23 | tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) | ||
24 | tl0_ill: membar #Sync | ||
25 | TRAP_7INSNS(do_illegal_instruction) | ||
26 | tl0_privop: TRAP(do_privop) | ||
27 | tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17) | ||
28 | tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) | ||
29 | tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f) | ||
30 | tl0_fpdis: TRAP_NOSAVE(do_fpdis) | ||
31 | tl0_fpieee: TRAP_SAVEFPU(do_fpieee) | ||
32 | tl0_fpother: TRAP_NOSAVE(do_fpother_check_fitos) | ||
33 | tl0_tof: TRAP(do_tof) | ||
34 | tl0_cwin: CLEAN_WINDOW | ||
35 | tl0_div0: TRAP(do_div0) | ||
36 | tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) | ||
37 | tl0_resv02f: BTRAP(0x2f) | ||
38 | tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception) | ||
39 | tl0_dtsb_4v: SUN4V_DTSB_MISS | ||
40 | tl0_dae: membar #Sync | ||
41 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | ||
42 | tl0_resv033: BTRAP(0x33) | ||
43 | tl0_mna: TRAP_NOSAVE(do_mna) | ||
44 | tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) | ||
45 | tl0_stdfmna: TRAP_NOSAVE(do_stdfmna) | ||
46 | tl0_privact: TRAP_NOSAVE(__do_privact) | ||
47 | tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) | ||
48 | tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) | ||
49 | #ifdef CONFIG_SMP | ||
50 | tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) | ||
51 | tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) | ||
52 | tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) | ||
53 | tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4) | ||
54 | #else | ||
55 | tl0_irq1: BTRAP(0x41) | ||
56 | tl0_irq2: BTRAP(0x42) | ||
57 | tl0_irq3: BTRAP(0x43) | ||
58 | tl0_irq4: BTRAP(0x44) | ||
59 | #endif | ||
60 | tl0_irq5: TRAP_IRQ(handler_irq, 5) | ||
61 | #ifdef CONFIG_SMP | ||
62 | tl0_irq6: TRAP_IRQ(smp_call_function_single_client, 6) | ||
63 | #else | ||
64 | tl0_irq6: BTRAP(0x46) | ||
65 | #endif | ||
66 | tl0_irq7: TRAP_IRQ(deferred_pcr_work_irq, 7) | ||
67 | #if defined(CONFIG_KGDB) && defined(CONFIG_SMP) | ||
68 | tl0_irq8: TRAP_IRQ(smp_kgdb_capture_client, 8) | ||
69 | #else | ||
70 | tl0_irq8: BTRAP(0x48) | ||
71 | #endif | ||
72 | tl0_irq9: BTRAP(0x49) | ||
73 | tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) | ||
74 | tl0_irq14: TRAP_IRQ(timer_interrupt, 14) | ||
75 | tl0_irq15: TRAP_NMI_IRQ(perfctr_irq, 15) | ||
76 | tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) | ||
77 | tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) | ||
78 | tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) | ||
79 | tl0_ivec: TRAP_IVEC | ||
80 | tl0_paw: TRAP(do_paw) | ||
81 | tl0_vaw: TRAP(do_vaw) | ||
82 | tl0_cee: membar #Sync | ||
83 | TRAP_NOSAVE_7INSNS(__spitfire_cee_trap) | ||
84 | tl0_iamiss: | ||
85 | #include "itlb_miss.S" | ||
86 | tl0_damiss: | ||
87 | #include "dtlb_miss.S" | ||
88 | tl0_daprot: | ||
89 | #include "dtlb_prot.S" | ||
90 | tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ | ||
91 | tl0_dcpe: BTRAP(0x71) /* D-cache Parity Error on Cheetah+ */ | ||
92 | tl0_icpe: BTRAP(0x72) /* I-cache Parity Error on Cheetah+ */ | ||
93 | tl0_resv073: BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) | ||
94 | tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) | ||
95 | tl0_cpu_mondo: TRAP_NOSAVE(sun4v_cpu_mondo) | ||
96 | tl0_dev_mondo: TRAP_NOSAVE(sun4v_dev_mondo) | ||
97 | tl0_res_mondo: TRAP_NOSAVE(sun4v_res_mondo) | ||
98 | tl0_nres_mondo: TRAP_NOSAVE(sun4v_nonres_mondo) | ||
99 | tl0_s0n: SPILL_0_NORMAL | ||
100 | tl0_s1n: SPILL_1_NORMAL | ||
101 | tl0_s2n: SPILL_2_NORMAL | ||
102 | tl0_s3n: SPILL_0_NORMAL_ETRAP | ||
103 | tl0_s4n: SPILL_1_GENERIC_ETRAP | ||
104 | tl0_s5n: SPILL_1_GENERIC_ETRAP_FIXUP | ||
105 | tl0_s6n: SPILL_2_GENERIC_ETRAP | ||
106 | tl0_s7n: SPILL_2_GENERIC_ETRAP_FIXUP | ||
107 | tl0_s0o: SPILL_0_OTHER | ||
108 | tl0_s1o: SPILL_1_OTHER | ||
109 | tl0_s2o: SPILL_2_OTHER | ||
110 | tl0_s3o: SPILL_3_OTHER | ||
111 | tl0_s4o: SPILL_4_OTHER | ||
112 | tl0_s5o: SPILL_5_OTHER | ||
113 | tl0_s6o: SPILL_6_OTHER | ||
114 | tl0_s7o: SPILL_7_OTHER | ||
115 | tl0_f0n: FILL_0_NORMAL | ||
116 | tl0_f1n: FILL_1_NORMAL | ||
117 | tl0_f2n: FILL_2_NORMAL | ||
118 | tl0_f3n: FILL_3_NORMAL | ||
119 | tl0_f4n: FILL_4_NORMAL | ||
120 | tl0_f5n: FILL_0_NORMAL_RTRAP | ||
121 | tl0_f6n: FILL_1_GENERIC_RTRAP | ||
122 | tl0_f7n: FILL_2_GENERIC_RTRAP | ||
123 | tl0_f0o: FILL_0_OTHER | ||
124 | tl0_f1o: FILL_1_OTHER | ||
125 | tl0_f2o: FILL_2_OTHER | ||
126 | tl0_f3o: FILL_3_OTHER | ||
127 | tl0_f4o: FILL_4_OTHER | ||
128 | tl0_f5o: FILL_5_OTHER | ||
129 | tl0_f6o: FILL_6_OTHER | ||
130 | tl0_f7o: FILL_7_OTHER | ||
131 | tl0_resv100: BTRAP(0x100) | ||
132 | tl0_bkpt: BREAKPOINT_TRAP | ||
133 | tl0_divz: TRAP(do_div0) | ||
134 | tl0_flushw: FLUSH_WINDOW_TRAP | ||
135 | tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) BTRAP(0x108) | ||
136 | tl0_resv109: BTRAP(0x109) BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) | ||
137 | tl0_resv10e: BTRAP(0x10e) BTRAP(0x10f) | ||
138 | tl0_linux32: LINUX_32BIT_SYSCALL_TRAP | ||
139 | tl0_oldlinux64: LINUX_64BIT_SYSCALL_TRAP | ||
140 | tl0_resv112: TRAP_UTRAP(UT_TRAP_INSTRUCTION_18,0x112) TRAP_UTRAP(UT_TRAP_INSTRUCTION_19,0x113) | ||
141 | tl0_resv114: TRAP_UTRAP(UT_TRAP_INSTRUCTION_20,0x114) TRAP_UTRAP(UT_TRAP_INSTRUCTION_21,0x115) | ||
142 | tl0_resv116: TRAP_UTRAP(UT_TRAP_INSTRUCTION_22,0x116) TRAP_UTRAP(UT_TRAP_INSTRUCTION_23,0x117) | ||
143 | tl0_resv118: TRAP_UTRAP(UT_TRAP_INSTRUCTION_24,0x118) TRAP_UTRAP(UT_TRAP_INSTRUCTION_25,0x119) | ||
144 | tl0_resv11a: TRAP_UTRAP(UT_TRAP_INSTRUCTION_26,0x11a) TRAP_UTRAP(UT_TRAP_INSTRUCTION_27,0x11b) | ||
145 | tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUCTION_29,0x11d) | ||
146 | tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f) | ||
147 | tl0_getcc: GETCC_TRAP | ||
148 | tl0_setcc: SETCC_TRAP | ||
149 | tl0_getpsr: TRAP(do_getpsr) | ||
150 | tl0_resv123: BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) BTRAP(0x127) | ||
151 | tl0_resv128: BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c) | ||
152 | tl0_resv12d: BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131) | ||
153 | tl0_resv132: BTRAP(0x132) BTRAP(0x133) BTRAP(0x134) BTRAP(0x135) BTRAP(0x136) | ||
154 | tl0_resv137: BTRAP(0x137) BTRAP(0x138) BTRAP(0x139) BTRAP(0x13a) BTRAP(0x13b) | ||
155 | tl0_resv13c: BTRAP(0x13c) BTRAP(0x13d) BTRAP(0x13e) BTRAP(0x13f) BTRAP(0x140) | ||
156 | tl0_resv141: BTRAP(0x141) BTRAP(0x142) BTRAP(0x143) BTRAP(0x144) BTRAP(0x145) | ||
157 | tl0_resv146: BTRAP(0x146) BTRAP(0x147) BTRAP(0x148) BTRAP(0x149) BTRAP(0x14a) | ||
158 | tl0_resv14b: BTRAP(0x14b) BTRAP(0x14c) BTRAP(0x14d) BTRAP(0x14e) BTRAP(0x14f) | ||
159 | tl0_resv150: BTRAP(0x150) BTRAP(0x151) BTRAP(0x152) BTRAP(0x153) BTRAP(0x154) | ||
160 | tl0_resv155: BTRAP(0x155) BTRAP(0x156) BTRAP(0x157) BTRAP(0x158) BTRAP(0x159) | ||
161 | tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e) | ||
162 | tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163) | ||
163 | tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) | ||
164 | tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) | ||
165 | tl0_linux64: LINUX_64BIT_SYSCALL_TRAP | ||
166 | tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) | ||
167 | tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) KGDB_TRAP(0x172) | ||
168 | tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) | ||
169 | tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) | ||
170 | tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) | ||
171 | #define BTRAPS(x) BTRAP(x) BTRAP(x+1) BTRAP(x+2) BTRAP(x+3) BTRAP(x+4) BTRAP(x+5) BTRAP(x+6) BTRAP(x+7) | ||
172 | tl0_resv180: BTRAPS(0x180) BTRAPS(0x188) | ||
173 | tl0_resv190: BTRAPS(0x190) BTRAPS(0x198) | ||
174 | tl0_resv1a0: BTRAPS(0x1a0) BTRAPS(0x1a8) | ||
175 | tl0_resv1b0: BTRAPS(0x1b0) BTRAPS(0x1b8) | ||
176 | tl0_resv1c0: BTRAPS(0x1c0) BTRAPS(0x1c8) | ||
177 | tl0_resv1d0: BTRAPS(0x1d0) BTRAPS(0x1d8) | ||
178 | tl0_resv1e0: BTRAPS(0x1e0) BTRAPS(0x1e8) | ||
179 | tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) | ||
180 | |||
181 | sparc64_ttable_tl1: | ||
182 | tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) | ||
183 | tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) | ||
184 | tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1) | ||
185 | tl1_itsb_4v: SUN4V_ITSB_MISS | ||
186 | tl1_iae: membar #Sync | ||
187 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | ||
188 | tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) | ||
189 | tl1_ill: TRAPTL1(do_ill_tl1) | ||
190 | tl1_privop: BTRAPTL1(0x11) | ||
191 | tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15) | ||
192 | tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19) | ||
193 | tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d) | ||
194 | tl1_resv01e: BTRAPTL1(0x1e) BTRAPTL1(0x1f) | ||
195 | tl1_fpdis: TRAP_NOSAVE(do_fpdis) | ||
196 | tl1_fpieee: TRAPTL1(do_fpieee_tl1) | ||
197 | tl1_fpother: TRAPTL1(do_fpother_tl1) | ||
198 | tl1_tof: TRAPTL1(do_tof_tl1) | ||
199 | tl1_cwin: CLEAN_WINDOW | ||
200 | tl1_div0: TRAPTL1(do_div0_tl1) | ||
201 | tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) | ||
202 | tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) | ||
203 | tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1) | ||
204 | tl1_dtsb_4v: SUN4V_DTSB_MISS | ||
205 | tl1_dae: membar #Sync | ||
206 | TRAP_NOSAVE_7INSNS(__spitfire_access_error) | ||
207 | tl1_resv033: BTRAPTL1(0x33) | ||
208 | tl1_mna: TRAP_NOSAVE(do_mna) | ||
209 | tl1_lddfmna: TRAPTL1(do_lddfmna_tl1) | ||
210 | tl1_stdfmna: TRAPTL1(do_stdfmna_tl1) | ||
211 | tl1_privact: BTRAPTL1(0x37) | ||
212 | tl1_resv038: BTRAPTL1(0x38) BTRAPTL1(0x39) BTRAPTL1(0x3a) BTRAPTL1(0x3b) | ||
213 | tl1_resv03c: BTRAPTL1(0x3c) BTRAPTL1(0x3d) BTRAPTL1(0x3e) BTRAPTL1(0x3f) | ||
214 | tl1_resv040: BTRAPTL1(0x40) | ||
215 | tl1_irq1: TRAP_IRQ(do_irq_tl1, 1) TRAP_IRQ(do_irq_tl1, 2) TRAP_IRQ(do_irq_tl1, 3) | ||
216 | tl1_irq4: TRAP_IRQ(do_irq_tl1, 4) TRAP_IRQ(do_irq_tl1, 5) TRAP_IRQ(do_irq_tl1, 6) | ||
217 | tl1_irq7: TRAP_IRQ(do_irq_tl1, 7) TRAP_IRQ(do_irq_tl1, 8) TRAP_IRQ(do_irq_tl1, 9) | ||
218 | tl1_irq10: TRAP_IRQ(do_irq_tl1, 10) TRAP_IRQ(do_irq_tl1, 11) | ||
219 | tl1_irq12: TRAP_IRQ(do_irq_tl1, 12) TRAP_IRQ(do_irq_tl1, 13) | ||
220 | tl1_irq14: TRAP_IRQ(do_irq_tl1, 14) TRAP_IRQ(do_irq_tl1, 15) | ||
221 | tl1_resv050: BTRAPTL1(0x50) BTRAPTL1(0x51) BTRAPTL1(0x52) BTRAPTL1(0x53) | ||
222 | tl1_resv054: BTRAPTL1(0x54) BTRAPTL1(0x55) BTRAPTL1(0x56) BTRAPTL1(0x57) | ||
223 | tl1_resv058: BTRAPTL1(0x58) BTRAPTL1(0x59) BTRAPTL1(0x5a) BTRAPTL1(0x5b) | ||
224 | tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) | ||
225 | tl1_ivec: TRAP_IVEC | ||
226 | tl1_paw: TRAPTL1(do_paw_tl1) | ||
227 | tl1_vaw: TRAPTL1(do_vaw_tl1) | ||
228 | tl1_cee: BTRAPTL1(0x63) | ||
229 | tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) | ||
230 | tl1_damiss: | ||
231 | #include "dtlb_miss.S" | ||
232 | tl1_daprot: | ||
233 | #include "dtlb_prot.S" | ||
234 | tl1_fecc: BTRAPTL1(0x70) /* Fast-ECC on Cheetah */ | ||
235 | tl1_dcpe: BTRAPTL1(0x71) /* D-cache Parity Error on Cheetah+ */ | ||
236 | tl1_icpe: BTRAPTL1(0x72) /* I-cache Parity Error on Cheetah+ */ | ||
237 | tl1_resv073: BTRAPTL1(0x73) | ||
238 | tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) | ||
239 | tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) | ||
240 | tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) | ||
241 | tl1_s0n: SPILL_0_NORMAL | ||
242 | tl1_s1n: SPILL_1_NORMAL | ||
243 | tl1_s2n: SPILL_2_NORMAL | ||
244 | tl1_s3n: SPILL_3_NORMAL | ||
245 | tl1_s4n: SPILL_4_NORMAL | ||
246 | tl1_s5n: SPILL_5_NORMAL | ||
247 | tl1_s6n: SPILL_6_NORMAL | ||
248 | tl1_s7n: SPILL_7_NORMAL | ||
249 | tl1_s0o: SPILL_0_OTHER | ||
250 | tl1_s1o: SPILL_1_OTHER | ||
251 | tl1_s2o: SPILL_2_OTHER | ||
252 | tl1_s3o: SPILL_3_OTHER | ||
253 | tl1_s4o: SPILL_4_OTHER | ||
254 | tl1_s5o: SPILL_5_OTHER | ||
255 | tl1_s6o: SPILL_6_OTHER | ||
256 | tl1_s7o: SPILL_7_OTHER | ||
257 | tl1_f0n: FILL_0_NORMAL | ||
258 | tl1_f1n: FILL_1_NORMAL | ||
259 | tl1_f2n: FILL_2_NORMAL | ||
260 | tl1_f3n: FILL_3_NORMAL | ||
261 | tl1_f4n: FILL_4_NORMAL | ||
262 | tl1_f5n: FILL_5_NORMAL | ||
263 | tl1_f6n: FILL_6_NORMAL | ||
264 | tl1_f7n: FILL_7_NORMAL | ||
265 | tl1_f0o: FILL_0_OTHER | ||
266 | tl1_f1o: FILL_1_OTHER | ||
267 | tl1_f2o: FILL_2_OTHER | ||
268 | tl1_f3o: FILL_3_OTHER | ||
269 | tl1_f4o: FILL_4_OTHER | ||
270 | tl1_f5o: FILL_5_OTHER | ||
271 | tl1_f6o: FILL_6_OTHER | ||
272 | tl1_f7o: FILL_7_OTHER | ||
diff --git a/arch/sparc/lib/atomic_32.S b/arch/sparc/lib/atomic_32.S new file mode 100644 index 00000000000..178cbb8ae1b --- /dev/null +++ b/arch/sparc/lib/atomic_32.S | |||
@@ -0,0 +1,99 @@ | |||
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 | /* Read asm-sparc/atomic.h carefully to understand how this works for SMP. | ||
44 | * Really, some things here for SMP are overly clever, go read the header. | ||
45 | */ | ||
46 | .globl ___atomic24_add | ||
47 | ___atomic24_add: | ||
48 | rd %psr, %g3 ! Keep the code small, old way was stupid | ||
49 | nop; nop; nop; ! Let the bits set | ||
50 | or %g3, PSR_PIL, %g7 ! Disable interrupts | ||
51 | wr %g7, 0x0, %psr ! Set %psr | ||
52 | nop; nop; nop; ! Let the bits set | ||
53 | #ifdef CONFIG_SMP | ||
54 | 1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. | ||
55 | orcc %g7, 0x0, %g0 ! Did we get it? | ||
56 | bne 1b ! Nope... | ||
57 | ld [%g1], %g7 ! Load locked atomic24_t | ||
58 | sra %g7, 8, %g7 ! Get signed 24-bit integer | ||
59 | add %g7, %g2, %g2 ! Add in argument | ||
60 | sll %g2, 8, %g7 ! Transpose back to atomic24_t | ||
61 | st %g7, [%g1] ! Clever: This releases the lock as well. | ||
62 | #else | ||
63 | ld [%g1], %g7 ! Load locked atomic24_t | ||
64 | add %g7, %g2, %g2 ! Add in argument | ||
65 | st %g2, [%g1] ! Store it back | ||
66 | #endif | ||
67 | wr %g3, 0x0, %psr ! Restore original PSR_PIL | ||
68 | nop; nop; nop; ! Let the bits set | ||
69 | jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h | ||
70 | mov %g4, %o7 ! Restore %o7 | ||
71 | |||
72 | .globl ___atomic24_sub | ||
73 | ___atomic24_sub: | ||
74 | rd %psr, %g3 ! Keep the code small, old way was stupid | ||
75 | nop; nop; nop; ! Let the bits set | ||
76 | or %g3, PSR_PIL, %g7 ! Disable interrupts | ||
77 | wr %g7, 0x0, %psr ! Set %psr | ||
78 | nop; nop; nop; ! Let the bits set | ||
79 | #ifdef CONFIG_SMP | ||
80 | 1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. | ||
81 | orcc %g7, 0x0, %g0 ! Did we get it? | ||
82 | bne 1b ! Nope... | ||
83 | ld [%g1], %g7 ! Load locked atomic24_t | ||
84 | sra %g7, 8, %g7 ! Get signed 24-bit integer | ||
85 | sub %g7, %g2, %g2 ! Subtract argument | ||
86 | sll %g2, 8, %g7 ! Transpose back to atomic24_t | ||
87 | st %g7, [%g1] ! Clever: This releases the lock as well | ||
88 | #else | ||
89 | ld [%g1], %g7 ! Load locked atomic24_t | ||
90 | sub %g7, %g2, %g2 ! Subtract argument | ||
91 | st %g2, [%g1] ! Store it back | ||
92 | #endif | ||
93 | wr %g3, 0x0, %psr ! Restore original PSR_PIL | ||
94 | nop; nop; nop; ! Let the bits set | ||
95 | jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h | ||
96 | mov %g4, %o7 ! Restore %o7 | ||
97 | |||
98 | .globl __atomic_end | ||
99 | __atomic_end: | ||
diff --git a/arch/sparc/lib/mul.S b/arch/sparc/lib/mul.S new file mode 100644 index 00000000000..c45470d0b0c --- /dev/null +++ b/arch/sparc/lib/mul.S | |||
@@ -0,0 +1,137 @@ | |||
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/rem.S b/arch/sparc/lib/rem.S new file mode 100644 index 00000000000..42fb8625281 --- /dev/null +++ b/arch/sparc/lib/rem.S | |||
@@ -0,0 +1,384 @@ | |||
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 new file mode 100644 index 00000000000..f0a0d4e4db7 --- /dev/null +++ b/arch/sparc/lib/sdiv.S | |||
@@ -0,0 +1,381 @@ | |||
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_32.S b/arch/sparc/lib/strlen_user_32.S new file mode 100644 index 00000000000..8c8a371df3c --- /dev/null +++ b/arch/sparc/lib/strlen_user_32.S | |||
@@ -0,0 +1,109 @@ | |||
1 | /* strlen_user.S: Sparc optimized strlen_user code | ||
2 | * | ||
3 | * Return length of string in userspace including terminating 0 | ||
4 | * or 0 for error | ||
5 | * | ||
6 | * Copyright (C) 1991,1996 Free Software Foundation | ||
7 | * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) | ||
8 | * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
9 | */ | ||
10 | |||
11 | #define LO_MAGIC 0x01010101 | ||
12 | #define HI_MAGIC 0x80808080 | ||
13 | |||
14 | 10: | ||
15 | ldub [%o0], %o5 | ||
16 | cmp %o5, 0 | ||
17 | be 1f | ||
18 | add %o0, 1, %o0 | ||
19 | andcc %o0, 3, %g0 | ||
20 | be 4f | ||
21 | or %o4, %lo(HI_MAGIC), %o3 | ||
22 | 11: | ||
23 | ldub [%o0], %o5 | ||
24 | cmp %o5, 0 | ||
25 | be 2f | ||
26 | add %o0, 1, %o0 | ||
27 | andcc %o0, 3, %g0 | ||
28 | be 5f | ||
29 | sethi %hi(LO_MAGIC), %o4 | ||
30 | 12: | ||
31 | ldub [%o0], %o5 | ||
32 | cmp %o5, 0 | ||
33 | be 3f | ||
34 | add %o0, 1, %o0 | ||
35 | b 13f | ||
36 | or %o4, %lo(LO_MAGIC), %o2 | ||
37 | 1: | ||
38 | retl | ||
39 | mov 1, %o0 | ||
40 | 2: | ||
41 | retl | ||
42 | mov 2, %o0 | ||
43 | 3: | ||
44 | retl | ||
45 | mov 3, %o0 | ||
46 | |||
47 | .align 4 | ||
48 | .global __strlen_user, __strnlen_user | ||
49 | __strlen_user: | ||
50 | sethi %hi(32768), %o1 | ||
51 | __strnlen_user: | ||
52 | mov %o1, %g1 | ||
53 | mov %o0, %o1 | ||
54 | andcc %o0, 3, %g0 | ||
55 | bne 10b | ||
56 | sethi %hi(HI_MAGIC), %o4 | ||
57 | or %o4, %lo(HI_MAGIC), %o3 | ||
58 | 4: | ||
59 | sethi %hi(LO_MAGIC), %o4 | ||
60 | 5: | ||
61 | or %o4, %lo(LO_MAGIC), %o2 | ||
62 | 13: | ||
63 | ld [%o0], %o5 | ||
64 | 2: | ||
65 | sub %o5, %o2, %o4 | ||
66 | andcc %o4, %o3, %g0 | ||
67 | bne 82f | ||
68 | add %o0, 4, %o0 | ||
69 | sub %o0, %o1, %g2 | ||
70 | 81: cmp %g2, %g1 | ||
71 | blu 13b | ||
72 | mov %o0, %o4 | ||
73 | ba,a 1f | ||
74 | |||
75 | /* Check every byte. */ | ||
76 | 82: srl %o5, 24, %g5 | ||
77 | andcc %g5, 0xff, %g0 | ||
78 | be 1f | ||
79 | add %o0, -3, %o4 | ||
80 | srl %o5, 16, %g5 | ||
81 | andcc %g5, 0xff, %g0 | ||
82 | be 1f | ||
83 | add %o4, 1, %o4 | ||
84 | srl %o5, 8, %g5 | ||
85 | andcc %g5, 0xff, %g0 | ||
86 | be 1f | ||
87 | add %o4, 1, %o4 | ||
88 | andcc %o5, 0xff, %g0 | ||
89 | bne 81b | ||
90 | sub %o0, %o1, %g2 | ||
91 | |||
92 | add %o4, 1, %o4 | ||
93 | 1: | ||
94 | retl | ||
95 | sub %o4, %o1, %o0 | ||
96 | |||
97 | .section .fixup,#alloc,#execinstr | ||
98 | .align 4 | ||
99 | 9: | ||
100 | retl | ||
101 | clr %o0 | ||
102 | |||
103 | .section __ex_table,#alloc | ||
104 | .align 4 | ||
105 | |||
106 | .word 10b, 9b | ||
107 | .word 11b, 9b | ||
108 | .word 12b, 9b | ||
109 | .word 13b, 9b | ||
diff --git a/arch/sparc/lib/strlen_user_64.S b/arch/sparc/lib/strlen_user_64.S new file mode 100644 index 00000000000..114ed111e25 --- /dev/null +++ b/arch/sparc/lib/strlen_user_64.S | |||
@@ -0,0 +1,95 @@ | |||
1 | /* strlen_user.S: Sparc64 optimized strlen_user code | ||
2 | * | ||
3 | * Return length of string in userspace including terminating 0 | ||
4 | * or 0 for error | ||
5 | * | ||
6 | * Copyright (C) 1991,1996 Free Software Foundation | ||
7 | * Copyright (C) 1996,1999 David S. Miller (davem@redhat.com) | ||
8 | * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | ||
9 | */ | ||
10 | |||
11 | #include <asm/asi.h> | ||
12 | |||
13 | #define LO_MAGIC 0x01010101 | ||
14 | #define HI_MAGIC 0x80808080 | ||
15 | |||
16 | .align 4 | ||
17 | .global __strlen_user, __strnlen_user | ||
18 | __strlen_user: | ||
19 | sethi %hi(32768), %o1 | ||
20 | __strnlen_user: | ||
21 | mov %o1, %g1 | ||
22 | mov %o0, %o1 | ||
23 | andcc %o0, 3, %g0 | ||
24 | be,pt %icc, 9f | ||
25 | sethi %hi(HI_MAGIC), %o4 | ||
26 | 10: lduba [%o0] %asi, %o5 | ||
27 | brz,pn %o5, 21f | ||
28 | add %o0, 1, %o0 | ||
29 | andcc %o0, 3, %g0 | ||
30 | be,pn %icc, 4f | ||
31 | or %o4, %lo(HI_MAGIC), %o3 | ||
32 | 11: lduba [%o0] %asi, %o5 | ||
33 | brz,pn %o5, 22f | ||
34 | add %o0, 1, %o0 | ||
35 | andcc %o0, 3, %g0 | ||
36 | be,pt %icc, 13f | ||
37 | srl %o3, 7, %o2 | ||
38 | 12: lduba [%o0] %asi, %o5 | ||
39 | brz,pn %o5, 23f | ||
40 | add %o0, 1, %o0 | ||
41 | ba,pt %icc, 2f | ||
42 | 15: lda [%o0] %asi, %o5 | ||
43 | 9: or %o4, %lo(HI_MAGIC), %o3 | ||
44 | 4: srl %o3, 7, %o2 | ||
45 | 13: lda [%o0] %asi, %o5 | ||
46 | 2: sub %o5, %o2, %o4 | ||
47 | andcc %o4, %o3, %g0 | ||
48 | bne,pn %icc, 82f | ||
49 | add %o0, 4, %o0 | ||
50 | sub %o0, %o1, %g2 | ||
51 | 81: cmp %g2, %g1 | ||
52 | blu,pt %icc, 13b | ||
53 | mov %o0, %o4 | ||
54 | ba,a,pt %xcc, 1f | ||
55 | |||
56 | /* Check every byte. */ | ||
57 | 82: srl %o5, 24, %g7 | ||
58 | andcc %g7, 0xff, %g0 | ||
59 | be,pn %icc, 1f | ||
60 | add %o0, -3, %o4 | ||
61 | srl %o5, 16, %g7 | ||
62 | andcc %g7, 0xff, %g0 | ||
63 | be,pn %icc, 1f | ||
64 | add %o4, 1, %o4 | ||
65 | srl %o5, 8, %g7 | ||
66 | andcc %g7, 0xff, %g0 | ||
67 | be,pn %icc, 1f | ||
68 | add %o4, 1, %o4 | ||
69 | andcc %o5, 0xff, %g0 | ||
70 | bne,pt %icc, 81b | ||
71 | sub %o0, %o1, %g2 | ||
72 | add %o4, 1, %o4 | ||
73 | 1: retl | ||
74 | sub %o4, %o1, %o0 | ||
75 | 21: retl | ||
76 | mov 1, %o0 | ||
77 | 22: retl | ||
78 | mov 2, %o0 | ||
79 | 23: retl | ||
80 | mov 3, %o0 | ||
81 | |||
82 | .section .fixup,#alloc,#execinstr | ||
83 | .align 4 | ||
84 | 30: | ||
85 | retl | ||
86 | clr %o0 | ||
87 | |||
88 | .section __ex_table,"a" | ||
89 | .align 4 | ||
90 | |||
91 | .word 10b, 30b | ||
92 | .word 11b, 30b | ||
93 | .word 12b, 30b | ||
94 | .word 15b, 30b | ||
95 | .word 13b, 30b | ||
diff --git a/arch/sparc/lib/strncpy_from_user_32.S b/arch/sparc/lib/strncpy_from_user_32.S new file mode 100644 index 00000000000..d77198976a6 --- /dev/null +++ b/arch/sparc/lib/strncpy_from_user_32.S | |||
@@ -0,0 +1,47 @@ | |||
1 | /* strncpy_from_user.S: Sparc strncpy from userspace. | ||
2 | * | ||
3 | * Copyright(C) 1996 David S. Miller | ||
4 | */ | ||
5 | |||
6 | #include <asm/ptrace.h> | ||
7 | #include <asm/errno.h> | ||
8 | |||
9 | .text | ||
10 | .align 4 | ||
11 | |||
12 | /* Must return: | ||
13 | * | ||
14 | * -EFAULT for an exception | ||
15 | * count if we hit the buffer limit | ||
16 | * bytes copied if we hit a null byte | ||
17 | */ | ||
18 | |||
19 | .globl __strncpy_from_user | ||
20 | __strncpy_from_user: | ||
21 | /* %o0=dest, %o1=src, %o2=count */ | ||
22 | mov %o2, %o3 | ||
23 | 1: | ||
24 | subcc %o2, 1, %o2 | ||
25 | bneg 2f | ||
26 | nop | ||
27 | 10: | ||
28 | ldub [%o1], %o4 | ||
29 | add %o0, 1, %o0 | ||
30 | cmp %o4, 0 | ||
31 | add %o1, 1, %o1 | ||
32 | bne 1b | ||
33 | stb %o4, [%o0 - 1] | ||
34 | 2: | ||
35 | add %o2, 1, %o0 | ||
36 | retl | ||
37 | sub %o3, %o0, %o0 | ||
38 | |||
39 | .section .fixup,#alloc,#execinstr | ||
40 | .align 4 | ||
41 | 4: | ||
42 | retl | ||
43 | mov -EFAULT, %o0 | ||
44 | |||
45 | .section __ex_table,#alloc | ||
46 | .align 4 | ||
47 | .word 10b, 4b | ||
diff --git a/arch/sparc/lib/strncpy_from_user_64.S b/arch/sparc/lib/strncpy_from_user_64.S new file mode 100644 index 00000000000..511c8f136f9 --- /dev/null +++ b/arch/sparc/lib/strncpy_from_user_64.S | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * strncpy_from_user.S: Sparc64 strncpy from userspace. | ||
3 | * | ||
4 | * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) | ||
5 | */ | ||
6 | |||
7 | #include <asm/asi.h> | ||
8 | #include <asm/errno.h> | ||
9 | |||
10 | .data | ||
11 | .align 8 | ||
12 | 0: .xword 0x0101010101010101 | ||
13 | |||
14 | .text | ||
15 | .align 32 | ||
16 | |||
17 | /* Must return: | ||
18 | * | ||
19 | * -EFAULT for an exception | ||
20 | * count if we hit the buffer limit | ||
21 | * bytes copied if we hit a null byte | ||
22 | * (without the null byte) | ||
23 | * | ||
24 | * This implementation assumes: | ||
25 | * %o1 is 8 aligned => !(%o2 & 7) | ||
26 | * %o0 is 8 aligned (if not, it will be slooooow, but will work) | ||
27 | * | ||
28 | * This is optimized for the common case: | ||
29 | * in my stats, 90% of src are 8 aligned (even on sparc32) | ||
30 | * and average length is 18 or so. | ||
31 | */ | ||
32 | |||
33 | .globl __strncpy_from_user | ||
34 | .type __strncpy_from_user,#function | ||
35 | __strncpy_from_user: | ||
36 | /* %o0=dest, %o1=src, %o2=count */ | ||
37 | andcc %o1, 7, %g0 ! IEU1 Group | ||
38 | bne,pn %icc, 30f ! CTI | ||
39 | add %o0, %o2, %g3 ! IEU0 | ||
40 | 60: ldxa [%o1] %asi, %g1 ! Load Group | ||
41 | brlez,pn %o2, 10f ! CTI | ||
42 | mov %o0, %o3 ! IEU0 | ||
43 | 50: sethi %hi(0b), %o4 ! IEU0 Group | ||
44 | ldx [%o4 + %lo(0b)], %o4 ! Load | ||
45 | sllx %o4, 7, %o5 ! IEU1 Group | ||
46 | 1: sub %g1, %o4, %g2 ! IEU0 Group | ||
47 | stx %g1, [%o0] ! Store | ||
48 | add %o0, 8, %o0 ! IEU1 | ||
49 | andcc %g2, %o5, %g0 ! IEU1 Group | ||
50 | bne,pn %xcc, 5f ! CTI | ||
51 | add %o1, 8, %o1 ! IEU0 | ||
52 | cmp %o0, %g3 ! IEU1 Group | ||
53 | bl,a,pt %xcc, 1b ! CTI | ||
54 | 61: ldxa [%o1] %asi, %g1 ! Load | ||
55 | 10: retl ! CTI Group | ||
56 | mov %o2, %o0 ! IEU0 | ||
57 | 5: srlx %g2, 32, %g7 ! IEU0 Group | ||
58 | sethi %hi(0xff00), %o4 ! IEU1 | ||
59 | andcc %g7, %o5, %g0 ! IEU1 Group | ||
60 | be,pn %icc, 2f ! CTI | ||
61 | or %o4, %lo(0xff00), %o4 ! IEU0 | ||
62 | srlx %g1, 48, %g7 ! IEU0 Group | ||
63 | andcc %g7, %o4, %g0 ! IEU1 Group | ||
64 | be,pn %icc, 50f ! CTI | ||
65 | andcc %g7, 0xff, %g0 ! IEU1 Group | ||
66 | be,pn %icc, 51f ! CTI | ||
67 | srlx %g1, 32, %g7 ! IEU0 | ||
68 | andcc %g7, %o4, %g0 ! IEU1 Group | ||
69 | be,pn %icc, 52f ! CTI | ||
70 | andcc %g7, 0xff, %g0 ! IEU1 Group | ||
71 | be,pn %icc, 53f ! CTI | ||
72 | 2: andcc %g2, %o5, %g0 ! IEU1 Group | ||
73 | be,pn %icc, 2f ! CTI | ||
74 | srl %g1, 16, %g7 ! IEU0 | ||
75 | andcc %g7, %o4, %g0 ! IEU1 Group | ||
76 | be,pn %icc, 54f ! CTI | ||
77 | andcc %g7, 0xff, %g0 ! IEU1 Group | ||
78 | be,pn %icc, 55f ! CTI | ||
79 | andcc %g1, %o4, %g0 ! IEU1 Group | ||
80 | be,pn %icc, 56f ! CTI | ||
81 | andcc %g1, 0xff, %g0 ! IEU1 Group | ||
82 | be,a,pn %icc, 57f ! CTI | ||
83 | sub %o0, %o3, %o0 ! IEU0 | ||
84 | 2: cmp %o0, %g3 ! IEU1 Group | ||
85 | bl,a,pt %xcc, 50b ! CTI | ||
86 | 62: ldxa [%o1] %asi, %g1 ! Load | ||
87 | retl ! CTI Group | ||
88 | mov %o2, %o0 ! IEU0 | ||
89 | 50: sub %o0, %o3, %o0 | ||
90 | retl | ||
91 | sub %o0, 8, %o0 | ||
92 | 51: sub %o0, %o3, %o0 | ||
93 | retl | ||
94 | sub %o0, 7, %o0 | ||
95 | 52: sub %o0, %o3, %o0 | ||
96 | retl | ||
97 | sub %o0, 6, %o0 | ||
98 | 53: sub %o0, %o3, %o0 | ||
99 | retl | ||
100 | sub %o0, 5, %o0 | ||
101 | 54: sub %o0, %o3, %o0 | ||
102 | retl | ||
103 | sub %o0, 4, %o0 | ||
104 | 55: sub %o0, %o3, %o0 | ||
105 | retl | ||
106 | sub %o0, 3, %o0 | ||
107 | 56: sub %o0, %o3, %o0 | ||
108 | retl | ||
109 | sub %o0, 2, %o0 | ||
110 | 57: retl | ||
111 | sub %o0, 1, %o0 | ||
112 | 30: brlez,pn %o2, 3f | ||
113 | sub %g0, %o2, %o3 | ||
114 | add %o0, %o2, %o0 | ||
115 | 63: lduba [%o1] %asi, %o4 | ||
116 | 1: add %o1, 1, %o1 | ||
117 | brz,pn %o4, 2f | ||
118 | stb %o4, [%o0 + %o3] | ||
119 | addcc %o3, 1, %o3 | ||
120 | bne,pt %xcc, 1b | ||
121 | 64: lduba [%o1] %asi, %o4 | ||
122 | 3: retl | ||
123 | mov %o2, %o0 | ||
124 | 2: retl | ||
125 | add %o2, %o3, %o0 | ||
126 | .size __strncpy_from_user, .-__strncpy_from_user | ||
127 | |||
128 | .section __ex_table,"a" | ||
129 | .align 4 | ||
130 | .word 60b, __retl_efault | ||
131 | .word 61b, __retl_efault | ||
132 | .word 62b, __retl_efault | ||
133 | .word 63b, __retl_efault | ||
134 | .word 64b, __retl_efault | ||
135 | .previous | ||
diff --git a/arch/sparc/lib/udiv.S b/arch/sparc/lib/udiv.S new file mode 100644 index 00000000000..2101405bdfc --- /dev/null +++ b/arch/sparc/lib/udiv.S | |||
@@ -0,0 +1,357 @@ | |||
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/umul.S b/arch/sparc/lib/umul.S new file mode 100644 index 00000000000..1f36ae68252 --- /dev/null +++ b/arch/sparc/lib/umul.S | |||
@@ -0,0 +1,171 @@ | |||
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 new file mode 100644 index 00000000000..77123eb83c4 --- /dev/null +++ b/arch/sparc/lib/urem.S | |||
@@ -0,0 +1,357 @@ | |||
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/mm/btfixup.c b/arch/sparc/mm/btfixup.c new file mode 100644 index 00000000000..8a7f81743c1 --- /dev/null +++ b/arch/sparc/mm/btfixup.c | |||
@@ -0,0 +1,329 @@ | |||
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/system.h> | ||
16 | #include <asm/cacheflush.h> | ||
17 | |||
18 | #define BTFIXUP_OPTIMIZE_NOP | ||
19 | #define BTFIXUP_OPTIMIZE_OTHER | ||
20 | |||
21 | extern char *srmmu_name; | ||
22 | static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for "; | ||
23 | static char str_sun4c[] __initdata = "sun4c\n"; | ||
24 | static char str_srmmu[] __initdata = "srmmu[%s]/"; | ||
25 | static char str_iommu[] __initdata = "iommu\n"; | ||
26 | static char str_iounit[] __initdata = "io-unit\n"; | ||
27 | |||
28 | static int visited __initdata = 0; | ||
29 | extern unsigned int ___btfixup_start[], ___btfixup_end[], __init_begin[], __init_end[], __init_text_end[]; | ||
30 | extern unsigned int _stext[], _end[], __start___ksymtab[], __stop___ksymtab[]; | ||
31 | static char wrong_f[] __initdata = "Trying to set f fixup %p to invalid function %08x\n"; | ||
32 | static char wrong_b[] __initdata = "Trying to set b fixup %p to invalid function %08x\n"; | ||
33 | static char wrong_s[] __initdata = "Trying to set s fixup %p to invalid value %08x\n"; | ||
34 | static char wrong_h[] __initdata = "Trying to set h fixup %p to invalid value %08x\n"; | ||
35 | static char wrong_a[] __initdata = "Trying to set a fixup %p to invalid value %08x\n"; | ||
36 | static char wrong[] __initdata = "Wrong address for %c fixup %p\n"; | ||
37 | static char insn_f[] __initdata = "Fixup f %p refers to weird instructions at %p[%08x,%08x]\n"; | ||
38 | static char insn_b[] __initdata = "Fixup b %p doesn't refer to a SETHI at %p[%08x]\n"; | ||
39 | static char insn_s[] __initdata = "Fixup s %p doesn't refer to an OR at %p[%08x]\n"; | ||
40 | static char insn_h[] __initdata = "Fixup h %p doesn't refer to a SETHI at %p[%08x]\n"; | ||
41 | static char insn_a[] __initdata = "Fixup a %p doesn't refer to a SETHI nor OR at %p[%08x]\n"; | ||
42 | static char insn_i[] __initdata = "Fixup i %p doesn't refer to a valid instruction at %p[%08x]\n"; | ||
43 | static char fca_und[] __initdata = "flush_cache_all undefined in btfixup()\n"; | ||
44 | static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n"; | ||
45 | |||
46 | #ifdef BTFIXUP_OPTIMIZE_OTHER | ||
47 | static void __init set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) | ||
48 | { | ||
49 | if (!fmangled) | ||
50 | *addr = value; | ||
51 | else { | ||
52 | unsigned int *q = (unsigned int *)q1; | ||
53 | if (*addr == 0x01000000) { | ||
54 | /* Noped */ | ||
55 | *q = value; | ||
56 | } else if (addr[-1] == *q) { | ||
57 | /* Moved */ | ||
58 | addr[-1] = value; | ||
59 | *q = value; | ||
60 | } else { | ||
61 | prom_printf(wrong_setaddr, addr-1, addr[-1], *addr, *q, value); | ||
62 | prom_halt(); | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | #else | ||
67 | static inline void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) | ||
68 | { | ||
69 | *addr = value; | ||
70 | } | ||
71 | #endif | ||
72 | |||
73 | void __init btfixup(void) | ||
74 | { | ||
75 | unsigned int *p, *q; | ||
76 | int type, count; | ||
77 | unsigned insn; | ||
78 | unsigned *addr; | ||
79 | int fmangled = 0; | ||
80 | void (*flush_cacheall)(void); | ||
81 | |||
82 | if (!visited) { | ||
83 | visited++; | ||
84 | printk(version); | ||
85 | if (ARCH_SUN4C) | ||
86 | printk(str_sun4c); | ||
87 | else { | ||
88 | printk(str_srmmu, srmmu_name); | ||
89 | if (sparc_cpu_model == sun4d) | ||
90 | printk(str_iounit); | ||
91 | else | ||
92 | printk(str_iommu); | ||
93 | } | ||
94 | } | ||
95 | for (p = ___btfixup_start; p < ___btfixup_end; ) { | ||
96 | count = p[2]; | ||
97 | q = p + 3; | ||
98 | switch (type = *(unsigned char *)p) { | ||
99 | case 'f': | ||
100 | count = p[3]; | ||
101 | q = p + 4; | ||
102 | if (((p[0] & 1) || p[1]) | ||
103 | && ((p[1] & 3) || (unsigned *)(p[1]) < _stext || (unsigned *)(p[1]) >= _end)) { | ||
104 | prom_printf(wrong_f, p, p[1]); | ||
105 | prom_halt(); | ||
106 | } | ||
107 | break; | ||
108 | case 'b': | ||
109 | if (p[1] < (unsigned long)__init_begin || p[1] >= (unsigned long)__init_text_end || (p[1] & 3)) { | ||
110 | prom_printf(wrong_b, p, p[1]); | ||
111 | prom_halt(); | ||
112 | } | ||
113 | break; | ||
114 | case 's': | ||
115 | if (p[1] + 0x1000 >= 0x2000) { | ||
116 | prom_printf(wrong_s, p, p[1]); | ||
117 | prom_halt(); | ||
118 | } | ||
119 | break; | ||
120 | case 'h': | ||
121 | if (p[1] & 0x3ff) { | ||
122 | prom_printf(wrong_h, p, p[1]); | ||
123 | prom_halt(); | ||
124 | } | ||
125 | break; | ||
126 | case 'a': | ||
127 | if (p[1] + 0x1000 >= 0x2000 && (p[1] & 0x3ff)) { | ||
128 | prom_printf(wrong_a, p, p[1]); | ||
129 | prom_halt(); | ||
130 | } | ||
131 | break; | ||
132 | } | ||
133 | if (p[0] & 1) { | ||
134 | p[0] &= ~1; | ||
135 | while (count) { | ||
136 | fmangled = 0; | ||
137 | addr = (unsigned *)*q; | ||
138 | if (addr < _stext || addr >= _end) { | ||
139 | prom_printf(wrong, type, p); | ||
140 | prom_halt(); | ||
141 | } | ||
142 | insn = *addr; | ||
143 | #ifdef BTFIXUP_OPTIMIZE_OTHER | ||
144 | if (type != 'f' && q[1]) { | ||
145 | insn = *(unsigned int *)q[1]; | ||
146 | if (!insn || insn == 1) | ||
147 | insn = *addr; | ||
148 | else | ||
149 | fmangled = 1; | ||
150 | } | ||
151 | #endif | ||
152 | switch (type) { | ||
153 | case 'f': /* CALL */ | ||
154 | if (addr >= __start___ksymtab && addr < __stop___ksymtab) { | ||
155 | *addr = p[1]; | ||
156 | break; | ||
157 | } else if (!q[1]) { | ||
158 | if ((insn & 0xc1c00000) == 0x01000000) { /* SETHI */ | ||
159 | *addr = (insn & 0xffc00000) | (p[1] >> 10); break; | ||
160 | } else if ((insn & 0xc1f82000) == 0x80102000) { /* OR X, %LO(i), Y */ | ||
161 | *addr = (insn & 0xffffe000) | (p[1] & 0x3ff); break; | ||
162 | } else if ((insn & 0xc0000000) != 0x40000000) { /* !CALL */ | ||
163 | bad_f: | ||
164 | prom_printf(insn_f, p, addr, insn, addr[1]); | ||
165 | prom_halt(); | ||
166 | } | ||
167 | } else if (q[1] != 1) | ||
168 | addr[1] = q[1]; | ||
169 | if (p[2] == BTFIXUPCALL_NORM) { | ||
170 | norm_f: | ||
171 | *addr = 0x40000000 | ((p[1] - (unsigned)addr) >> 2); | ||
172 | q[1] = 0; | ||
173 | break; | ||
174 | } | ||
175 | #ifndef BTFIXUP_OPTIMIZE_NOP | ||
176 | goto norm_f; | ||
177 | #else | ||
178 | if (!(addr[1] & 0x80000000)) { | ||
179 | if ((addr[1] & 0xc1c00000) != 0x01000000) /* !SETHI */ | ||
180 | goto bad_f; /* CALL, Bicc, FBfcc, CBccc are weird in delay slot, aren't they? */ | ||
181 | } else { | ||
182 | if ((addr[1] & 0x01800000) == 0x01800000) { | ||
183 | if ((addr[1] & 0x01f80000) == 0x01e80000) { | ||
184 | /* RESTORE */ | ||
185 | goto norm_f; /* It is dangerous to patch that */ | ||
186 | } | ||
187 | goto bad_f; | ||
188 | } | ||
189 | if ((addr[1] & 0xffffe003) == 0x9e03e000) { | ||
190 | /* ADD %O7, XX, %o7 */ | ||
191 | int displac = (addr[1] << 19); | ||
192 | |||
193 | displac = (displac >> 21) + 2; | ||
194 | *addr = (0x10800000) + (displac & 0x3fffff); | ||
195 | q[1] = addr[1]; | ||
196 | addr[1] = p[2]; | ||
197 | break; | ||
198 | } | ||
199 | if ((addr[1] & 0x201f) == 0x200f || (addr[1] & 0x7c000) == 0x3c000) | ||
200 | goto norm_f; /* Someone is playing bad tricks with us: rs1 or rs2 is o7 */ | ||
201 | if ((addr[1] & 0x3e000000) == 0x1e000000) | ||
202 | goto norm_f; /* rd is %o7. We'd better take care. */ | ||
203 | } | ||
204 | if (p[2] == BTFIXUPCALL_NOP) { | ||
205 | *addr = 0x01000000; | ||
206 | q[1] = 1; | ||
207 | break; | ||
208 | } | ||
209 | #ifndef BTFIXUP_OPTIMIZE_OTHER | ||
210 | goto norm_f; | ||
211 | #else | ||
212 | if (addr[1] == 0x01000000) { /* NOP in the delay slot */ | ||
213 | q[1] = addr[1]; | ||
214 | *addr = p[2]; | ||
215 | break; | ||
216 | } | ||
217 | if ((addr[1] & 0xc0000000) != 0xc0000000) { | ||
218 | /* Not a memory operation */ | ||
219 | if ((addr[1] & 0x30000000) == 0x10000000) { | ||
220 | /* Ok, non-memory op with rd %oX */ | ||
221 | if ((addr[1] & 0x3e000000) == 0x1c000000) | ||
222 | goto bad_f; /* Aiee. Someone is playing strange %sp tricks */ | ||
223 | if ((addr[1] & 0x3e000000) > 0x12000000 || | ||
224 | ((addr[1] & 0x3e000000) == 0x12000000 && | ||
225 | p[2] != BTFIXUPCALL_STO1O0 && p[2] != BTFIXUPCALL_SWAPO0O1) || | ||
226 | ((p[2] & 0xffffe000) == BTFIXUPCALL_RETINT(0))) { | ||
227 | /* Nobody uses the result. We can nop it out. */ | ||
228 | *addr = p[2]; | ||
229 | q[1] = addr[1]; | ||
230 | addr[1] = 0x01000000; | ||
231 | break; | ||
232 | } | ||
233 | if ((addr[1] & 0xf1ffffe0) == 0x90100000) { | ||
234 | /* MOV %reg, %Ox */ | ||
235 | if ((addr[1] & 0x3e000000) == 0x10000000 && | ||
236 | (p[2] & 0x7c000) == 0x20000) { | ||
237 | /* Ok, it is call xx; mov reg, %o0 and call optimizes | ||
238 | to doing something on %o0. Patch the patch. */ | ||
239 | *addr = (p[2] & ~0x7c000) | ((addr[1] & 0x1f) << 14); | ||
240 | q[1] = addr[1]; | ||
241 | addr[1] = 0x01000000; | ||
242 | break; | ||
243 | } | ||
244 | if ((addr[1] & 0x3e000000) == 0x12000000 && | ||
245 | p[2] == BTFIXUPCALL_STO1O0) { | ||
246 | *addr = (p[2] & ~0x3e000000) | ((addr[1] & 0x1f) << 25); | ||
247 | q[1] = addr[1]; | ||
248 | addr[1] = 0x01000000; | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | *addr = addr[1]; | ||
255 | q[1] = addr[1]; | ||
256 | addr[1] = p[2]; | ||
257 | break; | ||
258 | #endif /* BTFIXUP_OPTIMIZE_OTHER */ | ||
259 | #endif /* BTFIXUP_OPTIMIZE_NOP */ | ||
260 | case 'b': /* BLACKBOX */ | ||
261 | /* Has to be sethi i, xx */ | ||
262 | if ((insn & 0xc1c00000) != 0x01000000) { | ||
263 | prom_printf(insn_b, p, addr, insn); | ||
264 | prom_halt(); | ||
265 | } else { | ||
266 | void (*do_fixup)(unsigned *); | ||
267 | |||
268 | do_fixup = (void (*)(unsigned *))p[1]; | ||
269 | do_fixup(addr); | ||
270 | } | ||
271 | break; | ||
272 | case 's': /* SIMM13 */ | ||
273 | /* Has to be or %g0, i, xx */ | ||
274 | if ((insn & 0xc1ffe000) != 0x80102000) { | ||
275 | prom_printf(insn_s, p, addr, insn); | ||
276 | prom_halt(); | ||
277 | } | ||
278 | set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x1fff)); | ||
279 | break; | ||
280 | case 'h': /* SETHI */ | ||
281 | /* Has to be sethi i, xx */ | ||
282 | if ((insn & 0xc1c00000) != 0x01000000) { | ||
283 | prom_printf(insn_h, p, addr, insn); | ||
284 | prom_halt(); | ||
285 | } | ||
286 | set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); | ||
287 | break; | ||
288 | case 'a': /* HALF */ | ||
289 | /* Has to be sethi i, xx or or %g0, i, xx */ | ||
290 | if ((insn & 0xc1c00000) != 0x01000000 && | ||
291 | (insn & 0xc1ffe000) != 0x80102000) { | ||
292 | prom_printf(insn_a, p, addr, insn); | ||
293 | prom_halt(); | ||
294 | } | ||
295 | if (p[1] & 0x3ff) | ||
296 | set_addr(addr, q[1], fmangled, | ||
297 | (insn & 0x3e000000) | 0x80102000 | (p[1] & 0x1fff)); | ||
298 | else | ||
299 | set_addr(addr, q[1], fmangled, | ||
300 | (insn & 0x3e000000) | 0x01000000 | (p[1] >> 10)); | ||
301 | break; | ||
302 | case 'i': /* INT */ | ||
303 | if ((insn & 0xc1c00000) == 0x01000000) /* %HI */ | ||
304 | set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); | ||
305 | else if ((insn & 0x80002000) == 0x80002000) /* %LO */ | ||
306 | set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff)); | ||
307 | else { | ||
308 | prom_printf(insn_i, p, addr, insn); | ||
309 | prom_halt(); | ||
310 | } | ||
311 | break; | ||
312 | } | ||
313 | count -= 2; | ||
314 | q += 2; | ||
315 | } | ||
316 | } else | ||
317 | p = q + count; | ||
318 | } | ||
319 | #ifdef CONFIG_SMP | ||
320 | flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all); | ||
321 | #else | ||
322 | flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all); | ||
323 | #endif | ||
324 | if (!flush_cacheall) { | ||
325 | prom_printf(fca_und); | ||
326 | prom_halt(); | ||
327 | } | ||
328 | (*flush_cacheall)(); | ||
329 | } | ||
diff --git a/arch/sparc/mm/loadmmu.c b/arch/sparc/mm/loadmmu.c new file mode 100644 index 00000000000..82ec8f66603 --- /dev/null +++ b/arch/sparc/mm/loadmmu.c | |||
@@ -0,0 +1,44 @@ | |||
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/system.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/pgtable.h> | ||
17 | #include <asm/mmu_context.h> | ||
18 | #include <asm/oplib.h> | ||
19 | |||
20 | struct ctx_list *ctx_list_pool; | ||
21 | struct ctx_list ctx_free; | ||
22 | struct ctx_list ctx_used; | ||
23 | |||
24 | extern void ld_mmu_sun4c(void); | ||
25 | extern void ld_mmu_srmmu(void); | ||
26 | |||
27 | void __init load_mmu(void) | ||
28 | { | ||
29 | switch(sparc_cpu_model) { | ||
30 | case sun4c: | ||
31 | case sun4: | ||
32 | ld_mmu_sun4c(); | ||
33 | break; | ||
34 | case sun4m: | ||
35 | case sun4d: | ||
36 | case sparc_leon: | ||
37 | ld_mmu_srmmu(); | ||
38 | break; | ||
39 | default: | ||
40 | prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model); | ||
41 | prom_halt(); | ||
42 | } | ||
43 | btfixup(); | ||
44 | } | ||
diff --git a/arch/sparc/mm/nosun4c.c b/arch/sparc/mm/nosun4c.c new file mode 100644 index 00000000000..4e62c27147c --- /dev/null +++ b/arch/sparc/mm/nosun4c.c | |||
@@ -0,0 +1,77 @@ | |||
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/sun4c.c b/arch/sparc/mm/sun4c.c new file mode 100644 index 00000000000..1cf4f198709 --- /dev/null +++ b/arch/sparc/mm/sun4c.c | |||
@@ -0,0 +1,2166 @@ | |||
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/prom/segment.c b/arch/sparc/prom/segment.c new file mode 100644 index 00000000000..86a663f1d3c --- /dev/null +++ b/arch/sparc/prom/segment.c | |||
@@ -0,0 +1,28 @@ | |||
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 | } | ||