From fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 Mon Sep 17 00:00:00 2001 From: Jonathan Herman Date: Tue, 22 Jan 2013 10:38:37 -0500 Subject: Added missing tegra files. --- arch/sparc/boot/btfixupprep.c | 386 ++++++ arch/sparc/include/asm/apc.h | 64 + arch/sparc/include/asm/asi.h | 266 ++++ arch/sparc/include/asm/auxvec.h | 4 + arch/sparc/include/asm/bitsperlong.h | 13 + arch/sparc/include/asm/btfixup.h | 208 ++++ arch/sparc/include/asm/byteorder.h | 6 + arch/sparc/include/asm/cmt.h | 59 + arch/sparc/include/asm/cypress.h | 79 ++ arch/sparc/include/asm/display7seg.h | 79 ++ arch/sparc/include/asm/envctrl.h | 103 ++ arch/sparc/include/asm/errno.h | 117 ++ arch/sparc/include/asm/fcntl.h | 55 + arch/sparc/include/asm/fixmap.h | 110 ++ arch/sparc/include/asm/ioctl.h | 67 + arch/sparc/include/asm/ipcbuf.h | 32 + arch/sparc/include/asm/jsflash.h | 39 + arch/sparc/include/asm/memblock.h | 8 + arch/sparc/include/asm/memreg.h | 51 + arch/sparc/include/asm/module.h | 24 + arch/sparc/include/asm/mpmbox.h | 67 + arch/sparc/include/asm/msgbuf.h | 38 + arch/sparc/include/asm/openpromio.h | 69 ++ arch/sparc/include/asm/param.h | 7 + arch/sparc/include/asm/perfctr.h | 173 +++ arch/sparc/include/asm/pgtsun4.h | 171 +++ arch/sparc/include/asm/pgtsun4c.h | 172 +++ arch/sparc/include/asm/poll.h | 12 + arch/sparc/include/asm/posix_types.h | 155 +++ arch/sparc/include/asm/psrcompat.h | 45 + arch/sparc/include/asm/pstate.h | 91 ++ arch/sparc/include/asm/resource.h | 30 + arch/sparc/include/asm/sembuf.h | 31 + arch/sparc/include/asm/shmbuf.h | 50 + arch/sparc/include/asm/smpprim.h | 54 + arch/sparc/include/asm/socket.h | 66 + arch/sparc/include/asm/sockios.h | 14 + arch/sparc/include/asm/stat.h | 107 ++ arch/sparc/include/asm/statfs.h | 6 + arch/sparc/include/asm/swab.h | 45 + arch/sparc/include/asm/sysen.h | 15 + arch/sparc/include/asm/system.h | 8 + arch/sparc/include/asm/system_32.h | 284 +++++ arch/sparc/include/asm/system_64.h | 331 +++++ arch/sparc/include/asm/types.h | 23 + arch/sparc/include/asm/uctx.h | 71 ++ arch/sparc/include/asm/utrap.h | 51 + arch/sparc/include/asm/vac-ops.h | 127 ++ arch/sparc/include/asm/watchdog.h | 31 + arch/sparc/kernel/init_task.c | 22 + arch/sparc/kernel/muldiv.c | 239 ++++ arch/sparc/kernel/sun4c_irq.c | 264 ++++ arch/sparc/kernel/ttable.S | 272 +++++ arch/sparc/lib/atomic_32.S | 99 ++ arch/sparc/lib/mul.S | 137 +++ arch/sparc/lib/rem.S | 384 ++++++ arch/sparc/lib/sdiv.S | 381 ++++++ arch/sparc/lib/strlen_user_32.S | 109 ++ arch/sparc/lib/strlen_user_64.S | 95 ++ arch/sparc/lib/strncpy_from_user_32.S | 47 + arch/sparc/lib/strncpy_from_user_64.S | 135 ++ arch/sparc/lib/udiv.S | 357 ++++++ arch/sparc/lib/umul.S | 171 +++ arch/sparc/lib/urem.S | 357 ++++++ arch/sparc/mm/btfixup.c | 329 +++++ arch/sparc/mm/loadmmu.c | 44 + arch/sparc/mm/nosun4c.c | 77 ++ arch/sparc/mm/sun4c.c | 2166 +++++++++++++++++++++++++++++++++ arch/sparc/prom/segment.c | 28 + 69 files changed, 9827 insertions(+) create mode 100644 arch/sparc/boot/btfixupprep.c create mode 100644 arch/sparc/include/asm/apc.h create mode 100644 arch/sparc/include/asm/asi.h create mode 100644 arch/sparc/include/asm/auxvec.h create mode 100644 arch/sparc/include/asm/bitsperlong.h create mode 100644 arch/sparc/include/asm/btfixup.h create mode 100644 arch/sparc/include/asm/byteorder.h create mode 100644 arch/sparc/include/asm/cmt.h create mode 100644 arch/sparc/include/asm/cypress.h create mode 100644 arch/sparc/include/asm/display7seg.h create mode 100644 arch/sparc/include/asm/envctrl.h create mode 100644 arch/sparc/include/asm/errno.h create mode 100644 arch/sparc/include/asm/fcntl.h create mode 100644 arch/sparc/include/asm/fixmap.h create mode 100644 arch/sparc/include/asm/ioctl.h create mode 100644 arch/sparc/include/asm/ipcbuf.h create mode 100644 arch/sparc/include/asm/jsflash.h create mode 100644 arch/sparc/include/asm/memblock.h create mode 100644 arch/sparc/include/asm/memreg.h create mode 100644 arch/sparc/include/asm/module.h create mode 100644 arch/sparc/include/asm/mpmbox.h create mode 100644 arch/sparc/include/asm/msgbuf.h create mode 100644 arch/sparc/include/asm/openpromio.h create mode 100644 arch/sparc/include/asm/param.h create mode 100644 arch/sparc/include/asm/perfctr.h create mode 100644 arch/sparc/include/asm/pgtsun4.h create mode 100644 arch/sparc/include/asm/pgtsun4c.h create mode 100644 arch/sparc/include/asm/poll.h create mode 100644 arch/sparc/include/asm/posix_types.h create mode 100644 arch/sparc/include/asm/psrcompat.h create mode 100644 arch/sparc/include/asm/pstate.h create mode 100644 arch/sparc/include/asm/resource.h create mode 100644 arch/sparc/include/asm/sembuf.h create mode 100644 arch/sparc/include/asm/shmbuf.h create mode 100644 arch/sparc/include/asm/smpprim.h create mode 100644 arch/sparc/include/asm/socket.h create mode 100644 arch/sparc/include/asm/sockios.h create mode 100644 arch/sparc/include/asm/stat.h create mode 100644 arch/sparc/include/asm/statfs.h create mode 100644 arch/sparc/include/asm/swab.h create mode 100644 arch/sparc/include/asm/sysen.h create mode 100644 arch/sparc/include/asm/system.h create mode 100644 arch/sparc/include/asm/system_32.h create mode 100644 arch/sparc/include/asm/system_64.h create mode 100644 arch/sparc/include/asm/types.h create mode 100644 arch/sparc/include/asm/uctx.h create mode 100644 arch/sparc/include/asm/utrap.h create mode 100644 arch/sparc/include/asm/vac-ops.h create mode 100644 arch/sparc/include/asm/watchdog.h create mode 100644 arch/sparc/kernel/init_task.c create mode 100644 arch/sparc/kernel/muldiv.c create mode 100644 arch/sparc/kernel/sun4c_irq.c create mode 100644 arch/sparc/kernel/ttable.S create mode 100644 arch/sparc/lib/atomic_32.S create mode 100644 arch/sparc/lib/mul.S create mode 100644 arch/sparc/lib/rem.S create mode 100644 arch/sparc/lib/sdiv.S create mode 100644 arch/sparc/lib/strlen_user_32.S create mode 100644 arch/sparc/lib/strlen_user_64.S create mode 100644 arch/sparc/lib/strncpy_from_user_32.S create mode 100644 arch/sparc/lib/strncpy_from_user_64.S create mode 100644 arch/sparc/lib/udiv.S create mode 100644 arch/sparc/lib/umul.S create mode 100644 arch/sparc/lib/urem.S create mode 100644 arch/sparc/mm/btfixup.c create mode 100644 arch/sparc/mm/loadmmu.c create mode 100644 arch/sparc/mm/nosun4c.c create mode 100644 arch/sparc/mm/sun4c.c create mode 100644 arch/sparc/prom/segment.c (limited to 'arch/sparc') 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 @@ +/* + Simple utility to prepare vmlinux image for sparc. + Resolves all BTFIXUP uses and settings and creates + a special .s object to link to the image. + + Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include + +#define MAXSYMS 1024 + +static char *symtab = "SYMBOL TABLE:"; +static char *relrec = "RELOCATION RECORDS FOR ["; +static int rellen; +static int symlen; +int mode; + +struct _btfixup; + +typedef struct _btfixuprel { + char *sect; + unsigned long offset; + struct _btfixup *f; + int frel; + struct _btfixuprel *next; +} btfixuprel; + +typedef struct _btfixup { + int type; + int setinitval; + unsigned int initval; + char *initvalstr; + char *name; + btfixuprel *rel; +} btfixup; + +btfixup array[MAXSYMS]; +int last = 0; +char buffer[1024]; +unsigned long lastfoffset = -1; +unsigned long lastfrelno; +btfixup *lastf; + +static void fatal(void) __attribute__((noreturn)); +static void fatal(void) +{ + fprintf(stderr, "Malformed output from objdump\n%s\n", buffer); + exit(1); +} + +static btfixup *find(int type, char *name) +{ + int i; + for (i = 0; i < last; i++) { + if (array[i].type == type && !strcmp(array[i].name, name)) + return array + i; + } + array[last].type = type; + array[last].name = strdup(name); + array[last].setinitval = 0; + if (!array[last].name) fatal(); + array[last].rel = NULL; + last++; + if (last >= MAXSYMS) { + fprintf(stderr, "Ugh. Something strange. More than %d different BTFIXUP symbols\n", MAXSYMS); + exit(1); + } + return array + last - 1; +} + +static void set_mode (char *buffer) +{ + for (mode = 0;; mode++) + if (buffer[mode] < '0' || buffer[mode] > '9') + break; + if (mode != 8 && mode != 16) + fatal(); +} + + +int main(int argc,char **argv) +{ + char *p, *q; + char *sect; + int i, j, k; + unsigned int initval; + int shift; + btfixup *f; + btfixuprel *r, **rr; + unsigned long offset; + char *initvalstr; + + symlen = strlen(symtab); + while (fgets (buffer, 1024, stdin) != NULL) + if (!strncmp (buffer, symtab, symlen)) + goto main0; + fatal(); +main0: + rellen = strlen(relrec); + while (fgets (buffer, 1024, stdin) != NULL) + if (!strncmp (buffer, relrec, rellen)) + goto main1; + fatal(); +main1: + sect = malloc(strlen (buffer + rellen) + 1); + if (!sect) fatal(); + strcpy (sect, buffer + rellen); + p = strchr (sect, ']'); + if (!p) fatal(); + *p = 0; + if (fgets (buffer, 1024, stdin) == NULL) + fatal(); + while (fgets (buffer, 1024, stdin) != NULL) { + int nbase; + if (!strncmp (buffer, relrec, rellen)) + goto main1; + if (mode == 0) + set_mode (buffer); + p = strchr (buffer, '\n'); + if (p) *p = 0; + if (strlen (buffer) < 22+mode) + continue; + if (strncmp (buffer + mode, " R_SPARC_", 9)) + continue; + nbase = 27 - 8 + mode; + if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_') + continue; + switch (buffer[nbase+3]) { + case 'f': /* CALL */ + case 'b': /* BLACKBOX */ + case 's': /* SIMM13 */ + case 'a': /* HALF */ + case 'h': /* SETHI */ + case 'i': /* INT */ + break; + default: + continue; + } + p = strchr (buffer + nbase+5, '+'); + if (p) *p = 0; + shift = nbase + 5; + if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') { + shift = nbase + 6; + if (strcmp (sect, ".init.text")) { + fprintf(stderr, + "Wrong use of '%s' BTFIXUPSET in '%s' section.\n" + "BTFIXUPSET_CALL can be used only in" + " __init sections\n", + buffer + shift, sect); + exit(1); + } + } else if (buffer[nbase+4] != '_') + continue; + if (!strcmp (sect, ".text.exit")) + continue; + if (strcmp (sect, ".text") && + strcmp (sect, ".init.text") && + strcmp (sect, ".fixup") && + (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) { + if (buffer[nbase+3] == 'f') + fprintf(stderr, + "Wrong use of '%s' in '%s' section.\n" + " It can be used only in .text, .init.text," + " .fixup and __ksymtab\n", + buffer + shift, sect); + else + fprintf(stderr, + "Wrong use of '%s' in '%s' section.\n" + " It can be only used in .text, .init.text," + " and .fixup\n", buffer + shift, sect); + exit(1); + } + p = strstr (buffer + shift, "__btset_"); + if (p && buffer[nbase+4] == 's') { + fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer); + exit(1); + } + initval = 0; + initvalstr = NULL; + if (p) { + if (p[8] != '0' || p[9] != 'x') { + fprintf(stderr, "Pre-initialized values can be only initialized with hexadecimal constants starting 0x\n%s\n", buffer); + exit(1); + } + initval = strtoul(p + 10, &q, 16); + if (*q || !initval) { + 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); + exit(1); + } + initvalstr = p + 10; + *p = 0; + } + f = find(buffer[nbase+3], buffer + shift); + if (buffer[nbase+4] == 's') + continue; + switch (buffer[nbase+3]) { + case 'f': + if (initval) { + fprintf(stderr, "Cannot use pre-initialized fixups for calls\n%s\n", buffer); + exit(1); + } + if (!strcmp (sect, "__ksymtab")) { + if (strncmp (buffer + mode+9, "32 ", 10)) { + fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer); + exit(1); + } + } else if (strncmp (buffer + mode+9, "WDISP30 ", 10) && + strncmp (buffer + mode+9, "HI22 ", 10) && + strncmp (buffer + mode+9, "LO10 ", 10)) { + fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer); + exit(1); + } + break; + case 'b': + if (initval) { + fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer); + exit(1); + } + if (strncmp (buffer + mode+9, "HI22 ", 10)) { + fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer); + exit(1); + } + break; + case 's': + if (initval + 0x1000 >= 0x2000) { + fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer); + exit(1); + } + if (strncmp (buffer + mode+9, "13 ", 10)) { + fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer); + exit(1); + } + break; + case 'a': + if (initval + 0x1000 >= 0x2000 && (initval & 0x3ff)) { + fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer); + exit(1); + } + if (strncmp (buffer + mode+9, "13 ", 10)) { + fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer); + exit(1); + } + break; + case 'h': + if (initval & 0x3ff) { + fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer); + exit(1); + } + if (strncmp (buffer + mode+9, "HI22 ", 10)) { + fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer); + exit(1); + } + break; + case 'i': + if (initval) { + fprintf(stderr, "Cannot use pre-initialized fixups for INT\n%s\n", buffer); + exit(1); + } + if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) { + fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer); + exit(1); + } + break; + } + if (!f->setinitval) { + f->initval = initval; + if (initvalstr) { + f->initvalstr = strdup(initvalstr); + if (!f->initvalstr) fatal(); + } + f->setinitval = 1; + } else if (f->initval != initval) { + fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer\n%s\n", + f->name, f->initvalstr ? : "0x00000000", buffer); + exit(1); + } else if (initval && strcmp(f->initvalstr, initvalstr)) { + fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer.\n" + "Initializers have to match literally as well.\n%s\n", + f->name, f->initvalstr, buffer); + exit(1); + } + offset = strtoul(buffer, &q, 16); + if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) { + fprintf(stderr, "Malformed relocation address in\n%s\n", buffer); + exit(1); + } + for (k = 0, r = f->rel, rr = &f->rel; r; rr = &r->next, r = r->next, k++) + if (r->offset == offset && !strcmp(r->sect, sect)) { + fprintf(stderr, "Ugh. One address has two relocation records\n"); + exit(1); + } + *rr = malloc(sizeof(btfixuprel)); + if (!*rr) fatal(); + (*rr)->offset = offset; + (*rr)->f = NULL; + if (buffer[nbase+3] == 'f') { + lastf = f; + lastfoffset = offset; + lastfrelno = k; + } else if (lastfoffset + 4 == offset) { + (*rr)->f = lastf; + (*rr)->frel = lastfrelno; + } + (*rr)->sect = sect; + (*rr)->next = NULL; + } + printf("! Generated by btfixupprep. Do not edit.\n\n"); + printf("\t.section\t\".data..init\",#alloc,#write\n\t.align\t4\n\n"); + printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n"); + for (i = 0; i < last; i++) { + f = array + i; + printf("\t.global\t___%cs_%s\n", f->type, f->name); + if (f->type == 'f') + printf("___%cs_%s:\n\t.word 0x%08x,0,0,", f->type, f->name, f->type << 24); + else + printf("___%cs_%s:\n\t.word 0x%08x,0,", f->type, f->name, f->type << 24); + for (j = 0, r = f->rel; r != NULL; j++, r = r->next); + if (j) + printf("%d\n\t.word\t", j * 2); + else + printf("0\n"); + for (r = f->rel, j--; r != NULL; j--, r = r->next) { + if (!strcmp (r->sect, ".text")) + printf ("_stext+0x%08lx", r->offset); + else if (!strcmp (r->sect, ".init.text")) + printf ("__init_begin+0x%08lx", r->offset); + else if (!strcmp (r->sect, "__ksymtab")) + printf ("__start___ksymtab+0x%08lx", r->offset); + else if (!strcmp (r->sect, ".fixup")) + printf ("__start___fixup+0x%08lx", r->offset); + else + fatal(); + if (f->type == 'f' || !r->f) + printf (",0"); + else + printf (",___fs_%s+0x%08x", r->f->name, (4 + r->frel*2)*4 + 4); + if (j) printf (","); + else printf ("\n"); + } + printf("\n"); + } + printf("\n\t.global\t___btfixup_end\n___btfixup_end:\n"); + printf("\n\n! Define undefined references\n\n"); + for (i = 0; i < last; i++) { + f = array + i; + if (f->type == 'f') { + printf("\t.global\t___f_%s\n", f->name); + printf("___f_%s:\n", f->name); + } + } + printf("\tretl\n\t nop\n\n"); + for (i = 0; i < last; i++) { + f = array + i; + if (f->type != 'f') { + if (!f->initval) { + printf("\t.global\t___%c_%s\n", f->type, f->name); + printf("___%c_%s = 0\n", f->type, f->name); + } else { + printf("\t.global\t___%c_%s__btset_0x%s\n", f->type, f->name, f->initvalstr); + printf("___%c_%s__btset_0x%s = 0x%08x\n", f->type, f->name, f->initvalstr, f->initval); + } + } + } + printf("\n\n"); + exit(0); +} 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 @@ +/* apc - Driver definitions for power management functions + * of Aurora Personality Chip (APC) on SPARCstation-4/5 and + * derivatives + * + * Copyright (c) 2001 Eric Brower (ebrower@usa.net) + * + */ + +#ifndef _SPARC_APC_H +#define _SPARC_APC_H + +#include + +#define APC_IOC 'A' + +#define APCIOCGFANCTL _IOR(APC_IOC, 0x00, int) /* Get fan speed */ +#define APCIOCSFANCTL _IOW(APC_IOC, 0x01, int) /* Set fan speed */ + +#define APCIOCGCPWR _IOR(APC_IOC, 0x02, int) /* Get CPOWER state */ +#define APCIOCSCPWR _IOW(APC_IOC, 0x03, int) /* Set CPOWER state */ + +#define APCIOCGBPORT _IOR(APC_IOC, 0x04, int) /* Get BPORT state */ +#define APCIOCSBPORT _IOW(APC_IOC, 0x05, int) /* Set BPORT state */ + +/* + * Register offsets + */ +#define APC_IDLE_REG 0x00 +#define APC_FANCTL_REG 0x20 +#define APC_CPOWER_REG 0x24 +#define APC_BPORT_REG 0x30 + +#define APC_REGMASK 0x01 +#define APC_BPMASK 0x03 + +/* + * IDLE - CPU standby values (set to initiate standby) + */ +#define APC_IDLE_ON 0x01 + +/* + * FANCTL - Fan speed control state values + */ +#define APC_FANCTL_HI 0x00 /* Fan speed high */ +#define APC_FANCTL_LO 0x01 /* Fan speed low */ + +/* + * CPWR - Convenience power outlet state values + */ +#define APC_CPOWER_ON 0x00 /* Conv power on */ +#define APC_CPOWER_OFF 0x01 /* Conv power off */ + +/* + * BPA/BPB - Read-Write "Bit Ports" state values (reset to 0 at power-on) + * + * WARNING: Internal usage of bit ports is platform dependent-- + * don't modify BPORT settings unless you know what you are doing. + * + * On SS5 BPA seems to toggle onboard ethernet loopback... -E + */ +#define APC_BPORT_A 0x01 /* Bit Port A */ +#define APC_BPORT_B 0x02 /* Bit Port B */ + +#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 @@ +#ifndef _SPARC_ASI_H +#define _SPARC_ASI_H + +/* asi.h: Address Space Identifier values for the sparc. + * + * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) + * + * Pioneer work for sun4m: Paul Hatchman (paul@sfe.com.au) + * Joint edition for sun4c+sun4m: Pete A. Zaitcev + */ + +/* The first batch are for the sun4c. */ + +#define ASI_NULL1 0x00 +#define ASI_NULL2 0x01 + +/* sun4c and sun4 control registers and mmu/vac ops */ +#define ASI_CONTROL 0x02 +#define ASI_SEGMAP 0x03 +#define ASI_PTE 0x04 +#define ASI_HWFLUSHSEG 0x05 +#define ASI_HWFLUSHPAGE 0x06 +#define ASI_REGMAP 0x06 +#define ASI_HWFLUSHCONTEXT 0x07 + +#define ASI_USERTXT 0x08 +#define ASI_KERNELTXT 0x09 +#define ASI_USERDATA 0x0a +#define ASI_KERNELDATA 0x0b + +/* VAC Cache flushing on sun4c and sun4 */ +#define ASI_FLUSHSEG 0x0c +#define ASI_FLUSHPG 0x0d +#define ASI_FLUSHCTX 0x0e + +/* SPARCstation-5: only 6 bits are decoded. */ +/* wo = Write Only, rw = Read Write; */ +/* ss = Single Size, as = All Sizes; */ +#define ASI_M_RES00 0x00 /* Don't touch... */ +#define ASI_M_UNA01 0x01 /* Same here... */ +#define ASI_M_MXCC 0x02 /* Access to TI VIKING MXCC registers */ +#define ASI_M_FLUSH_PROBE 0x03 /* Reference MMU Flush/Probe; rw, ss */ +#ifndef CONFIG_SPARC_LEON +#define ASI_M_MMUREGS 0x04 /* MMU Registers; rw, ss */ +#else +#define ASI_M_MMUREGS 0x19 +#endif /* CONFIG_SPARC_LEON */ +#define ASI_M_TLBDIAG 0x05 /* MMU TLB only Diagnostics */ +#define ASI_M_DIAGS 0x06 /* Reference MMU Diagnostics */ +#define ASI_M_IODIAG 0x07 /* MMU I/O TLB only Diagnostics */ +#define ASI_M_USERTXT 0x08 /* Same as ASI_USERTXT; rw, as */ +#define ASI_M_KERNELTXT 0x09 /* Same as ASI_KERNELTXT; rw, as */ +#define ASI_M_USERDATA 0x0A /* Same as ASI_USERDATA; rw, as */ +#define ASI_M_KERNELDATA 0x0B /* Same as ASI_KERNELDATA; rw, as */ +#define ASI_M_TXTC_TAG 0x0C /* Instruction Cache Tag; rw, ss */ +#define ASI_M_TXTC_DATA 0x0D /* Instruction Cache Data; rw, ss */ +#define ASI_M_DATAC_TAG 0x0E /* Data Cache Tag; rw, ss */ +#define ASI_M_DATAC_DATA 0x0F /* Data Cache Data; rw, ss */ + +/* The following cache flushing ASIs work only with the 'sta' + * instruction. Results are unpredictable for 'swap' and 'ldstuba', + * so don't do it. + */ + +/* These ASI flushes affect external caches too. */ +#define ASI_M_FLUSH_PAGE 0x10 /* Flush I&D Cache Line (page); wo, ss */ +#define ASI_M_FLUSH_SEG 0x11 /* Flush I&D Cache Line (seg); wo, ss */ +#define ASI_M_FLUSH_REGION 0x12 /* Flush I&D Cache Line (region); wo, ss */ +#define ASI_M_FLUSH_CTX 0x13 /* Flush I&D Cache Line (context); wo, ss */ +#define ASI_M_FLUSH_USER 0x14 /* Flush I&D Cache Line (user); wo, ss */ + +/* Block-copy operations are available only on certain V8 cpus. */ +#define ASI_M_BCOPY 0x17 /* Block copy */ + +/* These affect only the ICACHE and are Ross HyperSparc and TurboSparc specific. */ +#define ASI_M_IFLUSH_PAGE 0x18 /* Flush I Cache Line (page); wo, ss */ +#define ASI_M_IFLUSH_SEG 0x19 /* Flush I Cache Line (seg); wo, ss */ +#define ASI_M_IFLUSH_REGION 0x1A /* Flush I Cache Line (region); wo, ss */ +#define ASI_M_IFLUSH_CTX 0x1B /* Flush I Cache Line (context); wo, ss */ +#define ASI_M_IFLUSH_USER 0x1C /* Flush I Cache Line (user); wo, ss */ + +/* Block-fill operations are available on certain V8 cpus */ +#define ASI_M_BFILL 0x1F + +/* This allows direct access to main memory, actually 0x20 to 0x2f are + * the available ASI's for physical ram pass-through, but I don't have + * any idea what the other ones do.... + */ + +#define ASI_M_BYPASS 0x20 /* Reference MMU bypass; rw, as */ +#define ASI_M_FBMEM 0x29 /* Graphics card frame buffer access */ +#define ASI_M_VMEUS 0x2A /* VME user 16-bit access */ +#define ASI_M_VMEPS 0x2B /* VME priv 16-bit access */ +#define ASI_M_VMEUT 0x2C /* VME user 32-bit access */ +#define ASI_M_VMEPT 0x2D /* VME priv 32-bit access */ +#define ASI_M_SBUS 0x2E /* Direct SBus access */ +#define ASI_M_CTL 0x2F /* Control Space (ECC and MXCC are here) */ + + +/* This is ROSS HyperSparc only. */ +#define ASI_M_FLUSH_IWHOLE 0x31 /* Flush entire ICACHE; wo, ss */ + +/* Tsunami/Viking/TurboSparc i/d cache flash clear. */ +#define ASI_M_IC_FLCLEAR 0x36 +#define ASI_M_DC_FLCLEAR 0x37 + +#define ASI_M_DCDR 0x39 /* Data Cache Diagnostics Register rw, ss */ + +#define ASI_M_VIKING_TMP1 0x40 /* Emulation temporary 1 on Viking */ +/* only available on SuperSparc I */ +/* #define ASI_M_VIKING_TMP2 0x41 */ /* Emulation temporary 2 on Viking */ + +#define ASI_M_ACTION 0x4c /* Breakpoint Action Register (GNU/Viking) */ + +/* V9 Architecture mandary ASIs. */ +#define ASI_N 0x04 /* Nucleus */ +#define ASI_NL 0x0c /* Nucleus, little endian */ +#define ASI_AIUP 0x10 /* Primary, user */ +#define ASI_AIUS 0x11 /* Secondary, user */ +#define ASI_AIUPL 0x18 /* Primary, user, little endian */ +#define ASI_AIUSL 0x19 /* Secondary, user, little endian */ +#define ASI_P 0x80 /* Primary, implicit */ +#define ASI_S 0x81 /* Secondary, implicit */ +#define ASI_PNF 0x82 /* Primary, no fault */ +#define ASI_SNF 0x83 /* Secondary, no fault */ +#define ASI_PL 0x88 /* Primary, implicit, l-endian */ +#define ASI_SL 0x89 /* Secondary, implicit, l-endian */ +#define ASI_PNFL 0x8a /* Primary, no fault, l-endian */ +#define ASI_SNFL 0x8b /* Secondary, no fault, l-endian */ + +/* SpitFire and later extended ASIs. The "(III)" marker designates + * UltraSparc-III and later specific ASIs. The "(CMT)" marker designates + * Chip Multi Threading specific ASIs. "(NG)" designates Niagara specific + * ASIs, "(4V)" designates SUN4V specific ASIs. + */ +#define ASI_PHYS_USE_EC 0x14 /* PADDR, E-cachable */ +#define ASI_PHYS_BYPASS_EC_E 0x15 /* PADDR, E-bit */ +#define ASI_BLK_AIUP_4V 0x16 /* (4V) Prim, user, block ld/st */ +#define ASI_BLK_AIUS_4V 0x17 /* (4V) Sec, user, block ld/st */ +#define ASI_PHYS_USE_EC_L 0x1c /* PADDR, E-cachable, little endian*/ +#define ASI_PHYS_BYPASS_EC_E_L 0x1d /* PADDR, E-bit, little endian */ +#define ASI_BLK_AIUP_L_4V 0x1e /* (4V) Prim, user, block, l-endian*/ +#define ASI_BLK_AIUS_L_4V 0x1f /* (4V) Sec, user, block, l-endian */ +#define ASI_SCRATCHPAD 0x20 /* (4V) Scratch Pad Registers */ +#define ASI_MMU 0x21 /* (4V) MMU Context Registers */ +#define ASI_BLK_INIT_QUAD_LDD_AIUS 0x23 /* (NG) init-store, twin load, + * secondary, user + */ +#define ASI_NUCLEUS_QUAD_LDD 0x24 /* Cachable, qword load */ +#define ASI_QUEUE 0x25 /* (4V) Interrupt Queue Registers */ +#define ASI_QUAD_LDD_PHYS_4V 0x26 /* (4V) Physical, qword load */ +#define ASI_NUCLEUS_QUAD_LDD_L 0x2c /* Cachable, qword load, l-endian */ +#define ASI_QUAD_LDD_PHYS_L_4V 0x2e /* (4V) Phys, qword load, l-endian */ +#define ASI_PCACHE_DATA_STATUS 0x30 /* (III) PCache data stat RAM diag */ +#define ASI_PCACHE_DATA 0x31 /* (III) PCache data RAM diag */ +#define ASI_PCACHE_TAG 0x32 /* (III) PCache tag RAM diag */ +#define ASI_PCACHE_SNOOP_TAG 0x33 /* (III) PCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS 0x34 /* (III+) PADDR, qword load */ +#define ASI_WCACHE_VALID_BITS 0x38 /* (III) WCache Valid Bits diag */ +#define ASI_WCACHE_DATA 0x39 /* (III) WCache data RAM diag */ +#define ASI_WCACHE_TAG 0x3a /* (III) WCache tag RAM diag */ +#define ASI_WCACHE_SNOOP_TAG 0x3b /* (III) WCache snoop tag RAM diag */ +#define ASI_QUAD_LDD_PHYS_L 0x3c /* (III+) PADDR, qw-load, l-endian */ +#define ASI_SRAM_FAST_INIT 0x40 /* (III+) Fast SRAM init */ +#define ASI_CORE_AVAILABLE 0x41 /* (CMT) LP Available */ +#define ASI_CORE_ENABLE_STAT 0x41 /* (CMT) LP Enable Status */ +#define ASI_CORE_ENABLE 0x41 /* (CMT) LP Enable RW */ +#define ASI_XIR_STEERING 0x41 /* (CMT) XIR Steering RW */ +#define ASI_CORE_RUNNING_RW 0x41 /* (CMT) LP Running RW */ +#define ASI_CORE_RUNNING_W1S 0x41 /* (CMT) LP Running Write-One Set */ +#define ASI_CORE_RUNNING_W1C 0x41 /* (CMT) LP Running Write-One Clr */ +#define ASI_CORE_RUNNING_STAT 0x41 /* (CMT) LP Running Status */ +#define ASI_CMT_ERROR_STEERING 0x41 /* (CMT) Error Steering RW */ +#define ASI_DCACHE_INVALIDATE 0x42 /* (III) DCache Invalidate diag */ +#define ASI_DCACHE_UTAG 0x43 /* (III) DCache uTag diag */ +#define ASI_DCACHE_SNOOP_TAG 0x44 /* (III) DCache snoop tag RAM diag */ +#define ASI_LSU_CONTROL 0x45 /* Load-store control unit */ +#define ASI_DCU_CONTROL_REG 0x45 /* (III) DCache Unit Control reg */ +#define ASI_DCACHE_DATA 0x46 /* DCache data-ram diag access */ +#define ASI_DCACHE_TAG 0x47 /* Dcache tag/valid ram diag access*/ +#define ASI_INTR_DISPATCH_STAT 0x48 /* IRQ vector dispatch status */ +#define ASI_INTR_RECEIVE 0x49 /* IRQ vector receive status */ +#define ASI_UPA_CONFIG 0x4a /* UPA config space */ +#define ASI_JBUS_CONFIG 0x4a /* (IIIi) JBUS Config Register */ +#define ASI_SAFARI_CONFIG 0x4a /* (III) Safari Config Register */ +#define ASI_SAFARI_ADDRESS 0x4a /* (III) Safari Address Register */ +#define ASI_ESTATE_ERROR_EN 0x4b /* E-cache error enable space */ +#define ASI_AFSR 0x4c /* Async fault status register */ +#define ASI_AFAR 0x4d /* Async fault address register */ +#define ASI_EC_TAG_DATA 0x4e /* E-cache tag/valid ram diag acc */ +#define ASI_IMMU 0x50 /* Insn-MMU main register space */ +#define ASI_IMMU_TSB_8KB_PTR 0x51 /* Insn-MMU 8KB TSB pointer reg */ +#define ASI_IMMU_TSB_64KB_PTR 0x52 /* Insn-MMU 64KB TSB pointer reg */ +#define ASI_ITLB_DATA_IN 0x54 /* Insn-MMU TLB data in reg */ +#define ASI_ITLB_DATA_ACCESS 0x55 /* Insn-MMU TLB data access reg */ +#define ASI_ITLB_TAG_READ 0x56 /* Insn-MMU TLB tag read reg */ +#define ASI_IMMU_DEMAP 0x57 /* Insn-MMU TLB demap */ +#define ASI_DMMU 0x58 /* Data-MMU main register space */ +#define ASI_DMMU_TSB_8KB_PTR 0x59 /* Data-MMU 8KB TSB pointer reg */ +#define ASI_DMMU_TSB_64KB_PTR 0x5a /* Data-MMU 16KB TSB pointer reg */ +#define ASI_DMMU_TSB_DIRECT_PTR 0x5b /* Data-MMU TSB direct pointer reg */ +#define ASI_DTLB_DATA_IN 0x5c /* Data-MMU TLB data in reg */ +#define ASI_DTLB_DATA_ACCESS 0x5d /* Data-MMU TLB data access reg */ +#define ASI_DTLB_TAG_READ 0x5e /* Data-MMU TLB tag read reg */ +#define ASI_DMMU_DEMAP 0x5f /* Data-MMU TLB demap */ +#define ASI_IIU_INST_TRAP 0x60 /* (III) Instruction Breakpoint */ +#define ASI_INTR_ID 0x63 /* (CMT) Interrupt ID register */ +#define ASI_CORE_ID 0x63 /* (CMT) LP ID register */ +#define ASI_CESR_ID 0x63 /* (CMT) CESR ID register */ +#define ASI_IC_INSTR 0x66 /* Insn cache instrucion ram diag */ +#define ASI_IC_TAG 0x67 /* Insn cache tag/valid ram diag */ +#define ASI_IC_STAG 0x68 /* (III) Insn cache snoop tag ram */ +#define ASI_IC_PRE_DECODE 0x6e /* Insn cache pre-decode ram diag */ +#define ASI_IC_NEXT_FIELD 0x6f /* Insn cache next-field ram diag */ +#define ASI_BRPRED_ARRAY 0x6f /* (III) Branch Prediction RAM diag*/ +#define ASI_BLK_AIUP 0x70 /* Primary, user, block load/store */ +#define ASI_BLK_AIUS 0x71 /* Secondary, user, block ld/st */ +#define ASI_MCU_CTRL_REG 0x72 /* (III) Memory controller regs */ +#define ASI_EC_DATA 0x74 /* (III) E-cache data staging reg */ +#define ASI_EC_CTRL 0x75 /* (III) E-cache control reg */ +#define ASI_EC_W 0x76 /* E-cache diag write access */ +#define ASI_UDB_ERROR_W 0x77 /* External UDB error regs W */ +#define ASI_UDB_CONTROL_W 0x77 /* External UDB control regs W */ +#define ASI_INTR_W 0x77 /* IRQ vector dispatch write */ +#define ASI_INTR_DATAN_W 0x77 /* (III) Out irq vector data reg N */ +#define ASI_INTR_DISPATCH_W 0x77 /* (III) Interrupt vector dispatch */ +#define ASI_BLK_AIUPL 0x78 /* Primary, user, little, blk ld/st*/ +#define ASI_BLK_AIUSL 0x79 /* Secondary, user, little, blk ld/st*/ +#define ASI_EC_R 0x7e /* E-cache diag read access */ +#define ASI_UDBH_ERROR_R 0x7f /* External UDB error regs rd hi */ +#define ASI_UDBL_ERROR_R 0x7f /* External UDB error regs rd low */ +#define ASI_UDBH_CONTROL_R 0x7f /* External UDB control regs rd hi */ +#define ASI_UDBL_CONTROL_R 0x7f /* External UDB control regs rd low*/ +#define ASI_INTR_R 0x7f /* IRQ vector dispatch read */ +#define ASI_INTR_DATAN_R 0x7f /* (III) In irq vector data reg N */ +#define ASI_PST8_P 0xc0 /* Primary, 8 8-bit, partial */ +#define ASI_PST8_S 0xc1 /* Secondary, 8 8-bit, partial */ +#define ASI_PST16_P 0xc2 /* Primary, 4 16-bit, partial */ +#define ASI_PST16_S 0xc3 /* Secondary, 4 16-bit, partial */ +#define ASI_PST32_P 0xc4 /* Primary, 2 32-bit, partial */ +#define ASI_PST32_S 0xc5 /* Secondary, 2 32-bit, partial */ +#define ASI_PST8_PL 0xc8 /* Primary, 8 8-bit, partial, L */ +#define ASI_PST8_SL 0xc9 /* Secondary, 8 8-bit, partial, L */ +#define ASI_PST16_PL 0xca /* Primary, 4 16-bit, partial, L */ +#define ASI_PST16_SL 0xcb /* Secondary, 4 16-bit, partial, L */ +#define ASI_PST32_PL 0xcc /* Primary, 2 32-bit, partial, L */ +#define ASI_PST32_SL 0xcd /* Secondary, 2 32-bit, partial, L */ +#define ASI_FL8_P 0xd0 /* Primary, 1 8-bit, fpu ld/st */ +#define ASI_FL8_S 0xd1 /* Secondary, 1 8-bit, fpu ld/st */ +#define ASI_FL16_P 0xd2 /* Primary, 1 16-bit, fpu ld/st */ +#define ASI_FL16_S 0xd3 /* Secondary, 1 16-bit, fpu ld/st */ +#define ASI_FL8_PL 0xd8 /* Primary, 1 8-bit, fpu ld/st, L */ +#define ASI_FL8_SL 0xd9 /* Secondary, 1 8-bit, fpu ld/st, L*/ +#define ASI_FL16_PL 0xda /* Primary, 1 16-bit, fpu ld/st, L */ +#define ASI_FL16_SL 0xdb /* Secondary, 1 16-bit, fpu ld/st,L*/ +#define ASI_BLK_COMMIT_P 0xe0 /* Primary, blk store commit */ +#define ASI_BLK_COMMIT_S 0xe1 /* Secondary, blk store commit */ +#define ASI_BLK_INIT_QUAD_LDD_P 0xe2 /* (NG) init-store, twin load, + * primary, implicit + */ +#define ASI_BLK_P 0xf0 /* Primary, blk ld/st */ +#define ASI_BLK_S 0xf1 /* Secondary, blk ld/st */ +#define ASI_BLK_PL 0xf8 /* Primary, blk ld/st, little */ +#define ASI_BLK_SL 0xf9 /* Secondary, blk ld/st, little */ + +#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 @@ +#ifndef __ASMSPARC_AUXVEC_H +#define __ASMSPARC_AUXVEC_H + +#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 @@ +#ifndef __ASM_ALPHA_BITSPERLONG_H +#define __ASM_ALPHA_BITSPERLONG_H + +#if defined(__sparc__) && defined(__arch64__) +#define __BITS_PER_LONG 64 +#else +#define __BITS_PER_LONG 32 +#endif + +#include + +#endif /* __ASM_ALPHA_BITSPERLONG_H */ + 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 @@ +/* + * asm/btfixup.h: Macros for boot time linking. + * + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef _SPARC_BTFIXUP_H +#define _SPARC_BTFIXUP_H + +#include + +#ifndef __ASSEMBLY__ + +#ifdef MODULE +extern unsigned int ___illegal_use_of_BTFIXUP_SIMM13_in_module(void); +extern unsigned int ___illegal_use_of_BTFIXUP_SETHI_in_module(void); +extern unsigned int ___illegal_use_of_BTFIXUP_HALF_in_module(void); +extern unsigned int ___illegal_use_of_BTFIXUP_INT_in_module(void); + +#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module() +#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module() +#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module() +#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module() +#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module + +#else + +#define BTFIXUP_SIMM13(__name) ___sf_##__name() +#define BTFIXUP_HALF(__name) ___af_##__name() +#define BTFIXUP_SETHI(__name) ___hf_##__name() +#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name) +/* This must be written in assembly and present in a sethi */ +#define BTFIXUP_BLACKBOX(__name) ___b_##__name +#endif /* MODULE */ + +/* Fixup call xx */ + +#define BTFIXUPDEF_CALL(__type, __name, __args...) \ + extern __type ___f_##__name(__args); \ + extern unsigned ___fs_##__name[3]; +#define BTFIXUPDEF_CALL_CONST(__type, __name, __args...) \ + extern __type ___f_##__name(__args) __attribute_const__; \ + extern unsigned ___fs_##__name[3]; +#define BTFIXUP_CALL(__name) ___f_##__name + +#define BTFIXUPDEF_BLACKBOX(__name) \ + extern unsigned ___bs_##__name[2]; + +/* Put bottom 13bits into some register variable */ + +#define BTFIXUPDEF_SIMM13(__name) \ + static inline unsigned int ___sf_##__name(void) __attribute_const__; \ + extern unsigned ___ss_##__name[2]; \ + static inline unsigned int ___sf_##__name(void) { \ + unsigned int ret; \ + __asm__ ("or %%g0, ___s_" #__name ", %0" : "=r"(ret)); \ + return ret; \ + } +#define BTFIXUPDEF_SIMM13_INIT(__name,__val) \ + static inline unsigned int ___sf_##__name(void) __attribute_const__; \ + extern unsigned ___ss_##__name[2]; \ + static inline unsigned int ___sf_##__name(void) { \ + unsigned int ret; \ + __asm__ ("or %%g0, ___s_" #__name "__btset_" #__val ", %0" : "=r"(ret));\ + return ret; \ + } + +/* Put either bottom 13 bits, or upper 22 bits into some register variable + * (depending on the value, this will lead into sethi FIX, reg; or + * mov FIX, reg; ) + */ + +#define BTFIXUPDEF_HALF(__name) \ + static inline unsigned int ___af_##__name(void) __attribute_const__; \ + extern unsigned ___as_##__name[2]; \ + static inline unsigned int ___af_##__name(void) { \ + unsigned int ret; \ + __asm__ ("or %%g0, ___a_" #__name ", %0" : "=r"(ret)); \ + return ret; \ + } +#define BTFIXUPDEF_HALF_INIT(__name,__val) \ + static inline unsigned int ___af_##__name(void) __attribute_const__; \ + extern unsigned ___as_##__name[2]; \ + static inline unsigned int ___af_##__name(void) { \ + unsigned int ret; \ + __asm__ ("or %%g0, ___a_" #__name "__btset_" #__val ", %0" : "=r"(ret));\ + return ret; \ + } + +/* Put upper 22 bits into some register variable */ + +#define BTFIXUPDEF_SETHI(__name) \ + static inline unsigned int ___hf_##__name(void) __attribute_const__; \ + extern unsigned ___hs_##__name[2]; \ + static inline unsigned int ___hf_##__name(void) { \ + unsigned int ret; \ + __asm__ ("sethi %%hi(___h_" #__name "), %0" : "=r"(ret)); \ + return ret; \ + } +#define BTFIXUPDEF_SETHI_INIT(__name,__val) \ + static inline unsigned int ___hf_##__name(void) __attribute_const__; \ + extern unsigned ___hs_##__name[2]; \ + static inline unsigned int ___hf_##__name(void) { \ + unsigned int ret; \ + __asm__ ("sethi %%hi(___h_" #__name "__btset_" #__val "), %0" : \ + "=r"(ret)); \ + return ret; \ + } + +/* Put a full 32bit integer into some register variable */ + +#define BTFIXUPDEF_INT(__name) \ + extern unsigned char ___i_##__name; \ + extern unsigned ___is_##__name[2]; + +#define BTFIXUPCALL_NORM 0x00000000 /* Always call */ +#define BTFIXUPCALL_NOP 0x01000000 /* Possibly optimize to nop */ +#define BTFIXUPCALL_RETINT(i) (0x90102000|((i) & 0x1fff)) /* Possibly optimize to mov i, %o0 */ +#define BTFIXUPCALL_ORINT(i) (0x90122000|((i) & 0x1fff)) /* Possibly optimize to or %o0, i, %o0 */ +#define BTFIXUPCALL_RETO0 0x01000000 /* Return first parameter, actually a nop */ +#define BTFIXUPCALL_ANDNINT(i) (0x902a2000|((i) & 0x1fff)) /* Possibly optimize to andn %o0, i, %o0 */ +#define BTFIXUPCALL_SWAPO0O1 0xd27a0000 /* Possibly optimize to swap [%o0],%o1 */ +#define BTFIXUPCALL_SWAPO0G0 0xc07a0000 /* Possibly optimize to swap [%o0],%g0 */ +#define BTFIXUPCALL_SWAPG1G2 0xc4784000 /* Possibly optimize to swap [%g1],%g2 */ +#define BTFIXUPCALL_STG0O0 0xc0220000 /* Possibly optimize to st %g0,[%o0] */ +#define BTFIXUPCALL_STO1O0 0xd2220000 /* Possibly optimize to st %o1,[%o0] */ + +#define BTFIXUPSET_CALL(__name, __addr, __insn) \ + do { \ + ___fs_##__name[0] |= 1; \ + ___fs_##__name[1] = (unsigned long)__addr; \ + ___fs_##__name[2] = __insn; \ + } while (0) + +#define BTFIXUPSET_BLACKBOX(__name, __func) \ + do { \ + ___bs_##__name[0] |= 1; \ + ___bs_##__name[1] = (unsigned long)__func; \ + } while (0) + +#define BTFIXUPCOPY_CALL(__name, __from) \ + do { \ + ___fs_##__name[0] |= 1; \ + ___fs_##__name[1] = ___fs_##__from[1]; \ + ___fs_##__name[2] = ___fs_##__from[2]; \ + } while (0) + +#define BTFIXUPSET_SIMM13(__name, __val) \ + do { \ + ___ss_##__name[0] |= 1; \ + ___ss_##__name[1] = (unsigned)__val; \ + } while (0) + +#define BTFIXUPCOPY_SIMM13(__name, __from) \ + do { \ + ___ss_##__name[0] |= 1; \ + ___ss_##__name[1] = ___ss_##__from[1]; \ + } while (0) + +#define BTFIXUPSET_HALF(__name, __val) \ + do { \ + ___as_##__name[0] |= 1; \ + ___as_##__name[1] = (unsigned)__val; \ + } while (0) + +#define BTFIXUPCOPY_HALF(__name, __from) \ + do { \ + ___as_##__name[0] |= 1; \ + ___as_##__name[1] = ___as_##__from[1]; \ + } while (0) + +#define BTFIXUPSET_SETHI(__name, __val) \ + do { \ + ___hs_##__name[0] |= 1; \ + ___hs_##__name[1] = (unsigned)__val; \ + } while (0) + +#define BTFIXUPCOPY_SETHI(__name, __from) \ + do { \ + ___hs_##__name[0] |= 1; \ + ___hs_##__name[1] = ___hs_##__from[1]; \ + } while (0) + +#define BTFIXUPSET_INT(__name, __val) \ + do { \ + ___is_##__name[0] |= 1; \ + ___is_##__name[1] = (unsigned)__val; \ + } while (0) + +#define BTFIXUPCOPY_INT(__name, __from) \ + do { \ + ___is_##__name[0] |= 1; \ + ___is_##__name[1] = ___is_##__from[1]; \ + } while (0) + +#define BTFIXUPVAL_CALL(__name) \ + ((unsigned long)___fs_##__name[1]) + +extern void btfixup(void); + +#else /* __ASSEMBLY__ */ + +#define BTFIXUP_SETHI(__name) %hi(___h_ ## __name) +#define BTFIXUP_SETHI_INIT(__name,__val) %hi(___h_ ## __name ## __btset_ ## __val) + +#endif /* __ASSEMBLY__ */ + +#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 @@ +#ifndef _SPARC_BYTEORDER_H +#define _SPARC_BYTEORDER_H + +#include + +#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 @@ +#ifndef _SPARC64_CMT_H +#define _SPARC64_CMT_H + +/* cmt.h: Chip Multi-Threading register definitions + * + * Copyright (C) 2004 David S. Miller (davem@redhat.com) + */ + +/* ASI_CORE_ID - private */ +#define LP_ID 0x0000000000000010UL +#define LP_ID_MAX 0x00000000003f0000UL +#define LP_ID_ID 0x000000000000003fUL + +/* ASI_INTR_ID - private */ +#define LP_INTR_ID 0x0000000000000000UL +#define LP_INTR_ID_ID 0x00000000000003ffUL + +/* ASI_CESR_ID - private */ +#define CESR_ID 0x0000000000000040UL +#define CESR_ID_ID 0x00000000000000ffUL + +/* ASI_CORE_AVAILABLE - shared */ +#define LP_AVAIL 0x0000000000000000UL +#define LP_AVAIL_1 0x0000000000000002UL +#define LP_AVAIL_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE_STATUS - shared */ +#define LP_ENAB_STAT 0x0000000000000010UL +#define LP_ENAB_STAT_1 0x0000000000000002UL +#define LP_ENAB_STAT_0 0x0000000000000001UL + +/* ASI_CORE_ENABLE - shared */ +#define LP_ENAB 0x0000000000000020UL +#define LP_ENAB_1 0x0000000000000002UL +#define LP_ENAB_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING - shared */ +#define LP_RUNNING_RW 0x0000000000000050UL +#define LP_RUNNING_W1S 0x0000000000000060UL +#define LP_RUNNING_W1C 0x0000000000000068UL +#define LP_RUNNING_1 0x0000000000000002UL +#define LP_RUNNING_0 0x0000000000000001UL + +/* ASI_CORE_RUNNING_STAT - shared */ +#define LP_RUN_STAT 0x0000000000000058UL +#define LP_RUN_STAT_1 0x0000000000000002UL +#define LP_RUN_STAT_0 0x0000000000000001UL + +/* ASI_XIR_STEERING - shared */ +#define LP_XIR_STEER 0x0000000000000030UL +#define LP_XIR_STEER_1 0x0000000000000002UL +#define LP_XIR_STEER_0 0x0000000000000001UL + +/* ASI_CMT_ERROR_STEERING - shared */ +#define CMT_ER_STEER 0x0000000000000040UL +#define CMT_ER_STEER_1 0x0000000000000002UL +#define CMT_ER_STEER_0 0x0000000000000001UL + +#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 @@ +/* + * cypress.h: Cypress module specific definitions and defines. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_CYPRESS_H +#define _SPARC_CYPRESS_H + +/* Cypress chips have %psr 'impl' of '0001' and 'vers' of '0001'. */ + +/* The MMU control register fields on the Sparc Cypress 604/605 MMU's. + * + * --------------------------------------------------------------- + * |implvers| MCA | MCM |MV| MID |BM| C|RSV|MR|CM|CL|CE|RSV|NF|ME| + * --------------------------------------------------------------- + * 31 24 23-22 21-20 19 18-15 14 13 12 11 10 9 8 7-2 1 0 + * + * MCA: MultiChip Access -- Used for configuration of multiple + * CY7C604/605 cache units. + * MCM: MultiChip Mask -- Again, for multiple cache unit config. + * MV: MultiChip Valid -- Indicates MCM and MCA have valid settings. + * MID: ModuleID -- Unique processor ID for MBus transactions. (605 only) + * BM: Boot Mode -- 0 = not in boot mode, 1 = in boot mode + * C: Cacheable -- Indicates whether accesses are cacheable while + * the MMU is off. 0=no 1=yes + * MR: MemoryReflection -- Indicates whether the bus attached to the + * MBus supports memory reflection. 0=no 1=yes (605 only) + * CM: CacheMode -- Indicates whether the cache is operating in write + * through or copy-back mode. 0=write-through 1=copy-back + * CL: CacheLock -- Indicates if the entire cache is locked or not. + * 0=not-locked 1=locked (604 only) + * CE: CacheEnable -- Is the virtual cache on? 0=no 1=yes + * NF: NoFault -- Do faults generate traps? 0=yes 1=no + * ME: MmuEnable -- Is the MMU doing translations? 0=no 1=yes + */ + +#define CYPRESS_MCA 0x00c00000 +#define CYPRESS_MCM 0x00300000 +#define CYPRESS_MVALID 0x00080000 +#define CYPRESS_MIDMASK 0x00078000 /* Only on 605 */ +#define CYPRESS_BMODE 0x00004000 +#define CYPRESS_ACENABLE 0x00002000 +#define CYPRESS_MRFLCT 0x00000800 /* Only on 605 */ +#define CYPRESS_CMODE 0x00000400 +#define CYPRESS_CLOCK 0x00000200 /* Only on 604 */ +#define CYPRESS_CENABLE 0x00000100 +#define CYPRESS_NFAULT 0x00000002 +#define CYPRESS_MENABLE 0x00000001 + +static inline void cypress_flush_page(unsigned long page) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (page), "i" (ASI_M_FLUSH_PAGE)); +} + +static inline void cypress_flush_segment(unsigned long addr) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_FLUSH_SEG)); +} + +static inline void cypress_flush_region(unsigned long addr) +{ + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (addr), "i" (ASI_M_FLUSH_REGION)); +} + +static inline void cypress_flush_context(void) +{ + __asm__ __volatile__("sta %%g0, [%%g0] %0\n\t" : : + "i" (ASI_M_FLUSH_CTX)); +} + +/* XXX Displacement flushes for buggy chips and initial testing + * XXX go here. + */ + +#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 @@ +/* + * + * display7seg - Driver interface for the 7-segment display + * present on Sun Microsystems CP1400 and CP1500 + * + * Copyright (c) 2000 Eric Brower + * + */ + +#ifndef __display7seg_h__ +#define __display7seg_h__ + +#define D7S_IOC 'p' + +#define D7SIOCRD _IOR(D7S_IOC, 0x45, int) /* Read device state */ +#define D7SIOCWR _IOW(D7S_IOC, 0x46, int) /* Write device state */ +#define D7SIOCTM _IO (D7S_IOC, 0x47) /* Translate mode (FLIP)*/ + +/* + * ioctl flag definitions + * + * POINT - Toggle decimal point (0=absent 1=present) + * ALARM - Toggle alarm LED (0=green 1=red) + * FLIP - Toggle inverted mode (0=normal 1=flipped) + * bits 0-4 - Character displayed (see definitions below) + * + * Display segments are defined as follows, + * subject to D7S_FLIP register state: + * + * a + * --- + * f| |b + * -g- + * e| |c + * --- + * d + */ + +#define D7S_POINT (1 << 7) /* Decimal point*/ +#define D7S_ALARM (1 << 6) /* Alarm LED */ +#define D7S_FLIP (1 << 5) /* Flip display */ + +#define D7S_0 0x00 /* Numerals 0-9 */ +#define D7S_1 0x01 +#define D7S_2 0x02 +#define D7S_3 0x03 +#define D7S_4 0x04 +#define D7S_5 0x05 +#define D7S_6 0x06 +#define D7S_7 0x07 +#define D7S_8 0x08 +#define D7S_9 0x09 +#define D7S_A 0x0A /* Letters A-F, H, L, P */ +#define D7S_B 0x0B +#define D7S_C 0x0C +#define D7S_D 0x0D +#define D7S_E 0x0E +#define D7S_F 0x0F +#define D7S_H 0x10 +#define D7S_E2 0x11 +#define D7S_L 0x12 +#define D7S_P 0x13 +#define D7S_SEGA 0x14 /* Individual segments */ +#define D7S_SEGB 0x15 +#define D7S_SEGC 0x16 +#define D7S_SEGD 0x17 +#define D7S_SEGE 0x18 +#define D7S_SEGF 0x19 +#define D7S_SEGG 0x1A +#define D7S_SEGABFG 0x1B /* Segment groupings */ +#define D7S_SEGCDEG 0x1C +#define D7S_SEGBCEF 0x1D +#define D7S_SEGADG 0x1E +#define D7S_BLANK 0x1F /* Clear all segments */ + +#define D7S_MIN_VAL 0x0 +#define D7S_MAX_VAL 0x1F + +#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 @@ +/* + * + * envctrl.h: Definitions for access to the i2c environment + * monitoring on Ultrasparc systems. + * + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2000 Vinh Truong (vinh.truong@eng.sun.com) + * VT - Add all ioctl commands and environment status definitions + * VT - Add application note + */ +#ifndef _SPARC64_ENVCTRL_H +#define _SPARC64_ENVCTRL_H 1 + +#include + +/* Application note: + * + * The driver supports 4 operations: open(), close(), ioctl(), read() + * The device name is /dev/envctrl. + * Below is sample usage: + * + * fd = open("/dev/envtrl", O_RDONLY); + * if (ioctl(fd, ENVCTRL_READ_SHUTDOWN_TEMPERATURE, 0) < 0) + * printf("error\n"); + * ret = read(fd, buf, 10); + * close(fd); + * + * Notice in the case of cpu voltage and temperature, the default is + * cpu0. If we need to know the info of cpu1, cpu2, cpu3, we need to + * pass in cpu number in ioctl() last parameter. For example, to + * get the voltage of cpu2: + * + * ioctlbuf[0] = 2; + * if (ioctl(fd, ENVCTRL_READ_CPU_VOLTAGE, ioctlbuf) < 0) + * printf("error\n"); + * ret = read(fd, buf, 10); + * + * All the return values are in ascii. So check read return value + * and do appropriate conversions in your application. + */ + +/* IOCTL commands */ + +/* Note: these commands reflect possible monitor features. + * Some boards choose to support some of the features only. + */ +#define ENVCTRL_RD_CPU_TEMPERATURE _IOR('p', 0x40, int) +#define ENVCTRL_RD_CPU_VOLTAGE _IOR('p', 0x41, int) +#define ENVCTRL_RD_FAN_STATUS _IOR('p', 0x42, int) +#define ENVCTRL_RD_WARNING_TEMPERATURE _IOR('p', 0x43, int) +#define ENVCTRL_RD_SHUTDOWN_TEMPERATURE _IOR('p', 0x44, int) +#define ENVCTRL_RD_VOLTAGE_STATUS _IOR('p', 0x45, int) +#define ENVCTRL_RD_SCSI_TEMPERATURE _IOR('p', 0x46, int) +#define ENVCTRL_RD_ETHERNET_TEMPERATURE _IOR('p', 0x47, int) +#define ENVCTRL_RD_MTHRBD_TEMPERATURE _IOR('p', 0x48, int) + +#define ENVCTRL_RD_GLOBALADDRESS _IOR('p', 0x49, int) + +/* Read return values for a voltage status request. */ +#define ENVCTRL_VOLTAGE_POWERSUPPLY_GOOD 0x01 +#define ENVCTRL_VOLTAGE_BAD 0x02 +#define ENVCTRL_POWERSUPPLY_BAD 0x03 +#define ENVCTRL_VOLTAGE_POWERSUPPLY_BAD 0x04 + +/* Read return values for a fan status request. + * A failure match means either the fan fails or + * the fan is not connected. Some boards have optional + * connectors to connect extra fans. + * + * There are maximum 8 monitor fans. Some are cpu fans + * some are system fans. The mask below only indicates + * fan by order number. + * Below is a sample application: + * + * if (ioctl(fd, ENVCTRL_READ_FAN_STATUS, 0) < 0) { + * printf("ioctl fan failed\n"); + * } + * if (read(fd, rslt, 1) <= 0) { + * printf("error or fan not monitored\n"); + * } else { + * if (rslt[0] == ENVCTRL_ALL_FANS_GOOD) { + * printf("all fans good\n"); + * } else if (rslt[0] == ENVCTRL_ALL_FANS_BAD) { + * printf("all fans bad\n"); + * } else { + * if (rslt[0] & ENVCTRL_FAN0_FAILURE_MASK) { + * printf("fan 0 failed or not connected\n"); + * } + * ...... + */ + +#define ENVCTRL_ALL_FANS_GOOD 0x00 +#define ENVCTRL_FAN0_FAILURE_MASK 0x01 +#define ENVCTRL_FAN1_FAILURE_MASK 0x02 +#define ENVCTRL_FAN2_FAILURE_MASK 0x04 +#define ENVCTRL_FAN3_FAILURE_MASK 0x08 +#define ENVCTRL_FAN4_FAILURE_MASK 0x10 +#define ENVCTRL_FAN5_FAILURE_MASK 0x20 +#define ENVCTRL_FAN6_FAILURE_MASK 0x40 +#define ENVCTRL_FAN7_FAILURE_MASK 0x80 +#define ENVCTRL_ALL_FANS_BAD 0xFF + +#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 @@ +#ifndef _SPARC_ERRNO_H +#define _SPARC_ERRNO_H + +/* These match the SunOS error numbering scheme. */ + +#include + +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Op not supported on transport endpoint */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Cannot assign requested address */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Net dropped connection because of reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Transport endpoint is already connected */ +#define ENOTCONN 57 /* Transport endpoint is not connected */ +#define ESHUTDOWN 58 /* No send after transport endpoint shutdown */ +#define ETOOMANYREFS 59 /* Too many references: cannot splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ +#define ELOOP 62 /* Too many symbolic links encountered */ +#define ENAMETOOLONG 63 /* File name too long */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ +#define EPROCLIM 67 /* SUNOS: Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Quota exceeded */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Object is remote */ +#define ENOSTR 72 /* Device not a stream */ +#define ETIME 73 /* Timer expired */ +#define ENOSR 74 /* Out of streams resources */ +#define ENOMSG 75 /* No message of desired type */ +#define EBADMSG 76 /* Not a data message */ +#define EIDRM 77 /* Identifier removed */ +#define EDEADLK 78 /* Resource deadlock would occur */ +#define ENOLCK 79 /* No record locks available */ +#define ENONET 80 /* Machine is not on the network */ +#define ERREMOTE 81 /* SunOS: Too many lvls of remote in path */ +#define ENOLINK 82 /* Link has been severed */ +#define EADV 83 /* Advertise error */ +#define ESRMNT 84 /* Srmount error */ +#define ECOMM 85 /* Communication error on send */ +#define EPROTO 86 /* Protocol error */ +#define EMULTIHOP 87 /* Multihop attempted */ +#define EDOTDOT 88 /* RFS specific error */ +#define EREMCHG 89 /* Remote address changed */ +#define ENOSYS 90 /* Function not implemented */ + +/* The rest have no SunOS equivalent. */ +#define ESTRPIPE 91 /* Streams pipe error */ +#define EOVERFLOW 92 /* Value too large for defined data type */ +#define EBADFD 93 /* File descriptor in bad state */ +#define ECHRNG 94 /* Channel number out of range */ +#define EL2NSYNC 95 /* Level 2 not synchronized */ +#define EL3HLT 96 /* Level 3 halted */ +#define EL3RST 97 /* Level 3 reset */ +#define ELNRNG 98 /* Link number out of range */ +#define EUNATCH 99 /* Protocol driver not attached */ +#define ENOCSI 100 /* No CSI structure available */ +#define EL2HLT 101 /* Level 2 halted */ +#define EBADE 102 /* Invalid exchange */ +#define EBADR 103 /* Invalid request descriptor */ +#define EXFULL 104 /* Exchange full */ +#define ENOANO 105 /* No anode */ +#define EBADRQC 106 /* Invalid request code */ +#define EBADSLT 107 /* Invalid slot */ +#define EDEADLOCK 108 /* File locking deadlock error */ +#define EBFONT 109 /* Bad font file format */ +#define ELIBEXEC 110 /* Cannot exec a shared library directly */ +#define ENODATA 111 /* No data available */ +#define ELIBBAD 112 /* Accessing a corrupted shared library */ +#define ENOPKG 113 /* Package not installed */ +#define ELIBACC 114 /* Can not access a needed shared library */ +#define ENOTUNIQ 115 /* Name not unique on network */ +#define ERESTART 116 /* Interrupted syscall should be restarted */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EILSEQ 122 /* Illegal byte sequence */ +#define ELIBMAX 123 /* Atmpt to link in too many shared libs */ +#define ELIBSCN 124 /* .lib section in a.out corrupted */ + +#define ENOMEDIUM 125 /* No medium found */ +#define EMEDIUMTYPE 126 /* Wrong medium type */ +#define ECANCELED 127 /* Operation Cancelled */ +#define ENOKEY 128 /* Required key not available */ +#define EKEYEXPIRED 129 /* Key has expired */ +#define EKEYREVOKED 130 /* Key has been revoked */ +#define EKEYREJECTED 131 /* Key was rejected by service */ + +/* for robust mutexes */ +#define EOWNERDEAD 132 /* Owner died */ +#define ENOTRECOVERABLE 133 /* State not recoverable */ + +#define ERFKILL 134 /* Operation not possible due to RF-kill */ + +#define EHWPOISON 135 /* Memory page has hardware error */ + +#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 @@ +#ifndef _SPARC_FCNTL_H +#define _SPARC_FCNTL_H + +#define O_APPEND 0x0008 +#define FASYNC 0x0040 /* fcntl, for BSD compatibility */ +#define O_CREAT 0x0200 /* not fcntl */ +#define O_TRUNC 0x0400 /* not fcntl */ +#define O_EXCL 0x0800 /* not fcntl */ +#define O_DSYNC 0x2000 /* used to be O_SYNC, see below */ +#define O_NONBLOCK 0x4000 +#if defined(__sparc__) && defined(__arch64__) +#define O_NDELAY 0x0004 +#else +#define O_NDELAY (0x0004 | O_NONBLOCK) +#endif +#define O_NOCTTY 0x8000 /* not fcntl */ +#define O_LARGEFILE 0x40000 +#define O_DIRECT 0x100000 /* direct disk access hint */ +#define O_NOATIME 0x200000 +#define O_CLOEXEC 0x400000 +/* + * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using + * the O_SYNC flag. We continue to use the existing numerical value + * for O_DSYNC semantics now, but using the correct symbolic name for it. + * This new value is used to request true Posix O_SYNC semantics. It is + * defined in this strange way to make sure applications compiled against + * new headers get at least O_DSYNC semantics on older kernels. + * + * This has the nice side-effect that we can simply test for O_DSYNC + * wherever we do not care if O_DSYNC or O_SYNC is used. + * + * Note: __O_SYNC must never be used directly. + */ +#define __O_SYNC 0x800000 +#define O_SYNC (__O_SYNC|O_DSYNC) + +#define O_PATH 0x1000000 + +#define F_GETOWN 5 /* for sockets. */ +#define F_SETOWN 6 /* for sockets. */ +#define F_GETLK 7 +#define F_SETLK 8 +#define F_SETLKW 9 + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 1 +#define F_WRLCK 2 +#define F_UNLCK 3 + +#define __ARCH_FLOCK_PAD short __unused; +#define __ARCH_FLOCK64_PAD short __unused; + +#include + +#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 @@ +/* + * fixmap.h: compile-time virtual memory allocation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998 Ingo Molnar + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + +#ifndef _ASM_FIXMAP_H +#define _ASM_FIXMAP_H + +#include +#include +#ifdef CONFIG_HIGHMEM +#include +#include +#endif + +/* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. We allocate these special addresses + * from the top of unused virtual memory (0xfd000000 - 1 page) backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * these 'compile-time allocated' memory buffers are + * fixed-size 4k pages. (or larger if used with an increment + * highger than 1) use fixmap_set(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ + +/* + * on UP currently we will have no trace of the fixmap mechanism, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ +enum fixed_addresses { + FIX_HOLE, +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, +#endif + __end_of_fixed_addresses +}; + +extern void __set_fixmap (enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); + +#define set_fixmap(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL) +/* + * Some hardware wants to get fixmapped without caching. + */ +#define set_fixmap_nocache(idx, phys) \ + __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) +/* + * used by vmalloc.c. + * + * Leave one empty page between IO pages at 0xfd000000 and + * the start of the fixmap. + */ +#define FIXADDR_TOP (0xfcfff000UL) +#define FIXADDR_SIZE ((__end_of_fixed_addresses) << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) + +#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) + +extern void __this_fixmap_does_not_exist(void); + +/* + * 'index to address' translation. If anyone tries to use the idx + * directly without tranlation, we catch the bug with a NULL-deference + * kernel oops. Illegal ranges of incoming indices are caught too. + */ +static inline unsigned long fix_to_virt(const unsigned int idx) +{ + /* + * this branch gets completely eliminated after inlining, + * except when someone tries to use fixaddr indices in an + * illegal way. (such as mixing up address types or using + * out-of-range indices). + * + * If it doesn't get removed, the linker will complain + * loudly with a reasonably clear error message.. + */ + if (idx >= __end_of_fixed_addresses) + __this_fixmap_does_not_exist(); + + return __fix_to_virt(idx); +} + +static inline unsigned long virt_to_fix(const unsigned long vaddr) +{ + BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); + return __virt_to_fix(vaddr); +} + +#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 @@ +#ifndef _SPARC_IOCTL_H +#define _SPARC_IOCTL_H + +/* + * Our DIR and SIZE overlap in order to simulteneously provide + * a non-zero _IOC_NONE (for binary compatibility) and + * 14 bits of size as on i386. Here's the layout: + * + * 0xE0000000 DIR + * 0x80000000 DIR = WRITE + * 0x40000000 DIR = READ + * 0x20000000 DIR = NONE + * 0x3FFF0000 SIZE (overlaps NONE bit) + * 0x0000FF00 TYPE + * 0x000000FF NR (CMD) + */ + +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 13 /* Actually 14, see below. */ +#define _IOC_DIRBITS 3 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_XSIZEMASK ((1 << (_IOC_SIZEBITS+1))-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) + +#define _IOC_NONE 1U +#define _IOC_READ 2U +#define _IOC_WRITE 4U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* Used to decode ioctl numbers in drivers despite the leading underscore... */ +#define _IOC_DIR(nr) \ + ( (((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) != 0)? \ + (((nr) >> _IOC_DIRSHIFT) & (_IOC_WRITE|_IOC_READ)): \ + (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) ) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) \ + ((((((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) & (_IOC_WRITE|_IOC_READ)) == 0)? \ + 0: (((nr) >> _IOC_SIZESHIFT) & _IOC_XSIZEMASK)) + +/* ...and for the PCMCIA and sound. */ +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_XSIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#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 @@ +#ifndef __SPARC_IPCBUF_H +#define __SPARC_IPCBUF_H + +/* + * The ipc64_perm structure for sparc/sparc64 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit seq + * - on sparc for 32 bit mode (it is 32 bit on sparc64) + * - 2 miscellaneous 64-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_uid_t cuid; + __kernel_gid_t cgid; +#ifndef __arch64__ + unsigned short __pad0; +#endif + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned long long __unused1; + unsigned long long __unused2; +}; + +#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 @@ +/* + * jsflash.h: OS Flash SIMM support for JavaStations. + * + * Copyright (C) 1999 Pete Zaitcev + */ + +#ifndef _SPARC_JSFLASH_H +#define _SPARC_JSFLASH_H + +#ifndef _SPARC_TYPES_H +#include +#endif + +/* + * Semantics of the offset is a full address. + * Hardcode it or get it from probe ioctl. + * + * We use full bus address, so that we would be + * automatically compatible with possible future systems. + */ + +#define JSFLASH_IDENT (('F'<<8)|54) +struct jsflash_ident_arg { + __u64 off; /* 0x20000000 is included */ + __u32 size; + char name[32]; /* With trailing zero */ +}; + +#define JSFLASH_ERASE (('F'<<8)|55) +/* Put 0 as argument, may be flags or sector number... */ + +#define JSFLASH_PROGRAM (('F'<<8)|56) +struct jsflash_program_arg { + __u64 data; /* char* for sparc and sparc64 */ + __u64 off; + __u32 size; +}; + +#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 @@ +#ifndef _SPARC64_MEMBLOCK_H +#define _SPARC64_MEMBLOCK_H + +#include + +#define MEMBLOCK_DBG(fmt...) prom_printf(fmt) + +#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 @@ +#ifndef _SPARC_MEMREG_H +#define _SPARC_MEMREG_H +/* memreg.h: Definitions of the values found in the synchronous + * and asynchronous memory error registers when a fault + * occurs on the sun4c. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +/* First the synchronous error codes, these are usually just + * normal page faults. + */ + +#define SUN4C_SYNC_WDRESET 0x0001 /* watchdog reset */ +#define SUN4C_SYNC_SIZE 0x0002 /* bad access size? whuz this? */ +#define SUN4C_SYNC_PARITY 0x0008 /* bad ram chips caused a parity error */ +#define SUN4C_SYNC_SBUS 0x0010 /* the SBUS had some problems... */ +#define SUN4C_SYNC_NOMEM 0x0020 /* translation to non-existent ram */ +#define SUN4C_SYNC_PROT 0x0040 /* access violated pte protections */ +#define SUN4C_SYNC_NPRESENT 0x0080 /* pte said that page was not present */ +#define SUN4C_SYNC_BADWRITE 0x8000 /* while writing something went bogus */ + +#define SUN4C_SYNC_BOLIXED \ + (SUN4C_SYNC_WDRESET | SUN4C_SYNC_SIZE | SUN4C_SYNC_SBUS | \ + SUN4C_SYNC_NOMEM | SUN4C_SYNC_PARITY) + +/* Now the asynchronous error codes, these are almost always produced + * by the cache writing things back to memory and getting a bad translation. + * Bad DVMA transactions can cause these faults too. + */ + +#define SUN4C_ASYNC_BADDVMA 0x0010 /* error during DVMA access */ +#define SUN4C_ASYNC_NOMEM 0x0020 /* write back pointed to bad phys addr */ +#define SUN4C_ASYNC_BADWB 0x0080 /* write back points to non-present page */ + +/* Memory parity error register with associated bit constants. */ +#ifndef __ASSEMBLY__ +extern __volatile__ unsigned long __iomem *sun4c_memerr_reg; +#endif + +#define SUN4C_MPE_ERROR 0x80 /* Parity error detected. (ro) */ +#define SUN4C_MPE_MULTI 0x40 /* Multiple parity errors detected. (ro) */ +#define SUN4C_MPE_TEST 0x20 /* Write inverse parity. (rw) */ +#define SUN4C_MPE_CHECK 0x10 /* Enable parity checking. (rw) */ +#define SUN4C_MPE_ERR00 0x08 /* Parity error in bits 0-7. (ro) */ +#define SUN4C_MPE_ERR08 0x04 /* Parity error in bits 8-15. (ro) */ +#define SUN4C_MPE_ERR16 0x02 /* Parity error in bits 16-23. (ro) */ +#define SUN4C_MPE_ERR24 0x01 /* Parity error in bits 24-31. (ro) */ +#define SUN4C_MPE_ERRS 0x0F /* Bit mask for the error bits. (ro) */ + +#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 @@ +#ifndef __SPARC_MODULE_H +#define __SPARC_MODULE_H +struct mod_arch_specific { }; + +/* + * Use some preprocessor magic to define the correct symbol + * for sparc32 and sparc64. + * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64 + */ +#define ___ELF(a, b, c) a##b##c +#define __ELF(a, b, c) ___ELF(a, b, c) +#define _Elf(t) __ELF(Elf, CONFIG_BITS, t) +#define _ELF(t) __ELF(ELF, CONFIG_BITS, t) + +#define Elf_Shdr _Elf(_Shdr) +#define Elf_Sym _Elf(_Sym) +#define Elf_Ehdr _Elf(_Ehdr) +#define Elf_Rela _Elf(_Rela) +#define Elf_Addr _Elf(_Addr) + +#define ELF_R_SYM _ELF(_R_SYM) +#define ELF_R_TYPE _ELF(_R_TYPE) + +#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 @@ +/* + * mpmbox.h: Interface and defines for the OpenProm mailbox + * facilities for MP machines under Linux. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_MPMBOX_H +#define _SPARC_MPMBOX_H + +/* The prom allocates, for each CPU on the machine an unsigned + * byte in physical ram. You probe the device tree prom nodes + * for these values. The purpose of this byte is to be able to + * pass messages from one cpu to another. + */ + +/* These are the main message types we have to look for in our + * Cpu mailboxes, based upon these values we decide what course + * of action to take. + */ + +/* The CPU is executing code in the kernel. */ +#define MAILBOX_ISRUNNING 0xf0 + +/* Another CPU called romvec->pv_exit(), you should call + * prom_stopcpu() when you see this in your mailbox. + */ +#define MAILBOX_EXIT 0xfb + +/* Another CPU called romvec->pv_enter(), you should call + * prom_cpuidle() when this is seen. + */ +#define MAILBOX_GOSPIN 0xfc + +/* Another CPU has hit a breakpoint either into kadb or the prom + * itself. Just like MAILBOX_GOSPIN, you should call prom_cpuidle() + * at this point. + */ +#define MAILBOX_BPT_SPIN 0xfd + +/* Oh geese, some other nitwit got a damn watchdog reset. The party's + * over so go call prom_stopcpu(). + */ +#define MAILBOX_WDOG_STOP 0xfe + +#ifndef __ASSEMBLY__ + +/* Handy macro's to determine a cpu's state. */ + +/* Is the cpu still in Power On Self Test? */ +#define MBOX_POST_P(letter) ((letter) >= 0x00 && (letter) <= 0x7f) + +/* Is the cpu at the 'ok' prompt of the PROM? */ +#define MBOX_PROMPROMPT_P(letter) ((letter) >= 0x80 && (letter) <= 0x8f) + +/* Is the cpu spinning in the PROM? */ +#define MBOX_PROMSPIN_P(letter) ((letter) >= 0x90 && (letter) <= 0xef) + +/* Sanity check... This is junk mail, throw it out. */ +#define MBOX_BOGON_P(letter) ((letter) >= 0xf1 && (letter) <= 0xfa) + +/* Is the cpu actively running an application/kernel-code? */ +#define MBOX_RUNNING_P(letter) ((letter) == MAILBOX_ISRUNNING) + +#endif /* !(__ASSEMBLY__) */ + +#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 @@ +#ifndef _SPARC_MSGBUF_H +#define _SPARC_MSGBUF_H + +/* + * The msqid64_ds structure for sparc64 architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +#if defined(__sparc__) && defined(__arch64__) +# define PADDING(x) +#else +# define PADDING(x) unsigned int x; +#endif + + +struct msqid64_ds { + struct ipc64_perm msg_perm; + PADDING(__pad1) + __kernel_time_t msg_stime; /* last msgsnd time */ + PADDING(__pad2) + __kernel_time_t msg_rtime; /* last msgrcv time */ + PADDING(__pad3) + __kernel_time_t msg_ctime; /* last change time */ + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused1; + unsigned long __unused2; +}; +#undef PADDING +#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 @@ +#ifndef _SPARC_OPENPROMIO_H +#define _SPARC_OPENPROMIO_H + +#include +#include +#include + +/* + * SunOS and Solaris /dev/openprom definitions. The ioctl values + * were chosen to be exactly equal to the SunOS equivalents. + */ + +struct openpromio +{ + u_int oprom_size; /* Actual size of the oprom_array. */ + char oprom_array[1]; /* Holds property names and values. */ +}; + +#define OPROMMAXPARAM 4096 /* Maximum size of oprom_array. */ + +#define OPROMGETOPT 0x20004F01 +#define OPROMSETOPT 0x20004F02 +#define OPROMNXTOPT 0x20004F03 +#define OPROMSETOPT2 0x20004F04 +#define OPROMNEXT 0x20004F05 +#define OPROMCHILD 0x20004F06 +#define OPROMGETPROP 0x20004F07 +#define OPROMNXTPROP 0x20004F08 +#define OPROMU2P 0x20004F09 +#define OPROMGETCONS 0x20004F0A +#define OPROMGETFBNAME 0x20004F0B +#define OPROMGETBOOTARGS 0x20004F0C +/* Linux extensions */ /* Arguments in oprom_array: */ +#define OPROMSETCUR 0x20004FF0 /* int node - Sets current node */ +#define OPROMPCI2NODE 0x20004FF1 /* int pci_bus, pci_devfn - Sets current node to PCI device's node */ +#define OPROMPATH2NODE 0x20004FF2 /* char path[] - Set current node from fully qualified PROM path */ + +/* + * Return values from OPROMGETCONS: + */ + +#define OPROMCONS_NOT_WSCONS 0 +#define OPROMCONS_STDIN_IS_KBD 0x1 /* stdin device is kbd */ +#define OPROMCONS_STDOUT_IS_FB 0x2 /* stdout is a framebuffer */ +#define OPROMCONS_OPENPROM 0x4 /* supports openboot */ + + +/* + * NetBSD/OpenBSD /dev/openprom definitions. + */ + +struct opiocdesc +{ + int op_nodeid; /* PROM Node ID (value-result) */ + int op_namelen; /* Length of op_name. */ + char __user *op_name; /* Pointer to the property name. */ + int op_buflen; /* Length of op_buf (value-result) */ + char __user *op_buf; /* Pointer to buffer. */ +}; + +#define OPIOCGET _IOWR('O', 1, struct opiocdesc) +#define OPIOCSET _IOW('O', 2, struct opiocdesc) +#define OPIOCNEXTPROP _IOWR('O', 3, struct opiocdesc) +#define OPIOCGETOPTNODE _IOR('O', 4, int) +#define OPIOCGETNEXT _IOWR('O', 5, int) +#define OPIOCGETCHILD _IOWR('O', 6, int) + +#endif /* _SPARC_OPENPROMIO_H */ + 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 @@ +#ifndef _ASMSPARC_PARAM_H +#define _ASMSPARC_PARAM_H + +#define EXEC_PAGESIZE 8192 /* Thanks for sun4's we carry baggage... */ +#include + +#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 @@ +/*---------------------------------------- + PERFORMANCE INSTRUMENTATION + Guillaume Thouvenin 08/10/98 + David S. Miller 10/06/98 + ---------------------------------------*/ +#ifndef PERF_COUNTER_API +#define PERF_COUNTER_API + +/* sys_perfctr() interface. First arg is operation code + * from enumeration below. The meaning of further arguments + * are determined by the operation code. + * + * NOTE: This system call is no longer provided, use the perf_events + * infrastructure. + * + * Pointers which are passed by the user are pointers to 64-bit + * integers. + * + * Once enabled, performance counter state is retained until the + * process either exits or performs an exec. That is, performance + * counters remain enabled for fork/clone children. + */ +enum perfctr_opcode { + /* Enable UltraSparc performance counters, ARG0 is pointer + * to 64-bit accumulator for D0 counter in PIC, ARG1 is pointer + * to 64-bit accumulator for D1 counter. ARG2 is a pointer to + * the initial PCR register value to use. + */ + PERFCTR_ON, + + /* Disable UltraSparc performance counters. The PCR is written + * with zero and the user counter accumulator pointers and + * working PCR register value are forgotten. + */ + PERFCTR_OFF, + + /* Add current D0 and D1 PIC values into user pointers given + * in PERFCTR_ON operation. The PIC is cleared before returning. + */ + PERFCTR_READ, + + /* Clear the PIC register. */ + PERFCTR_CLRPIC, + + /* Begin using a new PCR value, the pointer to which is passed + * in ARG0. The PIC is also cleared after the new PCR value is + * written. + */ + PERFCTR_SETPCR, + + /* Store in pointer given in ARG0 the current PCR register value + * being used. + */ + PERFCTR_GETPCR +}; + +/* I don't want the kernel's namespace to be polluted with this + * stuff when this file is included. --DaveM + */ +#ifndef __KERNEL__ + +#define PRIV 0x00000001 +#define SYS 0x00000002 +#define USR 0x00000004 + +/* Pic.S0 Selection Bit Field Encoding, Ultra-I/II */ +#define CYCLE_CNT 0x00000000 +#define INSTR_CNT 0x00000010 +#define DISPATCH0_IC_MISS 0x00000020 +#define DISPATCH0_STOREBUF 0x00000030 +#define IC_REF 0x00000080 +#define DC_RD 0x00000090 +#define DC_WR 0x000000A0 +#define LOAD_USE 0x000000B0 +#define EC_REF 0x000000C0 +#define EC_WRITE_HIT_RDO 0x000000D0 +#define EC_SNOOP_INV 0x000000E0 +#define EC_RD_HIT 0x000000F0 + +/* Pic.S0 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT 0x00000000 +#define US3_INSTR_CNT 0x00000010 +#define US3_DISPATCH0_IC_MISS 0x00000020 +#define US3_DISPATCH0_BR_TGT 0x00000030 +#define US3_DISPATCH0_2ND_BR 0x00000040 +#define US3_RSTALL_STOREQ 0x00000050 +#define US3_RSTALL_IU_USE 0x00000060 +#define US3_IC_REF 0x00000080 +#define US3_DC_RD 0x00000090 +#define US3_DC_WR 0x000000a0 +#define US3_EC_REF 0x000000c0 +#define US3_EC_WR_HIT_RTO 0x000000d0 +#define US3_EC_SNOOP_INV 0x000000e0 +#define US3_EC_RD_MISS 0x000000f0 +#define US3_PC_PORT0_RD 0x00000100 +#define US3_SI_SNOOP 0x00000110 +#define US3_SI_CIQ_FLOW 0x00000120 +#define US3_SI_OWNED 0x00000130 +#define US3_SW_COUNT_0 0x00000140 +#define US3_IU_BR_MISS_TAKEN 0x00000150 +#define US3_IU_BR_COUNT_TAKEN 0x00000160 +#define US3_DISP_RS_MISPRED 0x00000170 +#define US3_FA_PIPE_COMPL 0x00000180 +#define US3_MC_READS_0 0x00000200 +#define US3_MC_READS_1 0x00000210 +#define US3_MC_READS_2 0x00000220 +#define US3_MC_READS_3 0x00000230 +#define US3_MC_STALLS_0 0x00000240 +#define US3_MC_STALLS_2 0x00000250 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-I/II */ +#define CYCLE_CNT_D1 0x00000000 +#define INSTR_CNT_D1 0x00000800 +#define DISPATCH0_IC_MISPRED 0x00001000 +#define DISPATCH0_FP_USE 0x00001800 +#define IC_HIT 0x00004000 +#define DC_RD_HIT 0x00004800 +#define DC_WR_HIT 0x00005000 +#define LOAD_USE_RAW 0x00005800 +#define EC_HIT 0x00006000 +#define EC_WB 0x00006800 +#define EC_SNOOP_CB 0x00007000 +#define EC_IT_HIT 0x00007800 + +/* Pic.S1 Selection Bit Field Encoding, Ultra-III */ +#define US3_CYCLE_CNT_D1 0x00000000 +#define US3_INSTR_CNT_D1 0x00000800 +#define US3_DISPATCH0_MISPRED 0x00001000 +#define US3_IC_MISS_CANCELLED 0x00001800 +#define US3_RE_ENDIAN_MISS 0x00002000 +#define US3_RE_FPU_BYPASS 0x00002800 +#define US3_RE_DC_MISS 0x00003000 +#define US3_RE_EC_MISS 0x00003800 +#define US3_IC_MISS 0x00004000 +#define US3_DC_RD_MISS 0x00004800 +#define US3_DC_WR_MISS 0x00005000 +#define US3_RSTALL_FP_USE 0x00005800 +#define US3_EC_MISSES 0x00006000 +#define US3_EC_WB 0x00006800 +#define US3_EC_SNOOP_CB 0x00007000 +#define US3_EC_IC_MISS 0x00007800 +#define US3_RE_PC_MISS 0x00008000 +#define US3_ITLB_MISS 0x00008800 +#define US3_DTLB_MISS 0x00009000 +#define US3_WC_MISS 0x00009800 +#define US3_WC_SNOOP_CB 0x0000a000 +#define US3_WC_SCRUBBED 0x0000a800 +#define US3_WC_WB_WO_READ 0x0000b000 +#define US3_PC_SOFT_HIT 0x0000c000 +#define US3_PC_SNOOP_INV 0x0000c800 +#define US3_PC_HARD_HIT 0x0000d000 +#define US3_PC_PORT1_RD 0x0000d800 +#define US3_SW_COUNT_1 0x0000e000 +#define US3_IU_STAT_BR_MIS_UNTAKEN 0x0000e800 +#define US3_IU_STAT_BR_COUNT_UNTAKEN 0x0000f000 +#define US3_PC_MS_MISSES 0x0000f800 +#define US3_MC_WRITES_0 0x00010800 +#define US3_MC_WRITES_1 0x00011000 +#define US3_MC_WRITES_2 0x00011800 +#define US3_MC_WRITES_3 0x00012000 +#define US3_MC_STALLS_1 0x00012800 +#define US3_MC_STALLS_3 0x00013000 +#define US3_RE_RAW_MISS 0x00013800 +#define US3_FM_PIPE_COMPLETION 0x00014000 + +struct vcounter_struct { + unsigned long long vcnt0; + unsigned long long vcnt1; +}; + +#endif /* !(__KERNEL__) */ + +#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 @@ +/* + * pgtsun4.h: Sun4 specific pgtable.h defines and code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ +#ifndef _SPARC_PGTSUN4C_H +#define _SPARC_PGTSUN4C_H + +#include + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define SUN4C_PMD_SHIFT 23 + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define SUN4C_PGDIR_SHIFT 23 +#define SUN4C_PGDIR_SIZE (1UL << SUN4C_PGDIR_SHIFT) +#define SUN4C_PGDIR_MASK (~(SUN4C_PGDIR_SIZE-1)) +#define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK) + +/* To represent how the sun4c mmu really lays things out. */ +#define SUN4C_REAL_PGDIR_SHIFT 18 +#define SUN4C_REAL_PGDIR_SIZE (1UL << SUN4C_REAL_PGDIR_SHIFT) +#define SUN4C_REAL_PGDIR_MASK (~(SUN4C_REAL_PGDIR_SIZE-1)) +#define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK) + +/* 19 bit PFN on sun4 */ +#define SUN4C_PFN_MASK 0x7ffff + +/* Don't increase these unless the structures in sun4c.c are fixed */ +#define SUN4C_MAX_SEGMAPS 256 +#define SUN4C_MAX_CONTEXTS 16 + +/* + * To be efficient, and not have to worry about allocating such + * a huge pgd, we make the kernel sun4c tables each hold 1024 + * entries and the pgd similarly just like the i386 tables. + */ +#define SUN4C_PTRS_PER_PTE 1024 +#define SUN4C_PTRS_PER_PMD 1 +#define SUN4C_PTRS_PER_PGD 1024 + +/* + * Sparc SUN4C pte fields. + */ +#define _SUN4C_PAGE_VALID 0x80000000 +#define _SUN4C_PAGE_SILENT_READ 0x80000000 /* synonym */ +#define _SUN4C_PAGE_DIRTY 0x40000000 +#define _SUN4C_PAGE_SILENT_WRITE 0x40000000 /* synonym */ +#define _SUN4C_PAGE_PRIV 0x20000000 /* privileged page */ +#define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ +#define _SUN4C_PAGE_PRESENT 0x08000000 /* implemented in software */ +#define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ +#define _SUN4C_PAGE_FILE 0x02000000 /* implemented in software */ +#define _SUN4C_PAGE_READ 0x00800000 /* implemented in software */ +#define _SUN4C_PAGE_WRITE 0x00400000 /* implemented in software */ +#define _SUN4C_PAGE_ACCESSED 0x00200000 /* implemented in software */ +#define _SUN4C_PAGE_MODIFIED 0x00100000 /* implemented in software */ + +#define _SUN4C_READABLE (_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\ + _SUN4C_PAGE_ACCESSED) +#define _SUN4C_WRITEABLE (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\ + _SUN4C_PAGE_MODIFIED) + +#define _SUN4C_PAGE_CHG_MASK (0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED) + +#define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_PRESENT) +#define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\ + _SUN4C_PAGE_WRITE) +#define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) +#define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) +#define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\ + _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV) + +/* SUN4C swap entry encoding + * + * We use 5 bits for the type and 19 for the offset. This gives us + * 32 swapfiles of 4GB each. Encoding looks like: + * + * RRRRRRRRooooooooooooooooooottttt + * fedcba9876543210fedcba9876543210 + * + * The top 8 bits are reserved for protection and status bits, especially + * FILE and PRESENT. + */ +#define SUN4C_SWP_TYPE_MASK 0x1f +#define SUN4C_SWP_OFF_MASK 0x7ffff +#define SUN4C_SWP_OFF_SHIFT 5 + +#ifndef __ASSEMBLY__ + +static inline unsigned long sun4c_get_synchronous_error(void) +{ + unsigned long sync_err; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_err) : + "r" (AC_SYNC_ERR), "i" (ASI_CONTROL)); + return sync_err; +} + +static inline unsigned long sun4c_get_synchronous_address(void) +{ + unsigned long sync_addr; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_addr) : + "r" (AC_SYNC_VA), "i" (ASI_CONTROL)); + return sync_addr; +} + +/* SUN4 pte, segmap, and context manipulation */ +static inline unsigned long sun4c_get_segmap(unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlduha [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_SEGMAP)); + return entry; +} + +static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry) +{ + __asm__ __volatile__("\n\tstha %1, [%0] %2; nop; nop; nop;\n\t" : : + "r" (addr), "r" (entry), + "i" (ASI_SEGMAP) + : "memory"); +} + +static inline unsigned long sun4c_get_pte(unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_PTE)); + return entry; +} + +static inline void sun4c_put_pte(unsigned long addr, unsigned long entry) +{ + __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : : + "r" (addr), + "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE) + : "memory"); +} + +static inline int sun4c_get_context(void) +{ + register int ctx; + + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : + "=r" (ctx) : + "r" (AC_CONTEXT), "i" (ASI_CONTROL)); + + return ctx; +} + +static inline int sun4c_set_context(int ctx) +{ + __asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : : + "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL) + : "memory"); + + return ctx; +} + +#endif /* !(__ASSEMBLY__) */ + +#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 @@ +/* + * pgtsun4c.h: Sun4c specific pgtable.h defines and code. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _SPARC_PGTSUN4C_H +#define _SPARC_PGTSUN4C_H + +#include + +/* PMD_SHIFT determines the size of the area a second-level page table can map */ +#define SUN4C_PMD_SHIFT 22 + +/* PGDIR_SHIFT determines what a third-level page table entry can map */ +#define SUN4C_PGDIR_SHIFT 22 +#define SUN4C_PGDIR_SIZE (1UL << SUN4C_PGDIR_SHIFT) +#define SUN4C_PGDIR_MASK (~(SUN4C_PGDIR_SIZE-1)) +#define SUN4C_PGDIR_ALIGN(addr) (((addr)+SUN4C_PGDIR_SIZE-1)&SUN4C_PGDIR_MASK) + +/* To represent how the sun4c mmu really lays things out. */ +#define SUN4C_REAL_PGDIR_SHIFT 18 +#define SUN4C_REAL_PGDIR_SIZE (1UL << SUN4C_REAL_PGDIR_SHIFT) +#define SUN4C_REAL_PGDIR_MASK (~(SUN4C_REAL_PGDIR_SIZE-1)) +#define SUN4C_REAL_PGDIR_ALIGN(addr) (((addr)+SUN4C_REAL_PGDIR_SIZE-1)&SUN4C_REAL_PGDIR_MASK) + +/* 16 bit PFN on sun4c */ +#define SUN4C_PFN_MASK 0xffff + +/* Don't increase these unless the structures in sun4c.c are fixed */ +#define SUN4C_MAX_SEGMAPS 256 +#define SUN4C_MAX_CONTEXTS 16 + +/* + * To be efficient, and not have to worry about allocating such + * a huge pgd, we make the kernel sun4c tables each hold 1024 + * entries and the pgd similarly just like the i386 tables. + */ +#define SUN4C_PTRS_PER_PTE 1024 +#define SUN4C_PTRS_PER_PMD 1 +#define SUN4C_PTRS_PER_PGD 1024 + +/* + * Sparc SUN4C pte fields. + */ +#define _SUN4C_PAGE_VALID 0x80000000 +#define _SUN4C_PAGE_SILENT_READ 0x80000000 /* synonym */ +#define _SUN4C_PAGE_DIRTY 0x40000000 +#define _SUN4C_PAGE_SILENT_WRITE 0x40000000 /* synonym */ +#define _SUN4C_PAGE_PRIV 0x20000000 /* privileged page */ +#define _SUN4C_PAGE_NOCACHE 0x10000000 /* non-cacheable page */ +#define _SUN4C_PAGE_PRESENT 0x08000000 /* implemented in software */ +#define _SUN4C_PAGE_IO 0x04000000 /* I/O page */ +#define _SUN4C_PAGE_FILE 0x02000000 /* implemented in software */ +#define _SUN4C_PAGE_READ 0x00800000 /* implemented in software */ +#define _SUN4C_PAGE_WRITE 0x00400000 /* implemented in software */ +#define _SUN4C_PAGE_ACCESSED 0x00200000 /* implemented in software */ +#define _SUN4C_PAGE_MODIFIED 0x00100000 /* implemented in software */ + +#define _SUN4C_READABLE (_SUN4C_PAGE_READ|_SUN4C_PAGE_SILENT_READ|\ + _SUN4C_PAGE_ACCESSED) +#define _SUN4C_WRITEABLE (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE|\ + _SUN4C_PAGE_MODIFIED) + +#define _SUN4C_PAGE_CHG_MASK (0xffff|_SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_MODIFIED) + +#define SUN4C_PAGE_NONE __pgprot(_SUN4C_PAGE_PRESENT) +#define SUN4C_PAGE_SHARED __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE|\ + _SUN4C_PAGE_WRITE) +#define SUN4C_PAGE_COPY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) +#define SUN4C_PAGE_READONLY __pgprot(_SUN4C_PAGE_PRESENT|_SUN4C_READABLE) +#define SUN4C_PAGE_KERNEL __pgprot(_SUN4C_READABLE|_SUN4C_WRITEABLE|\ + _SUN4C_PAGE_DIRTY|_SUN4C_PAGE_PRIV) + +/* SUN4C swap entry encoding + * + * We use 5 bits for the type and 19 for the offset. This gives us + * 32 swapfiles of 4GB each. Encoding looks like: + * + * RRRRRRRRooooooooooooooooooottttt + * fedcba9876543210fedcba9876543210 + * + * The top 8 bits are reserved for protection and status bits, especially + * FILE and PRESENT. + */ +#define SUN4C_SWP_TYPE_MASK 0x1f +#define SUN4C_SWP_OFF_MASK 0x7ffff +#define SUN4C_SWP_OFF_SHIFT 5 + +#ifndef __ASSEMBLY__ + +static inline unsigned long sun4c_get_synchronous_error(void) +{ + unsigned long sync_err; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_err) : + "r" (AC_SYNC_ERR), "i" (ASI_CONTROL)); + return sync_err; +} + +static inline unsigned long sun4c_get_synchronous_address(void) +{ + unsigned long sync_addr; + + __asm__ __volatile__("lda [%1] %2, %0\n\t" : + "=r" (sync_addr) : + "r" (AC_SYNC_VA), "i" (ASI_CONTROL)); + return sync_addr; +} + +/* SUN4C pte, segmap, and context manipulation */ +static inline unsigned long sun4c_get_segmap(unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_SEGMAP)); + + return entry; +} + +static inline void sun4c_put_segmap(unsigned long addr, unsigned long entry) +{ + + __asm__ __volatile__("\n\tstba %1, [%0] %2; nop; nop; nop;\n\t" : : + "r" (addr), "r" (entry), + "i" (ASI_SEGMAP) + : "memory"); +} + +static inline unsigned long sun4c_get_pte(unsigned long addr) +{ + register unsigned long entry; + + __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" : + "=r" (entry) : + "r" (addr), "i" (ASI_PTE)); + return entry; +} + +static inline void sun4c_put_pte(unsigned long addr, unsigned long entry) +{ + __asm__ __volatile__("\n\tsta %1, [%0] %2; nop; nop; nop;\n\t" : : + "r" (addr), + "r" ((entry & ~(_SUN4C_PAGE_PRESENT))), "i" (ASI_PTE) + : "memory"); +} + +static inline int sun4c_get_context(void) +{ + register int ctx; + + __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" : + "=r" (ctx) : + "r" (AC_CONTEXT), "i" (ASI_CONTROL)); + + return ctx; +} + +static inline int sun4c_set_context(int ctx) +{ + __asm__ __volatile__("\n\tstba %0, [%1] %2; nop; nop; nop;\n\t" : : + "r" (ctx), "r" (AC_CONTEXT), "i" (ASI_CONTROL) + : "memory"); + + return ctx; +} + +#endif /* !(__ASSEMBLY__) */ + +#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 @@ +#ifndef __SPARC_POLL_H +#define __SPARC_POLL_H + +#define POLLWRNORM POLLOUT +#define POLLWRBAND 256 +#define POLLMSG 512 +#define POLLREMOVE 1024 +#define POLLRDHUP 2048 + +#include + +#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 @@ +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +#ifndef __SPARC_POSIX_TYPES_H +#define __SPARC_POSIX_TYPES_H + +#if defined(__sparc__) && defined(__arch64__) +/* sparc 64 bit */ +typedef unsigned long __kernel_size_t; +typedef long __kernel_ssize_t; +typedef long __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_clock_t; +typedef int __kernel_pid_t; +typedef int __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned int __kernel_mode_t; +typedef unsigned short __kernel_umode_t; +typedef unsigned int __kernel_nlink_t; +typedef int __kernel_daddr_t; +typedef long __kernel_off_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef int __kernel_clockid_t; +typedef int __kernel_timer_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef __kernel_uid_t __kernel_uid32_t; +typedef __kernel_gid_t __kernel_gid32_t; + +typedef unsigned int __kernel_old_dev_t; + +/* Note this piece of asymmetry from the v9 ABI. */ +typedef int __kernel_suseconds_t; + +#else +/* sparc 32 bit */ + +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef long int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_umode_t; +typedef short __kernel_nlink_t; +typedef long __kernel_daddr_t; +typedef long __kernel_off_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; +typedef unsigned short __kernel_old_dev_t; +typedef int __kernel_clockid_t; +typedef int __kernel_timer_t; + +#endif /* defined(__sparc__) && defined(__arch64__) */ + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { + int val[2]; +} __kernel_fsid_t; + +#ifdef __KERNEL__ + +#undef __FD_SET +static inline void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] |= (1UL<<_rem); +} + +#undef __FD_CLR +static inline void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem); +} + +#undef __FD_ISSET +static inline int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p) +{ + unsigned long _tmp = fd / __NFDBITS; + unsigned long _rem = fd % __NFDBITS; + return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0; +} + +/* + * This will unroll the loop for the normal constant cases (8 or 32 longs, + * for 256 and 1024-bit fd_sets respectively) + */ +#undef __FD_ZERO +static inline void __FD_ZERO(__kernel_fd_set *p) +{ + unsigned long *tmp = p->fds_bits; + int i; + + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 32: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; + tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; + tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0; + tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0; + tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0; + tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0; + return; + case 16: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; + tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; + return; + case 8: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + return; + case 4: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + return; + } + } + i = __FDSET_LONGS; + while (i) { + i--; + *tmp = 0; + tmp++; + } +} + +#endif /* __KERNEL__ */ +#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 @@ +#ifndef _SPARC64_PSRCOMPAT_H +#define _SPARC64_PSRCOMPAT_H + +#include + +/* Old 32-bit PSR fields for the compatibility conversion code. */ +#define PSR_CWP 0x0000001f /* current window pointer */ +#define PSR_ET 0x00000020 /* enable traps field */ +#define PSR_PS 0x00000040 /* previous privilege level */ +#define PSR_S 0x00000080 /* current privilege level */ +#define PSR_PIL 0x00000f00 /* processor interrupt level */ +#define PSR_EF 0x00001000 /* enable floating point */ +#define PSR_EC 0x00002000 /* enable co-processor */ +#define PSR_SYSCALL 0x00004000 /* inside of a syscall */ +#define PSR_LE 0x00008000 /* SuperSparcII little-endian */ +#define PSR_ICC 0x00f00000 /* integer condition codes */ +#define PSR_C 0x00100000 /* carry bit */ +#define PSR_V 0x00200000 /* overflow bit */ +#define PSR_Z 0x00400000 /* zero bit */ +#define PSR_N 0x00800000 /* negative bit */ +#define PSR_VERS 0x0f000000 /* cpu-version field */ +#define PSR_IMPL 0xf0000000 /* cpu-implementation field */ + +#define PSR_V8PLUS 0xff000000 /* fake impl/ver, meaning a 64bit CPU is present */ +#define PSR_XCC 0x000f0000 /* if PSR_V8PLUS, this is %xcc */ + +static inline unsigned int tstate_to_psr(unsigned long tstate) +{ + return ((tstate & TSTATE_CWP) | + PSR_S | + ((tstate & TSTATE_ICC) >> 12) | + ((tstate & TSTATE_XCC) >> 20) | + ((tstate & TSTATE_SYSCALL) ? PSR_SYSCALL : 0) | + PSR_V8PLUS); +} + +static inline unsigned long psr_to_tstate_icc(unsigned int psr) +{ + unsigned long tstate = ((unsigned long)(psr & PSR_ICC)) << 12; + if ((psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS) + tstate |= ((unsigned long)(psr & PSR_XCC)) << 20; + return tstate; +} + +#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 @@ +#ifndef _SPARC64_PSTATE_H +#define _SPARC64_PSTATE_H + +#include + +/* The V9 PSTATE Register (with SpitFire extensions). + * + * ----------------------------------------------------------------------- + * | Resv | IG | MG | CLE | TLE | MM | RED | PEF | AM | PRIV | IE | AG | + * ----------------------------------------------------------------------- + * 63 12 11 10 9 8 7 6 5 4 3 2 1 0 + */ +#define PSTATE_IG _AC(0x0000000000000800,UL) /* Interrupt Globals. */ +#define PSTATE_MG _AC(0x0000000000000400,UL) /* MMU Globals. */ +#define PSTATE_CLE _AC(0x0000000000000200,UL) /* Current Little Endian.*/ +#define PSTATE_TLE _AC(0x0000000000000100,UL) /* Trap Little Endian. */ +#define PSTATE_MM _AC(0x00000000000000c0,UL) /* Memory Model. */ +#define PSTATE_TSO _AC(0x0000000000000000,UL) /* MM: TotalStoreOrder */ +#define PSTATE_PSO _AC(0x0000000000000040,UL) /* MM: PartialStoreOrder */ +#define PSTATE_RMO _AC(0x0000000000000080,UL) /* MM: RelaxedMemoryOrder*/ +#define PSTATE_RED _AC(0x0000000000000020,UL) /* Reset Error Debug. */ +#define PSTATE_PEF _AC(0x0000000000000010,UL) /* Floating Point Enable.*/ +#define PSTATE_AM _AC(0x0000000000000008,UL) /* Address Mask. */ +#define PSTATE_PRIV _AC(0x0000000000000004,UL) /* Privilege. */ +#define PSTATE_IE _AC(0x0000000000000002,UL) /* Interrupt Enable. */ +#define PSTATE_AG _AC(0x0000000000000001,UL) /* Alternate Globals. */ + +/* The V9 TSTATE Register (with SpitFire and Linux extensions). + * + * --------------------------------------------------------------------- + * | Resv | GL | CCR | ASI | %pil | PSTATE | Resv | CWP | + * --------------------------------------------------------------------- + * 63 43 42 40 39 32 31 24 23 20 19 8 7 5 4 0 + */ +#define TSTATE_GL _AC(0x0000070000000000,UL) /* Global reg level */ +#define TSTATE_CCR _AC(0x000000ff00000000,UL) /* Condition Codes. */ +#define TSTATE_XCC _AC(0x000000f000000000,UL) /* Condition Codes. */ +#define TSTATE_XNEG _AC(0x0000008000000000,UL) /* %xcc Negative. */ +#define TSTATE_XZERO _AC(0x0000004000000000,UL) /* %xcc Zero. */ +#define TSTATE_XOVFL _AC(0x0000002000000000,UL) /* %xcc Overflow. */ +#define TSTATE_XCARRY _AC(0x0000001000000000,UL) /* %xcc Carry. */ +#define TSTATE_ICC _AC(0x0000000f00000000,UL) /* Condition Codes. */ +#define TSTATE_INEG _AC(0x0000000800000000,UL) /* %icc Negative. */ +#define TSTATE_IZERO _AC(0x0000000400000000,UL) /* %icc Zero. */ +#define TSTATE_IOVFL _AC(0x0000000200000000,UL) /* %icc Overflow. */ +#define TSTATE_ICARRY _AC(0x0000000100000000,UL) /* %icc Carry. */ +#define TSTATE_ASI _AC(0x00000000ff000000,UL) /* AddrSpace ID. */ +#define TSTATE_PIL _AC(0x0000000000f00000,UL) /* %pil (Linux traps)*/ +#define TSTATE_PSTATE _AC(0x00000000000fff00,UL) /* PSTATE. */ +#define TSTATE_IG _AC(0x0000000000080000,UL) /* Interrupt Globals.*/ +#define TSTATE_MG _AC(0x0000000000040000,UL) /* MMU Globals. */ +#define TSTATE_CLE _AC(0x0000000000020000,UL) /* CurrLittleEndian. */ +#define TSTATE_TLE _AC(0x0000000000010000,UL) /* TrapLittleEndian. */ +#define TSTATE_MM _AC(0x000000000000c000,UL) /* Memory Model. */ +#define TSTATE_TSO _AC(0x0000000000000000,UL) /* MM: TSO */ +#define TSTATE_PSO _AC(0x0000000000004000,UL) /* MM: PSO */ +#define TSTATE_RMO _AC(0x0000000000008000,UL) /* MM: RMO */ +#define TSTATE_RED _AC(0x0000000000002000,UL) /* Reset Error Debug.*/ +#define TSTATE_PEF _AC(0x0000000000001000,UL) /* FPU Enable. */ +#define TSTATE_AM _AC(0x0000000000000800,UL) /* Address Mask. */ +#define TSTATE_PRIV _AC(0x0000000000000400,UL) /* Privilege. */ +#define TSTATE_IE _AC(0x0000000000000200,UL) /* Interrupt Enable. */ +#define TSTATE_AG _AC(0x0000000000000100,UL) /* Alternate Globals.*/ +#define TSTATE_SYSCALL _AC(0x0000000000000020,UL) /* in syscall trap */ +#define TSTATE_CWP _AC(0x000000000000001f,UL) /* Curr Win-Pointer. */ + +/* Floating-Point Registers State Register. + * + * -------------------------------- + * | Resv | FEF | DU | DL | + * -------------------------------- + * 63 3 2 1 0 + */ +#define FPRS_FEF _AC(0x0000000000000004,UL) /* FPU Enable. */ +#define FPRS_DU _AC(0x0000000000000002,UL) /* Dirty Upper. */ +#define FPRS_DL _AC(0x0000000000000001,UL) /* Dirty Lower. */ + +/* Version Register. + * + * ------------------------------------------------------ + * | MANUF | IMPL | MASK | Resv | MAXTL | Resv | MAXWIN | + * ------------------------------------------------------ + * 63 48 47 32 31 24 23 16 15 8 7 5 4 0 + */ +#define VERS_MANUF _AC(0xffff000000000000,UL) /* Manufacturer. */ +#define VERS_IMPL _AC(0x0000ffff00000000,UL) /* Implementation. */ +#define VERS_MASK _AC(0x00000000ff000000,UL) /* Mask Set Revision.*/ +#define VERS_MAXTL _AC(0x000000000000ff00,UL) /* Max Trap Level. */ +#define VERS_MAXWIN _AC(0x000000000000001f,UL) /* Max RegWindow Idx.*/ + +#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 @@ +/* + * resource.h: Resource definitions. + * + * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_RESOURCE_H +#define _SPARC_RESOURCE_H + +/* + * These two resource limit IDs have a Sparc/Linux-specific ordering, + * the rest comes from the generic header: + */ +#define RLIMIT_NOFILE 6 /* max number of open files */ +#define RLIMIT_NPROC 7 /* max number of processes */ + +#if defined(__sparc__) && defined(__arch64__) +/* Use generic version */ +#else +/* + * SuS says limits have to be unsigned. + * We make this unsigned, but keep the + * old value for compatibility: + */ +#define RLIM_INFINITY 0x7fffffff +#endif + +#include + +#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 @@ +#ifndef _SPARC_SEMBUF_H +#define _SPARC_SEMBUF_H + +/* + * The semid64_ds structure for sparc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ +#if defined(__sparc__) && defined(__arch64__) +# define PADDING(x) +#else +# define PADDING(x) unsigned int x; +#endif + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + PADDING(__pad1) + __kernel_time_t sem_otime; /* last semop time */ + PADDING(__pad2) + __kernel_time_t sem_ctime; /* last change time */ + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused1; + unsigned long __unused2; +}; +#undef PADDING + +#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 @@ +#ifndef _SPARC_SHMBUF_H +#define _SPARC_SHMBUF_H + +/* + * The shmid64_ds structure for sparc architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +#if defined(__sparc__) && defined(__arch64__) +# define PADDING(x) +#else +# define PADDING(x) unsigned int x; +#endif + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + PADDING(__pad1) + __kernel_time_t shm_atime; /* last attach time */ + PADDING(__pad2) + __kernel_time_t shm_dtime; /* last detach time */ + PADDING(__pad3) + __kernel_time_t shm_ctime; /* last change time */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused1; + unsigned long __unused2; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#undef PADDING + +#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 @@ +/* + * smpprim.h: SMP locking primitives on the Sparc + * + * God knows we won't be actually using this code for some time + * but I thought I'd write it since I knew how. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC_SMPPRIM_H +#define __SPARC_SMPPRIM_H + +/* Test and set the unsigned byte at ADDR to 1. Returns the previous + * value. On the Sparc we use the ldstub instruction since it is + * atomic. + */ + +static inline __volatile__ char test_and_set(void *addr) +{ + char state = 0; + + __asm__ __volatile__("ldstub [%0], %1 ! test_and_set\n\t" + "=r" (addr), "=r" (state) : + "0" (addr), "1" (state) : "memory"); + + return state; +} + +/* Initialize a spin-lock. */ +static inline __volatile__ smp_initlock(void *spinlock) +{ + /* Unset the lock. */ + *((unsigned char *) spinlock) = 0; + + return; +} + +/* This routine spins until it acquires the lock at ADDR. */ +static inline __volatile__ smp_lock(void *addr) +{ + while(test_and_set(addr) == 0xff) + ; + + /* We now have the lock */ + return; +} + +/* This routine releases the lock at ADDR. */ +static inline __volatile__ smp_unlock(void *addr) +{ + *((unsigned char *) addr) = 0; +} + +#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 @@ +#ifndef _ASM_SOCKET_H +#define _ASM_SOCKET_H + +#include + +/* For setsockopt(2) */ +#define SOL_SOCKET 0xffff + +#define SO_DEBUG 0x0001 +#define SO_PASSCRED 0x0002 +#define SO_REUSEADDR 0x0004 +#define SO_KEEPALIVE 0x0008 +#define SO_DONTROUTE 0x0010 +#define SO_BROADCAST 0x0020 +#define SO_PEERCRED 0x0040 +#define SO_LINGER 0x0080 +#define SO_OOBINLINE 0x0100 +/* To add :#define SO_REUSEPORT 0x0200 */ +#define SO_BSDCOMPAT 0x0400 +#define SO_RCVLOWAT 0x0800 +#define SO_SNDLOWAT 0x1000 +#define SO_RCVTIMEO 0x2000 +#define SO_SNDTIMEO 0x4000 +#define SO_ACCEPTCONN 0x8000 + +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 +#define SO_SNDBUFFORCE 0x100a +#define SO_RCVBUFFORCE 0x100b +#define SO_ERROR 0x1007 +#define SO_TYPE 0x1008 +#define SO_PROTOCOL 0x1028 +#define SO_DOMAIN 0x1029 + + +/* Linux specific, keep the same. */ +#define SO_NO_CHECK 0x000b +#define SO_PRIORITY 0x000c + +#define SO_BINDTODEVICE 0x000d + +#define SO_ATTACH_FILTER 0x001a +#define SO_DETACH_FILTER 0x001b + +#define SO_PEERNAME 0x001c +#define SO_TIMESTAMP 0x001d +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_PEERSEC 0x001e +#define SO_PASSSEC 0x001f +#define SO_TIMESTAMPNS 0x0021 +#define SCM_TIMESTAMPNS SO_TIMESTAMPNS + +#define SO_MARK 0x0022 + +#define SO_TIMESTAMPING 0x0023 +#define SCM_TIMESTAMPING SO_TIMESTAMPING + +#define SO_RXQ_OVFL 0x0024 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 0x5001 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 +#define SO_SECURITY_ENCRYPTION_NETWORK 0x5004 + +#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 @@ +#ifndef _ASM_SPARC_SOCKIOS_H +#define _ASM_SPARC_SOCKIOS_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ +#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ + +#endif /* !(_ASM_SPARC_SOCKIOS_H) */ + 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 @@ +#ifndef __SPARC_STAT_H +#define __SPARC_STAT_H + +#include + +#if defined(__sparc__) && defined(__arch64__) +/* 64 bit sparc */ +struct stat { + unsigned st_dev; + ino_t st_ino; + mode_t st_mode; + short st_nlink; + uid_t st_uid; + gid_t st_gid; + unsigned st_rdev; + off_t st_size; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; + off_t st_blksize; + off_t st_blocks; + unsigned long __unused4[2]; +}; + +struct stat64 { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + + unsigned long st_rdev; + long st_size; + long st_blksize; + long st_blocks; + + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + long __unused[3]; +}; + +#else +/* 32 bit sparc */ +struct stat { + unsigned short st_dev; + ino_t st_ino; + mode_t st_mode; + short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + off_t st_size; + time_t st_atime; + unsigned long st_atime_nsec; + time_t st_mtime; + unsigned long st_mtime_nsec; + time_t st_ctime; + unsigned long st_ctime_nsec; + off_t st_blksize; + off_t st_blocks; + unsigned long __unused4[2]; +}; + +#define STAT_HAVE_NSEC 1 + +struct stat64 { + unsigned long long st_dev; + + unsigned long long st_ino; + + unsigned int st_mode; + unsigned int st_nlink; + + unsigned int st_uid; + unsigned int st_gid; + + unsigned long long st_rdev; + + unsigned char __pad3[8]; + + long long st_size; + unsigned int st_blksize; + + unsigned char __pad4[8]; + unsigned int st_blocks; + + unsigned int st_atime; + unsigned int st_atime_nsec; + + unsigned int st_mtime; + unsigned int st_mtime_nsec; + + unsigned int st_ctime; + unsigned int st_ctime_nsec; + + unsigned int __unused4; + unsigned int __unused5; +}; +#endif /* defined(__sparc__) && defined(__arch64__) */ +#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 @@ +#ifndef ___ASM_SPARC_STATFS_H +#define ___ASM_SPARC_STATFS_H + +#include + +#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 @@ +#ifndef _SPARC_SWAB_H +#define _SPARC_SWAB_H + +#include +#include + +#if defined(__sparc__) && defined(__arch64__) +static inline __u16 __arch_swab16p(const __u16 *addr) +{ + __u16 ret; + + __asm__ __volatile__ ("lduha [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PL)); + return ret; +} +#define __arch_swab16p __arch_swab16p + +static inline __u32 __arch_swab32p(const __u32 *addr) +{ + __u32 ret; + + __asm__ __volatile__ ("lduwa [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PL)); + return ret; +} +#define __arch_swab32p __arch_swab32p + +static inline __u64 __arch_swab64p(const __u64 *addr) +{ + __u64 ret; + + __asm__ __volatile__ ("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (addr), "i" (ASI_PL)); + return ret; +} +#define __arch_swab64p __arch_swab64p + +#else +#define __SWAB_64_THRU_32__ +#endif /* defined(__sparc__) && defined(__arch64__) */ + +#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 @@ +/* + * sysen.h: Bit fields within the "System Enable" register accessed via + * the ASI_CONTROL address space at address AC_SYSENABLE. + * + * Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef _SPARC_SYSEN_H +#define _SPARC_SYSEN_H + +#define SENABLE_DVMA 0x20 /* enable dvma transfers */ +#define SENABLE_CACHE 0x10 /* enable VAC cache */ +#define SENABLE_RESET 0x04 /* reset whole machine, danger Will Robinson */ + +#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 @@ +#ifndef ___ASM_SPARC_SYSTEM_H +#define ___ASM_SPARC_SYSTEM_H +#if defined(__sparc__) && defined(__arch64__) +#include +#else +#include +#endif +#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 @@ +#ifndef __SPARC_SYSTEM_H +#define __SPARC_SYSTEM_H + +#include +#include /* NR_CPUS */ +#include + +#include +#include +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#include + +/* + * Sparc (general) CPU types + */ +enum sparc_cpu { + sun4 = 0x00, + sun4c = 0x01, + sun4m = 0x02, + sun4d = 0x03, + sun4e = 0x04, + sun4u = 0x05, /* V8 ploos ploos */ + sun_unknown = 0x06, + ap1000 = 0x07, /* almost a sun4m */ + sparc_leon = 0x08, /* Leon SoC */ +}; + +/* Really, userland should not be looking at any of this... */ +#ifdef __KERNEL__ + +extern enum sparc_cpu sparc_cpu_model; + +#define ARCH_SUN4C (sparc_cpu_model==sun4c) + +#define SUN4M_NCPUS 4 /* Architectural limit of sun4m. */ + +extern char reboot_command[]; + +extern struct thread_info *current_set[NR_CPUS]; + +extern unsigned long empty_bad_page; +extern unsigned long empty_bad_page_table; +extern unsigned long empty_zero_page; + +extern void sun_do_break(void); +extern int serial_console; +extern int stop_a_enabled; +extern int scons_pwroff; + +static inline int con_is_present(void) +{ + return serial_console ? 0 : 1; +} + +/* When a context switch happens we must flush all user windows so that + * the windows of the current process are flushed onto its stack. This + * way the windows are all clean for the next process and the stack + * frames are up to date. + */ +extern void flush_user_windows(void); +extern void kill_user_windows(void); +extern void synchronize_user_stack(void); +extern void fpsave(unsigned long *fpregs, unsigned long *fsr, + void *fpqueue, unsigned long *fpqdepth); + +#ifdef CONFIG_SMP +#define SWITCH_ENTER(prv) \ + do { \ + if (test_tsk_thread_flag(prv, TIF_USEDFPU)) { \ + put_psr(get_psr() | PSR_EF); \ + fpsave(&(prv)->thread.float_regs[0], &(prv)->thread.fsr, \ + &(prv)->thread.fpqueue[0], &(prv)->thread.fpqdepth); \ + clear_tsk_thread_flag(prv, TIF_USEDFPU); \ + (prv)->thread.kregs->psr &= ~PSR_EF; \ + } \ + } while(0) + +#define SWITCH_DO_LAZY_FPU(next) /* */ +#else +#define SWITCH_ENTER(prv) /* */ +#define SWITCH_DO_LAZY_FPU(nxt) \ + do { \ + if (last_task_used_math != (nxt)) \ + (nxt)->thread.kregs->psr&=~PSR_EF; \ + } while(0) +#endif + +extern void flushw_all(void); + +/* + * Flush windows so that the VM switch which follows + * would not pull the stack from under us. + * + * SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work) + * XXX WTF is the above comment? Found in late teen 2.4.x. + */ +#define prepare_arch_switch(next) do { \ + __asm__ __volatile__( \ + ".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \ + "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \ + "save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \ + "save %sp, -0x40, %sp\n\t" \ + "restore; restore; restore; restore; restore; restore; restore"); \ +} while(0) + + /* Much care has gone into this code, do not touch it. + * + * We need to loadup regs l0/l1 for the newly forked child + * case because the trap return path relies on those registers + * holding certain values, gcc is told that they are clobbered. + * Gcc needs registers for 3 values in and 1 value out, so we + * clobber every non-fixed-usage register besides l2/l3/o4/o5. -DaveM + * + * Hey Dave, that do not touch sign is too much of an incentive + * - Anton & Pete + */ +#define switch_to(prev, next, last) do { \ + SWITCH_ENTER(prev); \ + SWITCH_DO_LAZY_FPU(next); \ + cpumask_set_cpu(smp_processor_id(), mm_cpumask(next->active_mm)); \ + __asm__ __volatile__( \ + "sethi %%hi(here - 0x8), %%o7\n\t" \ + "mov %%g6, %%g3\n\t" \ + "or %%o7, %%lo(here - 0x8), %%o7\n\t" \ + "rd %%psr, %%g4\n\t" \ + "std %%sp, [%%g6 + %4]\n\t" \ + "rd %%wim, %%g5\n\t" \ + "wr %%g4, 0x20, %%psr\n\t" \ + "nop\n\t" \ + "std %%g4, [%%g6 + %3]\n\t" \ + "ldd [%2 + %3], %%g4\n\t" \ + "mov %2, %%g6\n\t" \ + ".globl patchme_store_new_current\n" \ +"patchme_store_new_current:\n\t" \ + "st %2, [%1]\n\t" \ + "wr %%g4, 0x20, %%psr\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "nop\n\t" /* LEON needs all 3 nops: load to %sp depends on CWP. */ \ + "ldd [%%g6 + %4], %%sp\n\t" \ + "wr %%g5, 0x0, %%wim\n\t" \ + "ldd [%%sp + 0x00], %%l0\n\t" \ + "ldd [%%sp + 0x38], %%i6\n\t" \ + "wr %%g4, 0x0, %%psr\n\t" \ + "nop\n\t" \ + "nop\n\t" \ + "jmpl %%o7 + 0x8, %%g0\n\t" \ + " ld [%%g3 + %5], %0\n\t" \ + "here:\n" \ + : "=&r" (last) \ + : "r" (&(current_set[hard_smp_processor_id()])), \ + "r" (task_thread_info(next)), \ + "i" (TI_KPSR), \ + "i" (TI_KSP), \ + "i" (TI_TASK) \ + : "g1", "g2", "g3", "g4", "g5", "g7", \ + "l0", "l1", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", \ + "o0", "o1", "o2", "o3", "o7"); \ + } while(0) + +/* XXX Change this if we ever use a PSO mode kernel. */ +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() +#define read_barrier_depends() do { } while(0) +#define set_mb(__var, __value) do { __var = __value; mb(); } while(0) +#define smp_mb() __asm__ __volatile__("":::"memory") +#define smp_rmb() __asm__ __volatile__("":::"memory") +#define smp_wmb() __asm__ __volatile__("":::"memory") +#define smp_read_barrier_depends() do { } while(0) + +#define nop() __asm__ __volatile__ ("nop") + +/* This has special calling conventions */ +#ifndef CONFIG_SMP +BTFIXUPDEF_CALL(void, ___xchg32, void) +#endif + +static inline unsigned long xchg_u32(__volatile__ unsigned long *m, unsigned long val) +{ +#ifdef CONFIG_SMP + __asm__ __volatile__("swap [%2], %0" + : "=&r" (val) + : "0" (val), "r" (m) + : "memory"); + return val; +#else + register unsigned long *ptr asm("g1"); + register unsigned long ret asm("g2"); + + ptr = (unsigned long *) m; + ret = val; + + /* Note: this is magic and the nop there is + really needed. */ + __asm__ __volatile__( + "mov %%o7, %%g4\n\t" + "call ___f____xchg32\n\t" + " nop\n\t" + : "=&r" (ret) + : "0" (ret), "r" (ptr) + : "g3", "g4", "g7", "memory", "cc"); + + return ret; +#endif +} + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +extern void __xchg_called_with_bad_pointer(void); + +static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, int size) +{ + switch (size) { + case 4: + return xchg_u32(ptr, x); + } + __xchg_called_with_bad_pointer(); + return x; +} + +/* Emulate cmpxchg() the same way we emulate atomics, + * by hashing the object address and indexing into an array + * of spinlocks to get a bit of performance... + * + * See arch/sparc/lib/atomic32.c for implementation. + * + * Cribbed from + */ +#define __HAVE_ARCH_CMPXCHG 1 + +/* bug catcher for when unsupported size is used - won't link */ +extern void __cmpxchg_called_with_bad_pointer(void); +/* we only need to support cmpxchg of a u32 on sparc */ +extern unsigned long __cmpxchg_u32(volatile u32 *m, u32 old, u32 new_); + +/* don't worry...optimizer will get rid of most of this */ +static inline unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32((u32 *)ptr, (u32)old, (u32)new_); + default: + __cmpxchg_called_with_bad_pointer(); + break; + } + return old; +} + +#define cmpxchg(ptr, o, n) \ +({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ +}) + +#include + +/* + * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make + * them available. + */ +#define cmpxchg_local(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ + (unsigned long)(n), sizeof(*(ptr)))) +#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) + +extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#define arch_align_stack(x) (x) + +#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 @@ +#ifndef __SPARC64_SYSTEM_H +#define __SPARC64_SYSTEM_H + +#include +#include +#include + +#ifndef __ASSEMBLY__ + +#include +#include + +/* + * Sparc (general) CPU types + */ +enum sparc_cpu { + sun4 = 0x00, + sun4c = 0x01, + sun4m = 0x02, + sun4d = 0x03, + sun4e = 0x04, + sun4u = 0x05, /* V8 ploos ploos */ + sun_unknown = 0x06, + ap1000 = 0x07, /* almost a sun4m */ +}; + +#define sparc_cpu_model sun4u + +/* This cannot ever be a sun4c :) That's just history. */ +#define ARCH_SUN4C 0 + +extern char reboot_command[]; + +/* These are here in an effort to more fully work around Spitfire Errata + * #51. Essentially, if a memory barrier occurs soon after a mispredicted + * branch, the chip can stop executing instructions until a trap occurs. + * Therefore, if interrupts are disabled, the chip can hang forever. + * + * It used to be believed that the memory barrier had to be right in the + * delay slot, but a case has been traced recently wherein the memory barrier + * was one instruction after the branch delay slot and the chip still hung. + * The offending sequence was the following in sym_wakeup_done() of the + * sym53c8xx_2 driver: + * + * call sym_ccb_from_dsa, 0 + * movge %icc, 0, %l0 + * brz,pn %o0, .LL1303 + * mov %o0, %l2 + * membar #LoadLoad + * + * The branch has to be mispredicted for the bug to occur. Therefore, we put + * the memory barrier explicitly into a "branch always, predicted taken" + * delay slot to avoid the problem case. + */ +#define membar_safe(type) \ +do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ + " membar " type "\n" \ + "1:\n" \ + : : : "memory"); \ +} while (0) + +/* The kernel always executes in TSO memory model these days, + * and furthermore most sparc64 chips implement more stringent + * memory ordering than required by the specifications. + */ +#define mb() membar_safe("#StoreLoad") +#define rmb() __asm__ __volatile__("":::"memory") +#define wmb() __asm__ __volatile__("":::"memory") + +#endif + +#define nop() __asm__ __volatile__ ("nop") + +#define read_barrier_depends() do { } while(0) +#define set_mb(__var, __value) \ + do { __var = __value; membar_safe("#StoreLoad"); } while(0) + +#ifdef CONFIG_SMP +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#else +#define smp_mb() __asm__ __volatile__("":::"memory") +#define smp_rmb() __asm__ __volatile__("":::"memory") +#define smp_wmb() __asm__ __volatile__("":::"memory") +#endif + +#define smp_read_barrier_depends() do { } while(0) + +#define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory") + +#define flushw_all() __asm__ __volatile__("flushw") + +/* Performance counter register access. */ +#define read_pcr(__p) __asm__ __volatile__("rd %%pcr, %0" : "=r" (__p)) +#define write_pcr(__p) __asm__ __volatile__("wr %0, 0x0, %%pcr" : : "r" (__p)) +#define read_pic(__p) __asm__ __volatile__("rd %%pic, %0" : "=r" (__p)) + +/* Blackbird errata workaround. See commentary in + * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt() + * for more information. + */ +#define write_pic(__p) \ + __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \ + " nop\n\t" \ + ".align 64\n" \ + "99:wr %0, 0x0, %%pic\n\t" \ + "rd %%pic, %%g0" : : "r" (__p)) +#define reset_pic() write_pic(0) + +#ifndef __ASSEMBLY__ + +extern void sun_do_break(void); +extern int stop_a_enabled; +extern int scons_pwroff; + +extern void fault_in_user_windows(void); +extern void synchronize_user_stack(void); + +extern void __flushw_user(void); +#define flushw_user() __flushw_user() + +#define flush_user_windows flushw_user +#define flush_register_windows flushw_all + +/* Don't hold the runqueue lock over context switch */ +#define __ARCH_WANT_UNLOCKED_CTXSW +#define prepare_arch_switch(next) \ +do { \ + flushw_all(); \ +} while (0) + + /* See what happens when you design the chip correctly? + * + * We tell gcc we clobber all non-fixed-usage registers except + * for l0/l1. It will use one for 'next' and the other to hold + * the output value of 'last'. 'next' is not referenced again + * past the invocation of switch_to in the scheduler, so we need + * not preserve it's value. Hairy, but it lets us remove 2 loads + * and 2 stores in this critical code path. -DaveM + */ +#define switch_to(prev, next, last) \ +do { flush_tlb_pending(); \ + save_and_clear_fpu(); \ + /* If you are tempted to conditionalize the following */ \ + /* so that ASI is only written if it changes, think again. */ \ + __asm__ __volatile__("wr %%g0, %0, %%asi" \ + : : "r" (__thread_flag_byte_ptr(task_thread_info(next))[TI_FLAG_BYTE_CURRENT_DS]));\ + trap_block[current_thread_info()->cpu].thread = \ + task_thread_info(next); \ + __asm__ __volatile__( \ + "mov %%g4, %%g7\n\t" \ + "stx %%i6, [%%sp + 2047 + 0x70]\n\t" \ + "stx %%i7, [%%sp + 2047 + 0x78]\n\t" \ + "rdpr %%wstate, %%o5\n\t" \ + "stx %%o6, [%%g6 + %6]\n\t" \ + "stb %%o5, [%%g6 + %5]\n\t" \ + "rdpr %%cwp, %%o5\n\t" \ + "stb %%o5, [%%g6 + %8]\n\t" \ + "wrpr %%g0, 15, %%pil\n\t" \ + "mov %4, %%g6\n\t" \ + "ldub [%4 + %8], %%g1\n\t" \ + "wrpr %%g1, %%cwp\n\t" \ + "ldx [%%g6 + %6], %%o6\n\t" \ + "ldub [%%g6 + %5], %%o5\n\t" \ + "ldub [%%g6 + %7], %%o7\n\t" \ + "wrpr %%o5, 0x0, %%wstate\n\t" \ + "ldx [%%sp + 2047 + 0x70], %%i6\n\t" \ + "ldx [%%sp + 2047 + 0x78], %%i7\n\t" \ + "ldx [%%g6 + %9], %%g4\n\t" \ + "wrpr %%g0, 14, %%pil\n\t" \ + "brz,pt %%o7, switch_to_pc\n\t" \ + " mov %%g7, %0\n\t" \ + "sethi %%hi(ret_from_syscall), %%g1\n\t" \ + "jmpl %%g1 + %%lo(ret_from_syscall), %%g0\n\t" \ + " nop\n\t" \ + ".globl switch_to_pc\n\t" \ + "switch_to_pc:\n\t" \ + : "=&r" (last), "=r" (current), "=r" (current_thread_info_reg), \ + "=r" (__local_per_cpu_offset) \ + : "0" (task_thread_info(next)), \ + "i" (TI_WSTATE), "i" (TI_KSP), "i" (TI_NEW_CHILD), \ + "i" (TI_CWP), "i" (TI_TASK) \ + : "cc", \ + "g1", "g2", "g3", "g7", \ + "l1", "l2", "l3", "l4", "l5", "l6", "l7", \ + "i0", "i1", "i2", "i3", "i4", "i5", \ + "o0", "o1", "o2", "o3", "o4", "o5", "o7"); \ +} while(0) + +static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) +{ + unsigned long tmp1, tmp2; + + __asm__ __volatile__( +" mov %0, %1\n" +"1: lduw [%4], %2\n" +" cas [%4], %2, %0\n" +" cmp %2, %0\n" +" bne,a,pn %%icc, 1b\n" +" mov %1, %0\n" + : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) + : "0" (val), "r" (m) + : "cc", "memory"); + return val; +} + +static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val) +{ + unsigned long tmp1, tmp2; + + __asm__ __volatile__( +" mov %0, %1\n" +"1: ldx [%4], %2\n" +" casx [%4], %2, %0\n" +" cmp %2, %0\n" +" bne,a,pn %%xcc, 1b\n" +" mov %1, %0\n" + : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) + : "0" (val), "r" (m) + : "cc", "memory"); + return val; +} + +#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +extern void __xchg_called_with_bad_pointer(void); + +static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, + int size) +{ + switch (size) { + case 4: + return xchg32(ptr, x); + case 8: + return xchg64(ptr, x); + } + __xchg_called_with_bad_pointer(); + return x; +} + +extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noreturn)); + +/* + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + */ + +#define __HAVE_ARCH_CMPXCHG 1 + +static inline unsigned long +__cmpxchg_u32(volatile int *m, int old, int new) +{ + __asm__ __volatile__("cas [%2], %3, %0" + : "=&r" (new) + : "0" (new), "r" (m), "r" (old) + : "memory"); + + return new; +} + +static inline unsigned long +__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) +{ + __asm__ __volatile__("casx [%2], %3, %0" + : "=&r" (new) + : "0" (new), "r" (m), "r" (old) + : "memory"); + + return new; +} + +/* This function doesn't exist, so you'll get a linker error + if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +static inline unsigned long +__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + case 8: + return __cmpxchg_u64(ptr, old, new); + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + +/* + * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make + * them available. + */ + +static inline unsigned long __cmpxchg_local(volatile void *ptr, + unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + case 8: return __cmpxchg(ptr, old, new, size); + default: + return __cmpxchg_local_generic(ptr, old, new, size); + } + + return old; +} + +#define cmpxchg_local(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr)))) +#define cmpxchg64_local(ptr, o, n) \ + ({ \ + BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ + cmpxchg_local((ptr), (o), (n)); \ + }) + +#endif /* !(__ASSEMBLY__) */ + +#define arch_align_stack(x) (x) + +#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 @@ +#ifndef _SPARC_TYPES_H +#define _SPARC_TYPES_H +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +#if defined(__sparc__) + +#include + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* defined(__sparc__) */ + +#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 @@ +/* + * uctx.h: Sparc64 {set,get}context() register state layouts. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#ifndef __SPARC64_UCTX_H +#define __SPARC64_UCTX_H + +#define MC_TSTATE 0 +#define MC_PC 1 +#define MC_NPC 2 +#define MC_Y 3 +#define MC_G1 4 +#define MC_G2 5 +#define MC_G3 6 +#define MC_G4 7 +#define MC_G5 8 +#define MC_G6 9 +#define MC_G7 10 +#define MC_O0 11 +#define MC_O1 12 +#define MC_O2 13 +#define MC_O3 14 +#define MC_O4 15 +#define MC_O5 16 +#define MC_O6 17 +#define MC_O7 18 +#define MC_NGREG 19 + +typedef unsigned long mc_greg_t; +typedef mc_greg_t mc_gregset_t[MC_NGREG]; + +#define MC_MAXFPQ 16 +struct mc_fq { + unsigned long *mcfq_addr; + unsigned int mcfq_insn; +}; + +struct mc_fpu { + union { + unsigned int sregs[32]; + unsigned long dregs[32]; + long double qregs[16]; + } mcfpu_fregs; + unsigned long mcfpu_fsr; + unsigned long mcfpu_fprs; + unsigned long mcfpu_gsr; + struct mc_fq *mcfpu_fq; + unsigned char mcfpu_qcnt; + unsigned char mcfpu_qentsz; + unsigned char mcfpu_enab; +}; +typedef struct mc_fpu mc_fpu_t; + +typedef struct { + mc_gregset_t mc_gregs; + mc_greg_t mc_fp; + mc_greg_t mc_i7; + mc_fpu_t mc_fpregs; +} mcontext_t; + +struct ucontext { + struct ucontext *uc_link; + unsigned long uc_flags; + sigset_t uc_sigmask; + mcontext_t uc_mcontext; +}; +typedef struct ucontext ucontext_t; + +#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 @@ +/* + * include/asm/utrap.h + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#ifndef __ASM_SPARC64_UTRAP_H +#define __ASM_SPARC64_UTRAP_H + +#define UT_INSTRUCTION_EXCEPTION 1 +#define UT_INSTRUCTION_ERROR 2 +#define UT_INSTRUCTION_PROTECTION 3 +#define UT_ILLTRAP_INSTRUCTION 4 +#define UT_ILLEGAL_INSTRUCTION 5 +#define UT_PRIVILEGED_OPCODE 6 +#define UT_FP_DISABLED 7 +#define UT_FP_EXCEPTION_IEEE_754 8 +#define UT_FP_EXCEPTION_OTHER 9 +#define UT_TAG_OVERVIEW 10 +#define UT_DIVISION_BY_ZERO 11 +#define UT_DATA_EXCEPTION 12 +#define UT_DATA_ERROR 13 +#define UT_DATA_PROTECTION 14 +#define UT_MEM_ADDRESS_NOT_ALIGNED 15 +#define UT_PRIVILEGED_ACTION 16 +#define UT_ASYNC_DATA_ERROR 17 +#define UT_TRAP_INSTRUCTION_16 18 +#define UT_TRAP_INSTRUCTION_17 19 +#define UT_TRAP_INSTRUCTION_18 20 +#define UT_TRAP_INSTRUCTION_19 21 +#define UT_TRAP_INSTRUCTION_20 22 +#define UT_TRAP_INSTRUCTION_21 23 +#define UT_TRAP_INSTRUCTION_22 24 +#define UT_TRAP_INSTRUCTION_23 25 +#define UT_TRAP_INSTRUCTION_24 26 +#define UT_TRAP_INSTRUCTION_25 27 +#define UT_TRAP_INSTRUCTION_26 28 +#define UT_TRAP_INSTRUCTION_27 29 +#define UT_TRAP_INSTRUCTION_28 30 +#define UT_TRAP_INSTRUCTION_29 31 +#define UT_TRAP_INSTRUCTION_30 32 +#define UT_TRAP_INSTRUCTION_31 33 + +#define UTH_NOCHANGE (-1) + +#ifndef __ASSEMBLY__ +typedef int utrap_entry_t; +typedef void *utrap_handler_t; +#endif /* __ASSEMBLY__ */ + +#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 @@ +#ifndef _SPARC_VAC_OPS_H +#define _SPARC_VAC_OPS_H + +/* vac-ops.h: Inline assembly routines to do operations on the Sparc + * VAC (virtual address cache) for the sun4c. + * + * Copyright (C) 1994, David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include + +/* The SUN4C models have a virtually addressed write-through + * cache. + * + * The cache tags are directly accessible through an ASI and + * each have the form: + * + * ------------------------------------------------------------ + * | MBZ | CONTEXT | WRITE | PRIV | VALID | MBZ | TagID | MBZ | + * ------------------------------------------------------------ + * 31 25 24 22 21 20 19 18 16 15 2 1 0 + * + * MBZ: These bits are either unused and/or reserved and should + * be written as zeroes. + * + * CONTEXT: Records the context to which this cache line belongs. + * + * WRITE: A copy of the writable bit from the mmu pte access bits. + * + * PRIV: A copy of the privileged bit from the pte access bits. + * + * VALID: If set, this line is valid, else invalid. + * + * TagID: Fourteen bits of tag ID. + * + * Every virtual address is seen by the cache like this: + * + * ---------------------------------------- + * | RESV | TagID | LINE | BYTE-in-LINE | + * ---------------------------------------- + * 31 30 29 16 15 4 3 0 + * + * RESV: Unused/reserved. + * + * TagID: Used to match the Tag-ID in that vac tags. + * + * LINE: Which line within the cache + * + * BYTE-in-LINE: Which byte within the cache line. + */ + +/* Sun4c VAC Tags */ +#define S4CVACTAG_CID 0x01c00000 +#define S4CVACTAG_W 0x00200000 +#define S4CVACTAG_P 0x00100000 +#define S4CVACTAG_V 0x00080000 +#define S4CVACTAG_TID 0x0000fffc + +/* Sun4c VAC Virtual Address */ +/* These aren't used, why bother? (Anton) */ +#if 0 +#define S4CVACVA_TID 0x3fff0000 +#define S4CVACVA_LINE 0x0000fff0 +#define S4CVACVA_BIL 0x0000000f +#endif + +/* The indexing of cache lines creates a problem. Because the line + * field of a virtual address extends past the page offset within + * the virtual address it is possible to have what are called + * 'bad aliases' which will create inconsistencies. So we must make + * sure that within a context that if a physical page is mapped + * more than once, that 'extra' line bits are the same. If this is + * not the case, and thus is a 'bad alias' we must turn off the + * cacheable bit in the pte's of all such pages. + */ + +#define S4CVAC_BADBITS 0x0000f000 + +/* The following is true if vaddr1 and vaddr2 would cause + * a 'bad alias'. + */ +#define S4CVAC_BADALIAS(vaddr1, vaddr2) \ + ((((unsigned long) (vaddr1)) ^ ((unsigned long) (vaddr2))) & \ + (S4CVAC_BADBITS)) + +/* The following structure describes the characteristics of a sun4c + * VAC as probed from the prom during boot time. + */ +struct sun4c_vac_props { + unsigned int num_bytes; /* Size of the cache */ + unsigned int do_hwflushes; /* Hardware flushing available? */ + unsigned int linesize; /* Size of each line in bytes */ + unsigned int log2lsize; /* log2(linesize) */ + unsigned int on; /* VAC is enabled */ +}; + +extern struct sun4c_vac_props sun4c_vacinfo; + +/* sun4c_enable_vac() enables the sun4c virtual address cache. */ +static inline void sun4c_enable_vac(void) +{ + __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" + "or %%g1, %2, %%g1\n\t" + "stba %%g1, [%0] %1\n\t" + : /* no outputs */ + : "r" ((unsigned int) AC_SENABLE), + "i" (ASI_CONTROL), "i" (SENABLE_CACHE) + : "g1", "memory"); + sun4c_vacinfo.on = 1; +} + +/* sun4c_disable_vac() disables the virtual address cache. */ +static inline void sun4c_disable_vac(void) +{ + __asm__ __volatile__("lduba [%0] %1, %%g1\n\t" + "andn %%g1, %2, %%g1\n\t" + "stba %%g1, [%0] %1\n\t" + : /* no outputs */ + : "r" ((unsigned int) AC_SENABLE), + "i" (ASI_CONTROL), "i" (SENABLE_CACHE) + : "g1", "memory"); + sun4c_vacinfo.on = 0; +} + +#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 @@ +/* + * + * watchdog - Driver interface for the hardware watchdog timers + * present on Sun Microsystems boardsets + * + * Copyright (c) 2000 Eric Brower + * + */ + +#ifndef _SPARC64_WATCHDOG_H +#define _SPARC64_WATCHDOG_H + +#include + +/* Solaris compatibility ioctls-- + * Ref. for standard linux watchdog ioctls + */ +#define WIOCSTART _IO (WATCHDOG_IOCTL_BASE, 10) /* Start Timer */ +#define WIOCSTOP _IO (WATCHDOG_IOCTL_BASE, 11) /* Stop Timer */ +#define WIOCGSTAT _IOR(WATCHDOG_IOCTL_BASE, 12, int)/* Get Timer Status */ + +/* Status flags from WIOCGSTAT ioctl + */ +#define WD_FREERUN 0x01 /* timer is running, interrupts disabled */ +#define WD_EXPIRED 0x02 /* timer has expired */ +#define WD_RUNNING 0x04 /* timer is running, interrupts enabled */ +#define WD_STOPPED 0x08 /* timer has not been started */ +#define WD_SERVICED 0x10 /* timer interrupt was serviced */ + +#endif /* ifndef _SPARC64_WATCHDOG_H */ + 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 @@ +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct task_struct init_task = INIT_TASK(init_task); +EXPORT_SYMBOL(init_task); + +/* .text section in head.S is aligned at 8k boundary and this gets linked + * right after that so that the init_thread_union is aligned properly as well. + * If this is not aligned on a 8k boundary, then you should change code + * in etrap.S which assumes it. + */ +union thread_union init_thread_union __init_task_data = + { 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 @@ +/* + * muldiv.c: Hardware multiply/division illegal instruction trap + * for sun4c/sun4 (which do not have those instructions) + * + * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * + * 2004-12-25 Krzysztof Helt (krzysztof.h1@wp.pl) + * - fixed registers constrains in inline assembly declarations + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "kernel.h" + +/* #define DEBUG_MULDIV */ + +static inline int has_imm13(int insn) +{ + return (insn & 0x2000); +} + +static inline int is_foocc(int insn) +{ + return (insn & 0x800000); +} + +static inline int sign_extend_imm13(int imm) +{ + return imm << 19 >> 19; +} + +static inline void advance(struct pt_regs *regs) +{ + regs->pc = regs->npc; + regs->npc += 4; +} + +static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2, + unsigned int rd) +{ + if(rs2 >= 16 || rs1 >= 16 || rd >= 16) { + /* Wheee... */ + __asm__ __volatile__("save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "save %sp, -0x40, %sp\n\t" + "restore; restore; restore; restore;\n\t" + "restore; restore; restore;\n\t"); + } +} + +#define fetch_reg(reg, regs) ({ \ + struct reg_window32 __user *win; \ + register unsigned long ret; \ + \ + if (!(reg)) ret = 0; \ + else if ((reg) < 16) { \ + ret = regs->u_regs[(reg)]; \ + } else { \ + /* Ho hum, the slightly complicated case. */ \ + win = (struct reg_window32 __user *)regs->u_regs[UREG_FP];\ + if (get_user (ret, &win->locals[(reg) - 16])) return -1;\ + } \ + ret; \ +}) + +static inline int +store_reg(unsigned int result, unsigned int reg, struct pt_regs *regs) +{ + struct reg_window32 __user *win; + + if (!reg) + return 0; + if (reg < 16) { + regs->u_regs[reg] = result; + return 0; + } else { + /* need to use put_user() in this case: */ + win = (struct reg_window32 __user *) regs->u_regs[UREG_FP]; + return (put_user(result, &win->locals[reg - 16])); + } +} + +/* Should return 0 if mul/div emulation succeeded and SIGILL should + * not be issued. + */ +int do_user_muldiv(struct pt_regs *regs, unsigned long pc) +{ + unsigned int insn; + int inst; + unsigned int rs1, rs2, rdv; + + if (!pc) + return -1; /* This happens to often, I think */ + if (get_user (insn, (unsigned int __user *)pc)) + return -1; + if ((insn & 0xc1400000) != 0x80400000) + return -1; + inst = ((insn >> 19) & 0xf); + if ((inst & 0xe) != 10 && (inst & 0xe) != 14) + return -1; + + /* Now we know we have to do something with umul, smul, udiv or sdiv */ + rs1 = (insn >> 14) & 0x1f; + rs2 = insn & 0x1f; + rdv = (insn >> 25) & 0x1f; + if (has_imm13(insn)) { + maybe_flush_windows(rs1, 0, rdv); + rs2 = sign_extend_imm13(insn); + } else { + maybe_flush_windows(rs1, rs2, rdv); + rs2 = fetch_reg(rs2, regs); + } + rs1 = fetch_reg(rs1, regs); + switch (inst) { + case 10: /* umul */ +#ifdef DEBUG_MULDIV + printk ("unsigned muldiv: 0x%x * 0x%x = ", rs1, rs2); +#endif + __asm__ __volatile__ ("\n\t" + "mov %0, %%o0\n\t" + "call .umul\n\t" + " mov %1, %%o1\n\t" + "mov %%o0, %0\n\t" + "mov %%o1, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "0" (rs1), "1" (rs2) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); +#ifdef DEBUG_MULDIV + printk ("0x%x%08x\n", rs2, rs1); +#endif + if (store_reg(rs1, rdv, regs)) + return -1; + regs->y = rs2; + break; + case 11: /* smul */ +#ifdef DEBUG_MULDIV + printk ("signed muldiv: 0x%x * 0x%x = ", rs1, rs2); +#endif + __asm__ __volatile__ ("\n\t" + "mov %0, %%o0\n\t" + "call .mul\n\t" + " mov %1, %%o1\n\t" + "mov %%o0, %0\n\t" + "mov %%o1, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "0" (rs1), "1" (rs2) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", "cc"); +#ifdef DEBUG_MULDIV + printk ("0x%x%08x\n", rs2, rs1); +#endif + if (store_reg(rs1, rdv, regs)) + return -1; + regs->y = rs2; + break; + case 14: /* udiv */ +#ifdef DEBUG_MULDIV + printk ("unsigned muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); +#endif + if (!rs2) { +#ifdef DEBUG_MULDIV + printk ("DIVISION BY ZERO\n"); +#endif + handle_hw_divzero (regs, pc, regs->npc, regs->psr); + return 0; + } + __asm__ __volatile__ ("\n\t" + "mov %2, %%o0\n\t" + "mov %0, %%o1\n\t" + "mov %%g0, %%o2\n\t" + "call __udivdi3\n\t" + " mov %1, %%o3\n\t" + "mov %%o1, %0\n\t" + "mov %%o0, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "r" (regs->y), "0" (rs1), "1" (rs2) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "cc"); +#ifdef DEBUG_MULDIV + printk ("0x%x\n", rs1); +#endif + if (store_reg(rs1, rdv, regs)) + return -1; + break; + case 15: /* sdiv */ +#ifdef DEBUG_MULDIV + printk ("signed muldiv: 0x%x%08x / 0x%x = ", regs->y, rs1, rs2); +#endif + if (!rs2) { +#ifdef DEBUG_MULDIV + printk ("DIVISION BY ZERO\n"); +#endif + handle_hw_divzero (regs, pc, regs->npc, regs->psr); + return 0; + } + __asm__ __volatile__ ("\n\t" + "mov %2, %%o0\n\t" + "mov %0, %%o1\n\t" + "mov %%g0, %%o2\n\t" + "call __divdi3\n\t" + " mov %1, %%o3\n\t" + "mov %%o1, %0\n\t" + "mov %%o0, %1\n\t" + : "=r" (rs1), "=r" (rs2) + : "r" (regs->y), "0" (rs1), "1" (rs2) + : "o0", "o1", "o2", "o3", "o4", "o5", "o7", + "g1", "g2", "g3", "cc"); +#ifdef DEBUG_MULDIV + printk ("0x%x\n", rs1); +#endif + if (store_reg(rs1, rdv, regs)) + return -1; + break; + } + if (is_foocc (insn)) { + regs->psr &= ~PSR_ICC; + if ((inst & 0xe) == 14) { + /* ?div */ + if (rs2) regs->psr |= PSR_V; + } + if (!rs1) regs->psr |= PSR_Z; + if (((int)rs1) < 0) regs->psr |= PSR_N; +#ifdef DEBUG_MULDIV + printk ("psr muldiv: %08x\n", regs->psr); +#endif + } + advance(regs); + return 0; +} 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 @@ +/* + * sun4c irq support + * + * djhr: Hacked out of irq.c into a CPU dependent version. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com) + * Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk) + */ + +#include + +#include +#include +#include +#include + +#include "irq.h" + +/* Sun4c interrupts are typically laid out as follows: + * + * 1 - Software interrupt, SBUS level 1 + * 2 - SBUS level 2 + * 3 - ESP SCSI, SBUS level 3 + * 4 - Software interrupt + * 5 - Lance ethernet, SBUS level 4 + * 6 - Software interrupt + * 7 - Graphics card, SBUS level 5 + * 8 - SBUS level 6 + * 9 - SBUS level 7 + * 10 - Counter timer + * 11 - Floppy + * 12 - Zilog uart + * 13 - CS4231 audio + * 14 - Profiling timer + * 15 - NMI + * + * The interrupt enable bits in the interrupt mask register are + * really only used to enable/disable the timer interrupts, and + * for signalling software interrupts. There is also a master + * interrupt enable bit in this register. + * + * Interrupts are enabled by setting the SUN4C_INT_* bits, they + * are disabled by clearing those bits. + */ + +/* + * Bit field defines for the interrupt registers on various + * Sparc machines. + */ + +/* The sun4c interrupt register. */ +#define SUN4C_INT_ENABLE 0x01 /* Allow interrupts. */ +#define SUN4C_INT_E14 0x80 /* Enable level 14 IRQ. */ +#define SUN4C_INT_E10 0x20 /* Enable level 10 IRQ. */ +#define SUN4C_INT_E8 0x10 /* Enable level 8 IRQ. */ +#define SUN4C_INT_E6 0x08 /* Enable level 6 IRQ. */ +#define SUN4C_INT_E4 0x04 /* Enable level 4 IRQ. */ +#define SUN4C_INT_E1 0x02 /* Enable level 1 IRQ. */ + +/* + * Pointer to the interrupt enable byte + * Used by entry.S + */ +unsigned char __iomem *interrupt_enable; + +static void sun4c_mask_irq(struct irq_data *data) +{ + unsigned long mask = (unsigned long)data->chip_data; + + if (mask) { + unsigned long flags; + + local_irq_save(flags); + mask = sbus_readb(interrupt_enable) & ~mask; + sbus_writeb(mask, interrupt_enable); + local_irq_restore(flags); + } +} + +static void sun4c_unmask_irq(struct irq_data *data) +{ + unsigned long mask = (unsigned long)data->chip_data; + + if (mask) { + unsigned long flags; + + local_irq_save(flags); + mask = sbus_readb(interrupt_enable) | mask; + sbus_writeb(mask, interrupt_enable); + local_irq_restore(flags); + } +} + +static unsigned int sun4c_startup_irq(struct irq_data *data) +{ + irq_link(data->irq); + sun4c_unmask_irq(data); + + return 0; +} + +static void sun4c_shutdown_irq(struct irq_data *data) +{ + sun4c_mask_irq(data); + irq_unlink(data->irq); +} + +static struct irq_chip sun4c_irq = { + .name = "sun4c", + .irq_startup = sun4c_startup_irq, + .irq_shutdown = sun4c_shutdown_irq, + .irq_mask = sun4c_mask_irq, + .irq_unmask = sun4c_unmask_irq, +}; + +static unsigned int sun4c_build_device_irq(struct platform_device *op, + unsigned int real_irq) +{ + unsigned int irq; + + if (real_irq >= 16) { + prom_printf("Bogus sun4c IRQ %u\n", real_irq); + prom_halt(); + } + + irq = irq_alloc(real_irq, real_irq); + if (irq) { + unsigned long mask = 0UL; + + switch (real_irq) { + case 1: + mask = SUN4C_INT_E1; + break; + case 8: + mask = SUN4C_INT_E8; + break; + case 10: + mask = SUN4C_INT_E10; + break; + case 14: + mask = SUN4C_INT_E14; + break; + default: + /* All the rest are either always enabled, + * or are for signalling software interrupts. + */ + break; + } + irq_set_chip_and_handler_name(irq, &sun4c_irq, + handle_level_irq, "level"); + irq_set_chip_data(irq, (void *)mask); + } + return irq; +} + +struct sun4c_timer_info { + u32 l10_count; + u32 l10_limit; + u32 l14_count; + u32 l14_limit; +}; + +static struct sun4c_timer_info __iomem *sun4c_timers; + +static void sun4c_clear_clock_irq(void) +{ + sbus_readl(&sun4c_timers->l10_limit); +} + +static void sun4c_load_profile_irq(int cpu, unsigned int limit) +{ + /* Errm.. not sure how to do this.. */ +} + +static void __init sun4c_init_timers(irq_handler_t counter_fn) +{ + const struct linux_prom_irqs *prom_irqs; + struct device_node *dp; + unsigned int irq; + const u32 *addr; + int err; + + dp = of_find_node_by_name(NULL, "counter-timer"); + if (!dp) { + prom_printf("sun4c_init_timers: Unable to find counter-timer\n"); + prom_halt(); + } + + addr = of_get_property(dp, "address", NULL); + if (!addr) { + prom_printf("sun4c_init_timers: No address property\n"); + prom_halt(); + } + + sun4c_timers = (void __iomem *) (unsigned long) addr[0]; + + prom_irqs = of_get_property(dp, "intr", NULL); + of_node_put(dp); + if (!prom_irqs) { + prom_printf("sun4c_init_timers: No intr property\n"); + prom_halt(); + } + + /* Have the level 10 timer tick at 100HZ. We don't touch the + * level 14 timer limit since we are letting the prom handle + * them until we have a real console driver so L1-A works. + */ + sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); + + master_l10_counter = &sun4c_timers->l10_count; + + irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri); + err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); + if (err) { + prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); + prom_halt(); + } + + /* disable timer interrupt */ + sun4c_mask_irq(irq_get_irq_data(irq)); +} + +#ifdef CONFIG_SMP +static void sun4c_nop(void) +{ +} +#endif + +void __init sun4c_init_IRQ(void) +{ + struct device_node *dp; + const u32 *addr; + + dp = of_find_node_by_name(NULL, "interrupt-enable"); + if (!dp) { + prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n"); + prom_halt(); + } + + addr = of_get_property(dp, "address", NULL); + of_node_put(dp); + if (!addr) { + prom_printf("sun4c_init_IRQ: No address property\n"); + prom_halt(); + } + + interrupt_enable = (void __iomem *) (unsigned long) addr[0]; + + BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); + + sparc_irq_config.init_timers = sun4c_init_timers; + sparc_irq_config.build_device_irq = sun4c_build_device_irq; + +#ifdef CONFIG_SMP + BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); +#endif + sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable); + /* Cannot enable interrupts until OBP ticker is disabled. */ +} 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 @@ +/* ttable.S: Sparc V9 Trap Table(s) with SpitFire/Cheetah/SUN4V extensions. + * + * Copyright (C) 1996, 2001, 2006 David S. Miller (davem@davemloft.net) + */ + + + .globl sparc64_ttable_tl0, sparc64_ttable_tl1 + .globl tl0_icpe, tl1_icpe + .globl tl0_dcpe, tl1_dcpe + .globl tl0_fecc, tl1_fecc + .globl tl0_cee, tl1_cee + .globl tl0_iae, tl1_iae + .globl tl0_dae, tl1_dae + +sparc64_ttable_tl0: +tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) +tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) +tl0_iax: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception) +tl0_itsb_4v: SUN4V_ITSB_MISS +tl0_iae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) +tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) +tl0_ill: membar #Sync + TRAP_7INSNS(do_illegal_instruction) +tl0_privop: TRAP(do_privop) +tl0_resv012: BTRAP(0x12) BTRAP(0x13) BTRAP(0x14) BTRAP(0x15) BTRAP(0x16) BTRAP(0x17) +tl0_resv018: BTRAP(0x18) BTRAP(0x19) BTRAP(0x1a) BTRAP(0x1b) BTRAP(0x1c) BTRAP(0x1d) +tl0_resv01e: BTRAP(0x1e) BTRAP(0x1f) +tl0_fpdis: TRAP_NOSAVE(do_fpdis) +tl0_fpieee: TRAP_SAVEFPU(do_fpieee) +tl0_fpother: TRAP_NOSAVE(do_fpother_check_fitos) +tl0_tof: TRAP(do_tof) +tl0_cwin: CLEAN_WINDOW +tl0_div0: TRAP(do_div0) +tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) +tl0_resv02f: BTRAP(0x2f) +tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception) +tl0_dtsb_4v: SUN4V_DTSB_MISS +tl0_dae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) +tl0_resv033: BTRAP(0x33) +tl0_mna: TRAP_NOSAVE(do_mna) +tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) +tl0_stdfmna: TRAP_NOSAVE(do_stdfmna) +tl0_privact: TRAP_NOSAVE(__do_privact) +tl0_resv038: BTRAP(0x38) BTRAP(0x39) BTRAP(0x3a) BTRAP(0x3b) BTRAP(0x3c) BTRAP(0x3d) +tl0_resv03e: BTRAP(0x3e) BTRAP(0x3f) BTRAP(0x40) +#ifdef CONFIG_SMP +tl0_irq1: TRAP_IRQ(smp_call_function_client, 1) +tl0_irq2: TRAP_IRQ(smp_receive_signal_client, 2) +tl0_irq3: TRAP_IRQ(smp_penguin_jailcell, 3) +tl0_irq4: TRAP_IRQ(smp_new_mmu_context_version_client, 4) +#else +tl0_irq1: BTRAP(0x41) +tl0_irq2: BTRAP(0x42) +tl0_irq3: BTRAP(0x43) +tl0_irq4: BTRAP(0x44) +#endif +tl0_irq5: TRAP_IRQ(handler_irq, 5) +#ifdef CONFIG_SMP +tl0_irq6: TRAP_IRQ(smp_call_function_single_client, 6) +#else +tl0_irq6: BTRAP(0x46) +#endif +tl0_irq7: TRAP_IRQ(deferred_pcr_work_irq, 7) +#if defined(CONFIG_KGDB) && defined(CONFIG_SMP) +tl0_irq8: TRAP_IRQ(smp_kgdb_capture_client, 8) +#else +tl0_irq8: BTRAP(0x48) +#endif +tl0_irq9: BTRAP(0x49) +tl0_irq10: BTRAP(0x4a) BTRAP(0x4b) BTRAP(0x4c) BTRAP(0x4d) +tl0_irq14: TRAP_IRQ(timer_interrupt, 14) +tl0_irq15: TRAP_NMI_IRQ(perfctr_irq, 15) +tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) +tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) +tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) +tl0_ivec: TRAP_IVEC +tl0_paw: TRAP(do_paw) +tl0_vaw: TRAP(do_vaw) +tl0_cee: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_cee_trap) +tl0_iamiss: +#include "itlb_miss.S" +tl0_damiss: +#include "dtlb_miss.S" +tl0_daprot: +#include "dtlb_prot.S" +tl0_fecc: BTRAP(0x70) /* Fast-ECC on Cheetah */ +tl0_dcpe: BTRAP(0x71) /* D-cache Parity Error on Cheetah+ */ +tl0_icpe: BTRAP(0x72) /* I-cache Parity Error on Cheetah+ */ +tl0_resv073: BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) +tl0_resv076: BTRAP(0x76) BTRAP(0x77) BTRAP(0x78) BTRAP(0x79) BTRAP(0x7a) BTRAP(0x7b) +tl0_cpu_mondo: TRAP_NOSAVE(sun4v_cpu_mondo) +tl0_dev_mondo: TRAP_NOSAVE(sun4v_dev_mondo) +tl0_res_mondo: TRAP_NOSAVE(sun4v_res_mondo) +tl0_nres_mondo: TRAP_NOSAVE(sun4v_nonres_mondo) +tl0_s0n: SPILL_0_NORMAL +tl0_s1n: SPILL_1_NORMAL +tl0_s2n: SPILL_2_NORMAL +tl0_s3n: SPILL_0_NORMAL_ETRAP +tl0_s4n: SPILL_1_GENERIC_ETRAP +tl0_s5n: SPILL_1_GENERIC_ETRAP_FIXUP +tl0_s6n: SPILL_2_GENERIC_ETRAP +tl0_s7n: SPILL_2_GENERIC_ETRAP_FIXUP +tl0_s0o: SPILL_0_OTHER +tl0_s1o: SPILL_1_OTHER +tl0_s2o: SPILL_2_OTHER +tl0_s3o: SPILL_3_OTHER +tl0_s4o: SPILL_4_OTHER +tl0_s5o: SPILL_5_OTHER +tl0_s6o: SPILL_6_OTHER +tl0_s7o: SPILL_7_OTHER +tl0_f0n: FILL_0_NORMAL +tl0_f1n: FILL_1_NORMAL +tl0_f2n: FILL_2_NORMAL +tl0_f3n: FILL_3_NORMAL +tl0_f4n: FILL_4_NORMAL +tl0_f5n: FILL_0_NORMAL_RTRAP +tl0_f6n: FILL_1_GENERIC_RTRAP +tl0_f7n: FILL_2_GENERIC_RTRAP +tl0_f0o: FILL_0_OTHER +tl0_f1o: FILL_1_OTHER +tl0_f2o: FILL_2_OTHER +tl0_f3o: FILL_3_OTHER +tl0_f4o: FILL_4_OTHER +tl0_f5o: FILL_5_OTHER +tl0_f6o: FILL_6_OTHER +tl0_f7o: FILL_7_OTHER +tl0_resv100: BTRAP(0x100) +tl0_bkpt: BREAKPOINT_TRAP +tl0_divz: TRAP(do_div0) +tl0_flushw: FLUSH_WINDOW_TRAP +tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) BTRAP(0x108) +tl0_resv109: BTRAP(0x109) BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) +tl0_resv10e: BTRAP(0x10e) BTRAP(0x10f) +tl0_linux32: LINUX_32BIT_SYSCALL_TRAP +tl0_oldlinux64: LINUX_64BIT_SYSCALL_TRAP +tl0_resv112: TRAP_UTRAP(UT_TRAP_INSTRUCTION_18,0x112) TRAP_UTRAP(UT_TRAP_INSTRUCTION_19,0x113) +tl0_resv114: TRAP_UTRAP(UT_TRAP_INSTRUCTION_20,0x114) TRAP_UTRAP(UT_TRAP_INSTRUCTION_21,0x115) +tl0_resv116: TRAP_UTRAP(UT_TRAP_INSTRUCTION_22,0x116) TRAP_UTRAP(UT_TRAP_INSTRUCTION_23,0x117) +tl0_resv118: TRAP_UTRAP(UT_TRAP_INSTRUCTION_24,0x118) TRAP_UTRAP(UT_TRAP_INSTRUCTION_25,0x119) +tl0_resv11a: TRAP_UTRAP(UT_TRAP_INSTRUCTION_26,0x11a) TRAP_UTRAP(UT_TRAP_INSTRUCTION_27,0x11b) +tl0_resv11c: TRAP_UTRAP(UT_TRAP_INSTRUCTION_28,0x11c) TRAP_UTRAP(UT_TRAP_INSTRUCTION_29,0x11d) +tl0_resv11e: TRAP_UTRAP(UT_TRAP_INSTRUCTION_30,0x11e) TRAP_UTRAP(UT_TRAP_INSTRUCTION_31,0x11f) +tl0_getcc: GETCC_TRAP +tl0_setcc: SETCC_TRAP +tl0_getpsr: TRAP(do_getpsr) +tl0_resv123: BTRAP(0x123) BTRAP(0x124) BTRAP(0x125) BTRAP(0x126) BTRAP(0x127) +tl0_resv128: BTRAP(0x128) BTRAP(0x129) BTRAP(0x12a) BTRAP(0x12b) BTRAP(0x12c) +tl0_resv12d: BTRAP(0x12d) BTRAP(0x12e) BTRAP(0x12f) BTRAP(0x130) BTRAP(0x131) +tl0_resv132: BTRAP(0x132) BTRAP(0x133) BTRAP(0x134) BTRAP(0x135) BTRAP(0x136) +tl0_resv137: BTRAP(0x137) BTRAP(0x138) BTRAP(0x139) BTRAP(0x13a) BTRAP(0x13b) +tl0_resv13c: BTRAP(0x13c) BTRAP(0x13d) BTRAP(0x13e) BTRAP(0x13f) BTRAP(0x140) +tl0_resv141: BTRAP(0x141) BTRAP(0x142) BTRAP(0x143) BTRAP(0x144) BTRAP(0x145) +tl0_resv146: BTRAP(0x146) BTRAP(0x147) BTRAP(0x148) BTRAP(0x149) BTRAP(0x14a) +tl0_resv14b: BTRAP(0x14b) BTRAP(0x14c) BTRAP(0x14d) BTRAP(0x14e) BTRAP(0x14f) +tl0_resv150: BTRAP(0x150) BTRAP(0x151) BTRAP(0x152) BTRAP(0x153) BTRAP(0x154) +tl0_resv155: BTRAP(0x155) BTRAP(0x156) BTRAP(0x157) BTRAP(0x158) BTRAP(0x159) +tl0_resv15a: BTRAP(0x15a) BTRAP(0x15b) BTRAP(0x15c) BTRAP(0x15d) BTRAP(0x15e) +tl0_resv15f: BTRAP(0x15f) BTRAP(0x160) BTRAP(0x161) BTRAP(0x162) BTRAP(0x163) +tl0_resv164: BTRAP(0x164) BTRAP(0x165) BTRAP(0x166) BTRAP(0x167) BTRAP(0x168) +tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c) +tl0_linux64: LINUX_64BIT_SYSCALL_TRAP +tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context) +tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) KGDB_TRAP(0x172) +tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177) +tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c) +tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f) +#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) +tl0_resv180: BTRAPS(0x180) BTRAPS(0x188) +tl0_resv190: BTRAPS(0x190) BTRAPS(0x198) +tl0_resv1a0: BTRAPS(0x1a0) BTRAPS(0x1a8) +tl0_resv1b0: BTRAPS(0x1b0) BTRAPS(0x1b8) +tl0_resv1c0: BTRAPS(0x1c0) BTRAPS(0x1c8) +tl0_resv1d0: BTRAPS(0x1d0) BTRAPS(0x1d8) +tl0_resv1e0: BTRAPS(0x1e0) BTRAPS(0x1e8) +tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) + +sparc64_ttable_tl1: +tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) +tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) +tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1) +tl1_itsb_4v: SUN4V_ITSB_MISS +tl1_iae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) +tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) +tl1_ill: TRAPTL1(do_ill_tl1) +tl1_privop: BTRAPTL1(0x11) +tl1_resv012: BTRAPTL1(0x12) BTRAPTL1(0x13) BTRAPTL1(0x14) BTRAPTL1(0x15) +tl1_resv016: BTRAPTL1(0x16) BTRAPTL1(0x17) BTRAPTL1(0x18) BTRAPTL1(0x19) +tl1_resv01a: BTRAPTL1(0x1a) BTRAPTL1(0x1b) BTRAPTL1(0x1c) BTRAPTL1(0x1d) +tl1_resv01e: BTRAPTL1(0x1e) BTRAPTL1(0x1f) +tl1_fpdis: TRAP_NOSAVE(do_fpdis) +tl1_fpieee: TRAPTL1(do_fpieee_tl1) +tl1_fpother: TRAPTL1(do_fpother_tl1) +tl1_tof: TRAPTL1(do_tof_tl1) +tl1_cwin: CLEAN_WINDOW +tl1_div0: TRAPTL1(do_div0_tl1) +tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) +tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) +tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1) +tl1_dtsb_4v: SUN4V_DTSB_MISS +tl1_dae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) +tl1_resv033: BTRAPTL1(0x33) +tl1_mna: TRAP_NOSAVE(do_mna) +tl1_lddfmna: TRAPTL1(do_lddfmna_tl1) +tl1_stdfmna: TRAPTL1(do_stdfmna_tl1) +tl1_privact: BTRAPTL1(0x37) +tl1_resv038: BTRAPTL1(0x38) BTRAPTL1(0x39) BTRAPTL1(0x3a) BTRAPTL1(0x3b) +tl1_resv03c: BTRAPTL1(0x3c) BTRAPTL1(0x3d) BTRAPTL1(0x3e) BTRAPTL1(0x3f) +tl1_resv040: BTRAPTL1(0x40) +tl1_irq1: TRAP_IRQ(do_irq_tl1, 1) TRAP_IRQ(do_irq_tl1, 2) TRAP_IRQ(do_irq_tl1, 3) +tl1_irq4: TRAP_IRQ(do_irq_tl1, 4) TRAP_IRQ(do_irq_tl1, 5) TRAP_IRQ(do_irq_tl1, 6) +tl1_irq7: TRAP_IRQ(do_irq_tl1, 7) TRAP_IRQ(do_irq_tl1, 8) TRAP_IRQ(do_irq_tl1, 9) +tl1_irq10: TRAP_IRQ(do_irq_tl1, 10) TRAP_IRQ(do_irq_tl1, 11) +tl1_irq12: TRAP_IRQ(do_irq_tl1, 12) TRAP_IRQ(do_irq_tl1, 13) +tl1_irq14: TRAP_IRQ(do_irq_tl1, 14) TRAP_IRQ(do_irq_tl1, 15) +tl1_resv050: BTRAPTL1(0x50) BTRAPTL1(0x51) BTRAPTL1(0x52) BTRAPTL1(0x53) +tl1_resv054: BTRAPTL1(0x54) BTRAPTL1(0x55) BTRAPTL1(0x56) BTRAPTL1(0x57) +tl1_resv058: BTRAPTL1(0x58) BTRAPTL1(0x59) BTRAPTL1(0x5a) BTRAPTL1(0x5b) +tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) +tl1_ivec: TRAP_IVEC +tl1_paw: TRAPTL1(do_paw_tl1) +tl1_vaw: TRAPTL1(do_vaw_tl1) +tl1_cee: BTRAPTL1(0x63) +tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) +tl1_damiss: +#include "dtlb_miss.S" +tl1_daprot: +#include "dtlb_prot.S" +tl1_fecc: BTRAPTL1(0x70) /* Fast-ECC on Cheetah */ +tl1_dcpe: BTRAPTL1(0x71) /* D-cache Parity Error on Cheetah+ */ +tl1_icpe: BTRAPTL1(0x72) /* I-cache Parity Error on Cheetah+ */ +tl1_resv073: BTRAPTL1(0x73) +tl1_resv074: BTRAPTL1(0x74) BTRAPTL1(0x75) BTRAPTL1(0x76) BTRAPTL1(0x77) +tl1_resv078: BTRAPTL1(0x78) BTRAPTL1(0x79) BTRAPTL1(0x7a) BTRAPTL1(0x7b) +tl1_resv07c: BTRAPTL1(0x7c) BTRAPTL1(0x7d) BTRAPTL1(0x7e) BTRAPTL1(0x7f) +tl1_s0n: SPILL_0_NORMAL +tl1_s1n: SPILL_1_NORMAL +tl1_s2n: SPILL_2_NORMAL +tl1_s3n: SPILL_3_NORMAL +tl1_s4n: SPILL_4_NORMAL +tl1_s5n: SPILL_5_NORMAL +tl1_s6n: SPILL_6_NORMAL +tl1_s7n: SPILL_7_NORMAL +tl1_s0o: SPILL_0_OTHER +tl1_s1o: SPILL_1_OTHER +tl1_s2o: SPILL_2_OTHER +tl1_s3o: SPILL_3_OTHER +tl1_s4o: SPILL_4_OTHER +tl1_s5o: SPILL_5_OTHER +tl1_s6o: SPILL_6_OTHER +tl1_s7o: SPILL_7_OTHER +tl1_f0n: FILL_0_NORMAL +tl1_f1n: FILL_1_NORMAL +tl1_f2n: FILL_2_NORMAL +tl1_f3n: FILL_3_NORMAL +tl1_f4n: FILL_4_NORMAL +tl1_f5n: FILL_5_NORMAL +tl1_f6n: FILL_6_NORMAL +tl1_f7n: FILL_7_NORMAL +tl1_f0o: FILL_0_OTHER +tl1_f1o: FILL_1_OTHER +tl1_f2o: FILL_2_OTHER +tl1_f3o: FILL_3_OTHER +tl1_f4o: FILL_4_OTHER +tl1_f5o: FILL_5_OTHER +tl1_f6o: FILL_6_OTHER +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 @@ +/* atomic.S: Move this stuff here for better ICACHE hit rates. + * + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + */ + +#include +#include + + .text + .align 4 + + .globl __atomic_begin +__atomic_begin: + +#ifndef CONFIG_SMP + .globl ___xchg32_sun4c +___xchg32_sun4c: + rd %psr, %g3 + andcc %g3, PSR_PIL, %g0 + bne 1f + nop + wr %g3, PSR_PIL, %psr + nop; nop; nop +1: + andcc %g3, PSR_PIL, %g0 + ld [%g1], %g7 + bne 1f + st %g2, [%g1] + wr %g3, 0x0, %psr + nop; nop; nop +1: + mov %g7, %g2 + jmpl %o7 + 8, %g0 + mov %g4, %o7 + + .globl ___xchg32_sun4md +___xchg32_sun4md: + swap [%g1], %g2 + jmpl %o7 + 8, %g0 + mov %g4, %o7 +#endif + + /* Read asm-sparc/atomic.h carefully to understand how this works for SMP. + * Really, some things here for SMP are overly clever, go read the header. + */ + .globl ___atomic24_add +___atomic24_add: + rd %psr, %g3 ! Keep the code small, old way was stupid + nop; nop; nop; ! Let the bits set + or %g3, PSR_PIL, %g7 ! Disable interrupts + wr %g7, 0x0, %psr ! Set %psr + nop; nop; nop; ! Let the bits set +#ifdef CONFIG_SMP +1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 1b ! Nope... + ld [%g1], %g7 ! Load locked atomic24_t + sra %g7, 8, %g7 ! Get signed 24-bit integer + add %g7, %g2, %g2 ! Add in argument + sll %g2, 8, %g7 ! Transpose back to atomic24_t + st %g7, [%g1] ! Clever: This releases the lock as well. +#else + ld [%g1], %g7 ! Load locked atomic24_t + add %g7, %g2, %g2 ! Add in argument + st %g2, [%g1] ! Store it back +#endif + wr %g3, 0x0, %psr ! Restore original PSR_PIL + nop; nop; nop; ! Let the bits set + jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h + mov %g4, %o7 ! Restore %o7 + + .globl ___atomic24_sub +___atomic24_sub: + rd %psr, %g3 ! Keep the code small, old way was stupid + nop; nop; nop; ! Let the bits set + or %g3, PSR_PIL, %g7 ! Disable interrupts + wr %g7, 0x0, %psr ! Set %psr + nop; nop; nop; ! Let the bits set +#ifdef CONFIG_SMP +1: ldstub [%g1 + 3], %g7 ! Spin on the byte lock for SMP. + orcc %g7, 0x0, %g0 ! Did we get it? + bne 1b ! Nope... + ld [%g1], %g7 ! Load locked atomic24_t + sra %g7, 8, %g7 ! Get signed 24-bit integer + sub %g7, %g2, %g2 ! Subtract argument + sll %g2, 8, %g7 ! Transpose back to atomic24_t + st %g7, [%g1] ! Clever: This releases the lock as well +#else + ld [%g1], %g7 ! Load locked atomic24_t + sub %g7, %g2, %g2 ! Subtract argument + st %g2, [%g1] ! Store it back +#endif + wr %g3, 0x0, %psr ! Restore original PSR_PIL + nop; nop; nop; ! Let the bits set + jmpl %o7, %g0 ! NOTE: not + 8, see callers in atomic.h + mov %g4, %o7 ! Restore %o7 + + .globl __atomic_end +__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 @@ +/* + * mul.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + +/* + * Signed multiply, from Appendix E of the Sparc Version 8 + * Architecture Manual. + */ + +/* + * Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the upper 32 bits of + * the 64-bit product). + * + * This code optimizes short (less than 13-bit) multiplies. + */ + + .globl .mul + .globl _Mul +.mul: +_Mul: /* needed for export */ + mov %o0, %y ! multiplier -> Y + andncc %o0, 0xfff, %g0 ! test bits 12..31 + be Lmul_shortway ! if zero, can do it the short way + andcc %g0, %g0, %o4 ! zero the partial product and clear N and V + + /* + * Long multiply. 32 steps, followed by a final shift step. + */ + mulscc %o4, %o1, %o4 ! 1 + mulscc %o4, %o1, %o4 ! 2 + mulscc %o4, %o1, %o4 ! 3 + mulscc %o4, %o1, %o4 ! 4 + mulscc %o4, %o1, %o4 ! 5 + mulscc %o4, %o1, %o4 ! 6 + mulscc %o4, %o1, %o4 ! 7 + mulscc %o4, %o1, %o4 ! 8 + mulscc %o4, %o1, %o4 ! 9 + mulscc %o4, %o1, %o4 ! 10 + mulscc %o4, %o1, %o4 ! 11 + mulscc %o4, %o1, %o4 ! 12 + mulscc %o4, %o1, %o4 ! 13 + mulscc %o4, %o1, %o4 ! 14 + mulscc %o4, %o1, %o4 ! 15 + mulscc %o4, %o1, %o4 ! 16 + mulscc %o4, %o1, %o4 ! 17 + mulscc %o4, %o1, %o4 ! 18 + mulscc %o4, %o1, %o4 ! 19 + mulscc %o4, %o1, %o4 ! 20 + mulscc %o4, %o1, %o4 ! 21 + mulscc %o4, %o1, %o4 ! 22 + mulscc %o4, %o1, %o4 ! 23 + mulscc %o4, %o1, %o4 ! 24 + mulscc %o4, %o1, %o4 ! 25 + mulscc %o4, %o1, %o4 ! 26 + mulscc %o4, %o1, %o4 ! 27 + mulscc %o4, %o1, %o4 ! 28 + mulscc %o4, %o1, %o4 ! 29 + mulscc %o4, %o1, %o4 ! 30 + mulscc %o4, %o1, %o4 ! 31 + mulscc %o4, %o1, %o4 ! 32 + mulscc %o4, %g0, %o4 ! final shift + + ! If %o0 was negative, the result is + ! (%o0 * %o1) + (%o1 << 32)) + ! We fix that here. + +#if 0 + tst %o0 + bge 1f + rd %y, %o0 + + ! %o0 was indeed negative; fix upper 32 bits of result by subtracting + ! %o1 (i.e., return %o4 - %o1 in %o1). + retl + sub %o4, %o1, %o1 + +1: + retl + mov %o4, %o1 +#else + /* Faster code adapted from tege@sics.se's code for umul.S. */ + sra %o0, 31, %o2 ! make mask from sign bit + and %o1, %o2, %o2 ! %o2 = 0 or %o1, depending on sign of %o0 + rd %y, %o0 ! get lower half of product + retl + sub %o4, %o2, %o1 ! subtract compensation + ! and put upper half in place +#endif + +Lmul_shortway: + /* + * Short multiply. 12 steps, followed by a final shift step. + * The resulting bits are off by 12 and (32-12) = 20 bit positions, + * but there is no problem with %o0 being negative (unlike above). + */ + mulscc %o4, %o1, %o4 ! 1 + mulscc %o4, %o1, %o4 ! 2 + mulscc %o4, %o1, %o4 ! 3 + mulscc %o4, %o1, %o4 ! 4 + mulscc %o4, %o1, %o4 ! 5 + mulscc %o4, %o1, %o4 ! 6 + mulscc %o4, %o1, %o4 ! 7 + mulscc %o4, %o1, %o4 ! 8 + mulscc %o4, %o1, %o4 ! 9 + mulscc %o4, %o1, %o4 ! 10 + mulscc %o4, %o1, %o4 ! 11 + mulscc %o4, %o1, %o4 ! 12 + mulscc %o4, %g0, %o4 ! final shift + + /* + * %o4 has 20 of the bits that should be in the low part of the + * result; %y has the bottom 12 (as %y's top 12). That is: + * + * %o4 %y + * +----------------+----------------+ + * | -12- | -20- | -12- | -20- | + * +------(---------+------)---------+ + * --hi-- ----low-part---- + * + * The upper 12 bits of %o4 should be sign-extended to form the + * high part of the product (i.e., highpart = %o4 >> 20). + */ + + rd %y, %o5 + sll %o4, 12, %o0 ! shift middle bits left 12 + srl %o5, 20, %o5 ! shift low bits right 20, zero fill at left + or %o5, %o0, %o0 ! construct low part of result + retl + sra %o4, 20, %o1 ! ... and extract high part of result + + .globl .mul_patch +.mul_patch: + smul %o0, %o1, %o0 + retl + rd %y, %o1 + 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 @@ +/* + * rem.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + + +/* This file is generated from divrem.m4; DO NOT EDIT! */ +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .rem name of function to generate + * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1 + * true true=true => signed; true=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + + .globl .rem + .globl _Rem +.rem: +_Rem: /* needed for export */ + ! compute sign of result; if neither is negative, no problem + orcc %o1, %o0, %g0 ! either negative? + bge 2f ! no, go do the divide + mov %o0, %g2 ! compute sign in any case + + tst %o1 + bge 1f + tst %o0 + ! %o1 is definitely negative; %o0 might also be negative + bge 2f ! if %o0 not negative... + sub %g0, %o1, %o1 ! in any case, make %o1 nonneg +1: ! %o0 is negative, %o1 is nonnegative + sub %g0, %o0, %o0 ! make %o0 nonnegative +2: + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bne 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + ta ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + + sethi %hi(1 << (32 - 4 - 1)), %g1 + + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2**(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + + sll %o5, 4, %o5 + + b 1b + add %o4, 1, %o4 + + ! Now compute %g7. + 2: + addcc %o5, %o5, %o5 + + bcc Lnot_too_big + add %g7, 1, %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + + b Ldo_single_div + sub %g7, 1, %g7 + + Lnot_too_big: + 3: + cmp %o5, %o3 + blu 2b + nop + + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + subcc %g7, 1, %g7 + bl Lend_regular_divide + nop + + sub %o3, %o5, %o3 + mov 1, %o2 + + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + + b 2f + add %o2, 1, %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + sub %o2, 1, %o2 + 2: + Lend_single_divloop: + subcc %g7, 1, %g7 + bge Lsingle_divloop + tst %o3 + + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + cmp %o5, %o3 + bleu 1b + addcc %o4, 1, %o4 + be Lgot_result + sub %o4, 1, %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + 9: +Lend_regular_divide: + subcc %o4, 1, %o4 + bge Ldivloop + tst %o3 + + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + add %o3, %o1, %o3 + +Lgot_result: + ! check to see if answer should be < 0 + tst %g2 + bl,a 1f + sub %g0, %o3, %o3 +1: + retl + mov %o3, %o0 + + .globl .rem_patch +.rem_patch: + sra %o0, 0x1f, %o4 + wr %o4, 0x0, %y + nop + nop + nop + sdivcc %o0, %o1, %o2 + bvs,a 1f + xnor %o2, %g0, %o2 +1: smul %o2, %o1, %o2 + retl + sub %o0, %o2, %o0 + 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 @@ +/* + * sdiv.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + + +/* This file is generated from divrem.m4; DO NOT EDIT! */ +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .div name of function to generate + * div div=div => %o0 / %o1; div=rem => %o0 % %o1 + * true true=true => signed; true=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + + .globl .div + .globl _Div +.div: +_Div: /* needed for export */ + ! compute sign of result; if neither is negative, no problem + orcc %o1, %o0, %g0 ! either negative? + bge 2f ! no, go do the divide + xor %o1, %o0, %g2 ! compute sign in any case + + tst %o1 + bge 1f + tst %o0 + ! %o1 is definitely negative; %o0 might also be negative + bge 2f ! if %o0 not negative... + sub %g0, %o1, %o1 ! in any case, make %o1 nonneg +1: ! %o0 is negative, %o1 is nonnegative + sub %g0, %o0, %o0 ! make %o0 nonnegative +2: + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bne 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + ta ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + + sethi %hi(1 << (32 - 4 - 1)), %g1 + + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2**(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + + sll %o5, 4, %o5 + + b 1b + add %o4, 1, %o4 + + ! Now compute %g7. + 2: + addcc %o5, %o5, %o5 + bcc Lnot_too_big + add %g7, 1, %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + + b Ldo_single_div + sub %g7, 1, %g7 + + Lnot_too_big: + 3: + cmp %o5, %o3 + blu 2b + nop + + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + subcc %g7, 1, %g7 + bl Lend_regular_divide + nop + + sub %o3, %o5, %o3 + mov 1, %o2 + + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + + b 2f + add %o2, 1, %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + sub %o2, 1, %o2 + 2: + Lend_single_divloop: + subcc %g7, 1, %g7 + bge Lsingle_divloop + tst %o3 + + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + cmp %o5, %o3 + bleu 1b + addcc %o4, 1, %o4 + + be Lgot_result + sub %o4, 1, %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + 9: +Lend_regular_divide: + subcc %o4, 1, %o4 + bge Ldivloop + tst %o3 + + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + sub %o2, 1, %o2 + +Lgot_result: + ! check to see if answer should be < 0 + tst %g2 + bl,a 1f + sub %g0, %o2, %o2 +1: + retl + mov %o2, %o0 + + .globl .div_patch +.div_patch: + sra %o0, 0x1f, %o2 + wr %o2, 0x0, %y + nop + nop + nop + sdivcc %o0, %o1, %o0 + bvs,a 1f + xnor %o0, %g0, %o0 +1: retl + 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 @@ +/* strlen_user.S: Sparc optimized strlen_user code + * + * Return length of string in userspace including terminating 0 + * or 0 for error + * + * Copyright (C) 1991,1996 Free Software Foundation + * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#define LO_MAGIC 0x01010101 +#define HI_MAGIC 0x80808080 + +10: + ldub [%o0], %o5 + cmp %o5, 0 + be 1f + add %o0, 1, %o0 + andcc %o0, 3, %g0 + be 4f + or %o4, %lo(HI_MAGIC), %o3 +11: + ldub [%o0], %o5 + cmp %o5, 0 + be 2f + add %o0, 1, %o0 + andcc %o0, 3, %g0 + be 5f + sethi %hi(LO_MAGIC), %o4 +12: + ldub [%o0], %o5 + cmp %o5, 0 + be 3f + add %o0, 1, %o0 + b 13f + or %o4, %lo(LO_MAGIC), %o2 +1: + retl + mov 1, %o0 +2: + retl + mov 2, %o0 +3: + retl + mov 3, %o0 + + .align 4 + .global __strlen_user, __strnlen_user +__strlen_user: + sethi %hi(32768), %o1 +__strnlen_user: + mov %o1, %g1 + mov %o0, %o1 + andcc %o0, 3, %g0 + bne 10b + sethi %hi(HI_MAGIC), %o4 + or %o4, %lo(HI_MAGIC), %o3 +4: + sethi %hi(LO_MAGIC), %o4 +5: + or %o4, %lo(LO_MAGIC), %o2 +13: + ld [%o0], %o5 +2: + sub %o5, %o2, %o4 + andcc %o4, %o3, %g0 + bne 82f + add %o0, 4, %o0 + sub %o0, %o1, %g2 +81: cmp %g2, %g1 + blu 13b + mov %o0, %o4 + ba,a 1f + + /* Check every byte. */ +82: srl %o5, 24, %g5 + andcc %g5, 0xff, %g0 + be 1f + add %o0, -3, %o4 + srl %o5, 16, %g5 + andcc %g5, 0xff, %g0 + be 1f + add %o4, 1, %o4 + srl %o5, 8, %g5 + andcc %g5, 0xff, %g0 + be 1f + add %o4, 1, %o4 + andcc %o5, 0xff, %g0 + bne 81b + sub %o0, %o1, %g2 + + add %o4, 1, %o4 +1: + retl + sub %o4, %o1, %o0 + + .section .fixup,#alloc,#execinstr + .align 4 +9: + retl + clr %o0 + + .section __ex_table,#alloc + .align 4 + + .word 10b, 9b + .word 11b, 9b + .word 12b, 9b + .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 @@ +/* strlen_user.S: Sparc64 optimized strlen_user code + * + * Return length of string in userspace including terminating 0 + * or 0 for error + * + * Copyright (C) 1991,1996 Free Software Foundation + * Copyright (C) 1996,1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include + +#define LO_MAGIC 0x01010101 +#define HI_MAGIC 0x80808080 + + .align 4 + .global __strlen_user, __strnlen_user +__strlen_user: + sethi %hi(32768), %o1 +__strnlen_user: + mov %o1, %g1 + mov %o0, %o1 + andcc %o0, 3, %g0 + be,pt %icc, 9f + sethi %hi(HI_MAGIC), %o4 +10: lduba [%o0] %asi, %o5 + brz,pn %o5, 21f + add %o0, 1, %o0 + andcc %o0, 3, %g0 + be,pn %icc, 4f + or %o4, %lo(HI_MAGIC), %o3 +11: lduba [%o0] %asi, %o5 + brz,pn %o5, 22f + add %o0, 1, %o0 + andcc %o0, 3, %g0 + be,pt %icc, 13f + srl %o3, 7, %o2 +12: lduba [%o0] %asi, %o5 + brz,pn %o5, 23f + add %o0, 1, %o0 + ba,pt %icc, 2f +15: lda [%o0] %asi, %o5 +9: or %o4, %lo(HI_MAGIC), %o3 +4: srl %o3, 7, %o2 +13: lda [%o0] %asi, %o5 +2: sub %o5, %o2, %o4 + andcc %o4, %o3, %g0 + bne,pn %icc, 82f + add %o0, 4, %o0 + sub %o0, %o1, %g2 +81: cmp %g2, %g1 + blu,pt %icc, 13b + mov %o0, %o4 + ba,a,pt %xcc, 1f + + /* Check every byte. */ +82: srl %o5, 24, %g7 + andcc %g7, 0xff, %g0 + be,pn %icc, 1f + add %o0, -3, %o4 + srl %o5, 16, %g7 + andcc %g7, 0xff, %g0 + be,pn %icc, 1f + add %o4, 1, %o4 + srl %o5, 8, %g7 + andcc %g7, 0xff, %g0 + be,pn %icc, 1f + add %o4, 1, %o4 + andcc %o5, 0xff, %g0 + bne,pt %icc, 81b + sub %o0, %o1, %g2 + add %o4, 1, %o4 +1: retl + sub %o4, %o1, %o0 +21: retl + mov 1, %o0 +22: retl + mov 2, %o0 +23: retl + mov 3, %o0 + + .section .fixup,#alloc,#execinstr + .align 4 +30: + retl + clr %o0 + + .section __ex_table,"a" + .align 4 + + .word 10b, 30b + .word 11b, 30b + .word 12b, 30b + .word 15b, 30b + .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 @@ +/* strncpy_from_user.S: Sparc strncpy from userspace. + * + * Copyright(C) 1996 David S. Miller + */ + +#include +#include + + .text + .align 4 + + /* Must return: + * + * -EFAULT for an exception + * count if we hit the buffer limit + * bytes copied if we hit a null byte + */ + + .globl __strncpy_from_user +__strncpy_from_user: + /* %o0=dest, %o1=src, %o2=count */ + mov %o2, %o3 +1: + subcc %o2, 1, %o2 + bneg 2f + nop +10: + ldub [%o1], %o4 + add %o0, 1, %o0 + cmp %o4, 0 + add %o1, 1, %o1 + bne 1b + stb %o4, [%o0 - 1] +2: + add %o2, 1, %o0 + retl + sub %o3, %o0, %o0 + + .section .fixup,#alloc,#execinstr + .align 4 +4: + retl + mov -EFAULT, %o0 + + .section __ex_table,#alloc + .align 4 + .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 @@ +/* + * strncpy_from_user.S: Sparc64 strncpy from userspace. + * + * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include +#include + + .data + .align 8 +0: .xword 0x0101010101010101 + + .text + .align 32 + + /* Must return: + * + * -EFAULT for an exception + * count if we hit the buffer limit + * bytes copied if we hit a null byte + * (without the null byte) + * + * This implementation assumes: + * %o1 is 8 aligned => !(%o2 & 7) + * %o0 is 8 aligned (if not, it will be slooooow, but will work) + * + * This is optimized for the common case: + * in my stats, 90% of src are 8 aligned (even on sparc32) + * and average length is 18 or so. + */ + + .globl __strncpy_from_user + .type __strncpy_from_user,#function +__strncpy_from_user: + /* %o0=dest, %o1=src, %o2=count */ + andcc %o1, 7, %g0 ! IEU1 Group + bne,pn %icc, 30f ! CTI + add %o0, %o2, %g3 ! IEU0 +60: ldxa [%o1] %asi, %g1 ! Load Group + brlez,pn %o2, 10f ! CTI + mov %o0, %o3 ! IEU0 +50: sethi %hi(0b), %o4 ! IEU0 Group + ldx [%o4 + %lo(0b)], %o4 ! Load + sllx %o4, 7, %o5 ! IEU1 Group +1: sub %g1, %o4, %g2 ! IEU0 Group + stx %g1, [%o0] ! Store + add %o0, 8, %o0 ! IEU1 + andcc %g2, %o5, %g0 ! IEU1 Group + bne,pn %xcc, 5f ! CTI + add %o1, 8, %o1 ! IEU0 + cmp %o0, %g3 ! IEU1 Group + bl,a,pt %xcc, 1b ! CTI +61: ldxa [%o1] %asi, %g1 ! Load +10: retl ! CTI Group + mov %o2, %o0 ! IEU0 +5: srlx %g2, 32, %g7 ! IEU0 Group + sethi %hi(0xff00), %o4 ! IEU1 + andcc %g7, %o5, %g0 ! IEU1 Group + be,pn %icc, 2f ! CTI + or %o4, %lo(0xff00), %o4 ! IEU0 + srlx %g1, 48, %g7 ! IEU0 Group + andcc %g7, %o4, %g0 ! IEU1 Group + be,pn %icc, 50f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 51f ! CTI + srlx %g1, 32, %g7 ! IEU0 + andcc %g7, %o4, %g0 ! IEU1 Group + be,pn %icc, 52f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 53f ! CTI +2: andcc %g2, %o5, %g0 ! IEU1 Group + be,pn %icc, 2f ! CTI + srl %g1, 16, %g7 ! IEU0 + andcc %g7, %o4, %g0 ! IEU1 Group + be,pn %icc, 54f ! CTI + andcc %g7, 0xff, %g0 ! IEU1 Group + be,pn %icc, 55f ! CTI + andcc %g1, %o4, %g0 ! IEU1 Group + be,pn %icc, 56f ! CTI + andcc %g1, 0xff, %g0 ! IEU1 Group + be,a,pn %icc, 57f ! CTI + sub %o0, %o3, %o0 ! IEU0 +2: cmp %o0, %g3 ! IEU1 Group + bl,a,pt %xcc, 50b ! CTI +62: ldxa [%o1] %asi, %g1 ! Load + retl ! CTI Group + mov %o2, %o0 ! IEU0 +50: sub %o0, %o3, %o0 + retl + sub %o0, 8, %o0 +51: sub %o0, %o3, %o0 + retl + sub %o0, 7, %o0 +52: sub %o0, %o3, %o0 + retl + sub %o0, 6, %o0 +53: sub %o0, %o3, %o0 + retl + sub %o0, 5, %o0 +54: sub %o0, %o3, %o0 + retl + sub %o0, 4, %o0 +55: sub %o0, %o3, %o0 + retl + sub %o0, 3, %o0 +56: sub %o0, %o3, %o0 + retl + sub %o0, 2, %o0 +57: retl + sub %o0, 1, %o0 +30: brlez,pn %o2, 3f + sub %g0, %o2, %o3 + add %o0, %o2, %o0 +63: lduba [%o1] %asi, %o4 +1: add %o1, 1, %o1 + brz,pn %o4, 2f + stb %o4, [%o0 + %o3] + addcc %o3, 1, %o3 + bne,pt %xcc, 1b +64: lduba [%o1] %asi, %o4 +3: retl + mov %o2, %o0 +2: retl + add %o2, %o3, %o0 + .size __strncpy_from_user, .-__strncpy_from_user + + .section __ex_table,"a" + .align 4 + .word 60b, __retl_efault + .word 61b, __retl_efault + .word 62b, __retl_efault + .word 63b, __retl_efault + .word 64b, __retl_efault + .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 @@ +/* + * udiv.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + + +/* This file is generated from divrem.m4; DO NOT EDIT! */ +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .udiv name of function to generate + * div div=div => %o0 / %o1; div=rem => %o0 % %o1 + * false false=true => signed; false=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + + .globl .udiv + .globl _Udiv +.udiv: +_Udiv: /* needed for export */ + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bne 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + ta ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + + sethi %hi(1 << (32 - 4 - 1)), %g1 + + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2**(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + + sll %o5, 4, %o5 + + b 1b + add %o4, 1, %o4 + + ! Now compute %g7. + 2: + addcc %o5, %o5, %o5 + bcc Lnot_too_big + add %g7, 1, %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + + b Ldo_single_div + sub %g7, 1, %g7 + + Lnot_too_big: + 3: + cmp %o5, %o3 + blu 2b + nop + + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + subcc %g7, 1, %g7 + bl Lend_regular_divide + nop + + sub %o3, %o5, %o3 + mov 1, %o2 + + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + b 2f + add %o2, 1, %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + sub %o2, 1, %o2 + 2: + Lend_single_divloop: + subcc %g7, 1, %g7 + bge Lsingle_divloop + tst %o3 + + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + + cmp %o5, %o3 + bleu 1b + addcc %o4, 1, %o4 + + be Lgot_result + sub %o4, 1, %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + 9: +Lend_regular_divide: + subcc %o4, 1, %o4 + bge Ldivloop + tst %o3 + + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + sub %o2, 1, %o2 + +Lgot_result: + + retl + mov %o2, %o0 + + .globl .udiv_patch +.udiv_patch: + wr %g0, 0x0, %y + nop + nop + retl + udiv %o0, %o1, %o0 + 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 @@ +/* + * umul.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + + +/* + * Unsigned multiply. Returns %o0 * %o1 in %o1%o0 (i.e., %o1 holds the + * upper 32 bits of the 64-bit product). + * + * This code optimizes short (less than 13-bit) multiplies. Short + * multiplies require 25 instruction cycles, and long ones require + * 45 instruction cycles. + * + * On return, overflow has occurred (%o1 is not zero) if and only if + * the Z condition code is clear, allowing, e.g., the following: + * + * call .umul + * nop + * bnz overflow (or tnz) + */ + + .globl .umul + .globl _Umul +.umul: +_Umul: /* needed for export */ + or %o0, %o1, %o4 + mov %o0, %y ! multiplier -> Y + + andncc %o4, 0xfff, %g0 ! test bits 12..31 of *both* args + be Lmul_shortway ! if zero, can do it the short way + andcc %g0, %g0, %o4 ! zero the partial product and clear N and V + + /* + * Long multiply. 32 steps, followed by a final shift step. + */ + mulscc %o4, %o1, %o4 ! 1 + mulscc %o4, %o1, %o4 ! 2 + mulscc %o4, %o1, %o4 ! 3 + mulscc %o4, %o1, %o4 ! 4 + mulscc %o4, %o1, %o4 ! 5 + mulscc %o4, %o1, %o4 ! 6 + mulscc %o4, %o1, %o4 ! 7 + mulscc %o4, %o1, %o4 ! 8 + mulscc %o4, %o1, %o4 ! 9 + mulscc %o4, %o1, %o4 ! 10 + mulscc %o4, %o1, %o4 ! 11 + mulscc %o4, %o1, %o4 ! 12 + mulscc %o4, %o1, %o4 ! 13 + mulscc %o4, %o1, %o4 ! 14 + mulscc %o4, %o1, %o4 ! 15 + mulscc %o4, %o1, %o4 ! 16 + mulscc %o4, %o1, %o4 ! 17 + mulscc %o4, %o1, %o4 ! 18 + mulscc %o4, %o1, %o4 ! 19 + mulscc %o4, %o1, %o4 ! 20 + mulscc %o4, %o1, %o4 ! 21 + mulscc %o4, %o1, %o4 ! 22 + mulscc %o4, %o1, %o4 ! 23 + mulscc %o4, %o1, %o4 ! 24 + mulscc %o4, %o1, %o4 ! 25 + mulscc %o4, %o1, %o4 ! 26 + mulscc %o4, %o1, %o4 ! 27 + mulscc %o4, %o1, %o4 ! 28 + mulscc %o4, %o1, %o4 ! 29 + mulscc %o4, %o1, %o4 ! 30 + mulscc %o4, %o1, %o4 ! 31 + mulscc %o4, %o1, %o4 ! 32 + mulscc %o4, %g0, %o4 ! final shift + + + /* + * Normally, with the shift-and-add approach, if both numbers are + * positive you get the correct result. With 32-bit two's-complement + * numbers, -x is represented as + * + * x 32 + * ( 2 - ------ ) mod 2 * 2 + * 32 + * 2 + * + * (the `mod 2' subtracts 1 from 1.bbbb). To avoid lots of 2^32s, + * we can treat this as if the radix point were just to the left + * of the sign bit (multiply by 2^32), and get + * + * -x = (2 - x) mod 2 + * + * Then, ignoring the `mod 2's for convenience: + * + * x * y = xy + * -x * y = 2y - xy + * x * -y = 2x - xy + * -x * -y = 4 - 2x - 2y + xy + * + * For signed multiplies, we subtract (x << 32) from the partial + * product to fix this problem for negative multipliers (see mul.s). + * Because of the way the shift into the partial product is calculated + * (N xor V), this term is automatically removed for the multiplicand, + * so we don't have to adjust. + * + * But for unsigned multiplies, the high order bit wasn't a sign bit, + * and the correction is wrong. So for unsigned multiplies where the + * high order bit is one, we end up with xy - (y << 32). To fix it + * we add y << 32. + */ +#if 0 + tst %o1 + bl,a 1f ! if %o1 < 0 (high order bit = 1), + add %o4, %o0, %o4 ! %o4 += %o0 (add y to upper half) + +1: + rd %y, %o0 ! get lower half of product + retl + addcc %o4, %g0, %o1 ! put upper half in place and set Z for %o1==0 +#else + /* Faster code from tege@sics.se. */ + sra %o1, 31, %o2 ! make mask from sign bit + and %o0, %o2, %o2 ! %o2 = 0 or %o0, depending on sign of %o1 + rd %y, %o0 ! get lower half of product + retl + addcc %o4, %o2, %o1 ! add compensation and put upper half in place +#endif + +Lmul_shortway: + /* + * Short multiply. 12 steps, followed by a final shift step. + * The resulting bits are off by 12 and (32-12) = 20 bit positions, + * but there is no problem with %o0 being negative (unlike above), + * and overflow is impossible (the answer is at most 24 bits long). + */ + mulscc %o4, %o1, %o4 ! 1 + mulscc %o4, %o1, %o4 ! 2 + mulscc %o4, %o1, %o4 ! 3 + mulscc %o4, %o1, %o4 ! 4 + mulscc %o4, %o1, %o4 ! 5 + mulscc %o4, %o1, %o4 ! 6 + mulscc %o4, %o1, %o4 ! 7 + mulscc %o4, %o1, %o4 ! 8 + mulscc %o4, %o1, %o4 ! 9 + mulscc %o4, %o1, %o4 ! 10 + mulscc %o4, %o1, %o4 ! 11 + mulscc %o4, %o1, %o4 ! 12 + mulscc %o4, %g0, %o4 ! final shift + + /* + * %o4 has 20 of the bits that should be in the result; %y has + * the bottom 12 (as %y's top 12). That is: + * + * %o4 %y + * +----------------+----------------+ + * | -12- | -20- | -12- | -20- | + * +------(---------+------)---------+ + * -----result----- + * + * The 12 bits of %o4 left of the `result' area are all zero; + * in fact, all top 20 bits of %o4 are zero. + */ + + rd %y, %o5 + sll %o4, 12, %o0 ! shift middle bits left 12 + srl %o5, 20, %o5 ! shift low bits right 20 + or %o5, %o0, %o0 + retl + addcc %g0, %g0, %o1 ! %o1 = zero, and set Z + + .globl .umul_patch +.umul_patch: + umul %o0, %o1, %o0 + retl + rd %y, %o1 + 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 @@ +/* + * urem.S: This routine was taken from glibc-1.09 and is covered + * by the GNU Library General Public License Version 2. + */ + +/* This file is generated from divrem.m4; DO NOT EDIT! */ +/* + * Division and remainder, from Appendix E of the Sparc Version 8 + * Architecture Manual, with fixes from Gordon Irlam. + */ + +/* + * Input: dividend and divisor in %o0 and %o1 respectively. + * + * m4 parameters: + * .urem name of function to generate + * rem rem=div => %o0 / %o1; rem=rem => %o0 % %o1 + * false false=true => signed; false=false => unsigned + * + * Algorithm parameters: + * N how many bits per iteration we try to get (4) + * WORDSIZE total number of bits (32) + * + * Derived constants: + * TOPBITS number of bits in the top decade of a number + * + * Important variables: + * Q the partial quotient under development (initially 0) + * R the remainder so far, initially the dividend + * ITER number of main division loop iterations required; + * equal to ceil(log2(quotient) / N). Note that this + * is the log base (2^N) of the quotient. + * V the current comparand, initially divisor*2^(ITER*N-1) + * + * Cost: + * Current estimate for non-large dividend is + * ceil(log2(quotient) / N) * (10 + 7N/2) + C + * A large dividend is one greater than 2^(31-TOPBITS) and takes a + * different path, as the upper bits of the quotient must be developed + * one bit at a time. + */ + + .globl .urem + .globl _Urem +.urem: +_Urem: /* needed for export */ + + ! Ready to divide. Compute size of quotient; scale comparand. + orcc %o1, %g0, %o5 + bne 1f + mov %o0, %o3 + + ! Divide by zero trap. If it returns, return 0 (about as + ! wrong as possible, but that is what SunOS does...). + ta ST_DIV0 + retl + clr %o0 + +1: + cmp %o3, %o5 ! if %o1 exceeds %o0, done + blu Lgot_result ! (and algorithm fails otherwise) + clr %o2 + + sethi %hi(1 << (32 - 4 - 1)), %g1 + + cmp %o3, %g1 + blu Lnot_really_big + clr %o4 + + ! Here the dividend is >= 2**(31-N) or so. We must be careful here, + ! as our usual N-at-a-shot divide step will cause overflow and havoc. + ! The number of bits in the result here is N*ITER+SC, where SC <= N. + ! Compute ITER in an unorthodox manner: know we need to shift V into + ! the top decade: so do not even bother to compare to R. + 1: + cmp %o5, %g1 + bgeu 3f + mov 1, %g7 + + sll %o5, 4, %o5 + + b 1b + add %o4, 1, %o4 + + ! Now compute %g7. + 2: + addcc %o5, %o5, %o5 + bcc Lnot_too_big + add %g7, 1, %g7 + + ! We get here if the %o1 overflowed while shifting. + ! This means that %o3 has the high-order bit set. + ! Restore %o5 and subtract from %o3. + sll %g1, 4, %g1 ! high order bit + srl %o5, 1, %o5 ! rest of %o5 + add %o5, %g1, %o5 + + b Ldo_single_div + sub %g7, 1, %g7 + + Lnot_too_big: + 3: + cmp %o5, %o3 + blu 2b + nop + + be Ldo_single_div + nop + /* NB: these are commented out in the V8-Sparc manual as well */ + /* (I do not understand this) */ + ! %o5 > %o3: went too far: back up 1 step + ! srl %o5, 1, %o5 + ! dec %g7 + ! do single-bit divide steps + ! + ! We have to be careful here. We know that %o3 >= %o5, so we can do the + ! first divide step without thinking. BUT, the others are conditional, + ! and are only done if %o3 >= 0. Because both %o3 and %o5 may have the high- + ! order bit set in the first step, just falling into the regular + ! division loop will mess up the first time around. + ! So we unroll slightly... + Ldo_single_div: + subcc %g7, 1, %g7 + bl Lend_regular_divide + nop + + sub %o3, %o5, %o3 + mov 1, %o2 + + b Lend_single_divloop + nop + Lsingle_divloop: + sll %o2, 1, %o2 + bl 1f + srl %o5, 1, %o5 + ! %o3 >= 0 + sub %o3, %o5, %o3 + b 2f + add %o2, 1, %o2 + 1: ! %o3 < 0 + add %o3, %o5, %o3 + sub %o2, 1, %o2 + 2: + Lend_single_divloop: + subcc %g7, 1, %g7 + bge Lsingle_divloop + tst %o3 + + b,a Lend_regular_divide + +Lnot_really_big: +1: + sll %o5, 4, %o5 + + cmp %o5, %o3 + bleu 1b + addcc %o4, 1, %o4 + + be Lgot_result + sub %o4, 1, %o4 + + tst %o3 ! set up for initial iteration +Ldivloop: + sll %o2, 4, %o2 + ! depth 1, accumulated bits 0 + bl L.1.16 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 2, accumulated bits 1 + bl L.2.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits 3 + bl L.3.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 7 + bl L.4.23 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (7*2+1), %o2 + +L.4.23: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (7*2-1), %o2 + +L.3.19: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 5 + bl L.4.21 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (5*2+1), %o2 + +L.4.21: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (5*2-1), %o2 + +L.2.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits 1 + bl L.3.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits 3 + bl L.4.19 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (3*2+1), %o2 + +L.4.19: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (3*2-1), %o2 + +L.3.17: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits 1 + bl L.4.17 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (1*2+1), %o2 + +L.4.17: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (1*2-1), %o2 + +L.1.16: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 2, accumulated bits -1 + bl L.2.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 3, accumulated bits -1 + bl L.3.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -1 + bl L.4.15 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2+1), %o2 + +L.4.15: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-1*2-1), %o2 + +L.3.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -3 + bl L.4.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2+1), %o2 + +L.4.13: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-3*2-1), %o2 + +L.2.15: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 3, accumulated bits -3 + bl L.3.13 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + ! depth 4, accumulated bits -5 + bl L.4.11 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2+1), %o2 + +L.4.11: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-5*2-1), %o2 + +L.3.13: + ! remainder is negative + addcc %o3,%o5,%o3 + ! depth 4, accumulated bits -7 + bl L.4.9 + srl %o5,1,%o5 + ! remainder is positive + subcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2+1), %o2 + +L.4.9: + ! remainder is negative + addcc %o3,%o5,%o3 + b 9f + add %o2, (-7*2-1), %o2 + + 9: +Lend_regular_divide: + subcc %o4, 1, %o4 + bge Ldivloop + tst %o3 + + bl,a Lgot_result + ! non-restoring fixup here (one instruction only!) + add %o3, %o1, %o3 + +Lgot_result: + + retl + mov %o3, %o0 + + .globl .urem_patch +.urem_patch: + wr %g0, 0x0, %y + nop + nop + nop + udiv %o0, %o1, %o2 + umul %o2, %o1, %o2 + retl + 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 @@ +/* btfixup.c: Boot time code fixup and relocator, so that + * we can get rid of most indirect calls to achieve single + * image sun4c and srmmu kernel. + * + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BTFIXUP_OPTIMIZE_NOP +#define BTFIXUP_OPTIMIZE_OTHER + +extern char *srmmu_name; +static char version[] __initdata = "Boot time fixup v1.6. 4/Mar/98 Jakub Jelinek (jj@ultra.linux.cz). Patching kernel for "; +static char str_sun4c[] __initdata = "sun4c\n"; +static char str_srmmu[] __initdata = "srmmu[%s]/"; +static char str_iommu[] __initdata = "iommu\n"; +static char str_iounit[] __initdata = "io-unit\n"; + +static int visited __initdata = 0; +extern unsigned int ___btfixup_start[], ___btfixup_end[], __init_begin[], __init_end[], __init_text_end[]; +extern unsigned int _stext[], _end[], __start___ksymtab[], __stop___ksymtab[]; +static char wrong_f[] __initdata = "Trying to set f fixup %p to invalid function %08x\n"; +static char wrong_b[] __initdata = "Trying to set b fixup %p to invalid function %08x\n"; +static char wrong_s[] __initdata = "Trying to set s fixup %p to invalid value %08x\n"; +static char wrong_h[] __initdata = "Trying to set h fixup %p to invalid value %08x\n"; +static char wrong_a[] __initdata = "Trying to set a fixup %p to invalid value %08x\n"; +static char wrong[] __initdata = "Wrong address for %c fixup %p\n"; +static char insn_f[] __initdata = "Fixup f %p refers to weird instructions at %p[%08x,%08x]\n"; +static char insn_b[] __initdata = "Fixup b %p doesn't refer to a SETHI at %p[%08x]\n"; +static char insn_s[] __initdata = "Fixup s %p doesn't refer to an OR at %p[%08x]\n"; +static char insn_h[] __initdata = "Fixup h %p doesn't refer to a SETHI at %p[%08x]\n"; +static char insn_a[] __initdata = "Fixup a %p doesn't refer to a SETHI nor OR at %p[%08x]\n"; +static char insn_i[] __initdata = "Fixup i %p doesn't refer to a valid instruction at %p[%08x]\n"; +static char fca_und[] __initdata = "flush_cache_all undefined in btfixup()\n"; +static char wrong_setaddr[] __initdata = "Garbled CALL/INT patch at %p[%08x,%08x,%08x]=%08x\n"; + +#ifdef BTFIXUP_OPTIMIZE_OTHER +static void __init set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) +{ + if (!fmangled) + *addr = value; + else { + unsigned int *q = (unsigned int *)q1; + if (*addr == 0x01000000) { + /* Noped */ + *q = value; + } else if (addr[-1] == *q) { + /* Moved */ + addr[-1] = value; + *q = value; + } else { + prom_printf(wrong_setaddr, addr-1, addr[-1], *addr, *q, value); + prom_halt(); + } + } +} +#else +static inline void set_addr(unsigned int *addr, unsigned int q1, int fmangled, unsigned int value) +{ + *addr = value; +} +#endif + +void __init btfixup(void) +{ + unsigned int *p, *q; + int type, count; + unsigned insn; + unsigned *addr; + int fmangled = 0; + void (*flush_cacheall)(void); + + if (!visited) { + visited++; + printk(version); + if (ARCH_SUN4C) + printk(str_sun4c); + else { + printk(str_srmmu, srmmu_name); + if (sparc_cpu_model == sun4d) + printk(str_iounit); + else + printk(str_iommu); + } + } + for (p = ___btfixup_start; p < ___btfixup_end; ) { + count = p[2]; + q = p + 3; + switch (type = *(unsigned char *)p) { + case 'f': + count = p[3]; + q = p + 4; + if (((p[0] & 1) || p[1]) + && ((p[1] & 3) || (unsigned *)(p[1]) < _stext || (unsigned *)(p[1]) >= _end)) { + prom_printf(wrong_f, p, p[1]); + prom_halt(); + } + break; + case 'b': + if (p[1] < (unsigned long)__init_begin || p[1] >= (unsigned long)__init_text_end || (p[1] & 3)) { + prom_printf(wrong_b, p, p[1]); + prom_halt(); + } + break; + case 's': + if (p[1] + 0x1000 >= 0x2000) { + prom_printf(wrong_s, p, p[1]); + prom_halt(); + } + break; + case 'h': + if (p[1] & 0x3ff) { + prom_printf(wrong_h, p, p[1]); + prom_halt(); + } + break; + case 'a': + if (p[1] + 0x1000 >= 0x2000 && (p[1] & 0x3ff)) { + prom_printf(wrong_a, p, p[1]); + prom_halt(); + } + break; + } + if (p[0] & 1) { + p[0] &= ~1; + while (count) { + fmangled = 0; + addr = (unsigned *)*q; + if (addr < _stext || addr >= _end) { + prom_printf(wrong, type, p); + prom_halt(); + } + insn = *addr; +#ifdef BTFIXUP_OPTIMIZE_OTHER + if (type != 'f' && q[1]) { + insn = *(unsigned int *)q[1]; + if (!insn || insn == 1) + insn = *addr; + else + fmangled = 1; + } +#endif + switch (type) { + case 'f': /* CALL */ + if (addr >= __start___ksymtab && addr < __stop___ksymtab) { + *addr = p[1]; + break; + } else if (!q[1]) { + if ((insn & 0xc1c00000) == 0x01000000) { /* SETHI */ + *addr = (insn & 0xffc00000) | (p[1] >> 10); break; + } else if ((insn & 0xc1f82000) == 0x80102000) { /* OR X, %LO(i), Y */ + *addr = (insn & 0xffffe000) | (p[1] & 0x3ff); break; + } else if ((insn & 0xc0000000) != 0x40000000) { /* !CALL */ + bad_f: + prom_printf(insn_f, p, addr, insn, addr[1]); + prom_halt(); + } + } else if (q[1] != 1) + addr[1] = q[1]; + if (p[2] == BTFIXUPCALL_NORM) { + norm_f: + *addr = 0x40000000 | ((p[1] - (unsigned)addr) >> 2); + q[1] = 0; + break; + } +#ifndef BTFIXUP_OPTIMIZE_NOP + goto norm_f; +#else + if (!(addr[1] & 0x80000000)) { + if ((addr[1] & 0xc1c00000) != 0x01000000) /* !SETHI */ + goto bad_f; /* CALL, Bicc, FBfcc, CBccc are weird in delay slot, aren't they? */ + } else { + if ((addr[1] & 0x01800000) == 0x01800000) { + if ((addr[1] & 0x01f80000) == 0x01e80000) { + /* RESTORE */ + goto norm_f; /* It is dangerous to patch that */ + } + goto bad_f; + } + if ((addr[1] & 0xffffe003) == 0x9e03e000) { + /* ADD %O7, XX, %o7 */ + int displac = (addr[1] << 19); + + displac = (displac >> 21) + 2; + *addr = (0x10800000) + (displac & 0x3fffff); + q[1] = addr[1]; + addr[1] = p[2]; + break; + } + if ((addr[1] & 0x201f) == 0x200f || (addr[1] & 0x7c000) == 0x3c000) + goto norm_f; /* Someone is playing bad tricks with us: rs1 or rs2 is o7 */ + if ((addr[1] & 0x3e000000) == 0x1e000000) + goto norm_f; /* rd is %o7. We'd better take care. */ + } + if (p[2] == BTFIXUPCALL_NOP) { + *addr = 0x01000000; + q[1] = 1; + break; + } +#ifndef BTFIXUP_OPTIMIZE_OTHER + goto norm_f; +#else + if (addr[1] == 0x01000000) { /* NOP in the delay slot */ + q[1] = addr[1]; + *addr = p[2]; + break; + } + if ((addr[1] & 0xc0000000) != 0xc0000000) { + /* Not a memory operation */ + if ((addr[1] & 0x30000000) == 0x10000000) { + /* Ok, non-memory op with rd %oX */ + if ((addr[1] & 0x3e000000) == 0x1c000000) + goto bad_f; /* Aiee. Someone is playing strange %sp tricks */ + if ((addr[1] & 0x3e000000) > 0x12000000 || + ((addr[1] & 0x3e000000) == 0x12000000 && + p[2] != BTFIXUPCALL_STO1O0 && p[2] != BTFIXUPCALL_SWAPO0O1) || + ((p[2] & 0xffffe000) == BTFIXUPCALL_RETINT(0))) { + /* Nobody uses the result. We can nop it out. */ + *addr = p[2]; + q[1] = addr[1]; + addr[1] = 0x01000000; + break; + } + if ((addr[1] & 0xf1ffffe0) == 0x90100000) { + /* MOV %reg, %Ox */ + if ((addr[1] & 0x3e000000) == 0x10000000 && + (p[2] & 0x7c000) == 0x20000) { + /* Ok, it is call xx; mov reg, %o0 and call optimizes + to doing something on %o0. Patch the patch. */ + *addr = (p[2] & ~0x7c000) | ((addr[1] & 0x1f) << 14); + q[1] = addr[1]; + addr[1] = 0x01000000; + break; + } + if ((addr[1] & 0x3e000000) == 0x12000000 && + p[2] == BTFIXUPCALL_STO1O0) { + *addr = (p[2] & ~0x3e000000) | ((addr[1] & 0x1f) << 25); + q[1] = addr[1]; + addr[1] = 0x01000000; + break; + } + } + } + } + *addr = addr[1]; + q[1] = addr[1]; + addr[1] = p[2]; + break; +#endif /* BTFIXUP_OPTIMIZE_OTHER */ +#endif /* BTFIXUP_OPTIMIZE_NOP */ + case 'b': /* BLACKBOX */ + /* Has to be sethi i, xx */ + if ((insn & 0xc1c00000) != 0x01000000) { + prom_printf(insn_b, p, addr, insn); + prom_halt(); + } else { + void (*do_fixup)(unsigned *); + + do_fixup = (void (*)(unsigned *))p[1]; + do_fixup(addr); + } + break; + case 's': /* SIMM13 */ + /* Has to be or %g0, i, xx */ + if ((insn & 0xc1ffe000) != 0x80102000) { + prom_printf(insn_s, p, addr, insn); + prom_halt(); + } + set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x1fff)); + break; + case 'h': /* SETHI */ + /* Has to be sethi i, xx */ + if ((insn & 0xc1c00000) != 0x01000000) { + prom_printf(insn_h, p, addr, insn); + prom_halt(); + } + set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); + break; + case 'a': /* HALF */ + /* Has to be sethi i, xx or or %g0, i, xx */ + if ((insn & 0xc1c00000) != 0x01000000 && + (insn & 0xc1ffe000) != 0x80102000) { + prom_printf(insn_a, p, addr, insn); + prom_halt(); + } + if (p[1] & 0x3ff) + set_addr(addr, q[1], fmangled, + (insn & 0x3e000000) | 0x80102000 | (p[1] & 0x1fff)); + else + set_addr(addr, q[1], fmangled, + (insn & 0x3e000000) | 0x01000000 | (p[1] >> 10)); + break; + case 'i': /* INT */ + if ((insn & 0xc1c00000) == 0x01000000) /* %HI */ + set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); + else if ((insn & 0x80002000) == 0x80002000) /* %LO */ + set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff)); + else { + prom_printf(insn_i, p, addr, insn); + prom_halt(); + } + break; + } + count -= 2; + q += 2; + } + } else + p = q + count; + } +#ifdef CONFIG_SMP + flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(local_flush_cache_all); +#else + flush_cacheall = (void (*)(void))BTFIXUPVAL_CALL(flush_cache_all); +#endif + if (!flush_cacheall) { + prom_printf(fca_und); + prom_halt(); + } + (*flush_cacheall)(); +} 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 @@ +/* + * loadmmu.c: This code loads up all the mm function pointers once the + * machine type has been determined. It also sets the static + * mmu values such as PAGE_NONE, etc. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +struct ctx_list *ctx_list_pool; +struct ctx_list ctx_free; +struct ctx_list ctx_used; + +extern void ld_mmu_sun4c(void); +extern void ld_mmu_srmmu(void); + +void __init load_mmu(void) +{ + switch(sparc_cpu_model) { + case sun4c: + case sun4: + ld_mmu_sun4c(); + break; + case sun4m: + case sun4d: + case sparc_leon: + ld_mmu_srmmu(); + break; + default: + prom_printf("load_mmu: %d unsupported\n", (int)sparc_cpu_model); + prom_halt(); + } + btfixup(); +} 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 @@ +/* + * nosun4c.c: This file is a bunch of dummies for SMP compiles, + * so that it does not need sun4c and avoid ifdefs. + * + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include +#include +#include +#include + +static char shouldnothappen[] __initdata = "32bit SMP kernel only supports sun4m and sun4d\n"; + +/* Dummies */ +struct sun4c_mmu_ring { + unsigned long xxx1[3]; + unsigned char xxx2[2]; + int xxx3; +}; +struct sun4c_mmu_ring sun4c_kernel_ring; +struct sun4c_mmu_ring sun4c_kfree_ring; +unsigned long sun4c_kernel_faults; +unsigned long *sun4c_memerr_reg; + +static void __init should_not_happen(void) +{ + prom_printf(shouldnothappen); + prom_halt(); +} + +unsigned long __init sun4c_paging_init(unsigned long start_mem, unsigned long end_mem) +{ + should_not_happen(); + return 0; +} + +void __init ld_mmu_sun4c(void) +{ + should_not_happen(); +} + +void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus_type, int rdonly) +{ +} + +void sun4c_unmapioaddr(unsigned long virt_addr) +{ +} + +void sun4c_complete_all_stores(void) +{ +} + +pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address) +{ + return NULL; +} + +pte_t *sun4c_pte_offset_kernel(pmd_t *dir, unsigned long address) +{ + return NULL; +} + +void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +{ +} + +void __init sun4c_probe_vac(void) +{ + should_not_happen(); +} + +void __init sun4c_probe_memerr_reg(void) +{ + should_not_happen(); +} 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 @@ +/* sun4c.c: Doing in software what should be done in hardware. + * + * Copyright (C) 1996 David S. Miller (davem@davemloft.net) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1996 Andrew Tridgell (Andrew.Tridgell@anu.edu.au) + * Copyright (C) 1997-2000 Anton Blanchard (anton@samba.org) + * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#define NR_TASK_BUCKETS 512 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Because of our dynamic kernel TLB miss strategy, and how + * our DVMA mapping allocation works, you _MUST_: + * + * 1) Disable interrupts _and_ not touch any dynamic kernel + * memory while messing with kernel MMU state. By + * dynamic memory I mean any object which is not in + * the kernel image itself or a thread_union (both of + * which are locked into the MMU). + * 2) Disable interrupts while messing with user MMU state. + */ + +extern int num_segmaps, num_contexts; + +extern unsigned long page_kernel; + +/* That's it, we prom_halt() on sun4c if the cache size is something other than 65536. + * So let's save some cycles and just use that everywhere except for that bootup + * sanity check. + */ +#define SUN4C_VAC_SIZE 65536 + +#define SUN4C_KERNEL_BUCKETS 32 + +/* Flushing the cache. */ +struct sun4c_vac_props sun4c_vacinfo; +unsigned long sun4c_kernel_faults; + +/* Invalidate every sun4c cache line tag. */ +static void __init sun4c_flush_all(void) +{ + unsigned long begin, end; + + if (sun4c_vacinfo.on) + panic("SUN4C: AIEEE, trying to invalidate vac while it is on."); + + /* Clear 'valid' bit in all cache line tags */ + begin = AC_CACHETAGS; + end = (AC_CACHETAGS + SUN4C_VAC_SIZE); + while (begin < end) { + __asm__ __volatile__("sta %%g0, [%0] %1\n\t" : : + "r" (begin), "i" (ASI_CONTROL)); + begin += sun4c_vacinfo.linesize; + } +} + +static void sun4c_flush_context_hw(void) +{ + unsigned long end = SUN4C_VAC_SIZE; + + __asm__ __volatile__( + "1: addcc %0, -4096, %0\n\t" + " bne 1b\n\t" + " sta %%g0, [%0] %2" + : "=&r" (end) + : "0" (end), "i" (ASI_HWFLUSHCONTEXT) + : "cc"); +} + +/* Must be called minimally with IRQs disabled. */ +static void sun4c_flush_segment_hw(unsigned long addr) +{ + if (sun4c_get_segmap(addr) != invalid_segment) { + unsigned long vac_size = SUN4C_VAC_SIZE; + + __asm__ __volatile__( + "1: addcc %0, -4096, %0\n\t" + " bne 1b\n\t" + " sta %%g0, [%2 + %0] %3" + : "=&r" (vac_size) + : "0" (vac_size), "r" (addr), "i" (ASI_HWFLUSHSEG) + : "cc"); + } +} + +/* File local boot time fixups. */ +BTFIXUPDEF_CALL(void, sun4c_flush_page, unsigned long) +BTFIXUPDEF_CALL(void, sun4c_flush_segment, unsigned long) +BTFIXUPDEF_CALL(void, sun4c_flush_context, void) + +#define sun4c_flush_page(addr) BTFIXUP_CALL(sun4c_flush_page)(addr) +#define sun4c_flush_segment(addr) BTFIXUP_CALL(sun4c_flush_segment)(addr) +#define sun4c_flush_context() BTFIXUP_CALL(sun4c_flush_context)() + +/* Must be called minimally with interrupts disabled. */ +static void sun4c_flush_page_hw(unsigned long addr) +{ + addr &= PAGE_MASK; + if ((int)sun4c_get_pte(addr) < 0) + __asm__ __volatile__("sta %%g0, [%0] %1" + : : "r" (addr), "i" (ASI_HWFLUSHPAGE)); +} + +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_context_sw(void) +{ + unsigned long nbytes = SUN4C_VAC_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; + + __asm__ __volatile__( + "add %2, %2, %%g1\n\t" + "add %2, %%g1, %%g2\n\t" + "add %2, %%g2, %%g3\n\t" + "add %2, %%g3, %%g4\n\t" + "add %2, %%g4, %%g5\n\t" + "add %2, %%g5, %%o4\n\t" + "add %2, %%o4, %%o5\n" + "1:\n\t" + "subcc %0, %%o5, %0\n\t" + "sta %%g0, [%0] %3\n\t" + "sta %%g0, [%0 + %2] %3\n\t" + "sta %%g0, [%0 + %%g1] %3\n\t" + "sta %%g0, [%0 + %%g2] %3\n\t" + "sta %%g0, [%0 + %%g3] %3\n\t" + "sta %%g0, [%0 + %%g4] %3\n\t" + "sta %%g0, [%0 + %%g5] %3\n\t" + "bg 1b\n\t" + " sta %%g0, [%1 + %%o4] %3\n" + : "=&r" (nbytes) + : "0" (nbytes), "r" (lsize), "i" (ASI_FLUSHCTX) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); +} + +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_segment_sw(unsigned long addr) +{ + if (sun4c_get_segmap(addr) != invalid_segment) { + unsigned long nbytes = SUN4C_VAC_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; + + __asm__ __volatile__( + "add %2, %2, %%g1\n\t" + "add %2, %%g1, %%g2\n\t" + "add %2, %%g2, %%g3\n\t" + "add %2, %%g3, %%g4\n\t" + "add %2, %%g4, %%g5\n\t" + "add %2, %%g5, %%o4\n\t" + "add %2, %%o4, %%o5\n" + "1:\n\t" + "subcc %1, %%o5, %1\n\t" + "sta %%g0, [%0] %6\n\t" + "sta %%g0, [%0 + %2] %6\n\t" + "sta %%g0, [%0 + %%g1] %6\n\t" + "sta %%g0, [%0 + %%g2] %6\n\t" + "sta %%g0, [%0 + %%g3] %6\n\t" + "sta %%g0, [%0 + %%g4] %6\n\t" + "sta %%g0, [%0 + %%g5] %6\n\t" + "sta %%g0, [%0 + %%o4] %6\n\t" + "bg 1b\n\t" + " add %0, %%o5, %0\n" + : "=&r" (addr), "=&r" (nbytes), "=&r" (lsize) + : "0" (addr), "1" (nbytes), "2" (lsize), + "i" (ASI_FLUSHSEG) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); + } +} + +/* Don't inline the software version as it eats too many cache lines if expanded. */ +static void sun4c_flush_page_sw(unsigned long addr) +{ + addr &= PAGE_MASK; + if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) == + _SUN4C_PAGE_VALID) { + unsigned long left = PAGE_SIZE; + unsigned long lsize = sun4c_vacinfo.linesize; + + __asm__ __volatile__( + "add %2, %2, %%g1\n\t" + "add %2, %%g1, %%g2\n\t" + "add %2, %%g2, %%g3\n\t" + "add %2, %%g3, %%g4\n\t" + "add %2, %%g4, %%g5\n\t" + "add %2, %%g5, %%o4\n\t" + "add %2, %%o4, %%o5\n" + "1:\n\t" + "subcc %1, %%o5, %1\n\t" + "sta %%g0, [%0] %6\n\t" + "sta %%g0, [%0 + %2] %6\n\t" + "sta %%g0, [%0 + %%g1] %6\n\t" + "sta %%g0, [%0 + %%g2] %6\n\t" + "sta %%g0, [%0 + %%g3] %6\n\t" + "sta %%g0, [%0 + %%g4] %6\n\t" + "sta %%g0, [%0 + %%g5] %6\n\t" + "sta %%g0, [%0 + %%o4] %6\n\t" + "bg 1b\n\t" + " add %0, %%o5, %0\n" + : "=&r" (addr), "=&r" (left), "=&r" (lsize) + : "0" (addr), "1" (left), "2" (lsize), + "i" (ASI_FLUSHPG) + : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc"); + } +} + +/* The sun4c's do have an on chip store buffer. And the way you + * clear them out isn't so obvious. The only way I can think of + * to accomplish this is to read the current context register, + * store the same value there, then read an external hardware + * register. + */ +void sun4c_complete_all_stores(void) +{ + volatile int _unused; + + _unused = sun4c_get_context(); + sun4c_set_context(_unused); + _unused = get_auxio(); +} + +/* Bootup utility functions. */ +static inline void sun4c_init_clean_segmap(unsigned char pseg) +{ + unsigned long vaddr; + + sun4c_put_segmap(0, pseg); + for (vaddr = 0; vaddr < SUN4C_REAL_PGDIR_SIZE; vaddr += PAGE_SIZE) + sun4c_put_pte(vaddr, 0); + sun4c_put_segmap(0, invalid_segment); +} + +static inline void sun4c_init_clean_mmu(unsigned long kernel_end) +{ + unsigned long vaddr; + unsigned char savectx, ctx; + + savectx = sun4c_get_context(); + for (ctx = 0; ctx < num_contexts; ctx++) { + sun4c_set_context(ctx); + for (vaddr = 0; vaddr < 0x20000000; vaddr += SUN4C_REAL_PGDIR_SIZE) + sun4c_put_segmap(vaddr, invalid_segment); + for (vaddr = 0xe0000000; vaddr < KERNBASE; vaddr += SUN4C_REAL_PGDIR_SIZE) + sun4c_put_segmap(vaddr, invalid_segment); + for (vaddr = kernel_end; vaddr < KADB_DEBUGGER_BEGVM; vaddr += SUN4C_REAL_PGDIR_SIZE) + sun4c_put_segmap(vaddr, invalid_segment); + for (vaddr = LINUX_OPPROM_ENDVM; vaddr; vaddr += SUN4C_REAL_PGDIR_SIZE) + sun4c_put_segmap(vaddr, invalid_segment); + } + sun4c_set_context(savectx); +} + +void __init sun4c_probe_vac(void) +{ + sun4c_disable_vac(); + + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { + /* PROM on SS1 lacks this info, to be super safe we + * hard code it here since this arch is cast in stone. + */ + sun4c_vacinfo.num_bytes = 65536; + sun4c_vacinfo.linesize = 16; + } else { + sun4c_vacinfo.num_bytes = + prom_getintdefault(prom_root_node, "vac-size", 65536); + sun4c_vacinfo.linesize = + prom_getintdefault(prom_root_node, "vac-linesize", 16); + } + sun4c_vacinfo.do_hwflushes = + prom_getintdefault(prom_root_node, "vac-hwflush", 0); + + if (sun4c_vacinfo.do_hwflushes == 0) + sun4c_vacinfo.do_hwflushes = + prom_getintdefault(prom_root_node, "vac_hwflush", 0); + + if (sun4c_vacinfo.num_bytes != 65536) { + prom_printf("WEIRD Sun4C VAC cache size, " + "tell sparclinux@vger.kernel.org"); + prom_halt(); + } + + switch (sun4c_vacinfo.linesize) { + case 16: + sun4c_vacinfo.log2lsize = 4; + break; + case 32: + sun4c_vacinfo.log2lsize = 5; + break; + default: + prom_printf("probe_vac: Didn't expect vac-linesize of %d, halting\n", + sun4c_vacinfo.linesize); + prom_halt(); + } + + sun4c_flush_all(); + sun4c_enable_vac(); +} + +/* Patch instructions for the low level kernel fault handler. */ +extern unsigned long invalid_segment_patch1, invalid_segment_patch1_ff; +extern unsigned long invalid_segment_patch2, invalid_segment_patch2_ff; +extern unsigned long invalid_segment_patch1_1ff, invalid_segment_patch2_1ff; +extern unsigned long num_context_patch1, num_context_patch1_16; +extern unsigned long num_context_patch2_16; +extern unsigned long vac_linesize_patch, vac_linesize_patch_32; +extern unsigned long vac_hwflush_patch1, vac_hwflush_patch1_on; +extern unsigned long vac_hwflush_patch2, vac_hwflush_patch2_on; + +#define PATCH_INSN(src, dst) do { \ + daddr = &(dst); \ + iaddr = &(src); \ + *daddr = *iaddr; \ + } while (0) + +static void __init patch_kernel_fault_handler(void) +{ + unsigned long *iaddr, *daddr; + + switch (num_segmaps) { + case 128: + /* Default, nothing to do. */ + break; + case 256: + PATCH_INSN(invalid_segment_patch1_ff, + invalid_segment_patch1); + PATCH_INSN(invalid_segment_patch2_ff, + invalid_segment_patch2); + break; + case 512: + PATCH_INSN(invalid_segment_patch1_1ff, + invalid_segment_patch1); + PATCH_INSN(invalid_segment_patch2_1ff, + invalid_segment_patch2); + break; + default: + prom_printf("Unhandled number of segmaps: %d\n", + num_segmaps); + prom_halt(); + } + switch (num_contexts) { + case 8: + /* Default, nothing to do. */ + break; + case 16: + PATCH_INSN(num_context_patch1_16, + num_context_patch1); + break; + default: + prom_printf("Unhandled number of contexts: %d\n", + num_contexts); + prom_halt(); + } + + if (sun4c_vacinfo.do_hwflushes != 0) { + PATCH_INSN(vac_hwflush_patch1_on, vac_hwflush_patch1); + PATCH_INSN(vac_hwflush_patch2_on, vac_hwflush_patch2); + } else { + switch (sun4c_vacinfo.linesize) { + case 16: + /* Default, nothing to do. */ + break; + case 32: + PATCH_INSN(vac_linesize_patch_32, vac_linesize_patch); + break; + default: + prom_printf("Impossible VAC linesize %d, halting...\n", + sun4c_vacinfo.linesize); + prom_halt(); + } + } +} + +static void __init sun4c_probe_mmu(void) +{ + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) { + /* Hardcode these just to be safe, PROM on SS1 does + * not have this info available in the root node. + */ + num_segmaps = 128; + num_contexts = 8; + } else { + num_segmaps = + prom_getintdefault(prom_root_node, "mmu-npmg", 128); + num_contexts = + prom_getintdefault(prom_root_node, "mmu-nctx", 0x8); + } + patch_kernel_fault_handler(); +} + +volatile unsigned long __iomem *sun4c_memerr_reg = NULL; + +void __init sun4c_probe_memerr_reg(void) +{ + phandle node; + struct linux_prom_registers regs[1]; + + node = prom_getchild(prom_root_node); + node = prom_searchsiblings(prom_root_node, "memory-error"); + if (!node) + return; + if (prom_getproperty(node, "reg", (char *)regs, sizeof(regs)) <= 0) + return; + /* hmm I think regs[0].which_io is zero here anyways */ + sun4c_memerr_reg = ioremap(regs[0].phys_addr, regs[0].reg_size); +} + +static inline void sun4c_init_ss2_cache_bug(void) +{ + if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_IPX)) || + (idprom->id_machtype == (SM_SUN4C | SM_4C_ELC))) { + /* Whee.. */ + printk("SS2 cache bug detected, uncaching trap table page\n"); + sun4c_flush_page((unsigned int) &_start); + sun4c_put_pte(((unsigned long) &_start), + (sun4c_get_pte((unsigned long) &_start) | _SUN4C_PAGE_NOCACHE)); + } +} + +/* Addr is always aligned on a page boundary for us already. */ +static int sun4c_map_dma_area(struct device *dev, dma_addr_t *pba, unsigned long va, + unsigned long addr, int len) +{ + unsigned long page, end; + + *pba = addr; + + end = PAGE_ALIGN((addr + len)); + while (addr < end) { + page = va; + sun4c_flush_page(page); + page -= PAGE_OFFSET; + page >>= PAGE_SHIFT; + page |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_DIRTY | + _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_PRIV); + sun4c_put_pte(addr, page); + addr += PAGE_SIZE; + va += PAGE_SIZE; + } + + return 0; +} + +static void sun4c_unmap_dma_area(struct device *dev, unsigned long busa, int len) +{ + /* Fortunately for us, bus_addr == uncached_virt in sun4c. */ + /* XXX Implement this */ +} + +/* TLB management. */ + +/* Don't change this struct without changing entry.S. This is used + * in the in-window kernel fault handler, and you don't want to mess + * with that. (See sun4c_fault in entry.S). + */ +struct sun4c_mmu_entry { + struct sun4c_mmu_entry *next; + struct sun4c_mmu_entry *prev; + unsigned long vaddr; + unsigned char pseg; + unsigned char locked; + + /* For user mappings only, and completely hidden from kernel + * TLB miss code. + */ + unsigned char ctx; + struct sun4c_mmu_entry *lru_next; + struct sun4c_mmu_entry *lru_prev; +}; + +static struct sun4c_mmu_entry mmu_entry_pool[SUN4C_MAX_SEGMAPS]; + +static void __init sun4c_init_mmu_entry_pool(void) +{ + int i; + + for (i=0; i < SUN4C_MAX_SEGMAPS; i++) { + mmu_entry_pool[i].pseg = i; + mmu_entry_pool[i].next = NULL; + mmu_entry_pool[i].prev = NULL; + mmu_entry_pool[i].vaddr = 0; + mmu_entry_pool[i].locked = 0; + mmu_entry_pool[i].ctx = 0; + mmu_entry_pool[i].lru_next = NULL; + mmu_entry_pool[i].lru_prev = NULL; + } + mmu_entry_pool[invalid_segment].locked = 1; +} + +static inline void fix_permissions(unsigned long vaddr, unsigned long bits_on, + unsigned long bits_off) +{ + unsigned long start, end; + + end = vaddr + SUN4C_REAL_PGDIR_SIZE; + for (start = vaddr; start < end; start += PAGE_SIZE) + if (sun4c_get_pte(start) & _SUN4C_PAGE_VALID) + sun4c_put_pte(start, (sun4c_get_pte(start) | bits_on) & + ~bits_off); +} + +static inline void sun4c_init_map_kernelprom(unsigned long kernel_end) +{ + unsigned long vaddr; + unsigned char pseg, ctx; + + for (vaddr = KADB_DEBUGGER_BEGVM; + vaddr < LINUX_OPPROM_ENDVM; + vaddr += SUN4C_REAL_PGDIR_SIZE) { + pseg = sun4c_get_segmap(vaddr); + if (pseg != invalid_segment) { + mmu_entry_pool[pseg].locked = 1; + for (ctx = 0; ctx < num_contexts; ctx++) + prom_putsegment(ctx, vaddr, pseg); + fix_permissions(vaddr, _SUN4C_PAGE_PRIV, 0); + } + } + + for (vaddr = KERNBASE; vaddr < kernel_end; vaddr += SUN4C_REAL_PGDIR_SIZE) { + pseg = sun4c_get_segmap(vaddr); + mmu_entry_pool[pseg].locked = 1; + for (ctx = 0; ctx < num_contexts; ctx++) + prom_putsegment(ctx, vaddr, pseg); + fix_permissions(vaddr, _SUN4C_PAGE_PRIV, _SUN4C_PAGE_NOCACHE); + } +} + +static void __init sun4c_init_lock_area(unsigned long start, unsigned long end) +{ + int i, ctx; + + while (start < end) { + for (i = 0; i < invalid_segment; i++) + if (!mmu_entry_pool[i].locked) + break; + mmu_entry_pool[i].locked = 1; + sun4c_init_clean_segmap(i); + for (ctx = 0; ctx < num_contexts; ctx++) + prom_putsegment(ctx, start, mmu_entry_pool[i].pseg); + start += SUN4C_REAL_PGDIR_SIZE; + } +} + +/* Don't change this struct without changing entry.S. This is used + * in the in-window kernel fault handler, and you don't want to mess + * with that. (See sun4c_fault in entry.S). + */ +struct sun4c_mmu_ring { + struct sun4c_mmu_entry ringhd; + int num_entries; +}; + +static struct sun4c_mmu_ring sun4c_context_ring[SUN4C_MAX_CONTEXTS]; /* used user entries */ +static struct sun4c_mmu_ring sun4c_ufree_ring; /* free user entries */ +static struct sun4c_mmu_ring sun4c_ulru_ring; /* LRU user entries */ +struct sun4c_mmu_ring sun4c_kernel_ring; /* used kernel entries */ +struct sun4c_mmu_ring sun4c_kfree_ring; /* free kernel entries */ + +static inline void sun4c_init_rings(void) +{ + int i; + + for (i = 0; i < SUN4C_MAX_CONTEXTS; i++) { + sun4c_context_ring[i].ringhd.next = + sun4c_context_ring[i].ringhd.prev = + &sun4c_context_ring[i].ringhd; + sun4c_context_ring[i].num_entries = 0; + } + sun4c_ufree_ring.ringhd.next = sun4c_ufree_ring.ringhd.prev = + &sun4c_ufree_ring.ringhd; + sun4c_ufree_ring.num_entries = 0; + sun4c_ulru_ring.ringhd.lru_next = sun4c_ulru_ring.ringhd.lru_prev = + &sun4c_ulru_ring.ringhd; + sun4c_ulru_ring.num_entries = 0; + sun4c_kernel_ring.ringhd.next = sun4c_kernel_ring.ringhd.prev = + &sun4c_kernel_ring.ringhd; + sun4c_kernel_ring.num_entries = 0; + sun4c_kfree_ring.ringhd.next = sun4c_kfree_ring.ringhd.prev = + &sun4c_kfree_ring.ringhd; + sun4c_kfree_ring.num_entries = 0; +} + +static void add_ring(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_entry *head = &ring->ringhd; + + entry->prev = head; + (entry->next = head->next)->prev = entry; + head->next = entry; + ring->num_entries++; +} + +static inline void add_lru(struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_ring *ring = &sun4c_ulru_ring; + struct sun4c_mmu_entry *head = &ring->ringhd; + + entry->lru_next = head; + (entry->lru_prev = head->lru_prev)->lru_next = entry; + head->lru_prev = entry; +} + +static void add_ring_ordered(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_entry *head = &ring->ringhd; + unsigned long addr = entry->vaddr; + + while ((head->next != &ring->ringhd) && (head->next->vaddr < addr)) + head = head->next; + + entry->prev = head; + (entry->next = head->next)->prev = entry; + head->next = entry; + ring->num_entries++; + + add_lru(entry); +} + +static inline void remove_ring(struct sun4c_mmu_ring *ring, + struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_entry *next = entry->next; + + (next->prev = entry->prev)->next = next; + ring->num_entries--; +} + +static void remove_lru(struct sun4c_mmu_entry *entry) +{ + struct sun4c_mmu_entry *next = entry->lru_next; + + (next->lru_prev = entry->lru_prev)->lru_next = next; +} + +static void free_user_entry(int ctx, struct sun4c_mmu_entry *entry) +{ + remove_ring(sun4c_context_ring+ctx, entry); + remove_lru(entry); + add_ring(&sun4c_ufree_ring, entry); +} + +static void free_kernel_entry(struct sun4c_mmu_entry *entry, + struct sun4c_mmu_ring *ring) +{ + remove_ring(ring, entry); + add_ring(&sun4c_kfree_ring, entry); +} + +static void __init sun4c_init_fill_kernel_ring(int howmany) +{ + int i; + + while (howmany) { + for (i = 0; i < invalid_segment; i++) + if (!mmu_entry_pool[i].locked) + break; + mmu_entry_pool[i].locked = 1; + sun4c_init_clean_segmap(i); + add_ring(&sun4c_kfree_ring, &mmu_entry_pool[i]); + howmany--; + } +} + +static void __init sun4c_init_fill_user_ring(void) +{ + int i; + + for (i = 0; i < invalid_segment; i++) { + if (mmu_entry_pool[i].locked) + continue; + sun4c_init_clean_segmap(i); + add_ring(&sun4c_ufree_ring, &mmu_entry_pool[i]); + } +} + +static void sun4c_kernel_unmap(struct sun4c_mmu_entry *kentry) +{ + int savectx, ctx; + + savectx = sun4c_get_context(); + for (ctx = 0; ctx < num_contexts; ctx++) { + sun4c_set_context(ctx); + sun4c_put_segmap(kentry->vaddr, invalid_segment); + } + sun4c_set_context(savectx); +} + +static void sun4c_kernel_map(struct sun4c_mmu_entry *kentry) +{ + int savectx, ctx; + + savectx = sun4c_get_context(); + for (ctx = 0; ctx < num_contexts; ctx++) { + sun4c_set_context(ctx); + sun4c_put_segmap(kentry->vaddr, kentry->pseg); + } + sun4c_set_context(savectx); +} + +#define sun4c_user_unmap(__entry) \ + sun4c_put_segmap((__entry)->vaddr, invalid_segment) + +static void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx) +{ + struct sun4c_mmu_entry *head = &crp->ringhd; + unsigned long flags; + + local_irq_save(flags); + if (head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + flush_user_windows(); + sun4c_set_context(ctx); + sun4c_flush_context(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(ctx, entry); + + entry = next; + } while (entry != head); + sun4c_set_context(savectx); + } + local_irq_restore(flags); +} + +static int sun4c_user_taken_entries; /* This is how much we have. */ +static int max_user_taken_entries; /* This limits us and prevents deadlock. */ + +static struct sun4c_mmu_entry *sun4c_kernel_strategy(void) +{ + struct sun4c_mmu_entry *this_entry; + + /* If some are free, return first one. */ + if (sun4c_kfree_ring.num_entries) { + this_entry = sun4c_kfree_ring.ringhd.next; + return this_entry; + } + + /* Else free one up. */ + this_entry = sun4c_kernel_ring.ringhd.prev; + sun4c_flush_segment(this_entry->vaddr); + sun4c_kernel_unmap(this_entry); + free_kernel_entry(this_entry, &sun4c_kernel_ring); + this_entry = sun4c_kfree_ring.ringhd.next; + + return this_entry; +} + +/* Using this method to free up mmu entries eliminates a lot of + * potential races since we have a kernel that incurs tlb + * replacement faults. There may be performance penalties. + * + * NOTE: Must be called with interrupts disabled. + */ +static struct sun4c_mmu_entry *sun4c_user_strategy(void) +{ + struct sun4c_mmu_entry *entry; + unsigned char ctx; + int savectx; + + /* If some are free, return first one. */ + if (sun4c_ufree_ring.num_entries) { + entry = sun4c_ufree_ring.ringhd.next; + goto unlink_out; + } + + if (sun4c_user_taken_entries) { + entry = sun4c_kernel_strategy(); + sun4c_user_taken_entries--; + goto kunlink_out; + } + + /* Grab from the beginning of the LRU list. */ + entry = sun4c_ulru_ring.ringhd.lru_next; + ctx = entry->ctx; + + savectx = sun4c_get_context(); + flush_user_windows(); + sun4c_set_context(ctx); + sun4c_flush_segment(entry->vaddr); + sun4c_user_unmap(entry); + remove_ring(sun4c_context_ring + ctx, entry); + remove_lru(entry); + sun4c_set_context(savectx); + + return entry; + +unlink_out: + remove_ring(&sun4c_ufree_ring, entry); + return entry; +kunlink_out: + remove_ring(&sun4c_kfree_ring, entry); + return entry; +} + +/* NOTE: Must be called with interrupts disabled. */ +void sun4c_grow_kernel_ring(void) +{ + struct sun4c_mmu_entry *entry; + + /* Prevent deadlock condition. */ + if (sun4c_user_taken_entries >= max_user_taken_entries) + return; + + if (sun4c_ufree_ring.num_entries) { + entry = sun4c_ufree_ring.ringhd.next; + remove_ring(&sun4c_ufree_ring, entry); + add_ring(&sun4c_kfree_ring, entry); + sun4c_user_taken_entries++; + } +} + +/* 2 page buckets for task struct and kernel stack allocation. + * + * TASK_STACK_BEGIN + * bucket[0] + * bucket[1] + * [ ... ] + * bucket[NR_TASK_BUCKETS-1] + * TASK_STACK_BEGIN + (sizeof(struct task_bucket) * NR_TASK_BUCKETS) + * + * Each slot looks like: + * + * page 1 -- task struct + beginning of kernel stack + * page 2 -- rest of kernel stack + */ + +union task_union *sun4c_bucket[NR_TASK_BUCKETS]; + +static int sun4c_lowbucket_avail; + +#define BUCKET_EMPTY ((union task_union *) 0) +#define BUCKET_SHIFT (PAGE_SHIFT + 1) /* log2(sizeof(struct task_bucket)) */ +#define BUCKET_SIZE (1 << BUCKET_SHIFT) +#define BUCKET_NUM(addr) ((((addr) - SUN4C_LOCK_VADDR) >> BUCKET_SHIFT)) +#define BUCKET_ADDR(num) (((num) << BUCKET_SHIFT) + SUN4C_LOCK_VADDR) +#define BUCKET_PTE(page) \ + ((((page) - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(SUN4C_PAGE_KERNEL)) +#define BUCKET_PTE_PAGE(pte) \ + (PAGE_OFFSET + (((pte) & SUN4C_PFN_MASK) << PAGE_SHIFT)) + +static void get_locked_segment(unsigned long addr) +{ + struct sun4c_mmu_entry *stolen; + unsigned long flags; + + local_irq_save(flags); + addr &= SUN4C_REAL_PGDIR_MASK; + stolen = sun4c_user_strategy(); + max_user_taken_entries--; + stolen->vaddr = addr; + flush_user_windows(); + sun4c_kernel_map(stolen); + local_irq_restore(flags); +} + +static void free_locked_segment(unsigned long addr) +{ + struct sun4c_mmu_entry *entry; + unsigned long flags; + unsigned char pseg; + + local_irq_save(flags); + addr &= SUN4C_REAL_PGDIR_MASK; + pseg = sun4c_get_segmap(addr); + entry = &mmu_entry_pool[pseg]; + + flush_user_windows(); + sun4c_flush_segment(addr); + sun4c_kernel_unmap(entry); + add_ring(&sun4c_ufree_ring, entry); + max_user_taken_entries++; + local_irq_restore(flags); +} + +static inline void garbage_collect(int entry) +{ + int start, end; + + /* 32 buckets per segment... */ + entry &= ~31; + start = entry; + for (end = (start + 32); start < end; start++) + if (sun4c_bucket[start] != BUCKET_EMPTY) + return; + + /* Entire segment empty, release it. */ + free_locked_segment(BUCKET_ADDR(entry)); +} + +static struct thread_info *sun4c_alloc_thread_info_node(int node) +{ + unsigned long addr, pages; + int entry; + + pages = __get_free_pages(GFP_KERNEL, THREAD_INFO_ORDER); + if (!pages) + return NULL; + + for (entry = sun4c_lowbucket_avail; entry < NR_TASK_BUCKETS; entry++) + if (sun4c_bucket[entry] == BUCKET_EMPTY) + break; + if (entry == NR_TASK_BUCKETS) { + free_pages(pages, THREAD_INFO_ORDER); + return NULL; + } + if (entry >= sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry + 1; + + addr = BUCKET_ADDR(entry); + sun4c_bucket[entry] = (union task_union *) addr; + if(sun4c_get_segmap(addr) == invalid_segment) + get_locked_segment(addr); + + /* We are changing the virtual color of the page(s) + * so we must flush the cache to guarantee consistency. + */ + sun4c_flush_page(pages); + sun4c_flush_page(pages + PAGE_SIZE); + + sun4c_put_pte(addr, BUCKET_PTE(pages)); + sun4c_put_pte(addr + PAGE_SIZE, BUCKET_PTE(pages + PAGE_SIZE)); + +#ifdef CONFIG_DEBUG_STACK_USAGE + memset((void *)addr, 0, PAGE_SIZE << THREAD_INFO_ORDER); +#endif /* DEBUG_STACK_USAGE */ + + return (struct thread_info *) addr; +} + +static void sun4c_free_thread_info(struct thread_info *ti) +{ + unsigned long tiaddr = (unsigned long) ti; + unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tiaddr)); + int entry = BUCKET_NUM(tiaddr); + + /* We are deleting a mapping, so the flush here is mandatory. */ + sun4c_flush_page(tiaddr); + sun4c_flush_page(tiaddr + PAGE_SIZE); + + sun4c_put_pte(tiaddr, 0); + sun4c_put_pte(tiaddr + PAGE_SIZE, 0); + + sun4c_bucket[entry] = BUCKET_EMPTY; + if (entry < sun4c_lowbucket_avail) + sun4c_lowbucket_avail = entry; + + free_pages(pages, THREAD_INFO_ORDER); + garbage_collect(entry); +} + +static void __init sun4c_init_buckets(void) +{ + int entry; + + if (sizeof(union thread_union) != (PAGE_SIZE << THREAD_INFO_ORDER)) { + extern void thread_info_size_is_bolixed_pete(void); + thread_info_size_is_bolixed_pete(); + } + + for (entry = 0; entry < NR_TASK_BUCKETS; entry++) + sun4c_bucket[entry] = BUCKET_EMPTY; + sun4c_lowbucket_avail = 0; +} + +static unsigned long sun4c_iobuffer_start; +static unsigned long sun4c_iobuffer_end; +static unsigned long sun4c_iobuffer_high; +static unsigned long *sun4c_iobuffer_map; +static int iobuffer_map_size; + +/* + * Alias our pages so they do not cause a trap. + * Also one page may be aliased into several I/O areas and we may + * finish these I/O separately. + */ +static char *sun4c_lockarea(char *vaddr, unsigned long size) +{ + unsigned long base, scan; + unsigned long npages; + unsigned long vpage; + unsigned long pte; + unsigned long apage; + unsigned long high; + unsigned long flags; + + npages = (((unsigned long)vaddr & ~PAGE_MASK) + + size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + + local_irq_save(flags); + base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size, + 0, npages, 0); + if (base >= iobuffer_map_size) + goto abend; + + high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start; + high = SUN4C_REAL_PGDIR_ALIGN(high); + while (high > sun4c_iobuffer_high) { + get_locked_segment(sun4c_iobuffer_high); + sun4c_iobuffer_high += SUN4C_REAL_PGDIR_SIZE; + } + + vpage = ((unsigned long) vaddr) & PAGE_MASK; + for (scan = base; scan < base+npages; scan++) { + pte = ((vpage-PAGE_OFFSET) >> PAGE_SHIFT); + pte |= pgprot_val(SUN4C_PAGE_KERNEL); + pte |= _SUN4C_PAGE_NOCACHE; + set_bit(scan, sun4c_iobuffer_map); + apage = (scan << PAGE_SHIFT) + sun4c_iobuffer_start; + + /* Flush original mapping so we see the right things later. */ + sun4c_flush_page(vpage); + + sun4c_put_pte(apage, pte); + vpage += PAGE_SIZE; + } + local_irq_restore(flags); + return (char *) ((base << PAGE_SHIFT) + sun4c_iobuffer_start + + (((unsigned long) vaddr) & ~PAGE_MASK)); + +abend: + local_irq_restore(flags); + printk("DMA vaddr=0x%p size=%08lx\n", vaddr, size); + panic("Out of iobuffer table"); + return NULL; +} + +static void sun4c_unlockarea(char *vaddr, unsigned long size) +{ + unsigned long vpage, npages; + unsigned long flags; + int scan, high; + + vpage = (unsigned long)vaddr & PAGE_MASK; + npages = (((unsigned long)vaddr & ~PAGE_MASK) + + size + (PAGE_SIZE-1)) >> PAGE_SHIFT; + + local_irq_save(flags); + while (npages != 0) { + --npages; + + /* This mapping is marked non-cachable, no flush necessary. */ + sun4c_put_pte(vpage, 0); + clear_bit((vpage - sun4c_iobuffer_start) >> PAGE_SHIFT, + sun4c_iobuffer_map); + vpage += PAGE_SIZE; + } + + /* garbage collect */ + scan = (sun4c_iobuffer_high - sun4c_iobuffer_start) >> PAGE_SHIFT; + while (scan >= 0 && !sun4c_iobuffer_map[scan >> 5]) + scan -= 32; + scan += 32; + high = sun4c_iobuffer_start + (scan << PAGE_SHIFT); + high = SUN4C_REAL_PGDIR_ALIGN(high) + SUN4C_REAL_PGDIR_SIZE; + while (high < sun4c_iobuffer_high) { + sun4c_iobuffer_high -= SUN4C_REAL_PGDIR_SIZE; + free_locked_segment(sun4c_iobuffer_high); + } + local_irq_restore(flags); +} + +/* Note the scsi code at init time passes to here buffers + * which sit on the kernel stack, those are already locked + * by implication and fool the page locking code above + * if passed to by mistake. + */ +static __u32 sun4c_get_scsi_one(struct device *dev, char *bufptr, unsigned long len) +{ + unsigned long page; + + page = ((unsigned long)bufptr) & PAGE_MASK; + if (!virt_addr_valid(page)) { + sun4c_flush_page(page); + return (__u32)bufptr; /* already locked */ + } + return (__u32)sun4c_lockarea(bufptr, len); +} + +static void sun4c_get_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +{ + while (sz != 0) { + --sz; + sg->dma_address = (__u32)sun4c_lockarea(sg_virt(sg), sg->length); + sg->dma_length = sg->length; + sg = sg_next(sg); + } +} + +static void sun4c_release_scsi_one(struct device *dev, __u32 bufptr, unsigned long len) +{ + if (bufptr < sun4c_iobuffer_start) + return; /* On kernel stack or similar, see above */ + sun4c_unlockarea((char *)bufptr, len); +} + +static void sun4c_release_scsi_sgl(struct device *dev, struct scatterlist *sg, int sz) +{ + while (sz != 0) { + --sz; + sun4c_unlockarea((char *)sg->dma_address, sg->length); + sg = sg_next(sg); + } +} + +#define TASK_ENTRY_SIZE BUCKET_SIZE /* see above */ +#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1)) + +struct vm_area_struct sun4c_kstack_vma; + +static void __init sun4c_init_lock_areas(void) +{ + unsigned long sun4c_taskstack_start; + unsigned long sun4c_taskstack_end; + int bitmap_size; + + sun4c_init_buckets(); + sun4c_taskstack_start = SUN4C_LOCK_VADDR; + sun4c_taskstack_end = (sun4c_taskstack_start + + (TASK_ENTRY_SIZE * NR_TASK_BUCKETS)); + if (sun4c_taskstack_end >= SUN4C_LOCK_END) { + prom_printf("Too many tasks, decrease NR_TASK_BUCKETS please.\n"); + prom_halt(); + } + + sun4c_iobuffer_start = sun4c_iobuffer_high = + SUN4C_REAL_PGDIR_ALIGN(sun4c_taskstack_end); + sun4c_iobuffer_end = SUN4C_LOCK_END; + bitmap_size = (sun4c_iobuffer_end - sun4c_iobuffer_start) >> PAGE_SHIFT; + bitmap_size = (bitmap_size + 7) >> 3; + bitmap_size = LONG_ALIGN(bitmap_size); + iobuffer_map_size = bitmap_size << 3; + sun4c_iobuffer_map = __alloc_bootmem(bitmap_size, SMP_CACHE_BYTES, 0UL); + memset((void *) sun4c_iobuffer_map, 0, bitmap_size); + + sun4c_kstack_vma.vm_mm = &init_mm; + sun4c_kstack_vma.vm_start = sun4c_taskstack_start; + sun4c_kstack_vma.vm_end = sun4c_taskstack_end; + sun4c_kstack_vma.vm_page_prot = PAGE_SHARED; + sun4c_kstack_vma.vm_flags = VM_READ | VM_WRITE | VM_EXEC; + insert_vm_struct(&init_mm, &sun4c_kstack_vma); +} + +/* Cache flushing on the sun4c. */ +static void sun4c_flush_cache_all(void) +{ + unsigned long begin, end; + + flush_user_windows(); + begin = (KERNBASE + SUN4C_REAL_PGDIR_SIZE); + end = (begin + SUN4C_VAC_SIZE); + + if (sun4c_vacinfo.linesize == 32) { + while (begin < end) { + __asm__ __volatile__( + "ld [%0 + 0x00], %%g0\n\t" + "ld [%0 + 0x20], %%g0\n\t" + "ld [%0 + 0x40], %%g0\n\t" + "ld [%0 + 0x60], %%g0\n\t" + "ld [%0 + 0x80], %%g0\n\t" + "ld [%0 + 0xa0], %%g0\n\t" + "ld [%0 + 0xc0], %%g0\n\t" + "ld [%0 + 0xe0], %%g0\n\t" + "ld [%0 + 0x100], %%g0\n\t" + "ld [%0 + 0x120], %%g0\n\t" + "ld [%0 + 0x140], %%g0\n\t" + "ld [%0 + 0x160], %%g0\n\t" + "ld [%0 + 0x180], %%g0\n\t" + "ld [%0 + 0x1a0], %%g0\n\t" + "ld [%0 + 0x1c0], %%g0\n\t" + "ld [%0 + 0x1e0], %%g0\n" + : : "r" (begin)); + begin += 512; + } + } else { + while (begin < end) { + __asm__ __volatile__( + "ld [%0 + 0x00], %%g0\n\t" + "ld [%0 + 0x10], %%g0\n\t" + "ld [%0 + 0x20], %%g0\n\t" + "ld [%0 + 0x30], %%g0\n\t" + "ld [%0 + 0x40], %%g0\n\t" + "ld [%0 + 0x50], %%g0\n\t" + "ld [%0 + 0x60], %%g0\n\t" + "ld [%0 + 0x70], %%g0\n\t" + "ld [%0 + 0x80], %%g0\n\t" + "ld [%0 + 0x90], %%g0\n\t" + "ld [%0 + 0xa0], %%g0\n\t" + "ld [%0 + 0xb0], %%g0\n\t" + "ld [%0 + 0xc0], %%g0\n\t" + "ld [%0 + 0xd0], %%g0\n\t" + "ld [%0 + 0xe0], %%g0\n\t" + "ld [%0 + 0xf0], %%g0\n" + : : "r" (begin)); + begin += 256; + } + } +} + +static void sun4c_flush_cache_mm(struct mm_struct *mm) +{ + int new_ctx = mm->context; + + if (new_ctx != NO_CONTEXT) { + flush_user_windows(); + + if (sun4c_context_ring[new_ctx].num_entries) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + local_irq_save(flags); + if (head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + sun4c_set_context(new_ctx); + sun4c_flush_context(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while (entry != head); + sun4c_set_context(savectx); + } + local_irq_restore(flags); + } + } +} + +static void sun4c_flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; + + if (new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; + + flush_user_windows(); + + local_irq_save(flags); + /* All user segmap chains are ordered on entry->vaddr. */ + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + /* Tracing various job mixtures showed that this conditional + * only passes ~35% of the time for most worse case situations, + * therefore we avoid all of this gross overhead ~65% of the time. + */ + if ((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + sun4c_set_context(new_ctx); + + /* At this point, always, (start >= entry->vaddr) and + * (entry->vaddr < end), once the latter condition + * ceases to hold, or we hit the end of the list, we + * exit the loop. The ordering of all user allocated + * segmaps makes this all work out so beautifully. + */ + do { + struct sun4c_mmu_entry *next = entry->next; + unsigned long realend; + + /* "realstart" is always >= entry->vaddr */ + realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE; + if (end < realend) + realend = end; + if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) { + unsigned long page = entry->vaddr; + while (page < realend) { + sun4c_flush_page(page); + page += PAGE_SIZE; + } + } else { + sun4c_flush_segment(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + } + entry = next; + } while ((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); + } + local_irq_restore(flags); + } +} + +static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; + + /* Sun4c has no separate I/D caches so cannot optimize for non + * text page flushes. + */ + if (new_ctx != NO_CONTEXT) { + int octx = sun4c_get_context(); + unsigned long flags; + + flush_user_windows(); + local_irq_save(flags); + sun4c_set_context(new_ctx); + sun4c_flush_page(page); + sun4c_set_context(octx); + local_irq_restore(flags); + } +} + +static void sun4c_flush_page_to_ram(unsigned long page) +{ + unsigned long flags; + + local_irq_save(flags); + sun4c_flush_page(page); + local_irq_restore(flags); +} + +/* Sun4c cache is unified, both instructions and data live there, so + * no need to flush the on-stack instructions for new signal handlers. + */ +static void sun4c_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr) +{ +} + +/* TLB flushing on the sun4c. These routines count on the cache + * flushing code to flush the user register windows so that we need + * not do so when we get here. + */ + +static void sun4c_flush_tlb_all(void) +{ + struct sun4c_mmu_entry *this_entry, *next_entry; + unsigned long flags; + int savectx, ctx; + + local_irq_save(flags); + this_entry = sun4c_kernel_ring.ringhd.next; + savectx = sun4c_get_context(); + flush_user_windows(); + while (sun4c_kernel_ring.num_entries) { + next_entry = this_entry->next; + sun4c_flush_segment(this_entry->vaddr); + for (ctx = 0; ctx < num_contexts; ctx++) { + sun4c_set_context(ctx); + sun4c_put_segmap(this_entry->vaddr, invalid_segment); + } + free_kernel_entry(this_entry, &sun4c_kernel_ring); + this_entry = next_entry; + } + sun4c_set_context(savectx); + local_irq_restore(flags); +} + +static void sun4c_flush_tlb_mm(struct mm_struct *mm) +{ + int new_ctx = mm->context; + + if (new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + unsigned long flags; + + local_irq_save(flags); + if (head->next != head) { + struct sun4c_mmu_entry *entry = head->next; + int savectx = sun4c_get_context(); + + sun4c_set_context(new_ctx); + sun4c_flush_context(); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while (entry != head); + sun4c_set_context(savectx); + } + local_irq_restore(flags); + } +} + +static void sun4c_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; + + if (new_ctx != NO_CONTEXT) { + struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd; + struct sun4c_mmu_entry *entry; + unsigned long flags; + + local_irq_save(flags); + /* See commentary in sun4c_flush_cache_range(). */ + for (entry = head->next; + (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start); + entry = entry->next) + ; + + if ((entry != head) && (entry->vaddr < end)) { + int octx = sun4c_get_context(); + + sun4c_set_context(new_ctx); + do { + struct sun4c_mmu_entry *next = entry->next; + + sun4c_flush_segment(entry->vaddr); + sun4c_user_unmap(entry); + free_user_entry(new_ctx, entry); + + entry = next; + } while ((entry != head) && (entry->vaddr < end)); + sun4c_set_context(octx); + } + local_irq_restore(flags); + } +} + +static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + int new_ctx = mm->context; + + if (new_ctx != NO_CONTEXT) { + int savectx = sun4c_get_context(); + unsigned long flags; + + local_irq_save(flags); + sun4c_set_context(new_ctx); + page &= PAGE_MASK; + sun4c_flush_page(page); + sun4c_put_pte(page, 0); + sun4c_set_context(savectx); + local_irq_restore(flags); + } +} + +static inline void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr) +{ + unsigned long page_entry, pg_iobits; + + pg_iobits = _SUN4C_PAGE_PRESENT | _SUN4C_READABLE | _SUN4C_WRITEABLE | + _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE; + + page_entry = ((physaddr >> PAGE_SHIFT) & SUN4C_PFN_MASK); + page_entry |= ((pg_iobits | _SUN4C_PAGE_PRIV) & ~(_SUN4C_PAGE_PRESENT)); + sun4c_put_pte(virt_addr, page_entry); +} + +static void sun4c_mapiorange(unsigned int bus, unsigned long xpa, + unsigned long xva, unsigned int len) +{ + while (len != 0) { + len -= PAGE_SIZE; + sun4c_mapioaddr(xpa, xva); + xva += PAGE_SIZE; + xpa += PAGE_SIZE; + } +} + +static void sun4c_unmapiorange(unsigned long virt_addr, unsigned int len) +{ + while (len != 0) { + len -= PAGE_SIZE; + sun4c_put_pte(virt_addr, 0); + virt_addr += PAGE_SIZE; + } +} + +static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm) +{ + struct ctx_list *ctxp; + + ctxp = ctx_free.next; + if (ctxp != &ctx_free) { + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + mm->context = ctxp->ctx_number; + ctxp->ctx_mm = mm; + return; + } + ctxp = ctx_used.next; + if (ctxp->ctx_mm == old_mm) + ctxp = ctxp->next; + remove_from_ctx_list(ctxp); + add_to_used_ctxlist(ctxp); + ctxp->ctx_mm->context = NO_CONTEXT; + ctxp->ctx_mm = mm; + mm->context = ctxp->ctx_number; + sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number], + ctxp->ctx_number); +} + +/* Switch the current MM context. */ +static void sun4c_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu) +{ + struct ctx_list *ctx; + int dirty = 0; + + if (mm->context == NO_CONTEXT) { + dirty = 1; + sun4c_alloc_context(old_mm, mm); + } else { + /* Update the LRU ring of contexts. */ + ctx = ctx_list_pool + mm->context; + remove_from_ctx_list(ctx); + add_to_used_ctxlist(ctx); + } + if (dirty || old_mm != mm) + sun4c_set_context(mm->context); +} + +static void sun4c_destroy_context(struct mm_struct *mm) +{ + struct ctx_list *ctx_old; + + if (mm->context != NO_CONTEXT) { + sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context); + ctx_old = ctx_list_pool + mm->context; + remove_from_ctx_list(ctx_old); + add_to_free_ctxlist(ctx_old); + mm->context = NO_CONTEXT; + } +} + +static void sun4c_mmu_info(struct seq_file *m) +{ + int used_user_entries, i; + + used_user_entries = 0; + for (i = 0; i < num_contexts; i++) + used_user_entries += sun4c_context_ring[i].num_entries; + + seq_printf(m, + "vacsize\t\t: %d bytes\n" + "vachwflush\t: %s\n" + "vaclinesize\t: %d bytes\n" + "mmuctxs\t\t: %d\n" + "mmupsegs\t: %d\n" + "kernelpsegs\t: %d\n" + "kfreepsegs\t: %d\n" + "usedpsegs\t: %d\n" + "ufreepsegs\t: %d\n" + "user_taken\t: %d\n" + "max_taken\t: %d\n", + sun4c_vacinfo.num_bytes, + (sun4c_vacinfo.do_hwflushes ? "yes" : "no"), + sun4c_vacinfo.linesize, + num_contexts, + (invalid_segment + 1), + sun4c_kernel_ring.num_entries, + sun4c_kfree_ring.num_entries, + used_user_entries, + sun4c_ufree_ring.num_entries, + sun4c_user_taken_entries, + max_user_taken_entries); +} + +/* Nothing below here should touch the mmu hardware nor the mmu_entry + * data structures. + */ + +/* First the functions which the mid-level code uses to directly + * manipulate the software page tables. Some defines since we are + * emulating the i386 page directory layout. + */ +#define PGD_PRESENT 0x001 +#define PGD_RW 0x002 +#define PGD_USER 0x004 +#define PGD_ACCESSED 0x020 +#define PGD_DIRTY 0x040 +#define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY) + +static void sun4c_set_pte(pte_t *ptep, pte_t pte) +{ + *ptep = pte; +} + +static void sun4c_pgd_set(pgd_t * pgdp, pmd_t * pmdp) +{ +} + +static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep) +{ + pmdp->pmdv[0] = PGD_TABLE | (unsigned long) ptep; +} + +static void sun4c_pmd_populate(pmd_t * pmdp, struct page * ptep) +{ + if (page_address(ptep) == NULL) BUG(); /* No highmem on sun4c */ + pmdp->pmdv[0] = PGD_TABLE | (unsigned long) page_address(ptep); +} + +static int sun4c_pte_present(pte_t pte) +{ + return ((pte_val(pte) & (_SUN4C_PAGE_PRESENT | _SUN4C_PAGE_PRIV)) != 0); +} +static void sun4c_pte_clear(pte_t *ptep) { *ptep = __pte(0); } + +static int sun4c_pmd_bad(pmd_t pmd) +{ + return (((pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE) || + (!virt_addr_valid(pmd_val(pmd)))); +} + +static int sun4c_pmd_present(pmd_t pmd) +{ + return ((pmd_val(pmd) & PGD_PRESENT) != 0); +} + +#if 0 /* if PMD takes one word */ +static void sun4c_pmd_clear(pmd_t *pmdp) { *pmdp = __pmd(0); } +#else /* if pmd_t is a longish aggregate */ +static void sun4c_pmd_clear(pmd_t *pmdp) { + memset((void *)pmdp, 0, sizeof(pmd_t)); +} +#endif + +static int sun4c_pgd_none(pgd_t pgd) { return 0; } +static int sun4c_pgd_bad(pgd_t pgd) { return 0; } +static int sun4c_pgd_present(pgd_t pgd) { return 1; } +static void sun4c_pgd_clear(pgd_t * pgdp) { } + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +static pte_t sun4c_pte_mkwrite(pte_t pte) +{ + pte = __pte(pte_val(pte) | _SUN4C_PAGE_WRITE); + if (pte_val(pte) & _SUN4C_PAGE_MODIFIED) + pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE); + return pte; +} + +static pte_t sun4c_pte_mkdirty(pte_t pte) +{ + pte = __pte(pte_val(pte) | _SUN4C_PAGE_MODIFIED); + if (pte_val(pte) & _SUN4C_PAGE_WRITE) + pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_WRITE); + return pte; +} + +static pte_t sun4c_pte_mkyoung(pte_t pte) +{ + pte = __pte(pte_val(pte) | _SUN4C_PAGE_ACCESSED); + if (pte_val(pte) & _SUN4C_PAGE_READ) + pte = __pte(pte_val(pte) | _SUN4C_PAGE_SILENT_READ); + return pte; +} + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +static pte_t sun4c_mk_pte(struct page *page, pgprot_t pgprot) +{ + return __pte(page_to_pfn(page) | pgprot_val(pgprot)); +} + +static pte_t sun4c_mk_pte_phys(unsigned long phys_page, pgprot_t pgprot) +{ + return __pte((phys_page >> PAGE_SHIFT) | pgprot_val(pgprot)); +} + +static pte_t sun4c_mk_pte_io(unsigned long page, pgprot_t pgprot, int space) +{ + return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot)); +} + +static unsigned long sun4c_pte_pfn(pte_t pte) +{ + return pte_val(pte) & SUN4C_PFN_MASK; +} + +static pte_t sun4c_pgoff_to_pte(unsigned long pgoff) +{ + return __pte(pgoff | _SUN4C_PAGE_FILE); +} + +static unsigned long sun4c_pte_to_pgoff(pte_t pte) +{ + return pte_val(pte) & ((1UL << PTE_FILE_MAX_BITS) - 1); +} + + +static inline unsigned long sun4c_pmd_page_v(pmd_t pmd) +{ + return (pmd_val(pmd) & PAGE_MASK); +} + +static struct page *sun4c_pmd_page(pmd_t pmd) +{ + return virt_to_page(sun4c_pmd_page_v(pmd)); +} + +static unsigned long sun4c_pgd_page(pgd_t pgd) { return 0; } + +/* to find an entry in a page-table-directory */ +static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address) +{ + return mm->pgd + (address >> SUN4C_PGDIR_SHIFT); +} + +/* Find an entry in the second-level page table.. */ +static pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address) +{ + return (pmd_t *) dir; +} + +/* Find an entry in the third-level page table.. */ +pte_t *sun4c_pte_offset_kernel(pmd_t * dir, unsigned long address) +{ + return (pte_t *) sun4c_pmd_page_v(*dir) + + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1)); +} + +static unsigned long sun4c_swp_type(swp_entry_t entry) +{ + return (entry.val & SUN4C_SWP_TYPE_MASK); +} + +static unsigned long sun4c_swp_offset(swp_entry_t entry) +{ + return (entry.val >> SUN4C_SWP_OFF_SHIFT) & SUN4C_SWP_OFF_MASK; +} + +static swp_entry_t sun4c_swp_entry(unsigned long type, unsigned long offset) +{ + return (swp_entry_t) { + (offset & SUN4C_SWP_OFF_MASK) << SUN4C_SWP_OFF_SHIFT + | (type & SUN4C_SWP_TYPE_MASK) }; +} + +static void sun4c_free_pte_slow(pte_t *pte) +{ + free_page((unsigned long)pte); +} + +static void sun4c_free_pgd_slow(pgd_t *pgd) +{ + free_page((unsigned long)pgd); +} + +static pgd_t *sun4c_get_pgd_fast(void) +{ + unsigned long *ret; + + if ((ret = pgd_quicklist) != NULL) { + pgd_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } else { + pgd_t *init; + + ret = (unsigned long *)__get_free_page(GFP_KERNEL); + memset (ret, 0, (KERNBASE / SUN4C_PGDIR_SIZE) * sizeof(pgd_t)); + init = sun4c_pgd_offset(&init_mm, 0); + memcpy (((pgd_t *)ret) + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); + } + return (pgd_t *)ret; +} + +static void sun4c_free_pgd_fast(pgd_t *pgd) +{ + *(unsigned long *)pgd = (unsigned long) pgd_quicklist; + pgd_quicklist = (unsigned long *) pgd; + pgtable_cache_size++; +} + + +static inline pte_t * +sun4c_pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) +{ + unsigned long *ret; + + if ((ret = (unsigned long *)pte_quicklist) != NULL) { + pte_quicklist = (unsigned long *)(*ret); + ret[0] = ret[1]; + pgtable_cache_size--; + } + return (pte_t *)ret; +} + +static pte_t *sun4c_pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + + if ((pte = sun4c_pte_alloc_one_fast(mm, address)) != NULL) + return pte; + + pte = (pte_t *)get_zeroed_page(GFP_KERNEL|__GFP_REPEAT); + return pte; +} + +static pgtable_t sun4c_pte_alloc_one(struct mm_struct *mm, unsigned long address) +{ + pte_t *pte; + struct page *page; + + pte = sun4c_pte_alloc_one_kernel(mm, address); + if (pte == NULL) + return NULL; + page = virt_to_page(pte); + pgtable_page_ctor(page); + return page; +} + +static inline void sun4c_free_pte_fast(pte_t *pte) +{ + *(unsigned long *)pte = (unsigned long) pte_quicklist; + pte_quicklist = (unsigned long *) pte; + pgtable_cache_size++; +} + +static void sun4c_pte_free(pgtable_t pte) +{ + pgtable_page_dtor(pte); + sun4c_free_pte_fast(page_address(pte)); +} + +/* + * allocating and freeing a pmd is trivial: the 1-entry pmd is + * inside the pgd, so has no extra memory associated with it. + */ +static pmd_t *sun4c_pmd_alloc_one(struct mm_struct *mm, unsigned long address) +{ + BUG(); + return NULL; +} + +static void sun4c_free_pmd_fast(pmd_t * pmd) { } + +static void sun4c_check_pgt_cache(int low, int high) +{ + if (pgtable_cache_size > high) { + do { + if (pgd_quicklist) + sun4c_free_pgd_slow(sun4c_get_pgd_fast()); + if (pte_quicklist) + sun4c_free_pte_slow(sun4c_pte_alloc_one_fast(NULL, 0)); + } while (pgtable_cache_size > low); + } +} + +/* An experiment, turn off by default for now... -DaveM */ +#define SUN4C_PRELOAD_PSEG + +void sun4c_update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +{ + unsigned long flags; + int pseg; + + if (vma->vm_mm->context == NO_CONTEXT) + return; + + local_irq_save(flags); + address &= PAGE_MASK; + if ((pseg = sun4c_get_segmap(address)) == invalid_segment) { + struct sun4c_mmu_entry *entry = sun4c_user_strategy(); + struct mm_struct *mm = vma->vm_mm; + unsigned long start, end; + + entry->vaddr = start = (address & SUN4C_REAL_PGDIR_MASK); + entry->ctx = mm->context; + add_ring_ordered(sun4c_context_ring + mm->context, entry); + sun4c_put_segmap(entry->vaddr, entry->pseg); + end = start + SUN4C_REAL_PGDIR_SIZE; + while (start < end) { +#ifdef SUN4C_PRELOAD_PSEG + pgd_t *pgdp = sun4c_pgd_offset(mm, start); + pte_t *ptep; + + if (!pgdp) + goto no_mapping; + ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, start); + if (!ptep || !(pte_val(*ptep) & _SUN4C_PAGE_PRESENT)) + goto no_mapping; + sun4c_put_pte(start, pte_val(*ptep)); + goto next; + + no_mapping: +#endif + sun4c_put_pte(start, 0); +#ifdef SUN4C_PRELOAD_PSEG + next: +#endif + start += PAGE_SIZE; + } +#ifndef SUN4C_PRELOAD_PSEG + sun4c_put_pte(address, pte_val(*ptep)); +#endif + local_irq_restore(flags); + return; + } else { + struct sun4c_mmu_entry *entry = &mmu_entry_pool[pseg]; + + remove_lru(entry); + add_lru(entry); + } + + sun4c_put_pte(address, pte_val(*ptep)); + local_irq_restore(flags); +} + +extern void sparc_context_init(int); +extern unsigned long bootmem_init(unsigned long *pages_avail); +extern unsigned long last_valid_pfn; + +void __init sun4c_paging_init(void) +{ + int i, cnt; + unsigned long kernel_end, vaddr; + extern struct resource sparc_iomap; + unsigned long end_pfn, pages_avail; + + kernel_end = (unsigned long) &_end; + kernel_end = SUN4C_REAL_PGDIR_ALIGN(kernel_end); + + pages_avail = 0; + last_valid_pfn = bootmem_init(&pages_avail); + end_pfn = last_valid_pfn; + + sun4c_probe_mmu(); + invalid_segment = (num_segmaps - 1); + sun4c_init_mmu_entry_pool(); + sun4c_init_rings(); + sun4c_init_map_kernelprom(kernel_end); + sun4c_init_clean_mmu(kernel_end); + sun4c_init_fill_kernel_ring(SUN4C_KERNEL_BUCKETS); + sun4c_init_lock_area(sparc_iomap.start, IOBASE_END); + sun4c_init_lock_area(DVMA_VADDR, DVMA_END); + sun4c_init_lock_areas(); + sun4c_init_fill_user_ring(); + + sun4c_set_context(0); + memset(swapper_pg_dir, 0, PAGE_SIZE); + memset(pg0, 0, PAGE_SIZE); + memset(pg1, 0, PAGE_SIZE); + memset(pg2, 0, PAGE_SIZE); + memset(pg3, 0, PAGE_SIZE); + + /* Save work later. */ + vaddr = VMALLOC_START; + swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg0); + vaddr += SUN4C_PGDIR_SIZE; + swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg1); + vaddr += SUN4C_PGDIR_SIZE; + swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg2); + vaddr += SUN4C_PGDIR_SIZE; + swapper_pg_dir[vaddr>>SUN4C_PGDIR_SHIFT] = __pgd(PGD_TABLE | (unsigned long) pg3); + sun4c_init_ss2_cache_bug(); + sparc_context_init(num_contexts); + + { + unsigned long zones_size[MAX_NR_ZONES]; + unsigned long zholes_size[MAX_NR_ZONES]; + unsigned long npages; + int znum; + + for (znum = 0; znum < MAX_NR_ZONES; znum++) + zones_size[znum] = zholes_size[znum] = 0; + + npages = max_low_pfn - pfn_base; + + zones_size[ZONE_DMA] = npages; + zholes_size[ZONE_DMA] = npages - pages_avail; + + npages = highend_pfn - max_low_pfn; + zones_size[ZONE_HIGHMEM] = npages; + zholes_size[ZONE_HIGHMEM] = npages - calc_highpages(); + + free_area_init_node(0, zones_size, pfn_base, zholes_size); + } + + cnt = 0; + for (i = 0; i < num_segmaps; i++) + if (mmu_entry_pool[i].locked) + cnt++; + + max_user_taken_entries = num_segmaps - cnt - 40 - 1; + + printk("SUN4C: %d mmu entries for the kernel\n", cnt); +} + +static pgprot_t sun4c_pgprot_noncached(pgprot_t prot) +{ + prot |= __pgprot(_SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE); + + return prot; +} + +/* Load up routines and constants for sun4c mmu */ +void __init ld_mmu_sun4c(void) +{ + extern void ___xchg32_sun4c(void); + + printk("Loading sun4c MMU routines\n"); + + /* First the constants */ + BTFIXUPSET_SIMM13(pgdir_shift, SUN4C_PGDIR_SHIFT); + BTFIXUPSET_SETHI(pgdir_size, SUN4C_PGDIR_SIZE); + BTFIXUPSET_SETHI(pgdir_mask, SUN4C_PGDIR_MASK); + + BTFIXUPSET_SIMM13(ptrs_per_pmd, SUN4C_PTRS_PER_PMD); + BTFIXUPSET_SIMM13(ptrs_per_pgd, SUN4C_PTRS_PER_PGD); + BTFIXUPSET_SIMM13(user_ptrs_per_pgd, KERNBASE / SUN4C_PGDIR_SIZE); + + BTFIXUPSET_INT(page_none, pgprot_val(SUN4C_PAGE_NONE)); + PAGE_SHARED = pgprot_val(SUN4C_PAGE_SHARED); + BTFIXUPSET_INT(page_copy, pgprot_val(SUN4C_PAGE_COPY)); + BTFIXUPSET_INT(page_readonly, pgprot_val(SUN4C_PAGE_READONLY)); + BTFIXUPSET_INT(page_kernel, pgprot_val(SUN4C_PAGE_KERNEL)); + page_kernel = pgprot_val(SUN4C_PAGE_KERNEL); + + /* Functions */ + BTFIXUPSET_CALL(pgprot_noncached, sun4c_pgprot_noncached, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM); + + if (sun4c_vacinfo.do_hwflushes) { + BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_hw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_hw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_hw, BTFIXUPCALL_NORM); + } else { + BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_sw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_sw, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_sw, BTFIXUPCALL_NORM); + } + + BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP); + + BTFIXUPSET_CALL(set_pte, sun4c_set_pte, BTFIXUPCALL_STO1O0); + + BTFIXUPSET_CALL(pte_pfn, sun4c_pte_pfn, BTFIXUPCALL_NORM); +#if 0 /* PAGE_SHIFT <= 12 */ /* Eek. Investigate. XXX */ + BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_ANDNINT(PAGE_SIZE - 1)); +#else + BTFIXUPSET_CALL(pmd_page, sun4c_pmd_page, BTFIXUPCALL_NORM); +#endif + BTFIXUPSET_CALL(pmd_set, sun4c_pmd_set, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pmd_populate, sun4c_pmd_populate, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(pte_present, sun4c_pte_present, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_clear, sun4c_pte_clear, BTFIXUPCALL_STG0O0); + + BTFIXUPSET_CALL(pmd_bad, sun4c_pmd_bad, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pmd_present, sun4c_pmd_present, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pmd_clear, sun4c_pmd_clear, BTFIXUPCALL_STG0O0); + + BTFIXUPSET_CALL(pgd_none, sun4c_pgd_none, BTFIXUPCALL_RETINT(0)); + BTFIXUPSET_CALL(pgd_bad, sun4c_pgd_bad, BTFIXUPCALL_RETINT(0)); + BTFIXUPSET_CALL(pgd_present, sun4c_pgd_present, BTFIXUPCALL_RETINT(1)); + BTFIXUPSET_CALL(pgd_clear, sun4c_pgd_clear, BTFIXUPCALL_NOP); + + BTFIXUPSET_CALL(mk_pte, sun4c_mk_pte, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mk_pte_phys, sun4c_mk_pte_phys, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mk_pte_io, sun4c_mk_pte_io, BTFIXUPCALL_NORM); + + BTFIXUPSET_INT(pte_modify_mask, _SUN4C_PAGE_CHG_MASK); + BTFIXUPSET_CALL(pmd_offset, sun4c_pmd_offset, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_offset_kernel, sun4c_pte_offset_kernel, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pte_fast, sun4c_free_pte_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_free, sun4c_pte_free, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one_kernel, sun4c_pte_alloc_one_kernel, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_alloc_one, sun4c_pte_alloc_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_pmd_fast, sun4c_free_pmd_fast, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(pmd_alloc_one, sun4c_pmd_alloc_one, BTFIXUPCALL_RETO0); + BTFIXUPSET_CALL(free_pgd_fast, sun4c_free_pgd_fast, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(get_pgd_fast, sun4c_get_pgd_fast, BTFIXUPCALL_NORM); + + BTFIXUPSET_HALF(pte_writei, _SUN4C_PAGE_WRITE); + BTFIXUPSET_HALF(pte_dirtyi, _SUN4C_PAGE_MODIFIED); + BTFIXUPSET_HALF(pte_youngi, _SUN4C_PAGE_ACCESSED); + BTFIXUPSET_HALF(pte_filei, _SUN4C_PAGE_FILE); + BTFIXUPSET_HALF(pte_wrprotecti, _SUN4C_PAGE_WRITE|_SUN4C_PAGE_SILENT_WRITE); + BTFIXUPSET_HALF(pte_mkcleani, _SUN4C_PAGE_MODIFIED|_SUN4C_PAGE_SILENT_WRITE); + BTFIXUPSET_HALF(pte_mkoldi, _SUN4C_PAGE_ACCESSED|_SUN4C_PAGE_SILENT_READ); + BTFIXUPSET_CALL(pte_mkwrite, sun4c_pte_mkwrite, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_mkdirty, sun4c_pte_mkdirty, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pte_mkyoung, sun4c_pte_mkyoung, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(update_mmu_cache, sun4c_update_mmu_cache, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(pte_to_pgoff, sun4c_pte_to_pgoff, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(pgoff_to_pte, sun4c_pgoff_to_pte, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(mmu_lockarea, sun4c_lockarea, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_unlockarea, sun4c_unlockarea, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(mmu_get_scsi_one, sun4c_get_scsi_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_get_scsi_sgl, sun4c_get_scsi_sgl, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_release_scsi_one, sun4c_release_scsi_one, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_release_scsi_sgl, sun4c_release_scsi_sgl, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(mmu_map_dma_area, sun4c_map_dma_area, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(mmu_unmap_dma_area, sun4c_unmap_dma_area, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(sparc_mapiorange, sun4c_mapiorange, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(sparc_unmapiorange, sun4c_unmapiorange, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(__swp_type, sun4c_swp_type, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__swp_offset, sun4c_swp_offset, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(__swp_entry, sun4c_swp_entry, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(alloc_thread_info_node, sun4c_alloc_thread_info_node, BTFIXUPCALL_NORM); + BTFIXUPSET_CALL(free_thread_info, sun4c_free_thread_info, BTFIXUPCALL_NORM); + + BTFIXUPSET_CALL(mmu_info, sun4c_mmu_info, BTFIXUPCALL_NORM); + + /* These should _never_ get called with two level tables. */ + BTFIXUPSET_CALL(pgd_set, sun4c_pgd_set, BTFIXUPCALL_NOP); + BTFIXUPSET_CALL(pgd_page_vaddr, sun4c_pgd_page, BTFIXUPCALL_RETO0); +} 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 @@ +/* + * segment.c: Prom routine to map segments in other contexts before + * a standalone is completely mapped. This is for sun4 and + * sun4c architectures only. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include + +extern void restore_current(void); + +/* Set physical segment 'segment' at virtual address 'vaddr' in + * context 'ctx'. + */ +void +prom_putsegment(int ctx, unsigned long vaddr, int segment) +{ + unsigned long flags; + spin_lock_irqsave(&prom_lock, flags); + (*(romvec->pv_setctxt))(ctx, (char *) vaddr, segment); + restore_current(); + spin_unlock_irqrestore(&prom_lock, flags); +} -- cgit v1.2.2