diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-09-12 01:29:55 +0000 |
commit | 545f435ebcfd94a1e7c20b46efe81b4d6ac4e698 (patch) | |
tree | e9ce4bc598d06374bda906f18365984bf22a526a /arch/sparc64 | |
parent | 4291a610eef89d0d5c69d9a10ee6560e1aa36c74 (diff) |
Merge with Linux 2.1.55. More bugfixes and goodies from my private
CVS archive.
Diffstat (limited to 'arch/sparc64')
69 files changed, 9412 insertions, 1577 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index b8cf06878..20b90a651 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.20 1997/07/11 11:05:29 jj Exp $ +# $Id: Makefile,v 1.22 1997/08/29 15:51:53 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -17,7 +17,7 @@ LD = sparc64-linux-ld NM = sparc64-linux-nm AR = sparc64-linux-ar RANLIB = sparc64-linux-ranlib -ELF2AOUT64 = elf2aout64 +ELFTOAOUT = elftoaout # # Uncomment the first CFLAGS if you are doing kgdb source level @@ -34,13 +34,21 @@ HEAD := arch/sparc64/kernel/head.o arch/sparc64/kernel/init_task.o SUBDIRS := $(SUBDIRS) arch/sparc64/kernel arch/sparc64/lib arch/sparc64/mm \ arch/sparc64/prom +ifneq ($(CONFIG_SOLARIS_EMUL),n) + SUBDIRS += arch/sparc64/solaris +endif + CORE_FILES := arch/sparc64/kernel/kernel.o arch/sparc64/mm/mm.o $(CORE_FILES) +ifeq ($(CONFIG_SOLARIS_EMUL),y) + CORE_FILES += arch/sparc64/solaris/solaris.o +endif + LIBS := $(TOPDIR)/lib/lib.a $(LIBS) $(TOPDIR)/arch/sparc64/prom/promlib.a \ $(TOPDIR)/arch/sparc64/lib/lib.a vmlinux.aout: vmlinux - $(ELF2AOUT64) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux + $(ELFTOAOUT) -o $(TOPDIR)/vmlinux.aout $(TOPDIR)/vmlinux archclean: rm -f $(TOPDIR)/vmlinux.aout diff --git a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile index ed3fc6cdb..4f2b9ead3 100644 --- a/arch/sparc64/boot/Makefile +++ b/arch/sparc64/boot/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 1997/07/18 06:26:30 ralf Exp $ +# $Id: Makefile,v 1.3 1997/08/29 11:08:34 davem Exp $ # Makefile for the Sparc64 boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index fcbac5c1a..c3c438dc6 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.9 1997/07/04 11:33:05 davem Exp $ +# $Id: config.in,v 1.17 1997/09/04 01:54:43 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -43,6 +43,7 @@ else define_bool CONFIG_SUN_CONSOLE y define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y + define_bool CONFIG_PCI y source drivers/sbus/char/Config.in fi @@ -57,10 +58,11 @@ if [ "$CONFIG_SPARC32_COMPAT" != "n" ]; then bool 'Kernel support for 32-bit (ie. SunOS) a.out binaries' CONFIG_BINFMT_AOUT32 fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA + tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + tristate 'Kernel support for JAVA binaries (obsolete)' CONFIG_BINFMT_JAVA fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC + tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL fi endmenu @@ -83,6 +85,19 @@ fi tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP +if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Ultra/PCI IDE disk/cdrom/tape/floppy support' CONFIG_BLK_DEV_IDE + if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then + dep_tristate ' Include IDE/ATA-2 DISK support' CONFIG_BLK_DEV_IDEDISK $CONFIG_BLK_DEV_IDE + dep_tristate ' Include IDE/ATAPI CDROM support' CONFIG_BLK_DEV_IDECD $CONFIG_BLK_DEV_IDE + dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE + dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE + dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE + define_bool CONFIG_IDE_CHIPSETS y + define_bool CONFIG_BLK_DEV_NS87415 y + fi +fi + endmenu if [ "$CONFIG_NET" = "y" ]; then @@ -116,6 +131,21 @@ if [ "$CONFIG_SCSI" != "n" ]; then bool 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI tristate 'PTI Qlogic,ISP Driver' CONFIG_SCSI_QLOGICPTI $CONFIG_SCSI + + if [ "$CONFIG_PCI" != "n" ]; then + dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI + if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then + bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y + dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N + if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then + int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8 + fi + bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N + bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N + int ' Delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15 + fi + fi + endmenu fi endmenu @@ -141,6 +171,9 @@ if [ "$CONFIG_NET" = "y" ]; then tristate 'Sun Happy Meal 10/100baseT support' CONFIG_HAPPYMEAL tristate 'Sun QuadEthernet support' CONFIG_SUNQE tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS + if [ "$CONFIG_PCI" = "y" ]; then + tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 + fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then # fi diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index c9c92b987..85958cd6e 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -29,6 +29,7 @@ CONFIG_SUN_KEYBOARD=y CONFIG_SUN_CONSOLE=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y +CONFIG_PCI=y # # SBUS Frame Buffer support @@ -49,6 +50,7 @@ SUN_FB_CREATOR=y # CONFIG_SUN_OPENPROMIO=m CONFIG_SUN_MOSTEK_RTC=y +# CONFIG_SAB82532 is not set # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_OPENPROMFS=m @@ -61,17 +63,26 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_AOUT32=y CONFIG_BINFMT_JAVA=m CONFIG_BINFMT_MISC=m +CONFIG_SOLARIS_EMUL=m # # Floppy, IDE, and other block devices # -# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_MD=y CONFIG_MD_LINEAR=m CONFIG_MD_STRIPED=m CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_IDE=y +CONFIG_BLK_DEV_IDEDISK=y +CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDETAPE=m +CONFIG_BLK_DEV_IDEFLOPPY=m +# CONFIG_BLK_DEV_IDESCSI is not set +CONFIG_IDE_CHIPSETS=y +CONFIG_BLK_DEV_NS87415=y # # Networking options @@ -85,12 +96,13 @@ CONFIG_INET=y # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_SYN_COOKIES is not set +# CONFIG_XTP is not set # # (it is safe to leave these untouched) # # CONFIG_INET_PCTCP is not set -# CONFIG_INET_RARP is not set +CONFIG_INET_RARP=m CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y @@ -136,6 +148,12 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_SUNESP=y CONFIG_SCSI_QLOGICPTI=m +CONFIG_SCSI_AIC7XXX=y +# CONFIG_AIC7XXX_TAGGED_QUEUEING is not set +# CONFIG_OVERRIDE_CMDS is not set +# CONFIG_AIC7XXX_PAGE_ENABLE is not set +# CONFIG_AIC7XXX_PROC_STATS is not set +CONFIG_AIC7XXX_RESET_DELAY=5 # # Network device support @@ -155,6 +173,7 @@ CONFIG_SUNLANCE=y CONFIG_HAPPYMEAL=y CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m +CONFIG_DE4X5=y # # Filesystems @@ -187,6 +206,7 @@ CONFIG_AMIGA_PARTITION=y CONFIG_UFS_FS=m CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y +# CONFIG_MAC_PARTITION is not set # # Kernel hacking diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index aecb9fd47..2b07a0e15 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.30 1997/07/24 14:48:04 davem Exp $ +# $Id: Makefile,v 1.34 1997/08/12 04:12:36 ecd Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -29,9 +29,10 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o O_OBJS := process.o setup.o cpu.o idprom.o \ - systbls.o traps.o devices.o auxio.o ioport.o \ + traps.o devices.o auxio.o ioport.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ - unaligned.o sys_sunos32.o sunos_ioctl32.o + unaligned.o sys_sunos32.o sunos_ioctl32.o \ + central.o psycho.o ebus.o OX_OBJS := sparc64_ksyms.o ifdef SMP diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 00e5f2722..91365af85 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -3,15 +3,21 @@ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> #include <linux/stddef.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/smp.h> #include <linux/init.h> +#include <linux/delay.h> +#include <linux/ioport.h> + #include <asm/oplib.h> #include <asm/io.h> #include <asm/auxio.h> #include <asm/sbus.h> +#include <asm/ebus.h> +#include <asm/fhc.h> /* Probe and map in the Auxiliary I/O register */ unsigned char *auxio_register; @@ -31,9 +37,39 @@ __initfunc(void auxio_probe(void)) } if (!sdev) { +#ifdef CONFIG_PCI + struct linux_ebus *ebus; + struct linux_ebus_device *edev = 0; + unsigned long led_auxio; + + for_all_ebusdev(edev, ebus) + if (!strcmp(edev->prom_name, "auxio")) + break; + + if (edev) { + if (check_region(edev->base_address[0], + sizeof(unsigned int))) { + prom_printf("%s: Can't get region %lx, %d\n", + __FUNCTION__, edev->base_address[0], + sizeof(unsigned int)); + prom_halt(); + } + request_region(edev->base_address[0], + sizeof(unsigned int), "LED auxio"); + + led_auxio = edev->base_address[0]; + outl(0x01, led_auxio); + return; + } +#endif + if(central_bus) { + auxio_register = NULL; + return; + } prom_printf("Cannot find auxio node, cannot continue...\n"); prom_halt(); } + prom_getproperty(sdev->prom_node, "reg", (char *) auxregs, sizeof(auxregs)); prom_apply_sbus_ranges(sdev->my_bus, auxregs, 0x1, sdev); /* Map the register both read and write */ diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index 9ab2b7aca..ef41e3f7a 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -8,6 +8,9 @@ #define elf_check_arch(x) (((x) == EM_SPARC) || ((x) == EM_SPARC32PLUS)) +#define ELF_ET_DYN_BASE 0x60000000 + + #include <asm/processor.h> #include <linux/module.h> #include <linux/config.h> diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c new file mode 100644 index 000000000..817a8ecd3 --- /dev/null +++ b/arch/sparc64/kernel/central.c @@ -0,0 +1,129 @@ +/* $Id: central.c,v 1.4 1997/08/19 14:17:49 jj Exp $ + * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/string.h> + +#include <asm/page.h> +#include <asm/fhc.h> + +struct linux_central *central_bus = NULL; + +static inline unsigned long long_align(unsigned long addr) +{ + return ((addr + (sizeof(unsigned long) - 1)) & + ~(sizeof(unsigned long) - 1)); +} + +extern void prom_central_ranges_init(int cnode, struct linux_central *central); +extern void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc); + +unsigned long central_probe(unsigned long memory_start) +{ + struct linux_prom_registers fpregs[6]; + struct linux_fhc *fhc; + char namebuf[128]; + int cnode, fnode, err; + + printk("CENTRAL: "); + cnode = prom_finddevice("/central"); + if(cnode == 0 || cnode == -1) { + printk("no central found.\n"); + return memory_start; + } + prom_printf("CENTRAL: found central PROM node.\n"); + printk("found central PROM node.\n"); + + /* Ok we got one, grab some memory for software state. */ + memory_start = long_align(memory_start); + central_bus = (struct linux_central *) (memory_start); + + prom_printf("CENTRAL: central_bus[%p] ", central_bus); + memory_start += sizeof(struct linux_central); + memory_start = long_align(memory_start); + fhc = (struct linux_fhc *)(memory_start); + memory_start += sizeof(struct linux_fhc); + memory_start = long_align(memory_start); + + prom_printf("fhc[%p] ", fhc); + + /* First init central. */ + central_bus->child = fhc; + central_bus->prom_node = cnode; + + prom_getstring(cnode, "name", namebuf, sizeof(namebuf)); + strcpy(central_bus->prom_name, namebuf); + + prom_printf("init_central_ranges "); + prom_central_ranges_init(cnode, central_bus); + + /* And then central's FHC. */ + fhc->next = NULL; + fhc->parent = central_bus; + fnode = prom_searchsiblings(prom_getchild(cnode), "fhc"); + if(fnode == 0 || fnode == -1) { + prom_printf("Critical error, central board lacks fhc.\n"); + prom_halt(); + } + fhc->prom_node = fnode; + prom_getstring(fnode, "name", namebuf, sizeof(namebuf)); + strcpy(fhc->prom_name, namebuf); + + prom_printf("cnode[%x] fnode[%x] init_fhc_ranges\n", cnode, fnode); + prom_fhc_ranges_init(fnode, fhc); + + /* Finally, map in FHC register set. (From the prtconf dumps + * I have seen on Ex000 boxes only the central ranges need to + * be applied to the fhc internal register set) -DaveM + */ + err = prom_getproperty(fnode, "reg", (char *)&fpregs[0], sizeof(fpregs)); + if(err == -1) { + prom_printf("CENTRAL: fatal error, cannot get fhc regs.\n"); + prom_halt(); + } + prom_apply_central_ranges(central_bus, &fpregs[0], 6); + prom_printf("CENTRAL: FHC_REGS[(%08x,%08x) (%08x,%08x) " + "(%08x,%08x) (%08x,%08x) (%08x,%08x) (%08x,%08x)]\n", + fpregs[0].which_io, fpregs[0].phys_addr, + fpregs[1].which_io, fpregs[1].phys_addr, + fpregs[2].which_io, fpregs[2].phys_addr, + fpregs[3].which_io, fpregs[3].phys_addr, + fpregs[4].which_io, fpregs[4].phys_addr, + fpregs[5].which_io, fpregs[5].phys_addr); + fhc->fhc_regs.pregs = (struct fhc_internal_regs *) + __va((((unsigned long)fpregs[0].which_io)<<32) | + (((unsigned long)fpregs[0].phys_addr))); + fhc->fhc_regs.ireg = (struct fhc_ign_reg *) + __va((((unsigned long)fpregs[1].which_io)<<32) | + (((unsigned long)fpregs[1].phys_addr))); + fhc->fhc_regs.ffregs = (struct fhc_fanfail_regs *) + __va((((unsigned long)fpregs[2].which_io)<<32) | + (((unsigned long)fpregs[2].phys_addr))); + fhc->fhc_regs.sregs = (struct fhc_system_regs *) + __va((((unsigned long)fpregs[3].which_io)<<32) | + (((unsigned long)fpregs[3].phys_addr))); + fhc->fhc_regs.uregs = (struct fhc_uart_regs *) + __va((((unsigned long)fpregs[4].which_io)<<32) | + (((unsigned long)fpregs[4].phys_addr))); + fhc->fhc_regs.tregs = (struct fhc_tod_regs *) + __va((((unsigned long)fpregs[5].which_io)<<32) | + (((unsigned long)fpregs[5].phys_addr))); + prom_printf("CENTRAL: FHC_REGS[%p %p %p %p %p %p]\n", + fhc->fhc_regs.pregs, fhc->fhc_regs.ireg, + fhc->fhc_regs.ffregs, fhc->fhc_regs.sregs, + fhc->fhc_regs.uregs, fhc->fhc_regs.tregs); + + prom_printf("CENTRAL: reading FHC_ID register... "); + err = fhc->fhc_regs.pregs->fhc_id; + prom_printf("VALUE[%x]\n", err); + printk("FHC Version[%x] PartID[%x] Manufacturer[%x]\n", + ((err & FHC_ID_VERS) >> 28), + ((err & FHC_ID_PARTID) >> 12), + ((err & FHC_ID_MANUF) >> 1)); + + return memory_start; +} diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 2c96a83e9..d009f39d8 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c @@ -46,8 +46,13 @@ struct cpu_iu_info linux_sparc_chips[] = { #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) -char *sparc_cpu_type[NCPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; -char *sparc_fpu_type[NCPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; +#ifdef __SMP__ +char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", "cpu-oops1", "cpu-oops2", "cpu-oops3" }; +char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", "fpu-oops1", "fpu-oops2", "fpu-oops3" }; +#else +char *sparc_cpu_type[NR_CPUS] = { "cpu-oops", }; +char *sparc_fpu_type[NR_CPUS] = { "fpu-oops", }; +#endif unsigned int fsr_storage; diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 9327058a8..24ca3ff10 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -17,13 +17,14 @@ struct prom_cpuinfo linux_cpus[NR_CPUS]; int linux_num_cpus = 0; extern void cpu_probe(void); +extern unsigned long central_probe(unsigned long); __initfunc(unsigned long device_scan(unsigned long mem_start)) { char node_str[128]; int nd, prom_node_cpu, thismid; - int cpu_nds[NCPUS]; /* One node for each cpu */ + int cpu_nds[NR_CPUS]; /* One node for each cpu */ int cpu_ctr = 0; prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); @@ -43,11 +44,14 @@ device_scan(unsigned long mem_start)) if(strcmp(node_str, "cpu") == 0) { cpu_nds[cpu_ctr] = scan; linux_cpus[cpu_ctr].prom_node = scan; - prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid)); + prom_getproperty(scan, "upa-portid", + (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; prom_printf("Found CPU %d <node=%08x,mid=%d>\n", cpu_ctr, (unsigned) scan, thismid); + printk("Found CPU %d <node=%08x,mid=%d>\n", + cpu_ctr, (unsigned) scan, thismid); cpu_ctr++; } }; @@ -62,5 +66,5 @@ device_scan(unsigned long mem_start)) linux_num_cpus = cpu_ctr; cpu_probe(); - return mem_start; + return central_probe(mem_start); } diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S index b034ef407..04efb1cec 100644 --- a/arch/sparc64/kernel/dtlb_miss.S +++ b/arch/sparc64/kernel/dtlb_miss.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_miss.S,v 1.12 1997/06/26 12:47:08 jj Exp $ +/* $Id: dtlb_miss.S,v 1.13 1997/08/14 19:27:15 davem Exp $ * dtlb_miss.S: Data TLB miss code, this is included directly * into the trap table. * @@ -62,7 +62,7 @@ /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET /*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables /*0x48*/ sethi %uhi(KERN_HIGHBITS), %g1 ! Construct PTE ^ PAGE_OFFSET - /*0x4c*/ andcc %g3, 0x80, %g0 ! Slick trick... + /*0x4c*/ andcc %g3, 0x400, %g0 ! Slick trick... /*0x50*/ sllx %g1, 32, %g1 ! Move high bits up /*0x54*/ or %g1, (KERN_LOWBITS), %g1 ! Assume not IO /*0x58*/ bne,a,pn %icc, 5f ! Is it an IO page? diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S index 2cf372ca9..55e86c887 100644 --- a/arch/sparc64/kernel/dtlb_prot.S +++ b/arch/sparc64/kernel/dtlb_prot.S @@ -1,4 +1,4 @@ -/* $Id: dtlb_prot.S,v 1.12 1997/05/18 10:04:43 davem Exp $ +/* $Id: dtlb_prot.S,v 1.14 1997/08/03 09:07:00 davem Exp $ * dtlb_prot.S: Data TLB protection code, this is included directly * into the trap table. * @@ -36,17 +36,17 @@ /* ICACHE line 3 */ /*0x40*/ add %g2, 7, %g5 ! Compute mask /*0x44*/ andn %g4, %g5, %g4 ! Mask page - /*0x48*/ or %g4, 0x10, %g4 ! 2ndary Context - /*0x4c*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page - /*0x50*/ membar #Sync ! Synchronize - /*0x54*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE - /*0x58*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x5c*/ retry ! Trap return + /*0x48*/ mov TLB_SFSR, %g5 ! read SFSR + /*0x4c*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for + /*0x50*/ and %g5, 0x10, %g5 ! context bit + /*0x54*/ or %g4, %g5, %g4 ! for prot trap +1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page + /*0x5c*/ membar #Sync ! Synchronize /* ICACHE line 4 */ - /*0x60*/ nop - /*0x64*/ nop - /*0x68*/ nop + /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE + /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load + /*0x68*/ retry ! Trap return /*0x6c*/ nop /*0x70*/ nop /*0x74*/ nop diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c new file mode 100644 index 000000000..f484cfef8 --- /dev/null +++ b/arch/sparc64/kernel/ebus.c @@ -0,0 +1,326 @@ +/* $Id: ebus.c,v 1.8 1997/09/05 22:59:39 ecd Exp $ + * ebus.c: PCI to EBus bridge device. + * + * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/string.h> + +#include <asm/system.h> +#include <asm/page.h> +#include <asm/pbm.h> +#include <asm/ebus.h> +#include <asm/oplib.h> +#include <asm/bpp.h> + +#undef DEBUG_FILL_EBUS_DEV + +struct linux_ebus *ebus_chain = 0; + +extern void prom_ebus_ranges_init(struct linux_ebus *); +extern unsigned long pci_console_init(unsigned long memory_start); + +#ifdef CONFIG_SUN_OPENPROMIO +extern int openprom_init(void); +#endif +#ifdef CONFIG_SUN_MOSTEK_RTC +extern int rtc_init(void); +#endif +#ifdef CONFIG_SPARCAUDIO +extern int sparcaudio_init(void); +#endif +#ifdef CONFIG_SUN_AUXIO +extern void auxio_probe(void); +#endif + +extern unsigned int psycho_irq_build(unsigned int full_ino); + +static inline unsigned long +ebus_alloc(unsigned long *memory_start, size_t size) +{ + unsigned long mem; + + *memory_start = (*memory_start + 7) & ~(7); + mem = *memory_start; + *memory_start += size; + return mem; +} + +__initfunc(void fill_ebus_child(int node, struct linux_ebus_child *dev)) +{ + int regs[PROMREG_MAX]; + int irqs[PROMREG_MAX]; + char lbuf[128]; + int i, len; + + dev->prom_node = node; + prom_getstring(node, "name", lbuf, sizeof(lbuf)); + strcpy(dev->prom_name, lbuf); + + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + dev->num_addrs = len / sizeof(regs[0]); + + for (i = 0; i < dev->num_addrs; i++) { + if (regs[i] >= dev->parent->num_addrs) { + prom_printf("UGH: property for %s was %d, need < %d\n", + dev->prom_name, len, dev->parent->num_addrs); + panic(__FUNCTION__); + } + dev->base_address[i] = dev->parent->base_address[regs[i]]; + } + + len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); + if ((len == -1) || (len == 0)) { + dev->num_irqs = 0; + } else { + dev->num_irqs = len / sizeof(irqs[0]); + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = psycho_irq_build(irqs[i]); + } + +#ifdef DEBUG_FILL_EBUS_DEV + printk("child '%s': address%s\n", dev->prom_name, + dev->num_addrs > 1 ? "es" : ""); + for (i = 0; i < dev->num_addrs; i++) + printk(" %016lx\n", dev->base_address[i]); + if (dev->num_irqs) { + printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + for (i = 0; i < dev->num_irqs; i++) + printk(" %08x", dev->irqs[i]); + printk("\n"); + } +#endif +} + +__initfunc(unsigned long fill_ebus_device(int node, struct linux_ebus_device *dev, + unsigned long memory_start)) +{ + struct linux_prom_registers regs[PROMREG_MAX]; + struct linux_ebus_child *child; + int irqs[PROMINTR_MAX]; + char lbuf[128]; + int i, n, len; + + dev->prom_node = node; + prom_getstring(node, "name", lbuf, sizeof(lbuf)); + strcpy(dev->prom_name, lbuf); + + len = prom_getproperty(node, "reg", (void *)regs, sizeof(regs)); + if (len % sizeof(struct linux_prom_registers)) { + prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", + dev->prom_name, len, + (int)sizeof(struct linux_prom_registers)); + panic(__FUNCTION__); + } + dev->num_addrs = len / sizeof(struct linux_prom_registers); + + for (i = 0; i < dev->num_addrs; i++) { + n = (regs[i].which_io - 0x10) >> 2; + + dev->base_address[i] = dev->parent->self->base_address[n]; + dev->base_address[i] += (unsigned long)regs[i].phys_addr; + } + + len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); + if ((len == -1) || (len == 0)) { + dev->num_irqs = 0; + } else { + dev->num_irqs = len / sizeof(irqs[0]); + for (i = 0; i < dev->num_irqs; i++) + dev->irqs[i] = psycho_irq_build(irqs[i]); + } + +#ifdef DEBUG_FILL_EBUS_DEV + printk("'%s': address%s\n", dev->prom_name, + dev->num_addrs > 1 ? "es" : ""); + for (i = 0; i < dev->num_addrs; i++) + printk(" %016lx\n", dev->base_address[i]); + if (dev->num_irqs) { + printk(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); + for (i = 0; i < dev->num_irqs; i++) + printk(" %08x", dev->irqs[i]); + printk("\n"); + } +#endif + if ((node = prom_getchild(node))) { + dev->children = (struct linux_ebus_child *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus_child)); + + child = dev->children; + child->next = 0; + child->parent = dev; + fill_ebus_child(node, child); + + while ((node = prom_getsibling(node))) { + child->next = (struct linux_ebus_child *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus_child)); + + child = child->next; + child->next = 0; + child->parent = dev; + fill_ebus_child(node, child); + } + } + + return memory_start; +} + +__initfunc(unsigned long ebus_init(unsigned long memory_start, + unsigned long memory_end)) +{ + struct linux_prom_pci_registers regs[PROMREG_MAX]; + struct linux_pbm_info *pbm; + struct linux_ebus_device *dev; + struct linux_ebus *ebus; + struct pci_dev *pdev; + struct pcidev_cookie *cookie; + char lbuf[128]; + unsigned long addr, *base; + unsigned short pci_command; + int nd, len, ebusnd; + int reg, rng, nreg; + int num_ebus = 0; + + if (!pcibios_present()) + return memory_start; + + for (pdev = pci_devices; pdev; pdev = pdev->next) { + if ((pdev->vendor == PCI_VENDOR_ID_SUN) && + (pdev->device == PCI_DEVICE_ID_SUN_EBUS)) + break; + } + if (!pdev) { + printk("ebus: No EBus's found.\n"); + return memory_start; + } + + cookie = pdev->sysdata; + ebusnd = cookie->prom_node; + + ebus_chain = ebus = (struct linux_ebus *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus)); + ebus->next = 0; + + while (ebusnd) { + printk("ebus%d:\n", num_ebus); + + prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); + ebus->prom_node = ebusnd; + strcpy(ebus->prom_name, lbuf); + + ebus->self = pdev; + ebus->parent = pbm = cookie->pbm; + + /* Enable BUS Master. */ + pcibios_read_config_word(pdev->bus->number, pdev->devfn, + PCI_COMMAND, &pci_command); + pci_command |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pdev->bus->number, pdev->devfn, + PCI_COMMAND, pci_command); + + len = prom_getproperty(ebusnd, "reg", (void *)regs, + sizeof(regs)); + if (len == 0 || len == -1) { + prom_printf("%s: can't find reg property\n", + __FUNCTION__); + prom_halt(); + } + nreg = len / sizeof(struct linux_prom_pci_registers); + + base = &ebus->self->base_address[0]; + for (reg = 0; reg < nreg; reg++) { + if (!(regs[reg].phys_hi & 0x03000000)) + continue; + + for (rng = 0; rng < pbm->num_pbm_ranges; rng++) { + struct linux_prom_pci_ranges *rp = + &pbm->pbm_ranges[rng]; + + if ((rp->child_phys_hi ^ regs[reg].phys_hi) + & 0x03000000) + continue; + + addr = (u64)regs[reg].phys_lo; + addr += (u64)regs[reg].phys_mid << 32UL; + addr += (u64)rp->parent_phys_lo; + addr += (u64)rp->parent_phys_hi << 32UL; + *base++ = (unsigned long)__va(addr); + + break; + } + } + + prom_ebus_ranges_init(ebus); + + nd = prom_getchild(ebusnd); + ebus->devices = (struct linux_ebus_device *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus_device)); + + dev = ebus->devices; + dev->next = 0; + dev->children = 0; + dev->parent = ebus; + memory_start = fill_ebus_device(nd, dev, memory_start); + + while ((nd = prom_getsibling(nd))) { + dev->next = (struct linux_ebus_device *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus_device)); + + dev = dev->next; + dev->next = 0; + dev->children = 0; + dev->parent = ebus; + memory_start = fill_ebus_device(nd, dev, memory_start); + } + + for (pdev = pdev->next; pdev; pdev = pdev->next) { + if ((pdev->vendor == PCI_VENDOR_ID_SUN) && + (pdev->device == PCI_DEVICE_ID_SUN_EBUS)) + break; + } + if (!pdev) + break; + + cookie = pdev->sysdata; + ebusnd = cookie->prom_node; + + ebus->next = (struct linux_ebus *) + ebus_alloc(&memory_start, sizeof(struct linux_ebus)); + ebus = ebus->next; + ebus->next = 0; + ++num_ebus; + } + + memory_start = pci_console_init(memory_start); + +#ifdef CONFIG_SUN_OPENPROMIO + openprom_init(); +#endif +#ifdef CONFIG_SUN_MOSTEK_RTC + rtc_init(); +#endif +#ifdef CONFIG_SPARCAUDIO + sparcaudio_init(); +#endif +#ifdef CONFIG_SUN_BPP + bpp_init(); +#endif +#ifdef CONFIG_SUN_AUXIO + if (sparc_cpu_model == sun4u) + auxio_probe(); +#endif +#ifdef __sparc_v9__ + if (sparc_cpu_model == sun4u) { + extern void sun4u_start_timers(void); + extern void clock_probe(void); + + sun4u_start_timers(); + clock_probe(); + } +#endif + return memory_start; +} diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 425c2d873..a6e2d6da7 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,9 +1,9 @@ -/* $Id: entry.S,v 1.51 1997/07/24 12:15:04 davem Exp $ +/* $Id: entry.S,v 1.65 1997/08/29 15:51:29 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ @@ -17,6 +17,7 @@ #include <asm/page.h> #include <asm/signal.h> #include <asm/pgtable.h> +#include <asm/processor.h> /* #define SYSCALL_TRACING */ @@ -50,41 +51,39 @@ sparc64_dtlb_prot_catch: bgu,a,pn %icc, winfix_trampoline rdpr %tpc, %g3 + sethi %hi(109f), %g7 ba,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 b,pt %xcc, 1f mov 1, %o2 + .align 32 sparc64_dtlb_refbit_catch: srlx %g5, 9, %g4 and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 - cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) be,a,pt %xcc, 2f mov 1, %g4 wr %g0, ASI_DMMU, %asi rdpr %pstate, %g1 wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g3 ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - cmp %g3, 1 bgu,pn %icc, winfix_trampoline rdpr %tpc, %g3 + sethi %hi(109f), %g7 b,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 + clr %o2 1: srlx %l5, PAGE_SHIFT, %o1 add %sp, STACK_BIAS + REGWIN_SZ, %o0 - call do_sparc64_fault sllx %o1, PAGE_SHIFT, %o1 b,pt %xcc, rtrap clr %l6 - nop - nop - nop - nop - + .align 32 sparc64_itlb_refbit_catch: srlx %g5, 9, %g4 and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 @@ -95,17 +94,21 @@ sparc64_itlb_refbit_catch: wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate rdpr %tpc, %g5 + sethi %hi(109f), %g7 b,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 b,pt %xcc, 1b clr %o2 + + .align 32 2: sllx %g4, 63, %g4 ! _PAGE_VALID or %g5, _PAGE_ACCESSED, %g5 or %g5, %g4, %g5 stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE - stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load retry + + .align 32 3: sllx %g4, 63, %g4 ! _PAGE_VALID or %g5, _PAGE_ACCESSED, %g5 or %g5, %g4, %g5 @@ -113,24 +116,33 @@ sparc64_itlb_refbit_catch: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load retry +#define FPDIS_OFF (((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1)) /* This is trivial with the new code... */ .align 32 .globl do_fpdis do_fpdis: - wr %g0, FPRS_FEF, %fprs - ldx [%g6 + AOFF_task_flags], %g2 - sethi %hi(0x00100000), %g4 ! XXX PF_USEDFPU - andcc %g2, %g4, %g0 - - bne,a,pt %xcc, fpload_fromkstk - sethi %hi((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2 - fzero %f0 - fzero %f2 + ldx [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group + sethi %hi(TSTATE_PEF), %g4 ! IEU0 + sethi %hi(FPDIS_OFF), %g3 ! IEU1 + wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles + andcc %g5, SPARC_FLAG_USEDFPU, %g0 ! IEU1 Group + or %g3, %lo(FPDIS_OFF), %g2 ! IEU0 + sethi %hi(empty_zero_page), %g1 ! IEU0 Group + add %g6, %g2, %g2 ! IEU1 + be,a,pn %icc, 1f ! CTI + clr %g7 ! IEU0 Group + add %g2, 0x100, %g1 ! IEU1 + ldx [%g2 + 0x108], %g7 ! Load +1: andcc %g5, SPARC_FLAG_USEDFPUL, %g0 ! IEU1 Group + bne,pn %icc, 2f ! CTI + fzero %f0 ! FPA + andcc %g5, SPARC_FLAG_USEDFPUU, %g0 ! IEU1 Group + bne,pn %icc, 1f ! CTI + fzero %f2 ! FPA faddd %f0, %f2, %f4 fmuld %f0, %f2, %f6 faddd %f0, %f2, %f8 fmuld %f0, %f2, %f10 - faddd %f0, %f2, %f12 fmuld %f0, %f2, %f14 faddd %f0, %f2, %f16 @@ -139,7 +151,6 @@ do_fpdis: fmuld %f0, %f2, %f22 faddd %f0, %f2, %f24 fmuld %f0, %f2, %f26 - faddd %f0, %f2, %f28 fmuld %f0, %f2, %f30 faddd %f0, %f2, %f32 @@ -148,54 +159,92 @@ do_fpdis: fmuld %f0, %f2, %f38 faddd %f0, %f2, %f40 fmuld %f0, %f2, %f42 - faddd %f0, %f2, %f44 fmuld %f0, %f2, %f46 - ldx [%g6 + AOFF_task_flags], %g2 faddd %f0, %f2, %f48 fmuld %f0, %f2, %f50 - or %g2, %g4, %g2 faddd %f0, %f2, %f52 fmuld %f0, %f2, %f54 - - stx %g2, [%g6 + AOFF_task_flags] faddd %f0, %f2, %f56 - sethi %hi(empty_zero_page), %g3 fmuld %f0, %f2, %f58 - - faddd %f0, %f2, %f60 - ldx [%g3], %fsr ! wheee, empty_zero_page + b,pt %xcc, fpdis_exit2 + faddd %f0, %f2, %f60 +1: mov SECONDARY_CONTEXT, %g3 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + ldxa [%g3] ASI_DMMU, %g5 + stxa %g0, [%g3] ASI_DMMU + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + flush %g2 + wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + membar #StoreLoad | #LoadLoad + ldda [%g2 + 0x080] %asi, %f32 + ldda [%g2 + 0x0c0] %asi, %f48 + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 b,pt %xcc, fpdis_exit - wr %g0, 0, %gsr - -fpload_fromkstk: - or %g2, %lo((((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1))), %g2 - add %g6, %g2, %g2 + membar #Sync +2: andcc %g5, SPARC_FLAG_USEDFPUU, %g0 + bne,pt %icc, 3f + fzero %f32 mov SECONDARY_CONTEXT, %g3 + fzero %f34 + ldxa [%g3] ASI_DMMU, %g5 + stxa %g0, [%g3] ASI_DMMU + faddd %f32, %f34, %f36 + fmuld %f32, %f34, %f38 + flush %g2 + wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + membar #StoreLoad | #LoadLoad + ldda [%g2 + 0x000] %asi, %f0 + ldda [%g2 + 0x040] %asi, %f16 + faddd %f32, %f34, %f40 + fmuld %f32, %f34, %f42 + faddd %f32, %f34, %f44 + fmuld %f32, %f34, %f46 + faddd %f32, %f34, %f48 + fmuld %f32, %f34, %f50 + faddd %f32, %f34, %f52 + fmuld %f32, %f34, %f54 + faddd %f32, %f34, %f56 + fmuld %f32, %f34, %f58 + faddd %f32, %f34, %f60 + fmuld %f32, %f34, %f62 + b,pt %xcc, fpdis_exit + membar #Sync +3: mov SECONDARY_CONTEXT, %g3 + ldxa [%g3] ASI_DMMU, %g5 stxa %g0, [%g3] ASI_DMMU flush %g2 wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( membar #StoreLoad | #LoadLoad - ldda [%g2 + 0x000] %asi, %f0 ldda [%g2 + 0x040] %asi, %f16 ldda [%g2 + 0x080] %asi, %f32 ldda [%g2 + 0x0c0] %asi, %f48 - ldx [%g2 + 0x100], %fsr - ldx [%g2 + 0x108], %g2 membar #Sync - wr %g2, 0, %gsr fpdis_exit: + stxa %g5, [%g3] ASI_DMMU + flush %g2 +fpdis_exit2: + wr %g7, 0, %gsr + ldx [%g1], %fsr rdpr %tstate, %g3 - sethi %hi(TSTATE_PEF), %g4 or %g3, %g4, %g3 ! anal... wrpr %g3, %tstate + wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits retry -#ifdef __SMP__ - /* Note check out head.h, this code isn't even used for UP, - * for SMP things will be different. In particular the data - * registers for cross calls will be: + /* The registers for cross calls will be: * * DATA 0: [low 32-bits] Address of function to call, jmp to this * [high 32-bits] MMU Context Argument 0, place in %g5 @@ -205,11 +254,17 @@ fpdis_exit: * With this method we can do most of the cross-call tlb/cache * flushing very quickly. */ + .data + .align 8 + .globl ivec_spurious_cookie +ivec_spurious_cookie: .xword 0 + + .text .align 32 - .globl do_ivec, do_ivec_return + .globl do_ivec do_ivec: - ldxa [%g0] ASI_INTR_RECEIVE, %g1 - andcc %g1, 0x20, %g0 + ldxa [%g0] ASI_INTR_RECEIVE, %g5 + andcc %g5, 0x20, %g0 be,pn %xcc, do_ivec_return mov 0x40, %g2 @@ -223,39 +278,45 @@ do_ivec: sllx %g3, 3, %g3 ldx [%g1 + %g3], %g2 brz,pn %g2, do_ivec_spurious - nop + sethi %hi(0x80000000), %g5 + + or %g2, %g5, %g2 + stx %g2, [%g1 + %g3] /* No branches, worse case we don't know about this interrupt * yet, so we would just write a zero into the softint register * which is completely harmless. */ wr %g2, 0x0, %set_softint - do_ivec_return: - /* Acknowledge the UPA */ stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync retry do_ivec_xcall: srlx %g3, 32, %g5 add %g2, 0x10, %g2 - sra %g3, 0, %g3 + srl %g3, 0, %g3 ldxa [%g2] ASI_UDB_INTR_R, %g6 add %g2, 0x10, %g2 + ldxa [%g2] ASI_UDB_INTR_R, %g7 + stxa %g0, [%g0] ASI_INTR_RECEIVE jmpl %g3, %g0 - ldxa [%g2] ASI_UDB_INTR_R, %g7 + membar #Sync do_ivec_spurious: + srl %g3, 3, %g3 + sethi %hi(ivec_spurious_cookie), %g2 + stx %g3, [%g2 + %lo(ivec_spurious_cookie)] stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync - rdpr %pstate, %g1 - wrpr %g1, PSTATE_IG | PSTATE_AG, %pstate + rdpr %pstate, %g5 + wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate + sethi %hi(109f), %g7 ba,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 call report_spurious_ivec add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 -#endif /* __SMP__ */ .globl getcc, setcc getcc: @@ -359,8 +420,9 @@ floppy_overrun: floppy_dosoftint: rdpr %pil, %g2 wrpr %g0, 15, %pil + sethi %hi(109f), %g7 b,pt %xcc, etrap_irq - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 mov 11, %o0 mov 0, %o1 @@ -373,10 +435,8 @@ floppy_dosoftint: #endif /* CONFIG_BLK_DEV_FD */ /* XXX Here is stuff we still need to write... -DaveM XXX */ - .globl indirect_syscall, netbsd_syscall, solaris_syscall -indirect_syscall: + .globl netbsd_syscall netbsd_syscall: -solaris_syscall: retl nop @@ -386,8 +446,9 @@ do_mna: cmp %g3, 1 bgu,a,pn %icc, winfix_mna rdpr %tpc, %g3 + sethi %hi(109f), %g7 ba,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap @@ -573,14 +634,8 @@ sys_fork: sys_vfork: mov SIGCHLD, %o0 clr %o1 sys_clone: mov %o7, %l5 -/*???*/ save %sp, -REGWIN_SZ, %sp - flushw -/*???*/ restore %g0, %g0, %g0 - rdpr %cwp, %o4 add %sp, STACK_BIAS + REGWIN_SZ, %o2 - movrz %o1, %fp, %o1 - stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] call do_fork mov %l5, %o7 #ifdef __SMP__ @@ -611,9 +666,9 @@ linux_sparc_syscall: cmp %g1, NR_SYSCALLS ! IEU1 Group bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI mov %i0, %o0 ! IEU0 - sll %g1, 3, %l4 ! IEU0 Group + sll %g1, 2, %l4 ! IEU0 Group mov %i1, %o1 ! IEU1 - ldx [%l7 + %l4], %l7 ! Load + lduw [%l7 + %l4], %l7 ! Load syscall_is_too_hard: mov %i2, %o2 ! IEU0 Group ldx [%curptr + AOFF_task_flags], %l5 ! Load diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 4daf30e21..e10480454 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.30 1997/06/30 10:31:37 jj Exp $ +/* $Id: etrap.S,v 1.37 1997/08/21 09:13:18 davem Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -15,118 +15,127 @@ #define FPUREG_SZ ((64 * 4) + (2 * 8)) #define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \ TRACEREG_SZ-REGWIN_SZ) +#define FPU_OFF (STACK_BIAS + REGWIN_SZ + TRACEREG_SZ) + +/* + * On entry, %g7 is return address - 0x4. + * %g4 and %g5 will be preserved %l4 and %l5 respectively. + */ .text .align 32 +etrap_priv: or %g1, %g3, %g1 ! IEU0 Group + rd %fprs, %g3 ! Single Group+4bubbles + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU0 Group + andcc %g3, FPRS_FEF, %g0 ! IEU1 + add %g2, REGWIN_SZ + TRACEREG_SZ - FPUREG_SZ, %g3 ! IEU0 Group + be,pt %icc, 1f ! CTI + andcc %g1, TSTATE_PRIV, %g0 ! IEU1 + andn %g3, (64 - 1), %g3 ! IEU0 Group + ba,pt %xcc, 1f ! CTI + sub %g3, REGWIN_SZ + TRACEREG_SZ, %g2 ! IEU0 Group + + .align 32 .globl etrap, etrap_irq, etraptl1 -etrap: rdpr %pil, %g2 -etrap_irq: rdpr %tstate, %g1 - sllx %g2, 20, %g2 - or %g1, %g2, %g1 - andcc %g1, TSTATE_PRIV, %g0 - bne,pn %xcc, etrap_maybe_fpu - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 - sethi %hi(TASK_REGOFF), %g2 - - or %g2, %lo(TASK_REGOFF), %g2 - add %g6, %g2, %g2 -etrap_maybe_fpu:rd %fprs, %g3 - brnz,pn %g3, etrap_save_fpu - st %g0, [%g2 + REGWIN_SZ + PT_V9_FPRS] -etrap_after_fpu:rdpr %tpc, %g3 - stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] - rdpr %tnpc, %g1 - - stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] - rd %y, %g3 - stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] - st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] - save %g2, -STACK_BIAS, %sp ! The ordering here is - rdpr %pstate, %g1 ! critical, see winfixup - bne,pn %xcc, 2f - rdpr %canrestore, %g3 - - rdpr %wstate, %g2 - wrpr %g0, 7, %cleanwin - wrpr %g0, 0, %canrestore - sll %g2, 3, %g2 - wrpr %g3, 0, %otherwin - wrpr %g2, 0, %wstate - wr %g0, ASI_DMMU, %asi - ldxa [%g0 + PRIMARY_CONTEXT] %asi, %g2 - - stxa %g0, [%g0 + PRIMARY_CONTEXT] %asi - stxa %g2, [%g0 + SECONDARY_CONTEXT] %asi - flush %g6 -2: wrpr %g0, 0x0, %tl - or %g1, 0, %l1 - add %g4, 0, %l4 - or %g5, 0, %l5 - add %g7, 0, %l2 - - or %g6, 0, %l6 - wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate - stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] - stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] - stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] - stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] - stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] - stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] - - stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] - stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] - stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] - stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] - stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] - stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] - sethi %uhi(PAGE_OFFSET), %g4 - stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] - - stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] - sllx %g4, 32, %g4 - stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] - wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate - jmpl %l2 + 0x4, %g0 - mov %l6, %g6 -etrap_save_fpu: and %g3, FPRS_FEF, %g3 - brz,pn %g3, 2f - - nop - be,a,pt %xcc, 3f - add %g2, (TRACEREG_SZ + REGWIN_SZ), %g2 - wr %g0, ASI_BLK_P, %asi - add %g2, ((TRACEREG_SZ+REGWIN_SZ)-FPUREG_SZ), %g2 - andn %g2, (64 - 1), %g2 -1: st %g3, [%g2 - 0x4 /*REGWIN_SZ + PT_V9_FPRS*/] - rd %gsr, %g3 - - stx %fsr, [%g2 + 0x100] - stx %g3, [%g2 + 0x108] - membar #StoreStore | #LoadStore - stda %f0, [%g2 + 0x000] %asi - stda %f16, [%g2 + 0x040] %asi - stda %f32, [%g2 + 0x080] %asi - stda %f48, [%g2 + 0x0c0] %asi - membar #Sync - - sub %g2, (TRACEREG_SZ + REGWIN_SZ), %g2 -2: b,pt %xcc, etrap_after_fpu - wr %g0, 0, %fprs -3: /* Because Ultra lacks ASI_BLK_NUCLEUS a hack has to take place. */ - mov SECONDARY_CONTEXT, %g3 - stxa %g0, [%g3] ASI_DMMU - flush %g2 - wr %g0, ASI_BLK_S, %asi - nop +etrap: rdpr %pil, %g2 ! Single Group +etrap_irq: rdpr %tstate, %g1 ! Single Group + sllx %g2, 20, %g3 ! IEU0 Group + andcc %g1, TSTATE_PRIV, %g0 ! IEU1 + bne,pn %xcc, etrap_priv ! CTI + sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group + or %g1, %g3, %g1 ! IEU1 + or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group + add %g6, %g2, %g2 ! IEU0 Group +1: rdpr %tpc, %g3 ! Single Group + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group + rdpr %tnpc, %g1 ! Single Group + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group + rd %y, %g3 ! Single Group+4bubbles + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group + st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group + save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group + rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles + bne,pn %xcc, 2f ! CTI Group + sethi %hi(TSTATE_PEF), %l2 ! IEU0 + mov PRIMARY_CONTEXT, %l4 ! IEU1 + rdpr %canrestore, %g3 ! Single Group+4bubbles + rdpr %wstate, %g2 ! Single Group+4bubbles + wrpr %g0, 7, %cleanwin ! Single Group+4bubbles + wrpr %g0, 0, %canrestore ! Single Group+4bubbles + sll %g2, 3, %g2 ! IEU0 Group + mov SECONDARY_CONTEXT, %l5 ! IEU1 + wrpr %g3, 0, %otherwin ! Single Group+4bubbles + wrpr %g2, 0, %wstate ! Single Group+4bubbles + rdpr %tstate, %l3 ! Single Group + ldxa [%l4] ASI_DMMU, %g2 ! Load Group + stxa %g0, [%l4] ASI_DMMU ! Store Group + stxa %g2, [%l5] ASI_DMMU ! Store Group + flush %g6 ! Single Group+9bubbles + andcc %l3, %l2, %g0 ! IEU1 Group + be,a,pt %icc, 6f ! CTI + st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store + rd %fprs, %l0 ! Single Group+4bubbles + andcc %l0, FPRS_FEF, %g0 ! IEU1 Group + be,pn %icc, 6f ! CTI + st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store + ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group + stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group + or %l4, %l0, %l4 ! IEU0 Group + ba,pt %xcc, 3f ! CTI + st %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store +2: rd %fprs, %l0 ! Single Group+4bubbles + andcc %l0, FPRS_FEF, %g0 ! IEU1 Group + be,pn %icc, 6f ! CTI + st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store + stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group +3: rd %gsr, %l7 ! Single Group+4bubbles + cmp %l0, FPRS_FEF ! IEU1 Group + be,pn %icc, 6f ! CTI + stx %l7, [%sp + FPU_OFF + 0x108] ! Store + wr %g0, ASI_BLK_P, %asi ! Singe Group+4bubbles + andcc %l0, FPRS_DL, %g0 ! IEU1 Group + be,pn %icc, 4f ! CTI + membar #StoreStore | #LoadStore ! Memory + stda %f0, [%sp + FPU_OFF + 0x000] %asi ! Store Group + stda %f16, [%sp + FPU_OFF + 0x040] %asi ! Store Group + andcc %l0, FPRS_DU, %g0 ! IEU1 + be,pn %icc, 5f ! CTI + nop ! IEU0 Group +4: stda %f32, [%sp + FPU_OFF + 0x080] %asi ! Store Group + stda %f48, [%sp + FPU_OFF + 0x0c0] %asi ! Store Group +5: membar #Sync ! Memory +6: wr %g0, 0x0, %fprs ! Single Group+4bubbles + wrpr %g0, 0x0, %tl ! Single Group+4bubbles + mov %g1, %l1 ! IEU0 Group + mov %g4, %l4 ! IEU1 + mov %g5, %l5 ! IEU0 Group + mov %g7, %l2 ! IEU1 + mov %g6, %l6 ! IEU0 Group + wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles + stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group + stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group + stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group + stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group + stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group + stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group + stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group + stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group + sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 + stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group + stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group + sllx %g4, 32, %g4 ! IEU0 + stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group + wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles + jmpl %l2 + 0x4, %g0 ! CTI Group + mov %l6, %g6 ! IEU0 - b,pt %xcc, 1b - mov FPRS_FEF, %g3 - nop -etraptl1: rdpr %tstate, %g1 - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 - ba,pt %xcc, etrap_maybe_fpu - andcc %g1, TSTATE_PRIV, %g0 - nop +etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles + ba,pt %xcc, etrap_priv ! CTI Group + clr %g3 ! IEU0 #undef TASK_REGOFF #undef FPUREG_SZ diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index 0ed975aff..43f950b25 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.43 1997/07/07 03:05:25 davem Exp $ +/* $Id: head.S,v 1.46 1997/08/08 08:33:30 jj Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -21,6 +21,7 @@ #include <asm/processor.h> #include <asm/lsu.h> #include <asm/head.h> +#include <asm/ttable.h> /* This section from from _start to sparc64_boot_end should fit into * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space @@ -89,6 +90,28 @@ sparc64_boot: */ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate +#ifdef __SMP__ + /* Ugly but necessary... */ + sethi %hi(KERNBASE), %g7 + sethi %hi(sparc64_cpu_startup), %g5 + or %g5, %lo(sparc64_cpu_startup), %g5 + sub %g5, %g7, %g5 + sethi %hi(sparc64_cpu_startup_end), %g6 + or %g6, %lo(sparc64_cpu_startup_end), %g6 + sub %g6, %g7, %g6 + sethi %hi(smp_trampoline), %g3 + or %g3, %lo(smp_trampoline), %g3 + sub %g3, %g7, %g3 +1: ldx [%g5], %g1 + stx %g1, [%g3] + membar #StoreStore + flush %g3 + add %g5, 8, %g5 + cmp %g5, %g6 + blu,pt %xcc, 1b + add %g3, 8, %g3 +#endif + create_mappings: /* %g5 holds the tlb data */ sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 @@ -340,7 +363,7 @@ setup_tba: mov 0x40, %g2 /* INTR data 0 register */ /* Ok, we're done setting up all the state our trap mechanims needs, - * now get back into normal globals and let the PROM know what it up. + * now get back into normal globals and let the PROM know what is up. */ wrpr %g0, %g0, %wstate wrpr %o1, PSTATE_IE, %pstate @@ -374,6 +397,7 @@ bootup_kernel_stack: ! 0x0000000000408000 #include "ttable.S" +#include "systbls.S" #include "etrap.S" #include "rtrap.S" #include "winfixup.S" diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 81eb45e42..af88ca4b6 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.14 1997/07/17 06:21:12 davem Exp $ +/* $Id: ioctl32.c,v 1.18 1997/09/06 02:25:13 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -23,6 +23,7 @@ #include <linux/vt.h> #include <linux/fs.h> #include <linux/fd.h> +#include <linux/if_ppp.h> #include <asm/types.h> #include <asm/uaccess.h> @@ -102,6 +103,7 @@ static inline int dev_ifconf(unsigned int fd, u32 arg) if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) return -EFAULT; + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq); ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); if (!ifc.ifc_buf) return -ENOMEM; @@ -145,7 +147,8 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) unsigned long old_fs; int err; - if (cmd == SIOCSIFMAP) { + switch (cmd) { + case SIOCSIFMAP: if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) || __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || @@ -154,9 +157,20 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) return -EFAULT; - } else { + break; + case SIOCGPPPSTATS: + case SIOCGPPPCSTATS: + case SIOCGPPPVER: + if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + break; + default: if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) return -EFAULT; + break; } old_fs = get_fs(); set_fs (KERNEL_DS); @@ -177,6 +191,25 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32))) return -EFAULT; break; + case SIOCGPPPSTATS: + case SIOCGPPPCSTATS: + case SIOCGPPPVER: + { + u32 data; + int len; + + __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data)); + if(cmd == SIOCGPPPVER) + len = strlen(PPP_VERSION) + 1; + else if(cmd == SIOCGPPPCSTATS) + len = sizeof(struct ppp_comp_stats); + else + len = sizeof(struct ppp_stats); + + if (copy_to_user((char *)A(data), ifr.ifr_data, len)) + return -EFAULT; + break; + } case SIOCGIFMAP: if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) || __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || @@ -481,6 +514,74 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) return ret; } +static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + unsigned long old_fs = get_fs(); + unsigned long kval; + unsigned int *uvp; + int error; + + set_fs(KERNEL_DS); + error = sys_ioctl(fd, cmd, (long)&kval); + set_fs(old_fs); + + if(error == 0) { + uvp = (unsigned int *)A(arg); + if(put_user(kval, uvp)) + error = -EFAULT; + } + return error; +} + +struct ppp_option_data32 { + __kernel_caddr_t32 ptr; + __u32 length; + int transmit; +}; +#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) + +static int ppp_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +{ + unsigned long old_fs = get_fs(); + struct ppp_option_data32 data32; + struct ppp_option_data data; + int err; + + switch (cmd) { + case PPPIOCSCOMPRESS32: + if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32))) + return -EFAULT; + data.ptr = kmalloc (data32.length, GFP_KERNEL); + if (!data.ptr) + return -ENOMEM; + if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) { + err = -EFAULT; + goto out; + } + data.length = data32.length; + data.transmit = data32.transmit; + break; + default: + printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + return -EINVAL; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&data); + set_fs (old_fs); + if (err) + goto out; + switch (cmd) { + case PPPIOCSCOMPRESS32: + default: + break; + } +out: + kfree(data.ptr); + return err; +} + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; @@ -527,6 +628,9 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCSIFDSTADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: + case SIOCGPPPSTATS: + case SIOCGPPPCSTATS: + case SIOCGPPPVER: error = dev_ifsioc(fd, cmd, arg); goto out; @@ -557,6 +661,16 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) error = fbiogscursor(fd, cmd, arg); goto out; + case HDIO_GET_KEEPSETTINGS: + case HDIO_GET_UNMASKINTR: + case HDIO_GET_DMA: + case HDIO_GET_32BIT: + case HDIO_GET_MULTCOUNT: + case HDIO_GET_NOWERR: + case HDIO_GET_NICE: + error = hdio_ioctl_trans(fd, cmd, arg); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -619,6 +733,23 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case FIBMAP: case FIGETBSZ: + /* 0x03 -- HD/IDE ioctl's used by hdparm and friends. + * Some need translations, these do not. + */ + case HDIO_GET_IDENTITY: + case HDIO_SET_DMA: + case HDIO_SET_KEEPSETTINGS: + case HDIO_SET_UNMASKINTR: + case HDIO_SET_NOWERR: + case HDIO_SET_32BIT: + case HDIO_SET_MULTCOUNT: + case HDIO_DRIVE_CMD: + case HDIO_SET_PIO_MODE: + case HDIO_SCAN_HWIF: + case HDIO_SET_NICE: + case BLKROSET: + case BLKROGET: + /* 0x02 -- Floppy ioctls */ case FDSETEMSGTRESH: case FDFLUSH: @@ -729,11 +860,40 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case SIOCSARP: case SIOCGARP: case SIOCDARP: + case OLD_SIOCSARP: + case OLD_SIOCGARP: + case OLD_SIOCDARP: + case SIOCSRARP: + case SIOCGRARP: + case SIOCDRARP: case SIOCADDDLCI: case SIOCDELDLCI: + + /* PPP stuff */ + case PPPIOCGFLAGS: + case PPPIOCSFLAGS: + case PPPIOCGASYNCMAP: + case PPPIOCSASYNCMAP: + case PPPIOCGUNIT: + case PPPIOCGRASYNCMAP: + case PPPIOCSRASYNCMAP: + case PPPIOCGMRU: + case PPPIOCSMRU: + case PPPIOCSMAXCID: + case PPPIOCGXASYNCMAP: + case PPPIOCSXASYNCMAP: + case PPPIOCXFERUNIT: + case PPPIOCGNPMODE: + case PPPIOCSNPMODE: + case PPPIOCGDEBUG: + case PPPIOCSDEBUG: + case PPPIOCGIDLE: error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; - break; + + case PPPIOCSCOMPRESS32: + error = ppp_ioctl (fd, cmd, (unsigned long)arg); + goto out; default: printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c index 7d1580b39..7ae12df11 100644 --- a/arch/sparc64/kernel/ioport.c +++ b/arch/sparc64/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.11 1997/07/22 06:14:04 davem Exp $ +/* $Id: ioport.c,v 1.13 1997/08/18 01:20:22 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -45,7 +45,7 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, u32 bus_type, int rdonly) { unsigned long vaddr, base_address; - unsigned long addr = ((unsigned long) address) + (((unsigned long) bus_type) << 32); + unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32); unsigned long offset = (addr & (~PAGE_MASK)); if (virtual) { @@ -64,7 +64,12 @@ void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, /* Tell Linux resource manager about the mapping */ request_region ((vaddr | offset), len, name); } else { - return __va(addr); + unsigned long vaddr = (unsigned long) __va(addr); + + if(!check_region(vaddr, len)) + request_region(vaddr, len, name); + + return (void *) vaddr; } base_address = vaddr; @@ -83,11 +88,11 @@ void sparc_free_io (void *virtual, int len) unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK; + release_region(vaddr, plen); + if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL) return; - release_region(vaddr, plen); - for (; plen != 0;) { plen -= PAGE_SIZE; unmapioaddr(vaddr + plen); diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index f76c27c57..6f4c9dfdf 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.19 1997/07/24 12:15:04 davem Exp $ +/* $Id: irq.c,v 1.39 1997/08/31 03:11:18 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -28,8 +28,18 @@ #include <asm/hardirq.h> #include <asm/softirq.h> +#ifdef CONFIG_PCI +#include <linux/pci.h> +#include <asm/pbm.h> +#endif + /* Internal flag, should not be visible elsewhere at all. */ -#define SA_SYSIO_MASKED 0x100 +#define SA_IMAP_MASKED 0x100 + +#ifdef __SMP__ +void distribute_irqs(void); +static int irqs_have_been_distributed = 0; +#endif /* UPA nodes send interrupt packet to UltraSparc with first data reg value * low 5 bits holding the IRQ identifier being delivered. We must translate @@ -37,10 +47,39 @@ * make things even more swift we store the complete mask here. */ -#define NUM_IVECS 2048 /* XXX may need more on sunfire/wildfire */ +#define NUM_HARD_IVECS 2048 +#define NUM_IVECS (NUM_HARD_IVECS + 64) /* For SMP IRQ distribution alg. */ unsigned long ivector_to_mask[NUM_IVECS]; +struct ino_bucket { + struct ino_bucket *next; + unsigned int ino; + unsigned int *imap; + unsigned int *iclr; +}; + +#define INO_HASHSZ (NUM_HARD_IVECS >> 2) +#define NUM_INO_STATIC 4 +static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, }; +static struct ino_bucket static_ino_buckets[NUM_INO_STATIC]; +static int static_ino_bucket_count = 0; + +static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino) +{ + struct ino_bucket *ret = ino_hash[hash]; + + for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next) + ; + + return ret; +} + +static inline struct ino_bucket *ino_lookup(unsigned int ino) +{ + return __ino_lookup((ino & (INO_HASHSZ - 1)), ino); +} + /* This is based upon code in the 32-bit Sparc kernel written mostly by * David Redman (djhr@tadpole.co.uk). */ @@ -73,15 +112,22 @@ int get_irq_list(char *buf) } len += sprintf(buf + len, "\n"); } +#if 0 +#ifdef CONFIG_PCI + len += sprintf(buf + len, "ISTAT: PCI[%016lx] OBIO[%016lx]\n", + psycho_root->psycho_regs->pci_istate, + psycho_root->psycho_regs->obio_istate); +#endif +#endif return len; } -/* INO number to Sparc PIL level. */ -unsigned char ino_to_pil[] = { - 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 0 */ - 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 1 */ - 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 2 */ - 0, 1, 2, 3, 5, 7, 8, 9, /* SBUS slot 3 */ +/* SBUS SYSIO INO number to Sparc PIL level. */ +unsigned char sysio_ino_to_pil[] = { + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 0 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 1 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 2 */ + 0, 1, 2, 7, 5, 7, 8, 9, /* SBUS slot 3 */ 3, /* Onboard SCSI */ 5, /* Onboard Ethernet */ /*XXX*/ 8, /* Onboard BPP */ @@ -112,7 +158,7 @@ unsigned char ino_to_pil[] = { */ #define offset(x) ((unsigned long)(&(((struct sysio_regs *)0)->x))) #define bogon ((unsigned long) -1) -static unsigned long irq_offsets[] = { +static unsigned long sysio_irq_offsets[] = { /* SBUS Slot 0 --> 3, level 1 --> 7 */ offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), offset(imap_slot0),offset(imap_slot0),offset(imap_slot0),offset(imap_slot0), @@ -134,29 +180,29 @@ offset(imap_pmgmt), #undef bogon -#define NUM_IRQ_ENTRIES (sizeof(irq_offsets) / sizeof(irq_offsets[0])) +#define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0])) -/* Convert an "interrupts" property IRQ level to an SBUS/SYSIO - * Interrupt Mapping register pointer, or NULL if none exists. +/* XXX Old compatability cruft, get rid of me when all drivers have been + * XXX converted to dcookie registry calls... -DaveM */ -static unsigned int *irq_to_imap(unsigned int irq) +static unsigned int *sysio_irq_to_imap(unsigned int irq) { unsigned long offset; struct sysio_regs *sregs; if((irq == 14) || - (irq >= NUM_IRQ_ENTRIES) || - ((offset = irq_offsets[irq]) == ((unsigned long)-1))) + (irq >= NUM_SYSIO_OFFSETS) || + ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1))) return NULL; sregs = SBus_chain->iommu->sysio_regs; offset += ((unsigned long) sregs); - return ((unsigned int *)offset) + 1; + return ((unsigned int *)offset); } /* Convert Interrupt Mapping register pointer to assosciated - * Interrupt Clear register pointer. + * Interrupt Clear register pointer, SYSIO specific version. */ -static unsigned int *imap_to_iclr(unsigned int *imap) +static unsigned int *sysio_imap_to_iclr(unsigned int *imap) { unsigned long diff; @@ -166,32 +212,68 @@ static unsigned int *imap_to_iclr(unsigned int *imap) #undef offset -/* For non-SBUS IRQ's we do nothing, else we must enable them in the - * appropriate SYSIO interrupt map registers. +#ifdef CONFIG_PCI +/* PCI PSYCHO INO number to Sparc PIL level. */ +unsigned char psycho_ino_to_pil[] = { + 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */ + 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */ + 0, 0, 0, 0, + 0, 0, 0, 0, + 6, 4, 3, 1, /* PCI B slot 0 Int A, B, C, D */ + 6, 4, 3, 1, /* PCI B slot 1 Int A, B, C, D */ + 6, 4, 3, 1, /* PCI B slot 2 Int A, B, C, D */ + 6, 4, 3, 1, /* PCI B slot 3 Int A, B, C, D */ + 3, /* SCSI */ + 5, /* Ethernet */ + 8, /* Parallel Port */ + 13, /* Audio Record */ + 14, /* Audio Playback */ + 15, /* PowerFail */ + 12, /* Keyboard/Mouse/Serial */ + 11, /* Floppy */ + 2, /* Spare Hardware */ + 12, /* Keyboard */ + 4, /* Mouse */ + 12, /* Serial */ + 10, /* Timer 0 */ + 11, /* Timer 1 */ + 15, /* Uncorrectable ECC */ + 15, /* Correctable ECC */ + 15, /* PCI Bus A Error */ + 15, /* PCI Bus B Error */ + 1, /* Power Management */ +}; + +/* INO number to IMAP register offset for PSYCHO external IRQ's. */ -void enable_irq(unsigned int irq) +#define psycho_offset(x) ((unsigned long)(&(((struct psycho_regs *)0)->x))) + +#define psycho_imap_offset(ino) \ + ((ino & 0x20) ? (psycho_offset(imap_scsi) + (((ino) & 0x1f) << 3)) : \ + (psycho_offset(imap_a_slot0) + (((ino) & 0x3c) << 1))) + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (psycho_offset(iclr_scsi) + (((ino) & 0x1f) << 3)) : \ + (psycho_offset(iclr_a_slot0[0]) + (((ino) & 0x1f) << 3))) + +#endif + +/* Now these are always passed a true fully specified sun4u INO. */ +void enable_irq(unsigned int ino) { + struct ino_bucket *bucket; unsigned long tid; unsigned int *imap; - /* If this is for the tick interrupt, just ignore, note - * that this is the one and only locally generated interrupt - * source, all others come from external sources (essentially - * any UPA device which is an interruptor). (actually, on - * second thought Ultra can generate local interrupts for - * async memory errors and we may setup handlers for those - * at some point as well) - * - * XXX See commentary below in request_irq() this assumption - * XXX is broken and needs to be fixed. - */ - if(irq == 14) +#ifdef CONFIG_PCI + if(PCI_IRQ_P(ino)) + ino &= (PCI_IRQ_IGN | PCI_IRQ_INO); +#endif + bucket = ino_lookup(ino); + if(!bucket) return; - /* Check for bogons. */ - imap = irq_to_imap(irq); - if(imap == NULL) - goto do_the_stb_watoosi; + imap = bucket->imap; /* We send it to our UPA MID, for SMP this will be different. */ __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG)); @@ -202,28 +284,27 @@ void enable_irq(unsigned int irq) * Register, the hardware just mirrors that value here. * However for Graphics and UPA Slave devices the full * SYSIO_IMAP_INR field can be set by the programmer here. - * (XXX we will have to handle those for FFB etc. XXX) + * + * Things like FFB can now be handled via the dcookie mechanism. */ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); - return; - -do_the_stb_watoosi: - printk("Cannot enable irq(%d), doing the \"STB Watoosi\" instead.", irq); - panic("Trying to enable bogon IRQ"); } -void disable_irq(unsigned int irq) +/* This now gets passed true ino's as well. */ +void disable_irq(unsigned int ino) { + struct ino_bucket *bucket; unsigned int *imap; - /* XXX Grrr, I know this is broken... */ - if(irq == 14) +#ifdef CONFIG_PCI + if(PCI_IRQ_P(ino)) + ino &= (PCI_IRQ_IGN | PCI_IRQ_INO); +#endif + bucket = ino_lookup(ino); + if(!bucket) return; - /* Check for bogons. */ - imap = irq_to_imap(irq); - if(imap == NULL) - goto do_the_stb_watoosi; + imap = bucket->imap; /* NOTE: We do not want to futz with the IRQ clear registers * and move the state to IDLE, the SCSI code does call @@ -231,34 +312,254 @@ void disable_irq(unsigned int irq) * SCSI adapter driver code. Thus we'd lose interrupts. */ *imap &= ~(SYSIO_IMAP_VALID); - return; +} + +static void get_irq_translations(int *cpu_irq, int *ivindex_fixup, + unsigned int **imap, unsigned int **iclr, + void *busp, unsigned long flags, + unsigned int irq) +{ + if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL) + return; + + if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) { + printk("get_irq_translations: Partial specification, this is bad.\n"); + printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n", + *cpu_irq, *imap, *iclr, busp); + panic("Bad IRQ translations..."); + } + + if(SA_BUS(flags) == SA_SBUS) { + struct linux_sbus *sbusp = busp; + struct sysio_regs *sregs = sbusp->iommu->sysio_regs; + unsigned long offset; -do_the_stb_watoosi: - printk("Cannot disable irq(%d), doing the \"STB Watoosi\" instead.", irq); - panic("Trying to enable bogon IRQ"); + *cpu_irq = sysio_ino_to_pil[irq]; + if(*cpu_irq == 0) { + printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq); + panic("Bad SYSIO IRQ translations..."); + } + offset = sysio_irq_offsets[irq]; + if(offset == ((unsigned long)-1)) { + printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", + irq, *cpu_irq); + panic("BAD SYSIO IRQ offset..."); + } + offset += ((unsigned long)sregs); + *imap = ((unsigned int *)offset); + + /* SYSIO inconsistancy. For external SLOTS, we have to select + * the right ICLR register based upon the lower SBUS irq level + * bits. + */ + if(irq >= 0x20) { + *iclr = sysio_imap_to_iclr(*imap); + } else { + unsigned long iclraddr; + int sbus_slot = (irq & 0x18)>>3; + int sbus_level = irq & 0x7; + + switch(sbus_slot) { + case 0: + *iclr = &sregs->iclr_slot0; + break; + case 1: + *iclr = &sregs->iclr_slot1; + break; + case 2: + *iclr = &sregs->iclr_slot2; + break; + case 3: + *iclr = &sregs->iclr_slot3; + break; + }; + + iclraddr = (unsigned long) *iclr; + iclraddr += ((sbus_level - 1) * 8); + *iclr = (unsigned int *) iclraddr; + +#if 0 /* DEBUGGING */ + printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ", + sbus_slot, sbus_level, *iclr); +#endif + + /* Also, make sure this is accounted for in ivindex + * computations done by the caller. + */ + *ivindex_fixup = sbus_level; + } + return; + } +#ifdef CONFIG_PCI + if(SA_BUS(flags) == SA_PCI) { + struct pci_bus *pbusp = busp; + struct linux_pbm_info *pbm = pbusp->sysdata; + struct psycho_regs *pregs = pbm->parent->psycho_regs; + unsigned long offset; + + *cpu_irq = psycho_ino_to_pil[irq & 0x3f]; + if(*cpu_irq == 0) { + printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq); + panic("Bad PSYCHO IRQ translations..."); + } + offset = psycho_imap_offset(irq); + if(offset == ((unsigned long)-1)) { + printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n", + irq, *cpu_irq); + panic("Bad PSYCHO IRQ offset..."); + } + offset += ((unsigned long)pregs); + *imap = ((unsigned int *)offset) + 1; + *iclr = (unsigned int *) + (((unsigned long)pregs) + psycho_imap_offset(irq)); + return; + } +#endif +#if 0 /* XXX More to do before we can use this. -DaveM */ + if(SA_BUS(flags) == SA_FHC) { + struct fhc_bus *fbusp = busp; + struct fhc_regs *fregs = fbusp->regs; + unsigned long offset; + + *cpu_irq = fhc_ino_to_pil[irq]; + if(*cpu_irq == 0) { + printk("get_irq_translations: Bad FHC INO[%x]\n", irq); + panic("Bad FHC IRQ translations..."); + } + offset = fhc_irq_offset[*cpu_irq]; + if(offset == ((unsigned long)-1)) { + printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n", + irq, *cpu_irq); + panic("Bad FHC IRQ offset..."); + } + offset += ((unsigned long)pregs); + *imap = (((unsigned int *)offset)+1); + *iclr = fhc_imap_to_iclr(*imap); + return; + } +#endif + printk("get_irq_translations: IRQ register for unknown bus type.\n"); + printk("get_irq_translations: BUS[%lx] IRQ[%x]\n", + SA_BUS(flags), irq); + panic("Bad IRQ bus type..."); +} + +#ifdef CONFIG_PCI +static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup, + unsigned int **imap, unsigned int **iclr, + unsigned int irq) +{ + struct linux_psycho *psycho = psycho_root; + struct psycho_regs *pregs = psycho->psycho_regs; + unsigned long addr, imoff; + + addr = (unsigned long) &pregs->imap_a_slot0; + imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT; + addr = addr + imoff; + + *imap = ((unsigned int *)addr) + 1; + + addr = (unsigned long) pregs; + addr += psycho_iclr_offset(irq & (PCI_IRQ_INO)); + *iclr = ((unsigned int *)addr) + 1; + + *cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)]; + if(*cpu_irq == 0) { + printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq); + panic("Bad PSYCHO IRQ frobnication..."); + } + + /* IVINDEX fixup only needed for PCI slot irq lines. */ + if(!(irq & 0x20)) + *ivindex_fixup = irq & 0x03; +} +#endif + +/* Once added, they are never removed. */ +static struct ino_bucket *add_ino_hash(unsigned int ivindex, + unsigned int *imap, unsigned int *iclr, + unsigned long flags) +{ + struct ino_bucket *new = NULL, **hashp; + unsigned int hash = (ivindex & (INO_HASHSZ - 1)); + + new = __ino_lookup(hash, ivindex); + if(new) + return new; + if(flags & SA_STATIC_ALLOC) { + if(static_ino_bucket_count < NUM_INO_STATIC) + new = &static_ino_buckets[static_ino_bucket_count++]; + else + printk("Request for ino bucket SA_STATIC_ALLOC failed " + "using kmalloc\n"); + } + if(new == NULL) + new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL); + if(new) { + hashp = &ino_hash[hash]; + new->imap = imap; + new->iclr = iclr; + new->ino = ivindex; + new->next = *hashp; + *hashp = new; + } + return new; } int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, const char *name, void *dev_cookie) + unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action, *tmp = NULL; + struct devid_cookie *dcookie = NULL; + struct ino_bucket *bucket = NULL; unsigned long flags; - unsigned int cpu_irq, *imap, *iclr; + unsigned int *imap, *iclr; + void *bus_id = NULL; + int ivindex, ivindex_fixup, cpu_irq = -1; - /* XXX This really is not the way to do it, the "right way" - * XXX is to have drivers set SA_SBUS or something like that - * XXX in irqflags and we base our decision here on whether - * XXX that flag bit is set or not. - */ - if(irq == 14) - cpu_irq = irq; - else - cpu_irq = ino_to_pil[irq]; - if(!handler) return -EINVAL; - imap = irq_to_imap(irq); + imap = iclr = NULL; + + ivindex_fixup = 0; +#ifdef CONFIG_PCI + if(PCI_IRQ_P(irq)) { + pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); + } else +#endif + if(irqflags & SA_DCOOKIE) { + if(!dev_id) { + printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n"); + panic("Bogus irq registry."); + } + dcookie = dev_id; + dev_id = dcookie->real_dev_id; + cpu_irq = dcookie->pil; + imap = dcookie->imap; + iclr = dcookie->iclr; + bus_id = dcookie->bus_cookie; + get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, + &iclr, bus_id, irqflags, irq); + } else { + /* XXX NOTE: This code is maintained for compatability until I can + * XXX verify that all drivers sparc64 will use are updated + * XXX to use the new IRQ registry dcookie interface. -DaveM + */ + if(irq == 14) + cpu_irq = irq; + else + cpu_irq = sysio_ino_to_pil[irq]; + imap = sysio_irq_to_imap(irq); + if(!imap) { + printk("request_irq: BAD, null imap for old style " + "irq registry IRQ[%x].\n", irq); + panic("Bad IRQ registery..."); + } + iclr = sysio_imap_to_iclr(imap); + } + ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + ivindex += ivindex_fixup; action = *(cpu_irq + irq_action); if(action) { @@ -297,52 +598,67 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) return -ENOMEM; } - if(imap) { - int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + bucket = add_ino_hash(ivindex, imap, iclr, irqflags); + if(!bucket) { + kfree(action); + restore_flags(flags); + return -ENOMEM; + } - ivector_to_mask[ivindex] = (1<<cpu_irq); - iclr = imap_to_iclr(imap); - action->mask = (unsigned long) iclr; - irqflags |= SA_SYSIO_MASKED; - } else { - action->mask = 0; + ivector_to_mask[ivindex] = (1 << cpu_irq); + + if(dcookie) { + dcookie->ret_ino = ivindex; + dcookie->ret_pil = cpu_irq; } + action->mask = (unsigned long) bucket; action->handler = handler; - action->flags = irqflags; + action->flags = irqflags | SA_IMAP_MASKED; action->name = name; action->next = NULL; - action->dev_id = dev_cookie; + action->dev_id = dev_id; if(tmp) tmp->next = action; else *(cpu_irq + irq_action) = action; - enable_irq(irq); + enable_irq(ivindex); restore_flags(flags); +#ifdef __SMP__ + if(irqs_have_been_distributed) + distribute_irqs(); +#endif return 0; } -void free_irq(unsigned int irq, void *dev_cookie) +void free_irq(unsigned int irq, void *dev_id) { struct irqaction *action; struct irqaction *tmp = NULL; unsigned long flags; unsigned int cpu_irq; + int ivindex = -1; - if(irq == 14) + if(irq == 14) { cpu_irq = irq; - else - cpu_irq = ino_to_pil[irq]; + } else { +#ifdef CONFIG_PCI + if(PCI_IRQ_P(irq)) + cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO]; + else +#endif + cpu_irq = sysio_ino_to_pil[irq]; + } action = *(cpu_irq + irq_action); if(!action->handler) { printk("Freeing free IRQ %d\n", irq); return; } - if(dev_cookie) { + if(dev_id) { for( ; action; action = action->next) { - if(action->dev_id == dev_cookie) + if(action->dev_id == dev_id) break; tmp = action; } @@ -351,7 +667,7 @@ void free_irq(unsigned int irq, void *dev_cookie) return; } } else if(action->flags & SA_SHIRQ) { - printk("Trying to free shared IRQ %d with NULL device cookie\n", irq); + printk("Trying to free shared IRQ %d with NULL device ID\n", irq); return; } @@ -367,29 +683,37 @@ void free_irq(unsigned int irq, void *dev_cookie) else *(cpu_irq + irq_action) = action->next; - if(action->flags & SA_SYSIO_MASKED) { - unsigned int *imap = irq_to_imap(irq); - if(imap != NULL) - ivector_to_mask[*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)] = 0; + if(action->flags & SA_IMAP_MASKED) { + struct ino_bucket *bucket = (struct ino_bucket *)action->mask; + unsigned int *imap = bucket->imap; + + if(imap != NULL) { + ivindex = bucket->ino; + ivector_to_mask[ivindex] = 0; + } else printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n"); } kfree(action); - if(!*(cpu_irq + irq_action)) - disable_irq(irq); + if(ivindex != -1) + disable_irq(ivindex); restore_flags(flags); } -/* Per-processor IRQ locking depth, both SMP and non-SMP code use this. */ -unsigned int local_irq_count[NR_CPUS]; +/* Only uniprocessor needs this IRQ locking depth, on SMP it lives in the per-cpu + * structure for cache reasons. + */ +#ifndef __SMP__ +unsigned int local_irq_count; +#endif #ifndef __SMP__ int __sparc64_bh_counter = 0; -#define irq_enter(cpu, irq) (local_irq_count[cpu]++) -#define irq_exit(cpu, irq) (local_irq_count[cpu]--) +#define irq_enter(cpu, irq) (local_irq_count++) +#define irq_exit(cpu, irq) (local_irq_count--) #else @@ -407,18 +731,31 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; /* Global IRQ locking depth. */ atomic_t global_irq_count = ATOMIC_INIT(0); -static inline void wait_on_irq(int cpu) +static unsigned long previous_irqholder; + +#undef INIT_STUCK +#define INIT_STUCK 100000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("wait_on_irq CPU#%d stuck at %08lx, waiting for %08lx (local=%d, global=%d)\n", cpu, where, previous_irqholder, local_count, atomic_read(&global_irq_count)); stuck = INIT_STUCK; } + +static inline void wait_on_irq(int cpu, unsigned long where) { - int local_count = local_irq_count[cpu]; + int stuck = INIT_STUCK; + int local_count = local_irq_count; while(local_count != atomic_read(&global_irq_count)) { atomic_sub(local_count, &global_irq_count); spin_unlock(&global_irq_lock); for(;;) { + STUCK; + membar("#StoreLoad | #LoadLoad"); if (atomic_read(&global_irq_count)) continue; - if (*((unsigned char *)&global_irq_lock)) + if (*((volatile unsigned char *)&global_irq_lock)) continue; + membar("#LoadLoad | #LoadStore"); if (spin_trylock(&global_irq_lock)) break; } @@ -426,25 +763,41 @@ static inline void wait_on_irq(int cpu) } } -static inline void get_irqlock(int cpu) +#undef INIT_STUCK +#define INIT_STUCK 10000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("get_irqlock stuck at %08lx, waiting for %08lx\n", where, previous_irqholder); stuck = INIT_STUCK;} + +static inline void get_irqlock(int cpu, unsigned long where) { + int stuck = INIT_STUCK; + if (!spin_trylock(&global_irq_lock)) { + membar("#StoreLoad | #LoadLoad"); if ((unsigned char) cpu == global_irq_holder) return; do { - barrier(); + do { + STUCK; + membar("#LoadLoad"); + } while(*((volatile unsigned char *)&global_irq_lock)); } while (!spin_trylock(&global_irq_lock)); } - wait_on_irq(cpu); + wait_on_irq(cpu, where); global_irq_holder = cpu; + previous_irqholder = where; } void __global_cli(void) { int cpu = smp_processor_id(); + unsigned long where; + __asm__ __volatile__("mov %%i7, %0" : "=r" (where)); __cli(); - get_irqlock(cpu); + get_irqlock(cpu, where); } void __global_sti(void) @@ -453,11 +806,6 @@ void __global_sti(void) __sti(); } -unsigned long __global_save_flags(void) -{ - return global_irq_holder == (unsigned char) smp_processor_id(); -} - void __global_restore_flags(unsigned long flags) { if (flags & 1) { @@ -472,15 +820,24 @@ void __global_restore_flags(unsigned long flags) } } +#undef INIT_STUCK +#define INIT_STUCK 200000000 + +#undef STUCK +#define STUCK \ +if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;} + void irq_enter(int cpu, int irq) { + int stuck = INIT_STUCK; + hardirq_enter(cpu); - barrier(); - while (*((unsigned char *)&global_irq_lock)) { + while (*((volatile unsigned char *)&global_irq_lock)) { if ((unsigned char) cpu == global_irq_holder) printk("irq_enter: Frosted Lucky Charms, " "they're magically delicious!\n"); - barrier(); + STUCK; + membar("#LoadLoad"); } } @@ -492,8 +849,7 @@ void irq_exit(int cpu, int irq) void synchronize_irq(void) { - int cpu = smp_processor_id(); - int local_count = local_irq_count[cpu]; + int local_count = local_irq_count; unsigned long flags; if (local_count != atomic_read(&global_irq_count)) { @@ -506,9 +862,13 @@ void synchronize_irq(void) void report_spurious_ivec(struct pt_regs *regs) { - printk("IVEC: Spurious interrupt vector received at (%016lx)\n", - regs->tpc); - return; + extern unsigned long ivec_spurious_cookie; + static int times = 0; + + printk("IVEC: Spurious interrupt vector (%016lx) received at (%016lx)\n", + ivec_spurious_cookie, regs->tpc); + if(times++ > 1) + prom_halt(); } void unexpected_irq(int irq, void *dev_cookie, struct pt_regs *regs) @@ -547,13 +907,28 @@ void handler_irq(int irq, struct pt_regs *regs) irq_enter(cpu, irq); action = *(irq + irq_action); kstat.interrupts[irq]++; - do { - if(!action || !action->handler) - unexpected_irq(irq, 0, regs); - action->handler(irq, action->dev_id, regs); - if(action->flags & SA_SYSIO_MASKED) - *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; - } while((action = action->next) != NULL); + if(!action) { + unexpected_irq(irq, 0, regs); + } else { + do { + struct ino_bucket *bucket = NULL; + unsigned int ino = 0; + + if(action->flags & SA_IMAP_MASKED) { + bucket = (struct ino_bucket *)action->mask; + + ino = bucket->ino; + if(!(ivector_to_mask[ino] & 0x80000000)) + continue; + } + + action->handler(irq, action->dev_id, regs); + if(bucket) { + ivector_to_mask[ino] &= ~(0x80000000); + *(bucket->iclr) = SYSIO_ICLR_IDLE; + } + } while((action = action->next) != NULL); + } irq_exit(cpu, irq); } @@ -567,7 +942,7 @@ void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs) irq_enter(cpu, irq); floppy_interrupt(irq, dev_cookie, regs); - if(action->flags & SA_SYSIO_MASKED) + if(action->flags & SA_IMAP_MASKED) *((unsigned int *)action->mask) = SYSIO_ICLR_IDLE; irq_exit(cpu, irq); } @@ -595,7 +970,7 @@ static void install_fast_irq(unsigned int cpu_irq, insns[0] = SPARC_BRANCH(((unsigned long) handler), ((unsigned long)&insns[0])); insns[1] = SPARC_NOP; - __asm__ __volatile__("flush %0" : : "r" (ttent)); + __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent)); } int request_fast_irq(unsigned int irq, @@ -605,6 +980,7 @@ int request_fast_irq(unsigned int irq, struct irqaction *action; unsigned long flags; unsigned int cpu_irq, *imap, *iclr; + int ivindex = -1; /* XXX This really is not the way to do it, the "right way" * XXX is to have drivers set SA_SBUS or something like that @@ -616,11 +992,11 @@ int request_fast_irq(unsigned int irq, */ if(irq == 14) return -EINVAL; - cpu_irq = ino_to_pil[irq]; + cpu_irq = sysio_ino_to_pil[irq]; if(!handler) return -EINVAL; - imap = irq_to_imap(irq); + imap = sysio_irq_to_imap(irq); action = *(cpu_irq + irq_action); if(action) { if(action->flags & SA_SHIRQ) @@ -648,12 +1024,12 @@ int request_fast_irq(unsigned int irq, install_fast_irq(cpu_irq, handler); if(imap) { - int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - + ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); ivector_to_mask[ivindex] = (1 << cpu_irq); - iclr = imap_to_iclr(imap); + iclr = sysio_imap_to_iclr(imap); action->mask = (unsigned long) iclr; - irqflags |= SA_SYSIO_MASKED; + irqflags |= SA_IMAP_MASKED; + add_ino_hash(ivindex, imap, iclr, irqflags); } else action->mask = 0; @@ -665,7 +1041,9 @@ int request_fast_irq(unsigned int irq, *(cpu_irq + irq_action) = action; - enable_irq(irq); + if(ivindex != -1) + enable_irq(ivindex); + restore_flags(flags); return 0; } @@ -675,31 +1053,27 @@ int request_fast_irq(unsigned int irq, */ unsigned long probe_irq_on(void) { - return 0; + return 0; } int probe_irq_off(unsigned long mask) { - return 0; + return 0; } struct sun5_timer *linux_timers = NULL; -/* This is called from sbus_init() to get the jiffies timer going. - * We need to call this after there exists a valid SBus_chain so - * that the IMAP/ICLR registers can be accessed. - * - * XXX That is because the whole startup sequence is broken. I will - * XXX fix it all up very soon. -DaveM - */ +/* This is gets the master level10 timer going. */ void init_timers(void (*cfunc)(int, void *, struct pt_regs *)) { struct linux_prom64_registers pregs[3]; + struct devid_cookie dcookie; + unsigned int *imap, *iclr; u32 pirqs[2]; int node, err; node = prom_finddevice("/counter-timer"); - if(node == 0) { + if(node == 0 || node == -1) { prom_printf("init_timers: Cannot find counter-timer PROM node.\n"); prom_halt(); } @@ -715,13 +1089,22 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *)) prom_halt(); } linux_timers = (struct sun5_timer *) __va(pregs[0].phys_addr); + iclr = (((unsigned int *)__va(pregs[1].phys_addr))+1); + imap = (((unsigned int *)__va(pregs[2].phys_addr))+1); /* Shut it up first. */ linux_timers->limit0 = 0; /* Register IRQ handler. */ - err = request_irq(pirqs[0] & 0x3f, /* XXX Fix this for big Enterprise XXX */ - cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); + dcookie.real_dev_id = NULL; + dcookie.imap = imap; + dcookie.iclr = iclr; + dcookie.pil = 10; + dcookie.bus_cookie = NULL; + + err = request_irq(pirqs[0], cfunc, + (SA_DCOOKIE | SA_INTERRUPT | SA_STATIC_ALLOC), + "timer", &dcookie); if(err) { prom_printf("Serious problem, cannot register timer interrupt\n"); @@ -825,6 +1208,52 @@ void enable_prom_timer(void) prom_timers->count0 = 0; } +#ifdef __SMP__ +/* Called from smp_commence, when we know how many cpus are in the system + * and can have device IRQ's directed at them. + */ +void distribute_irqs(void) +{ + unsigned long flags; + int cpu, level; + + printk("SMP: redistributing interrupts...\n"); + save_and_cli(flags); + cpu = 0; + for(level = 0; level < NR_IRQS; level++) { + struct irqaction *p = irq_action[level]; + + while(p) { + if(p->flags & SA_IMAP_MASKED) { + struct ino_bucket *bucket = (struct ino_bucket *)p->mask; + unsigned int *imap = bucket->imap; + unsigned int val; + unsigned long tid = linux_cpus[cpu].mid << 9; + + val = *imap; + *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); + + printk("SMP: Redirecting IGN[%x] INO[%x] " + "to cpu %d [%s]\n", + (val & SYSIO_IMAP_IGN) >> 6, + (val & SYSIO_IMAP_INO), cpu, + p->name); + + cpu += 1; + while(!(cpu_present_map & (1UL << cpu))) { + cpu += 1; + if(cpu >= smp_num_cpus) + cpu = 0; + } + } + p = p->next; + } + } + restore_flags(flags); + irqs_have_been_distributed = 1; +} +#endif + __initfunc(void init_IRQ(void)) { int i; diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index afd5af8d0..35d4d606d 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.31 1997/07/24 12:15:05 davem Exp $ +/* $Id: process.c,v 1.42 1997/08/19 14:17:55 jj Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -27,18 +27,21 @@ #include <linux/a.out.h> #include <linux/config.h> #include <linux/reboot.h> +#include <linux/delay.h> #include <asm/oplib.h> #include <asm/uaccess.h> #include <asm/system.h> #include <asm/page.h> #include <asm/pgtable.h> -#include <asm/delay.h> #include <asm/processor.h> #include <asm/pstate.h> #include <asm/elf.h> #include <asm/fpumacro.h> +#define PGTCACHE_HIGH_WATER 50 +#define PGTCACHE_LOW_WATER 25 + #ifndef __SMP__ /* @@ -53,6 +56,16 @@ asmlinkage int sys_idle(void) current->priority = -100; current->counter = -100; for (;;) { + if(pgtable_cache_size > PGTCACHE_LOW_WATER) { + do { + if(pgd_quicklist) + free_page((unsigned long) get_pgd_fast()); + if(pmd_quicklist) + free_page((unsigned long) get_pmd_fast()); + if(pte_quicklist) + free_page((unsigned long) get_pte_fast()); + } while(pgtable_cache_size > PGTCACHE_HIGH_WATER); + } run_task_queue(&tq_scheduler); schedule(); } @@ -68,13 +81,26 @@ asmlinkage int cpu_idle(void) { current->priority = -100; while(1) { + if(pgtable_cache_size > PGTCACHE_LOW_WATER) { + do { + if(pgd_quicklist) + free_page((unsigned long) get_pgd_fast()); + if(pmd_quicklist) + free_page((unsigned long) get_pmd_fast()); + if(pte_quicklist) + free_page((unsigned long) get_pte_fast()); + } while(pgtable_cache_size > PGTCACHE_HIGH_WATER); + } if(tq_scheduler) { lock_kernel(); run_task_queue(&tq_scheduler); unlock_kernel(); } + barrier(); current->counter = -100; - schedule(); + if(resched_needed()) + schedule(); + barrier(); } } @@ -251,8 +277,20 @@ void show_stackframe32(struct sparc_stackf32 *sf) } while ((size -= sizeof(unsigned))); } -void show_regs(struct pt_regs * regs) +#ifdef __SMP__ +static spinlock_t regdump_lock = SPIN_LOCK_UNLOCKED; +#endif + +void __show_regs(struct pt_regs * regs) { +#ifdef __SMP__ + unsigned long flags; + + spin_lock_irqsave(®dump_lock, flags); + printk("CPU[%d]: local_irq_count[%ld] global_irq_count[%d]\n", + smp_processor_id(), local_irq_count, + atomic_read(&global_irq_count)); +#endif printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", @@ -268,6 +306,21 @@ void show_regs(struct pt_regs * regs) regs->u_regs[12], regs->u_regs[13], regs->u_regs[14], regs->u_regs[15]); show_regwindow(regs); +#ifdef __SMP__ + spin_unlock_irqrestore(®dump_lock, flags); +#endif +} + +void show_regs(struct pt_regs *regs) +{ + __show_regs(regs); +#ifdef __SMP__ + { + extern void smp_report_regs(void); + + smp_report_regs(); + } +#endif } void show_regs32(struct pt_regs32 *regs) @@ -332,17 +385,22 @@ void flush_thread(void) /* No new signal delivery by default. */ current->tss.new_signal = 0; - current->flags &= ~PF_USEDFPU; + current->tss.flags &= ~(SPARC_FLAG_USEDFPU | SPARC_FLAG_USEDFPUL | + SPARC_FLAG_USEDFPUU); /* Now, this task is no longer a kernel thread. */ current->tss.current_ds = USER_DS; if(current->tss.flags & SPARC_FLAG_KTHREAD) { + extern spinlock_t scheduler_lock; + current->tss.flags &= ~SPARC_FLAG_KTHREAD; /* exec_mmap() set context to NO_CONTEXT, here is * where we grab a new one. */ + spin_lock(&scheduler_lock); get_mmu_context(current); + spin_unlock(&scheduler_lock); } current->tss.ctx = current->mm->context & 0x1fff; spitfire_set_secondary_context (current->tss.ctx); @@ -437,10 +495,14 @@ void fault_in_user_windows(struct pt_regs *regs) struct reg_window *rwin = &tp->reg_window[window]; if(copy_to_user((char *)sp, rwin, winsize)) - do_exit(SIGILL); + goto barf; } while(window--); } current->tss.w_saved = 0; + return; +barf: + lock_kernel(); + do_exit(SIGILL); } /* Copy a Sparc thread. The fork() return value conventions @@ -483,7 +545,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.kpc = ((unsigned long) ret_from_syscall) - 0x8; #endif p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); - p->tss.cwp = regs->u_regs[UREG_G0]; + p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; if(regs->tstate & TSTATE_PRIV) { p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; p->tss.flags |= SPARC_FLAG_KTHREAD; @@ -581,6 +643,7 @@ asmlinkage int sparc_execve(struct pt_regs *regs) if(!error) { fprs_write(0); regs->fprs = 0; + regs->tstate &= ~TSTATE_PEF; } out: unlock_kernel(); diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c new file mode 100644 index 000000000..8aa1c342b --- /dev/null +++ b/arch/sparc64/kernel/psycho.c @@ -0,0 +1,1417 @@ +/* $Id: psycho.c,v 1.22 1997/08/31 03:51:40 davem Exp $ + * psycho.c: Ultra/AX U2P PCI controller support. + * + * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/types.h> + +#include <asm/ebus.h> +#include <asm/sbus.h> /* for sanity check... */ + +#ifndef CONFIG_PCI + +int pcibios_present(void) +{ + return 0; +} + +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + return 0; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + return 0; +} + +#else + +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/bios32.h> +#include <linux/pci.h> + +#include <asm/io.h> +#include <asm/oplib.h> +#include <asm/pbm.h> +#include <asm/uaccess.h> + +struct linux_psycho *psycho_root = NULL; + +/* This is used to make the scan_bus in the generic PCI code be + * a nop, as we need to control the actual bus probing sequence. + * After that we leave it on of course. + */ +static int pci_probe_enable = 0; + +static inline unsigned long long_align(unsigned long addr) +{ + return ((addr + (sizeof(unsigned long) - 1)) & + ~(sizeof(unsigned long) - 1)); +} + +static unsigned long psycho_iommu_init(struct linux_psycho *psycho, + unsigned long memory_start) +{ + unsigned long tsbbase = PAGE_ALIGN(memory_start); + unsigned long control, i; + unsigned long *iopte; + + memory_start = (tsbbase + ((32 * 1024) * 8)); + iopte = (unsigned long *)tsbbase; + + for(i = 0; i < (65536 / 2); i++) { + *iopte = (IOPTE_VALID | IOPTE_64K | + IOPTE_CACHE | IOPTE_WRITE); + *iopte |= (i << 16); + iopte++; + } + + psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase); + + control = psycho->psycho_regs->iommu_control; + control &= ~(IOMMU_CTRL_TSBSZ); + control |= (IOMMU_TSBSZ_32K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); + psycho->psycho_regs->iommu_control = control; + + return memory_start; +} + +extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); + +unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end) +{ + struct linux_prom64_registers pr_regs[3]; + char namebuf[128]; + u32 portid; + int node; + + printk("PSYCHO: Probing for controllers.\n"); + + memory_start = long_align(memory_start); + node = prom_getchild(prom_root_node); + while((node = prom_searchsiblings(node, "pci")) != 0) { + struct linux_psycho *psycho = (struct linux_psycho *)memory_start; + struct linux_psycho *search; + struct linux_pbm_info *pbm = NULL; + u32 busrange[2]; + int err, is_pbm_a; + + portid = prom_getintdefault(node, "upa-portid", 0xff); + for(search = psycho_root; search; search = search->next) { + if(search->upa_portid == portid) { + psycho = search; + + /* This represents _this_ instance, so it's + * which ever one does _not_ have the prom node + * info filled in yet. + */ + is_pbm_a = (psycho->pbm_A.prom_node == 0); + goto other_pbm; + } + } + + memory_start = long_align(memory_start + sizeof(struct linux_psycho)); + + memset(psycho, 0, sizeof(*psycho)); + + psycho->next = psycho_root; + psycho_root = psycho; + + psycho->upa_portid = portid; + + /* Map in PSYCHO register set and report the presence of this PSYCHO. */ + err = prom_getproperty(node, "reg", + (char *)&pr_regs[0], sizeof(pr_regs)); + if(err == 0 || err == -1) { + prom_printf("PSYCHO: Error, cannot get U2P registers " + "from PROM.\n"); + prom_halt(); + } + + /* Third REG in property is base of entire PSYCHO register space. */ + psycho->psycho_regs = sparc_alloc_io((pr_regs[2].phys_addr & 0xffffffff), + NULL, sizeof(struct psycho_regs), + "PSYCHO Registers", + (pr_regs[2].phys_addr >> 32), 0); + if(psycho->psycho_regs == NULL) { + prom_printf("PSYCHO: Error, cannot map PSYCHO " + "main registers.\n"); + prom_halt(); + } + + printk("PSYCHO: Found controller, main regs at %p\n", + psycho->psycho_regs); +#if 0 + printk("PSYCHO: Interrupt retry [%016lx]\n", + psycho->psycho_regs->irq_retry); +#endif + psycho->psycho_regs->irq_retry = 0xff; + + /* Now map in PCI config space for entire PSYCHO. */ + psycho->pci_config_space = + sparc_alloc_io(((pr_regs[2].phys_addr & 0xffffffff)+0x01000000), + NULL, 0x01000000, + "PCI Config Space", + (pr_regs[2].phys_addr >> 32), 0); + if(psycho->pci_config_space == NULL) { + prom_printf("PSYCHO: Error, cannot map PCI config space.\n"); + prom_halt(); + } + + /* Report some more info. */ + printk("PSYCHO: PCI config space at %p\n", psycho->pci_config_space); + + memory_start = psycho_iommu_init(psycho, memory_start); + + is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); + + /* Enable arbitration for all PCI slots. */ + psycho->psycho_regs->pci_a_control |= 0x3f; + psycho->psycho_regs->pci_b_control |= 0x3f; + + other_pbm: + if(is_pbm_a) + pbm = &psycho->pbm_A; + else + pbm = &psycho->pbm_B; + + pbm->parent = psycho; + pbm->IO_assignments = NULL; + pbm->MEM_assignments = NULL; + pbm->prom_node = node; + + prom_getstring(node, "name", namebuf, sizeof(namebuf)); + strcpy(pbm->prom_name, namebuf); + + /* Now the ranges. */ + prom_pbm_ranges_init(node, pbm); + + /* Finally grab the pci bus root array for this pbm after + * having found the bus range existing under it. + */ + err = prom_getproperty(node, "bus-range", + (char *)&busrange[0], sizeof(busrange)); + if(err == 0 || err == -1) { + prom_printf("PSYCHO: Error, cannot get PCI bus range.\n"); + prom_halt(); + } + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + memset(&pbm->pci_bus, 0, sizeof(struct pci_bus)); + + node = prom_getsibling(node); + if(!node) + break; + } + + /* Last minute sanity check. */ + if(psycho_root == NULL && SBus_chain == NULL) { + prom_printf("Fatal error, neither SBUS nor PCI bus found.\n"); + prom_halt(); + } + + return memory_start; +} + +int pcibios_present(void) +{ + return psycho_root != NULL; +} + +int pcibios_find_device (unsigned short vendor, unsigned short device_id, + unsigned short index, unsigned char *bus, + unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->vendor == vendor && dev->device == device_id) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +int pcibios_find_class (unsigned int class_code, unsigned short index, + unsigned char *bus, unsigned char *devfn) +{ + unsigned int curr = 0; + struct pci_dev *dev; + + for (dev = pci_devices; dev; dev = dev->next) { + if (dev->class == class_code) { + if (curr == index) { + *devfn = dev->devfn; + *bus = dev->bus->number; + return PCIBIOS_SUCCESSFUL; + } + ++curr; + } + } + return PCIBIOS_DEVICE_NOT_FOUND; +} + +static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm, + unsigned long start, + int io) +{ + struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments); + + while(vp) { + if(vp->end > start) + break; + vp = vp->next; + } + return vp; +} + +static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, int io) +{ + struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments); + + if(!vp) { + new->next = NULL; + if(io) + pbm->IO_assignments = new; + else + pbm->MEM_assignments = new; + } else { + struct pci_vma *prev = NULL; + + while(vp && (vp->end < new->end)) { + prev = vp; + vp = vp->next; + } + new->next = vp; + if(!prev) { + if(io) + pbm->IO_assignments = new; + else + pbm->MEM_assignments = new; + } else { + prev->next = new; + } + + /* Check for programming errors. */ + if(vp && + ((vp->start >= new->start && vp->start < new->end) || + ((vp->end - 1) >= new->start && (vp->end - 1) < new->end))) { + prom_printf("pci_add_vma: Wheee, overlapping %s PCI vma's\n", + io ? "IO" : "MEM"); + prom_printf("pci_add_vma: vp[%016lx:%016lx] " + "new[%016lx:%016lx]\n", + vp->start, vp->end, + new->start, new->end); + } + } +} + +static unsigned long *pci_alloc_arena = NULL; + +static inline void pci_init_alloc_init(unsigned long *mstart) +{ + pci_alloc_arena = mstart; +} + +static inline void pci_init_alloc_fini(void) +{ + pci_alloc_arena = NULL; +} + +static void *pci_init_alloc(int size) +{ + unsigned long start = long_align(*pci_alloc_arena); + void *mp = (void *)start; + + if(!pci_alloc_arena) { + prom_printf("pci_init_alloc: pci_vma arena not init'd\n"); + prom_halt(); + } + start += size; + *pci_alloc_arena = start; + return mp; +} + +static inline struct pci_vma *pci_vma_alloc(void) +{ + return pci_init_alloc(sizeof(struct pci_vma)); +} + +static inline struct pcidev_cookie *pci_devcookie_alloc(void) +{ + return pci_init_alloc(sizeof(struct pcidev_cookie)); +} + +static void pbm_probe(struct linux_pbm_info *pbm, unsigned long *mstart) +{ + struct pci_bus *pbus = &pbm->pci_bus; + + /* PSYCHO PBM's include child PCI bridges in bus-range property, + * but we don't scan each of those ourselves, Linux generic PCI + * probing code will find child bridges and link them into this + * pbm's root PCI device hierarchy. + */ + pbus->number = pbm->pci_first_busno; + pbus->sysdata = pbm; + pbus->subordinate = pci_scan_bus(pbus, mstart); +} + +static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, + struct pci_dev *pdev, + int node) +{ + struct linux_prom_pci_registers pregs[PROMREG_MAX]; + int err; + + while(node) { + int child; + + child = prom_getchild(node); + if(child != 0 && child != -1) { + int res; + + res = pdev_to_pnode_sibtraverse(pbm, pdev, child); + if(res != 0 && res != -1) + return res; + } + err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); + if(err != 0 && err != -1) { + u32 devfn = (pregs[0].phys_hi >> 8) & 0xff; + + if(devfn == pdev->devfn) + return node; /* Match */ + } + + node = prom_getsibling(node); + } + return 0; +} + +static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp; + int node = prom_getchild(pbm->prom_node); + + node = pdev_to_pnode_sibtraverse(pbm, pdev, node); + if(node == 0) + node = -1; + pcp = pci_devcookie_alloc(); + pcp->pbm = pbm; + pcp->prom_node = node; + pdev->sysdata = pcp; +} + +static void fill_in_pbm_cookies(struct linux_pbm_info *pbm) +{ + struct pci_bus *pbtmp, *pbus = &pbm->pci_bus; + struct pci_dev *pdev; + + for(pbtmp = pbus->children; pbtmp; pbtmp = pbtmp->children) + pbtmp->sysdata = pbm; + + for( ; pbus; pbus = pbus->children) + for(pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_cookie_fillin(pbm, pdev); +} + +/* #define RECORD_ASSIGNMENTS_DEBUG */ + +/* Walk PROM device tree under PBM, looking for 'assigned-address' + * properties, and recording them in pci_vma's linked in via + * PBM->assignments. + */ +static int gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs) +{ + struct linux_prom_ebus_ranges erng[PROMREG_MAX]; + int err, iter; + + err = prom_getproperty(node, "ranges", (char *)&erng[0], sizeof(erng)); + if(err == 0 || err == -1) { + prom_printf("EBUS: fatal error, no range property.\n"); + prom_halt(); + } + err = (err / sizeof(struct linux_prom_ebus_ranges)); + for(iter = 0; iter < err; iter++) { + struct linux_prom_ebus_ranges *ep = &erng[iter]; + struct linux_prom_pci_registers *ap = &aregs[iter]; + + ap->phys_hi = ep->parent_phys_hi; + ap->phys_mid = ep->parent_phys_mid; + ap->phys_lo = ep->parent_phys_lo; + } + return err; +} + +static void assignment_process(struct linux_pbm_info *pbm, int node) +{ + struct linux_prom_pci_registers aregs[PROMREG_MAX]; + char pname[256]; + int err, iter, numa; + + err = prom_getproperty(node, "name", (char *)&pname[0], sizeof(pname)); + if(strncmp(pname, "ebus", 4) == 0) { + numa = gimme_ebus_assignments(node, &aregs[0]); + } else { + err = prom_getproperty(node, "assigned-addresses", + (char *)&aregs[0], sizeof(aregs)); + + /* No assignments, nothing to do. */ + if(err == 0 || err == -1) + return; + + numa = (err / sizeof(struct linux_prom_pci_ranges)); + } + + for(iter = 0; iter < numa; iter++) { + struct linux_prom_pci_registers *ap = &aregs[iter]; + struct pci_vma *vp; + int space, breg, io; + + space = (ap->phys_hi >> 24) & 3; + if(space != 1 && space != 2) + continue; + io = (space == 1); + + breg = (ap->phys_hi & 0xff); + if(breg == PCI_ROM_ADDRESS) + continue; + + vp = pci_vma_alloc(); + + /* XXX Means we don't support > 32-bit range of + * XXX PCI MEM space, PSYCHO/PBM does not support it + * XXX either due to it's layout so... + */ + vp->start = ap->phys_lo; + vp->end = vp->start + ap->size_lo; + vp->base_reg = breg; + + /* Sanity */ + if(io && (vp->end & ~(0xffff))) { + prom_printf("assignment_process: Out of range PCI I/O " + "[%08lx:%08lx]\n", vp->start, vp->end); + prom_halt(); + } + + pci_add_vma(pbm, vp, io); + } +} + +static void assignment_walk_siblings(struct linux_pbm_info *pbm, int node) +{ + while(node) { + int child = prom_getchild(node); + if(child) + assignment_walk_siblings(pbm, child); + + assignment_process(pbm, node); + + node = prom_getsibling(node); + } +} + +static void record_assignments(struct linux_pbm_info *pbm) +{ + assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node)); +} + +/* #define FIXUP_REGS_DEBUG */ + +static void fixup_regs(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + struct linux_prom_pci_registers *pregs, + int nregs, + struct linux_prom_pci_registers *assigned, + int numaa) +{ + int preg, rng; + int IO_seen = 0; + int MEM_seen = 0; + + for(preg = 0; preg < nregs; preg++) { + struct linux_prom_pci_registers *ap = NULL; + int bustype = (pregs[preg].phys_hi >> 24) & 0x3; + int bsreg, brindex; + u64 pci_addr; + + if(bustype == 0) { + /* Config space cookie, nothing to do. */ + if(preg != 0) + prom_printf("fixup_doit: strange, config space not 0\n"); + continue; + } else if(bustype == 3) { + /* XXX add support for this... */ + prom_printf("fixup_doit: Warning, ignoring 64-bit PCI " + "memory space, tell DaveM.\n"); + continue; + } + bsreg = (pregs[preg].phys_hi & 0xff); + + /* We can safely ignore these. */ + if(bsreg == PCI_ROM_ADDRESS) + continue; + + /* Sanity */ + if((bsreg < PCI_BASE_ADDRESS_0) || + (bsreg > (PCI_BASE_ADDRESS_5 + 4)) || + (bsreg & 3)) { + prom_printf("fixup_doit: Warning, ignoring bogus basereg [%x]\n", + bsreg); + continue; + } + + brindex = (bsreg - PCI_BASE_ADDRESS_0) >> 2; + if(numaa) { + int r; + + for(r = 0; r < numaa; r++) { + int abreg; + + abreg = (assigned[r].phys_hi & 0xff); + if(abreg == bsreg) { + ap = &assigned[r]; + break; + } + } + } + + /* Now construct UPA physical address. */ + pci_addr = (((u64)pregs[preg].phys_mid) << 32UL); + pci_addr |= (((u64)pregs[preg].phys_lo)); + + if(ap) { + pci_addr += ((u64)ap->phys_lo); + pci_addr += (((u64)ap->phys_mid) << 32UL); + } + + /* Final step, apply PBM range. */ + for(rng = 0; rng < pbm->num_pbm_ranges; rng++) { + struct linux_prom_pci_ranges *rp = &pbm->pbm_ranges[rng]; + int space = (rp->child_phys_hi >> 24) & 3; + + if(space == bustype) { + pci_addr += ((u64)rp->parent_phys_lo); + pci_addr += (((u64)rp->parent_phys_hi) << 32UL); + break; + } + } + if(rng == pbm->num_pbm_ranges) { + /* AIEEE */ + prom_printf("fixup_doit: YIEEE, cannot find PBM ranges\n"); + } + pdev->base_address[brindex] = (unsigned long)__va(pci_addr); + + /* Preserve I/O space bit. */ + if(bustype == 0x1) { + pdev->base_address[brindex] |= 1; + IO_seen = 1; + } else { + MEM_seen = 1; + } + } + + /* Now handle assignments PROM did not take care of. */ + if(nregs) { + int breg; + + for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) { + unsigned int rtmp, ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2); + unsigned int base = (unsigned int)pdev->base_address[ridx]; + struct pci_vma *vp; + u64 pci_addr; + int io; + + if(pdev->base_address[ridx] > PAGE_OFFSET) + continue; + + io = (base & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO; + base &= ~((io ? + PCI_BASE_ADDRESS_IO_MASK : + PCI_BASE_ADDRESS_MEM_MASK)); + vp = pci_find_vma(pbm, base, io); + if(!vp || vp->start > base) { + unsigned int size, new_base; + + pcibios_read_config_dword(pdev->bus->number, + pdev->devfn, + breg, &rtmp); + pcibios_write_config_dword(pdev->bus->number, + pdev->devfn, + breg, 0xffffffff); + pcibios_read_config_dword(pdev->bus->number, + pdev->devfn, + breg, &size); + if(io) + size &= ~1; + size = (~(size) + 1); + if(!size) + continue; + + new_base = 0; + for(vp=pci_find_vma(pbm,new_base,io); ; vp=vp->next) { + if(!vp || new_base + size <= vp->start) + break; + new_base = (vp->end + (size - 1)) & ~(size-1); + } + if(vp && (new_base + size > vp->start)) { + prom_printf("PCI: Impossible full %s space.\n", + (io ? "IO" : "MEM")); + prom_halt(); + } + vp = pci_vma_alloc(); + vp->start = new_base; + vp->end = vp->start + size; + vp->base_reg = breg; + + /* Sanity */ + if(io && vp->end & ~(0xffff)) { + prom_printf("PCI: Out of range PCI I/O " + "[%08lx:%08lx] during fixup\n", + vp->start, vp->end); + prom_halt(); + } + pci_add_vma(pbm, vp, io); + + rtmp = new_base; + if(io) + rtmp |= (rtmp & PCI_BASE_ADDRESS_IO_MASK); + else + rtmp |= (rtmp & PCI_BASE_ADDRESS_MEM_MASK); + pcibios_write_config_dword(pdev->bus->number, + pdev->devfn, + breg, rtmp); + + /* Apply PBM ranges and update pci_dev. */ + pci_addr = new_base; + for(rng = 0; rng < pbm->num_pbm_ranges; rng++) { + struct linux_prom_pci_ranges *rp; + int rspace; + + rp = &pbm->pbm_ranges[rng]; + rspace = (rp->child_phys_hi >> 24) & 3; + if(io && rspace != 1) + continue; + else if(!io && rspace != 2) + continue; + pci_addr += ((u64)rp->parent_phys_lo); + pci_addr += (((u64)rp->parent_phys_hi)<<32UL); + break; + } + if(rng == pbm->num_pbm_ranges) { + /* AIEEE */ + prom_printf("fixup_doit: YIEEE, cannot find " + "PBM ranges\n"); + } + pdev->base_address[ridx] = (unsigned long)__va(pci_addr); + + /* Preserve I/O space bit. */ + if(io) { + pdev->base_address[ridx] |= 1; + IO_seen = 1; + } else { + MEM_seen = 1; + } + } + } + } + if(IO_seen || MEM_seen) { + unsigned int l; + + pcibios_read_config_dword(pdev->bus->number, + pdev->devfn, + PCI_COMMAND, &l); +#ifdef FIXUP_REGS_DEBUG + prom_printf("["); +#endif + if(IO_seen) { +#ifdef FIXUP_REGS_DEBUG + prom_printf("IO "); +#endif + l |= PCI_COMMAND_IO; + } + if(MEM_seen) { +#ifdef FIXUP_REGS_DEBUG + prom_printf("MEM"); +#endif + l |= PCI_COMMAND_MEMORY; + } +#ifdef FIXUP_REGS_DEBUG + prom_printf("]"); +#endif + pcibios_write_config_dword(pdev->bus->number, + pdev->devfn, + PCI_COMMAND, l); + } + +#ifdef FIXUP_REGS_DEBUG + prom_printf("REG_FIXUP[%s]: ", pci_strdev(pdev->vendor, pdev->device)); + for(preg = 0; preg < 6; preg++) { + if(pdev->base_address[preg] != 0) + prom_printf("%d[%016lx] ", preg, pdev->base_address[preg]); + } + prom_printf("\n"); +#endif +} + +#define imap_offset(__member) \ + ((unsigned long)(&(((struct psycho_regs *)0)->__member))) + +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus, slot; + + bus = (ino & 0x10) >> 4; + slot = (ino & 0x0c) >> 2; + + if(bus == 0) { + /* Perform a sanity check, we might as well. + * PBM A only has 2 PCI slots. + */ + if(slot > 1) { + prom_printf("pcislot_imap: Bogus slot on PBM A (%ld)\n", slot); + prom_halt(); + } + if(slot == 0) + return imap_offset(imap_a_slot0); + else + return imap_offset(imap_a_slot1); + } else { + switch(slot) { + case 0: + return imap_offset(imap_b_slot0); + case 1: + return imap_offset(imap_b_slot1); + case 2: + return imap_offset(imap_b_slot2); + case 3: + return imap_offset(imap_b_slot3); + default: + prom_printf("pcislot_imap: IMPOSSIBLE [%d:%d]\n", + bus, slot); + prom_halt(); + return 0; /* Make gcc happy */ + }; + } +} + +/* Exported for EBUS probing layer. */ +unsigned int psycho_irq_build(unsigned int full_ino) +{ + unsigned long imap_off, ign, ino; + + ign = (full_ino & PSYCHO_IMAP_IGN) >> 6; + ino = (full_ino & PSYCHO_IMAP_INO); + + /* Compute IMAP register offset, generic IRQ layer figures out + * the ICLR register address as this is simple given the 32-bit + * irq number and IMAP register address. + */ + if((ino & 0x20) == 0) + imap_off = psycho_pcislot_imap_offset(ino); + else { + switch(ino) { + case 0x20: + /* Onboard SCSI. */ + imap_off = imap_offset(imap_scsi); + break; + + case 0x21: + /* Onboard Ethernet (ie. CheerIO/HME) */ + imap_off = imap_offset(imap_eth); + break; + + case 0x22: + /* Onboard Parallel Port */ + imap_off = imap_offset(imap_bpp); + break; + + case 0x23: + /* Audio Record */ + imap_off = imap_offset(imap_au_rec); + break; + + case 0x24: + /* Audio Play */ + imap_off = imap_offset(imap_au_play); + break; + + case 0x25: + /* Power Fail */ + imap_off = imap_offset(imap_pfail); + break; + + case 0x26: + /* Onboard KBD/MOUSE/SERIAL */ + imap_off = imap_offset(imap_kms); + break; + + case 0x27: + /* Floppy (ie. fdthree) */ + imap_off = imap_offset(imap_flpy); + break; + + case 0x28: + /* Spare HW INT */ + imap_off = imap_offset(imap_shw); + break; + + case 0x29: + /* Onboard Keyboard (only) */ + imap_off = imap_offset(imap_kbd); + break; + + case 0x2a: + /* Onboard Mouse (only) */ + imap_off = imap_offset(imap_ms); + break; + + case 0x2b: + /* Onboard Serial (only) */ + imap_off = imap_offset(imap_ser); + break; + + case 0x32: + /* Power Management */ + imap_off = imap_offset(imap_pmgmt); + break; + + default: + /* We don't expect anything else. The other possible + * values are not found in PCI device nodes, and are + * so hardware specific that they should use DCOOKIE's + * anyways. + */ + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + }; + } + imap_off -= imap_offset(imap_a_slot0); + + return pci_irq_encode(imap_off, 0 /* XXX */, ign, ino); +} + +/* #define FIXUP_IRQ_DEBUG */ + +static void fixup_irq(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + int node) +{ + unsigned int prom_irq, portid = pbm->parent->upa_portid; + unsigned char pci_irq_line = pdev->irq; + int err; + +#ifdef FIXUP_IRQ_DEBUG + printk("fixup_irq[%s:%s]: ", + pci_strvendor(pdev->vendor), + pci_strdev(pdev->vendor, pdev->device)); +#endif + err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq)); + if(err == 0 || err == -1) { + prom_printf("fixup_irq: No interrupts property for dev[%s:%s]\n", + pci_strvendor(pdev->vendor), + pci_strdev(pdev->vendor, pdev->device)); + prom_halt(); + } + + /* See if fully specified already (ie. for onboard devices like hme) */ + if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { + pdev->irq = psycho_irq_build(prom_irq); +#ifdef FIXUP_IRQ_DEBUG + printk("fully specified prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); +#endif + } else { + unsigned int bus, slot, line; + + bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; + line = (pci_irq_line) & 3; + + /* Slot determination is only slightly complex. Handle + * the easy case first. + */ + if(pdev->bus->number == pbm->pci_first_busno) { + if(pbm == &pbm->parent->pbm_A) + slot = (pdev->devfn >> 3) - 1; + else + slot = ((pdev->devfn >> 3) >> 1) - 1; + } else { + /* Underneath a bridge, use slot number of parent + * bridge. + */ + slot = (pdev->bus->self->devfn >> 3) - 1; + + /* Use low slot number bits of child as IRQ line. */ + line = ((pdev->devfn >> 3) & 3); + } + slot = (slot << 2); + + pdev->irq = psycho_irq_build((((portid << 6) & PSYCHO_IMAP_IGN) | + (bus | slot | line))); +#ifdef FIXUP_IRQ_DEBUG + do { + unsigned char iline, ipin; + + (void)pcibios_read_config_byte(pdev->bus->number, + pdev->devfn, + PCI_INTERRUPT_PIN, + &ipin); + (void)pcibios_read_config_byte(pdev->bus->number, + pdev->devfn, + PCI_INTERRUPT_LINE, + &iline); + printk("FIXED portid[%x] bus[%x] slot[%x] line[%x] irq[%x] " + "iline[%x] ipin[%x] prom_irq[%x]", + portid, bus>>4, slot>>2, line, pdev->irq, + iline, ipin, prom_irq); + } while(0); +#endif + } +#ifdef FIXUP_IRQ_DEBUG + printk("\n"); +#endif +} + +static void fixup_doit(struct pci_dev *pdev, + struct linux_pbm_info *pbm, + struct linux_prom_pci_registers *pregs, + int nregs, + int node) +{ + struct linux_prom_pci_registers assigned[PROMREG_MAX]; + int numaa, err; + + /* Get assigned addresses, if any. */ + err = prom_getproperty(node, "assigned-addresses", + (char *)&assigned[0], sizeof(assigned)); + if(err == 0 || err == -1) + numaa = 0; + else + numaa = (err / sizeof(struct linux_prom_pci_registers)); + + /* First, scan and fixup base registers. */ + fixup_regs(pdev, pbm, pregs, nregs, &assigned[0], numaa); + + /* Next, fixup interrupt numbers. */ + fixup_irq(pdev, pbm, node); +} + +static void fixup_pci_dev(struct pci_dev *pdev, + struct pci_bus *pbus, + struct linux_pbm_info *pbm) +{ + struct linux_prom_pci_registers pregs[PROMREG_MAX]; + struct pcidev_cookie *pcp = pdev->sysdata; + int node, nregs, err; + + /* If this is a PCI bridge, we must program it. */ + if(pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) { + unsigned short cmd; + + /* First, enable bus mastering. */ + pcibios_read_config_word(pdev->bus->number, + pdev->devfn, + PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + pcibios_write_config_word(pdev->bus->number, + pdev->devfn, + PCI_COMMAND, cmd); + + /* Now, set cache line size to 64-bytes. */ + pcibios_write_config_byte(pdev->bus->number, + pdev->devfn, + PCI_CACHE_LINE_SIZE, 64); + } + + /* Ignore if this is one of the PBM's, EBUS, or a + * sub-bridge underneath the PBM. We only need to fixup + * true devices. + */ + if((pdev->class >> 8 == PCI_CLASS_BRIDGE_PCI) || + (pdev->class >> 8 == PCI_CLASS_BRIDGE_HOST) || + (pdev->class >> 8 == PCI_CLASS_BRIDGE_OTHER) || + (pcp == NULL)) + return; + + node = pcp->prom_node; + + err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); + if(err == 0 || err == -1) { + prom_printf("Cannot find REG for pci_dev\n"); + prom_halt(); + } + + nregs = (err / sizeof(pregs[0])); + + fixup_doit(pdev, pbm, &pregs[0], nregs, node); +} + +static void fixup_pci_bus(struct pci_bus *pbus, struct linux_pbm_info *pbm) +{ + struct pci_dev *pdev; + + for(pdev = pbus->devices; pdev; pdev = pdev->sibling) + fixup_pci_dev(pdev, pbus, pbm); + + for(pbus = pbus->children; pbus; pbus = pbus->children) + fixup_pci_bus(pbus, pbm); +} + +static void fixup_addr_irq(struct linux_pbm_info *pbm) +{ + struct pci_bus *pbus = &pbm->pci_bus; + + /* Work through top level devices (not bridges, those and their + * devices are handled specially in the next loop). + */ + fixup_pci_bus(pbus, pbm); +} + +/* Walk all PCI devices probes, fixing up base registers and IRQ registers. + * We use OBP for most of this work. + */ +static void psycho_final_fixup(struct linux_psycho *psycho) +{ + /* Second, fixup base address registers and IRQ lines... */ + fixup_addr_irq(&psycho->pbm_A); + fixup_addr_irq(&psycho->pbm_B); + +#if 0 + prom_halt(); +#endif +} + +unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end) +{ + struct linux_psycho *psycho = psycho_root; + + pci_probe_enable = 1; + + /* XXX Really this should be per-PSYCHO, but the config space + * XXX reads and writes give us no way to know which PSYCHO + * XXX in which the config space reads should occur. + * XXX + * XXX Further thought says that we cannot change this generic + * XXX interface, else we'd break xfree86 and other parts of the + * XXX kernel (but whats more important is breaking userland for + * XXX the ix86/Alpha/etc. people). So we should define our own + * XXX internal extension initially, we can compile our own user + * XXX apps that need to get at PCI configuration space. + */ + + /* Probe busses under PBM A. */ + pbm_probe(&psycho->pbm_A, &memory_start); + + /* Probe busses under PBM B. */ + pbm_probe(&psycho->pbm_B, &memory_start); + + pci_init_alloc_init(&memory_start); + + /* Walk all PCI devices found. For each device, and + * PCI bridge which is not one of the PSYCHO PBM's, fill in the + * sysdata with a pointer to the PBM (for pci_bus's) or + * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's). + */ + fill_in_pbm_cookies(&psycho->pbm_A); + fill_in_pbm_cookies(&psycho->pbm_B); + + /* See what OBP has taken care of already. */ + record_assignments(&psycho->pbm_A); + record_assignments(&psycho->pbm_B); + + /* Now, fix it all up. */ + psycho_final_fixup(psycho); + + pci_init_alloc_fini(); + + return ebus_init(memory_start, memory_end); +} + +/* "PCI: The emerging standard..." 8-( */ +volatile int pci_poke_in_progress = 0; +volatile int pci_poke_faulted = 0; + +/* XXX Current PCI support code is broken, it assumes one master PCI config + * XXX space exists, on Ultra we can have many of them, especially with + * XXX 'dual-pci' boards on Sunfire/Starfire/Wildfire. + */ +static char *pci_mkaddr(unsigned char bus, unsigned char device_fn, + unsigned char where) +{ + unsigned long ret = (unsigned long) psycho_root->pci_config_space; + + ret |= (1 << 24); + ret |= ((bus & 0xff) << 16); + ret |= ((device_fn & 0xff) << 8); + ret |= (where & 0xfc); + return (unsigned char *)ret; +} + +static inline int out_of_range(unsigned char bus, unsigned char device_fn) +{ + return ((bus == 0 && PCI_SLOT(device_fn) > 4) || + (bus == 1 && PCI_SLOT(device_fn) > 6) || + (pci_probe_enable == 0)); +} + +int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char *value) +{ + unsigned char *addr = pci_mkaddr(bus, device_fn, where); + unsigned int word, trapped; + + *value = 0xff; + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + trapped = pci_poke_faulted; + pci_poke_faulted = 0; + if(!trapped) { + switch(where & 3) { + case 0: + *value = word & 0xff; + break; + case 1: + *value = (word >> 8) & 0xff; + break; + case 2: + *value = (word >> 16) & 0xff; + break; + case 3: + *value = (word >> 24) & 0xff; + break; + }; + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short *value) +{ + unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); + unsigned int word, trapped; + + *value = 0xffff; + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + trapped = pci_poke_faulted; + pci_poke_faulted = 0; + if(!trapped) { + switch(where & 3) { + case 0: + *value = word & 0xffff; + break; + case 2: + *value = (word >> 16) & 0xffff; + break; + default: + printk("pcibios_read_config_word: misaligned " + "reg [%x]\n", where); + break; + }; + } + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int *value) +{ + unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + unsigned int word, trapped; + + *value = 0xffffffff; + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + trapped = pci_poke_faulted; + pci_poke_faulted = 0; + if(!trapped) + *value = word; + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned char value) +{ + unsigned char *addr = pci_mkaddr(bus, device_fn, where); + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + + /* Endianness doesn't matter but we have to get the memory + * barriers in there so... + */ + __asm__ __volatile__("membar #Sync\n\t" + "stba %0, [%1] %2\n\t" + "membar #Sync\n\t" + : /* no outputs */ + : "r" (value), "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_word (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned short value) +{ + unsigned short *addr = (unsigned short *)pci_mkaddr(bus, device_fn, where); + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + __asm__ __volatile__("membar #Sync\n\t" + "stha %0, [%1] %2\n\t" + "membar #Sync\n\t" + : /* no outputs */ + : "r" (value), "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + return PCIBIOS_SUCCESSFUL; +} + +int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn, + unsigned char where, unsigned int value) +{ + unsigned int *addr = (unsigned int *)pci_mkaddr(bus, device_fn, where); + + if(out_of_range(bus, device_fn)) + return PCIBIOS_SUCCESSFUL; + + pci_poke_in_progress = 1; + __asm__ __volatile__("membar #Sync\n\t" + "stwa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (value), "r" (addr), "i" (ASI_PL)); + pci_poke_in_progress = 0; + return PCIBIOS_SUCCESSFUL; +} + +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + int err = 0; + + lock_kernel(); + switch(len) { + case 1: + pcibios_read_config_byte(bus, dfn, off, &ubyte); + put_user(ubyte, buf); + break; + case 2: + pcibios_read_config_word(bus, dfn, off, &ushort); + put_user(ushort, buf); + break; + case 4: + pcibios_read_config_dword(bus, dfn, off, &uint); + put_user(uint, buf); + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); + + return err; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + unsigned char ubyte; + unsigned short ushort; + unsigned int uint; + int err = 0; + + lock_kernel(); + switch(len) { + case 1: + err = get_user(ubyte, (unsigned char *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, ubyte); + break; + + case 2: + err = get_user(ushort, (unsigned short *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, ushort); + break; + + case 4: + err = get_user(uint, (unsigned int *)buf); + if(err) + break; + pcibios_write_config_byte(bus, dfn, off, uint); + break; + + default: + err = -EINVAL; + break; + + }; + unlock_kernel(); + + return err; +} + +#endif diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index ac91df894..3df35ef14 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -609,10 +609,6 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long tmp; int res; -#if 0 - /* XXX Find out what is really going on. */ - flush_cache_all(); -#endif /* Non-word alignment _not_ allowed on Sparc. */ if (current->tss.flags & SPARC_FLAG_32BIT) { unsigned int x; @@ -1055,7 +1051,7 @@ asmlinkage void syscall_trace(void) current->exit_code = SIGTRAP; current->state = TASK_STOPPED; current->tss.flags ^= MAGIC_CONSTANT; - notify_parent(current); + notify_parent(current, SIGCHLD); schedule(); /* * this isn't the same as continuing with a signal, but it will do @@ -1067,9 +1063,9 @@ asmlinkage void syscall_trace(void) current->pid, current->exit_code); #endif if (current->exit_code) { - /* spin_lock_irq(¤t->sigmask_lock); */ + spin_lock_irq(¤t->sigmask_lock); current->signal |= (1 << (current->exit_code - 1)); - /* spin_unlock_irq(¤t->sigmask_lock); */ + spin_unlock_irq(¤t->sigmask_lock); } current->exit_code = 0; diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 9f087a969..a3ac093f3 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.28 1997/06/30 10:31:39 jj Exp $ +/* $Id: rtrap.S,v 1.33 1997/08/21 09:13:22 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -36,13 +36,29 @@ rtrap: sethi %hi(bh_active), %l2 andn %l1, %l4, %l1 be,pt %icc, to_user andn %l7, PSTATE_IE, %l7 -rt_continue: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 - ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 - ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 - brnz,pn %l2, rt_fpu_restore - ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 -rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 + ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 + andcc %l2, FPRS_FEF, %g0 + be,pt %icc, rt_continue + and %l2, FPRS_DL, %l6 + wr %g0, FPRS_FEF, %fprs + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %g5 + membar #StoreLoad | #LoadLoad + brz,pn %l6, 1f + wr %g0, ASI_BLK_P, %asi + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 +1: andcc %l2, FPRS_DU, %g0 + be,pn %icc, 1f + wr %g5, 0, %gsr + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 +1: membar #Sync + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr +rt_continue: ld [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 + ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 + ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 + ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 mov %g6, %l6 ldx [%sp + PTREGS_OFF + PT_V9_G4], %g4 ldx [%sp + PTREGS_OFF + PT_V9_G5], %g5 @@ -69,10 +85,12 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 wrpr %l1, %g0, %tstate wrpr %l2, %g0, %tpc + wrpr %o2, %g0, %tnpc mov PRIMARY_CONTEXT, %l7 brnz,pn %l3, kern_rtt - wrpr %o2, %g0, %tnpc + mov SECONDARY_CONTEXT, %l5 stxa %l0, [%l7] ASI_DMMU + stxa %l0, [%l5] ASI_DMMU flush %l6 rdpr %wstate, %l1 @@ -88,10 +106,14 @@ rt_after_fpu: ldx [%sp + PTREGS_OFF + PT_V9_G3], %g3 retry kern_rtt: restore retry -to_user: sethi %hi(need_resched), %l0 - ld [%l0 + %lo(need_resched)], %l0 +to_user: lduw [%g6 + AOFF_task_processor], %o0 + mov 1, %o1 + sethi %hi(need_resched), %l0 + ldx [%l0 + %lo(need_resched)], %l0 + sllx %o1, %o0, %o1 wrpr %l7, PSTATE_IE, %pstate - brz,pt %l0, check_signal + andcc %o1, %l0, %g0 + be,pt %xcc, check_signal ldx [%g6 + AOFF_task_signal], %l0 call schedule @@ -99,36 +121,123 @@ to_user: sethi %hi(need_resched), %l0 ldx [%g6 + AOFF_task_signal], %l0 nop check_signal: ldx [%g6 + AOFF_task_blocked], %o0 + ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 andncc %l0, %o0, %g0 be,pt %xcc, check_user_wins ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 - mov %l5, %o2 mov %l6, %o3 call do_signal add %sp, STACK_BIAS + REGWIN_SZ, %o1 ldx [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 -check_user_wins: - brz,pt %o2, rt_continue - nop +check_user_wins:brz,pt %o2, 1f + sethi %hi(TSTATE_PEF), %o3 call fault_in_user_windows add %sp, STACK_BIAS + REGWIN_SZ, %o0 - ba,a,pt %xcc, rt_continue -rt_fpu_restore: wr %g0, FPRS_FEF, %fprs - add %sp, PTREGS_OFF + TRACEREG_SZ, %g4 - wr %g0, ASI_BLK_P, %asi + sethi %hi(TSTATE_PEF), %o3 +1: andcc %l2, FPRS_FEF, %g0 + be,a,pt %icc, rt_continue + andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3 + ld [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 + wr %g0, FPRS_FEF, %fprs + wr %o3, 0, %gsr + andcc %l2, SPARC_FLAG_USEDFPUL, %g0 + bne,pn %icc, 2f + andcc %l2, SPARC_FLAG_USEDFPUU, %g0 + fzero %f0 + bne,pn %icc, 1f + fzero %f2 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 + faddd %f0, %f2, %f32 + fmuld %f0, %f2, %f34 + faddd %f0, %f2, %f36 + fmuld %f0, %f2, %f38 + faddd %f0, %f2, %f40 + fmuld %f0, %f2, %f42 + faddd %f0, %f2, %f44 + fmuld %f0, %f2, %f46 + faddd %f0, %f2, %f48 + fmuld %f0, %f2, %f50 + faddd %f0, %f2, %f52 + fmuld %f0, %f2, %f54 + faddd %f0, %f2, %f56 + fmuld %f0, %f2, %f58 + faddd %f0, %f2, %f60 + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr + ba,pt %xcc, rt_continue + wr %g0, FPRS_FEF, %fprs +1: wr %g0, ASI_BLK_P, %asi membar #StoreLoad | #LoadLoad - ldda [%g4 + 0x000] %asi, %f0 - ldda [%g4 + 0x040] %asi, %f16 - ldda [%g4 + 0x080] %asi, %f32 - ldda [%g4 + 0x0c0] %asi, %f48 - ldx [%g4 + 0x100], %fsr - ldx [%g4 + 0x108], %g3 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 + faddd %f0, %f2, %f4 + fmuld %f0, %f2, %f6 + faddd %f0, %f2, %f8 + fmuld %f0, %f2, %f10 + faddd %f0, %f2, %f12 + fmuld %f0, %f2, %f14 + faddd %f0, %f2, %f16 + fmuld %f0, %f2, %f18 + faddd %f0, %f2, %f20 + fmuld %f0, %f2, %f22 + faddd %f0, %f2, %f24 + fmuld %f0, %f2, %f26 + faddd %f0, %f2, %f28 + fmuld %f0, %f2, %f30 + membar #Sync + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr + ba,pt %xcc, rt_continue + wr %g0, FPRS_FEF, %fprs +2: membar #StoreLoad | #LoadLoad + andcc %l2, SPARC_FLAG_USEDFPUU, %g0 + bne,pt %icc, 3f + wr %g0, ASI_BLK_P, %asi + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 + fzero %f32 + fzero %f34 + faddd %f32, %f34, %f36 + fmuld %f32, %f34, %f38 + faddd %f32, %f34, %f40 + fmuld %f32, %f34, %f42 + faddd %f32, %f34, %f44 + fmuld %f32, %f34, %f46 + faddd %f32, %f34, %f48 + fmuld %f32, %f34, %f50 + faddd %f32, %f34, %f52 + fmuld %f32, %f34, %f54 + faddd %f32, %f34, %f56 + fmuld %f32, %f34, %f58 + faddd %f32, %f34, %f60 + fmuld %f32, %f34, %f62 + membar #Sync + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr + ba,pt %xcc, rt_continue + wr %g0, FPRS_FEF, %fprs +3: ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 + ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 membar #Sync + ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr + ba,pt %xcc, rt_continue + wr %g0, FPRS_FEF, %fprs - b,pt %xcc, rt_after_fpu - wr %g3, 0, %gsr #undef PTREGS_OFF diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index 7eb47e976..147c6e55d 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.11 1997/07/24 12:15:05 davem Exp $ +/* $Id: setup.c,v 1.12 1997/08/28 02:23:19 ecd Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -233,8 +233,6 @@ extern unsigned ramdisk_size; extern int root_mountflags; -extern void register_console(void (*proc)(const char *)); - char saved_command_line[256]; char reboot_command[256]; diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index cfc55fc2e..87241f8e3 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $ +/* $Id: signal.c,v 1.24 1997/09/02 20:53:03 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -54,12 +54,12 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) if(tp->w_saved || (((unsigned long)ucp) & (sizeof(unsigned long)-1)) || (!__access_ok((unsigned long)ucp, sizeof(*ucp)))) - do_exit(SIGSEGV); + goto do_sigsegv; grp = &ucp->uc_mcontext.mc_gregs; __get_user(pc, &((*grp)[MC_PC])); __get_user(npc, &((*grp)[MC_NPC])); if((pc | npc) & 3) - do_exit(SIGSEGV); + goto do_sigsegv; if(regs->u_regs[UREG_I1]) { __get_user(current->blocked, &ucp->uc_sigmask); current->blocked &= _BLOCKABLE; @@ -67,7 +67,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) regs->tpc = pc; regs->tnpc = npc; __get_user(regs->y, &((*grp)[MC_Y])); - __get_user(tstate, &((*grp)[MC_Y])); + __get_user(tstate, &((*grp)[MC_TSTATE])); regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); regs->tstate |= (tstate & (TSTATE_ICC | TSTATE_XCC)); __get_user(regs->u_regs[UREG_G1], (&(*grp)[MC_G1])); @@ -94,12 +94,23 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); if(fenab) { unsigned long *fpregs = (unsigned long *)(regs+1); - copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), - (sizeof(unsigned long) * 32)); + unsigned long fprs; + __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); + if (fprs & FPRS_DL) + copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), + (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, + (sizeof(unsigned int) * 32)); __get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); __get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); - regs->fprs = FPRS_FEF; + regs->fprs = fprs; + regs->tstate |= TSTATE_PEF; } + return; +do_sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } asmlinkage void sparc64_get_context(struct pt_regs *regs) @@ -109,11 +120,11 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) mc_gregset_t *grp; mcontext_t *mcp; unsigned long fp, i7; - unsigned char fenab = (current->flags & PF_USEDFPU); + unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU); synchronize_user_stack(); if(tp->w_saved || clear_user(ucp, sizeof(*ucp))) - do_exit(SIGSEGV); + goto do_sigsegv; mcp = &ucp->uc_mcontext; grp = &mcp->mc_gregs; @@ -150,12 +161,30 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab)); if(fenab) { unsigned long *fpregs = (unsigned long *)(regs+1); - copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, - (sizeof(unsigned long) * 32)); + unsigned long fprs; + + fprs = (regs->fprs & FPRS_FEF) | + (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + if (fprs & FPRS_DL) + copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, + (sizeof(unsigned int) * 32)); + else + clear_user(&(mcp->mc_fpregs.mcfpu_fregs), + (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16, + (sizeof(unsigned int) * 32)); + else + clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, + (sizeof(unsigned int) * 32)); __put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr)); __put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr)); - __put_user(FPRS_FEF, &(mcp->mc_fpregs.mcfpu_fprs)); + __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs)); } + return; +do_sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } /* @@ -233,11 +262,19 @@ static inline void restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(regs+1); - copy_from_user(fpregs, &fpu->si_float_regs[0], - (sizeof(unsigned int) * 64)); + unsigned long fprs; + + __get_user(fprs, &fpu->si_fprs); + if (fprs & FPRS_DL) + copy_from_user(fpregs, &fpu->si_float_regs[0], + (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_from_user(fpregs+16, &fpu->si_float_regs[32], + (sizeof(unsigned int) * 32)); __get_user(fpregs[32], &fpu->si_fsr); __get_user(fpregs[33], &fpu->si_gsr); - regs->fprs = FPRS_FEF; + regs->fprs = fprs; + regs->tstate |= TSTATE_PEF; } void do_sigreturn(struct pt_regs *regs) @@ -304,11 +341,26 @@ static inline void save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(regs+1); - copy_to_user(&fpu->si_float_regs[0], fpregs, - (sizeof(unsigned int) * 64)); + unsigned long fprs; + + fprs = (regs->fprs & FPRS_FEF) | + (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + if (fprs & FPRS_DL) + copy_to_user(&fpu->si_float_regs[0], fpregs, + (sizeof(unsigned int) * 32)); + else + clear_user(&fpu->si_float_regs[0], + (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_to_user(&fpu->si_float_regs[32], fpregs+16, + (sizeof(unsigned int) * 32)); + else + clear_user(&fpu->si_float_regs[32], + (sizeof(unsigned int) * 32)); __put_user(fpregs[32], &fpu->si_fsr); __put_user(fpregs[33], &fpu->si_gsr); - regs->fprs = 0; + __put_user(fprs, &fpu->si_fprs); + regs->tstate &= ~TSTATE_PEF; } static inline void @@ -321,7 +373,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, /* 1. Make sure everything is clean */ synchronize_user_stack(); sigframe_size = NF_ALIGNEDSZ; - if (!(current->flags & PF_USEDFPU)) + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct new_signal_frame *) @@ -339,7 +391,7 @@ new_setup_frame(struct sigaction *sa, struct pt_regs *regs, /* 2. Save the current process state */ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); - if (current->flags & PF_USEDFPU) { + if (current->tss.flags & SPARC_FLAG_USEDFPU) { save_fpu_state(regs, &sf->fpu_state); __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { @@ -452,7 +504,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; - notify_parent(current); + notify_parent(current, SIGCHLD); schedule(); if (!(signr = current->exit_code)) continue; @@ -498,7 +550,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs, current->exit_code = signr; if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & SA_NOCLDSTOP)) - notify_parent(current); + notify_parent(current, SIGCHLD); schedule(); continue; diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 5135c2ae5..16cec2a72 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $ +/* $Id: signal32.c,v 1.30 1997/08/29 15:51:33 jj Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -117,9 +117,17 @@ asmlinkage void _sigpause32_common(unsigned int set, struct pt_regs *regs) static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(regs + 1); - copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 64)); + unsigned long fprs; + + __get_user(fprs, &fpu->si_fprs); + if (fprs & FPRS_DL) + copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); __get_user(fpregs[32], &fpu->si_fsr); __get_user(fpregs[33], &fpu->si_gsr); + regs->fprs = fprs; + regs->tstate |= TSTATE_PEF; } void do_new_sigreturn32(struct pt_regs *regs) @@ -169,8 +177,10 @@ void do_new_sigreturn32(struct pt_regs *regs) regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); +#if 0 if (psr & PSR_EF) - regs->fprs = FPRS_FEF; + regs->tstate |= TSTATE_PEF; +#endif __get_user(fpu_save, &sf->fpu_save); if (fpu_save) @@ -273,7 +283,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); psr = tstate_to_psr (regs->tstate); - if(current->flags & PF_USEDFPU) + if(current->tss.flags & SPARC_FLAG_USEDFPU) psr |= PSR_EF; __put_user(psr, &sc->sigc_psr); __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); @@ -318,10 +328,22 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { unsigned long *fpregs = (unsigned long *)(regs+1); - copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 64)); + unsigned long fprs; + + fprs = (regs->fprs & FPRS_FEF) | + (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + if (fprs & FPRS_DL) + copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); + else + clear_user(&fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); + if (fprs & FPRS_DU) + copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); + else + clear_user(&fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); __put_user(fpregs[32], &fpu->si_fsr); __put_user(fpregs[33], &fpu->si_gsr); - regs->fprs = 0; + __put_user(fprs, &fpu->si_fprs); + regs->tstate &= ~TSTATE_PEF; } static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, @@ -335,7 +357,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, /* 1. Make sure everything is clean */ synchronize_user_stack(); sigframe_size = NF_ALIGNEDSZ; - if (!(current->flags & PF_USEDFPU)) + if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) sigframe_size -= sizeof(__siginfo_fpu_t); regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; @@ -362,7 +384,7 @@ static inline void new_setup_frame32(struct sigaction *sa, struct pt_regs *regs, __put_user(regs->tnpc, &sf->info.si_regs.npc); __put_user(regs->y, &sf->info.si_regs.y); psr = tstate_to_psr (regs->tstate); - if(current->flags & PF_USEDFPU) + if(current->tss.flags & SPARC_FLAG_USEDFPU) psr |= PSR_EF; __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) @@ -469,7 +491,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(regs->tpc, &((*gr) [SVR4_PC])); __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); - if(current->flags & PF_USEDFPU) + if(current->tss.flags & SPARC_FLAG_USEDFPU) psr |= PSR_EF; __put_user(psr, &((*gr) [SVR4_PSR])); __put_user(regs->y, &((*gr) [SVR4_Y])); @@ -488,7 +510,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, /* Save the currently window file: */ /* 1. Link sfp->uc->gwins to our windows */ - __put_user(gw, &mc->gwin); + __put_user((u32)(long)gw, &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ __put_user(current->tss.w_saved, &gw->count); @@ -506,9 +528,9 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, */ #if 0 for(window = 0; window < current->tss.w_saved; window++) { - __put_user((int *) &(gw->win [window]), &gw->winptr [window]); + __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window ); copy_to_user(&gw->win [window], ¤t->tss.reg_window [window], sizeof (svr4_rwindow_t)); - __put_user(0, gw->winptr [window]); + __put_user(0, (int *)gw->winptr + window); } #endif @@ -546,7 +568,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, } asmlinkage int -svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) +svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) { svr4_gregset_t *gr; svr4_mcontext_t *mc; @@ -555,6 +577,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) synchronize_user_stack(); if (current->tss.w_saved){ printk ("Uh oh, w_saved is not zero (%ld)\n", current->tss.w_saved); + lock_kernel(); do_exit (SIGSEGV); } if(clear_user(uc, sizeof (*uc))) @@ -571,7 +594,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); __put_user((tstate_to_psr(regs->tstate) | - ((current->flags & PF_USEDFPU) ? PSR_EF : 0)), + ((current->tss.flags & SPARC_FLAG_USEDFPU) ? PSR_EF : 0)), &uc->mcontext.greg [SVR4_PSR]); __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); @@ -594,7 +617,7 @@ svr4_getcontext32(svr4_ucontext_t *uc, struct pt_regs *regs) /* Set the context for a svr4 application, this is Solaris way to sigreturn */ -asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs) +asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) { struct thread_struct *tp = ¤t->tss; svr4_gregset_t *gr; @@ -639,9 +662,10 @@ asmlinkage int svr4_setcontext32(svr4_ucontext_t *c, struct pt_regs *regs) __get_user(psr, &((*gr) [SVR4_PSR])); regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); +#if 0 if(psr & PSR_EF) - regs->fprs = FPRS_FEF; - + regs->tstate |= TSTATE_PEF; +#endif /* Restore g[1..7] and o[0..7] registers */ for (i = 0; i < 7; i++) __get_user(regs->u_regs[UREG_G1+i], (&(*gr)[SVR4_G1])+i); @@ -718,7 +742,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, if ((current->flags & PF_PTRACED) && signr != SIGKILL) { current->exit_code = signr; current->state = TASK_STOPPED; - notify_parent(current); + notify_parent(current, SIGCHLD); schedule(); if (!(signr = current->exit_code)) continue; @@ -764,7 +788,7 @@ asmlinkage int do_signal32(unsigned long oldmask, struct pt_regs * regs, current->exit_code = signr; if(!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags & SA_NOCLDSTOP)) - notify_parent(current); + notify_parent(current, SIGCHLD); schedule(); continue; diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 77ccf40a0..8dd471be6 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -10,11 +10,12 @@ #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> +#include <linux/delay.h> +#include <asm/head.h> #include <asm/ptrace.h> #include <asm/atomic.h> -#include <asm/delay.h> #include <asm/irq.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -33,9 +34,9 @@ volatile int smp_processors_ready = 0; unsigned long cpu_present_map = 0; int smp_num_cpus = 1; int smp_threads_ready = 0; -volatile unsigned long cpu_callin_map[NR_CPUS] = {0,}; -struct cpuinfo_sparc cpu_data[NR_CPUS]; +struct cpuinfo_sparc cpu_data[NR_CPUS] __attribute__ ((aligned (64))); + static unsigned char boot_cpu_id = 0; static int smp_activated = 0; @@ -44,8 +45,6 @@ volatile int cpu_logical_map[NR_CPUS]; struct klock_info klock_info = { KLOCK_CLEAR, 0 }; -static volatile int smp_commenced = 0; - void smp_setup(char *str, int *ints) { /* XXX implement me XXX */ @@ -68,45 +67,64 @@ char *smp_info(void) void smp_store_cpu_info(int id) { - cpu_data[id].udelay_val = loops_per_sec; + cpu_data[id].udelay_val = loops_per_sec; + cpu_data[id].irq_count = 0; + cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK; + cpu_data[id].pgcache_size = 0; + cpu_data[id].pgd_cache = NULL; + cpu_data[id].pmd_cache = NULL; + cpu_data[id].pte_cache = NULL; } +extern void distribute_irqs(void); + void smp_commence(void) { - flush_cache_all(); - flush_tlb_all(); - smp_commenced = 1; - flush_cache_all(); - flush_tlb_all(); + distribute_irqs(); } static void smp_setup_percpu_timer(void); static volatile unsigned long callin_flag = 0; +extern void inherit_locked_prom_mappings(int save_p); +extern void cpu_probe(void); + void smp_callin(void) { int cpuid = hard_smp_processor_id(); - flush_cache_all(); - flush_tlb_all(); + inherit_locked_prom_mappings(0); + + __flush_cache_all(); + __flush_tlb_all(); + + cpu_probe(); + + /* Master did this already, now is the time for us to do it. */ + __asm__ __volatile__(" + sethi %%hi(0x80000000), %%g1 + sllx %%g1, 32, %%g1 + rd %%tick, %%g2 + add %%g2, 6, %%g2 + andn %%g2, %%g1, %%g2 + wrpr %%g2, 0, %%tick +" : /* no outputs */ + : /* no inputs */ + : "g1", "g2"); smp_setup_percpu_timer(); + __sti(); + calibrate_delay(); smp_store_cpu_info(cpuid); callin_flag = 1; __asm__ __volatile__("membar #Sync\n\t" "flush %%g6" : : : "memory"); - while(!task[cpuid]) - barrier(); - current = task[cpuid]; - - while(!smp_commenced) - barrier(); - - __sti(); + while(!smp_processors_ready) + membar("#LoadLoad"); } extern int cpu_idle(void *unused); @@ -130,18 +148,22 @@ void cpu_panic(void) panic("SMP bolixed\n"); } +static void smp_tickoffset_init(void); + extern struct prom_cpuinfo linux_cpus[NR_CPUS]; -extern unsigned long sparc64_cpu_startup; + +extern unsigned long smp_trampoline; void smp_boot_cpus(void) { int cpucount = 0, i; printk("Entering UltraSMPenguin Mode...\n"); + smp_tickoffset_init(); __sti(); cpu_present_map = 0; for(i = 0; i < linux_num_cpus; i++) - cpu_present_map |= (1 << i); + cpu_present_map |= (1UL << i); for(i = 0; i < NR_CPUS; i++) { cpu_number_map[i] = -1; cpu_logical_map[i] = -1; @@ -160,23 +182,24 @@ void smp_boot_cpus(void) if(i == boot_cpu_id) continue; - if(cpu_present_map & (1 << i)) { + if(cpu_present_map & (1UL << i)) { + unsigned long entry = (unsigned long)(&smp_trampoline); struct task_struct *p; int timeout; + entry -= KERNBASE; kernel_thread(start_secondary, NULL, CLONE_PID); p = task[++cpucount]; p->processor = i; + callin_flag = 0; prom_startcpu(linux_cpus[i].prom_node, - ((unsigned long)&sparc64_cpu_startup), - ((unsigned long)p)); + entry, ((unsigned long)p)); for(timeout = 0; timeout < 5000000; timeout++) { - if(cpu_callin_map[i]) + if(callin_flag) break; udelay(100); } - if(cpu_callin_map[i]) { - /* XXX fix this */ + if(callin_flag) { cpu_number_map[i] = i; cpu_logical_map[i] = i; } else { @@ -184,19 +207,19 @@ void smp_boot_cpus(void) printk("Processor %d is stuck.\n", i); } } - if(!(cpu_callin_map[i])) { - cpu_present_map &= ~(1 << i); + if(!callin_flag) { + cpu_present_map &= ~(1UL << i); cpu_number_map[i] = -1; } } if(cpucount == 0) { printk("Error: only one processor found.\n"); - cpu_present_map = (1 << smp_processor_id()); + cpu_present_map = (1UL << smp_processor_id()); } else { unsigned long bogosum = 0; for(i = 0; i < NR_CPUS; i++) { - if(cpu_present_map & (1 << i)) + if(cpu_present_map & (1UL << i)) bogosum += cpu_data[i].udelay_val; } printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", @@ -207,27 +230,39 @@ void smp_boot_cpus(void) smp_num_cpus = cpucount + 1; } smp_processors_ready = 1; + membar("#StoreStore | #StoreLoad"); } -/* XXX deprecated interface... */ +/* We don't even need to do anything, the only generic message pass done + * anymore is to stop all cpus during a panic(). When the user drops to + * the PROM prompt, the firmware will send the other cpu's it's MONDO + * vector anyways, so doing anything special here is pointless. + * + * This whole thing should go away anyways... + */ void smp_message_pass(int target, int msg, unsigned long data, int wait) { - printk("smp_message_pass() called, this is bad, spinning.\n"); - __sti(); - while(1) - barrier(); } +/* #define XCALL_DEBUG */ + static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, int cpu) { - u64 result, target = (cpu_number_map[cpu] << 14) | 0x70; - + u64 result, target = (((unsigned long)linux_cpus[cpu].mid) << 14) | 0x70; + int stuck; + +#ifdef XCALL_DEBUG + printk("CPU[%d]: xcall(data[%016lx:%016lx:%016lx],tgt[%016lx])\n", + smp_processor_id(), data0, data1, data2, target); +#endif +again: __asm__ __volatile__(" wrpr %0, %1, %%pstate wr %%g0, %2, %%asi stxa %3, [0x40] %%asi stxa %4, [0x50] %%asi stxa %5, [0x60] %%asi + membar #Sync stxa %%g0, [%6] %%asi membar #Sync" : /* No outputs */ @@ -235,27 +270,46 @@ static inline void xcall_deliver(u64 data0, u64 data1, u64 data2, u64 pstate, in "r" (data0), "r" (data1), "r" (data2), "r" (target)); /* NOTE: PSTATE_IE is still clear. */ + stuck = 100000; do { __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (result) : "i" (ASI_INTR_DISPATCH_STAT)); + if(result == 0) { + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : : "r" (pstate)); + return; + } + stuck -= 1; + if(stuck == 0) + break; } while(result & 0x1); __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); - if(result & 0x2) - panic("Penguin NACK's master!"); + if(stuck == 0) { +#ifdef XCALL_DEBUG + printk("CPU[%d]: mondo stuckage result[%016lx]\n", + smp_processor_id(), result); +#endif + } else { +#ifdef XCALL_DEBUG + printk("CPU[%d]: Penguin %d NACK's master.\n", smp_processor_id(), cpu); +#endif + udelay(2); + goto again; + } } void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) { if(smp_processors_ready) { - unsigned long mask = (cpu_present_map & ~(1<<smp_processor_id())); + unsigned long mask = (cpu_present_map & ~(1UL<<smp_processor_id())); u64 pstate, data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff)); int i, ncpus = smp_num_cpus; __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); for(i = 0; i < ncpus; i++) { - if(mask & (1 << i)) + if(mask & (1UL << i)) xcall_deliver(data0, data1, data2, pstate, i); } /* NOTE: Caller runs local copy on master. */ @@ -266,7 +320,14 @@ extern unsigned long xcall_flush_tlb_page; extern unsigned long xcall_flush_tlb_mm; extern unsigned long xcall_flush_tlb_range; extern unsigned long xcall_flush_tlb_all; +extern unsigned long xcall_tlbcachesync; extern unsigned long xcall_flush_cache_all; +extern unsigned long xcall_report_regs; + +void smp_report_regs(void) +{ + smp_cross_call(&xcall_report_regs, 0, 0, 0); +} void smp_flush_cache_all(void) { @@ -280,11 +341,33 @@ void smp_flush_tlb_all(void) __flush_tlb_all(); } +static void smp_cross_call_avoidance(struct mm_struct *mm) +{ + spin_lock(&scheduler_lock); + get_new_mmu_context(mm, &tlb_context_cache); + mm->cpu_vm_mask = (1UL << smp_processor_id()); + if(current->tss.current_ds) { + u32 ctx = mm->context & 0x1fff; + + current->tss.ctx = ctx; + spitfire_set_secondary_context(ctx); + __asm__ __volatile__("flush %g6"); + } + spin_unlock(&scheduler_lock); +} + void smp_flush_tlb_mm(struct mm_struct *mm) { u32 ctx = mm->context & 0x1fff; - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); + + if(mm == current->mm && mm->count == 1) { + if(mm->cpu_vm_mask == (1UL << smp_processor_id())) + goto local_flush_and_out; + return smp_cross_call_avoidance(mm); + } + smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); + +local_flush_and_out: __flush_tlb_mm(ctx); } @@ -292,22 +375,101 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { u32 ctx = mm->context & 0x1fff; - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); + + if(mm == current->mm && mm->count == 1) { + if(mm->cpu_vm_mask == (1UL << smp_processor_id())) + goto local_flush_and_out; + return smp_cross_call_avoidance(mm); + } + smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); + +local_flush_and_out: __flush_tlb_range(ctx, start, end); } -void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) { - struct mm_struct *mm = vma->vm_mm; u32 ctx = mm->context & 0x1fff; - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); + if(mm == current->mm && mm->count == 1) { + if(mm->cpu_vm_mask == (1UL << smp_processor_id())) + goto local_flush_and_out; + return smp_cross_call_avoidance(mm); + } +#if 0 /* XXX Disabled until further notice... */ + else if(mm != current->mm && mm->count == 1) { + /* Try to handle two special cases to avoid cross calls + * in common scenerios where we are swapping process + * pages out. + */ + if((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK) + return; /* It's dead, nothing to do. */ + if(mm->cpu_vm_mask == (1UL << smp_processor_id())) + goto local_flush_and_out; + } +#endif + smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); + +local_flush_and_out: __flush_tlb_page(ctx, page); } -static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; +/* CPU capture. */ +#define CAPTURE_DEBUG +extern unsigned long xcall_capture; + +static atomic_t smp_capture_depth = ATOMIC_INIT(0); +static atomic_t smp_capture_registry = ATOMIC_INIT(0); +static unsigned long penguins_are_doing_time = 0; + +void smp_capture(void) +{ + int result = atomic_add_return(1, &smp_capture_depth); + + membar("#StoreStore | #LoadStore"); + if(result == 1) { + int ncpus = smp_num_cpus; + +#ifdef CAPTURE_DEBUG + printk("CPU[%d]: Sending penguins to jail...", smp_processor_id()); +#endif + penguins_are_doing_time = 1; + membar("#StoreStore | #LoadStore"); + atomic_inc(&smp_capture_registry); + smp_cross_call(&xcall_capture, 0, 0, 0); + while(atomic_read(&smp_capture_registry) != ncpus) + membar("#LoadLoad"); +#ifdef CAPTURE_DEBUG + printk("done\n"); +#endif + } +} + +void smp_release(void) +{ + if(atomic_dec_and_test(&smp_capture_depth)) { +#ifdef CAPTURE_DEBUG + printk("CPU[%d]: Giving pardon to imprisoned penguins\n", + smp_processor_id()); +#endif + penguins_are_doing_time = 0; + membar("#StoreStore | #StoreLoad"); + atomic_dec(&smp_capture_registry); + } +} + +/* Imprisoned penguins run with %pil == 15, but PSTATE_IE set, so they + * can service tlb flush xcalls... + */ +void smp_penguin_jailcell(void) +{ + flushw_user(); + atomic_inc(&smp_capture_registry); + membar("#StoreLoad | #StoreStore"); + while(penguins_are_doing_time) + membar("#LoadLoad"); + atomic_dec(&smp_capture_registry); +} static inline void sparc64_do_profile(unsigned long pc) { @@ -317,59 +479,100 @@ static inline void sparc64_do_profile(unsigned long pc) pc -= (unsigned long) &_stext; pc >>= prof_shift; - spin_lock(&ticker_lock); - if(pc < prof_len) - prof_buffer[pc]++; - else - prof_buffer[prof_len - 1]++; - spin_unlock(&ticker_lock); + if(pc >= prof_len) + pc = prof_len - 1; + atomic_inc((atomic_t *)&prof_buffer[pc]); } } -unsigned int prof_multiplier[NR_CPUS]; -unsigned int prof_counter[NR_CPUS]; +static unsigned long real_tick_offset, current_tick_offset; + +#define prof_multiplier(__cpu) cpu_data[(__cpu)].multiplier +#define prof_counter(__cpu) cpu_data[(__cpu)].counter extern void update_one_process(struct task_struct *p, unsigned long ticks, unsigned long user, unsigned long system); void smp_percpu_timer_interrupt(struct pt_regs *regs) { + unsigned long compare, tick; int cpu = smp_processor_id(); int user = user_mode(regs); - /* XXX clear_profile_irq(cpu); */ - if(!user) - sparc64_do_profile(regs->tpc); - if(!--prof_counter[cpu]) { - if(current->pid) { - update_one_process(current, 1, user, !user); - if(--current->counter < 0) { - current->counter = 0; - need_resched = 1; - } - - spin_lock(&ticker_lock); - if(user) { - if(current->priority < DEF_PRIORITY) - kstat.cpu_nice++; - else - kstat.cpu_user++; - } else { - kstat.cpu_system++; + clear_softint((1UL << 0)); + do { + if(!user) + sparc64_do_profile(regs->tpc); + if(!--prof_counter(cpu)) { + if(current->pid) { + unsigned int *inc_me; + + update_one_process(current, 1, user, !user); + if(--current->counter < 0) { + current->counter = 0; + resched_force(); + } + + if(user) { + if(current->priority < DEF_PRIORITY) + inc_me = &kstat.cpu_nice; + else + inc_me = &kstat.cpu_user; + } else { + inc_me = &kstat.cpu_system; + } + atomic_inc((atomic_t *)inc_me); } - spin_unlock(&ticker_lock); + prof_counter(cpu) = prof_multiplier(cpu); } - prof_counter[cpu] = prof_multiplier[cpu]; - } + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "add %0, %2, %0\n\t" + "wr %0, 0x0, %%tick_cmpr\n\t" + "rd %%tick, %1" + : "=&r" (compare), "=r" (tick) + : "r" (current_tick_offset)); + } while (tick >= compare); } static void smp_setup_percpu_timer(void) { - /* XXX implement me */ + int cpu = smp_processor_id(); + + prof_counter(cpu) = prof_multiplier(cpu) = 1; + + __asm__ __volatile__("rd %%tick, %%g1\n\t" + "add %%g1, %0, %%g1\n\t" + "wr %%g1, 0x0, %%tick_cmpr" + : /* no outputs */ + : "r" (current_tick_offset) + : "g1"); +} + +static void smp_tickoffset_init(void) +{ + int node; + + node = linux_cpus[0].prom_node; + real_tick_offset = prom_getint(node, "clock-frequency"); + real_tick_offset = real_tick_offset / HZ; + current_tick_offset = real_tick_offset; } int setup_profiling_timer(unsigned int multiplier) { - /* XXX implement me */ + unsigned long flags; + int i; + + if((!multiplier) || (real_tick_offset / multiplier) < 1000) + return -EINVAL; + + save_and_cli(flags); + for(i = 0; i < NR_CPUS; i++) { + if(cpu_present_map & (1UL << i)) + prof_multiplier(i) = multiplier; + } + current_tick_offset = (real_tick_offset / multiplier); + restore_flags(flags); + return 0; } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 990202bac..c1ceacc3f 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.21 1997/09/03 12:29:07 jj Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> +#include <linux/in6.h> #include <asm/oplib.h> #include <asm/delay.h> @@ -28,11 +29,13 @@ #include <asm/ptrace.h> #include <asm/user.h> #include <asm/uaccess.h> +#include <asm/checksum.h> #ifdef CONFIG_SBUS #include <asm/sbus.h> #include <asm/dma.h> #endif #include <asm/a.out.h> +#include <asm/svr4.h> struct poll { int fd; @@ -45,18 +48,36 @@ extern unsigned long sunos_mmap(unsigned long, unsigned long, unsigned long, void _sigpause_common (unsigned int set, struct pt_regs *); extern void *__bzero_1page(void *); extern void *__bzero(void *, size_t); +extern void *__bzero_noasi(void *, size_t); extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern int __strncmp(const char *, const char *, __kernel_size_t); -extern unsigned int __csum_partial_copy_sparc_generic (const char *, char *); extern char saved_command_line[]; - +extern char *getname32(u32 name); +extern void linux_sparc_syscall(void); +extern void rtrap(void); +extern void show_regs(struct pt_regs *); +extern void solaris_syscall(void); +extern void syscall_trace(void); +extern u32 sunos_sys_table[], sys_call_table32[]; +extern void tl0_solaris(void); +extern void sys_sigsuspend(void); +extern int sys_getppid(void); +extern int svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs); +extern int svr4_setcontext(svr4_ucontext_t *uc, struct pt_regs *regs); +extern int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); +extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg); + extern void bcopy (const char *, char *, int); extern int __ashrdi3(int, int); extern void dump_thread(struct pt_regs *, struct user *); +#ifdef __SMP__ +extern spinlock_t scheduler_lock; +#endif + /* One thing to note is that the way the symbols of the mul/div * support routines are named is a mess, they all start with * a '.' which makes it a bitch to export, here is the trick: @@ -70,7 +91,17 @@ __attribute__((section("__ksymtab"))) = \ /* used by various drivers */ #ifdef __SMP__ +EXPORT_SYMBOL(scheduler_lock); +EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(klock_info); +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(synchronize_irq); +EXPORT_SYMBOL(cpu_data); +EXPORT_SYMBOL_PRIVATE(global_cli); +EXPORT_SYMBOL_PRIVATE(global_sti); +EXPORT_SYMBOL_PRIVATE(global_restore_flags); +#else +EXPORT_SYMBOL(local_irq_count); #endif EXPORT_SYMBOL_PRIVATE(_lock_kernel); EXPORT_SYMBOL_PRIVATE(_unlock_kernel); @@ -81,12 +112,13 @@ EXPORT_SYMBOL(mstk48t02_regs); EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); -EXPORT_SYMBOL(local_irq_count); EXPORT_SYMBOL(__sparc64_bh_counter); EXPORT_SYMBOL(sparc_ultra_unmapioaddr); EXPORT_SYMBOL(mmu_get_scsi_sgl); EXPORT_SYMBOL(mmu_get_scsi_one); EXPORT_SYMBOL(sparc_dvma_malloc); +EXPORT_SYMBOL(mmu_release_scsi_one); +EXPORT_SYMBOL(mmu_release_scsi_sgl); #if CONFIG_SBUS EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); @@ -139,6 +171,25 @@ EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strspn); +#ifdef CONFIG_SOLARIS_EMUL_MODULE +EXPORT_SYMBOL(getname32); +EXPORT_SYMBOL(linux_sparc_syscall); +EXPORT_SYMBOL(rtrap); +EXPORT_SYMBOL(show_regs); +EXPORT_SYMBOL(solaris_syscall); +EXPORT_SYMBOL(syscall_trace); +EXPORT_SYMBOL(sunos_sys_table); +EXPORT_SYMBOL(sys_call_table32); +EXPORT_SYMBOL(tl0_solaris); +EXPORT_SYMBOL(sys_sigsuspend); +EXPORT_SYMBOL(sys_getppid); +EXPORT_SYMBOL(svr4_getcontext); +EXPORT_SYMBOL(svr4_setcontext); +EXPORT_SYMBOL(linux_cpus); +EXPORT_SYMBOL(sys_ioctl); +EXPORT_SYMBOL(sys32_ioctl); +#endif + /* Special internal versions of library functions. */ EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memset); @@ -150,12 +201,13 @@ EXPORT_SYMBOL(__memcmp); EXPORT_SYMBOL(__strncmp); EXPORT_SYMBOL(__memmove); -EXPORT_SYMBOL(__csum_partial_copy_sparc_generic); +EXPORT_SYMBOL(csum_partial_copy_sparc64); /* Moving data to/from userspace. */ EXPORT_SYMBOL(__copy_to_user); EXPORT_SYMBOL(__copy_from_user); EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(__bzero_noasi); /* No version information on this, heavily used in inline asm, * and will always be 'void __ret_efault(void)'. diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index ca0faec5d..37c541755 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.2 1997/07/25 01:50:47 ralf Exp $ +/* $Id: sys32.S,v 1.3 1997/08/22 20:11:47 davem Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -73,7 +73,7 @@ sys32_mremap: .globl sys32_readlink, sys32_unlink, sys32_rmdir, sys32_symlink .globl sys32_link, sys32_rename, sys32_truncate, sys32_ftruncate .globl sys32_chroot, sys32_chmod, sys32_chown, sys32_creat - .globl sys32_mkdir, sys32_mknod, sys32_utimes, sys32_ustat + .globl sys32_mkdir, sys32_mknod, sys32_ustat sys32_read: srl %o1, 0, %o1 mov %o7, %g1 @@ -202,12 +202,6 @@ sys32_mknod: srl %o2, 16, %o2 call sys_mknod mov %g1, %o7 -sys32_utimes: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_utimes - mov %g1, %o7 sys32_ustat: srl %o1, 0, %o1 mov %o7, %g1 @@ -285,24 +279,9 @@ sys32_getsockopt: call sys_setsockopt mov %g1, %o7 - .align 32 - .globl sys32_gettimeofday, sys32_settimeofday -sys32_gettimeofday: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_gettimeofday - mov %g1, %o7 -sys32_settimeofday: - srl %o0, 0, %o0 - mov %o7, %g1 - srl %o1, 0, %o1 - call sys_settimeofday - mov %g1, %o7 - .globl sys32_bdflush, sys32_uselib, sys32_umount, sys32_syslog - .globl sys32_personality, sys32_waitpid, sys32_getitimer - .globl sys32_setitimer, sys32_sched_setscheduler + .globl sys32_personality, sys32_waitpid + .globl sys32_sched_setscheduler .globl sys32_sched_setparam, sys32_sched_getparam, sys32_signal .globl sys32_reboot, sys32_acct, sys32_newuname, sys32_olduname .globl sys32_sethostname, sys32_gethostname, sys32_setdomainname @@ -338,17 +317,6 @@ sys32_waitpid: mov %o7, %g1 call sys_waitpid mov %g1, %o7 -sys32_getitimer: - srl %o1, 0, %o1 - mov %o7, %g1 - call sys_getitimer - mov %g1, %o7 -sys32_setitimer: - srl %o1, 0, %o1 - mov %o7, %g1 - srl %o2, 0, %o2 - call sys_setitimer - mov %g1, %o7 sys32_sched_setscheduler: srl %o2, 0, %o2 mov %o7, %g1 diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index c827df7a1..0ec6de167 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.2 1997/07/05 09:52:34 davem Exp $ +/* $Id: sys_sparc.c,v 1.5 1997/09/03 12:29:05 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -191,9 +191,12 @@ out: asmlinkage unsigned long c_sys_nis_syscall (struct pt_regs *regs) { + static int count=0; lock_kernel(); - printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); - show_regs (regs); + if (++count <= 20) { /* Don't make the system unusable, if someone goes stuck */ + printk ("Unimplemented SPARC system call %ld\n",regs->u_regs[1]); + show_regs (regs); + } unlock_kernel(); return -ENOSYS; } @@ -220,46 +223,36 @@ asmlinkage int sparc_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction) { struct sigaction new_sa, *p; - int err = -EINVAL; - lock_kernel(); if(signum < 0) { current->tss.new_signal = 1; signum = -signum; } - if (signum<1 || signum>32) - goto out; + return -EINVAL; p = signum - 1 + current->sig->action; if (action) { - err = -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) - goto out; - err = -EFAULT; + return -EINVAL; if(copy_from_user(&new_sa, action, sizeof(struct sigaction))) - goto out; + return -EFAULT; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { - err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); + int err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) - goto out; + return err; } } - if (oldaction) { - err = -EFAULT; if (copy_to_user(oldaction, p, sizeof(struct sigaction))) - goto out; + return -EFAULT; } - if (action) { + spin_lock_irq(¤t->sig->siglock); *p = new_sa; check_pending(signum); + spin_unlock_irq(¤t->sig->siglock); } - - err = 0; -out: - unlock_kernel(); - return err; + return 0; } /* only AP+ systems have sys_aplib */ @@ -267,3 +260,15 @@ asmlinkage int sys_aplib(void) { return -ENOSYS; } + +asmlinkage int solaris_syscall(struct pt_regs *regs) +{ + lock_kernel(); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + printk ("For Solaris binary emulation you need solaris module loaded\n"); + show_regs (regs); + send_sig(SIGSEGV, current, 1); + unlock_kernel(); + return 0; +} diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index b6ca9448c..e2c199f60 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.44 1997/07/20 09:18:47 davem Exp $ +/* $Id: sys_sparc32.c,v 1.55 1997/09/04 01:54:51 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -44,6 +44,7 @@ #include <asm/ipc.h> #include <asm/uaccess.h> #include <asm/fpumacro.h> +#include <asm/semaphore.h> /* As gcc will warn about casting u32 to some ptr, we have to cast it to * unsigned long first, and that's what is A() for. @@ -53,6 +54,33 @@ */ #define A(x) ((unsigned long)x) +extern char * getname_quicklist; +extern int getname_quickcount; +extern struct semaphore getname_quicklock; +extern int kerneld_msqid; + +/* Tuning: increase locality by reusing same pages again... + * if getname_quicklist becomes too long on low memory machines, either a limit + * should be added or after a number of cycles some pages should + * be released again ... + */ +static inline char * get_page(void) +{ + char * res; + down(&getname_quicklock); + res = getname_quicklist; + if (res) { + getname_quicklist = *(char**)res; + getname_quickcount--; + } + else + res = (char*)__get_free_page(GFP_KERNEL); + up(&getname_quicklock); + return res; +} + +#define putname32 putname + /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. @@ -74,44 +102,67 @@ static inline int do_getname32(u32 filename, char *page) return retval; } -/* This is a single page for faster getname. - * If the page is available when entering getname, use it. - * If the page is not available, call __get_free_page instead. - * This works even though do_getname can block (think about it). - * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996. - * We don't use the common getname/putname from namei.c, so that - * this still works well, as every routine which calls getname32 - * will then call getname, then putname and then putname32. - */ -static unsigned long name_page_cache32 = 0; +char * getname32(u32 filename) +{ + char *tmp, *result; + + result = ERR_PTR(-ENOMEM); + tmp = get_page(); + if (tmp) { + int retval = do_getname32(filename, tmp); -void putname32(char * name) + result = tmp; + if (retval < 0) { + putname32(tmp); + result = ERR_PTR(retval); + } + } + return result; +} + +/* 32-bit timeval and related flotsam. */ + +struct timeval32 { - if (name_page_cache32 == 0) - name_page_cache32 = (unsigned long) name; - else - free_page((unsigned long) name); + int tv_sec, tv_usec; +}; + +struct itimerval32 +{ + struct timeval32 it_interval; + struct timeval32 it_value; +}; + +static inline long get_tv32(struct timeval *o, struct timeval32 *i) +{ + return (!access_ok(VERIFY_READ, tv32, sizeof(*tv32)) || + (__get_user(o->tv_sec, &i->tv_sec) | + __get_user(o->tv_usec, &i->tv_usec))); } -int getname32(u32 filename, char **result) +static inline long put_tv32(struct timeval32 *o, struct timeval *i) { - unsigned long page; - int retval; + return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || + (__put_user(i->tv_sec, &o->tv_sec) | + __put_user(i->tv_usec, &o->tv_usec))); +} - page = name_page_cache32; - name_page_cache32 = 0; - if (!page) { - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - } +static inline long get_it32(struct itimerval *o, struct itimerval32 *i) +{ + return (!access_ok(VERIFY_READ, i32, sizeof(*i32)) || + (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | + __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | + __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | + __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); +} - retval = do_getname32(filename, (char *) page); - if (retval < 0) - putname32( (char *) page ); - else - *result = (char *) page; - return retval; +static inline long put_it32(struct itimerval32 *o, struct itimerval *i) +{ + return (!access_ok(VERIFY_WRITE, i32, sizeof(*i32)) || + (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | + __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | + __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | + __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); } extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on); @@ -266,14 +317,25 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u switch (call) { case MSGSND: { - struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL); + struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL); if (!p) err = -ENOMEM; else { - if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || - __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second)) - err = -EFAULT; - else { + err = 0; + if (first == kerneld_msqid) { + *(int *)p->mtext = 0; + if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || + __copy_from_user(&p->mtext[4], &(((struct msgbuf32 *)A(ptr))->mtext[0]), 4) || + __copy_from_user(&p->mtext[8], &(((struct msgbuf32 *)A(ptr))->mtext[4]), second-4)) + err = -EFAULT; + else + second += 4; + } else { + if (get_user(p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || + __copy_from_user(p->mtext, &(((struct msgbuf32 *)A(ptr))->mtext), second)) + err = -EFAULT; + } + if (!err) { unsigned long old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_msgsnd (first, p, second, third); @@ -287,6 +349,7 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u { struct msgbuf *p; unsigned long old_fs; + long msgtyp = fifth; if (!version) { struct ipc_kludge tmp; @@ -297,20 +360,35 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u if(copy_from_user(&tmp,(struct ipc_kludge *)A(ptr), sizeof (tmp))) goto out; ptr = tmp.msgp; - fifth = tmp.msgtyp; + msgtyp = tmp.msgtyp; } - p = kmalloc (second + sizeof (struct msgbuf), GFP_KERNEL); + + p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_KERNEL); if (!p) { err = -EFAULT; goto out; } + old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_msgrcv (first, p, second, fifth, third); + err = sys_msgrcv (first, p, second + 4, msgtyp, third); set_fs (old_fs); - if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || - __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, second)) - err = -EFAULT; + + if (err < 0) + goto out; + + if (first == kerneld_msqid) { + if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || + __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[0]), &p->mtext[4], 4) || + __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext[4]), &p->mtext[8], err-8)) + err = -EFAULT; + else + err -= 4; + } else { + if (put_user (p->mtype, &(((struct msgbuf32 *)A(ptr))->mtype)) || + __copy_to_user(&(((struct msgbuf32 *)A(ptr))->mtext), p->mtext, err)) + err = -EFAULT; + } kfree (p); goto out; } @@ -472,8 +550,9 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u err = -EINVAL; goto out; } - else - err = -EINVAL; + + err = -EINVAL; + out: unlock_kernel(); return err; @@ -565,8 +644,9 @@ asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr) return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr)); } - err = getname32 (special, &spec); - if (err) return err; + spec = getname32 (special); + err = PTR_ERR(spec); + if (IS_ERR(spec)) return err; old_fs = get_fs (); set_fs (KERNEL_DS); err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr)); @@ -608,8 +688,9 @@ asmlinkage int sys32_statfs(u32 path, u32 buf) unsigned long old_fs = get_fs(); char *pth; - ret = getname32 (path, &pth); - if (!ret) { + pth = getname32 (path); + ret = PTR_ERR(pth); + if (!IS_ERR(pth)) { set_fs (KERNEL_DS); ret = sys_statfs((const char *)pth, &s); set_fs (old_fs); @@ -651,8 +732,9 @@ asmlinkage int sys32_utime(u32 filename, u32 times) if (get_user (t.actime, &(((struct utimbuf32 *)A(times))->actime)) || __get_user (t.modtime, &(((struct utimbuf32 *)A(times))->modtime))) return -EFAULT; - ret = getname32 (filename, &filenam); - if (!ret) { + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { old_fs = get_fs(); set_fs (KERNEL_DS); ret = sys_utime(filenam, &t); @@ -1010,7 +1092,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) lock_kernel (); p = (char *)__get_free_page (GFP_KERNEL); if (!p) - goto out; + goto out_nofree; q = (u32 *)p; Inp = (u32 *)A(inp); @@ -1019,7 +1101,13 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) ret = -EFAULT; - nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long)); + nn = (n + (8 * sizeof(long)) - 1) / (8 * sizeof(long)); + if (inp && verify_area(VERIFY_WRITE, Inp, nn*sizeof(long))) + goto out; + if (outp && verify_area(VERIFY_WRITE, Outp, nn*sizeof(long))) + goto out; + if (exp && verify_area(VERIFY_WRITE, Exp, nn*sizeof(long))) + goto out; for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) { if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1))) goto out; @@ -1033,7 +1121,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) ktvp = NULL; if(tvp) { - if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp))) + if (get_tv32(&kern_tv, (struct timeval32 *)A(tvp))) goto out; ktvp = &kern_tv; } @@ -1048,8 +1136,12 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) ktvp); set_fs (old_fs); - if(tvp && !(current->personality & STICKY_TIMEOUTS)) - copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp)); + if(tvp && !(current->personality & STICKY_TIMEOUTS)) { + if (put_tv32((struct timeval32 *)A(tvp), &kern_tv)) { + ret = -EFAULT; + goto out; + } + } q = (u32 *)p; Inp = (u32 *)A(inp); @@ -1079,6 +1171,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp) } out: free_page ((unsigned long)p); +out_nofree: unlock_kernel(); return ret; } @@ -1111,8 +1204,9 @@ asmlinkage int sys32_newstat(u32 filename, u32 statbuf) char *filenam; unsigned long old_fs = get_fs(); - ret = getname32 (filename, &filenam); - if (!ret) { + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { set_fs (KERNEL_DS); ret = sys_newstat(filenam, &s); set_fs (old_fs); @@ -1132,8 +1226,9 @@ asmlinkage int sys32_newlstat(u32 filename, u32 statbuf) char *filenam; unsigned long old_fs = get_fs(); - ret = getname32 (filename, &filenam); - if (!ret) { + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { set_fs (KERNEL_DS); ret = sys_newlstat(filenam, &s); set_fs (old_fs); @@ -1239,12 +1334,12 @@ static void *do_smb_super_data_conv(void *raw_data) struct smb_mount_data *s = (struct smb_mount_data *)raw_data; struct smb_mount_data32 *s32 = (struct smb_mount_data32 *)raw_data; - s->dir_mode = s32->dir_mode; - s->file_mode = s32->file_mode; - s->gid = s32->gid; - s->uid = s32->uid; - memmove (&s->addr, &s32->addr, (((long)&s->uid) - ((long)&s->addr))); + s->version = s32->version; s->mounted_uid = s32->mounted_uid; + s->uid = s32->uid; + s->gid = s32->gid; + s->file_mode = s32->file_mode; + s->dir_mode = s32->dir_mode; return raw_data; } @@ -1344,8 +1439,8 @@ asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, } struct rusage32 { - struct timeval ru_utime; - struct timeval ru_stime; + struct timeval32 ru_utime; + struct timeval32 ru_stime; s32 ru_maxrss; s32 ru_ixrss; s32 ru_idrss; @@ -1703,7 +1798,7 @@ struct timex32 { s32 constant; s32 precision; s32 tolerance; - struct timeval time; + struct timeval32 time; s32 tick; s32 ppsfreq; s32 jitter; @@ -2110,54 +2205,45 @@ asmlinkage int sparc32_sigaction (int signum, u32 action, u32 oldaction) { struct sigaction32 new_sa, old_sa; struct sigaction *p; - int err = -EINVAL; - lock_kernel(); if(signum < 0) { current->tss.new_signal = 1; signum = -signum; } - if (signum<1 || signum>32) - goto out; + return -EINVAL; p = signum - 1 + current->sig->action; if (action) { - err = -EINVAL; if (signum==SIGKILL || signum==SIGSTOP) - goto out; - err = -EFAULT; + return -EINVAL; if(copy_from_user(&new_sa, A(action), sizeof(struct sigaction32))) - goto out; + return -EFAULT; if (((__sighandler_t)A(new_sa.sa_handler)) != SIG_DFL && ((__sighandler_t)A(new_sa.sa_handler)) != SIG_IGN) { - err = verify_area(VERIFY_READ, (__sighandler_t)A(new_sa.sa_handler), 1); + int err = verify_area(VERIFY_READ, + (__sighandler_t)A(new_sa.sa_handler), 1); if (err) - goto out; + return err; } } - if (oldaction) { - err = -EFAULT; old_sa.sa_handler = (unsigned)(u64)(p->sa_handler); old_sa.sa_mask = (sigset_t32)(p->sa_mask); old_sa.sa_flags = (unsigned)(p->sa_flags); old_sa.sa_restorer = (unsigned)(u64)(p->sa_restorer); if (copy_to_user(A(oldaction), &old_sa, sizeof(struct sigaction32))) - goto out; + return -EFAULT; } - if (action) { + spin_lock_irq(¤t->sig->siglock); p->sa_handler = (__sighandler_t)A(new_sa.sa_handler); p->sa_mask = (sigset_t)(new_sa.sa_mask); p->sa_flags = new_sa.sa_flags; p->sa_restorer = (void (*)(void))A(new_sa.sa_restorer); check_pending(signum); + spin_unlock_irq(¤t->sig->siglock); } - - err = 0; -out: - unlock_kernel(); - return err; + return 0; } /* @@ -2298,7 +2384,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) base = 1; lock_kernel(); - filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]); + filename = getname((char *)A((u32)regs->u_regs[base + UREG_I0])); error = PTR_ERR(filename); if(IS_ERR(filename)) goto out; @@ -2310,6 +2396,7 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if(!error) { fprs_write(0); regs->fprs = 0; + regs->tstate &= ~TSTATE_PEF; } out: unlock_kernel(); @@ -2369,8 +2456,12 @@ asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_si case QM_MODULES: case QM_REFS: case QM_DEPS: - if (name_user && (ret = getname32 (name_user, &usernam))) - return ret; + if (name_user) { + usernam = getname32 (name_user); + ret = PTR_ERR(usernam); + if (IS_ERR(usernam)) + return ret; + } buff = kmalloc (bufsiz, GFP_KERNEL); if (!buff) { if (name_user) putname32 (usernam); @@ -2431,8 +2522,12 @@ qmsym_toshort: if (name_user) putname32 (usernam); return ret; case QM_INFO: - if (name_user && (ret = getname32 (name_user, &usernam))) - return ret; + if (name_user) { + usernam = getname32 (name_user); + ret = PTR_ERR(usernam); + if (IS_ERR(usernam)) + return ret; + } set_fs (KERNEL_DS); ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val); set_fs (old_fs); @@ -2720,9 +2815,7 @@ static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res return 0; } -extern asmlinkage int sys_nfsservctl(int cmd, - struct nfsctl_arg *arg, - union nfsctl_res *resp); +extern asmlinkage int sys_nfsservctl(int cmd, void *arg, void *resp); int asmlinkage sys32_nfsservctl(int cmd, u32 u_argp, u32 u_resp) { @@ -2793,3 +2886,106 @@ done: kfree(kres); return err; } + +/* Translations due to time_t size differences. Which affects all + sorts of things, like timeval and itimerval. */ + +extern struct timezone sys_tz; +extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz); + +asmlinkage int sys32_gettimeofday(u32 tv, u32 tz) +{ + if (tv) { + struct timeval ktv; + do_gettimeofday(&ktv); + if (put_tv32((struct timeval32 *)A(tv), &ktv)) + return -EFAULT; + } + if (tz) { + if (copy_to_user((void*)A(tz), &sys_tz, sizeof(sys_tz))) + return -EFAULT; + } + return 0; +} + +asmlinkage int sys32_settimeofday(u32 tv, u32 tz) +{ + struct timeval ktv; + struct timezone ktz; + + if (tv) { + if (get_tv32(&ktv, (struct timeval32 *)A(tv))) + return -EFAULT; + } + if (tz) { + if (copy_from_user(&ktz, (void*)A(tz), sizeof(ktz))) + return -EFAULT; + } + + return do_sys_settimeofday(tv ? &ktv : NULL, tz ? &ktz : NULL); +} + +extern int do_getitimer(int which, struct itimerval *value); + +asmlinkage int sys32_getitimer(int which, u32 it) +{ + struct itimerval kit; + int error; + + error = do_getitimer(which, &kit); + if (!error && put_it32((struct itimerval32 *)A(it), &kit)) + error = -EFAULT; + + return error; +} + +extern int do_setitimer(int which, struct itimerval *, struct itimerval *); + +asmlinkage int sys32_setitimer(int which, u32 in, u32 out) +{ + struct itimerval kin, kout; + int error; + + if (in) { + if (get_it32(&kin, (struct itimerval32 *)A(in))) + return -EFAULT; + } else + memset(&kin, 0, sizeof(kin)); + + error = do_setitimer(which, &kin, out ? &kout : NULL); + if (error || !out) + return error; + if (put_it32((struct itimerval32 *)A(out), &kout)) + return -EFAULT; + + return 0; + +} + +asmlinkage int sys_utimes(char *, struct timeval *); + +asmlinkage int sys32_utimes(u32 filename, u32 tvs) +{ + char *kfilename; + struct timeval ktvs[2]; + unsigned long old_fs; + int ret; + + kfilename = getname32(filename); + ret = PTR_ERR(kfilename); + if (!IS_ERR(kfilename)) { + if (tvs) { + if (get_tv32(&ktvs[0], (struct timeval32 *)A(tvs)) || + get_tv32(&ktvs[1], 1+(struct timeval32 *)A(tvs))) + return -EFAULT; + } + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_utimes(kfilename, &ktvs[0]); + set_fs(old_fs); + + putname32(kfilename); + } + return ret; +} diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index eda0ff326..9b00175a3 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.21 1997/07/05 07:09:17 davem Exp $ +/* $Id: systbls.S,v 1.24 1997/08/22 20:12:06 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -10,213 +10,214 @@ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu) */ - .data - .align 8 + .text + .align 1024 /* First, the 32-bit Linux native syscall table. */ .globl sys_call_table32 sys_call_table32: -/*0*/ .xword sys_setup, sys_exit, sys_fork, sys32_read, sys32_write -/*5*/ .xword sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link -/*10*/ .xword sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod -/*15*/ .xword sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek -/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .xword sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .xword sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice - .xword sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall -/*40*/ .xword sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil - .xword sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid -/*50*/ .xword sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl - .xword sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve -/*60*/ .xword sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize - .xword sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*70*/ .xword sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect - .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups -/*80*/ .xword sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall - .xword sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall -/*90*/ .xword sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall - .xword sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*100*/ .xword sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall -/*120*/ .xword sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod - .xword sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate -/*130*/ .xword sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall -/*140*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit - .xword sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount -/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall - .xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall -/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents - .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module - .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname -/*190*/ .xword sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock - .xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask -/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir - .xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall -/*210*/ .xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo - .xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex -/*220*/ .xword sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid - .xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall -/*240*/ .xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep -/*250*/ .xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl - .xword sys_aplib, sys_nis_syscall +/*0*/ .word sys_setup, sys_exit, sys_fork, sys32_read, sys32_write +/*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys32_link +/*10*/ .word sys32_unlink, sunos_execv, sys32_chdir, sys_nis_syscall, sys32_mknod +/*15*/ .word sys32_chmod, sys32_chown, sparc32_brk, sys_nis_syscall, sys32_lseek +/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid +/*25*/ .word sys32_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause +/*30*/ .word sys32_utime, sys_stty, sys_gtty, sys32_access, sys_nice + .word sys_ftime, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall +/*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_profil + .word sys_nis_syscall, sys_setgid, sys_getgid, sys32_signal, sys_geteuid +/*50*/ .word sys_getegid, sys32_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl + .word sys32_reboot, sys_nis_syscall, sys32_symlink, sys32_readlink, sys32_execve +/*60*/ .word sys_umask, sys32_chroot, sys32_newfstat, sys_nis_syscall, sys_getpagesize + .word sys32_msync, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*70*/ .word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys32_munmap, sys32_mprotect + .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys32_getgroups +/*80*/ .word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_nis_syscall + .word sys32_swapon, sys32_getitimer, sys_nis_syscall, sys32_sethostname, sys_nis_syscall +/*90*/ .word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall + .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*100*/ .word sys_getpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall +/*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod + .word sys_nis_syscall, sys32_setreuid, sys_setregid, sys32_rename, sys32_truncate +/*130*/ .word sys32_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys32_mkdir, sys32_rmdir, sys_nis_syscall, sys_nis_syscall +/*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit + .word sys32_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys32_statfs, sys32_fstatfs, sys32_umount +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_setdomainname, sys_nis_syscall + .word sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall +/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents + .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_query_module + .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname +/*190*/ .word sys32_init_module, sys32_personality, sys_prof, sys_break, sys_lock + .word sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask +/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir + .word sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall +/*210*/ .word sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo + .word sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex +/*220*/ .word sys32_sigprocmask, sys32_create_module, sys32_delete_module, sys32_get_kernel_syms, sys_getpgid + .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid +/*230*/ .word sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall + .word sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall +/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep +/*250*/ .word sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl + .word sys_aplib /* Now the 64-bit native Linux syscall table. */ + .align 1024 .globl sys_call_table64, sys_call_table sys_call_table64: sys_call_table: -/*0*/ .xword sys_setup, sys_exit, sys_fork, sys_read, sys_write -/*5*/ .xword sys_open, sys_close, sys_wait4, sys_creat, sys_link -/*10*/ .xword sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod -/*15*/ .xword sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek -/*20*/ .xword sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .xword sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause -/*30*/ .xword sys_utime, sys_stty, sys_gtty, sys_access, sys_nice - .xword sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall -/*40*/ .xword sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil - .xword sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid -/*50*/ .xword sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl - .xword sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve -/*60*/ .xword sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize - .xword sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*70*/ .xword sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect - .xword sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups -/*80*/ .xword sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall - .xword sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall -/*90*/ .xword sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall - .xword sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept -/*100*/ .xword sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind - .xword sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*110*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg - .xword sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall -/*120*/ .xword sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod - .xword sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate -/*130*/ .xword sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown - .xword sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall -/*140*/ .xword sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit - .xword sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*150*/ .xword sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount -/*160*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall - .xword sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall -/*170*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents - .xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall -/*180*/ .xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module - .xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname -/*190*/ .xword sys_init_module, sys_personality, sys_prof, sys_break, sys_lock - .xword sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask -/*200*/ .xword sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall - .xword sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall -/*210*/ .xword sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo - .xword sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex -/*220*/ .xword sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid - .xword sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid -/*230*/ .xword sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall - .xword sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall -/*240*/ .xword sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall - .xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep -/*250*/ .xword sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .xword sys_aplib, sys_nis_syscall +/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write +/*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod +/*15*/ .word sys_chmod, sys_chown, sparc_brk, sys_nis_syscall, sys_lseek +/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_pause +/*30*/ .word sys_utime, sys_stty, sys_gtty, sys_access, sys_nice + .word sys_ftime, sys_sync, sys_kill, sys_newstat, sys_nis_syscall +/*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_profil + .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid +/*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl + .word sys_reboot, sys_nis_syscall, sys_symlink, sys_readlink, sys_execve +/*60*/ .word sys_umask, sys_chroot, sys_newfstat, sys_nis_syscall, sys_getpagesize + .word sys_nis_syscall, sys_vfork, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*70*/ .word sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect + .word sys_nis_syscall, sys_vhangup, sys_nis_syscall, sys_nis_syscall, sys_getgroups +/*80*/ .word sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_nis_syscall + .word sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall +/*90*/ .word sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall + .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept +/*100*/ .word sys_getpriority, sys_send, sys_recv, sys_nis_syscall, sys_bind + .word sys_setsockopt, sys_listen, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg + .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall +/*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod + .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate +/*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown + .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall +/*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit + .word sys_setrlimit, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_statfs, sys_fstatfs, sys_umount +/*160*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_setdomainname, sys_nis_syscall + .word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall +/*170*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents + .word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall +/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module + .word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname +/*190*/ .word sys_init_module, sys_personality, sys_prof, sys_break, sys_lock + .word sys_mpx, sys_ulimit, sys_getppid, sparc_sigaction, sys_sgetmask +/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall + .word sys_nis_syscall, sys_nis_syscall, sys_syslog, sys_nis_syscall, sys_nis_syscall +/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo + .word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex +/*220*/ .word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid + .word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid +/*230*/ .word sys_llseek, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall + .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall +/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep +/*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl + .word sys_aplib /* Now the 32-bit SunOS syscall table. */ - .align 8 + .align 1024 .globl sunos_sys_table sunos_sys_table: -/*0*/ .xword sunos_indir, sys_exit, sys_fork - .xword sunos_read, sunos_write, sunos_open - .xword sys_close, sunos_wait4, sys32_creat - .xword sys32_link, sys32_unlink, sunos_execv - .xword sys32_chdir, sunos_nosys, sys32_mknod - .xword sys32_chmod, sys32_chown, sunos_brk - .xword sunos_nosys, sys32_lseek, sunos_getpid - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_getuid, sunos_nosys, sys_ptrace - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sys32_access, sunos_nosys, sunos_nosys - .xword sys_sync, sys_kill, sys32_newstat - .xword sunos_nosys, sys32_newlstat, sys_dup - .xword sys_pipe, sunos_nosys, sys_profil - .xword sunos_nosys, sunos_nosys, sunos_getgid - .xword sunos_nosys, sunos_nosys -/*50*/ .xword sunos_nosys, sys32_acct, sunos_nosys - .xword sunos_mctl, sunos_ioctl, sys32_reboot - .xword sunos_nosys, sys32_symlink, sys32_readlink - .xword sys32_execve, sys_umask, sys32_chroot - .xword sys32_newfstat, sunos_nosys, sys_getpagesize - .xword sys32_msync, sys_vfork, sunos_nosys - .xword sunos_nosys, sunos_sbrk, sunos_sstk - .xword sunos_mmap, sunos_vadvise, sys32_munmap - .xword sys32_mprotect, sunos_madvise, sys_vhangup - .xword sunos_nosys, sunos_mincore, sys32_getgroups - .xword sys32_setgroups, sys_getpgrp, sunos_setpgrp - .xword sys32_setitimer, sunos_nosys, sys32_swapon - .xword sys32_getitimer, sys32_gethostname, sys32_sethostname - .xword sunos_getdtablesize, sys_dup2, sunos_nop - .xword sys32_fcntl, sunos_select, sunos_nop - .xword sys_fsync, sys_setpriority, sys_socket - .xword sys32_connect, sunos_accept -/*100*/ .xword sys_getpriority, sunos_send, sunos_recv - .xword sunos_nosys, sys32_bind, sunos_setsockopt - .xword sys_listen, sunos_nosys, sunos_sigaction - .xword sunos_sigblock, sunos_sigsetmask, sys_sigpause - .xword sys32_sigstack, sys32_recvmsg, sys32_sendmsg - .xword sunos_nosys, sys_gettimeofday, sys32_getrusage - .xword sunos_getsockopt, sunos_nosys, sunos_readv - .xword sunos_writev, sys_settimeofday, sys_fchown - .xword sys_fchmod, sys32_recvfrom, sys32_setreuid - .xword sys_setregid, sys32_rename, sys32_truncate - .xword sys32_ftruncate, sys_flock, sunos_nosys - .xword sys32_sendto, sys_shutdown, sys_socketpair - .xword sys32_mkdir, sys32_rmdir, sys32_utimes - .xword sys_sigreturn, sunos_nosys, sys32_getpeername - .xword sunos_gethostid, sunos_nosys, sys32_getrlimit - .xword sys32_setrlimit, sunos_killpg, sunos_nosys - .xword sunos_nosys, sunos_nosys -/*150*/ .xword sys32_getsockname, sunos_nosys, sunos_nosys - .xword sys32_poll, sunos_nosys, sunos_nosys - .xword sunos_getdirentries, sys32_statfs, sys32_fstatfs - .xword sys32_umount, sunos_nosys, sunos_nosys - .xword sunos_getdomainname, sys32_setdomainname - .xword sunos_nosys, sys32_quotactl, sunos_nosys - .xword sunos_mount, sys32_ustat, sunos_semsys - .xword sunos_nosys, sunos_shmsys, sunos_audit - .xword sunos_nosys, sunos_getdents, sys_setsid - .xword sys_fchdir, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sys32_sigpending, sunos_nosys - .xword sys_setpgid, sunos_pathconf, sunos_fpathconf - .xword sunos_sysconf, sunos_uname, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys -/*200*/ .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys -/*250*/ .xword sunos_nosys, sunos_nosys, sunos_nosys - .xword sunos_nosys, sunos_nosys, sys_aplib +/*0*/ .word sunos_indir, sys_exit, sys_fork + .word sunos_read, sunos_write, sunos_open + .word sys_close, sunos_wait4, sys32_creat + .word sys32_link, sys32_unlink, sunos_execv + .word sys32_chdir, sunos_nosys, sys32_mknod + .word sys32_chmod, sys32_chown, sunos_brk + .word sunos_nosys, sys32_lseek, sunos_getpid + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_getuid, sunos_nosys, sys_ptrace + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sys32_access, sunos_nosys, sunos_nosys + .word sys_sync, sys_kill, sys32_newstat + .word sunos_nosys, sys32_newlstat, sys_dup + .word sys_pipe, sunos_nosys, sys_profil + .word sunos_nosys, sunos_nosys, sunos_getgid + .word sunos_nosys, sunos_nosys +/*50*/ .word sunos_nosys, sys32_acct, sunos_nosys + .word sunos_mctl, sunos_ioctl, sys32_reboot + .word sunos_nosys, sys32_symlink, sys32_readlink + .word sys32_execve, sys_umask, sys32_chroot + .word sys32_newfstat, sunos_nosys, sys_getpagesize + .word sys32_msync, sys_vfork, sunos_nosys + .word sunos_nosys, sunos_sbrk, sunos_sstk + .word sunos_mmap, sunos_vadvise, sys32_munmap + .word sys32_mprotect, sunos_madvise, sys_vhangup + .word sunos_nosys, sunos_mincore, sys32_getgroups + .word sys32_setgroups, sys_getpgrp, sunos_setpgrp + .word sys32_setitimer, sunos_nosys, sys32_swapon + .word sys32_getitimer, sys32_gethostname, sys32_sethostname + .word sunos_getdtablesize, sys_dup2, sunos_nop + .word sys32_fcntl, sunos_select, sunos_nop + .word sys_fsync, sys_setpriority, sys_socket + .word sys32_connect, sunos_accept +/*100*/ .word sys_getpriority, sunos_send, sunos_recv + .word sunos_nosys, sys32_bind, sunos_setsockopt + .word sys_listen, sunos_nosys, sunos_sigaction + .word sunos_sigblock, sunos_sigsetmask, sys_sigpause + .word sys32_sigstack, sys32_recvmsg, sys32_sendmsg + .word sunos_nosys, sys32_gettimeofday, sys32_getrusage + .word sunos_getsockopt, sunos_nosys, sunos_readv + .word sunos_writev, sys32_settimeofday, sys_fchown + .word sys_fchmod, sys32_recvfrom, sys32_setreuid + .word sys_setregid, sys32_rename, sys32_truncate + .word sys32_ftruncate, sys_flock, sunos_nosys + .word sys32_sendto, sys_shutdown, sys_socketpair + .word sys32_mkdir, sys32_rmdir, sys32_utimes + .word sys_sigreturn, sunos_nosys, sys32_getpeername + .word sunos_gethostid, sunos_nosys, sys32_getrlimit + .word sys32_setrlimit, sunos_killpg, sunos_nosys + .word sunos_nosys, sunos_nosys +/*150*/ .word sys32_getsockname, sunos_nosys, sunos_nosys + .word sys32_poll, sunos_nosys, sunos_nosys + .word sunos_getdirentries, sys32_statfs, sys32_fstatfs + .word sys32_umount, sunos_nosys, sunos_nosys + .word sunos_getdomainname, sys32_setdomainname + .word sunos_nosys, sys32_quotactl, sunos_nosys + .word sunos_mount, sys32_ustat, sunos_semsys + .word sunos_nosys, sunos_shmsys, sunos_audit + .word sunos_nosys, sunos_getdents, sys_setsid + .word sys_fchdir, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sys32_sigpending, sunos_nosys + .word sys_setpgid, sunos_pathconf, sunos_fpathconf + .word sunos_sysconf, sunos_uname, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys +/*200*/ .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys +/*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sys_aplib diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index df6a1c05e..8b0152231 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.5 1997/07/23 11:32:06 davem Exp $ +/* $Id: time.c,v 1.12 1997/08/22 20:12:13 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,7 @@ * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) */ +#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -17,12 +18,17 @@ #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/init.h> +#include <linux/ioport.h> #include <asm/oplib.h> #include <asm/mostek.h> #include <asm/timer.h> #include <asm/irq.h> #include <asm/io.h> +#include <asm/sbus.h> +#include <asm/fhc.h> +#include <asm/pbm.h> +#include <asm/ebus.h> struct mostek48t02 *mstk48t02_regs = 0; struct mostek48t08 *mstk48t08_regs = 0; @@ -155,33 +161,55 @@ static int has_low_battery(void) /* Probe for the real time clock chip. */ -__initfunc(static void clock_probe(void)) +__initfunc(static void set_system_time(void)) { - struct linux_prom_registers clk_reg[2]; - char model[128]; - int node, sbusnd, err; - - /* XXX HACK HACK HACK, delete me soon */ - struct linux_prom_ranges XXX_sbus_ranges[PROMREG_MAX]; - int XXX_sbus_nranges; + unsigned int year, mon, day, hour, min, sec; + struct mostek48t02 *mregs; - node = prom_getchild(prom_root_node); - sbusnd = prom_searchsiblings(node, "sbus"); - node = prom_getchild(sbusnd); + do_get_fast_time = do_gettimeofday; - if(node == 0 || node == -1) { - prom_printf("clock_probe: Serious problem can't find sbus PROM node.\n"); + mregs = mstk48t02_regs; + if(!mregs) { + prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); + } + + mregs->creg |= MSTK_CREG_READ; + sec = MSTK_REG_SEC(mregs); + min = MSTK_REG_MIN(mregs); + hour = MSTK_REG_HOUR(mregs); + day = MSTK_REG_DOM(mregs); + mon = MSTK_REG_MONTH(mregs); + year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); + xtime.tv_sec = mktime(year, mon, day, hour, min, sec); + xtime.tv_usec = 0; + mregs->creg &= ~MSTK_CREG_READ; +} + +__initfunc(void clock_probe(void)) +{ + struct linux_prom_registers clk_reg[2]; + char model[128]; + int node, busnd = -1, err; + + if(central_bus != NULL) { + busnd = central_bus->child->prom_node; + } +#ifdef CONFIG_PCI + else if (ebus_chain != NULL) { + busnd = ebus_chain->prom_node; + } +#endif + else { + busnd = SBus_chain->prom_node; } - /* XXX FIX ME */ - err = prom_getproperty(sbusnd, "ranges", (char *) XXX_sbus_ranges, - sizeof(XXX_sbus_ranges)); - if(err == -1) { - prom_printf("clock_probe: Cannot get XXX sbus ranges\n"); + if(busnd == -1) { + prom_printf("clock_probe: problem, cannot find bus to search.\n"); prom_halt(); } - XXX_sbus_nranges = (err / sizeof(struct linux_prom_ranges)); + + node = prom_getchild(busnd); while(1) { prom_getstring(node, "model", model, sizeof(model)); @@ -199,12 +227,48 @@ __initfunc(static void clock_probe(void)) err = prom_getproperty(node, "reg", (char *)clk_reg, sizeof(clk_reg)); if(err == -1) { - prom_printf("clock_probe: Cannot make Mostek\n"); + prom_printf("clock_probe: Cannot get Mostek reg property\n"); prom_halt(); } - /* XXX fix me badly */ - prom_adjust_regs(clk_reg, 1, XXX_sbus_ranges, XXX_sbus_nranges); + if(central_bus) { + prom_apply_fhc_ranges(central_bus->child, clk_reg, 1); + prom_apply_central_ranges(central_bus, clk_reg, 1); + } +#ifdef CONFIG_PCI + else if (ebus_chain) { + struct linux_ebus_device *edev; + + for_each_ebusdev(edev, ebus_chain) + if (edev->prom_node == node) + break; + if (!edev) { + prom_printf("%s: Mostek not probed by EBUS\n", + __FUNCTION__); + prom_halt(); + } + + if (check_region(edev->base_address[0], + sizeof(struct mostek48t59))) { + prom_printf("%s: Can't get region %lx, %d\n", + __FUNCTION__, edev->base_address[0], + sizeof(struct mostek48t59)); + prom_halt(); + } + request_region(edev->base_address[0], + sizeof(struct mostek48t59), "clock"); + + mstk48t59_regs = (struct mostek48t59 *) + edev->base_address[0]; + mstk48t02_regs = &mstk48t59_regs->regs; + break; + } +#endif + else { + prom_adjust_regs(clk_reg, 1, + SBus_chain->sbus_ranges, + SBus_chain->num_sbus_ranges); + } if(model[5] == '0' && model[6] == '2') { mstk48t02_regs = (struct mostek48t02 *) @@ -234,6 +298,8 @@ __initfunc(static void clock_probe(void)) /* Kick start the clock if it is completely stopped. */ if (mstk48t02_regs->sec & MSTK_STOP) kick_start_clock(); + + set_system_time(); } #ifndef BCD_TO_BIN @@ -246,29 +312,10 @@ __initfunc(static void clock_probe(void)) __initfunc(void time_init(void)) { - unsigned int year, mon, day, hour, min, sec; - struct mostek48t02 *mregs; - - do_get_fast_time = do_gettimeofday; - - clock_probe(); - - mregs = mstk48t02_regs; - if(!mregs) { - prom_printf("Something wrong, clock regs not mapped yet.\n"); - prom_halt(); - } - - mregs->creg |= MSTK_CREG_READ; - sec = MSTK_REG_SEC(mregs); - min = MSTK_REG_MIN(mregs); - hour = MSTK_REG_HOUR(mregs); - day = MSTK_REG_DOM(mregs); - mon = MSTK_REG_MONTH(mregs); - year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); - xtime.tv_sec = mktime(year, mon, day, hour, min, sec); - xtime.tv_usec = 0; - mregs->creg &= ~MSTK_CREG_READ; + /* clock_probe() is now done at end of sbus_init on sparc64 + * so that both sbus and fhc bus information is probed and + * available. + */ } extern void init_timers(void (*func)(int, void *, struct pt_regs *)); @@ -301,22 +348,29 @@ void do_gettimeofday(struct timeval *tv) /* Load doubles must be used on xtime so that what we get * is guarenteed to be atomic, this is why we can run this * with interrupts on full blast. Don't touch this... -DaveM + * + * Note with time_t changes to the timeval type, I must now use + * nucleus atomic quad 128-bit loads. */ __asm__ __volatile__(" sethi %hi(linux_timers), %o1 sethi %hi(xtime), %g2 ldx [%o1 + %lo(linux_timers)], %g3 -1: ldd [%g2 + %lo(xtime)], %o4 + or %g2, %lo(xtime), %g2 +1: ldda [%g2] 0x24, %o4 + membar #LoadLoad | #MemIssue ldx [%g3], %o1 - ldd [%g2 + %lo(xtime)], %o2 + membar #LoadLoad | #MemIssue + ldda [%g2] 0x24, %o2 + membar #LoadLoad xor %o4, %o2, %o2 xor %o5, %o3, %o3 orcc %o2, %o3, %g0 - bne,pn %icc, 1b + bne,pn %xcc, 1b cmp %o1, 0 bge,pt %icc, 1f sethi %hi(tick), %o3 - ld [%o3 + %lo(tick)], %o3 + ldx [%o3 + %lo(tick)], %o3 sethi %hi(0x1fffff), %o2 or %o2, %lo(0x1fffff), %o2 add %o5, %o3, %o5 @@ -325,12 +379,12 @@ void do_gettimeofday(struct timeval *tv) sethi %hi(1000000), %o2 or %o2, %lo(1000000), %o2 cmp %o5, %o2 - bl,a,pn %icc, 1f - st %o4, [%o0 + 0x0] + bl,a,pn %xcc, 1f + stx %o4, [%o0 + 0x0] add %o4, 0x1, %o4 sub %o5, %o2, %o5 - st %o4, [%o0 + 0x0] -1: st %o5, [%o0 + 0x4]"); + stx %o4, [%o0 + 0x0] +1: stx %o5, [%o0 + 0x8]"); } void do_settimeofday(struct timeval *tv) diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S new file mode 100644 index 000000000..cefcb6ba3 --- /dev/null +++ b/arch/sparc64/kernel/trampoline.S @@ -0,0 +1,207 @@ +/* $Id: trampoline.S,v 1.2 1997/08/30 04:53:05 ralf Exp $ + * trampoline.S: Jump start slave processors on sparc64. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <asm/head.h> +#include <asm/asi.h> +#include <asm/lsu.h> +#include <asm/pstate.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/spitfire.h> +#include <asm/asm_offsets.h> + + .data + .align 8 + .globl smp_trampoline +smp_trampoline: .skip 0x300 + + .text + .align 8 + .globl sparc64_cpu_startup, sparc64_cpu_startup_end +sparc64_cpu_startup: + flushw + mov (LSU_CONTROL_IC | LSU_CONTROL_DC | LSU_CONTROL_IM | LSU_CONTROL_DM), %g1 + stxa %g1, [%g0] ASI_LSU_CONTROL + membar #Sync + wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate + wrpr %g0, 15, %pil + + sethi %uhi(PAGE_OFFSET), %g4 + sllx %g4, 32, %g4 + + /* XXX Buggy PROM... */ + srl %o0, 0, %g6 + add %g6, %g4, %g6 + + sethi %uhi(_PAGE_VALID | _PAGE_SZ4MB), %g5 + sllx %g5, 32, %g5 + or %g5, (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W | _PAGE_G), %g5 + + sethi %uhi(_PAGE_PADDR), %g3 + or %g3, %ulo(_PAGE_PADDR), %g3 + sllx %g3, 32, %g3 + sethi %hi(_PAGE_PADDR), %g7 + or %g7, %lo(_PAGE_PADDR), %g7 + or %g3, %g7, %g3 + + clr %l0 + set 0x1fff, %l2 + rd %pc, %l3 + andn %l3, %l2, %g2 +1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 + cmp %g1, %g2 + be,a,pn %xcc, 2f + ldxa [%l0] ASI_ITLB_DATA_ACCESS, %g1 + cmp %l0, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + +2: nop + nop + nop + and %g1, %g3, %g1 + sub %g1, %g2, %g1 + or %g5, %g1, %g5 + clr %l0 + sethi %hi(KERNBASE), %g3 + sethi %hi(KERNBASE<<1), %g7 + mov TLB_TAG_ACCESS, %l7 +1: ldxa [%l0] ASI_ITLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_IMMU + stxa %g0, [%l0] ASI_ITLB_DATA_ACCESS +2: cmp %l0, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + nop + nop + nop + clr %l0 +1: ldxa [%l0] ASI_DTLB_TAG_READ, %g1 + nop + nop + nop + andn %g1, %l2, %g1 + cmp %g1, %g3 + blu,pn %xcc, 2f + cmp %g1, %g7 + bgeu,pn %xcc, 2f + nop + stxa %g0, [%l7] ASI_DMMU + stxa %g0, [%l0] ASI_DTLB_DATA_ACCESS +2: cmp %l0, (63 << 3) + blu,pt %xcc, 1b + add %l0, (1 << 3), %l0 + + nop + nop + nop + sethi %hi(KERNBASE), %g3 + mov (63 << 3), %g7 + stxa %g3, [%l7] ASI_DMMU + stxa %g5, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + stxa %g3, [%l7] ASI_IMMU + stxa %g5, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + flush %g3 + membar #Sync + b,pt %xcc, 1f + nop +1: set bounce, %g2 + jmpl %g2 + %g0, %g0 + nop + +bounce: + mov PRIMARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + mov SECONDARY_CONTEXT, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + + mov TLB_TAG_ACCESS, %g2 + stxa %g3, [%g2] ASI_IMMU + stxa %g3, [%g2] ASI_DMMU + + mov (63 << 3), %g7 + ldxa [%g7] ASI_ITLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_ITLB_DATA_ACCESS + membar #Sync + + ldxa [%g7] ASI_DTLB_DATA_ACCESS, %g1 + andn %g1, (_PAGE_G), %g1 + stxa %g1, [%g7] ASI_DTLB_DATA_ACCESS + membar #Sync + + flush %g3 + membar #Sync + + mov 1, %g5 + sllx %g5, (PAGE_SHIFT + 1), %g5 + sub %g5, (REGWIN_SZ + STACK_BIAS), %g5 + add %g6, %g5, %sp + mov 0, %fp + + wrpr %g0, 0, %wstate + wrpr %g0, 0, %tl + + /* Setup the trap globals, then we can resurface. */ + rdpr %pstate, %o1 + mov %g6, %o2 + wrpr %o1, (PSTATE_AG | PSTATE_IE), %pstate + sethi %hi(sparc64_ttable_tl0), %g5 + wrpr %g5, %tba + mov %o2, %g6 + + wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate + sethi %hi(0x1ff8), %g2 + or %g2, %lo(0x1ff8), %g2 + ldx [%o2 + AOFF_task_mm], %g6 + ldx [%g6 + AOFF_mm_pgd], %g6 + clr %g7 + + wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate + sethi %hi(ivector_to_mask), %g5 + or %g5, %lo(ivector_to_mask), %g1 + mov 0x40, %g2 + + wrpr %g0, 0, %wstate + wrpr %o1, PSTATE_IE, %pstate + + mov TSB_REG, %o4 + mov 1, %o5 + stxa %o5, [%o4] ASI_DMMU + stxa %o5, [%o4] ASI_IMMU + membar #Sync + + or %o1, PSTATE_IE, %o1 + wrpr %o1, 0, %pstate + + call smp_callin + nop + call cpu_idle + mov 0, %o0 + call cpu_panic + nop +1: b,a,pt %xcc, 1b + + .align 8 +sparc64_cpu_startup_end: diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index ac3e79958..1ffd43730 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.29 1997/07/05 09:52:38 davem Exp $ +/* $Id: traps.c,v 1.31 1997/08/11 14:35:33 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -25,6 +25,7 @@ #include <asm/unistd.h> #include <asm/uaccess.h> #include <asm/fpumacro.h> +#include <asm/lsu.h> /* #define SYSCALL_TRACING */ /* #define VERBOSE_SYSCALL_TRACING */ @@ -194,8 +195,55 @@ void data_access_exception (struct pt_regs *regs) send_sig(SIGSEGV, current, 1); } +#ifdef CONFIG_PCI +/* This is really pathetic... */ +/* #define DEBUG_PCI_POKES */ +extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_faulted; +#endif + void do_dae(struct pt_regs *regs) { +#ifdef CONFIG_PCI +#ifdef DEBUG_PCI_POKES + prom_printf(" (POKE "); +#endif + if(pci_poke_in_progress) { + unsigned long va; +#ifdef DEBUG_PCI_POKES + prom_printf("tpc[%016lx] tnpc[%016lx] ", + regs->tpc, regs->tnpc); +#endif + pci_poke_faulted = 1; + regs->tnpc = regs->tpc + 4; + + +#ifdef DEBUG_PCI_POKES + prom_printf("PCI) "); + /* prom_halt(); */ +#endif + /* Re-enable I/D caches, Ultra turned them off. */ + for(va = 0; va < (PAGE_SIZE << 1); va += 32) { + spitfire_put_icache_tag(va, 0x0); + spitfire_put_dcache_tag(va, 0x0); + } + __asm__ __volatile__("flush %%g6\n\t" + "membar #Sync\n\t" + "stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (LSU_CONTROL_IC | LSU_CONTROL_DC | + LSU_CONTROL_IM | LSU_CONTROL_DM), + "i" (ASI_LSU_CONTROL) + : "memory"); + return; + } +#ifdef DEBUG_PCI_POKES + prom_printf("USER) "); + prom_printf("tpc[%016lx] tnpc[%016lx]\n"); + prom_halt(); +#endif +#endif send_sig(SIGSEGV, current, 1); } @@ -215,11 +263,9 @@ void do_fpe_common(struct pt_regs *regs) regs->tpc = regs->tnpc; regs->tnpc += 4; } else { - lock_kernel(); current->tss.sig_address = regs->tpc; current->tss.sig_desc = SUBSIG_FPERROR; send_sig(SIGFPE, current, 1); - unlock_kernel(); } } @@ -288,6 +334,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) } printk("Instruction DUMP:"); instruction_dump ((unsigned int *) regs->tpc); + lock_kernel(); /* Or else! */ if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); @@ -298,13 +345,11 @@ void do_illegal_instruction(struct pt_regs *regs) unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; - lock_kernel(); if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); - unlock_kernel(); } void mem_address_unaligned(struct pt_regs *regs) @@ -333,19 +378,16 @@ void do_privact(struct pt_regs *regs) current->tss.sig_address = regs->tpc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); - unlock_kernel(); } void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long tstate) { - lock_kernel(); if(tstate & TSTATE_PRIV) die_if_kernel("Penguin instruction from Penguin mode??!?!", regs); current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); - unlock_kernel(); } /* XXX User may want to be allowed to do this. XXX */ @@ -353,7 +395,6 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long tstate) { - lock_kernel(); if(regs->tstate & TSTATE_PRIV) { printk("KERNEL MNA at pc %016lx npc %016lx called by %016lx\n", pc, npc, regs->u_regs[UREG_RETPC]); @@ -363,15 +404,12 @@ void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned lon current->tss.sig_address = pc; current->tss.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); - unlock_kernel(); } void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc, unsigned long psr) { - lock_kernel(); send_sig(SIGILL, current, 1); - unlock_kernel(); } /* Trap level 1 stuff or other traps we should never see... */ diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 73bda96d9..bf00cb231 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.18 1997/07/05 09:52:41 davem Exp $ +/* $Id: ttable.S,v 1.20 1997/08/29 15:51:39 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -44,7 +44,8 @@ tl0_irq5: TRAP_IRQ(handler_irq, 5) TRAP_IRQ(handler_irq, 6) tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12) -tl0_irq13: TRAP_IRQ(handler_irq, 13) TRAP_IRQ(handler_irq, 14) +tl0_irq13: TRAP_IRQ(handler_irq, 13) +tl0_itick: TRAP_TICK tl0_irq15: TRAP_IRQ(handler_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) @@ -99,6 +100,7 @@ tl0_bkpt: BREAKPOINT_TRAP tl0_resv102: BTRAP(0x102) tl0_flushw: FLUSH_WINDOW_TRAP tl0_resv104: BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107) + .globl tl0_solaris tl0_solaris: SOLARIS_SYSCALL_TRAP tl0_netbsd: NETBSD_SYSCALL_TRAP tl0_resv10a: BTRAP(0x10a) BTRAP(0x10b) BTRAP(0x10c) BTRAP(0x10d) BTRAP(0x10e) diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index f66889195..3aea13953 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.1 1997/07/18 06:26:45 ralf Exp $ +/* $Id: unaligned.c,v 1.4 1997/08/19 15:25:11 jj Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -205,19 +205,19 @@ __asm__ __volatile__ ( \ "stx %%g7, [%0 + 8]\n" \ "0:\n\n\t" \ ".section __ex_table\n\t" \ - ".xword 4b, " #errh "\n\t" \ - ".xword 5b, " #errh "\n\t" \ - ".xword 6b, " #errh "\n\t" \ - ".xword 7b, " #errh "\n\t" \ - ".xword 8b, " #errh "\n\t" \ - ".xword 9b, " #errh "\n\t" \ - ".xword 10b, " #errh "\n\t" \ - ".xword 11b, " #errh "\n\t" \ - ".xword 12b, " #errh "\n\t" \ - ".xword 13b, " #errh "\n\t" \ - ".xword 14b, " #errh "\n\t" \ - ".xword 15b, " #errh "\n\t" \ - ".xword 16b, " #errh "\n\n\t" \ + ".word 4b, " #errh "\n\t" \ + ".word 5b, " #errh "\n\t" \ + ".word 6b, " #errh "\n\t" \ + ".word 7b, " #errh "\n\t" \ + ".word 8b, " #errh "\n\t" \ + ".word 9b, " #errh "\n\t" \ + ".word 10b, " #errh "\n\t" \ + ".word 11b, " #errh "\n\t" \ + ".word 12b, " #errh "\n\t" \ + ".word 13b, " #errh "\n\t" \ + ".word 14b, " #errh "\n\t" \ + ".word 15b, " #errh "\n\t" \ + ".word 16b, " #errh "\n\n\t" \ ".previous\n\t" \ : : "r" (dest_reg), "r" (size), "r" (saddr), "r" (is_signed), "r" (asi) \ : "l1", "l2", "g7", "g1", "cc"); \ @@ -259,20 +259,20 @@ __asm__ __volatile__ ( \ "17:\t" "stba %%l1, [%0 + 1] %%asi\n" \ "0:\n\n\t" \ ".section __ex_table\n\t" \ - ".xword 4b, " #errh "\n\t" \ - ".xword 5b, " #errh "\n\t" \ - ".xword 6b, " #errh "\n\t" \ - ".xword 7b, " #errh "\n\t" \ - ".xword 8b, " #errh "\n\t" \ - ".xword 9b, " #errh "\n\t" \ - ".xword 10b, " #errh "\n\t" \ - ".xword 11b, " #errh "\n\t" \ - ".xword 12b, " #errh "\n\t" \ - ".xword 13b, " #errh "\n\t" \ - ".xword 14b, " #errh "\n\t" \ - ".xword 15b, " #errh "\n\t" \ - ".xword 16b, " #errh "\n\t" \ - ".xword 17b, " #errh "\n\n\t" \ + ".word 4b, " #errh "\n\t" \ + ".word 5b, " #errh "\n\t" \ + ".word 6b, " #errh "\n\t" \ + ".word 7b, " #errh "\n\t" \ + ".word 8b, " #errh "\n\t" \ + ".word 9b, " #errh "\n\t" \ + ".word 10b, " #errh "\n\t" \ + ".word 11b, " #errh "\n\t" \ + ".word 12b, " #errh "\n\t" \ + ".word 13b, " #errh "\n\t" \ + ".word 14b, " #errh "\n\t" \ + ".word 15b, " #errh "\n\t" \ + ".word 16b, " #errh "\n\t" \ + ".word 17b, " #errh "\n\n\t" \ ".previous\n\t" \ : : "r" (dst_addr), "r" (size), "r" (src_val), "r" (asi) \ : "l1", "l2", "g7", "g1", "cc"); \ diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index f2c714eae..0ebf92767 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $ +/* $Id: winfixup.S,v 1.19 1997/08/08 08:33:37 jj Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -143,8 +143,9 @@ spill_fixup: retry window_scheisse_from_user_common: wrpr %g1, %cwp + sethi %hi(109f), %g7 ba,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 window_scheisse_merge: srlx %l5, PAGE_SHIFT, %o1 @@ -244,8 +245,9 @@ spill_fixup_mna: retry window_mna_from_user_common: wrpr %g1, %cwp + sethi %hi(109f), %g7 ba,pt %xcc, etrap - rd %pc, %g7 +109: or %g7, %lo(109b), %g7 window_mna_merge: call mem_address_unaligned add %sp, STACK_BIAS + REGWIN_SZ, %o0 diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index 3da21c606..9f8729ee5 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -1,12 +1,12 @@ -# $Id: Makefile,v 1.13 1997/07/16 10:12:03 jj Exp $ +# $Id: Makefile,v 1.15 1997/08/19 03:11:50 davem Exp $ # Makefile for Sparc library files.. # -CFLAGS := $(CFLAGS) -ansi +CFLAGS := $(CFLAGS) -OBJS = blockops.o locks.o strlen.o strncmp.o \ +OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o + VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c new file mode 100644 index 000000000..6677f581a --- /dev/null +++ b/arch/sparc64/lib/PeeCeeI.c @@ -0,0 +1,225 @@ +/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $ + * PeeCeeI.c: The emerging standard... + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#include <linux/config.h> + +#ifdef CONFIG_PCI + +#include <asm/io.h> + +void outsb(unsigned long addr, const void *src, unsigned long count) +{ + const u8 *p = src; + + while(count--) + outb(*p++, addr); +} + +void outsw(unsigned long addr, const void *src, unsigned long count) +{ + if(count) { + const u16 *ps = src; + const u32 *pi; + + if(((u64)src) & 0x2) { + outw(*ps++, addr); + count--; + } + pi = (const u32 *)ps; + while(count >= 2) { + u32 w; + + w = *pi++; + outw(w >> 16, addr); + outw(w, addr); + count -= 2; + } + ps = (const u16 *)pi; + if(count) + outw(*ps, addr); + } +} + +void outsl(unsigned long addr, const void *src, unsigned long count) +{ + if(count) { + if((((u64)src) & 0x3) == 0) { + const u32 *p = src; + while(count--) + outl(*p++, addr); + } else { + const u8 *pb; + const u16 *ps = src; + u32 l = 0, l2; + const u32 *pi; + + switch(((u64)src) & 0x3) { + case 0x2: + count -= 1; + l = *ps++; + pi = (const u32 *)ps; + while(count--) { + l2 = *pi++; + outl(((l <<16) | (l2 >> 16)), addr); + l = l2; + } + ps = (const u16 *)pi; + outl(((l << 16) | (*ps >> 16)), addr); + break; + + case 0x1: + count -= 1; + pb = src; + l = (*pb++ << 16); + ps = (const u16 *)pb; + l |= *ps++; + pi = (const u32 *)ps; + while(count--) { + l2 = *pi++; + outl(((l << 8) | (l2 >> 24)), addr); + l = l2; + } + pb = (const u8 *)pi; + outl(((l << 8) | (*pb >> 24)), addr); + break; + + case 0x3: + count -= 1; + pb = src; + l = (*pb++ >> 24); + pi = (const u32 *)pb; + while(count--) { + l2 = *pi++; + outl(((l << 24) | (l2 >> 8)), addr); + l = l2; + } + ps = (const u16 *)pi; + l2 = (*ps++ << 16); + pb = (const u8 *)ps; + l2 |= (*pb << 8); + outl(((l << 24) | (l2 >> 8)), addr); + break; + } + } + } +} + +void insb(unsigned long addr, void *dst, unsigned long count) +{ + if(count) { + u32 *pi; + u8 *pb = dst; + + while((((unsigned long)pb) & 0x3) && count--) + *pb++ = inb(addr); + pi = (u32 *)pb; + while(count >= 4) { + u32 w; + + w = (inb(addr) << 24); + w |= (inb(addr) << 16); + w |= (inb(addr) << 8); + w |= inb(addr); + *pi++ = w; + count -= 4; + } + pb = (u8 *)pi; + while(count--) + *pb++ = inb(addr); + } +} + +void insw(unsigned long addr, void *dst, unsigned long count) +{ + if(count) { + u16 *ps = dst; + u32 *pi; + + if(((unsigned long)ps) & 0x2) { + *ps++ = inw(addr); + count--; + } + pi = (u32 *)ps; + while(count >= 2) { + u32 w; + + w = (inw(addr) << 16); + w |= inw(addr); + *pi++ = w; + count -= 2; + } + ps = (u16 *)pi; + if(count) + *ps = inw(addr); + } +} + +void insl(unsigned long addr, void *dst, unsigned long count) +{ + if(count) { + if((((unsigned long)dst) & 0x3) == 0) { + u32 *pi = dst; + while(count--) + *pi++ = inl(addr); + } else { + u32 l = 0, l2, *pi; + u16 *ps; + u8 *pb; + + switch(((unsigned long)dst) & 3) { + case 0x2: + ps = dst; + count -= 1; + l = inl(addr); + *ps++ = (l >> 16); + pi = (u32 *)ps; + while(count--) { + l2 = inl(addr); + *pi++ = (l << 16) | (l2 >> 16); + l = l2; + } + ps = (u16 *)pi; + *ps = (l << 16); + break; + + case 0x1: + pb = dst; + count -= 1; + *pb++ = (l >> 24); + ps = (u16 *)pb; + *ps++ = (l >> 8); + pi = (u32 *)ps; + while(count--) { + l2 = inl(addr); + *pi++ = ((l << 24) | (l2 >> 8)); + l = l2; + } + pb = (u8 *)pi; + *pb = (l >> 8); + break; + + case 0x3: + pb = (u8 *)dst; + count -= 1; + l = inl(addr); + *pb++ = l >> 24; + pi = (u32 *)pb; + while(count--) { + l2 = inl(addr); + *pi++ = ((l >> 24) | (l2 << 8)); + l = l2; + } + ps = (u16 *)pi; + *ps++ = l >> 8; + pb = (u8 *)ps; + *pb = l; + break; + } + } + } +} + +#endif /* CONFIG_PCI */ diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S index 3c86861fd..ede87843b 100644 --- a/arch/sparc64/lib/VISbzero.S +++ b/arch/sparc64/lib/VISbzero.S @@ -1,4 +1,4 @@ -/* $Id: VISbzero.S,v 1.1 1997/07/18 06:26:48 ralf Exp $ +/* $Id: VISbzero.S,v 1.8 1997/08/22 15:54:50 jj Exp $ * VISbzero.S: High speed clear operations utilizing the UltraSparc * Visual Instruction Set. * @@ -16,8 +16,8 @@ 99: ba VISbzerofixup_ret##z; \ a, b, %o0; \ .section __ex_table; \ - .align 8; \ - .xword 98b, 99b; \ + .align 4; \ + .word 98b, 99b; \ .text; \ .align 4; #define EXC(x,y,a,b,c...) \ @@ -28,15 +28,15 @@ ba VISbzerofixup_ret0; \ a, b, %o0; \ .section __ex_table; \ - .align 8; \ - .xword 98b, 99b; \ + .align 4; \ + .word 98b, 99b; \ .text; \ .align 4; #define EXO1(x,y) \ 98: x,y; \ .section __ex_table; \ - .align 8; \ - .xword 98b, VISbzerofixup_reto1; \ + .align 4; \ + .word 98b, VISbzerofixup_reto1; \ .text; \ .align 4; #define EX(x,y,a,b) EXN(x,y,a,b,0) @@ -44,8 +44,8 @@ #define EX2(x,y,a,b) EXN(x,y,a,b,2) #define EXT(start,end,handler) \ .section __ex_table; \ - .align 8; \ - .xword start, 0, end, handler; \ + .align 4; \ + .word start, 0, end, handler; \ .text; \ .align 4 #else @@ -147,7 +147,7 @@ bzero: #else wr %g0, ASI_BLK_P, %asi #endif - membar #StoreStore | #LoadStore + membar #StoreLoad | #StoreStore | #LoadStore fzero %f0 andcc %o3, 0xc0, %o2 and %o1, 0x3f, %o1 @@ -180,16 +180,28 @@ bzero: #ifdef __KERNEL__ wr %g0, 0, %fprs wr %g7, 0x0, %asi +#else +#ifndef REGS_64BIT + wr %g0, FPRS_FEF, %fprs #endif - membar #Sync +#endif + membar #StoreLoad | #StoreStore 9: andcc %o1, 0xf8, %o2 be,pn %xcc, 13f andcc %o1, 7, %o1 +#ifdef __KERNEL__ +14: sethi %hi(13f), %o4 + srl %o2, 1, %o3 + sub %o4, %o3, %o4 + jmpl %o4 + %lo(13f), %g0 + add %o0, %o2, %o0 +#else 14: rd %pc, %o4 srl %o2, 1, %o3 sub %o4, %o3, %o4 jmpl %o4 + (13f - 14b), %g0 add %o0, %o2, %o0 +#endif 12: ZERO_BLOCKS(%o0, 0xc8, %g0) ZERO_BLOCKS(%o0, 0x88, %g0) ZERO_BLOCKS(%o0, 0x48, %g0) diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index 1429f1658..40b781e73 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.1 1997/07/18 06:26:48 ralf Exp $ +/* $Id: VIScopy.S,v 1.14 1997/08/22 15:54:53 jj Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -42,8 +42,8 @@ 99: ba VIScopyfixup_ret; \ a, b, %o0; \ .section __ex_table; \ - .align 8; \ - .xword 98b, 99b; \ + .align 4; \ + .word 98b, 99b; \ .text; \ .align 4; #define EX2(x,y,c,d,e,a,b) \ @@ -54,37 +54,48 @@ ba VIScopyfixup_ret; \ a, b, %o0; \ .section __ex_table; \ - .align 8; \ - .xword 98b, 99b; \ + .align 4; \ + .word 98b, 99b; \ .text; \ .align 4; #define EXO2(x,y) \ 98: x,y; \ .section __ex_table; \ - .align 8; \ - .xword 98b, VIScopyfixup_reto2; \ + .align 4; \ + .word 98b, VIScopyfixup_reto2; \ .text; \ .align 4; #define EXVISN(x,y,n) \ 98: x,y; \ .section __ex_table; \ - .align 8; \ - .xword 98b, VIScopyfixup_vis##n; \ + .align 4; \ + .word 98b, VIScopyfixup_vis##n; \ .text; \ .align 4; #define EXT(start,end,handler) \ .section __ex_table; \ - .align 8; \ - .xword start, 0, end, handler; \ + .align 4; \ + .word start, 0, end, handler; \ .text; \ .align 4; #else -#define FPU_CLEAN_RETL \ - retl; \ +#ifdef REGS_64BIT +#define FPU_CLEAN_RETL \ + retl; \ mov %g6, %o0; -#define FPU_RETL \ - retl; \ +#define FPU_RETL \ + retl; \ mov %g6, %o0; +#else +#define FPU_CLEAN_RETL \ + wr %g0, FPRS_FEF, %fprs; \ + retl; \ + mov %g6, %o0; +#define FPU_RETL \ + wr %g0, FPRS_FEF, %fprs; \ + retl; \ + mov %g6, %o0; +#endif #define NORMAL_RETL \ retl; \ mov %g6, %o0; @@ -113,8 +124,8 @@ #define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \ EXVIS(LDBLK [%src] ASIBLK, %fdest); \ - add %src, 0x40, %src; \ ASI_SETDST_BLK \ + add %src, 0x40, %src; \ add %dest, 0x40, %dest; \ subcc %len, 0x40, %len; \ be,pn %xcc, jmptgt; \ @@ -303,7 +314,7 @@ copy_page: wr %g0, FPRS_FEF, %fprs ! FPU Group sethi %hi(8192), %o2 ! IEU0 Group mov ASI_BLK_P, asi_src ! IEU1 b,pt %xcc, dest_is_64byte_aligned ! CTI - mov ASI_BLK_COMMIT_P, asi_dest ! IEU0 Group + mov ASI_BLK_P, asi_dest ! IEU0 Group .align 32 .globl __copy_from_user @@ -446,6 +457,13 @@ dest_is_64byte_aligned: EXVIS1(LDBLK [%o1 + 0x40] ASIBLK, %f16) ! LSU Group sub %g7, 0x80, %g7 ! IEU0 EXVIS(LDBLK [%o1 + 0x80] ASIBLK, %f32) ! LSU Group +#ifdef __KERNEL__ +vispc: sll %g2, 9, %g2 ! IEU0 Group + sethi %hi(vis00), %g5 ! IEU1 + or %g5, %lo(vis00), %g5 ! IEU0 Group + jmpl %g5 + %g2, %g0 ! CTI Group brk forced + addcc %o1, 0xc0, %o1 ! IEU1 Group +#else ! Clk1 Group 8-( ! Clk2 Group 8-( ! Clk3 Group 8-( @@ -455,6 +473,7 @@ vispc: rd %pc, %g5 ! PDU Group 8-( sll %g2, 9, %g2 ! IEU0 jmpl %g5 + %g2, %g0 ! CTI Group brk forced addcc %o1, 0xc0, %o1 ! IEU1 Group +#endif .align 512 /* OK, here comes the fun part... */ vis00:FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16) LOOP_CHUNK1(o1, o0, g7, vis01) FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32) LOOP_CHUNK2(o1, o0, g7, vis02) @@ -721,20 +740,21 @@ __memcpy_16plus: 3: andcc %o2, 0x70, %g7 ! IEU1 Group 41: be,pn %xcc, 80f ! CTI andcc %o2, 8, %g0 ! IEU1 Group - ! Clk1 8-( - ! Clk2 8-( - ! Clk3 8-( - ! Clk4 8-( -79: rd %pc, %o5 ! PDU Group #ifdef __KERNEL__ +79: sethi %hi(80f), %o5 ! IEU0 sll %g7, 1, %g5 ! IEU0 Group add %o1, %g7, %o1 ! IEU1 srl %g7, 1, %g2 ! IEU0 Group sub %o5, %g5, %o5 ! IEU1 sub %o5, %g2, %o5 ! IEU0 Group - jmpl %o5 + %lo(80f - 79b), %g0 ! CTI Group brk forced + jmpl %o5 + %lo(80f), %g0 ! CTI Group brk forced add %o0, %g7, %o0 ! IEU0 Group #else + ! Clk1 8-( + ! Clk2 8-( + ! Clk3 8-( + ! Clk4 8-( +79: rd %pc, %o5 ! PDU Group sll %g7, 1, %g5 ! IEU0 Group add %o1, %g7, %o1 ! IEU1 sub %o5, %g5, %o5 ! IEU0 Group @@ -814,19 +834,20 @@ normal_retl: andcc %o2, 0x70, %g7 ! IEU1 be,pn %xcc, 84f ! CTI andcc %o2, 8, %g0 ! IEU1 Group +#ifdef __KERNEL__ +83: srl %g7, 1, %g5 ! IEU0 + sethi %hi(84f), %o5 ! IEU0 Group + add %g7, %g5, %g5 ! IEU1 + add %o1, %g7, %o1 ! IEU0 Group + sub %o5, %g5, %o5 ! IEU1 + jmpl %o5 + %lo(84f), %g0 ! CTI Group brk forced + add %o0, %g7, %o0 ! IEU0 Group +#else ! Clk1 8-( ! Clk2 8-( ! Clk3 8-( ! Clk4 8-( 83: rd %pc, %o5 ! PDU Group -#ifdef __KERNEL__ - srl %g7, 1, %g5 ! IEU0 Group - add %g7, %g5, %g5 ! IEU0 Group - add %o1, %g7, %o1 ! IEU1 - sub %o5, %g5, %o5 ! IEU0 Group - jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced - add %o0, %g7, %o0 ! IEU0 Group -#else add %o1, %g7, %o1 ! IEU0 Group sub %o5, %g7, %o5 ! IEU1 jmpl %o5 + %lo(84f - 83b), %g0 ! CTI Group brk forced diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S index 1ccb98759..81b020c49 100644 --- a/arch/sparc64/lib/VIScsum.S +++ b/arch/sparc64/lib/VIScsum.S @@ -1,4 +1,4 @@ -/* $Id: VIScsum.S,v 1.1 1997/07/18 06:26:49 ralf Exp $ +/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc * Visual Instruction Set. * @@ -345,11 +345,19 @@ csum_partial: 20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ be,pn %icc, 23f /* CTI */ and %o1, 0xf, %o3 /* IEU0 */ -22: rd %pc, %g7 /* LSU Group */ +#ifdef __KERNEL__ +22: sll %g1, 1, %o4 /* IEU0 Group */ + sethi %hi(23f), %g7 /* IEU1 */ + sub %g7, %o4, %g7 /* IEU0 Group */ + jmpl %g7 + %lo(23f), %g0 /* CTI Group brk forced */ + add %o0, %g1, %o0 /* IEU0 */ +#else +22: rd %pc, %g7 /* LSU Group+4bubbles */ sll %g1, 1, %o4 /* IEU0 Group */ sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */ - add %o0, %g1, %o0 /* IEU0 */ + add %o0, %g1, %o0 /* IEU0 */ +#endif CSUM_LASTCHUNK(0xe0) CSUM_LASTCHUNK(0xd0) CSUM_LASTCHUNK(0xc0) diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S new file mode 100644 index 000000000..efd2bfcd5 --- /dev/null +++ b/arch/sparc64/lib/VIScsumcopy.S @@ -0,0 +1,880 @@ +/* $Id: VIScsumcopy.S,v 1.2 1997/08/19 15:25:22 jj Exp $ + * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous + * copying utilizing the UltraSparc Visual Instruction Set. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Based on older sparc32/sparc64 checksum.S, which is: + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1995 Miguel de Icaza + * Copyright(C) 1996,1997 David S. Miller + * derived from: + * Linux/Alpha checksum c-code + * Linux/ix86 inline checksum assembly + * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code) + * David Mosberger-Tang for optimized reference c-code + * BSD4.4 portable checksum routine + */ + +#ifdef __sparc_v9__ +#define STACKOFF 0x7ff+128 +#else +#define STACKOFF 64 +#endif + +#ifdef __KERNEL__ +#include <asm/head.h> +#include <asm/asi.h> +#include <asm/page.h> +#else +#define ASI_P 0x80 +#define ASI_BLK_P 0xf0 +#define FRPS_FEF 0x04 +#define FPRS_DU 0x02 +#define FPRS_DL 0x01 +#endif +#define ASI_BLK_XOR (ASI_BLK_P ^ ASI_P) + +#define src o0 +#define dst o1 +#define len o2 +#define sum o3 +#define x1 g1 +#define x2 g2 +#define x3 g3 +#define x4 g4 +#define x5 g5 +#define x6 g7 +#define x7 o4 +#define x8 o5 + +/* Dobrou noc, SunSoft engineers. Spete sladce. + * This has a couple of tricks in and those + * tricks are UltraLinux trade secrets :)) + * Once AGAIN, the SunSoft engineers are caught + * asleep at the keyboard :)). + * The main loop does about 20 superscalar cycles + * per 64bytes checksummed/copied. + */ + +#define LDBLK(O0) \ + ldda [%src] %asi, %O0 /* Load Group */ + +#define STBLK \ + stda %f48, [%dst] ASI_BLK_P /* Store */ + +#define ST(fx,off) \ + std %fx, [%dst + off] /* Store */ + +#define SYNC \ + membar #Sync + + +#define DO_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14,DUMMY1,A0,A2,A4,A6,A8,A10,A12,A14,B14,DYMMY2,LOAD,STORE1,STORE2,STORE3,STORE4,STORE5,STORE6,STORE7,STORE8,DUMMY3,BRANCH...) \ + LOAD /* Load Group */; \ + faligndata %A14, %F0, %A14 /* FPA Group */; \ + inc %x5 /* IEU0 */; \ + STORE1 /* Store (optional) */; \ + faligndata %F0, %F2, %A0 /* FPA Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA Group */; \ + inc %x6 /* IEU0 */; \ + STORE2 /* Store (optional) */; \ + faligndata %F2, %F4, %A2 /* FPA Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA Group */; \ + add %src, 64, %src /* IEU0 */; \ + add %dst, 64, %dst /* IEU1 */; \ + fcmpgt32 %f0, %F0, %x1 /* FPM Group */; \ + inc %x7 /* IEU0 */; \ + STORE3 /* Store (optional) */; \ + faligndata %F4, %F6, %A4 /* FPA */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fpadd32 %F4, %f4, %F4 /* FPA */; \ + fcmpgt32 %f2, %F2, %x2 /* FPM Group */; \ + inc %x8 /* IEU0 */; \ + STORE4 /* Store (optional) */; \ + faligndata %F6, %F8, %A6 /* FPA */; \ + srl %x8, 1, %x8 /* IEU0 Group */; \ + add %sum, %x7, %sum /* IEU1 */; \ + fpadd32 %F6, %f6, %F6 /* FPA */; \ + fcmpgt32 %f4, %F4, %x3 /* FPM Group */; \ + inc %x1 /* IEU0 */; \ + STORE5 /* Store (optional) */; \ + faligndata %F8, %F10, %A8 /* FPA */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + add %sum, %x8, %sum /* IEU1 */; \ + fpadd32 %F8, %f8, %F8 /* FPA */; \ + fcmpgt32 %f6, %F6, %x4 /* FPM Group */; \ + inc %x2 /* IEU0 */; \ + STORE6 /* Store (optional) */; \ + faligndata %F10, %F12, %A10 /* FPA */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + fpadd32 %F10, %f10, %F10 /* FPA */; \ + fcmpgt32 %f8, %F8, %x5 /* FPM Group */; \ + inc %x3 /* IEU0 */; \ + STORE7 /* Store (optional) */; \ + faligndata %F12, %F14, %A12 /* FPA */; \ + srl %x3, 1, %x3 /* IEU0 Group */; \ + add %sum, %x2, %sum /* IEU1 */; \ + fpadd32 %F12, %f12, %F12 /* FPA */; \ + fcmpgt32 %f10, %F10, %x6 /* FPM Group */; \ + inc %x4 /* IEU0 */; \ + STORE8 /* Store (optional) */; \ + fmovd %F14, %B14 /* FPA */; \ + srl %x4, 1, %x4 /* IEU0 Group */; \ + add %sum, %x3, %sum /* IEU1 */; \ + fpadd32 %F14, %f14, %F14 /* FPA */; \ + fcmpgt32 %f12, %F12, %x7 /* FPM Group */; \ + subcc %len, 64, %len /* IEU1 */; \ + BRANCH /* CTI */; \ + fcmpgt32 %f14, %F14, %x8 /* FPM Group */; \ + +#define END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,S0,S1,S2,S3,T0,T1,U0,fz) \ + inc %x5 /* IEU0 Group */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + srl %x5, 1, %x5 /* IEU0 Group */; \ + add %sum, %x4, %sum /* IEU1 */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fcmpgt32 %f0, %S0, %x1 /* FPM Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + inc %x7 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA */; \ + fcmpgt32 %f4, %S1, %x2 /* FPM Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + fpadd32 %f14, %f12, %S3 /* FPA */; \ + inc %x8 /* IEU0 Group */; \ + add %sum, %x7, %sum /* IEU1 */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %x3 /* FPM Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + inc %x1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fcmpgt32 %f12, %S3, %x4 /* FPM Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + add %sum, %x8, %sum /* IEU1 */; \ + fpadd32 %S2, %S3, %T1 /* FPA */; \ + inc %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + fcmpgt32 %S0, %T0, %x5 /* FPM Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + inc %x3 /* IEU1 */; \ + fcmpgt32 %S2, %T1, %x6 /* FPM Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + add %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + add %sum, %x3, %sum /* IEU1 */; \ + fcmpgt32 %fz, %f2, %x7 /* FPM Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + inc %x5 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA */; \ + fcmpgt32 %fz, %f6, %x8 /* FPM Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + add %sum, %x4, %sum /* IEU1 */; \ + inc %x6 /* IEU0 Group */; \ + add %sum, %x5, %sum /* IEU1 */; \ + fcmpgt32 %fz, %f10, %x1 /* FPM Group */; \ + srl %x6, 1, %x6 /* IEU0 */; \ + inc %x7 /* IEU1 */; \ + fcmpgt32 %fz, %f14, %x2 /* FPM Group */; \ + ba,pt %xcc, ett /* CTI */; \ + fmovd %FA, %FB /* FPA */; \ + +#define END_THE_TRICK1(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB) \ + END_THE_TRICK(f0,f2,f4,f6,f8,f10,f12,f14,FA,FB,f48,f50,f52,f54,f56,f58,f60,f62) + +#define END_THE_TRICK2(S0,S1,S2,S3,T0,T1,U0,U1,V0,fz) \ + fpadd32 %U0, %U1, %V0 /* FPA Group */; \ + srl %x7, 1, %x7 /* IEU0 */; \ + add %sum, %x6, %sum /* IEU1 */; \ + std %V0, [%sp + STACKOFF] /* Store Group */; \ + inc %x8 /* IEU0 */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + fcmpgt32 %fz, %S1, %x3 /* FPM Group */; \ + srl %x8, 1, %x8 /* IEU0 */; \ + inc %x1 /* IEU1 */; \ + fcmpgt32 %fz, %S3, %x4 /* FPM Group */; \ + srl %x1, 1, %x1 /* IEU0 */; \ + sub %sum, %x8, %sum /* IEU1 */; \ + ldx [%sp + STACKOFF], %x8 /* Load Group */; \ + inc %x2 /* IEU0 */; \ + sub %sum, %x1, %sum /* IEU1 */; \ + fcmpgt32 %fz, %T1, %x5 /* FPM Group */; \ + srl %x2, 1, %x2 /* IEU0 */; \ + inc %x3 /* IEU1 */; \ + fcmpgt32 %T0, %U0, %x6 /* FPM Group */; \ + srl %x3, 1, %x3 /* IEU0 */; \ + sub %sum, %x2, %sum /* IEU1 */; \ + inc %x4 /* IEU0 Group */; \ + sub %sum, %x3, %sum /* IEU1 */; \ + fcmpgt32 %fz, %U1, %x7 /* FPM Group */; \ + srl %x4, 1, %x4 /* IEU0 */; \ + inc %x5 /* IEU1 */; \ + fcmpgt32 %U0, %V0, %x1 /* FPM Group */; \ + srl %x5, 1, %x5 /* IEU0 */; \ + sub %sum, %x4, %sum /* IEU1 */; \ + fcmpgt32 %fz, %V0, %x2 /* FPM Group */; \ + inc %x6 /* IEU0 */; \ + sub %sum, %x5, %sum /* IEU1 */; \ + srl %x6, 1, %x6 /* IEU0 Group */; \ + inc %x7 /* IEU1 */; \ + srl %x7, 1, %x7 /* IEU0 Group */; \ + add %sum, %x6, %sum /* IEU1 */; \ + inc %x1 /* IEU0 Group */; \ + sub %sum, %x7, %sum /* IEU1 */; \ + srl %x1, 1, %x1 /* IEU0 Group */; \ + inc %x2 /* IEU1 */; \ + srl %x2, 1, %x2 /* IEU0 Group */; \ + add %sum, %x1, %sum /* IEU1 */; \ + sub %sum, %x2, %sum /* IEU0 Group */; \ + addcc %sum, %x8, %sum /* IEU Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %sum, 1, %sum /* IEU0 */; \ +33: /* That's it */; + + .text + .globl csum_partial_copy_vis + .align 32 +/* %asi should be either ASI_P or ASI_S for csum_partial_copy resp. csum_partial_copy_from_user */ +/* This assumes that !((%src^%dst)&3) && !((%src|%dst)&1) && %len >= 256 */ +csum_partial_copy_vis: + andcc %dst, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + and %dst, 0x38, %g3 /* IEU0 */ + mov 1, %g5 /* IEU0 Group */ + andcc %dst, 2, %g0 /* IEU1 */ + be,pt %icc, 1f /* CTI */ + and %dst, 4, %g7 /* IEU0 Group */ + lduha [%src] %asi, %g2 /* Load */ + sub %len, 2, %len /* IEU0 Group */ + add %dst, 2, %dst /* IEU1 */ + andcc %dst, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sth %g2, [%dst - 2] /* Store Group */ + sll %g2, 16, %g2 /* IEU0 */ + add %src, 2, %src /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, %g5, %sum /* IEU0 */ +1: lduwa [%src] %asi, %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %dst, 0x38, %g3 /* IEU0 */ + add %dst, 4, %dst /* IEU0 Group */ + sub %len, 4, %len /* IEU1 */ + addcc %g2, %sum, %sum /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: and %dst, 0x38, %g3 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + add %src, 4, %src /* IEU1 */ +4: +#ifdef __KERNEL__ + wr %g0, FPRS_FEF, %fprs /* LSU Group */ +#endif + mov %src, %g7 /* IEU1 Group */ + fzero %f48 /* FPA */ + alignaddr %src, %g0, %src /* Single Group */ + subcc %g7, %src, %g7 /* IEU1 Group */ + be,pt %xcc, 1f /* CTI */ + mov 0x40, %g1 /* IEU0 */ + lduwa [%src] %asi, %g2 /* Load Group */ + subcc %sum, %g2, %sum /* IEU1 Group+load stall */ + bcs,a,pn %icc, 1f /* CTI */ + sub %sum, 1, %sum /* IEU0 */ +1: srl %sum, 0, %sum /* IEU0 Group */ + clr %g5 /* IEU1 */ + brz,pn %g3, 3f /* CTI+IEU1 Group */ + sub %g1, %g3, %g1 /* IEU0 */ + ldda [%src] %asi, %f0 /* Load */ + clr %g3 /* IEU0 Group */ + andcc %dst, 8, %g0 /* IEU1 */ + be,pn %icc, 1f /* CTI */ + ldda [%src + 8] %asi, %f2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + sub %len, 8, %len /* IEU1 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + addcc %dst, 8, %dst /* IEU1 Group */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g3 /* FPM Group */ + fmovd %f2, %f0 /* FPA Group */ + ldda [%src + 8] %asi, %f2 /* Load */ + std %f16, [%dst - 8] /* Store */ + fmovd %f50, %f48 /* FPA */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + add %src, 16, %src /* IEU0 */ + add %dst, 16, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + sub %len, 16, %len /* IEU0 */ + inc %g3 /* IEU1 */ + std %f16, [%dst - 16] /* Store Group */ + fpadd32 %f2, %f50, %f48 /* FPA */ + srl %g3, 1, %o5 /* IEU0 */ + faligndata %f2, %f4, %f18 /* FPA Group */ + std %f18, [%dst - 8] /* Store */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + ldda [%src + 8] %asi, %f2 /* Load */ + fmovd %f4, %f0 /* FPA */ +1: brz,a,pn %g1, 4f /* CTI+IEU1 Group */ + rd %asi, %g2 /* LSU Group + 4 bubbles */ + inc %g5 /* IEU0 */ + fpadd32 %f0, %f48, %f50 /* FPA */ + ldda [%src + 16] %asi, %f4 /* Load Group */ + srl %g5, 1, %g5 /* IEU0 */ + add %dst, 32, %dst /* IEU1 */ + faligndata %f0, %f2, %f16 /* FPA */ + fcmpgt32 %f48, %f50, %o5 /* FPM Group */ + inc %g3 /* IEU0 */ + ldda [%src + 24] %asi, %f6 /* Load */ + srl %g3, 1, %g3 /* IEU0 Group */ + add %g5, %sum, %sum /* IEU1 */ + ldda [%src + 32] %asi, %f8 /* Load */ + fpadd32 %f2, %f50, %f48 /* FPA */ + faligndata %f2, %f4, %f18 /* FPA Group */ + sub %len, 32, %len /* IEU0 */ + std %f16, [%dst - 32] /* Store */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + inc %o5 /* IEU0 */ + add %g3, %sum, %sum /* IEU1 */ + fpadd32 %f4, %f48, %f50 /* FPA */ + faligndata %f4, %f6, %f20 /* FPA Group */ + srl %o5, 1, %o5 /* IEU0 */ + fcmpgt32 %f48, %f50, %g5 /* FPM Group */ + add %o5, %sum, %sum /* IEU0 */ + std %f18, [%dst - 24] /* Store */ + fpadd32 %f6, %f50, %f48 /* FPA */ + inc %o4 /* IEU0 Group */ + std %f20, [%dst - 16] /* Store */ + add %src, 32, %src /* IEU1 */ + faligndata %f6, %f8, %f22 /* FPA */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + srl %o4, 1, %o4 /* IEU0 */ + std %f22, [%dst - 8] /* Store */ + add %o4, %sum, %sum /* IEU0 Group */ +3: rd %asi, %g2 /* LSU Group + 4 bubbles */ +#ifdef __KERNEL__ +4: sethi %hi(vis0s), %g7 /* IEU0 Group */ +#else +4: rd %pc, %g7 /* LSU Group + 4 bubbles */ +#endif + inc %g5 /* IEU0 Group */ + and %src, 0x38, %o4 /* IEU1 */ + membar #StoreLoad /* LSU Group */ + srl %g5, 1, %g5 /* IEU0 */ + inc %g3 /* IEU1 */ + sll %o4, 8, %o4 /* IEU0 Group */ + sub %len, 0xc0, %len /* IEU1 */ + addcc %g5, %sum, %sum /* IEU1 Group */ + srl %g3, 1, %g3 /* IEU0 */ + add %g7, %o4, %g7 /* IEU0 Group */ + add %g3, %sum, %sum /* IEU1 */ +#ifdef __KERNEL__ + jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ +#else + jmpl %g7 + (vis0s - 4b), %g0 /* CTI+IEU1 Group */ +#endif + fzero %f32 /* FPA */ + + .align 2048 +vis0s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f62 /* FPA Group */ + faligndata %f0, %f2, %f48 /* FPA Group */ + fcmpgt32 %f32, %f2, %x1 /* FPM Group */ + fpadd32 %f0, %f62, %f0 /* FPA */ + fcmpgt32 %f32, %f4, %x2 /* FPM Group */ + faligndata %f2, %f4, %f50 /* FPA */ + fcmpgt32 %f62, %f0, %x3 /* FPM Group */ + faligndata %f4, %f6, %f52 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + inc %x1 /* IEU0 */ + faligndata %f6, %f8, %f54 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + srl %x1, 1, %x1 /* IEU0 */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f56 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + add %sum, %x1, %sum /* IEU1 */ + faligndata %f10, %f12, %f58 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f60 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f62 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ +vis0: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f32), STBLK,,,,,,,, + ,bcs,pn %icc, vis0e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f0), STBLK,,,,,,,, + ,bcs,pn %icc, vis0e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f48,f50,f52,f54,f56,f58,f60,f62,f62, + ,LDBLK(f16), STBLK,,,,,,,, + ,bcc,pt %icc, vis0) +vis0e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f48,f50,f52,f54,f56,f58,f60,f62,f32, + ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), + ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e2) +vis0e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f48,f50,f52,f54,f56,f58,f60,f62,f0, + ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), + ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e3) +vis0e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f48,f50,f52,f54,f56,f58,f60,f62,f16, + ,SYNC, STBLK,ST(f48,64),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40),ST(f60,48), + ,add %dst, 56, %dst; add %len, 192 - 8*8, %len; ba,pt %icc, e1) + .align 2048 +vis1s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 8, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fcmpgt32 %f32, %f2, %x2 /* FPM Group */ + faligndata %f2, %f4, %f48 /* FPA */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f50 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f52 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + inc %x2 /* IEU1 */ + faligndata %f8, %f10, %f54 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + srl %x2, 1, %x2 /* IEU0 */ + faligndata %f10, %f12, %f56 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + add %sum, %x2, %sum /* IEU1 */ + faligndata %f12, %f14, %f58 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f60 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ +vis1: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f62,f48,f50,f52,f54,f56,f58,f60,f60, + ,LDBLK(f32), ,STBLK,,,,,,, + ,bcs,pn %icc, vis1e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f62,f48,f50,f52,f54,f56,f58,f60,f60, + ,LDBLK(f0), ,STBLK,,,,,,, + ,bcs,pn %icc, vis1e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f62,f48,f50,f52,f54,f56,f58,f60,f60, + ,LDBLK(f16), ,STBLK,,,,,,, + ,bcc,pt %icc, vis1) +vis1e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f62,f48,f50,f52,f54,f56,f58,f60,f32, + ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), + ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e2) +vis1e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f62,f48,f50,f52,f54,f56,f58,f60,f0, + ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), + ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e3) +vis1e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f62,f48,f50,f52,f54,f56,f58,f60,f16, + ,SYNC, ,STBLK,ST(f48,0),ST(f50,8),ST(f52,16),ST(f54,24),ST(f56,32),ST(f58,40), + ,add %dst, 48, %dst; add %len, 192 - 7*8, %len; ba,pt %icc, e1) + .align 2048 +vis2s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 16, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fzero %f2 /* FPA Group */ + fcmpgt32 %f32, %f4, %x3 /* FPM Group */ + faligndata %f4, %f6, %f48 /* FPA */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f50 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f52 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f54 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + inc %x3 /* IEU0 */ + faligndata %f12, %f14, %f56 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + srl %x3, 1, %x3 /* IEU0 */ + inc %x4 /* IEU1 */ + fmovd %f14, %f58 /* FPA */ + srl %x4, 1, %x4 /* IEU0 Group */ + add %sum, %x3, %sum /* IEU1 */ +vis2: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f60,f62,f48,f50,f52,f54,f56,f58,f58, + ,LDBLK(f32), ,,STBLK,,,,,, + ,bcs,pn %icc, vis2e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f60,f62,f48,f50,f52,f54,f56,f58,f58, + ,LDBLK(f0), ,,STBLK,,,,,, + ,bcs,pn %icc, vis2e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f60,f62,f48,f50,f52,f54,f56,f58,f58, + ,LDBLK(f16), ,,STBLK,,,,,, + ,bcc,pt %icc, vis2) +vis2e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f60,f62,f48,f50,f52,f54,f56,f58,f32, + ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), + ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e2) +vis2e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f60,f62,f48,f50,f52,f54,f56,f58,f0, + ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), + ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e3) +vis2e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f60,f62,f48,f50,f52,f54,f56,f58,f16, + ,SYNC, ,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88),ST(f56,96), + ,add %dst, 104, %dst; add %len, 192 - 6*8, %len; ba,pt %icc, e1) + .align 2048 +vis3s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 24, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fzero %f2 /* FPA Group */ + fzero %f4 /* FPA Group */ + fcmpgt32 %f32, %f6, %x4 /* FPM Group */ + faligndata %f6, %f8, %f48 /* FPA */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f50 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f52 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f54 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f56 /* FPA */ + inc %x4 /* IEU0 */ + srl %x4, 1, %x4 /* IEU0 Group */ +vis3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f58,f60,f62,f48,f50,f52,f54,f56,f56, + ,LDBLK(f32), ,,,STBLK,,,,, + ,bcs,pn %icc, vis3e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f58,f60,f62,f48,f50,f52,f54,f56,f56, + ,LDBLK(f0), ,,,STBLK,,,,, + ,bcs,pn %icc, vis3e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f58,f60,f62,f48,f50,f52,f54,f56,f56, + ,LDBLK(f16), ,,,STBLK,,,,, + ,bcc,pt %icc, vis3) +vis3e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f58,f60,f62,f48,f50,f52,f54,f56,f32, + ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), + ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e2) +vis3e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f58,f60,f62,f48,f50,f52,f54,f56,f0, + ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), + ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e3) +vis3e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f58,f60,f62,f48,f50,f52,f54,f56,f16, + ,SYNC, ,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80),ST(f54,88), + ,add %dst, 96, %dst; add %len, 192 - 5*8, %len; ba,pt %icc, e1) + .align 2048 +vis4s: wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + add %src, 128 - 32, %src /* IEU0 Group */ + ldda [%src-128] %asi, %f0 /* Load Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + sub %dst, 64, %dst /* IEU0 */ + fzero %f2 /* FPA Group */ + fzero %f4 /* FPA Group */ + fzero %f6 /* FPA Group */ + clr %x4 /* IEU0 */ + fcmpgt32 %f32, %f8, %x5 /* FPM Group */ + faligndata %f8, %f10, %f48 /* FPA */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + faligndata %f10, %f12, %f50 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f52 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f54 /* FPA */ +vis4: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f56,f58,f60,f62,f48,f50,f52,f54,f54, + ,LDBLK(f32), ,,,,STBLK,,,, + ,bcs,pn %icc, vis4e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f56,f58,f60,f62,f48,f50,f52,f54,f54, + ,LDBLK(f0), ,,,,STBLK,,,, + ,bcs,pn %icc, vis4e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f56,f58,f60,f62,f48,f50,f52,f54,f54, + ,LDBLK(f16), ,,,,STBLK,,,, + ,bcc,pt %icc, vis4) +vis4e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f56,f58,f60,f62,f48,f50,f52,f54,f32, + ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80), + ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e2) +vis4e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f56,f58,f60,f62,f48,f50,f52,f54,f0, + ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80), + ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e3) +vis4e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f56,f58,f60,f62,f48,f50,f52,f54,f16, + ,SYNC, ,,,,STBLK,ST(f48,64),ST(f50,72),ST(f52,80), + ,add %dst, 88, %dst; add %len, 192 - 4*8, %len; ba,pt %icc, e1) + .align 2048 +vis5s: add %src, 128 - 40, %src /* IEU0 Group */ + ldda [%src-88] %asi, %f10 /* Load Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fcmpgt32 %f32, %f10, %x6 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f10, %f12, %f48 /* FPA */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + faligndata %f12, %f14, %f50 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f52 /* FPA */ +vis5: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f54,f56,f58,f60,f62,f48,f50,f52,f52, + ,LDBLK(f32), ,,,,,STBLK,,, + ,bcs,pn %icc, vis5e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f54,f56,f58,f60,f62,f48,f50,f52,f52, + ,LDBLK(f0), ,,,,,STBLK,,, + ,bcs,pn %icc, vis5e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f54,f56,f58,f60,f62,f48,f50,f52,f52, + ,LDBLK(f16), ,,,,,STBLK,,, + ,bcc,pt %icc, vis5) +vis5e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f54,f56,f58,f60,f62,f48,f50,f52,f32, + ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72), + ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e2) +vis5e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f54,f56,f58,f60,f62,f48,f50,f52,f0, + ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72), + ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e3) +vis5e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f54,f56,f58,f60,f62,f48,f50,f52,f16, + ,SYNC, ,,,,,STBLK,ST(f48,64),ST(f50,72), + ,add %dst, 80, %dst; add %len, 192 - 3*8, %len; ba,pt %icc, e1) + .align 2048 +vis6s: add %src, 128 - 48, %src /* IEU0 Group */ + ldda [%src-80] %asi, %f12 /* Load Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + fcmpgt32 %f32, %f12, %x7 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + faligndata %f12, %f14, %f48 /* FPA */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + fmovd %f14, %f50 /* FPA */ +vis6: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f52,f54,f56,f58,f60,f62,f48,f50,f50, + ,LDBLK(f32), ,,,,,,STBLK,, + ,bcs,pn %icc, vis6e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f52,f54,f56,f58,f60,f62,f48,f50,f50, + ,LDBLK(f0), ,,,,,,STBLK,, + ,bcs,pn %icc, vis6e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f52,f54,f56,f58,f60,f62,f48,f50,f50, + ,LDBLK(f16), ,,,,,,STBLK,, + ,bcc,pt %icc, vis6) +vis6e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f52,f54,f56,f58,f60,f62,f48,f50,f32, + ,SYNC, ,,,,,,STBLK,ST(f48,64), + ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e2) +vis6e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f52,f54,f56,f58,f60,f62,f48,f50,f0, + ,SYNC, ,,,,,,STBLK,ST(f48,64), + ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e3) +vis6e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f52,f54,f56,f58,f60,f62,f48,f50,f16, + ,SYNC, ,,,,,,STBLK,ST(f48,64), + ,add %dst, 72, %dst; add %len, 192 - 2*8, %len; ba,pt %icc, e1) + .align 2048 +vis7s: add %src, 128 - 56, %src /* IEU0 Group */ + ldda [%src-72] %asi, %f14 /* Load Group */ + wr %g2, ASI_BLK_XOR, %asi /* LSU Group */ + ldda [%src-64] %asi, %f16 /* Load Group */ + fmovd %f48, %f0 /* FPA Group */ + fmuld %f32, %f32, %f2 /* FPM */ + clr %x4 /* IEU0 */ + faddd %f32, %f32, %f4 /* FPA Group */ + fmuld %f32, %f32, %f6 /* FPM */ + clr %x5 /* IEU0 */ + faddd %f32, %f32, %f8 /* FPA Group */ + fmuld %f32, %f32, %f10 /* FPM */ + clr %x6 /* IEU0 */ + faddd %f32, %f32, %f12 /* FPA Group */ + clr %x7 /* IEU0 */ + fcmpgt32 %f32, %f14, %x8 /* FPM Group */ + sub %dst, 64, %dst /* IEU0 */ + fmovd %f14, %f48 /* FPA */ +vis7: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f50,f52,f54,f56,f58,f60,f62,f48,f48, + ,LDBLK(f32), ,,,,,,,STBLK, + ,bcs,pn %icc, vis7e1) + DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f50,f52,f54,f56,f58,f60,f62,f48,f48, + ,LDBLK(f0), ,,,,,,,STBLK, + ,bcs,pn %icc, vis7e2) + DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f50,f52,f54,f56,f58,f60,f62,f48,f48, + ,LDBLK(f16), ,,,,,,,STBLK, + ,bcc,pt %icc, vis7) +vis7e3: DO_THE_TRICK( f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30, + ,f50,f52,f54,f56,f58,f60,f62,f48,f32, + ,SYNC, ,,,,,,,STBLK, + ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e2) +vis7e1: DO_THE_TRICK( f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46, + ,f50,f52,f54,f56,f58,f60,f62,f48,f0, + ,SYNC, ,,,,,,,STBLK, + ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e3) +vis7e2: DO_THE_TRICK( f32,f34,f36,f38,f40,f42,f44,f46,f0,f2,f4,f6,f8,f10,f12,f14, + ,f50,f52,f54,f56,f58,f60,f62,f48,f16, + ,SYNC, ,,,,,,,STBLK, + ,add %dst, 64, %dst; add %len, 192 - 1*8, %len; ba,pt %icc, e1) +e1: END_THE_TRICK1( f0,f2,f4,f6,f8,f10,f12,f14,f16,f6) +e2: END_THE_TRICK1( f16,f18,f20,f22,f24,f26,f28,f30,f32,f6) +e3: END_THE_TRICK1( f32,f34,f36,f38,f40,f42,f44,f46,f0,f6) +ett: rd %gsr, %x3 /* LSU Group+4bubbles */ + andcc %x3, 7, %x3 /* IEU1 Group */ + add %dst, 8, %dst /* IEU0 Group */ + bne,pn %icc, 1f /* CTI */ + fzero %f10 /* FPA */ + brz,a,pn %len, 2f /* CTI+IEU1 Group */ + std %f6, [%dst - 8] /* Store */ +1: rd %asi, %x4 /* LSU Group+4bubbles */ + sub %src, 64, %src /* IEU0 Group */ + cmp %len, 8 /* IEU1 */ + blu,pn %icc, 3f /* CTI */ + wr %x4, ASI_BLK_XOR, %asi /* LSU Group+4bubbles */ +1: ldda [%src] %asi, %f2 /* Load Group */ + fpadd32 %f10, %f2, %f12 /* FPA Group+load stall */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + faligndata %f6, %f2, %f14 /* FPA Group */ + fcmpgt32 %f10, %f12, %x5 /* FPM Group */ + std %f14, [%dst - 16] /* Store */ + fmovd %f2, %f6 /* FPA */ + fmovd %f12, %f10 /* FPA Group */ + sub %len, 8, %len /* IEU1 */ + fzero %f16 /* FPA Group - FPU nop */ + fzero %f18 /* FPA Group - FPU nop */ + inc %x5 /* IEU0 */ + srl %x5, 1, %x5 /* IEU0 Group (regdep) */ + cmp %len, 8 /* IEU1 */ + bgeu,pt %icc, 1b /* CTI */ + add %x5, %sum, %sum /* IEU0 Group */ +3: brz,a,pt %x3, 2f /* CTI+IEU1 */ + std %f6, [%dst - 8] /* Store Group */ + st %f7, [%dst - 8] /* Store Group */ + sub %dst, 4, %dst /* IEU0 */ + add %len, 4, %len /* IEU1 */ +2: +#ifdef __KERNEL__ + sub %sp, 8, %sp /* IEU0 Group */ +#endif + END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) + membar #Sync /* LSU Group */ +#ifdef __KERNEL__ + wr %g0, 0, %fprs /* LSU Group */ + add %sp, 8, %sp /* IEU0 Group */ +#endif +23: brnz,pn %len, 26f /* CTI+IEU1 Group */ +24: sllx %sum, 32, %g1 /* IEU0 */ +25: addcc %sum, %g1, %src /* IEU1 Group */ + srlx %src, 32, %src /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %src, 1, %src /* IEU1 */ +#ifndef __KERNEL__ +1: retl /* CTI Group brk forced */ + srl %src, 0, %src /* IEU0 */ +#else +1: sethi %uhi(PAGE_OFFSET), %g4 /* IEU0 Group */ + retl /* CTI Group brk forced */ + sllx %g4, 32, %g4 /* IEU0 */ +#endif +26: andcc %len, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + lduwa [%src] %asi, %g3 /* Load */ + lduwa [%src+4] %asi, %g2 /* Load Group */ + add %src, 8, %src /* IEU0 */ + add %dst, 8, %dst /* IEU1 */ + sllx %g3, 32, %g5 /* IEU0 Group */ + stw %g3, [%dst - 8] /* Store */ + or %g5, %g2, %g5 /* IEU0 Group */ + stw %g2, [%dst - 4] /* Store */ + addcc %g5, %sum, %sum /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: andcc %len, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduwa [%src] %asi, %g7 /* Load */ + add %src, 4, %src /* IEU0 Group */ + add %dst, 4, %dst /* IEU1 */ + sllx %g7, 32, %g2 /* IEU0 Group */ + stw %g7, [%dst - 4] /* Store */ +1: andcc %len, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduha [%src] %asi, %g7 /* Load */ + add %src, 2, %src /* IEU1 */ + add %dst, 2, %dst /* IEU0 Group */ + sll %g7, 16, %o4 /* IEU0 Group */ + sth %g7, [%dst - 2] /* Store */ +1: andcc %len, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + lduba [%src] %asi, %g7 /* Load */ + sll %g7, 8, %o5 /* IEU0 Group */ + stb %g7, [%dst] /* Store */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %sum, %sum /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %sum, 1, %sum /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %sum, 32, %g1 /* IEU0 */ + +#ifdef __KERNEL__ +end: + + .section __ex_table + .align 4 + .word csum_partial_copy_vis, 0, end, cpc_handler +#endif diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S index d674f2a6e..4c24931ba 100644 --- a/arch/sparc64/lib/VISmemset.S +++ b/arch/sparc64/lib/VISmemset.S @@ -1,4 +1,4 @@ -/* $Id: VISmemset.S,v 1.1 1997/07/18 06:26:49 ralf Exp $ +/* $Id: VISmemset.S,v 1.7 1997/08/22 15:54:56 jj Exp $ * VISmemset.S: High speed memset operations utilizing the UltraSparc * Visual Instruction Set. * @@ -171,11 +171,22 @@ memset: 12: #ifdef __KERNEL__ wr %g0, 0, %fprs +#else +#ifndef REGS_64BIT + wr %g0, FPRS_FEF, %fprs #endif - membar #Sync +#endif + membar #StoreLoad | #StoreStore 9: andcc %o2, 0x78, %g5 be,pn %xcc, 13f andcc %o2, 7, %o2 +#ifdef __KERNEL__ +14: srl %g5, 1, %o3 + sethi %hi(13f), %o4 + sub %o4, %o3, %o4 + jmpl %o4 + %lo(13f), %g0 + add %o0, %g5, %o0 +#else 14: rd %pc, %o4 #ifdef REGS_64BIT srl %g5, 1, %o3 @@ -185,6 +196,7 @@ memset: #endif jmpl %o4 + (13f - 14b), %g0 add %o0, %g5, %o0 +#endif 12: SET_BLOCKS(%o0, 0x68, %o1) SET_BLOCKS(%o0, 0x48, %o1) SET_BLOCKS(%o0, 0x28, %o1) diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index 59083aa02..7d5b240ad 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.10 1997/06/24 17:29:10 jj Exp $ +/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $ * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -15,7 +15,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */ wr %g0, FPRS_FEF, %fprs ! FPU Group ldd [%o1], %f48 ! Load Group wr %g0, ASI_BLK_P, %asi ! LSU Group - membar #StoreStore | #LoadStore ! LSU Group + membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group mov 32, %g2 ! IEU0 Group /* Cannot perform real arithmatic on the pattern, that can @@ -36,7 +36,7 @@ __bfill64: /* %o0 = buf, %o1= ptr to pattern */ subcc %g2, 1, %g2 ! IEU1 Group bne,pt %icc, 1b ! CTI add %o0, 0x100, %o0 ! IEU0 - membar #Sync ! LSU Group + membar #StoreLoad | #StoreStore ! LSU Group jmpl %o7 + 0x8, %g0 ! CTI Group brk forced wr %g0, 0, %fprs ! FPU Group @@ -56,7 +56,7 @@ __bzero_1page: faddd %f0, %f2, %f12 ! FPA Group fmuld %f0, %f2, %f14 ! FPM wr %g0, ASI_BLK_P, %asi ! LSU Group - membar #StoreStore | #LoadStore ! LSU Group + membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group 1: stda %f0, [%o0 + 0x00] %asi ! Store Group stda %f0, [%o0 + 0x40] %asi ! Store Group stda %f0, [%o0 + 0x80] %asi ! Store Group @@ -65,6 +65,6 @@ __bzero_1page: subcc %g1, 1, %g1 ! IEU1 bne,pt %icc, 1b ! CTI add %o0, 0x100, %o0 ! IEU0 Group - membar #Sync ! LSU Group + membar #StoreLoad | #StoreStore ! LSU Group jmpl %o7 + 0x8, %g0 ! CTI Group brk forced wr %g0, 0, %fprs ! FPU Group diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S index 703370fc6..5f35f136b 100644 --- a/arch/sparc64/lib/checksum.S +++ b/arch/sparc64/lib/checksum.S @@ -23,456 +23,456 @@ * are two fold. Firstly, they cannot pair with jack shit, * and also they only add in the 32-bit carry condition bit * into the accumulated sum. The following is much better. - * - * This should run at max bandwidth for ecache hits, a better - * technique is to use VIS and fpu operations. This is already - * done for csum_partial, needs to be written for the copy stuff - * still. + * For larger chunks we use VIS code, which is faster ;) */ - .text - .globl __csum_partial_copy_start, __csum_partial_copy_end -__csum_partial_copy_start: +#define src o0 +#define dst o1 +#define len o2 +#define sum o3 + .text /* I think I have an erection... Once _AGAIN_ the SunSoft * engineers are caught asleep at the keyboard, tsk tsk... */ -#define CSUMCOPY_ECACHE_LOAD(src, off, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldxa [src + off + 0x00] %asi, t0; \ - ldxa [src + off + 0x08] %asi, t1; \ - ldxa [src + off + 0x10] %asi, t2; \ - ldxa [src + off + 0x18] %asi, t3; \ - ldxa [src + off + 0x20] %asi, t4; \ - ldxa [src + off + 0x28] %asi, t5; \ - ldxa [src + off + 0x30] %asi, t6; \ - ldxa [src + off + 0x38] %asi, t7; \ +#define CSUMCOPY_ECACHE_LOAD(off, t0, t1, t2, t3, t4, t5, t6, t7) \ + ldxa [%src + off + 0x00] %asi, t0; \ + ldxa [%src + off + 0x08] %asi, t1; \ + ldxa [%src + off + 0x10] %asi, t2; \ + ldxa [%src + off + 0x18] %asi, t3; \ + ldxa [%src + off + 0x20] %asi, t4; \ + ldxa [%src + off + 0x28] %asi, t5; \ + ldxa [%src + off + 0x30] %asi, t6; \ + ldxa [%src + off + 0x38] %asi, t7; \ nop; nop; /* DO NOT TOUCH THIS!!!!! */ -#define CSUMCOPY_EC_STALIGNED_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\ - stx t0, [dest + off - 0x40]; \ - addcc sum, t0, sum; \ +#define CSUMCOPY_EC_STALIGNED_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \ + stx t0, [%dst + off - 0x40]; \ + addcc %sum, t0, %sum; \ bcc,pt %xcc, 11f; \ - ldxa [src + off + 0x00] %asi, t0; \ - add sum, 1, sum; \ -11: stx t1, [dest + off - 0x38]; \ - addcc sum, t1, sum; \ + ldxa [%src + off + 0x00] %asi, t0; \ + add %sum, 1, %sum; \ +11: stx t1, [%dst + off - 0x38]; \ + addcc %sum, t1, %sum; \ bcc,pt %xcc, 12f; \ - ldxa [src + off + 0x08] %asi, t1; \ - add sum, 1, sum; \ -12: stx t2, [dest + off - 0x30]; \ - addcc sum, t2, sum; \ + ldxa [%src + off + 0x08] %asi, t1; \ + add %sum, 1, %sum; \ +12: stx t2, [%dst + off - 0x30]; \ + addcc %sum, t2, %sum; \ bcc,pt %xcc, 13f; \ - ldxa [src + off + 0x10] %asi, t2; \ - add sum, 1, sum; \ -13: stx t3, [dest + off - 0x28]; \ - addcc sum, t3, sum; \ + ldxa [%src + off + 0x10] %asi, t2; \ + add %sum, 1, %sum; \ +13: stx t3, [%dst + off - 0x28]; \ + addcc %sum, t3, %sum; \ bcc,pt %xcc, 14f; \ - ldxa [src + off + 0x18] %asi, t3; \ - add sum, 1, sum; \ -14: stx t4, [dest + off - 0x20]; \ - addcc sum, t4, sum; \ + ldxa [%src + off + 0x18] %asi, t3; \ + add %sum, 1, %sum; \ +14: stx t4, [%dst + off - 0x20]; \ + addcc %sum, t4, %sum; \ bcc,pt %xcc, 15f; \ - ldxa [src + off + 0x20] %asi, t4; \ - add sum, 1, sum; \ -15: stx t5, [dest + off - 0x18]; \ - addcc sum, t5, sum; \ + ldxa [%src + off + 0x20] %asi, t4; \ + add %sum, 1, %sum; \ +15: stx t5, [%dst + off - 0x18]; \ + addcc %sum, t5, %sum; \ bcc,pt %xcc, 16f; \ - ldxa [src + off + 0x28] %asi, t5; \ - add sum, 1, sum; \ -16: stx t6, [dest + off - 0x10]; \ - addcc sum, t6, sum; \ + ldxa [%src + off + 0x28] %asi, t5; \ + add %sum, 1, %sum; \ +16: stx t6, [%dst + off - 0x10]; \ + addcc %sum, t6, %sum; \ bcc,pt %xcc, 17f; \ - ldxa [src + off + 0x30] %asi, t6; \ - add sum, 1, sum; \ -17: stx t7, [dest + off - 0x08]; \ - addcc sum, t7, sum; \ + ldxa [%src + off + 0x30] %asi, t6; \ + add %sum, 1, %sum; \ +17: stx t7, [%dst + off - 0x08]; \ + addcc %sum, t7, %sum; \ bcc,pt %xcc, 18f; \ - ldxa [src + off + 0x38] %asi, t7; \ - add sum, 1, sum; \ + ldxa [%src + off + 0x38] %asi, t7; \ + add %sum, 1, %sum; \ 18: -#define CSUMCOPY_EC_STUNALIGN_LDNXT(src, dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7)\ - stw t0, [dest + off - 0x3c]; \ - addcc sum, t0, sum; \ +#define CSUMCOPY_EC_STUNALIGN_LDNXT(off, t0, t1, t2, t3, t4, t5, t6, t7) \ + stw t0, [%dst + off - 0x3c]; \ + addcc %sum, t0, %sum; \ srlx t0, 32, t0; \ - stw t0, [dest + off - 0x40]; \ + stw t0, [%dst + off - 0x40]; \ bcc,pt %xcc, 21f; \ - ldxa [src + off + 0x00] %asi, t0; \ - add sum, 1, sum; \ -21: stw t1, [dest + off - 0x34]; \ - addcc sum, t1, sum; \ + ldxa [%src + off + 0x00] %asi, t0; \ + add %sum, 1, %sum; \ +21: stw t1, [%dst + off - 0x34]; \ + addcc %sum, t1, %sum; \ srlx t1, 32, t1; \ - stw t1, [dest + off - 0x38]; \ + stw t1, [%dst + off - 0x38]; \ bcc,pt %xcc, 22f; \ - ldxa [src + off + 0x08] %asi, t1; \ - add sum, 1, sum; \ -22: stw t2, [dest + off - 0x2c]; \ - addcc sum, t2, sum; \ + ldxa [%src + off + 0x08] %asi, t1; \ + add %sum, 1, %sum; \ +22: stw t2, [%dst + off - 0x2c]; \ + addcc %sum, t2, %sum; \ srlx t2, 32, t2; \ - stw t2, [dest + off - 0x30]; \ + stw t2, [%dst + off - 0x30]; \ bcc,pt %xcc, 23f; \ - ldxa [src + off + 0x10] %asi, t2; \ - add sum, 1, sum; \ -23: stw t3, [dest + off - 0x24]; \ - addcc sum, t3, sum; \ + ldxa [%src + off + 0x10] %asi, t2; \ + add %sum, 1, %sum; \ +23: stw t3, [%dst + off - 0x24]; \ + addcc %sum, t3, %sum; \ srlx t3, 32, t3; \ - stw t3, [dest + off - 0x28]; \ + stw t3, [%dst + off - 0x28]; \ bcc,pt %xcc, 24f; \ - ldxa [src + off + 0x18] %asi, t3; \ - add sum, 1, sum; \ -24: stw t4, [dest + off - 0x1c]; \ - addcc sum, t4, sum; \ + ldxa [%src + off + 0x18] %asi, t3; \ + add %sum, 1, %sum; \ +24: stw t4, [%dst + off - 0x1c]; \ + addcc %sum, t4, %sum; \ srlx t4, 32, t4; \ - stw t4, [dest + off - 0x20]; \ + stw t4, [%dst + off - 0x20]; \ bcc,pt %xcc, 25f; \ - ldxa [src + off + 0x20] %asi, t4; \ - add sum, 1, sum; \ -25: stw t5, [dest + off - 0x14]; \ - addcc sum, t5, sum; \ + ldxa [%src + off + 0x20] %asi, t4; \ + add %sum, 1, %sum; \ +25: stw t5, [%dst + off - 0x14]; \ + addcc %sum, t5, %sum; \ srlx t5, 32, t5; \ - stw t5, [dest + off - 0x18]; \ + stw t5, [%dst + off - 0x18]; \ bcc,pt %xcc, 26f; \ - ldxa [src + off + 0x28] %asi, t5; \ - add sum, 1, sum; \ -26: stw t6, [dest + off - 0x0c]; \ - addcc sum, t6, sum; \ + ldxa [%src + off + 0x28] %asi, t5; \ + add %sum, 1, %sum; \ +26: stw t6, [%dst + off - 0x0c]; \ + addcc %sum, t6, %sum; \ srlx t6, 32, t6; \ - stw t6, [dest + off - 0x10]; \ + stw t6, [%dst + off - 0x10]; \ bcc,pt %xcc, 27f; \ - ldxa [src + off + 0x30] %asi, t6; \ - add sum, 1, sum; \ -27: stw t7, [dest + off - 0x04]; \ - addcc sum, t7, sum; \ + ldxa [%src + off + 0x30] %asi, t6; \ + add %sum, 1, %sum; \ +27: stw t7, [%dst + off - 0x04]; \ + addcc %sum, t7, %sum; \ srlx t7, 32, t7; \ - stw t7, [dest + off - 0x08]; \ + stw t7, [%dst + off - 0x08]; \ bcc,pt %xcc, 28f; \ - ldxa [src + off + 0x38] %asi, t7; \ - add sum, 1, sum; \ + ldxa [%src + off + 0x38] %asi, t7; \ + add %sum, 1, %sum; \ 28: -#define CSUMCOPY_EC_STALIGNED(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \ - addcc sum, t0, sum; \ +#define CSUMCOPY_EC_STALIGNED(off, t0, t1, t2, t3, t4, t5, t6, t7) \ + addcc %sum, t0, %sum; \ bcc,pt %xcc, 31f; \ - stx t0, [dest + off + 0x00]; \ - add sum, 1, sum; \ -31: addcc sum, t1, sum; \ + stx t0, [%dst + off + 0x00]; \ + add %sum, 1, %sum; \ +31: addcc %sum, t1, %sum; \ bcc,pt %xcc, 32f; \ - stx t1, [dest + off + 0x08]; \ - add sum, 1, sum; \ -32: addcc sum, t2, sum; \ + stx t1, [%dst + off + 0x08]; \ + add %sum, 1, %sum; \ +32: addcc %sum, t2, %sum; \ bcc,pt %xcc, 33f; \ - stx t2, [dest + off + 0x10]; \ - add sum, 1, sum; \ -33: addcc sum, t3, sum; \ + stx t2, [%dst + off + 0x10]; \ + add %sum, 1, %sum; \ +33: addcc %sum, t3, %sum; \ bcc,pt %xcc, 34f; \ - stx t3, [dest + off + 0x18]; \ - add sum, 1, sum; \ -34: addcc sum, t4, sum; \ + stx t3, [%dst + off + 0x18]; \ + add %sum, 1, %sum; \ +34: addcc %sum, t4, %sum; \ bcc,pt %xcc, 35f; \ - stx t4, [dest + off + 0x20]; \ - add sum, 1, sum; \ -35: addcc sum, t5, sum; \ + stx t4, [%dst + off + 0x20]; \ + add %sum, 1, %sum; \ +35: addcc %sum, t5, %sum; \ bcc,pt %xcc, 36f; \ - stx t5, [dest + off + 0x28]; \ - add sum, 1, sum; \ -36: addcc sum, t6, sum; \ + stx t5, [%dst + off + 0x28]; \ + add %sum, 1, %sum; \ +36: addcc %sum, t6, %sum; \ bcc,pt %xcc, 37f; \ - stx t6, [dest + off + 0x30]; \ - add sum, 1, sum; \ -37: addcc sum, t7, sum; \ + stx t6, [%dst + off + 0x30]; \ + add %sum, 1, %sum; \ +37: addcc %sum, t7, %sum; \ bcc,pt %xcc, 38f; \ - stx t7, [dest + off + 0x38]; \ - add sum, 1, sum; \ + stx t7, [%dst + off + 0x38]; \ + add %sum, 1, %sum; \ 38: -#define CSUMCOPY_EC_STUNALIGN(dest, off, sum, t0, t1, t2, t3, t4, t5, t6, t7) \ - stw t0, [dest + off + 0x04]; \ - addcc sum, t0, sum; \ +#define CSUMCOPY_EC_STUNALIGN(off, t0, t1, t2, t3, t4, t5, t6, t7) \ + stw t0, [%dst + off + 0x04]; \ + addcc %sum, t0, %sum; \ srlx t0, 32, t0; \ bcc,pt %xcc, 41f; \ - stw t0, [dest + off + 0x00]; \ - add sum, 1, sum; \ -41: stw t1, [dest + off + 0x0c]; \ - addcc sum, t1, sum; \ + stw t0, [%dst + off + 0x00]; \ + add %sum, 1, %sum; \ +41: stw t1, [%dst + off + 0x0c]; \ + addcc %sum, t1, %sum; \ srlx t1, 32, t1; \ bcc,pt %xcc, 42f; \ - stw t1, [dest + off + 0x08]; \ - add sum, 1, sum; \ -42: stw t2, [dest + off + 0x14]; \ - addcc sum, t2, sum; \ + stw t1, [%dst + off + 0x08]; \ + add %sum, 1, %sum; \ +42: stw t2, [%dst + off + 0x14]; \ + addcc %sum, t2, %sum; \ srlx t2, 32, t2; \ bcc,pt %xcc, 43f; \ - stw t2, [dest + off + 0x10]; \ - add sum, 1, sum; \ -43: stw t3, [dest + off + 0x1c]; \ - addcc sum, t3, sum; \ + stw t2, [%dst + off + 0x10]; \ + add %sum, 1, %sum; \ +43: stw t3, [%dst + off + 0x1c]; \ + addcc %sum, t3, %sum; \ srlx t3, 32, t3; \ bcc,pt %xcc, 44f; \ - stw t3, [dest + off + 0x18]; \ - add sum, 1, sum; \ -44: stw t4, [dest + off + 0x24]; \ - addcc sum, t4, sum; \ + stw t3, [%dst + off + 0x18]; \ + add %sum, 1, %sum; \ +44: stw t4, [%dst + off + 0x24]; \ + addcc %sum, t4, %sum; \ srlx t4, 32, t4; \ bcc,pt %xcc, 45f; \ - stw t4, [dest + off + 0x20]; \ - add sum, 1, sum; \ -45: stw t5, [dest + off + 0x2c]; \ - addcc sum, t5, sum; \ + stw t4, [%dst + off + 0x20]; \ + add %sum, 1, %sum; \ +45: stw t5, [%dst + off + 0x2c]; \ + addcc %sum, t5, %sum; \ srlx t5, 32, t5; \ bcc,pt %xcc, 46f; \ - stw t5, [dest + off + 0x28]; \ - add sum, 1, sum; \ -46: stw t6, [dest + off + 0x34]; \ - addcc sum, t6, sum; \ + stw t5, [%dst + off + 0x28]; \ + add %sum, 1, %sum; \ +46: stw t6, [%dst + off + 0x34]; \ + addcc %sum, t6, %sum; \ srlx t6, 32, t6; \ bcc,pt %xcc, 47f; \ - stw t6, [dest + off + 0x30]; \ - add sum, 1, sum; \ -47: stw t7, [dest + off + 0x3c]; \ - addcc sum, t7, sum; \ + stw t6, [%dst + off + 0x30]; \ + add %sum, 1, %sum; \ +47: stw t7, [%dst + off + 0x3c]; \ + addcc %sum, t7, %sum; \ srlx t7, 32, t7; \ bcc,pt %xcc, 48f; \ - stw t7, [dest + off + 0x38]; \ - add sum, 1, sum; \ + stw t7, [%dst + off + 0x38]; \ + add %sum, 1, %sum; \ 48: -#define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1) \ - ldxa [src - off - 0x08] %asi, t0; \ - ldxa [src - off - 0x00] %asi, t1; \ +#define CSUMCOPY_LASTCHUNK(off, t0, t1) \ + ldxa [%src - off - 0x08] %asi, t0; \ + ldxa [%src - off - 0x00] %asi, t1; \ nop; nop; \ - addcc t0, sum, sum; \ - stw t0, [dst - off - 0x04]; \ + addcc t0, %sum, %sum; \ + stw t0, [%dst - off - 0x04]; \ srlx t0, 32, t0; \ bcc,pt %xcc, 51f; \ - stw t0, [dst - off - 0x08]; \ - add sum, 1, sum; \ -51: addcc t1, sum, sum; \ - stw t1, [dst - off + 0x04]; \ + stw t0, [%dst - off - 0x08]; \ + add %sum, 1, %sum; \ +51: addcc t1, %sum, %sum; \ + stw t1, [%dst - off + 0x04]; \ srlx t1, 32, t1; \ bcc,pt %xcc, 52f; \ - stw t1, [dst - off - 0x00]; \ - add sum, 1, sum; \ + stw t1, [%dst - off - 0x00]; \ + add %sum, 1, %sum; \ 52: +cpc_start: cc_end_cruft: - andcc %o3, 8, %g0 ! IEU1 Group + andcc %g7, 8, %g0 ! IEU1 Group be,pn %icc, 1f ! CTI - and %o3, 4, %g5 ! IEU0 - ldxa [%o0 + 0x00] %asi, %g2 ! Load Group - add %o1, 8, %o1 ! IEU0 - add %o0, 8, %o0 ! IEU1 - addcc %g2, %g7, %g7 ! IEU1 Group + 2 bubbles - stw %g2, [%o1 - 0x04] ! Store + and %g7, 4, %g5 ! IEU0 + ldxa [%src + 0x00] %asi, %g2 ! Load Group + add %dst, 8, %dst ! IEU0 + add %src, 8, %src ! IEU1 + addcc %g2, %sum, %sum ! IEU1 Group + 2 bubbles + stw %g2, [%dst - 0x04] ! Store srlx %g2, 32, %g2 ! IEU0 bcc,pt %xcc, 1f ! CTI Group - stw %g2, [%o1 - 0x08] ! Store - add %g7, 1, %g7 ! IEU0 + stw %g2, [%dst - 0x08] ! Store + add %sum, 1, %sum ! IEU0 1: brz,pt %g5, 1f ! CTI Group clr %g2 ! IEU0 - lduwa [%o0 + 0x00] %asi, %g2 ! Load - add %o1, 4, %o1 ! IEU0 Group - add %o0, 4, %o0 ! IEU1 - stw %g2, [%o1 - 0x04] ! Store Group + 2 bubbles + lduwa [%src + 0x00] %asi, %g2 ! Load + add %dst, 4, %dst ! IEU0 Group + add %src, 4, %src ! IEU1 + stw %g2, [%dst - 0x04] ! Store Group + 2 bubbles sllx %g2, 32, %g2 ! IEU0 -1: andcc %o3, 2, %g0 ! IEU1 +1: andcc %g7, 2, %g0 ! IEU1 be,pn %icc, 1f ! CTI Group clr %o4 ! IEU1 - lduha [%o0 + 0x00] %asi, %o4 ! Load - add %o0, 2, %o0 ! IEU0 Group - add %o1, 2, %o1 ! IEU1 - sth %o4, [%o1 - 0x2] ! Store Group + 2 bubbles + lduha [%src + 0x00] %asi, %o4 ! Load + add %src, 2, %src ! IEU0 Group + add %dst, 2, %dst ! IEU1 + sth %o4, [%dst - 0x2] ! Store Group + 2 bubbles sll %o4, 16, %o4 ! IEU0 -1: andcc %o3, 1, %g0 ! IEU1 +1: andcc %g7, 1, %g0 ! IEU1 be,pn %icc, 1f ! CTI Group clr %o5 ! IEU0 - lduba [%o0 + 0x00] %asi, %o5 ! Load - stb %o5, [%o1 + 0x00] ! Store Group + 2 bubbles + lduba [%src + 0x00] %asi, %o5 ! Load + stb %o5, [%dst + 0x00] ! Store Group + 2 bubbles sll %o5, 8, %o5 ! IEU0 1: or %g2, %o4, %o4 ! IEU1 or %o5, %o4, %o4 ! IEU0 Group - addcc %o4, %g7, %g7 ! IEU1 + addcc %o4, %sum, %sum ! IEU1 bcc,pt %xcc, ccfold ! CTI sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 Group b,pt %xcc, ccfold ! CTI - add %g7, 1, %g7 ! IEU1 + add %sum, 1, %sum ! IEU1 cc_fixit: bl,a,pn %icc, ccte ! CTI - andcc %g1, 0xf, %o3 ! IEU1 Group - andcc %o0, 1, %g0 ! IEU1 Group - bne,pn %icc, ccslow ! CTI - andcc %o0, 2, %g0 ! IEU1 Group + andcc %len, 0xf, %g7 ! IEU1 Group + andcc %src, 2, %g0 ! IEU1 Group be,pn %icc, 1f ! CTI - andcc %o0, 0x4, %g0 ! IEU1 Group - lduha [%o0 + 0x00] %asi, %g4 ! Load - sub %g1, 2, %g1 ! IEU0 - add %o0, 2, %o0 ! IEU0 Group - add %o1, 2, %o1 ! IEU1 + andcc %src, 0x4, %g0 ! IEU1 Group + lduha [%src + 0x00] %asi, %g4 ! Load + sub %len, 2, %len ! IEU0 + add %src, 2, %src ! IEU0 Group + add %dst, 2, %dst ! IEU1 sll %g4, 16, %g3 ! IEU0 Group + 1 bubble - addcc %g3, %g7, %g7 ! IEU1 + addcc %g3, %sum, %sum ! IEU1 bcc,pt %xcc, 0f ! CTI - srl %g7, 16, %g3 ! IEU0 Group + srl %sum, 16, %g3 ! IEU0 Group add %g3, 1, %g3 ! IEU0 4 clocks (mispredict) -0: andcc %o0, 0x4, %g0 ! IEU1 Group - sth %g4, [%o1 - 0x2] ! Store - sll %g7, 16, %g7 ! IEU0 +0: andcc %src, 0x4, %g0 ! IEU1 Group + sth %g4, [%dst - 0x2] ! Store + sll %sum, 16, %sum ! IEU0 sll %g3, 16, %g3 ! IEU0 Group - srl %g7, 16, %g7 ! IEU0 Group - or %g3, %g7, %g7 ! IEU0 Group (regdep) + srl %sum, 16, %sum ! IEU0 Group + or %g3, %sum, %sum ! IEU0 Group (regdep) 1: be,pt %icc, cc_dword_aligned ! CTI - andn %g1, 0xff, %g2 ! IEU1 - lduwa [%o0 + 0x00] %asi, %g4 ! Load Group - sub %g1, 4, %g1 ! IEU0 - add %o0, 4, %o0 ! IEU1 - add %o1, 4, %o1 ! IEU0 Group - addcc %g4, %g7, %g7 ! IEU1 Group + 1 bubble - stw %g4, [%o1 - 0x4] ! Store + andn %len, 0xff, %g2 ! IEU1 + lduwa [%src + 0x00] %asi, %g4 ! Load Group + sub %len, 4, %len ! IEU0 + add %src, 4, %src ! IEU1 + add %dst, 4, %dst ! IEU0 Group + addcc %g4, %sum, %sum ! IEU1 Group + 1 bubble + stw %g4, [%dst - 0x4] ! Store bcc,pt %xcc, cc_dword_aligned ! CTI - andn %g1, 0xff, %g2 ! IEU0 Group + andn %len, 0xff, %g2 ! IEU0 Group b,pt %xcc, cc_dword_aligned ! CTI 4 clocks (mispredict) - add %g7, 1, %g7 ! IEU0 + add %sum, 1, %sum ! IEU0 .align 32 - .globl __csum_partial_copy_sparc_generic, csum_partial_copy -csum_partial_copy: -__csum_partial_copy_sparc_generic: /* %o0=src, %o1=dest, %g1=len, %g7=sum */ - xorcc %o0, %o1, %o4 ! IEU1 Group - srl %g7, 0, %g7 ! IEU0 + .globl csum_partial_copy_sparc64 +csum_partial_copy_sparc64: /* %o0=src, %o1=dest, %o2=len, %o3=sum */ + xorcc %src, %dst, %o4 ! IEU1 Group + srl %sum, 0, %sum ! IEU0 andcc %o4, 3, %g0 ! IEU1 Group - srl %g1, 0, %g1 ! IEU0 + srl %len, 0, %len ! IEU0 + bne,pn %icc, ccslow ! CTI + andcc %src, 1, %g0 ! IEU1 Group bne,pn %icc, ccslow ! CTI - andcc %o0, 7, %g0 ! IEU1 Group + cmp %len, 256 ! IEU1 Group + bgeu,pt %icc, csum_partial_copy_vis ! CTI + andcc %src, 7, %g0 ! IEU1 Group be,pt %icc, cc_dword_aligned ! CTI - andn %g1, 0xff, %g2 ! IEU0 + andn %len, 0xff, %g2 ! IEU0 b,pt %xcc, cc_fixit ! CTI Group - cmp %g1, 6 ! IEU1 + cmp %len, 6 ! IEU1 cc_dword_aligned: brz,pn %g2, 3f ! CTI Group - andcc %o1, 4, %g0 ! IEU1 Group (brz uses IEU1) + andcc %dst, 4, %g0 ! IEU1 Group (brz uses IEU1) be,pn %icc, ccdbl + 4 ! CTI -5: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STUNALIGN_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STUNALIGN( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) +5: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STUNALIGN_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STUNALIGN_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STUNALIGN_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STUNALIGN( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) 10: - sub %g1, 256, %g1 ! IEU0 Group - add %o0, 256, %o0 ! IEU1 - andncc %g1, 0xff, %g0 ! IEU1 Group + sub %len, 256, %len ! IEU0 Group + add %src, 256, %src ! IEU1 + andncc %len, 0xff, %g0 ! IEU1 Group bne,pt %icc, 5b ! CTI - add %o1, 256, %o1 ! IEU0 -3: andcc %g1, 0xf0, %o2 ! IEU1 Group + add %dst, 256, %dst ! IEU0 +3: andcc %len, 0xf0, %g1 ! IEU1 Group ccmerge:be,pn %icc, ccte ! CTI - andcc %g1, 0xf, %o3 ! IEU1 Group - sll %o2, 2, %o4 ! IEU0 -13: rd %pc, %o5 ! LSU Group + 4 clocks - add %o0, %o2, %o0 ! IEU0 Group - sub %o5, %o4, %o5 ! IEU1 Group - jmpl %o5 + (12f - 13b), %g0 ! CTI Group brk forced - add %o1, %o2, %o1 ! IEU0 Group -cctbl: CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xe8,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xd8,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xc8,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xb8,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0xa8,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x98,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x88,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x78,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x68,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x58,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x48,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x38,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x28,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x18,%g2,%g3) - CSUMCOPY_LASTCHUNK(%o0,%o1,%g7,0x08,%g2,%g3) + andcc %len, 0xf, %g7 ! IEU1 Group + sll %g1, 2, %o4 ! IEU0 +13: sethi %hi(12f), %o5 ! IEU0 Group + add %src, %g1, %src ! IEU1 + sub %o5, %o4, %o5 ! IEU0 Group + jmpl %o5 + %lo(12f), %g0 ! CTI Group brk forced + add %dst, %g1, %dst ! IEU0 Group +cctbl: CSUMCOPY_LASTCHUNK(0xe8,%g2,%g3) + CSUMCOPY_LASTCHUNK(0xd8,%g2,%g3) + CSUMCOPY_LASTCHUNK(0xc8,%g2,%g3) + CSUMCOPY_LASTCHUNK(0xb8,%g2,%g3) + CSUMCOPY_LASTCHUNK(0xa8,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x98,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x88,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x78,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x68,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x58,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x48,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x38,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x28,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x18,%g2,%g3) + CSUMCOPY_LASTCHUNK(0x08,%g2,%g3) 12: - andcc %g1, 0xf, %o3 ! IEU1 Group + andcc %len, 0xf, %g7 ! IEU1 Group ccte: bne,pn %icc, cc_end_cruft ! CTI sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 -ccfold: sllx %g7, 32, %o0 ! IEU0 Group - addcc %g7, %o0, %o0 ! IEU1 Group (regdep) +ccfold: sllx %sum, 32, %o0 ! IEU0 Group + addcc %sum, %o0, %o0 ! IEU1 Group (regdep) srlx %o0, 32, %o0 ! IEU0 Group (regdep) bcs,a,pn %xcc, 1f ! CTI add %o0, 1, %o0 ! IEU1 4 clocks (mispredict) 1: retl ! CTI Group brk forced sllx %g4, 32,%g4 ! IEU0 Group -ccdbl: CSUMCOPY_ECACHE_LOAD( %o0, 0x00, %o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x40,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0x80,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STALIGNED_LDNXT(%o0,%o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) - CSUMCOPY_EC_STALIGNED( %o1,0xc0,%g7,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3) +ccdbl: CSUMCOPY_ECACHE_LOAD( 0x00,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STALIGNED_LDNXT(0x40,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STALIGNED_LDNXT(0x80,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STALIGNED_LDNXT(0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) + CSUMCOPY_EC_STALIGNED( 0xc0,%o4,%o5,%g2,%g3,%g4,%g5,%g1,%g7) 11: - sub %g1, 256, %g1 ! IEU0 Group - add %o0, 256, %o0 ! IEU1 - andncc %g1, 0xff, %g0 ! IEU1 Group + sub %len, 256, %len ! IEU0 Group + add %src, 256, %src ! IEU1 + andncc %len, 0xff, %g0 ! IEU1 Group bne,pt %icc, ccdbl ! CTI - add %o1, 256, %o1 ! IEU0 + add %dst, 256, %dst ! IEU0 b,pt %xcc, ccmerge ! CTI Group - andcc %g1, 0xf0, %o2 ! IEU1 + andcc %len, 0xf0, %g1 ! IEU1 ccslow: mov 0, %g5 - brlez,pn %g1, 4f - andcc %o0, 1, %o5 + brlez,pn %len, 4f + andcc %src, 1, %o5 be,a,pt %icc, 1f - srl %g1, 1, %o3 - sub %g1, 1, %g1 - lduba [%o0] %asi, %g5 - add %o0, 1, %o0 - stb %g5, [%o1] - srl %g1, 1, %o3 - add %o1, 1, %o1 -1: brz,a,pn %o3, 3f - andcc %g1, 1, %g0 - andcc %o0, 2, %g0 + srl %len, 1, %g7 + sub %len, 1, %len + lduba [%src] %asi, %g5 + add %src, 1, %src + stb %g5, [%dst] + srl %len, 1, %g7 + add %dst, 1, %dst +1: brz,a,pn %g7, 3f + andcc %len, 1, %g0 + andcc %src, 2, %g0 be,a,pt %icc, 1f - srl %o3, 1, %o3 - lduha [%o0] %asi, %o4 - sub %g1, 2, %g1 + srl %g7, 1, %g7 + lduha [%src] %asi, %o4 + sub %len, 2, %len srl %o4, 8, %g2 - sub %o3, 1, %o3 - stb %g2, [%o1] + sub %g7, 1, %g7 + stb %g2, [%dst] add %o4, %g5, %g5 - stb %o4, [%o1 + 1] - add %o0, 2, %o0 - srl %o3, 1, %o3 - add %o1, 2, %o1 -1: brz,a,pn %o3, 2f - andcc %g1, 2, %g0 - lda [%o0] %asi, %o4 + stb %o4, [%dst + 1] + add %src, 2, %src + srl %g7, 1, %g7 + add %dst, 2, %dst +1: brz,a,pn %g7, 2f + andcc %len, 2, %g0 + lduwa [%src] %asi, %o4 5: srl %o4, 24, %g2 srl %o4, 16, %g3 - stb %g2, [%o1] + stb %g2, [%dst] srl %o4, 8, %g2 - stb %g3, [%o1 + 1] - add %o0, 4, %o0 - stb %g2, [%o1 + 2] + stb %g3, [%dst + 1] + add %src, 4, %src + stb %g2, [%dst + 2] addcc %o4, %g5, %g5 - stb %o4, [%o1 + 3] - addc %g5, %g0, %g5 ! I am now to lazy to optimize this (question is if it - add %o1, 4, %o1 ! is worthy). Maybe some day - with the sll/srl - subcc %o3, 1, %o3 ! tricks + stb %o4, [%dst + 3] + addc %g5, %g0, %g5 + add %dst, 4, %dst + subcc %g7, 1, %g7 bne,a,pt %icc, 5b - lda [%o0] %asi, %o4 + lduwa [%src] %asi, %o4 sll %g5, 16, %g2 srl %g5, 16, %g5 srl %g2, 16, %g2 - andcc %g1, 2, %g0 + andcc %len, 2, %g0 add %g2, %g5, %g5 2: be,a,pt %icc, 3f - andcc %g1, 1, %g0 - lduha [%o0] %asi, %o4 - andcc %g1, 1, %g0 + andcc %len, 1, %g0 + lduha [%src] %asi, %o4 + andcc %len, 1, %g0 srl %o4, 8, %g2 - add %o0, 2, %o0 - stb %g2, [%o1] + add %src, 2, %src + stb %g2, [%dst] add %g5, %o4, %g5 - stb %o4, [%o1 + 1] - add %o1, 2, %o1 + stb %o4, [%dst + 1] + add %dst, 2, %dst 3: be,a,pt %icc, 1f sll %g5, 16, %o4 - lduba [%o0] %asi, %g2 + lduba [%src] %asi, %g2 sll %g2, 8, %o4 - stb %g2, [%o1] + stb %g2, [%dst] add %g5, %o4, %g5 sll %g5, 16, %o4 1: addcc %o4, %g5, %g5 @@ -484,8 +484,22 @@ ccslow: mov 0, %g5 and %o4, 0xff, %o4 sll %g2, 8, %g2 or %g2, %o4, %g5 -4: addcc %g7, %g5, %g7 - addc %g0, %g7, %o0 +4: addcc %sum, %g5, %sum + addc %g0, %sum, %o0 retl srl %o0, 0, %o0 -__csum_partial_copy_end: +cpc_end: + + .globl cpc_handler +cpc_handler: + ldx [%sp + 0x7ff + 128], %g1 + sub %g0, EFAULT, %g2 + brnz,a,pt %g1, 1f + st %g2, [%g1] +1: retl + nop + + .section __ex_table + .align 4 + .word cpc_start, 0, cpc_end, cpc_handler + diff --git a/arch/sparc64/lib/locks.S b/arch/sparc64/lib/locks.S index 74054f63a..7b2bdba62 100644 --- a/arch/sparc64/lib/locks.S +++ b/arch/sparc64/lib/locks.S @@ -1,4 +1,4 @@ -/* $Id: locks.S,v 1.3 1997/07/22 05:51:42 davem Exp $ +/* $Id: locks.S,v 1.5 1997/07/31 05:28:16 davem Exp $ * locks.S: SMP low-level lock primitives on Sparc64. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -12,9 +12,9 @@ .align 32 ___lk_busy_spin: - orcc %g2, 0, %g0 - bne,pt %icc, ___lk_busy_spin - ldub [%g1 + 0], %g2 + ldub [%g1 + 0], %g2 + brnz,pt %g2, ___lk_busy_spin + membar #LoadLoad b,pt %xcc, 1f ldstub [%g1 + 0], %g2 @@ -23,16 +23,15 @@ ___lock_kernel: addcc %g2, -1, %g2 rdpr %pil, %g3 bcs,a,pn %icc, 9f - st %g2, [%g6 + AOFF_task_lock_depth] + stw %g2, [%g6 + AOFF_task_lock_depth] wrpr %g0, 15, %pil ldstub [%g1 + 0], %g2 -1: brnz,a,pn %g2, ___lk_busy_spin - ldub [%g1 + 0], %g2 +1: brnz,pn %g2, ___lk_busy_spin + membar #StoreLoad | #StoreStore lduw [%g6 + AOFF_task_processor], %g2 - membar #LoadLoad | #LoadStore stb %g2, [%g1 + 1] 2: mov -1, %g2 - st %g2, [%g6 + AOFF_task_lock_depth] + stw %g2, [%g6 + AOFF_task_lock_depth] wrpr %g3, 0, %pil 9: jmpl %o7 + 0x8, %g0 mov %g5, %o7 @@ -41,16 +40,16 @@ ___lock_kernel: ___lock_reacquire_kernel: rdpr %pil, %g3 wrpr %g0, 15, %pil - st %g2, [%g6 + AOFF_task_lock_depth] + stw %g2, [%g6 + AOFF_task_lock_depth] ldstub [%g1 + 0], %g2 1: brz,pt %g2, 3f - ldub [%g1 + 0], %g2 -2: brnz,a,pt %g2, 2b - ldub [%g1 + 0], %g2 + membar #StoreLoad | #StoreStore +2: ldub [%g1 + 0], %g2 + brnz,pt %g2, 2b + membar #LoadLoad b,pt %xcc, 1b ldstub [%g1 + 0], %g2 3: lduw [%g6 + AOFF_task_processor], %g2 - membar #LoadLoad | #LoadStore stb %g2, [%g1 + 1] wrpr %g3, 0, %pil jmpl %o7 + 0x8, %g0 diff --git a/arch/sparc64/lib/strlen_user.S b/arch/sparc64/lib/strlen_user.S index ef6cee5a6..9ae3d0381 100644 --- a/arch/sparc64/lib/strlen_user.S +++ b/arch/sparc64/lib/strlen_user.S @@ -78,11 +78,11 @@ __strlen_user: clr %o0 .section __ex_table,#alloc - .align 8 + .align 4 - .xword 10b, 30b - .xword 11b, 30b - .xword 12b, 30b - .xword 15b, 30b - .xword 13b, 30b - .xword 14b, 30b + .word 10b, 30b + .word 11b, 30b + .word 12b, 30b + .word 15b, 30b + .word 13b, 30b + .word 14b, 30b diff --git a/arch/sparc64/lib/strncpy_from_user.S b/arch/sparc64/lib/strncpy_from_user.S index 7a5dc768f..e0fb0f09b 100644 --- a/arch/sparc64/lib/strncpy_from_user.S +++ b/arch/sparc64/lib/strncpy_from_user.S @@ -49,6 +49,6 @@ __strncpy_from_user: mov -EFAULT, %o0 .section __ex_table,#alloc - .align 8 - .xword 10b, 4b - .xword 11b, 4b + .align 4 + .word 10b, 4b + .word 11b, 4b diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 5e16e1218..6bc52f3eb 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.18 1997/07/17 02:20:56 davem Exp $ +/* $Id: fault.c,v 1.20 1997/08/04 16:16:51 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -217,56 +217,3 @@ bad_area: out: unlock_kernel(); } - -void fixup_dcache_alias(struct vm_area_struct *vma, unsigned long address, pte_t pte) -{ - struct vm_area_struct *vmaring; - struct inode *inode; - unsigned long vaddr, offset, start; - pgd_t *pgdp; - pmd_t *pmdp; - pte_t *ptep; - int alias_found = 0; - - inode = vma->vm_dentry->d_inode; - if(!inode) - return; - - offset = (address & PAGE_MASK) - vma->vm_start; - vmaring = inode->i_mmap; - do { - vaddr = vmaring->vm_start + offset; - - /* This conditional is misleading... */ - if((vaddr ^ address) & PAGE_SIZE) { - alias_found++; - start = vmaring->vm_start; - while(start < vmaring->vm_end) { - pgdp = pgd_offset(vmaring->vm_mm, start); - if(!pgdp) goto next; - pmdp = pmd_offset(pgdp, start); - if(!pmdp) goto next; - ptep = pte_offset(pmdp, start); - if(!ptep) goto next; - - if(pte_val(*ptep) & _PAGE_PRESENT) { - flush_cache_page(vmaring, start); - *ptep = __pte(pte_val(*ptep) & - ~(_PAGE_CV)); - flush_tlb_page(vmaring, start); - } - next: - start += PAGE_SIZE; - } - } - } while((vmaring = vmaring->vm_next_share) != NULL); - - if(alias_found && (pte_val(pte) & _PAGE_CV)) { - pgdp = pgd_offset(vma->vm_mm, address); - pmdp = pmd_offset(pgdp, address); - ptep = pte_offset(pmdp, address); - flush_cache_page(vma, address); - *ptep = __pte(pte_val(*ptep) & ~(_PAGE_CV)); - flush_tlb_page(vma, address); - } -} diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 386c8540f..4a7a1bce1 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.40 1997/07/24 16:48:27 davem Exp $ +/* $Id: init.c,v 1.55 1997/08/24 01:22:29 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -37,6 +37,18 @@ unsigned long tlb_context_cache = CTX_FIRST_VERSION; /* References to section boundaries */ extern char __init_begin, __init_end, etext, __bss_start; +extern void __bfill64(void *, unsigned long *); + +static __inline__ void __init_pmd(pmd_t *pmdp) +{ + __bfill64((void *)pmdp, &null_pte_table); +} + +static __inline__ void __init_pgd(pgd_t *pgdp) +{ + __bfill64((void *)pgdp, &null_pmd_table); +} + /* * BAD_PAGE is the page that is used for page faults when linux * is out-of-memory. Older versions of linux just did a @@ -103,48 +115,72 @@ void show_mem(void) /* IOMMU support, the ideas are right, the code should be cleaned a bit still... */ -/* XXX Also, play with the streaming buffers at some point, both - * XXX Fusion and Sunfire both have them aparently... -DaveM - */ - /* This keeps track of pages used in sparc_alloc_dvma() invocations. */ static unsigned long dvma_map_pages[0x10000000 >> 16] = { 0, }; static unsigned long dvma_pages_current_offset = 0; static int dvma_pages_current_index = 0; +/* #define E3000_DEBUG */ + __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, unsigned long memory_end, struct linux_sbus *sbus)) { struct iommu_struct *iommu; struct sysio_regs *sregs; - struct linux_prom_registers rprop[2]; + struct linux_prom64_registers rprop; unsigned long impl, vers; unsigned long control, tsbbase; unsigned long *iopte; + u32 rlow, rhigh; int err, i; - err = prom_getproperty(iommu_node, "reg", (char *)rprop, +#ifdef E3000_DEBUG + prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ", + iommu_node, memory_start, memory_end, sbus); +#endif + err = prom_getproperty(iommu_node, "reg", (char *)&rprop, sizeof(rprop)); if(err == -1) { prom_printf("iommu_init: Cannot map SYSIO control registers.\n"); prom_halt(); } - sregs = (struct sysio_regs *) sparc_alloc_io(rprop[0].phys_addr, - (void *)0, + rlow = (rprop.phys_addr & 0xffffffff); + rhigh = (rprop.phys_addr >> 32); +#ifdef E3000_DEBUG + prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh); +#endif + sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0, sizeof(struct sysio_regs), - "SYSIO Regs", - rprop[0].which_io, 0x0); + "SYSIO Regs", rhigh, 0x0); +#ifdef E3000_DEBUG + prom_printf("sregs[%p]\n"); +#endif + if(!sregs) { + prom_printf("iommu_init: Fatal error, sysio regs not mapped\n"); + prom_halt(); + } memory_start = (memory_start + 7) & ~7; iommu = (struct iommu_struct *) memory_start; memory_start += sizeof(struct iommu_struct); + +#ifdef E3000_DEBUG + prom_printf("iommu_init: iommu[%p] ", iommu); +#endif + + spin_lock_init(&iommu->iommu_lock); iommu->sysio_regs = sregs; sbus->iommu = iommu; control = sregs->iommu_control; impl = (control & IOMMU_CTRL_IMPL) >> 60; vers = (control & IOMMU_CTRL_VERS) >> 56; - printk("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", +#ifdef E3000_DEBUG + prom_printf("sreg_control[%08x]\n", control); + prom_printf("IOMMU: IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", + (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); +#endif + printk("IOMMU(SBUS): IMPL[%x] VERS[%x] SYSIO mapped at %016lx\n", (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); control &= ~(IOMMU_CTRL_TSBSZ); @@ -168,7 +204,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, /* Setup aliased mappings... */ for(i = 0; i < (65536 - 4096); i++) { - *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); + *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF | + IOPTE_CACHE | IOPTE_WRITE); *iopte |= (i << 16); iopte++; } @@ -177,15 +214,47 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, for( ; i < 65536; i++) *iopte++ = 0; +#ifdef E3000_DEBUG + prom_printf("IOMMU: pte's mapped, enabling IOMMU... "); +#endif sregs->iommu_tsbbase = __pa(tsbbase); sregs->iommu_control = control; +#ifdef E3000_DEBUG + prom_printf("done\n"); +#endif + /* Get the streaming buffer going. */ + control = sregs->sbuf_control; + impl = (control & SYSIO_SBUFCTRL_IMPL) >> 60; + vers = (control & SYSIO_SBUFCTRL_REV) >> 56; +#ifdef E3000_DEBUG + prom_printf("IOMMU: enabling streaming buffer, control[%08x]... ", + control); +#endif + printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ", + (unsigned int)impl, (unsigned int)vers); + printk("FlushFLAG[%p,%016lx] ... ", + (iommu->sbuf_flushflag_va = (unsigned int *)memory_start), + (iommu->sbuf_flushflag_pa = __pa(memory_start))); + *(iommu->sbuf_flushflag_va) = 0; + memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */ + + sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN); + +#ifdef E3000_DEBUG + prom_printf("done, returning %016lx\n", memory_start); +#endif + printk("ENABLED\n"); + + /* Finally enable DVMA arbitration for all devices, just in case. */ + sregs->sbus_control |= SYSIO_SBCNTRL_AEN; + return memory_start; } -void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr) +void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, + struct linux_sbus *sbus) { - struct iommu_struct *iommu = SBus_chain->iommu; /* GROSS ME OUT! */ pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; @@ -193,6 +262,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr) /* Find out if we need to grab some pages. */ if(!dvma_map_pages[dvma_pages_current_index] || ((dvma_pages_current_offset + len) > (1 << 16))) { + struct linux_sbus *sbus; unsigned long *iopte; unsigned long newpages = __get_free_pages(GFP_KERNEL, 3, 0); int i; @@ -212,9 +282,16 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr) /* Stick it in the IOMMU. */ i = (65536 - 4096) + i; - iopte = (unsigned long *)(iommu->page_table + i); - *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); - *iopte |= __pa(newpages); + for_each_sbus(sbus) { + struct iommu_struct *iommu = sbus->iommu; + unsigned long flags; + + spin_lock_irqsave(&iommu->iommu_lock, flags); + iopte = (unsigned long *)(iommu->page_table + i); + *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_CACHE | IOPTE_WRITE); + *iopte |= __pa(newpages); + spin_unlock_irqrestore(&iommu->iommu_lock, flags); + } } /* Get this out of the way. */ @@ -258,6 +335,33 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) return (__u32)0; } +void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) +{ + struct iommu_struct *iommu = sbus->iommu; + struct sysio_regs *sregs = iommu->sysio_regs; + unsigned long start = (unsigned long) vaddr; + unsigned long end = PAGE_ALIGN(start + len); + unsigned long flags; + unsigned int *sync_word; + + start &= PAGE_MASK; + + spin_lock_irqsave(&iommu->iommu_lock, flags); + + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + sync_word = iommu->sbuf_flushflag_va; + sregs->sbuf_fsync = iommu->sbuf_flushflag_pa; + membar("#StoreLoad | #MemIssue"); + while((*sync_word & 0x1) == 0) + membar("#LoadLoad"); + *sync_word = 0; + + spin_unlock_irqrestore(&iommu->iommu_lock, flags); +} + void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { while(sz >= 0) { @@ -273,6 +377,36 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) } } +void mmu_release_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) +{ + struct iommu_struct *iommu = sbus->iommu; + struct sysio_regs *sregs = iommu->sysio_regs; + unsigned long flags; + unsigned int *sync_word; + + spin_lock_irqsave(&iommu->iommu_lock, flags); + + while(sz >= 0) { + unsigned long start = sg[sz].dvma_addr; + unsigned long end = PAGE_ALIGN(start + sg[sz].len); + + start &= PAGE_MASK; + while(start < end) { + sregs->sbuf_pflush = start; + start += PAGE_SIZE; + } + sz--; + } + sync_word = iommu->sbuf_flushflag_va; + sregs->sbuf_fsync = iommu->sbuf_flushflag_pa; + membar("#StoreLoad | #MemIssue"); + while((*sync_word & 0x1) == 0) + membar("#LoadLoad"); + *sync_word = 0; + + spin_unlock_irqrestore(&iommu->iommu_lock, flags); +} + static char sfmmuinfo[512]; char *mmu_info(void) @@ -340,7 +474,7 @@ int prom_itlb_ent, prom_dtlb_ent; unsigned long prom_itlb_tag, prom_itlb_data; unsigned long prom_dtlb_tag, prom_dtlb_data; -static inline void inherit_locked_prom_mappings(void) +void inherit_locked_prom_mappings(int save_p) { int i; int dtlb_seen = 0; @@ -367,9 +501,12 @@ static inline void inherit_locked_prom_mappings(void) data = spitfire_get_dtlb_data(i); if(!dtlb_seen && (data & _PAGE_L)) { unsigned long tag = spitfire_get_dtlb_tag(i); - prom_dtlb_ent = i; - prom_dtlb_tag = tag; - prom_dtlb_data = data; + + if(save_p) { + prom_dtlb_ent = i; + prom_dtlb_tag = tag; + prom_dtlb_data = data; + } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); membar("#Sync"); @@ -390,9 +527,12 @@ static inline void inherit_locked_prom_mappings(void) data = spitfire_get_itlb_data(i); if(!itlb_seen && (data & _PAGE_L)) { unsigned long tag = spitfire_get_itlb_tag(i); - prom_itlb_ent = i; - prom_itlb_tag = tag; - prom_itlb_data = data; + + if(save_p) { + prom_itlb_ent = i; + prom_itlb_tag = tag; + prom_itlb_data = data; + } __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); membar("#Sync"); @@ -443,10 +583,14 @@ void __flush_cache_all(void) /* If not locked, zap it. */ void __flush_tlb_all(void) { - unsigned long flags; + unsigned long pstate; int i; - save_flags(flags); cli(); + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate\n\t" + "flushw" + : "=r" (pstate) + : "i" (PSTATE_IE)); for(i = 0; i < 64; i++) { if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) { __asm__ __volatile__("stxa %%g0, [%0] %1" @@ -465,19 +609,67 @@ void __flush_tlb_all(void) membar("#Sync"); } } - restore_flags(flags); + __asm__ __volatile__("wrpr %0, 0, %%pstate" + : : "r" (pstate)); } -void get_new_mmu_context(struct mm_struct *mm, unsigned long ctx) +/* We are always protected by scheduler_lock under SMP. */ +void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx) { - if((ctx & ~(CTX_VERSION_MASK)) == 0) { - flush_tlb_all(); - ctx = (ctx & CTX_VERSION_MASK) + CTX_FIRST_VERSION; - if(ctx == 1) - ctx = CTX_FIRST_VERSION; + unsigned int new_ctx = *ctx; + + if((new_ctx & ~(CTX_VERSION_MASK)) == 0) { + new_ctx += CTX_FIRST_VERSION; + if(new_ctx == 1) + new_ctx = CTX_FIRST_VERSION; + *ctx = new_ctx; + DO_LOCAL_FLUSH(smp_processor_id()); } - tlb_context_cache = ctx + 1; - mm->context = ctx; + mm->context = new_ctx; + mm->cpu_vm_mask = 0; /* Callers sets it properly. */ + (*ctx)++; +} + +#ifndef __SMP__ +unsigned long *pgd_quicklist = NULL; +unsigned long *pmd_quicklist = NULL; +unsigned long *pte_quicklist = NULL; +unsigned long pgtable_cache_size = 0; +#endif + +pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd; + + pgd = (pgd_t *) __get_free_page(GFP_KERNEL); + if(pgd) + __init_pgd(pgd); + return pgd; +} + +pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) +{ + pmd_t *pmd; + + pmd = (pmd_t *) __get_free_page(GFP_KERNEL); + if(pmd) { + __init_pmd(pmd); + pgd_set(pgd, pmd); + return pmd + offset; + } + return NULL; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) get_free_page(GFP_KERNEL); + if(pte) { + pmd_set(pmd, pte); + return pte + offset; + } + return NULL; } __initfunc(static void @@ -595,7 +787,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) */ pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB; pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; - save_flags(flags); cli(); + __save_and_cli(flags); __asm__ __volatile__(" stxa %1, [%0] %3 stxa %2, [%5] %4 @@ -608,15 +800,18 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) : "r" (TLB_TAG_ACCESS), "r" (alias_base), "r" (pt), "i" (ASI_DMMU), "i" (ASI_DTLB_DATA_ACCESS), "r" (61 << 3) : "memory"); - restore_flags(flags); + __restore_flags(flags); /* Now set kernel pgd to upper alias so physical page computations * work. */ init_mm.pgd += ((shift) / (sizeof(pgd_t *))); - null_pmd_table = __pa(((unsigned long)&empty_null_pmd_table) + shift); - null_pte_table = __pa(((unsigned long)&empty_null_pte_table) + shift); + /* The funny offsets are to make page table operations much quicker and + * requite less state, see pgtable.h for gory details. + */ + null_pmd_table=__pa(((unsigned long)&empty_null_pmd_table)+shift); + null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift); pmdp = (pmd_t *) &empty_null_pmd_table; for(i = 0; i < 1024; i++) @@ -658,7 +853,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) flushi((long)&empty_zero_page); membar("#Sync"); - inherit_locked_prom_mappings(); + inherit_locked_prom_mappings(1); flush_tlb_all(); diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 18f9a363d..ec96e8871 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.9 1997/07/24 12:15:08 davem Exp $ +/* $Id: ultra.S,v 1.3 1997/08/30 04:53:20 ralf Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -13,28 +13,26 @@ .align 32 .globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page __flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */ - rdpr %otherwin, %g1 - brz,pt %g1, 1f - mov %o7, %g3 - call __flushw_user - clr %g2 -1: rdpr %pil, %g1 -9: mov SECONDARY_CONTEXT, %g7 - wrpr %g0, 15, %pil - - ldxa [%g7] ASI_DMMU, %g2 + mov SECONDARY_CONTEXT, %g7 +9: ldxa [%g7] ASI_DMMU, %g2 cmp %g2, %o0 - be,pt %icc, 1f + bne,pn %icc, 1f mov 0x50, %g3 + stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + retl + flush %g6 +1: rdpr %pstate, %g1 + wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%g7] ASI_DMMU -1: stxa %g0, [%g3] ASI_DMMU_DEMAP - be,pt %icc, 1f - stxa %g0, [%g3] ASI_IMMU_DEMAP - + stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + flush %g6 stxa %g2, [%g7] ASI_DMMU -1: wrpr %g1, 0x0, %pil + flush %g6 retl - flush %g6 + wrpr %g1, 0, %pstate + nop __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */ sethi %hi(8192 - 1), %g5 or %g5, %lo(8192 - 1), %g5 @@ -43,19 +41,13 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */ sub %o2, %o1, %o3 add %g5, 1, %g5 - orcc %o1, 0x50, %o1 + orcc %o1, 0x10, %o1 srlx %o3, 13, %o4 - rdpr %otherwin, %g1 - brz,pt %g1, 1f - mov %o7, %g3 - call __flushw_user - - clr %g2 -1: cmp %o4, 96 + cmp %o4, 96 bgu,pn %icc, 9b - rdpr %pil, %g1 - mov SECONDARY_CONTEXT, %g7 - wrpr %g0, 15, %pil + mov SECONDARY_CONTEXT, %g7 + rdpr %pstate, %g1 + wrpr %g1, PSTATE_IE, %pstate ldxa [%g7] ASI_DMMU, %g2 cmp %g2, %o0 @@ -66,37 +58,37 @@ __flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */ stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP brnz,pt %o3, 1b sub %o3, %g5, %o3 - nop + flush %g6 - be,pt %icc, 1f - wrpr %g1, 0x0, %pil + be,a,pt %icc, 1f + nop stxa %g2, [%g7] ASI_DMMU -1: retl - flush %g6 +1: flush %g6 + wrpr %g1, 0, %pstate + retl + nop .align 32 __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */ - rdpr %otherwin, %g1 - brz,pt %g1, 1f - mov %o7, %g3 - call __flushw_user - clr %g2 -1: rdpr %pil, %g1 mov SECONDARY_CONTEXT, %g7 - wrpr %g0, 15, %pil - ldxa [%g7] ASI_DMMU, %g2 cmp %g2, %o0 be,pt %icc, 1f or %o1, 0x10, %g3 + stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + retl + flush %g6 +1: rdpr %pstate, %g1 + wrpr %g1, PSTATE_IE, %pstate stxa %o0, [%g7] ASI_DMMU -1: stxa %g0, [%g3] ASI_DMMU_DEMAP - be,pt %icc, 1f - stxa %g0, [%g3] ASI_IMMU_DEMAP + stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + flush %g6 stxa %g2, [%g7] ASI_DMMU -1: wrpr %g1, 0x0, %pil + flush %g6 retl - flush %g6 + wrpr %g1, 0, %pstate #ifdef __SMP__ /* These are all called by the slaves of a cross call, at @@ -111,50 +103,29 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */ * %g2 scratch 1 * %g3 scratch 2 * %g4 scratch 3 - * - * NOTE: We do not acknowledge the UPA until we are done - * with the service. This is what tells the master - * that he can consider the effects of the flush - * "complete" on this cpu. */ .align 32 - .globl xcall_flush_tlb_page + .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range xcall_flush_tlb_page: mov SECONDARY_CONTEXT, %g2 - nop + or %g6, 0x10, %g4 ldxa [%g2] ASI_DMMU, %g3 - cmp %g3, %g5 - be,pt %icc, 1f - or %g6, 0x10, %g4 stxa %g5, [%g2] ASI_DMMU -1: stxa %g0, [%g4] ASI_DMMU_DEMAP - - be,pt %icc, 1f - stxa %g0, [%g4] ASI_IMMU_DEMAP + stxa %g0, [%g4] ASI_DMMU_DEMAP + stxa %g0, [%g4] ASI_IMMU_DEMAP stxa %g3, [%g2] ASI_DMMU -1: b,pt %xcc, do_ivec_return - flush %g1 + retry - .align 32 - .globl xcall_flush_tlb_mm xcall_flush_tlb_mm: mov SECONDARY_CONTEXT, %g2 - nop + mov 0x50, %g4 ldxa [%g2] ASI_DMMU, %g3 - cmp %g3, %g5 - be,pt %icc, 1f - mov 0x50, %g4 stxa %g5, [%g2] ASI_DMMU -1: stxa %g0, [%g4] ASI_DMMU_DEMAP - - be,pt %icc, 1f - stxa %g0, [%g4] ASI_IMMU_DEMAP + stxa %g0, [%g4] ASI_DMMU_DEMAP + stxa %g0, [%g4] ASI_IMMU_DEMAP stxa %g3, [%g2] ASI_DMMU -1: b,pt %xcc, do_ivec_return - flush %g1 + retry - .align 32 - .globl xcall_flush_tlb_range xcall_flush_tlb_range: sethi %hi(8192 - 1), %g2 or %g2, %lo(8192 - 1), %g2 @@ -162,26 +133,54 @@ xcall_flush_tlb_range: andn %g7, %g2, %g7 sub %g7, %g6, %g3 add %g2, 1, %g2 - orcc %g6, 0x50, %g6 + orcc %g6, 0x10, %g6 srlx %g3, 13, %g4 cmp %g4, 96 bgu,pn %icc, xcall_flush_tlb_mm mov SECONDARY_CONTEXT, %g4 ldxa [%g4] ASI_DMMU, %g7 - cmp %g7, %g5 - be,pt %icc, 1f - sub %g3, %g2, %g3 + sub %g3, %g2, %g3 stxa %g5, [%g4] ASI_DMMU + nop + nop 1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP brnz,pt %g3, 1b sub %g3, %g2, %g3 - bne,a,pn %icc, 1f - stxa %g7, [%g4] ASI_DMMU -1: b,pt %xcc, do_ivec_return - flush %g1 + stxa %g7, [%g4] ASI_DMMU + retry + nop + nop + + .globl xcall_report_regs +xcall_report_regs: + rdpr %pstate, %g2 + wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate + rdpr %pil, %g2 + wrpr %g0, 15, %pil + sethi %hi(109f), %g7 + b,pt %xcc, etrap_irq +109: or %g7, %lo(109b), %g7 + call __show_regs + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + b,pt %xcc, rtrap + clr %l6 + + .globl xcall_capture +xcall_capture: + rdpr %pstate, %g2 + wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate + rdpr %pil, %g2 + wrpr %g0, 15, %pil + sethi %hi(109f), %g7 + b,pt %xcc, etrap_irq +109: or %g7, %lo(109b), %g7 + call smp_penguin_jailcell + nop + b,pt %xcc, rtrap + clr %l6 /* These two are not performance critical... */ .globl xcall_flush_tlb_all @@ -209,8 +208,8 @@ xcall_flush_tlb_all: cmp %g2, 63 ble,pt %icc, 1b sll %g2, 3, %g3 - b,pt %xcc, do_ivec_return - flush %g1 + flush %g1 + retry .globl xcall_flush_cache_all xcall_flush_cache_all: @@ -222,6 +221,6 @@ xcall_flush_cache_all: cmp %g3, %g2 bleu,pt %xcc, 1b nop - b,pt %xcc, do_ivec_return - flush %g1 + flush %g1 + retry #endif /* __SMP__ */ diff --git a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c index 40b33da4b..80ba5ec10 100644 --- a/arch/sparc64/prom/console.c +++ b/arch/sparc64/prom/console.c @@ -1,4 +1,4 @@ -/* $Id: console.c,v 1.7 1997/07/19 08:28:29 ecd Exp $ +/* $Id: console.c,v 1.8 1997/08/16 08:00:16 davem Exp $ * console.c: Routines that deal with sending and receiving IO * to/from the current console device using the PROM. * @@ -85,13 +85,13 @@ prom_query_input_device() if(prom_node_has_property(st_p, "keyboard")) return PROMDEV_IKBD; prom_getproperty(st_p, "device_type", propb, sizeof(propb)); - if(strncmp(propb, "serial", sizeof("serial"))) + if(strncmp(propb, "serial", 6)) return PROMDEV_I_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "input-device", propb, sizeof(propb)); - if (strncmp (propb, "tty", 3) || !propb[3] || propb[4]) + if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_I_UNK; switch (propb[3]) { case 'a': return PROMDEV_ITTYA; @@ -114,13 +114,13 @@ prom_query_output_device() if (propl >= 0 && propl == sizeof("display") && strncmp("display", propb, sizeof("display")) == 0) return PROMDEV_OSCREEN; - if(strncmp("serial", propb, sizeof("serial"))) + if(strncmp("serial", propb, 6)) return PROMDEV_O_UNK; /* FIXME: Is there any better way how to find out? */ memset(propb, 0, sizeof(propb)); st_p = prom_finddevice ("/options"); prom_getproperty(st_p, "output-device", propb, sizeof(propb)); - if (strncmp (propb, "tty", 3) || !propb[3] || propb[4]) + if (strncmp (propb, "tty", 3) || !propb[3]) return PROMDEV_O_UNK; switch (propb[3]) { case 'a': return PROMDEV_OTTYA; diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index 0703b5cd7..9c5bce294 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.11 1997/07/24 12:15:11 davem Exp $ +/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -64,7 +64,7 @@ long p1275_cmd (char *service, long fmt, ...) long ctx = 0; p = p1275buf.prom_buffer; - save_and_cli(flags); + __save_and_cli(flags); ctx = spitfire_get_primary_context (); if (ctx) { flushw_user (); @@ -149,7 +149,7 @@ long p1275_cmd (char *service, long fmt, ...) if (ctx) spitfire_set_primary_context (ctx); - restore_flags(flags); + __restore_flags(flags); return x; } diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c index 323539237..83f860d45 100644 --- a/arch/sparc64/prom/ranges.c +++ b/arch/sparc64/prom/ranges.c @@ -1,15 +1,21 @@ -/* $Id: ranges.c,v 1.3 1997/03/21 12:33:36 jj Exp $ +/* $Id: ranges.c,v 1.8 1997/08/17 22:39:45 ecd Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include <linux/config.h> #include <linux/init.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/sbus.h> +#include <asm/fhc.h> #include <asm/system.h> +#ifdef CONFIG_PCI +#include <asm/pbm.h> +#include <asm/ebus.h> +#endif struct linux_prom_ranges promlib_obio_ranges[PROMREG_MAX]; int num_obio_ranges; @@ -62,6 +68,25 @@ void prom_apply_sbus_ranges(struct linux_sbus *sbus, struct linux_prom_registers } } +/* Apply probed fhc ranges to registers passed, if no ranges return. */ +void prom_apply_fhc_ranges(struct linux_fhc *fhc, + struct linux_prom_registers *regs, + int nregs) +{ + if(fhc->num_fhc_ranges) + prom_adjust_regs(regs, nregs, fhc->fhc_ranges, + fhc->num_fhc_ranges); +} + +/* Apply probed central ranges to registers passed, if no ranges return. */ +void prom_apply_central_ranges(struct linux_central *central, + struct linux_prom_registers *regs, int nregs) +{ + if(central->num_central_ranges) + prom_adjust_regs(regs, nregs, central->central_ranges, + central->num_central_ranges); +} + __initfunc(void prom_ranges_init(void)) { } @@ -78,6 +103,56 @@ __initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus)) sbus->num_sbus_ranges = (success/sizeof(struct linux_prom_ranges)); } +__initfunc(void prom_central_ranges_init(int cnode, struct linux_central *central)) +{ + int success; + + central->num_central_ranges = 0; + success = prom_getproperty(central->prom_node, "ranges", + (char *) central->central_ranges, + sizeof (central->central_ranges)); + if (success != -1) + central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc)) +{ + int success; + + fhc->num_fhc_ranges = 0; + success = prom_getproperty(fhc->prom_node, "ranges", + (char *) fhc->fhc_ranges, + sizeof (fhc->fhc_ranges)); + if (success != -1) + fhc->num_fhc_ranges = (success/sizeof(struct linux_prom_ranges)); +} + +#ifdef CONFIG_PCI +__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus)) +{ + int success; + + ebus->num_ebus_ranges = 0; + success = prom_getproperty(ebus->prom_node, "ranges", + (char *)ebus->ebus_ranges, + sizeof(ebus->ebus_ranges)); + if (success != -1) + ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); +} + +__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm)) +{ + int success; + + pbm->num_pbm_ranges = 0; + success = prom_getproperty(pbm->prom_node, "ranges", + (char *)&pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if(success != -1) + pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges)); +} +#endif + void prom_apply_generic_ranges (int node, int parent, struct linux_prom_registers *regs, int nregs) { diff --git a/arch/sparc64/prom/tree.c b/arch/sparc64/prom/tree.c index ae4baf858..c2b386641 100644 --- a/arch/sparc64/prom/tree.c +++ b/arch/sparc64/prom/tree.c @@ -1,4 +1,4 @@ -/* $Id: tree.c,v 1.5 1997/03/24 17:44:01 jj Exp $ +/* $Id: tree.c,v 1.6 1997/08/12 16:32:48 davem Exp $ * tree.c: Basic device tree traversal/scanning for the Linux * prom library. * @@ -26,7 +26,7 @@ __prom_getchild(int node) __inline__ int prom_getchild(int node) { - long cnode; + int cnode; if(node == -1) return 0; cnode = __prom_getchild(node); @@ -37,7 +37,7 @@ prom_getchild(int node) __inline__ int prom_getparent(int node) { - long cnode; + int cnode; if(node == -1) return 0; cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); @@ -57,12 +57,12 @@ __prom_getsibling(int node) __inline__ int prom_getsibling(int node) { - long sibnode; + int sibnode; if(node == -1) return 0; sibnode = __prom_getsibling(node); if(sibnode == -1) return 0; - return (int)sibnode; + return sibnode; } /* Return the length in bytes of property 'prop' at node 'node'. diff --git a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile new file mode 100644 index 000000000..56d252962 --- /dev/null +++ b/arch/sparc64/solaris/Makefile @@ -0,0 +1,26 @@ +# +# Makefile for the Solaris binary emulation. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +O_TARGET := solaris.o +O_OBJS := entry64.o fs.o misc.o signal.o systbl.o ioctl.o ipc.o socksys.o +ifeq ($(CONFIG_SOLARIS_EMUL),m) +M_OBJS := $(O_TARGET) +endif + +.S.s: + $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s + +.S.o: + $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o + +ifneq ($(CONFIG_SOLARIS_EMUL),y) +do_it_all: +endif + +include $(TOPDIR)/Rules.make diff --git a/arch/sparc64/solaris/conv.h b/arch/sparc64/solaris/conv.h new file mode 100644 index 000000000..c806d3dc1 --- /dev/null +++ b/arch/sparc64/solaris/conv.h @@ -0,0 +1,28 @@ +/* $Id: conv.h,v 1.2 1997/09/03 12:29:13 jj Exp $ + * conv.h: Utility macros for Solaris emulation + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +/* #define DEBUG_SOLARIS */ + +#ifndef __ASSEMBLY__ + +#include <asm/unistd.h> + +/* As gcc will warn about casting u32 to some ptr, we have to cast it to + * unsigned long first, and that's what is A() for. + * You just do (void *)A(x), instead of having to + * type (void *)((unsigned long)x) or instead of just (void *)x, which will + * produce warnings. + */ +#define A(x) ((unsigned long)x) + +extern unsigned sys_call_table[]; +extern unsigned sys_call_table32[]; +extern unsigned sunos_sys_table[]; + +#define SYS(name) ((long)sys_call_table[__NR_##name]) +#define SUNOS(x) ((long)sunos_sys_table[x]) + +#endif /* __ASSEMBLY__ */ diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S new file mode 100644 index 000000000..e983010d1 --- /dev/null +++ b/arch/sparc64/solaris/entry64.S @@ -0,0 +1,202 @@ +/* $Id: entry64.S,v 1.3 1997/09/03 12:29:12 jj Exp $ + * entry64.S: Solaris syscall emulation entry point. + * + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + */ + +#include <linux/errno.h> + +#include <asm/head.h> +#include <asm/asi.h> +#include <asm/smp.h> +#include <asm/ptrace.h> +#include <asm/page.h> +#include <asm/signal.h> +#include <asm/pgtable.h> +#include <asm/processor.h> + +#include "conv.h" + +#define NR_SYSCALLS 256 + + .text +solaris_syscall_trace: + call syscall_trace + nop + mov %i0, %o0 + mov %i1, %o1 + mov %i2, %o2 + mov %i3, %o3 + b,pt %xcc, 2f + mov %i4, %o4 + +solaris_sucks: +/* Solaris is a big system which needs to be able to do all the things + * in Inf+1 different ways */ + add %i6, 0x5c, %o0 + mov %i0, %g1 + mov %i1, %i0 + mov %i2, %i1 + srl %o0, 0, %o0 + mov %i3, %i2 + mov %i4, %i3 + mov %i5, %i4 + ba,pt %xcc, solaris_sparc_syscall +exen: lduwa [%o0] ASI_S, %i5 + +exenf: ba,pt %xcc, solaris_sparc_syscall + clr %i5 + +/* For shared binaries, binfmt_elf32 already sets up personality + and exec_domain. This is to handle static binaries as well */ +solaris_reg: + call solaris_register + nop + ba,pt %xcc, 1f + mov %i0, %o0 + +linux_syscall_for_solaris: + sll %l7, 2, %l4 + ba,pt %xcc, 10f + lduw [%l6 + %l4], %l7 + + /* Solaris system calls enter here... */ + .align 32 + .globl solaris_sparc_syscall +solaris_sparc_syscall: +#ifdef DEBUG_SOLARIS + mov %g1, %o0 + call entry_printk + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +#endif + ldub [%g6 + AOFF_task_personality + ASIZ_task_personality - 1], %l0 + cmp %g1, 255 + bg,pn %icc, solaris_unimplemented + srl %g1, 0, %g1 + sethi %hi(solaris_sys_table), %l7 + brz,pn %g1, solaris_sucks + mov %i0, %o0 + sll %g1, 2, %l4 + cmp %l0, 1 + bne,pn %icc, solaris_reg +1: mov %i1, %o1 + lduw [%l7 + %l4], %l7 + mov %i2, %o2 + ldx [%g6 + AOFF_task_flags], %l5 +! st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] + cmp %l7, NR_SYSCALLS + bleu,a,pn %xcc, linux_syscall_for_solaris + sethi %hi(sys_call_table32), %l6 + andcc %l7, 1, %g0 + bne,a,pn %icc, 10f + add %sp, STACK_BIAS + REGWIN_SZ, %o0 +10: mov %i3, %o3 + mov %i4, %o4 + andn %l7, 3, %l7 + andcc %l5, 0x20, %g0 + bne,pn %icc, solaris_syscall_trace + mov %i0, %l5 +2: call %l7 + mov %i5, %o5 +ret_from_solaris: +#ifdef DEBUG_SOLARIS + call exit_printk + mov %o0, %l0 + mov %l0, %o0 +#endif + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + ldx [%g6 + AOFF_task_flags], %l6 + sra %o0, 0, %o0 + mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3 + cmp %o0, -ENOIOCTLCMD + sllx %g2, 32, %g2 + bgeu,pn %xcc, 1f + andcc %l6, 0x20, %l6 + + /* System call success, clear Carry condition code. */ + andn %g3, %g2, %g3 + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] + bne,pn %icc, solaris_syscall_trace2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc + add %l1, 0x4, %l2 !npc = npc+4 + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + clr %l6 + call rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] +1: + /* System call failure, set Carry condition code. + * Also, get abs(errno) to return to the process. + */ + sub %g0, %o0, %o0 + or %g3, %g2, %g3 + cmp %o0, ERANGE /* 0-ERANGE are identity mapped */ + bleu,pt %icc, 1f + cmp %o0, EMEDIUMTYPE + bgu,pn %icc, 1f + sethi %hi(solaris_err_table), %l6 + sll %o0, 2, %o0 + or %l6, %lo(solaris_err_table), %l6 + ldsw [%l6 + %o0], %o0 +1: stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + mov 1, %l6 + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE] + bne,pn %icc, solaris_syscall_trace2 + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc + add %l1, 0x4, %l2 !npc = npc+4 + + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + call rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] +solaris_syscall_trace2: + call syscall_trace + add %l1, 0x4, %l2 /* npc = npc+4 */ + stx %l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC] + call rtrap + stx %l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC] + + /* This one is tricky, so that's why we do it in assembly */ + .globl solaris_sigsuspend +solaris_sigsuspend: + call do_sol_sigsuspend + nop + brlz,pn %o0, ret_from_solaris + nop + call sys_sigsuspend + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] + + .globl solaris_getpid +solaris_getpid: + call sys_getppid /* This is tricky, so don't do it in assembly */ + nop + stx %o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + b,pt %xcc, ret_from_solaris + lduw [%g6 + AOFF_task_pid], %o0 + + .globl solaris_getuid +solaris_getuid: + lduh [%g6 + AOFF_task_euid], %o1 + lduh [%g6 + AOFF_task_uid], %o0 + b,pt %xcc, ret_from_solaris + stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + + .globl solaris_getgid +solaris_getgid: + lduh [%g6 + AOFF_task_egid], %o1 + lduh [%g6 + AOFF_task_gid], %o0 + b,pt %xcc, ret_from_solaris + stx %o1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] + + .globl solaris_unimplemented +solaris_unimplemented: + call do_sol_unimplemented + add %sp, STACK_BIAS + REGWIN_SZ, %o0 + ba,pt %xcc, ret_from_solaris + nop + + .section __ex_table,#alloc + .align 4 + .word exen, exenf + diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c new file mode 100644 index 000000000..9d0905adc --- /dev/null +++ b/arch/sparc64/solaris/fs.c @@ -0,0 +1,711 @@ +/* $Id: fs.c,v 1.4 1997/09/04 15:46:26 jj Exp $ + * fs.c: fs related syscall emulation for Solaris + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/smp_lock.h> +#include <linux/limits.h> +#include <linux/resource.h> + +#include <asm/uaccess.h> +#include <asm/string.h> +#include <asm/ptrace.h> + +#include "conv.h" + +extern char * getname32(u32 filename); +#define putname32 putname + +#define R4_DEV(DEV) ((DEV & 0xff) | ((DEV & 0xff00) << 10)) +#define R4_MAJOR(DEV) (((DEV) >> 18) & 0x3fff) +#define R4_MINOR(DEV) ((DEV) & 0x3ffff) +#define R3_VERSION 1 +#define R4_VERSION 2 + +typedef struct { + s32 tv_sec; + s32 tv_nsec; +} timestruct_t; + +struct sol_stat { + u32 st_dev; + s32 st_pad1[3]; /* network id */ + u32 st_ino; + u32 st_mode; + u32 st_nlink; + u32 st_uid; + u32 st_gid; + u32 st_rdev; + s32 st_pad2[2]; + s32 st_size; + s32 st_pad3; /* st_size, off_t expansion */ + timestruct_t st_atime; + timestruct_t st_mtime; + timestruct_t st_ctime; + s32 st_blksize; + s32 st_blocks; + char st_fstype[16]; + s32 st_pad4[8]; /* expansion area */ +}; + +#define UFSMAGIC (((unsigned)'u'<<24)||((unsigned)'f'<<16)||((unsigned)'s'<<8)) + +static inline int putstat(struct sol_stat *ubuf, struct stat *kbuf) +{ + if (put_user (R4_DEV(kbuf->st_dev), &ubuf->st_dev) || + __put_user (kbuf->st_ino, &ubuf->st_ino) || + __put_user (kbuf->st_mode, &ubuf->st_mode) || + __put_user (kbuf->st_nlink, &ubuf->st_nlink) || + __put_user (kbuf->st_uid, &ubuf->st_uid) || + __put_user (kbuf->st_gid, &ubuf->st_gid) || + __put_user (R4_DEV(kbuf->st_rdev), &ubuf->st_rdev) || + __put_user (kbuf->st_size, &ubuf->st_size) || + __put_user (kbuf->st_atime, &ubuf->st_atime.tv_sec) || + __put_user (0, &ubuf->st_atime.tv_nsec) || + __put_user (kbuf->st_mtime, &ubuf->st_mtime.tv_sec) || + __put_user (0, &ubuf->st_mtime.tv_nsec) || + __put_user (kbuf->st_ctime, &ubuf->st_ctime.tv_sec) || + __put_user (0, &ubuf->st_ctime.tv_nsec) || + __put_user (kbuf->st_blksize, &ubuf->st_blksize) || + __put_user (kbuf->st_blocks, &ubuf->st_blocks) || + __put_user (UFSMAGIC, (unsigned *)ubuf->st_fstype)) + return -EFAULT; + return 0; +} + +asmlinkage int solaris_stat(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + unsigned long old_fs = get_fs(); + int (*sys_newstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(stat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat ((struct sol_stat *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + +asmlinkage int solaris_xstat(int vers, u32 filename, u32 statbuf) +{ + /* Solaris doesn't bother with looking at vers, so we do neither */ + return solaris_stat(filename, statbuf); +} + +asmlinkage int solaris_lstat(u32 filename, u32 statbuf) +{ + int ret; + struct stat s; + char *filenam; + unsigned long old_fs = get_fs(); + int (*sys_newlstat)(char *,struct stat *) = + (int (*)(char *,struct stat *))SYS(lstat); + + filenam = getname32 (filename); + ret = PTR_ERR(filenam); + if (!IS_ERR(filenam)) { + set_fs (KERNEL_DS); + ret = sys_newlstat(filenam, &s); + set_fs (old_fs); + putname32 (filenam); + if (putstat ((struct sol_stat *)A(statbuf), &s)) + return -EFAULT; + } + return ret; +} + +asmlinkage int solaris_lxstat(int vers, u32 filename, u32 statbuf) +{ + return solaris_lstat(filename, statbuf); +} + +asmlinkage int solaris_fstat(unsigned int fd, u32 statbuf) +{ + int ret; + struct stat s; + unsigned long old_fs = get_fs(); + int (*sys_newfstat)(unsigned,struct stat *) = + (int (*)(unsigned,struct stat *))SYS(fstat); + + set_fs (KERNEL_DS); + ret = sys_newfstat(fd, &s); + set_fs (old_fs); + if (putstat ((struct sol_stat *)A(statbuf), &s)) + return -EFAULT; + return ret; +} + +asmlinkage int solaris_fxstat(int vers, u32 fd, u32 statbuf) +{ + return solaris_fstat(fd, statbuf); +} + +asmlinkage int solaris_mknod(u32 path, u32 mode, s32 dev) +{ + int (*sys_mknod)(const char *,int,dev_t) = + (int (*)(const char *,int,dev_t))SYS(mknod); + int major, minor; + + if ((major = R4_MAJOR(dev)) > 255 || + (minor = R4_MINOR(dev)) > 255) return -EINVAL; + return sys_mknod((const char *)A(path), mode, MKDEV(major,minor)); +} + +asmlinkage int solaris_xmknod(int vers, u32 path, u32 mode, s32 dev) +{ + return solaris_mknod(path, mode, dev); +} + +/* This statfs thingie probably will go in the near future, but... */ + +struct sol_statfs { + short f_type; + s32 f_bsize; + s32 f_frsize; + s32 f_blocks; + s32 f_bfree; + u32 f_files; + u32 f_ffree; + char f_fname[6]; + char f_fpack[6]; +}; + +asmlinkage int solaris_statfs(u32 path, u32 buf, int len, int fstype) +{ + int ret; + struct statfs s; + unsigned long old_fs = get_fs(); + int (*sys_statfs)(const char *,struct statfs *) = + (int (*)(const char *,struct statfs *))SYS(statfs); + struct sol_statfs *ss = (struct sol_statfs *)A(buf); + + if (len != sizeof(struct sol_statfs)) return -EINVAL; + if (!fstype) { + set_fs (KERNEL_DS); + ret = sys_statfs((const char *)A(path), &s); + set_fs (old_fs); + if (!ret) { + if (put_user (s.f_type, &ss->f_type) || + __put_user (s.f_bsize, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (s.f_blocks, &ss->f_blocks) || + __put_user (s.f_bfree, &ss->f_bfree) || + __put_user (s.f_files, &ss->f_files) || + __put_user (s.f_ffree, &ss->f_ffree) || + __clear_user (&ss->f_fname, 12)) + return -EFAULT; + } + return ret; + } +/* Linux can't stat unmounted filesystems so we + * simply lie and claim 100MB of 1GB is free. Sorry. + */ + if (put_user (fstype, &ss->f_type) || + __put_user (1024, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (1024*1024, &ss->f_blocks) || + __put_user (100*1024, &ss->f_bfree) || + __put_user (60000, &ss->f_files) || + __put_user (50000, &ss->f_ffree) || + __clear_user (&ss->f_fname, 12)) + return -EFAULT; + return 0; +} + +asmlinkage int solaris_fstatfs(u32 fd, u32 buf, int len, int fstype) +{ + int ret; + struct statfs s; + unsigned long old_fs = get_fs(); + int (*sys_fstatfs)(unsigned,struct statfs *) = + (int (*)(unsigned,struct statfs *))SYS(fstatfs); + struct sol_statfs *ss = (struct sol_statfs *)A(buf); + + if (len != sizeof(struct sol_statfs)) return -EINVAL; + if (!fstype) { + set_fs (KERNEL_DS); + ret = sys_fstatfs(fd, &s); + set_fs (old_fs); + if (!ret) { + if (put_user (s.f_type, &ss->f_type) || + __put_user (s.f_bsize, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (s.f_blocks, &ss->f_blocks) || + __put_user (s.f_bfree, &ss->f_bfree) || + __put_user (s.f_files, &ss->f_files) || + __put_user (s.f_ffree, &ss->f_ffree) || + __clear_user (&ss->f_fname, 12)) + return -EFAULT; + } + return ret; + } + /* Otherwise fstatfs is the same as statfs */ + return solaris_statfs(0, buf, len, fstype); +} + +struct sol_statvfs { + u32 f_bsize; + u32 f_frsize; + u32 f_blocks; + u32 f_bfree; + u32 f_bavail; + u32 f_files; + u32 f_ffree; + u32 f_favail; + u32 f_fsid; + char f_basetype[16]; + u32 f_flag; + u32 f_namemax; + char f_fstr[32]; + u32 f_filler[16]; +}; + +static int report_statvfs(struct inode *inode, u32 buf) +{ + struct statfs s; + unsigned long old_fs = get_fs(); + int error; + struct sol_statvfs *ss = (struct sol_statvfs *)A(buf); + + set_fs (KERNEL_DS); + error = inode->i_sb->s_op->statfs(inode->i_sb, &s, sizeof(struct statfs)); + set_fs (old_fs); + if (!error) { + const char *p = inode->i_sb->s_type->name; + int i = 0; + int j = strlen (p); + + if (j > 15) j = 15; + if (IS_RDONLY(inode)) i = 1; + if (IS_NOSUID(inode)) i |= 2; + if (put_user (s.f_bsize, &ss->f_bsize) || + __put_user (0, &ss->f_frsize) || + __put_user (s.f_blocks, &ss->f_blocks) || + __put_user (s.f_bfree, &ss->f_bfree) || + __put_user (s.f_bavail, &ss->f_bavail) || + __put_user (s.f_files, &ss->f_files) || + __put_user (s.f_ffree, &ss->f_ffree) || + __put_user (s.f_ffree, &ss->f_favail) || + __put_user (R4_DEV(inode->i_sb->s_dev), &ss->f_fsid) || + __copy_to_user (ss->f_basetype,p,j) || + __put_user (0, (char *)&ss->f_basetype[j]) || + __put_user (s.f_namelen, &ss->f_namemax) || + __put_user (i, &ss->f_flag) || + __clear_user (&ss->f_fstr, 32)) + return -EFAULT; + } + return error; +} + +asmlinkage int solaris_statvfs(u32 path, u32 buf) +{ + struct dentry * dentry; + int error; + + lock_kernel(); + dentry = namei((const char *)A(path)); + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + struct inode * inode = dentry->d_inode; + + error = -ENOSYS; + if (inode->i_sb->s_op->statfs) + error = report_statvfs(inode, buf); + dput(dentry); + } + unlock_kernel(); + return error; +} + +asmlinkage int solaris_fstatvfs(unsigned int fd, u32 buf) +{ + struct inode * inode; + struct dentry * dentry; + struct file * file; + int error; + + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + error = -EBADF; + else if (!(dentry = file->f_dentry)) + error = -ENOENT; + else if (!(inode = dentry->d_inode)) + error = -ENOENT; + else if (!inode->i_sb) + error = -ENODEV; + else if (!inode->i_sb->s_op->statfs) + error = -ENOSYS; + else + error = report_statvfs(inode, buf); + unlock_kernel(); + return error; +} + +asmlinkage int solaris_open(u32 filename, int flags, u32 mode) +{ + int (*sys_open)(const char *,int,int) = + (int (*)(const char *,int,int))SYS(open); + int fl = flags & 0xf; + + if (flags & 0x8050) fl |= O_SYNC; + if (flags & 0x80) fl |= O_NONBLOCK; + if (flags & 0x100) fl |= O_CREAT; + if (flags & 0x200) fl |= O_TRUNC; + if (flags & 0x400) fl |= O_EXCL; + if (flags & 0x800) fl |= O_NOCTTY; + return sys_open((const char *)A(filename), fl, mode); +} + +#define SOL_F_SETLK 6 +#define SOL_F_SETLKW 7 +#define SOL_F_FREESP 11 +#define SOL_F_ISSTREAM 13 +#define SOL_F_GETLK 14 +#define SOL_F_PRIV 15 +#define SOL_F_NPRIV 16 +#define SOL_F_QUOTACTL 17 +#define SOL_F_BLOCKS 18 +#define SOL_F_BLKSIZE 19 +#define SOL_F_GETOWN 23 +#define SOL_F_SETOWN 24 + +struct sol_flock { + short l_type; + short l_whence; + u32 l_start; + u32 l_len; + s32 l_sysid; + s32 l_pid; + s32 l_pad[4]; +}; + +asmlinkage int solaris_fcntl(unsigned fd, unsigned cmd, u32 arg) +{ + int (*sys_fcntl)(unsigned,unsigned,unsigned long) = + (int (*)(unsigned,unsigned,unsigned long))SYS(fcntl); + int ret, flags; + + switch (cmd) { + case F_DUPFD: + case F_GETFD: + case F_SETFD: return sys_fcntl(fd, cmd, (unsigned long)arg); + case F_GETFL: + flags = sys_fcntl(fd, cmd, 0); + ret = flags & 0xf; + if (flags & O_SYNC) ret |= 0x8050; + if (flags & O_NONBLOCK) ret |= 0x80; + return ret; + case F_SETFL: + flags = arg & 0xf; + if (arg & 0x8050) flags |= O_SYNC; + if (arg & 0x80) flags |= O_NONBLOCK; + return sys_fcntl(fd, cmd, (long)flags); + case SOL_F_GETLK: + case SOL_F_SETLK: + case SOL_F_SETLKW: + { + struct flock f; + unsigned long old_fs = get_fs(); + + switch (cmd) { + case SOL_F_GETLK: cmd = F_GETLK; break; + case SOL_F_SETLK: cmd = F_SETLK; break; + case SOL_F_SETLKW: cmd = F_SETLKW; break; + } + + get_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT); + __get_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT); + __get_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT); + __get_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT); + __get_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT); + set_fs(KERNEL_DS); + ret = sys_fcntl(fd, cmd, (unsigned long)&f); + set_fs(old_fs); + __put_user_ret (f.l_type, &((struct sol_flock *)A(arg))->l_type, -EFAULT); + __put_user_ret (f.l_whence, &((struct sol_flock *)A(arg))->l_whence, -EFAULT); + __put_user_ret (f.l_start, &((struct sol_flock *)A(arg))->l_start, -EFAULT); + __put_user_ret (f.l_len, &((struct sol_flock *)A(arg))->l_len, -EFAULT); + __put_user_ret (f.l_pid, &((struct sol_flock *)A(arg))->l_pid, -EFAULT); + __put_user_ret (0, &((struct sol_flock *)A(arg))->l_sysid, -EFAULT); + return ret; + } + } + return -EINVAL; +} + +asmlinkage int solaris_ulimit(int cmd, int val) +{ + switch (cmd) { + case 1: /* UL_GETFSIZE - in 512B chunks */ + return current->rlim[RLIMIT_FSIZE].rlim_cur >> 9; + case 2: /* UL_SETFSIZE */ + if ((unsigned long)val > (LONG_MAX>>9)) return -ERANGE; + val <<= 9; + lock_kernel(); + if (val > current->rlim[RLIMIT_FSIZE].rlim_max) { + if (!suser()) { + unlock_kernel(); + return -EPERM; + } + current->rlim[RLIMIT_FSIZE].rlim_max = val; + } + current->rlim[RLIMIT_FSIZE].rlim_cur = val; + unlock_kernel(); + return 0; + case 3: /* UL_GMEMLIM */ + return current->rlim[RLIMIT_DATA].rlim_cur; + case 4: /* UL_GDESLIM */ + return NR_OPEN; + } + return -EINVAL; +} + +static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +{ + struct inode * inode; + struct iattr newattrs; + int error; + + error = -ENOENT; + if (!(inode = dentry->d_inode)) { + printk("chown_common: NULL inode\n"); + goto out; + } + error = -EROFS; + if (IS_RDONLY(inode)) + goto out; + error = -EPERM; + if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) + goto out; + if (user == (uid_t) -1) + user = inode->i_uid; + if (group == (gid_t) -1) + group = inode->i_gid; + newattrs.ia_mode = inode->i_mode; + newattrs.ia_uid = user; + newattrs.ia_gid = group; + newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; + /* + * If the owner has been changed, remove the setuid bit + */ + if (inode->i_mode & S_ISUID) { + newattrs.ia_mode &= ~S_ISUID; + newattrs.ia_valid |= ATTR_MODE; + } + /* + * If the group has been changed, remove the setgid bit + * + * Don't remove the setgid bit if no group execute bit. + * This is a file marked for mandatory locking. + */ + if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + newattrs.ia_mode &= ~S_ISGID; + newattrs.ia_valid |= ATTR_MODE; + } + if (inode->i_sb && inode->i_sb->dq_op) { + inode->i_sb->dq_op->initialize(inode, -1); + error = -EDQUOT; + if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) + goto out; + error = notify_change(inode, &newattrs); + if (error) + inode->i_sb->dq_op->transfer(inode, &newattrs, 1); + } else + error = notify_change(inode, &newattrs); +out: + return error; +} + +/* Linux chown works like Solaris lchown. Solaris chown does follow symlink */ +asmlinkage int solaris_chown(u32 filename, s32 user, s32 group) +{ + struct dentry * dentry; + int error; + + lock_kernel(); + dentry = namei((const char *)A(filename)); + + error = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + error = chown_common(dentry, user, group); + dput(dentry); + } + unlock_kernel(); + return error; +} + +/* At least at the time I'm writing this, Linux doesn't have ACLs, so we + just fake this */ +asmlinkage int solaris_acl(u32 filename, int cmd, int nentries, u32 aclbufp) +{ + return -ENOSYS; +} + +asmlinkage int solaris_facl(unsigned int fd, int cmd, int nentries, u32 aclbufp) +{ + return -ENOSYS; +} + +asmlinkage int solaris_pread(int fd, u32 buf, u32 nbyte, s32 offset) +{ + off_t temp; + int retval; + struct file * file; + long (*sys_read)(unsigned int, char *, unsigned long) = + (long (*)(unsigned int, char *, unsigned long))SYS(read); + long (*sys_lseek)(unsigned int, off_t, unsigned int) = + (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); + + lock_kernel(); + retval = -EBADF; + if (fd >= NR_OPEN || + !(file = current->files->fd[fd])) + goto bad; + temp = file->f_pos; + if (temp != offset) { + retval = sys_lseek(fd, offset, 0); + if (retval < 0) goto bad; + } + retval = sys_read(fd, (char *)A(buf), nbyte); + if (file->f_pos != temp) { + if (!retval) + retval = sys_lseek(fd, temp, 0); + else + sys_lseek(fd, temp, 0); + } +bad: + unlock_kernel(); + return retval; +} + +asmlinkage int solaris_pwrite(int fd, u32 buf, u32 nbyte, s32 offset) +{ + off_t temp; + int retval; + struct file * file; + long (*sys_write)(unsigned int, char *, unsigned long) = + (long (*)(unsigned int, char *, unsigned long))SYS(read); + long (*sys_lseek)(unsigned int, off_t, unsigned int) = + (long (*)(unsigned int, off_t, unsigned int))SYS(lseek); + + lock_kernel(); + retval = -EBADF; + if (fd >= NR_OPEN || + !(file = current->files->fd[fd])) + goto bad; + temp = file->f_pos; + if (temp != offset) { + retval = sys_lseek(fd, offset, 0); + if (retval < 0) goto bad; + } + retval = sys_write(fd, (char *)A(buf), nbyte); + if (file->f_pos != temp) { + if (!retval) + retval = sys_lseek(fd, temp, 0); + else + sys_lseek(fd, temp, 0); + } +bad: + unlock_kernel(); + return retval; +} + +/* POSIX.1 names */ +#define _PC_LINK_MAX 1 +#define _PC_MAX_CANON 2 +#define _PC_MAX_INPUT 3 +#define _PC_NAME_MAX 4 +#define _PC_PATH_MAX 5 +#define _PC_PIPE_BUF 6 +#define _PC_NO_TRUNC 7 +#define _PC_VDISABLE 8 +#define _PC_CHOWN_RESTRICTED 9 +/* POSIX.4 names */ +#define _PC_ASYNC_IO 10 +#define _PC_PRIO_IO 11 +#define _PC_SYNC_IO 12 +#define _PC_LAST 12 + +/* This is not a real and complete implementation yet, just to keep + * the easy Solaris binaries happy. + */ +asmlinkage int solaris_fpathconf(int fd, int name) +{ + int ret; + + switch(name) { + case _PC_LINK_MAX: + ret = LINK_MAX; + break; + case _PC_MAX_CANON: + ret = MAX_CANON; + break; + case _PC_MAX_INPUT: + ret = MAX_INPUT; + break; + case _PC_NAME_MAX: + ret = NAME_MAX; + break; + case _PC_PATH_MAX: + ret = PATH_MAX; + break; + case _PC_PIPE_BUF: + ret = PIPE_BUF; + break; + case _PC_CHOWN_RESTRICTED: + ret = 1; + break; + case _PC_NO_TRUNC: + case _PC_VDISABLE: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +asmlinkage int solaris_pathconf(u32 path, int name) +{ + return solaris_fpathconf(0, name); +} + +/* solaris_llseek returns long long - quite difficult */ +asmlinkage long solaris_llseek(struct pt_regs *regs, u32 off_hi, u32 off_lo, int whence) +{ + int (*sys_llseek)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int) = + (int (*)(unsigned int, unsigned long, unsigned long, loff_t *, unsigned int))SYS(_llseek); + int ret; + unsigned long old_fs = get_fs(); + loff_t retval; + + set_fs(KERNEL_DS); + ret = sys_llseek((unsigned int)regs->u_regs[UREG_I0], off_hi, off_lo, &retval, whence); + set_fs(old_fs); + if (ret < 0) return ret; + regs->u_regs[UREG_I1] = (u32)retval; + return (retval >> 32); +} + +/* Have to mask out all but lower 3 bits */ +asmlinkage int solaris_access(u32 filename, long mode) +{ + int (*sys_access)(const char *, int) = + (int (*)(const char *, int))SYS(access); + + return sys_access((const char *)A(filename), mode & 7); +} diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c new file mode 100644 index 000000000..43b844caf --- /dev/null +++ b/arch/sparc64/solaris/ioctl.c @@ -0,0 +1,316 @@ +/* $Id: ioctl.c,v 1.2 1997/09/04 00:59:22 davem Exp $ + * ioctl.c: Solaris ioctl emulation. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Streams & timod emulation based on code + * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) + * + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/ioctl.h> +#include <linux/fs.h> + +#include <asm/uaccess.h> +#include <asm/termios.h> + +#include "conv.h" + +extern char * getname32(u32 filename); +#define putname32 putname + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg); +extern asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, + u32 arg); +asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg); + +/* termio* stuff {{{ */ + +struct solaris_termios { + u32 c_iflag; + u32 c_oflag; + u32 c_cflag; + u32 c_lflag; + u8 c_cc[19]; +}; + +struct solaris_termio { + u16 c_iflag; + u16 c_oflag; + u16 c_cflag; + u16 c_lflag; + s8 c_line; + u8 c_cc[8]; +}; + +struct solaris_termiox { + u16 x_hflag; + u16 x_cflag; + u16 x_rflag[5]; + u16 x_sflag; +}; + +static u32 solaris_to_linux_cflag(u32 cflag) +{ + cflag &= 0x7fdff000; + if (cflag & 0x200000) { + int baud = cflag & 0xf; + cflag &= ~0x20000f; + switch (baud) { + case 0: baud = B57600; break; + case 1: baud = B76800; break; + case 2: baud = B115200; break; + case 3: baud = B153600; break; + case 4: baud = B230400; break; + case 5: baud = B307200; break; + case 6: baud = B460800; break; + } + cflag |= CBAUDEX | baud; + } + return cflag; +} + +static u32 linux_to_solaris_cflag(u32 cflag) +{ + cflag &= ~(CMSPAR | CIBAUD); + if (cflag & CBAUDEX) { + int baud = cflag & CBAUD; + cflag &= ~CBAUD; + switch (baud) { + case B57600: baud = 0; break; + case B76800: baud = 1; break; + case B115200: baud = 2; break; + case B153600: baud = 3; break; + case B230400: baud = 4; break; + case B307200: baud = 5; break; + case B460800: baud = 6; break; + case B614400: baud = 7; break; + case B921600: baud = 8; break; + /* case B1843200: baud = 9; break; */ + } + cflag |= 0x200000 | baud; + } + return cflag; +} + +static inline int linux_to_solaris_termio(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret; + + ret = sys_ioctl(fd, cmd, A(arg)); + if (!ret) { + u32 cflag; + + if (__get_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag)) + return -EFAULT; + cflag = linux_to_solaris_cflag(cflag); + if (__put_user (cflag, &((struct solaris_termio *)A(arg))->c_cflag)) + return -EFAULT; + } + return ret; +} + +static int solaris_to_linux_termio(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret; + struct solaris_termio s; + unsigned long old_fs = get_fs(); + + if (copy_from_user (&s, (struct solaris_termio *)A(arg), sizeof(struct solaris_termio))) + return -EFAULT; + s.c_cflag = solaris_to_linux_cflag(s.c_cflag); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, cmd, (unsigned long)&s); + set_fs(old_fs); + return ret; +} + +static inline int linux_to_solaris_termios(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret; + struct solaris_termios s; + unsigned long old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, cmd, (unsigned long)&s); + set_fs(old_fs); + if (!ret) { + if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) || + __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) || + __put_user (linux_to_solaris_cflag(s.c_cflag), &((struct solaris_termios *)A(arg))->c_cflag) || + __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) || + __copy_to_user (((struct solaris_termios *)A(arg))->c_cc, s.c_cc, 16) || + __clear_user (((struct solaris_termios *)A(arg))->c_cc + 16, 2)) + return -EFAULT; + } + return ret; +} + +static int solaris_to_linux_termios(unsigned int fd, unsigned int cmd, u32 arg) +{ + int ret; + struct solaris_termios s; + unsigned long old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, TCGETS, (unsigned long)&s); + set_fs(old_fs); + if (ret) return ret; + if (put_user (s.c_iflag, &((struct solaris_termios *)A(arg))->c_iflag) || + __put_user (s.c_oflag, &((struct solaris_termios *)A(arg))->c_oflag) || + __put_user (s.c_cflag, &((struct solaris_termios *)A(arg))->c_cflag) || + __put_user (s.c_lflag, &((struct solaris_termios *)A(arg))->c_lflag) || + __copy_from_user (s.c_cc, ((struct solaris_termios *)A(arg))->c_cc, 16)) + return -EFAULT; + s.c_cflag = solaris_to_linux_cflag(s.c_cflag); + set_fs(KERNEL_DS); + ret = sys_ioctl(fd, cmd, (unsigned long)&s); + set_fs(old_fs); + return ret; +} + +static inline int solaris_T(unsigned int fd, unsigned int cmd, u32 arg) +{ + switch (cmd & 0xff) { + case 1: /* TCGETA */ + return linux_to_solaris_termio(fd, TCGETA, arg); + case 2: /* TCSETA */ + return solaris_to_linux_termio(fd, TCSETA, arg); + case 3: /* TCSETAW */ + return solaris_to_linux_termio(fd, TCSETAW, arg); + case 4: /* TCSETAF */ + return solaris_to_linux_termio(fd, TCSETAF, arg); + case 5: /* TCSBRK */ + return sys_ioctl(fd, TCSBRK, arg); + case 6: /* TCXONC */ + return sys_ioctl(fd, TCXONC, arg); + case 7: /* TCFLSH */ + return sys_ioctl(fd, TCFLSH, arg); + case 13: /* TCGETS */ + return linux_to_solaris_termios(fd, TCGETS, arg); + case 14: /* TCSETS */ + return solaris_to_linux_termios(fd, TCSETS, arg); + case 15: /* TCSETSW */ + return solaris_to_linux_termios(fd, TCSETSW, arg); + case 16: /* TCSETSF */ + return solaris_to_linux_termios(fd, TCSETSF, arg); + case 103: /* TIOCSWINSZ */ + return sys_ioctl(fd, TIOCSWINSZ, arg); + case 104: /* TIOCGWINSZ */ + return sys_ioctl(fd, TIOCGWINSZ, arg); + } + return -ENOSYS; +} + +static inline int solaris_t(unsigned int fd, unsigned int cmd, u32 arg) +{ + switch (cmd & 0xff) { + case 20: /* TIOCGPGRP */ + return sys_ioctl(fd, TIOCGPGRP, arg); + case 21: /* TIOCSPGRP */ + return sys_ioctl(fd, TIOCSPGRP, arg); + } + return -ENOSYS; +} + +/* }}} */ + +/* A pseudo STREAMS support {{{ */ + +struct strioctl { + int cmd, timeout, len; + u32 data; +}; + +static inline int solaris_S(unsigned int fd, unsigned int cmd, u32 arg) +{ + char *p; + int ret; + unsigned long old_fs; + struct strioctl si; + + switch (cmd & 0xff) { + case 1: /* I_NREAD */ + return -ENOSYS; + case 2: /* I_PUSH */ + p = getname32 (arg); + if (IS_ERR (p)) + return PTR_ERR(p); + putname32 (p); + return 0; + case 3: /* I_POP */ + return 0; + case 5: /* I_FLUSH */ + return 0; + case 8: /* I_STR */ + if (copy_from_user (&si, (struct strioctl *)A(arg), sizeof(struct strioctl))) + return -EFAULT; + switch ((si.cmd >> 8) & 0xff) { + case 'T': + default: + return solaris_ioctl(fd, si.cmd, si.data); + } + case 9: /* I_SETSIG */ + return sys_ioctl(fd, FIOSETOWN, current->pid); + case 10: /* I_GETSIG */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + sys_ioctl(fd, FIOGETOWN, (unsigned long)&ret); + set_fs(old_fs); + if (ret == current->pid) return 0x3ff; + else return -EINVAL; + case 11: /* I_FIND */ + p = getname32 (arg); + if (IS_ERR (p)) + return PTR_ERR(p); + ret = !strcmp(p, "timod"); + putname32 (p); + return ret; + } + return -ENOSYS; +} +/* }}} */ + +asmlinkage int solaris_ioctl(unsigned int fd, unsigned int cmd, u32 arg) +{ + struct file * filp; + int error = -EBADF; + + lock_kernel(); + if(fd >= NR_OPEN) goto out; + + filp = current->files->fd[fd]; + if(!filp) goto out; + + if (!filp->f_op || !filp->f_op->ioctl) { + error = sys_ioctl (fd, cmd, (unsigned long)arg); + goto out; + } + + error = -EFAULT; + switch ((cmd >> 8) & 0xff) { + case 'S': error = solaris_S(fd, cmd, arg); break; + case 'T': error = solaris_T(fd, cmd, arg); break; + case 't': error = solaris_t(fd, cmd, arg); break; + default: + error = -ENOSYS; + break; + } +out: + if (error == -ENOSYS) { + unsigned char c = cmd>>8; + + if (c < ' ' || c > 126) c = '.'; + printk("solaris_ioctl: Unknown cmd fd(%d) cmd(%08x '%c') arg(%08x)\n", + (int)fd, (unsigned int)cmd, c, (unsigned int)arg); + error = -EINVAL; + } + unlock_kernel(); + return error; +} diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c new file mode 100644 index 000000000..132028447 --- /dev/null +++ b/arch/sparc64/solaris/ipc.c @@ -0,0 +1,122 @@ +/* $Id: ipc.c,v 1.1 1997/09/03 12:29:29 jj Exp $ + * ipc.c: Solaris IPC emulation + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include <linux/types.h> +#include <linux/smp_lock.h> +#include <linux/shm.h> +#include <linux/sem.h> +#include <linux/msg.h> + +#include <asm/uaccess.h> +#include <asm/string.h> +#include <asm/ipc.h> + +#include "conv.h" + +struct solaris_ipc_perm { + s32 uid; + s32 gid; + s32 cuid; + s32 cgid; + u32 mode; + u32 seq; + int key; + s32 pad[4]; +}; + +struct solaris_shmid_ds { + struct solaris_ipc_perm shm_perm; + int shm_segsz; + u32 shm_amp; + unsigned short shm_lkcnt; + char __padxx[2]; + s32 shm_lpid; + s32 shm_cpid; + u32 shm_nattch; + u32 shm_cnattch; + s32 shm_atime; + s32 shm_pad1; + s32 shm_dtime; + s32 shm_pad2; + s32 shm_ctime; + s32 shm_pad3; + unsigned short shm_cv; + char shm_pad4[2]; + u32 shm_sptas; + s32 shm_pad5[2]; +}; + +asmlinkage long solaris_shmsys(int cmd, u32 arg1, u32 arg2, u32 arg3) +{ + int (*sys_ipc)(unsigned,int,int,unsigned long,void *,long) = + (int (*)(unsigned,int,int,unsigned long,void *,long))SYS(ipc); + unsigned long old_fs; + unsigned long raddr; + int ret; + + switch (cmd) { + case 0: /* shmat */ + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ipc(SHMAT, arg1, arg3 & ~0x4000, (unsigned long)&raddr, (void *)A(arg2), 0); + set_fs(old_fs); + if (ret >= 0) return (u32)raddr; + else return ret; + case 1: /* shmctl */ + switch (arg2) { + case 3: /* SHM_LOCK */ + case 4: /* SHM_UNLOCK */ + return sys_ipc(SHMCTL, arg1, (arg2 == 3) ? SHM_LOCK : SHM_UNLOCK, 0, NULL, 0); + case 10: /* IPC_RMID */ + return sys_ipc(SHMCTL, arg1, IPC_RMID, 0, NULL, 0); + case 11: /* IPC_SET */ + { + struct shmid_ds s; + + if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) || + __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) || + __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode))) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0); + set_fs(old_fs); + return ret; + } + case 12: /* IPC_STAT */ + { + struct shmid_ds s; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_ipc(SHMCTL, arg1, IPC_SET, 0, &s, 0); + set_fs(old_fs); + if (get_user (s.shm_perm.uid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.uid)) || + __get_user (s.shm_perm.gid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.gid)) || + __get_user (s.shm_perm.cuid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cuid)) || + __get_user (s.shm_perm.cgid, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.cgid)) || + __get_user (s.shm_perm.mode, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.mode)) || + __get_user (s.shm_perm.seq, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.seq)) || + __get_user (s.shm_perm.key, &(((struct solaris_shmid_ds *)A(arg3))->shm_perm.key)) || + __get_user (s.shm_segsz, &(((struct solaris_shmid_ds *)A(arg3))->shm_segsz)) || + __get_user (s.shm_lpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_lpid)) || + __get_user (s.shm_cpid, &(((struct solaris_shmid_ds *)A(arg3))->shm_cpid)) || + __get_user (s.shm_nattch, &(((struct solaris_shmid_ds *)A(arg3))->shm_nattch)) || + __get_user (s.shm_atime, &(((struct solaris_shmid_ds *)A(arg3))->shm_atime)) || + __get_user (s.shm_dtime, &(((struct solaris_shmid_ds *)A(arg3))->shm_dtime)) || + __get_user (s.shm_ctime, &(((struct solaris_shmid_ds *)A(arg3))->shm_ctime))) + return -EFAULT; + return ret; + } + default: return -EINVAL; + } + case 2: /* shmdt */ + return sys_ipc(SHMDT, 0, 0, 0, (void *)A(arg1), 0); + case 3: /* shmget */ + return sys_ipc(SHMGET, arg1, arg2, arg3, NULL, 0); + } + return -EINVAL; +} diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c new file mode 100644 index 000000000..fdabd0e26 --- /dev/null +++ b/arch/sparc64/solaris/misc.c @@ -0,0 +1,463 @@ +/* $Id: misc.c,v 1.4 1997/09/04 14:57:31 jj Exp $ + * misc.c: Miscelaneous syscall emulation for Solaris + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/smp_lock.h> +#include <linux/utsname.h> +#include <linux/limits.h> +#include <linux/mm.h> +#include <linux/smp.h> + +#include <asm/uaccess.h> +#include <asm/string.h> +#include <asm/oplib.h> +#include <asm/idprom.h> +#include <asm/machines.h> + +#include "conv.h" + +/* Conversion from Linux to Solaris errnos. 0-34 are identity mapped. + Some Linux errnos (EPROCLIM, EDOTDOT, ERREMOTE, EUCLEAN, ENOTNAM, + ENAVAIL, EISNAM, EREMOTEIO, ENOMEDIUM, EMEDIUMTYPE) have no Solaris + equivalents. I return EINVAL in that case, which is very wrong. If + someone suggest a better value for them, you're welcomed. + On the other side, Solaris ECANCELED and ENOTSUP have no Linux equivalents, + but that doesn't matter here. --jj */ +int solaris_err_table[] = { +/* 0 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +/* 10 */ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, +/* 20 */ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, +/* 30 */ 30, 31, 32, 33, 34, 22, 150, 149, 95, 96, +/* 40 */ 97, 98, 99, 120, 121, 122, 123, 124, 125, 126, +/* 50 */ 127, 128, 129, 130, 131, 132, 133, 134, 143, 144, +/* 60 */ 145, 146, 90, 78, 147, 148, 93, 22, 94, 49, +/* 70 */ 151, 66, 60, 62, 63, 35, 77, 36, 45, 46, +/* 80 */ 64, 22, 67, 68, 69, 70, 71, 74, 22, 82, +/* 90 */ 89, 92, 79, 81, 37, 38, 39, 40, 41, 42, +/* 100 */ 43, 44, 50, 51, 52, 53, 54, 55, 56, 57, +/* 110 */ 87, 61, 84, 65, 83, 80, 91, 22, 22, 22, +/* 120 */ 22, 22, 88, 86, 85, 22, 22, +}; + +asmlinkage u32 solaris_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) +{ + u32 (*sunos_mmap)(u32,u32,u32,u32,u32,u32) = + (u32 (*)(u32,u32,u32,u32,u32,u32))SUNOS(71); + u32 ret; + + ret = sunos_mmap(addr,len,prot,flags,fd,off); + /* sunos_mmap sets personality to PER_BSD */ + current->personality = PER_SVR4; + return ret; +} + +asmlinkage int solaris_brk(u32 brk) +{ + int (*sunos_brk)(u32) = (int (*)(u32))SUNOS(17); + + return sunos_brk(brk); +} + +#define set_utsfield(to, from, dotchop, countfrom) { \ + char *p; \ + int i, len = (countfrom) ? \ + ((sizeof(to) > sizeof(from) ? \ + sizeof(from) : sizeof(to))) : sizeof(to); \ + copy_to_user_ret(to, from, len, -EFAULT); \ + if (dotchop) \ + for (p=from,i=0; *p && *p != '.' && --len; p++,i++); \ + else \ + i = len - 1; \ + __put_user_ret('\0', (char *)(to+i), -EFAULT); \ +} + +struct sol_uname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +struct sol_utsname { + char sysname[257]; + char nodename[257]; + char release[257]; + char version[257]; + char machine[257]; +}; + +static char *machine(void) +{ + switch (sparc_cpu_model) { + case sun4: return "sun4"; + case sun4c: return "sun4c"; + case sun4e: return "sun4e"; + case sun4m: return "sun4m"; + case sun4d: return "sun4d"; + case sun4u: return "sun4u"; + default: return "sparc"; + } +} + +static char *platform(char *buffer) +{ + int i; + struct { + char *platform; + int id_machtype; + } platforms [] = { + { "sun4", (SM_SUN4 | SM_4_110) }, + { "sun4", (SM_SUN4 | SM_4_260) }, + { "sun4", (SM_SUN4 | SM_4_330) }, + { "sun4", (SM_SUN4 | SM_4_470) }, + { "SUNW,Sun_4_60", (SM_SUN4C | SM_4C_SS1) }, + { "SUNW,Sun_4_40", (SM_SUN4C | SM_4C_IPC) }, + { "SUNW,Sun_4_65", (SM_SUN4C | SM_4C_SS1PLUS) }, + { "SUNW,Sun_4_20", (SM_SUN4C | SM_4C_SLC) }, + { "SUNW,Sun_4_75", (SM_SUN4C | SM_4C_SS2) }, + { "SUNW,Sun_4_25", (SM_SUN4C | SM_4C_ELC) }, + { "SUNW,Sun_4_50", (SM_SUN4C | SM_4C_IPX) }, + { "SUNW,Sun_4_600", (SM_SUN4M | SM_4M_SS60) }, + { "SUNW,SPARCstation-5", (SM_SUN4M | SM_4M_SS50) }, + { "SUNW,SPARCstation-20", (SM_SUN4M | SM_4M_SS40) } + }; + + *buffer = 0; + prom_getproperty(prom_root_node, "name", buffer, 256); + if (*buffer) { + char *p; + + for (p = buffer; *p; p++) + if (*p == '/' || *p == ' ') *p = '_'; + return buffer; + } + for (i = 0; i < sizeof (platforms)/sizeof (platforms[0]); i++) + if (platforms[i].id_machtype == idprom->id_machtype) + return platforms[i].platform; + return "sun4c"; +} + +static char *serial(char *buffer) +{ + int node = prom_getchild(prom_root_node); + + node = prom_searchsiblings(node, "options"); + *buffer = 0; + prom_getproperty(node, "system-board-serial#", buffer, 256); + if (!*buffer) + return "4512348717234"; + else + return buffer; +} + +asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) +{ + switch (which) { + case 0: /* old uname */ + /* Lets cheat */ + set_utsfield(((struct sol_uname *)A(buf))->sysname, + "SunOS", 1, 0); + set_utsfield(((struct sol_uname *)A(buf))->nodename, + system_utsname.nodename, 1, 1); + set_utsfield(((struct sol_uname *)A(buf))->release, + "2.6", 0, 0); + set_utsfield(((struct sol_uname *)A(buf))->version, + "Generic", 0, 0); + set_utsfield(((struct sol_uname *)A(buf))->machine, + machine(), 0, 0); + return 0; + case 2: /* ustat */ + return -ENOSYS; + case 3: /* fusers */ + return -ENOSYS; + default: + return -ENOSYS; + } +} + +asmlinkage int solaris_utsname(u32 buf) +{ + /* Why should we not lie a bit? */ + set_utsfield(((struct sol_utsname *)A(buf))->sysname, + "SunOS", 0, 0); + set_utsfield(((struct sol_utsname *)A(buf))->nodename, + system_utsname.nodename, 1, 1); + set_utsfield(((struct sol_utsname *)A(buf))->release, + "5.6", 0, 0); + set_utsfield(((struct sol_utsname *)A(buf))->version, + "Generic", 0, 0); + set_utsfield(((struct sol_utsname *)A(buf))->machine, + machine(), 0, 0); + return 0; +} + +#define SI_SYSNAME 1 /* return name of operating system */ +#define SI_HOSTNAME 2 /* return name of node */ +#define SI_RELEASE 3 /* return release of operating system */ +#define SI_VERSION 4 /* return version field of utsname */ +#define SI_MACHINE 5 /* return kind of machine */ +#define SI_ARCHITECTURE 6 /* return instruction set arch */ +#define SI_HW_SERIAL 7 /* return hardware serial number */ +#define SI_HW_PROVIDER 8 /* return hardware manufacturer */ +#define SI_SRPC_DOMAIN 9 /* return secure RPC domain */ +#define SI_PLATFORM 513 /* return platform identifier */ + +asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count) +{ + char *p, *q, *r; + char buffer[256]; + int len; + + /* Again, we cheat :)) */ + switch (cmd) { + case SI_SYSNAME: r = "SunOS"; break; + case SI_HOSTNAME: + r = buffer + 256; + for (p = system_utsname.nodename, q = buffer; + q < r && *p && *p != '.'; *q++ = *p++); + *q = 0; + r = buffer; + break; + case SI_RELEASE: r = "5.6"; break; + case SI_MACHINE: r = machine(); break; + case SI_ARCHITECTURE: r = "sparc"; break; + case SI_HW_PROVIDER: r = "Sun_Microsystems"; break; + case SI_HW_SERIAL: r = serial(buffer); break; + case SI_PLATFORM: r = platform(buffer); break; + case SI_SRPC_DOMAIN: r = ""; break; + case SI_VERSION: r = "Generic"; break; + default: return -EINVAL; + } + len = strlen(r) + 1; + if (count < len) { + copy_to_user_ret((char *)A(buf), r, count - 1, -EFAULT); + __put_user_ret(0, (char *)A(buf) + count - 1, -EFAULT); + } else + copy_to_user_ret((char *)A(buf), r, len, -EFAULT); + return len; +} + +#define SOLARIS_CONFIG_NGROUPS 2 +#define SOLARIS_CONFIG_CHILD_MAX 3 +#define SOLARIS_CONFIG_OPEN_FILES 4 +#define SOLARIS_CONFIG_POSIX_VER 5 +#define SOLARIS_CONFIG_PAGESIZE 6 +#define SOLARIS_CONFIG_CLK_TCK 7 +#define SOLARIS_CONFIG_XOPEN_VER 8 +#define SOLARIS_CONFIG_PROF_TCK 10 +#define SOLARIS_CONFIG_NPROC_CONF 11 +#define SOLARIS_CONFIG_NPROC_ONLN 12 +#define SOLARIS_CONFIG_AIO_LISTIO_MAX 13 +#define SOLARIS_CONFIG_AIO_MAX 14 +#define SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX 15 +#define SOLARIS_CONFIG_DELAYTIMER_MAX 16 +#define SOLARIS_CONFIG_MQ_OPEN_MAX 17 +#define SOLARIS_CONFIG_MQ_PRIO_MAX 18 +#define SOLARIS_CONFIG_RTSIG_MAX 19 +#define SOLARIS_CONFIG_SEM_NSEMS_MAX 20 +#define SOLARIS_CONFIG_SEM_VALUE_MAX 21 +#define SOLARIS_CONFIG_SIGQUEUE_MAX 22 +#define SOLARIS_CONFIG_SIGRT_MIN 23 +#define SOLARIS_CONFIG_SIGRT_MAX 24 +#define SOLARIS_CONFIG_TIMER_MAX 25 +#define SOLARIS_CONFIG_PHYS_PAGES 26 +#define SOLARIS_CONFIG_AVPHYS_PAGES 27 + +asmlinkage int solaris_sysconf(int id) +{ + switch (id) { + case SOLARIS_CONFIG_NGROUPS: return NGROUPS_MAX; + case SOLARIS_CONFIG_CHILD_MAX: return CHILD_MAX; + case SOLARIS_CONFIG_OPEN_FILES: return OPEN_MAX; + case SOLARIS_CONFIG_POSIX_VER: return 199309; + case SOLARIS_CONFIG_PAGESIZE: return PAGE_SIZE; + case SOLARIS_CONFIG_XOPEN_VER: return 3; + case SOLARIS_CONFIG_CLK_TCK: + case SOLARIS_CONFIG_PROF_TCK: + return prom_getintdefault( + linux_cpus[smp_processor_id()].prom_node, + "clock-frequency", 167000000); +#ifdef __SMP__ + case SOLARIS_CONFIG_NPROC_CONF: return NCPUS; + case SOLARIS_CONFIG_NPROC_ONLN: return smp_num_cpus; +#else + case SOLARIS_CONFIG_NPROC_CONF: return 1; + case SOLARIS_CONFIG_NPROC_ONLN: return 1; +#endif + case SOLARIS_CONFIG_SIGRT_MIN: return 37; + case SOLARIS_CONFIG_SIGRT_MAX: return 44; + case SOLARIS_CONFIG_PHYS_PAGES: + case SOLARIS_CONFIG_AVPHYS_PAGES: + { + struct sysinfo s; + + si_meminfo(&s); + if (id == SOLARIS_CONFIG_PHYS_PAGES) + return s.totalram >>= PAGE_SHIFT; + else + return s.freeram >>= PAGE_SHIFT; + } + /* XXX support these as well -jj */ + case SOLARIS_CONFIG_AIO_LISTIO_MAX: return -EINVAL; + case SOLARIS_CONFIG_AIO_MAX: return -EINVAL; + case SOLARIS_CONFIG_AIO_PRIO_DELTA_MAX: return -EINVAL; + case SOLARIS_CONFIG_DELAYTIMER_MAX: return -EINVAL; + case SOLARIS_CONFIG_MQ_OPEN_MAX: return -EINVAL; + case SOLARIS_CONFIG_MQ_PRIO_MAX: return -EINVAL; + case SOLARIS_CONFIG_RTSIG_MAX: return -EINVAL; + case SOLARIS_CONFIG_SEM_NSEMS_MAX: return -EINVAL; + case SOLARIS_CONFIG_SEM_VALUE_MAX: return -EINVAL; + case SOLARIS_CONFIG_SIGQUEUE_MAX: return -EINVAL; + case SOLARIS_CONFIG_TIMER_MAX: return -EINVAL; + default: return -EINVAL; + } +} + +asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) +{ + int ret; + + switch (cmd) { + case 0: /* getpgrp */ + return current->pgrp; + case 1: /* setpgrp */ + { + int (*sys_setpgid)(pid_t,pid_t) = + (int (*)(pid_t,pid_t))SYS(setpgid); + + /* can anyone explain me the difference between + Solaris setpgrp and setsid? */ + ret = sys_setpgid(0, 0); + if (ret) return ret; + current->tty = NULL; + return current->pgrp; + } + case 2: /* getsid */ + { + int (*sys_getsid)(pid_t) = (int (*)(pid_t))SYS(getsid); + return sys_getsid(pid); + } + case 3: /* setsid */ + { + int (*sys_setsid)(void) = (int (*)(void))SYS(setsid); + return sys_setsid(); + } + case 4: /* getpgid */ + { + int (*sys_getpgid)(pid_t) = (int (*)(pid_t))SYS(getpgid); + return sys_getpgid(pid); + } + case 5: /* setpgid */ + { + int (*sys_setpgid)(pid_t,pid_t) = + (int (*)(pid_t,pid_t))SYS(setpgid); + return sys_setpgid(pid,pgid); + } + } + return -EINVAL; +} + +asmlinkage int do_sol_unimplemented(struct pt_regs *regs) +{ + printk ("Unimplemented Solaris syscall %d %08x %08x %08x %08x\n", + (int)regs->u_regs[UREG_G1], + (int)regs->u_regs[UREG_I0], + (int)regs->u_regs[UREG_I1], + (int)regs->u_regs[UREG_I2], + (int)regs->u_regs[UREG_I3]); + return -ENOSYS; +} + +asmlinkage void solaris_register(void) +{ + lock_kernel(); + current->personality = PER_SVR4; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + current->exec_domain = lookup_exec_domain(current->personality); + if (current->exec_domain && current->exec_domain->module) + __MOD_INC_USE_COUNT(current->exec_domain->module); + unlock_kernel(); +} + +extern long solaris_to_linux_signals[], linux_to_solaris_signals[]; + +struct exec_domain solaris_exec_domain = { + "Solaris", + (lcall7_func)NULL, + 1, 1, /* PER_SVR4 personality */ + solaris_to_linux_signals, + linux_to_solaris_signals, +#ifdef MODULE + &__this_module, +#else + NULL, +#endif + NULL +}; + +#ifdef MODULE + +MODULE_AUTHOR("Jakub Jelinek (jj@sunsite.mff.cuni.cz)"); +MODULE_DESCRIPTION("Solaris binary emulation module"); + +#ifdef __sparc_v9__ +extern u32 tl0_solaris[8]; +#define update_ttable(x) \ + tl0_solaris[3] = (((long)(x) - (long)tl0_solaris - 3) >> 2) | 0x40000000; \ + __asm__ __volatile__ ("membar #StoreStore; flush %0" : : "r" (&tl0_solaris[3])) +#else +#endif + +extern u32 solaris_sparc_syscall[]; +extern u32 solaris_syscall[]; +extern int init_socksys(void); +extern void cleanup_socksys(void); + +int init_module(void) +{ + int ret; + register_exec_domain(&solaris_exec_domain); + if ((ret = init_socksys())) { + unregister_exec_domain(&solaris_exec_domain); + return ret; + } + update_ttable(solaris_sparc_syscall); + return 0; +} + +void cleanup_module(void) +{ + update_ttable(solaris_syscall); + cleanup_socksys(); + unregister_exec_domain(&solaris_exec_domain); +} + +#else +int init_solaris_emul(void) +{ + register_exec_domain(&solaris_exec_domain); + init_socksys(); +} +#endif + +#ifdef DEBUG_SOLARIS +void entry_printk(int sysno, struct pt_regs *regs) +{ + printk ("Entering %d\n", sysno); + printk ("%08x %08x %08x %08x\n", (int)regs->u_regs[UREG_I0], + (int)regs->u_regs[UREG_I1], + (int)regs->u_regs[UREG_I2], + (int)regs->u_regs[UREG_I3]); +} + +void exit_printk(unsigned long ret) +{ + printk ("Returning %016lx\n", ret); +} +#endif diff --git a/arch/sparc64/solaris/signal.c b/arch/sparc64/solaris/signal.c new file mode 100644 index 000000000..6d3081c03 --- /dev/null +++ b/arch/sparc64/solaris/signal.c @@ -0,0 +1,419 @@ +/* $Id: signal.c,v 1.2 1997/09/03 12:29:19 jj Exp $ + * signal.c: Signal emulation for Solaris + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#include <linux/types.h> +#include <linux/smp_lock.h> + +#include <asm/uaccess.h> +#include <asm/svr4.h> +#include <asm/string.h> + +#include "conv.h" +#include "signal.h" + +#define _S(nr) (1L<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +long linux_to_solaris_signals[] = { + 0, + SOLARIS_SIGHUP, SOLARIS_SIGINT, + SOLARIS_SIGQUIT, SOLARIS_SIGILL, + SOLARIS_SIGTRAP, SOLARIS_SIGIOT, + SOLARIS_SIGEMT, SOLARIS_SIGFPE, + SOLARIS_SIGKILL, SOLARIS_SIGBUS, + SOLARIS_SIGSEGV, SOLARIS_SIGSYS, + SOLARIS_SIGPIPE, SOLARIS_SIGALRM, + SOLARIS_SIGTERM, SOLARIS_SIGURG, + SOLARIS_SIGSTOP, SOLARIS_SIGTSTP, + SOLARIS_SIGCONT, SOLARIS_SIGCLD, + SOLARIS_SIGTTIN, SOLARIS_SIGTTOU, + SOLARIS_SIGPOLL, SOLARIS_SIGXCPU, + SOLARIS_SIGXFSZ, SOLARIS_SIGVTALRM, + SOLARIS_SIGPROF, SOLARIS_SIGWINCH, + SOLARIS_SIGUSR1, SOLARIS_SIGUSR1, + SOLARIS_SIGUSR2, -1, +}; + +long solaris_to_linux_signals[] = { + 0, + SIGHUP, SIGINT, SIGQUIT, SIGILL, + SIGTRAP, SIGIOT, SIGEMT, SIGFPE, + SIGKILL, SIGBUS, SIGSEGV, SIGSYS, + SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, + SIGUSR2, SIGCHLD, -1, SIGWINCH, + SIGURG, SIGPOLL, SIGSTOP, SIGTSTP, + SIGCONT, SIGTTIN, SIGTTOU, SIGVTALRM, + SIGPROF, SIGXCPU, SIGXFSZ, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, + -1, -1, -1, -1, +}; + +static inline long mapsig(long sig) +{ + if ((unsigned long)sig > SOLARIS_NSIGNALS) + return -EINVAL; + return solaris_to_linux_signals[sig]; +} + +asmlinkage int solaris_kill(int pid, int sig) +{ + int (*sys_kill)(int,int) = + (int (*)(int,int))SYS(kill); + int s = mapsig(sig); + + if (s < 0) return s; + return sys_kill(pid, s); +} + +static long sig_handler(int sig, u32 arg, int one_shot) +{ + struct sigaction sa, old; + int ret; + unsigned long old_fs = get_fs(); + int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = + (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction); + + sa.sa_mask = 0L; + sa.sa_restorer = NULL; + sa.sa_handler = (__sighandler_t)A(arg); + sa.sa_flags = 0; + if (one_shot) sa.sa_flags = SA_ONESHOT | SA_NOMASK; + set_fs (KERNEL_DS); + ret = sys_sigaction(sig, &sa, &old); + set_fs (old_fs); + if (ret < 0) return ret; + return (u32)(long)old.sa_handler; +} + +static inline long solaris_signal(int sig, u32 arg) +{ + return sig_handler (sig, arg, 1); +} + +static long solaris_sigset(int sig, u32 arg) +{ + if (arg != 2) /* HOLD */ { + spin_lock_irq(¤t->sigmask_lock); + current->blocked &= ~_S(sig); + spin_unlock_irq(¤t->sigmask_lock); + return sig_handler (sig, arg, 0); + } else { + sigset_t n = _S(sig) & _BLOCKABLE; + spin_lock_irq(¤t->sigmask_lock); + current->blocked |= n; + spin_unlock_irq(¤t->sigmask_lock); + return 0; + } +} + +static inline long solaris_sighold(int sig) +{ + return solaris_sigset(sig, 2); +} + +static inline long solaris_sigrelse(int sig) +{ + spin_lock_irq(¤t->sigmask_lock); + current->blocked &= ~_S(sig); + spin_unlock_irq(¤t->sigmask_lock); + return 0; +} + +static inline long solaris_sigignore(int sig) +{ + return sig_handler (sig, (u32)SIG_IGN, 0); +} + +static inline long solaris_sigpause(int sig) +{ + printk ("Need to support solaris sigpause\n"); + return -ENOSYS; +} + +asmlinkage long solaris_sigfunc(int sig, u32 arg) +{ + int func = sig & ~0xff; + + sig = mapsig(sig & 0xff); + if (sig < 0) return sig; + switch (func) { + case 0: return solaris_signal(sig, arg); + case 0x100: return solaris_sigset(sig, arg); + case 0x200: return solaris_sighold(sig); + case 0x400: return solaris_sigrelse(sig); + case 0x800: return solaris_sigignore(sig); + case 0x1000: return solaris_sigpause(sig); + } + return -EINVAL; +} + +typedef struct { + u32 __sigbits[4]; +} sol_sigset_t; + +static inline int mapin(u32 *p, sigset_t *q) +{ + int i; + u32 x; + int sig; + + *q = 0L; + x = p[0]; + for (i = 1; i <= SOLARIS_NSIGNALS; i++) { + if (x & 1) { + sig = solaris_to_linux_signals[i]; + if (sig == -1) + return -EINVAL; + *q |= 1L << (sig - 1); + } + x >>= 1; + if (i == 32) + x = p[1]; + } + return 0; +} + +static inline int mapout(sigset_t *q, u32 *p) +{ + int i; + sigset_t x; + int sig; + + p[0] = 0; + p[1] = 0; + x = *q; + for (i = 1; i <= 32; i++, x >>= 1) { + if (x & 1) { + sig = linux_to_solaris_signals[i]; + if (sig == -1) + return -EINVAL; + if (sig > 32) + p[1] |= 1L << (sig - 33); + else + p[0] |= 1L << (sig - 1); + } + } + return 0; + +} + +asmlinkage int solaris_sigprocmask(int how, u32 in, u32 out) +{ + sigset_t in_s, *ins, out_s, *outs; + unsigned long old_fs = get_fs(); + int ret; + int (*sys_sigprocmask)(int,sigset_t *,sigset_t *) = + (int (*)(int,sigset_t *,sigset_t *))SYS(sigprocmask); + + ins = NULL; outs = NULL; + if (in) { + u32 tmp[2]; + + if (copy_from_user (tmp, (sol_sigset_t *)A(in), 2*sizeof(u32))) + return -EFAULT; + ins = &in_s; + if (mapin (tmp, ins)) return -EINVAL; + } + if (out) outs = &out_s; + set_fs (KERNEL_DS); + ret = sys_sigprocmask((how == 3) ? SIG_SETMASK : how, ins, outs); + set_fs (old_fs); + if (ret) return ret; + if (out) { + u32 tmp[4]; + + tmp[2] = 0; tmp[3] = 0; + if (mapout (outs, tmp)) return -EINVAL; + if (copy_to_user((sol_sigset_t *)A(out), tmp, 4*sizeof(u32))) + return -EFAULT; + } + return 0; +} + +asmlinkage long do_sol_sigsuspend(u32 mask) +{ + sigset_t s; + u32 tmp[2]; + + if (copy_from_user (tmp, (sol_sigset_t *)A(mask), 2*sizeof(u32))) + return -EFAULT; + if (mapin (tmp, &s)) return -EINVAL; + return (long)s; +} + +struct sol_sigaction { + int sa_flags; + u32 sa_handler; + u32 sa_mask[4]; + int sa_resv[2]; +}; + +asmlinkage int solaris_sigaction(int sig, u32 act, u32 old) +{ + u32 tmp, tmp2[4]; + struct sigaction s, s2; + int ret; + unsigned long old_fs = get_fs(); + int (*sys_sigaction)(int,struct sigaction *,struct sigaction *) = + (int (*)(int,struct sigaction *,struct sigaction *))SYS(sigaction); + + sig = mapsig(sig); + if (sig < 0) { + /* We cheat a little bit for Solaris only signals */ + if (old && clear_user((struct sol_sigaction *)A(old), sizeof(struct sol_sigaction))) + return -EFAULT; + return 0; + } + if (act) { + if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_flags)) + return -EFAULT; + s.sa_flags = 0; + if (tmp & SOLARIS_SA_ONSTACK) s.sa_flags |= SA_STACK; + if (tmp & SOLARIS_SA_RESTART) s.sa_flags |= SA_RESTART; + if (tmp & SOLARIS_SA_NODEFER) s.sa_flags |= SA_NOMASK; + if (tmp & SOLARIS_SA_RESETHAND) s.sa_flags |= SA_ONESHOT; + if (tmp & SOLARIS_SA_NOCLDSTOP) s.sa_flags |= SA_NOCLDSTOP; + if (get_user (tmp, &((struct sol_sigaction *)A(act))->sa_handler) || + copy_from_user (tmp2, &((struct sol_sigaction *)A(act))->sa_mask, 2*sizeof(u32))) + return -EFAULT; + s.sa_handler = (__sighandler_t)A(tmp); + if (mapin (tmp2, &s.sa_mask)) return -EINVAL; + s.sa_restorer = 0; + } + set_fs(KERNEL_DS); + ret = sys_sigaction(sig, act ? &s : NULL, old ? &s2 : NULL); + set_fs(old_fs); + if (ret) return ret; + if (old) { + if (mapout (&s2.sa_mask, tmp2)) return -EINVAL; + tmp = 0; tmp2[2] = 0; tmp2[3] = 0; + if (s2.sa_flags & SA_STACK) tmp |= SOLARIS_SA_ONSTACK; + if (s2.sa_flags & SA_RESTART) tmp |= SOLARIS_SA_RESTART; + if (s2.sa_flags & SA_NOMASK) tmp |= SOLARIS_SA_NODEFER; + if (s2.sa_flags & SA_ONESHOT) tmp |= SOLARIS_SA_RESETHAND; + if (s2.sa_flags & SA_NOCLDSTOP) tmp |= SOLARIS_SA_NOCLDSTOP; + if (put_user (tmp, &((struct sol_sigaction *)A(old))->sa_flags) || + __put_user ((u32)(long)s2.sa_handler, &((struct sol_sigaction *)A(old))->sa_handler) || + copy_to_user (&((struct sol_sigaction *)A(old))->sa_mask, tmp2, 4*sizeof(u32))) + return -EFAULT; + } + return 0; +} + +asmlinkage int solaris_sigpending(int which, u32 set) +{ + sigset_t s; + u32 tmp[4]; + switch (which) { + case 1: /* sigpending */ + lock_kernel(); + s = current->blocked & current->signal; + unlock_kernel(); + break; + case 2: /* sigfillset - I just set signals which have linux equivalents */ + s = 0x7fffffff; + break; + default: return -EINVAL; + } + if (mapout (&s, tmp)) return -EINVAL; + tmp[2] = 0; tmp[3] = 0; + if (copy_to_user ((u32 *)A(set), tmp, sizeof(tmp))) + return -EFAULT; + return 0; +} + +asmlinkage int solaris_wait(u32 stat_loc) +{ + int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) = + (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4); + int ret, status; + + ret = sys_wait4(-1, (unsigned int *)A(stat_loc), WUNTRACED, NULL); + if (ret >= 0 && stat_loc) { + if (get_user (status, (unsigned int *)A(stat_loc))) + return -EFAULT; + if (((status - 1) & 0xffff) < 0xff) + status = linux_to_solaris_signals[status & 0x7f] & 0x7f; + else if ((status & 0xff) == 0x7f) + status = (linux_to_solaris_signals[(status >> 8) & 0xff] << 8) | 0x7f; + if (__put_user (status, (unsigned int *)A(stat_loc))) + return -EFAULT; + } + return ret; +} + +asmlinkage int solaris_waitid(int idtype, s32 pid, u32 info, int options) +{ + int (*sys_wait4)(pid_t,unsigned int *, int, struct rusage *) = + (int (*)(pid_t,unsigned int *, int, struct rusage *))SYS(wait4); + int opts, status, ret; + + switch (idtype) { + case 0: /* P_PID */ break; + case 1: /* P_PGID */ pid = -pid; break; + case 7: /* P_ALL */ pid = -1; break; + default: return -EINVAL; + } + opts = 0; + if (options & SOLARIS_WUNTRACED) opts |= WUNTRACED; + if (options & SOLARIS_WNOHANG) opts |= WNOHANG; + current->state = TASK_RUNNING; + ret = sys_wait4(pid, (unsigned int *)A(info), opts, NULL); + if (ret < 0) return ret; + if (info) { + struct sol_siginfo *s = (struct sol_siginfo *)A(info); + + if (get_user (status, (unsigned int *)A(info))) return -EFAULT; + __put_user_ret (SOLARIS_SIGCLD, &s->si_signo, -EFAULT); + __put_user_ret (ret, &s->_data._proc._pid, -EFAULT); + switch (status & 0xff) { + case 0: ret = SOLARIS_CLD_EXITED; + status = (status >> 8) & 0xff; + break; + case 0x7f: + status = (status >> 8) & 0xff; + switch (status) { + case SIGSTOP: + case SIGTSTP: ret = SOLARIS_CLD_STOPPED; + default: ret = SOLARIS_CLD_EXITED; + } + status = linux_to_solaris_signals[status]; + break; + default: + if (status & 0x80) ret = SOLARIS_CLD_DUMPED; + else ret = SOLARIS_CLD_KILLED; + status = linux_to_solaris_signals[status & 0x7f]; + break; + } + __put_user_ret (ret, &s->si_code, -EFAULT); + __put_user_ret (status, &s->_data._proc._pdata._cld._status, -EFAULT); + } + return 0; +} + +extern int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs); +extern int svr4_getcontext(svr4_ucontext_t *c, struct pt_regs *regs); + +asmlinkage int solaris_context(struct pt_regs *regs) +{ + switch ((unsigned)regs->u_regs[UREG_I0]) { + case 0: /* getcontext */ + return svr4_getcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs); + case 1: /* setcontext */ + return svr4_setcontext((svr4_ucontext_t *)(long)(u32)regs->u_regs[UREG_I1], regs); + default: + return -EINVAL; + + } +} + +asmlinkage int solaris_sigaltstack(u32 ss, u32 oss) +{ +/* XXX Implement this soon */ + return 0; +} diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h new file mode 100644 index 000000000..2e948c788 --- /dev/null +++ b/arch/sparc64/solaris/signal.h @@ -0,0 +1,109 @@ +/* $Id: signal.h,v 1.2 1997/09/03 12:29:21 jj Exp $ + * signal.h: Signal emulation for Solaris + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + */ + +#define SOLARIS_SIGHUP 1 +#define SOLARIS_SIGINT 2 +#define SOLARIS_SIGQUIT 3 +#define SOLARIS_SIGILL 4 +#define SOLARIS_SIGTRAP 5 +#define SOLARIS_SIGIOT 6 +#define SOLARIS_SIGEMT 7 +#define SOLARIS_SIGFPE 8 +#define SOLARIS_SIGKILL 9 +#define SOLARIS_SIGBUS 10 +#define SOLARIS_SIGSEGV 11 +#define SOLARIS_SIGSYS 12 +#define SOLARIS_SIGPIPE 13 +#define SOLARIS_SIGALRM 14 +#define SOLARIS_SIGTERM 15 +#define SOLARIS_SIGUSR1 16 +#define SOLARIS_SIGUSR2 17 +#define SOLARIS_SIGCLD 18 +#define SOLARIS_SIGPWR 19 +#define SOLARIS_SIGWINCH 20 +#define SOLARIS_SIGURG 21 +#define SOLARIS_SIGPOLL 22 +#define SOLARIS_SIGSTOP 23 +#define SOLARIS_SIGTSTP 24 +#define SOLARIS_SIGCONT 25 +#define SOLARIS_SIGTTIN 26 +#define SOLARIS_SIGTTOU 27 +#define SOLARIS_SIGVTALRM 28 +#define SOLARIS_SIGPROF 29 +#define SOLARIS_SIGXCPU 30 +#define SOLARIS_SIGXFSZ 31 +#define SOLARIS_SIGWAITING 32 +#define SOLARIS_SIGLWP 33 +#define SOLARIS_SIGFREEZE 34 +#define SOLARIS_SIGTHAW 35 +#define SOLARIS_SIGCANCEL 36 +#define SOLARIS_SIGRTMIN 37 +#define SOLARIS_SIGRTMAX 44 +#define SOLARIS_NSIGNALS 44 + + +#define SOLARIS_SA_ONSTACK 1 +#define SOLARIS_SA_RESETHAND 2 +#define SOLARIS_SA_RESTART 4 +#define SOLARIS_SA_SIGINFO 8 +#define SOLARIS_SA_NODEFER 16 +#define SOLARIS_SA_NOCLDWAIT 0x10000 +#define SOLARIS_SA_NOCLDSTOP 0x20000 + +struct sol_siginfo { + int si_signo; + int si_code; + int si_errno; + union { + char pad[128-3*sizeof(int)]; + struct { + s32 _pid; + union { + struct { + s32 _uid; + s32 _value; + } _kill; + struct { + s32 _utime; + int _status; + s32 _stime; + } _cld; + } _pdata; + } _proc; + struct { /* SIGSEGV, SIGBUS, SIGILL and SIGFPE */ + u32 _addr; + int _trapno; + } _fault; + struct { /* SIGPOLL, SIGXFSZ */ + int _fd; + s32 _band; + } _file; + } _data; +}; + +#define SOLARIS_WUNTRACED 0x04 +#define SOLARIS_WNOHANG 0x40 +#define SOLARIS_WEXITED 0x01 +#define SOLARIS_WTRAPPED 0x02 +#define SOLARIS_WSTOPPED WUNTRACED +#define SOLARIS_WCONTINUED 0x08 +#define SOLARIS_WNOWAIT 0x80 + +#define SOLARIS_TRAP_BRKPT 1 +#define SOLARIS_TRAP_TRACE 2 +#define SOLARIS_CLD_EXITED 1 +#define SOLARIS_CLD_KILLED 2 +#define SOLARIS_CLD_DUMPED 3 +#define SOLARIS_CLD_TRAPPED 4 +#define SOLARIS_CLD_STOPPED 5 +#define SOLARIS_CLD_CONTINUED 6 +#define SOLARIS_POLL_IN 1 +#define SOLARIS_POLL_OUT 2 +#define SOLARIS_POLL_MSG 3 +#define SOLARIS_POLL_ERR 4 +#define SOLARIS_POLL_PRI 5 +#define SOLARIS_POLL_HUP 6 + diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c new file mode 100644 index 000000000..984b1bdb5 --- /dev/null +++ b/arch/sparc64/solaris/socksys.c @@ -0,0 +1,127 @@ +/* $Id: socksys.c,v 1.1 1997/09/03 12:29:27 jj Exp $ + * socksys.c: /dev/inet/ stuff for Solaris emulation. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1995, 1996 Mike Jagdis (jaggy@purplet.demon.co.uk) + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/ioctl.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/poll.h> + +#include <asm/uaccess.h> +#include <asm/termios.h> + +#include "conv.h" + +extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, + unsigned long arg); + +static int af_inet_protocols[] = { +IPPROTO_ICMP, IPPROTO_ICMP, IPPROTO_IGMP, IPPROTO_IPIP, IPPROTO_TCP, +IPPROTO_EGP, IPPROTO_PUP, IPPROTO_UDP, IPPROTO_IDP, IPPROTO_RAW, +0, 0, 0, 0, 0, 0, +}; + +static struct file_operations socksys_file_ops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ +}; + +static int socksys_open(struct inode * inode, struct file * filp) +{ + int family, type, protocol, fd; + int (*sys_socket)(int,int,int) = + (int (*)(int,int,int))SUNOS(97); + + family = ((MINOR(inode->i_rdev) >> 4) & 0xf); + switch (family) { + case AF_UNIX: + type = SOCK_STREAM; + protocol = 0; + break; + case AF_INET: + protocol = af_inet_protocols[MINOR(inode->i_rdev) & 0xf]; + switch (protocol) { + case IPPROTO_TCP: type = SOCK_STREAM; break; + case IPPROTO_UDP: type = SOCK_DGRAM; break; + default: type = SOCK_RAW; break; + } + break; + default: + type = SOCK_RAW; + protocol = 0; + break; + } + fd = sys_socket(family, type, protocol); + if (fd < 0) return fd; + return 0; +} + +static int socksys_release(struct inode * inode, struct file * filp) +{ + return 0; +} + +static unsigned int socksys_poll(struct file * filp, poll_table * wait) +{ + return 0; +} + +static struct file_operations socksys_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + NULL, /* ioctl */ + NULL, /* mmap */ + socksys_open, /* open */ + socksys_release,/* release */ +}; + +__initfunc(int +init_socksys(void)) +{ + int ret; + int (*sys_socket)(int,int,int) = + (int (*)(int,int,int))SUNOS(97); + int (*sys_close)(unsigned int) = + (int (*)(unsigned int))SYS(close); + + ret = register_chrdev (30, "socksys", &socksys_fops); + if (ret < 0) { + printk ("Couldn't register socksys character device\n"); + return ret; + } + ret = sys_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (ret < 0) { + printk ("Couldn't create socket\n"); + return ret; + } + socksys_file_ops = *current->files->fd[ret]->f_op; + sys_close(ret); + socksys_file_ops.poll = socksys_poll; + socksys_file_ops.release = socksys_release; + return 0; +} + +void +cleanup_socksys(void) +{ + if (unregister_chrdev (30, "socksys")) + printk ("Couldn't unregister socksys character device\n"); +} diff --git a/arch/sparc64/solaris/systbl.S b/arch/sparc64/solaris/systbl.S new file mode 100644 index 000000000..c425fb721 --- /dev/null +++ b/arch/sparc64/solaris/systbl.S @@ -0,0 +1,289 @@ +/* $Id: systbl.S,v 1.5 1997/09/04 15:46:24 jj Exp $ + * systbl.S: System call entry point table for Solaris compatibility. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) + */ + +#include <asm/unistd.h> + +/* Fall back to sys_call_table32 entry */ +#define CHAIN(name) __NR_##name + +/* Pass pt_regs pointer as first argument */ +#define REGS(name) name+1 + +/* Hack till all be implemented */ +#define solaris_getmsg solaris_unimplemented +#define solaris_getpmsg solaris_unimplemented +#define solaris_hrtsys solaris_unimplemented +#define solaris_msgsys solaris_unimplemented +#define solaris_putmsg solaris_unimplemented +#define solaris_putpmsg solaris_unimplemented +#define solaris_semsys solaris_unimplemented + + .data + .align 1024 + .globl solaris_sys_table +solaris_sys_table: + .word solaris_unimplemented /* nosys 0 */ + .word CHAIN(exit) /* exit d 1 */ + .word CHAIN(fork) /* fork 2 */ + .word CHAIN(read) /* read dpd 3 */ + .word CHAIN(write) /* write dpd 4 */ + .word solaris_open /* open soo 5 */ + .word CHAIN(close) /* close d 6 */ + .word solaris_wait /* wait xxx 7 */ + .word CHAIN(creat) /* creat so 8 */ + .word CHAIN(link) /* link ss 9 */ + .word CHAIN(unlink) /* unlink s 10 */ + .word solaris_unimplemented /* exec sxx 11 */ + .word CHAIN(chdir) /* chdir s 12 */ + .word CHAIN(time) /* time 13 */ + .word solaris_mknod /* mknod sox 14 */ + .word CHAIN(chmod) /* chmod so 15 */ + .word solaris_chown /* chown sdd 16 */ + .word solaris_brk /* brk/break x 17 */ + .word solaris_stat /* stat sp 18 */ + .word CHAIN(lseek) /* seek/lseek ddd 19 */ + .word solaris_getpid /* getpid 20 */ + .word solaris_unimplemented /* mount 21 */ + .word CHAIN(umount) /* umount s 22 */ + .word CHAIN(setuid) /* setuid d 23 */ + .word solaris_getuid /* getuid 24 */ + .word CHAIN(stime) /* stime d 25 */ +#if 0 + .word solaris_ptrace /* ptrace xdxx 26 */ +#else + .word CHAIN(ptrace) /* ptrace xdxx 26 */ +#endif + .word CHAIN(alarm) /* alarm d 27 */ + .word solaris_fstat /* fstat dp 28 */ + .word CHAIN(pause) /* pause 29 */ + .word CHAIN(utime) /* utime xx 30 */ + .word solaris_unimplemented /* stty 31 */ + .word solaris_unimplemented /* gtty 32 */ + .word solaris_access /* access so 33 */ + .word CHAIN(nice) /* nice d 34 */ + .word solaris_statfs /* statfs spdd 35 */ + .word CHAIN(sync) /* sync 36 */ + .word solaris_kill /* kill dd 37 */ + .word solaris_fstatfs /* fstatfs dpdd 38 */ + .word solaris_procids /* pgrpsys ddd 39 */ + .word solaris_unimplemented /* xenix 40 */ + .word CHAIN(dup) /* dup d 41 */ + .word CHAIN(pipe) /* pipe 42 */ + .word CHAIN(times) /* times p 43 */ + .word CHAIN(profil) /* prof xxxx 44 */ + .word solaris_unimplemented /* lock/plock 45 */ + .word CHAIN(setgid) /* setgid d 46 */ + .word solaris_getgid /* getgid 47 */ + .word solaris_sigfunc /* sigfunc xx 48 */ + .word REGS(solaris_msgsys) /* msgsys dxddd 49 */ + .word solaris_unimplemented /* syssun/3b 50 */ + .word CHAIN(acct) /* acct/sysacct x 51 */ + .word solaris_shmsys /* shmsys ddxo 52 */ + .word REGS(solaris_semsys) /* semsys dddx 53 */ + .word solaris_ioctl /* ioctl dxx 54 */ + .word solaris_unimplemented /* uadmin xxx 55 */ + .word solaris_unimplemented /* reserved:exch 56 */ + .word solaris_utssys /* utssys x 57 */ + .word CHAIN(fsync) /* fsync d 58 */ + .word CHAIN(execve) /* execv spp 59 */ + .word CHAIN(umask) /* umask o 60 */ + .word CHAIN(chroot) /* chroot s 61 */ + .word solaris_fcntl /* fcntl dxx 62 */ + .word solaris_ulimit /* ulimit xx 63 */ + .word solaris_unimplemented /* ? 64 */ + .word solaris_unimplemented /* ? 65 */ + .word solaris_unimplemented /* ? 66 */ + .word solaris_unimplemented /* ? 67 */ + .word solaris_unimplemented /* ? 68 */ + .word solaris_unimplemented /* ? 69 */ + .word solaris_unimplemented /* advfs 70 */ + .word solaris_unimplemented /* unadvfs 71 */ + .word solaris_unimplemented /* rmount 72 */ + .word solaris_unimplemented /* rumount 73 */ + .word solaris_unimplemented /* rfstart 74 */ + .word solaris_unimplemented /* ? 75 */ + .word solaris_unimplemented /* rdebug 76 */ + .word solaris_unimplemented /* rfstop 77 */ + .word solaris_unimplemented /* rfsys 78 */ + .word CHAIN(rmdir) /* rmdir s 79 */ + .word CHAIN(mkdir) /* mkdir so 80 */ + .word CHAIN(getdents) /* getdents dxd 81 */ + .word solaris_unimplemented /* libattach 82 */ + .word solaris_unimplemented /* libdetach 83 */ + .word CHAIN(sysfs) /* sysfs dxx 84 */ + .word REGS(solaris_getmsg) /* getmsg dxxx 85 */ + .word REGS(solaris_putmsg) /* putmsg dxxd 86 */ + .word CHAIN(poll) /* poll xdd 87 */ + .word solaris_lstat /* lstat sp 88 */ + .word CHAIN(symlink) /* symlink ss 89 */ + .word CHAIN(readlink) /* readlink spd 90 */ + .word CHAIN(setgroups) /* setgroups dp 91 */ + .word CHAIN(getgroups) /* getgroups dp 92 */ + .word CHAIN(fchmod) /* fchmod do 93 */ + .word CHAIN(fchown) /* fchown ddd 94 */ + .word solaris_sigprocmask /* sigprocmask dxx 95 */ + .word solaris_sigsuspend /* sigsuspend x 96 */ + .word solaris_sigaltstack /* sigaltstack xx 97 */ + .word solaris_sigaction /* sigaction dxx 98 */ + .word solaris_sigpending /* sigpending dd 99 */ + .word REGS(solaris_context) /* context 100 */ + .word solaris_unimplemented /* evsys 101 */ + .word solaris_unimplemented /* evtrapret 102 */ + .word solaris_statvfs /* statvfs sp 103 */ + .word solaris_fstatvfs /* fstatvfs dp 104 */ + .word solaris_unimplemented /* unknown 105 */ + .word solaris_unimplemented /* nfssys 106 */ + .word solaris_waitid /* waitid ddxd 107 */ + .word solaris_unimplemented /* sigsendsys ddd 108 */ + .word REGS(solaris_hrtsys) /* hrtsys xxx 109 */ + .word solaris_unimplemented /* acancel dxd 110 */ + .word solaris_unimplemented /* async 111 */ + .word solaris_unimplemented /* priocntlsys 112 */ + .word solaris_pathconf /* pathconf sd 113 */ + .word solaris_unimplemented /* mincore xdx 114 */ + .word solaris_mmap /* mmap xxxxdx 115 */ + .word CHAIN(mprotect) /* mprotect xdx 116 */ + .word CHAIN(munmap) /* munmap xd 117 */ + .word solaris_fpathconf /* fpathconf dd 118 */ + .word CHAIN(fork) /* fork 119 */ + .word solaris_unimplemented /* fchdir d 120 */ + .word CHAIN(readv) /* readv dxd 121 */ + .word CHAIN(writev) /* writev dxd 122 */ + .word solaris_xstat /* xstat dsx 123 */ + .word solaris_lxstat /* lxstat dsx 124 */ + .word solaris_fxstat /* fxstat ddx 125 */ + .word solaris_xmknod /* xmknod dsox 126 */ + .word solaris_unimplemented /* syslocal d 127 */ + .word solaris_unimplemented /* setrlimit 128 */ + .word solaris_unimplemented /* getrlimit 129 */ + .word CHAIN(chown) /* lchown sdd 130 */ + .word solaris_unimplemented /* memcntl 131 */ + .word solaris_getpmsg /* getpmsg dxxxx 132 */ + .word solaris_putpmsg /* putpmsg dxxdd 133 */ + .word CHAIN(rename) /* rename ss 134 */ + .word solaris_utsname /* uname x 135 */ + .word solaris_unimplemented /* setegid 136 */ + .word solaris_sysconf /* sysconfig d 137 */ + .word solaris_unimplemented /* adjtime 138 */ + .word solaris_sysinfo /* systeminfo dsd 139 */ + .word solaris_unimplemented /* ? 140 */ + .word solaris_unimplemented /* seteuid 141 */ + .word solaris_unimplemented /* ? 142 */ + .word solaris_unimplemented /* ? 143 */ + .word solaris_unimplemented /* secsys dx 144 */ + .word solaris_unimplemented /* filepriv sdxd 145 */ + .word solaris_unimplemented /* procpriv dxd 146 */ + .word solaris_unimplemented /* devstat sdx 147 */ + .word solaris_unimplemented /* aclipc ddddx 148 */ + .word solaris_unimplemented /* fdevstat ddx 149 */ + .word solaris_unimplemented /* flvlfile ddx 150 */ + .word solaris_unimplemented /* lvlfile sdx 151 */ + .word solaris_unimplemented /* ? 152 */ + .word solaris_unimplemented /* fchroot d 153 */ + .word solaris_unimplemented /* lvlproc dx 154 */ + .word solaris_unimplemented /* ? 155 */ + .word CHAIN(gettimeofday) /* gettimeofday xx 156 */ + .word CHAIN(getitimer) /* getitimer dx 157 */ + .word CHAIN(setitimer) /* setitimer dxx 158 */ + .word solaris_unimplemented /* lwp-xxx 159 */ + .word solaris_unimplemented /* lwp-xxx 160 */ + .word solaris_unimplemented /* lwp-xxx 161 */ + .word solaris_unimplemented /* lwp-xxx 162 */ + .word solaris_unimplemented /* lwp-xxx 163 */ + .word solaris_unimplemented /* lwp-xxx 164 */ + .word solaris_unimplemented /* lwp-xxx 165 */ + .word solaris_unimplemented /* lwp-xxx 166 */ + .word solaris_unimplemented /* lwp-xxx 167 */ + .word solaris_unimplemented /* lwp-xxx 168 */ + .word solaris_unimplemented /* lwp-xxx 169 */ + .word solaris_unimplemented /* lwp-xxx 170 */ + .word solaris_unimplemented /* lwp-xxx 171 */ + .word solaris_unimplemented /* lwp-xxx 172 */ + .word solaris_pread /* pread dpdd 173 */ + .word solaris_pwrite /* pwrite dpdd 174 */ + .word REGS(solaris_llseek) /* llseek dLd 175 */ + .word solaris_unimplemented /* lwpself 176 */ + .word solaris_unimplemented /* lwpinfo 177 */ + .word solaris_unimplemented /* lwpprivate 178 */ + .word solaris_unimplemented /* processorbind 179 */ + .word solaris_unimplemented /* processorexbind 180 */ + .word solaris_unimplemented /* 181 */ + .word solaris_unimplemented /* sync_mailbox 182 */ + .word solaris_unimplemented /* prepblock 183 */ + .word solaris_unimplemented /* block 184 */ + .word solaris_acl /* acl sddp 185 */ + .word solaris_unimplemented /* unblock 186 */ + .word solaris_unimplemented /* cancelblock 187 */ + .word solaris_unimplemented /* ? 188 */ + .word solaris_unimplemented /* xxxxx 189 */ + .word solaris_unimplemented /* xxxxxe 190 */ + .word solaris_unimplemented /* 191 */ + .word solaris_unimplemented /* 192 */ + .word solaris_unimplemented /* 193 */ + .word solaris_unimplemented /* 194 */ + .word solaris_unimplemented /* 195 */ + .word solaris_unimplemented /* 196 */ + .word solaris_unimplemented /* 197 */ + .word solaris_unimplemented /* 198 */ + .word CHAIN(nanosleep) /* nanosleep dd 199 */ + .word solaris_facl /* facl dddp 200 */ + .word solaris_unimplemented /* 201 */ + .word solaris_unimplemented /* 202 */ + .word solaris_unimplemented /* 203 */ + .word solaris_unimplemented /* 204 */ + .word solaris_unimplemented /* 205 */ + .word solaris_unimplemented /* 206 */ + .word solaris_unimplemented /* 207 */ + .word solaris_unimplemented /* 208 */ + .word solaris_unimplemented /* 209 */ + .word solaris_unimplemented /* 210 */ + .word solaris_unimplemented /* 211 */ + .word solaris_unimplemented /* 212 */ + .word solaris_unimplemented /* 213 */ + .word solaris_unimplemented /* 214 */ + .word solaris_unimplemented /* 215 */ + .word solaris_unimplemented /* 216 */ + .word solaris_unimplemented /* 217 */ + .word solaris_unimplemented /* 218 */ + .word solaris_unimplemented /* 219 */ + .word solaris_unimplemented /* 220 */ + .word solaris_unimplemented /* 221 */ + .word solaris_unimplemented /* 222 */ + .word solaris_unimplemented /* 223 */ + .word solaris_unimplemented /* 224 */ + .word solaris_unimplemented /* 225 */ + .word solaris_unimplemented /* 226 */ + .word solaris_unimplemented /* 227 */ + .word solaris_unimplemented /* 228 */ + .word solaris_unimplemented /* 229 */ + .word solaris_unimplemented /* 230 */ + .word solaris_unimplemented /* 231 */ + .word solaris_unimplemented /* 232 */ + .word solaris_unimplemented /* 233 */ + .word solaris_unimplemented /* 234 */ + .word solaris_unimplemented /* 235 */ + .word solaris_unimplemented /* 236 */ + .word solaris_unimplemented /* 237 */ + .word solaris_unimplemented /* 238 */ + .word solaris_unimplemented /* 239 */ + .word solaris_unimplemented /* 240 */ + .word solaris_unimplemented /* 241 */ + .word solaris_unimplemented /* 242 */ + .word solaris_unimplemented /* 243 */ + .word solaris_unimplemented /* 244 */ + .word solaris_unimplemented /* 245 */ + .word solaris_unimplemented /* 246 */ + .word solaris_unimplemented /* 247 */ + .word solaris_unimplemented /* 248 */ + .word solaris_unimplemented /* 249 */ + .word solaris_unimplemented /* 250 */ + .word solaris_unimplemented /* 251 */ + .word solaris_unimplemented /* 252 */ + .word solaris_unimplemented /* 253 */ + .word solaris_unimplemented /* 254 */ + .word solaris_unimplemented /* 255 */ + diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index eac8314ca..661acc098 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -52,12 +52,14 @@ SECTIONS . += 8192; empty_bad_pte_table = .; . += 8192; + empty_bad_page = .; + . += 8192; + . += 0x40; empty_null_pmd_table = .; . += 8192; + . += 0x40; empty_null_pte_table = .; . += 8192; - empty_bad_page = .; - . += 8192; } _end = . ; PROVIDE (end = .); |