diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-10-09 00:00:47 +0000 |
commit | d6434e1042f3b0a6dfe1b1f615af369486f9b1fa (patch) | |
tree | e2be02f33984c48ec019c654051d27964e42c441 /arch/sparc64 | |
parent | 609d1e803baf519487233b765eb487f9ec227a18 (diff) |
Merge with 2.3.19.
Diffstat (limited to 'arch/sparc64')
119 files changed, 6823 insertions, 8571 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index 4df9bc0f5..1216a3a4f 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.37 1999/06/04 13:29:10 jj Exp $ +# $Id: Makefile,v 1.40 1999/08/19 02:31:57 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -15,7 +15,7 @@ SHELL =/bin/bash CC := sparc64-linux-gcc -D__KERNEL__ -I$(TOPDIR)/include CC_HAS_ARGS := $(shell if echo "$(CC)" | grep '\(__KERNEL__\| \)' > /dev/null; then echo y; else echo n; fi) -IS_EGCS := $(shell if $(CC) -c -m64 -mcmodel=medlow -o _tmp.o arch/sparc64/math-emu/fnegq.c >/dev/null 2>&1; then echo y; else echo n; fi; rm -f _tmp.o) +IS_EGCS := $(shell if $(CC) -m64 -mcmodel=medlow -S -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo y; else echo n; fi; ) NEW_GAS := $(shell if $(LD) --version 2>&1 | grep 'elf64_sparc' > /dev/null; then echo y; else echo n; fi) ifneq ($(CC_HAS_ARGS),y) diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index e03e9b427..cf8af1a78 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.67 1999/05/01 09:17:37 davem Exp $ +# $Id: config.in,v 1.78 1999/09/06 01:17:28 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -36,6 +36,7 @@ endmenu # Global things across all Sun machines. define_bool CONFIG_SBUS y define_bool CONFIG_SBUSCHAR y +define_bool CONFIG_BUSMOUSE y define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y @@ -49,9 +50,6 @@ source drivers/sbus/char/Config.in source drivers/sbus/audio/Config.in tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS -if [ "$CONFIG_PCI" = "y" ]; then - bool 'Backward-compatible /proc/pci' CONFIG_PCI_OLD_PROC -fi bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT @@ -66,10 +64,9 @@ tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL fi - +source drivers/parport/Config.in +dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT if [ "$CONFIG_PCI" = "y" ]; then - source drivers/misc/Config.in - dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi endmenu @@ -105,7 +102,8 @@ if [ "$CONFIG_PCI" = "y" ]; then dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE define_bool CONFIG_BLK_DEV_IDEPCI y define_bool CONFIG_BLK_DEV_IDEDMA y - define_bool CONFIG_IDEDMA_PCI_AUTO y + define_bool CONFIG_IDEDMA_AUTO y + define_bool IDEDMA_NEW_DRIVE_LISTINGS y define_bool CONFIG_BLK_DEV_NS87415 y define_bool CONFIG_BLK_DEV_CMD646 y fi @@ -206,6 +204,10 @@ if [ "$CONFIG_NET" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5 tristate '3c590/3c900 series (592/595/597) "Vortex/Boomerang" support' CONFIG_VORTEX + tristate 'RealTek 8129/8139 (not 8019/8029!) support' CONFIG_RTL8139 + tristate 'PCI NE2000 support' CONFIG_NE2K_PCI + tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 + tristate 'Adaptec Starfire support' CONFIG_ADAPTEC_STARFIRE fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 6d865228d..53a69e509 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -27,6 +27,7 @@ CONFIG_VT_CONSOLE=y CONFIG_PROM_CONSOLE=y CONFIG_FB=y CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_CLGEN is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_MATROX is not set CONFIG_FB_ATY=y @@ -49,6 +50,7 @@ CONFIG_FONT_SUN8x16=y # CONFIG_FBCON_FONTS is not set CONFIG_SBUS=y CONFIG_SBUSCHAR=y +CONFIG_BUSMOUSE=y CONFIG_SUN_MOUSE=y CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y @@ -69,6 +71,7 @@ CONFIG_OBP_FLASH=m # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set CONFIG_SUN_AURORA=m +# CONFIG_TADPOLE_TS102_UCTRL is not set CONFIG_APM_RTC_IS_GMT=y # CONFIG_RTC is not set @@ -81,7 +84,6 @@ CONFIG_SPARCAUDIO_CS4231=y # CONFIG_SPARCAUDIO_DBRI is not set # CONFIG_SPARCAUDIO_DUMMY is not set CONFIG_SUN_OPENPROMFS=m -CONFIG_PCI_OLD_PROC=y CONFIG_NET=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set @@ -93,12 +95,14 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_MISC=m CONFIG_SOLARIS_EMUL=m CONFIG_PARPORT=m -# CONFIG_PARPORT_PC is not set +CONFIG_PARPORT_PC=m +CONFIG_PARPORT_PC_FIFO=y # CONFIG_PARPORT_AMIGA is not set # CONFIG_PARPORT_MFC3 is not set # CONFIG_PARPORT_ATARI is not set +# CONFIG_PARPORT_SUNBPP is not set # CONFIG_PARPORT_OTHER is not set -# CONFIG_PARPORT_1284 is not set +CONFIG_PARPORT_1284=y CONFIG_PRINTER=m CONFIG_ENVCTRL=m @@ -106,11 +110,7 @@ CONFIG_ENVCTRL=m # Floppy, IDE, and other block devices # CONFIG_BLK_DEV_FD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_STRIPED=m -CONFIG_MD_MIRRORING=m -CONFIG_MD_RAID5=m +# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_INITRD=y CONFIG_BLK_DEV_LOOP=m @@ -123,7 +123,8 @@ CONFIG_BLK_DEV_IDEFLOPPY=m # CONFIG_BLK_DEV_IDESCSI is not set CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_IDEDMA=y -CONFIG_IDEDMA_PCI_AUTO=y +CONFIG_IDEDMA_AUTO=y +IDEDMA_NEW_DRIVE_LISTINGS=y CONFIG_BLK_DEV_NS87415=y CONFIG_BLK_DEV_CMD646=y @@ -131,8 +132,9 @@ CONFIG_BLK_DEV_CMD646=y # Networking options # CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK is not set -# CONFIG_FIREWALL is not set +# CONFIG_NETFILTER is not set # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y @@ -148,10 +150,11 @@ CONFIG_INET=y # # (it is safe to leave these untouched) # -CONFIG_INET_RARP=m CONFIG_SKB_LARGE=y CONFIG_IPV6=m # CONFIG_IPV6_EUI64 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set # # @@ -172,7 +175,6 @@ CONFIG_DECNET_RAW=y # CONFIG_WAN_ROUTER is not set # CONFIG_NET_FASTROUTE is not set # CONFIG_NET_HW_FLOWCONTROL is not set -# CONFIG_CPU_IS_SLOW is not set # # QoS and/or fair queueing @@ -256,6 +258,10 @@ CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=m CONFIG_VORTEX=m +CONFIG_RTL8139=m +CONFIG_NE2K_PCI=m +CONFIG_EEXPRESS_PRO100=m +CONFIG_ADAPTEC_STARFIRE=m # # Unix 98 PTY support @@ -284,6 +290,8 @@ CONFIG_VFAT_FS=m CONFIG_EFS_FS=m CONFIG_ISO9660_FS=m # CONFIG_JOLIET is not set +CONFIG_UDF_FS=m +# CONFIG_UDF_RW is not set CONFIG_MINIX_FS=m # CONFIG_NTFS_FS is not set CONFIG_HPFS_FS=m @@ -319,13 +327,13 @@ CONFIG_NCP_FS=m # # Partition Types # -CONFIG_BSD_DISKLABEL=y -# CONFIG_MAC_PARTITION is not set -CONFIG_SMD_DISKLABEL=y -CONFIG_SOLARIS_X86_PARTITION=y -# CONFIG_SGI_DISKLABEL is not set +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_SOLARIS_X86_PARTITION is not set # CONFIG_UNIXWARE_DISKLABEL is not set -CONFIG_AMIGA_PARTITION=y +# CONFIG_SGI_PARTITION is not set +CONFIG_SUN_PARTITION=y CONFIG_NLS=y # @@ -356,6 +364,7 @@ CONFIG_NLS=y # CONFIG_NLS_ISO8859_7 is not set # CONFIG_NLS_ISO8859_8 is not set # CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_14 is not set # CONFIG_NLS_ISO8859_15 is not set # CONFIG_NLS_KOI8_R is not set diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 6934dda6e..34f52698e 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.43 1999/01/02 16:45:53 davem Exp $ +# $Id: Makefile,v 1.46 1999/08/31 04:39:34 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -20,7 +20,9 @@ O_OBJS := process.o setup.o cpu.o idprom.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 \ - central.o psycho.o starfire.o + central.o pci.o pci_common.o pci_iommu.o \ + pci_psycho.o pci_sabre.o starfire.o semaphore.o \ + power.o OX_OBJS := sparc64_ksyms.o ifdef CONFIG_PCI @@ -61,12 +63,16 @@ endif check_asm: dummy @echo "/* Automatically generated. Do not edit. */" > asm_offsets.h @echo "#ifndef __ASM_OFFSETS_H__" >> asm_offsets.h - @echo "#define __ASM_OFFSETS_H__" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#include <linux/config.h>" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#ifndef CONFIG_SMP" >> asm_offsets.h - @echo "" >> asm_offsets.h + @echo -e "#define __ASM_OFFSETS_H__\n" >> asm_offsets.h + @echo -e "#include <linux/config.h>\n" >> asm_offsets.h + @echo '#if defined(__KERNEL__) && !defined(__ASSEMBLY__)' >> asm_offsets.h + @if $(CC) -c -m64 -mcmodel=medlow -o /dev/null /dev/null >/dev/null 2>&1; then \ + echo '# if !((__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8))' >> asm_offsets.h; \ + else \ + echo '# if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)' >> asm_offsets.h; \ + fi + @echo -e "# error Please issue 'make check_asm' in linux top-level directory first\n# endif\n#endif\n" >> asm_offsets.h + @echo -e "#ifndef CONFIG_SMP\n" >> asm_offsets.h @echo "#include <linux/config.h>" > tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#include <linux/sched.h>" >> tmp.c @@ -92,11 +98,8 @@ check_asm: dummy # </hack> ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c - @echo "" >> asm_offsets.h - @echo "#else /* CONFIG_SMP */" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#ifndef SPIN_LOCK_DEBUG" >>asm_offsets.h - @echo "" >> asm_offsets.h + @echo -e "\n#else /* CONFIG_SMP */\n" >> asm_offsets.h + @echo -e "#ifndef SPIN_LOCK_DEBUG\n" >>asm_offsets.h @echo "#include <linux/config.h>" > tmp.c @echo "#undef CONFIG_SMP" >> tmp.c @echo "#define CONFIG_SMP 1" >> tmp.c @@ -124,9 +127,7 @@ check_asm: dummy # </hack> ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c - @echo "" >> asm_offsets.h - @echo "#else /* SPIN_LOCK_DEBUG */" >> asm_offsets.h - @echo "" >> asm_offsets.h + @echo -e "\n#else /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h @echo "#include <linux/sched.h>" > tmp.c $(CC) -D__SMP__ -DSPIN_LOCK_DEBUG -E tmp.c -o tmp.i @echo "/* Automatically generated. Do not edit. */" > check_asm.c @@ -151,10 +152,8 @@ check_asm: dummy # </hack> ./check_asm >> asm_offsets.h @rm -f check_asm check_asm.c - @echo "#endif /* SPIN_LOCK_DEBUG */" >> asm_offsets.h - @echo "" >> asm_offsets.h - @echo "#endif /* CONFIG_SMP */" >> asm_offsets.h - @echo "" >> asm_offsets.h + @echo -e "#endif /* SPIN_LOCK_DEBUG */\n" >> asm_offsets.h + @echo -e "#endif /* CONFIG_SMP */\n" >> asm_offsets.h @echo "#endif /* __ASM_OFFSETS_H__ */" >> asm_offsets.h @if test -r $(HPATH)/asm/asm_offsets.h; then \ if cmp -s asm_offsets.h $(HPATH)/asm/asm_offsets.h; then \ diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index a674399e4..c6bcb6bd7 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -22,7 +22,7 @@ /* Probe and map in the Auxiliary I/O register */ unsigned char *auxio_register; -__initfunc(void auxio_probe(void)) +void __init auxio_probe(void) { struct linux_sbus *bus; struct linux_sbus_device *sdev = 0; @@ -51,17 +51,7 @@ __initfunc(void auxio_probe(void)) ebus_done: 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]; + led_auxio = edev->resource[0].start; outl(0x01, led_auxio); return; } diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index bc77266f9..cbbb3557b 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -39,7 +39,8 @@ static int aout32_core_dump(long signr, struct pt_regs * regs); extern void dump_thread(struct pt_regs *, struct user *); static struct linux_binfmt aout32_format = { - NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump + NULL, NULL, load_aout32_binary, load_aout32_library, aout32_core_dump, + PAGE_SIZE }; static void set_brk(unsigned long start, unsigned long end) @@ -63,12 +64,12 @@ static int dump_write(struct file *file, const void *addr, int nr) #define DUMP_WRITE(addr, nr) \ if (!dump_write(file, (void *)(addr), (nr))) \ - goto close_coredump; + goto end_coredump; #define DUMP_SEEK(offset) \ if (file->f_op->llseek) { \ if (file->f_op->llseek(file,(offset),0) != (offset)) \ - goto close_coredump; \ + goto end_coredump; \ } else file->f_pos = (offset) /* @@ -82,45 +83,17 @@ if (file->f_op->llseek) { \ */ static inline int -do_aout32_core_dump(long signr, struct pt_regs * regs) +do_aout32_core_dump(long signr, struct pt_regs * regs, struct file *file) { - struct dentry * dentry = NULL; - struct inode * inode = NULL; - struct file * file; mm_segment_t fs; int has_dumped = 0; - char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; struct user dump; # define START_DATA(u) (u.u_tsize) # define START_STACK(u) ((regs->u_regs[UREG_FP]) & ~(PAGE_SIZE - 1)) - if (!current->dumpable || atomic_read(¤t->mm->count) != 1) - return 0; - current->dumpable = 0; - -/* See if we have enough room to write the upage. */ - if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) - return 0; fs = get_fs(); set_fs(KERNEL_DS); - memcpy(corefile,"core.",5); -#if 0 - memcpy(corefile+5,current->comm,sizeof(current->comm)); -#else - corefile[4] = '\0'; -#endif - file = filp_open(corefile,O_CREAT | 2 | O_TRUNC | O_NOFOLLOW, 0600); - if (IS_ERR(file)) - goto end_coredump; - dentry = file->f_dentry; - inode = dentry->d_inode; - if (!S_ISREG(inode->i_mode)) - goto close_coredump; - if (!inode->i_op || !inode->i_op->default_file_ops) - goto close_coredump; - if (!file->f_op->write) - goto close_coredump; has_dumped = 1; current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(current->comm)); @@ -165,20 +138,18 @@ do_aout32_core_dump(long signr, struct pt_regs * regs) /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); -close_coredump: - filp_close(file, NULL); end_coredump: set_fs(fs); return has_dumped; } static int -aout32_core_dump(long signr, struct pt_regs * regs) +aout32_core_dump(long signr, struct pt_regs * regs, struct file * file) { int retval; MOD_INC_USE_COUNT; - retval = do_aout32_core_dump(signr, regs); + retval = do_aout32_core_dump(signr, regs, file); MOD_DEC_USE_COUNT; return retval; } @@ -368,6 +339,16 @@ beyond_if: current->mm->start_stack = (unsigned long) create_aout32_tables((char *)bprm->p, bprm); + if (!(current->thread.flags & SPARC_FLAG_32BIT)) { + unsigned long pgd_cache; + + pgd_cache = ((unsigned long)current->mm->pgd[0])<<11UL; + __asm__ __volatile__("stxa\t%0, [%1] %2" + : /* no outputs */ + : "r" (pgd_cache), + "r" (TSB_REG), "i" (ASI_DMMU)); + current->thread.flags |= SPARC_FLAG_32BIT; + } start_thread32(regs, ex.a_entry, current->mm->start_stack); if (current->flags & PF_PTRACED) send_sig(SIGTRAP, current, 0); @@ -472,7 +453,7 @@ load_aout32_library(int fd) } -__initfunc(int init_aout32_binfmt(void)) +int __init init_aout32_binfmt(void) { return register_binfmt(&aout32_format); } diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c index f0c36d1a7..252a685f4 100644 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ b/arch/sparc64/kernel/binfmt_elf32.c @@ -142,7 +142,7 @@ struct elf_prpsinfo32 #ifdef CONFIG_BINFMT_ELF32_MODULE #define CONFIG_BINFMT_ELF_MODULE CONFIG_BINFMT_ELF32_MODULE #endif -#define ELF_FLAGS_INIT current->tss.flags |= SPARC_FLAG_32BIT +#define ELF_FLAGS_INIT current->thread.flags |= SPARC_FLAG_32BIT MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra"); MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c index 86518e50e..dbcc0d45f 100644 --- a/arch/sparc64/kernel/cpu.c +++ b/arch/sparc64/kernel/cpu.c @@ -33,7 +33,7 @@ struct cpu_fp_info linux_sparc_fpu[] = { { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"}, - { 0x17, 0x13, 0, "UltraSparc III integrated FPU"}, + { 0x17, 0x14, 0, "UltraSparc III integrated FPU"}, }; #define NSPARCFPU (sizeof(linux_sparc_fpu)/sizeof(struct cpu_fp_info)) @@ -43,7 +43,7 @@ struct cpu_iu_info linux_sparc_chips[] = { { 0x22, 0x10, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x12, "TI UltraSparc IIi"}, - { 0x17, 0x13, "TI UltraSparc III (Cheetah)"}, /* A guess... */ + { 0x17, 0x14, "TI UltraSparc III (Cheetah)"}, /* A guess... */ }; #define NSPARCCHIPS (sizeof(linux_sparc_chips)/sizeof(struct cpu_iu_info)) @@ -58,7 +58,7 @@ char *sparc_fpu_type[64] = { "fpu-oops", }; unsigned int fsr_storage; -__initfunc(void cpu_probe(void)) +void __init cpu_probe(void) { int manuf, impl; unsigned i, cpuid; diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 0aef0b019..d8085bf06 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -5,8 +5,9 @@ */ #include <linux/kernel.h> -#include <linux/tasks.h> +#include <linux/threads.h> #include <linux/init.h> +#include <linux/ioport.h> #include <asm/page.h> #include <asm/oplib.h> @@ -20,14 +21,18 @@ 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)) +unsigned long __init +device_scan(unsigned long mem_start) { char node_str[128]; int nd, prom_node_cpu, thismid; int cpu_nds[64]; /* One node for each cpu */ int cpu_ctr = 0; + /* FIX ME FAST... -DaveM */ + ioport_resource.end = 0xffffffffffffffffUL; + iomem_resource.end = 0xffffffffffffffffUL; + prom_getstring(prom_root_node, "device_type", node_str, sizeof(node_str)); prom_printf("Booting Linux...\n"); diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index e64e87299..0b3d16007 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,7 +1,8 @@ -/* $Id: ebus.c,v 1.36 1999/05/04 03:21:42 davem Exp $ +/* $Id: ebus.c,v 1.44 1999/09/05 09:28:09 ecd Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 David S. Miller (davem@redhat.com) */ #include <linux/config.h> @@ -17,15 +18,7 @@ #include <asm/ebus.h> #include <asm/oplib.h> #include <asm/bpp.h> - -#undef PROM_DEBUG -#undef DEBUG_FILL_EBUS_DEV - -#ifdef PROM_DEBUG -#define dprintf prom_printf -#else -#define dprintf printk -#endif +#include <asm/irq.h> struct linux_ebus *ebus_chain = 0; @@ -45,20 +38,20 @@ extern int flash_init(void); extern int envctrl_init(void); #endif -static inline unsigned long ebus_alloc(size_t size) +static inline void *ebus_alloc(size_t size) { - unsigned long mem; + void *mem; - mem = (unsigned long)kmalloc(size, GFP_ATOMIC); + mem = kmalloc(size, GFP_ATOMIC); if (!mem) panic(__FUNCTION__ ": out of memory"); memset((char *)mem, 0, size); return mem; } -__initfunc(void ebus_intmap_match(struct linux_ebus *ebus, - struct linux_prom_registers *reg, - int *interrupt)) +void __init ebus_intmap_match(struct linux_ebus *ebus, + struct linux_prom_registers *reg, + int *interrupt) { unsigned int hi, lo, irq; int i; @@ -83,28 +76,43 @@ __initfunc(void ebus_intmap_match(struct linux_ebus *ebus, prom_halt(); } -__initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, - struct linux_ebus_child *dev)) +void __init fill_ebus_child(int node, struct linux_prom_registers *preg, + struct linux_ebus_child *dev, int non_standard_regs) { 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); + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk(" (%s)", dev->prom_name); 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__); + if (non_standard_regs) { + /* This is to handle reg properties which are not + * in the parent relative format. One example are + * children of the i2c device on CompactPCI systems. + * + * So, for such devices we just record the property + * raw in the child resources. + */ + for (i = 0; i < dev->num_addrs; i++) + dev->resource[i].start = regs[i]; + } else { + for (i = 0; i < dev->num_addrs; i++) { + int rnum = regs[i]; + if (rnum >= 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->resource[i].start = dev->parent->resource[i].start; + dev->resource[i].end = dev->parent->resource[i].end; + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; } - dev->base_address[i] = dev->parent->base_address[regs[i]]; } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -128,52 +136,53 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + ebus_intmap_match(dev->bus, preg, &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, - dev->bus->self, irqs[i]); + dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); } } +} -#ifdef DEBUG_FILL_EBUS_DEV - dprintf("child '%s': address%s\n", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintf(" %016lx\n", dev->base_address[i]); - if (dev->num_irqs) { - dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintf(" %s", __irq_itoa(dev->irqs[i])); - dprintf("\n"); - } -#endif +static int __init child_regs_nonstandard(struct linux_ebus_device *dev) +{ + if (!strcmp(dev->prom_name, "i2c")) + return 1; + return 0; } -__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) +void __init fill_ebus_device(int node, struct linux_ebus_device *dev) { 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); + prom_getstring(node, "name", dev->prom_name, sizeof(dev->prom_name)); + printk(" [%s", dev->prom_name); 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__); + prom_halt(); } 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->bus->self->base_address[n]; - dev->base_address[i] += (unsigned long)regs[i].phys_addr; + dev->resource[i].start = dev->bus->self->resource[n].start; + dev->resource[i].start += (unsigned long)regs[i].phys_addr; + dev->resource[i].end = + (dev->resource[i].start + (unsigned long)regs[i].reg_size - 1UL); + dev->resource[i].flags = IORESOURCE_MEM; + dev->resource[i].name = dev->prom_name; + request_resource(&dev->bus->self->resource[n], + &dev->resource[i]); } len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); @@ -182,62 +191,51 @@ __initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { + struct pci_pbm_info *pbm = dev->bus->parent; + struct pci_controller_info *p = pbm->parent; + ebus_intmap_match(dev->bus, ®s[0], &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, - dev->bus->self, irqs[i]); + dev->irqs[i] = p->irq_build(p, dev->bus->self, irqs[i]); } } -#ifdef DEBUG_FILL_EBUS_DEV - dprintf("'%s': address%s\n", dev->prom_name, - dev->num_addrs > 1 ? "es" : ""); - for (i = 0; i < dev->num_addrs; i++) - dprintf(" %016lx\n", dev->base_address[i]); - if (dev->num_irqs) { - dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); - for (i = 0; i < dev->num_irqs; i++) - dprintf(" %s", __irq_itoa(dev->irqs[i])); - dprintf("\n"); - } -#endif if ((node = prom_getchild(node))) { - dev->children = (struct linux_ebus_child *) - ebus_alloc(sizeof(struct linux_ebus_child)); + printk(" ->"); + dev->children = ebus_alloc(sizeof(struct linux_ebus_child)); child = dev->children; child->next = 0; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], child); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); while ((node = prom_getsibling(node))) { - child->next = (struct linux_ebus_child *) - ebus_alloc(sizeof(struct linux_ebus_child)); + child->next = ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; child->next = 0; child->parent = dev; child->bus = dev->bus; - fill_ebus_child(node, ®s[0], child); + fill_ebus_child(node, ®s[0], + child, child_regs_nonstandard(dev)); } } + printk("]"); } extern void clock_probe(void); +extern void power_init(void); -__initfunc(void ebus_init(void)) +void __init ebus_init(void) { - struct linux_prom_pci_registers regs[PROMREG_MAX]; - struct linux_pbm_info *pbm; + struct pci_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 nd, ebusnd; int num_ebus = 0; if (!pci_present()) @@ -246,17 +244,13 @@ __initfunc(void ebus_init(void)) pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); if (!pdev) { printk("ebus: No EBus's found.\n"); -#ifdef PROM_DEBUG - dprintf("ebus: No EBus's found.\n"); -#endif return; } cookie = pdev->sysdata; ebusnd = cookie->prom_node; - ebus_chain = ebus = (struct linux_ebus *) - ebus_alloc(sizeof(struct linux_ebus)); + ebus_chain = ebus = ebus_alloc(sizeof(struct linux_ebus)); ebus->next = 0; while (ebusnd) { @@ -273,9 +267,6 @@ __initfunc(void ebus_init(void)) if (ebus == ebus_chain) { ebus_chain = NULL; printk("ebus: No EBus's found.\n"); -#ifdef PROM_DEBUG - dprintf("ebus: No EBus's found.\n"); -#endif return; } break; @@ -286,14 +277,10 @@ __initfunc(void ebus_init(void)) continue; } printk("ebus%d:", num_ebus); -#ifdef PROM_DEBUG - dprintf("ebus%d:", num_ebus); -#endif - prom_getstring(ebusnd, "name", lbuf, sizeof(lbuf)); + prom_getstring(ebusnd, "name", ebus->prom_name, sizeof(ebus->prom_name)); + ebus->index = num_ebus; ebus->prom_node = ebusnd; - strcpy(ebus->prom_name, lbuf); - ebus->self = pdev; ebus->parent = pbm = cookie->pbm; @@ -306,49 +293,7 @@ __initfunc(void ebus_init(void)) pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); /* NOTE: Cache line size is in 32-bit word units. */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10); - - 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); - - printk(" %lx[%x]", (unsigned long)__va(addr), - regs[reg].size_lo); -#ifdef PROM_DEBUG - dprintf(" %lx[%x]", (unsigned long)__va(addr), - regs[reg].size_lo); -#endif - break; - } - } - printk("\n"); -#ifdef PROM_DEBUG - dprintf("\n"); -#endif + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 64/sizeof(u32)); prom_ebus_ranges_init(ebus); prom_ebus_intmap_init(ebus); @@ -357,8 +302,7 @@ __initfunc(void ebus_init(void)) if (!nd) goto next_ebus; - ebus->devices = (struct linux_ebus_device *) - ebus_alloc(sizeof(struct linux_ebus_device)); + ebus->devices = ebus_alloc(sizeof(struct linux_ebus_device)); dev = ebus->devices; dev->next = 0; @@ -367,8 +311,7 @@ __initfunc(void ebus_init(void)) fill_ebus_device(nd, dev); while ((nd = prom_getsibling(nd))) { - dev->next = (struct linux_ebus_device *) - ebus_alloc(sizeof(struct linux_ebus_device)); + dev->next = ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; dev->next = 0; @@ -378,6 +321,8 @@ __initfunc(void ebus_init(void)) } next_ebus: + printk("\n"); + pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, pdev); if (!pdev) @@ -386,8 +331,7 @@ __initfunc(void ebus_init(void)) cookie = pdev->sysdata; ebusnd = cookie->prom_node; - ebus->next = (struct linux_ebus *) - ebus_alloc(sizeof(struct linux_ebus)); + ebus->next = ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; ebus->next = 0; ++num_ebus; @@ -409,4 +353,5 @@ __initfunc(void ebus_init(void)) flash_init(); #endif clock_probe(); + power_init(); } diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 4134dcc3a..fbd64a507 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.103 1999/05/08 03:00:21 davem Exp $ +/* $Id: entry.S,v 1.107 1999/08/31 19:25:29 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -42,13 +42,13 @@ sparc64_vpte_patchme2: /* This is trivial with the new code... */ .globl do_fpdis do_fpdis: - ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g5 ! Load Group sethi %hi(TSTATE_PEF), %g4 ! IEU0 wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles andcc %g5, FPRS_FEF, %g0 ! IEU1 Group be,a,pt %icc, 1f ! CTI clr %g7 ! IEU0 - ldub [%g6 + AOFF_task_tss + AOFF_thread_gsr], %g7 ! Load Group + ldub [%g6 + AOFF_task_thread + AOFF_thread_gsr], %g7 ! Load Group 1: andcc %g5, FPRS_DL, %g0 ! IEU1 bne,pn %icc, 2f ! CTI fzero %f0 ! FPA @@ -157,7 +157,7 @@ fpdis_exit: flush %g6 fpdis_exit2: wr %g7, 0, %gsr - ldx [%g6 + AOFF_task_tss + AOFF_thread_xfsr], %fsr + ldx [%g6 + AOFF_task_thread + AOFF_thread_xfsr], %fsr rdpr %tstate, %g3 or %g3, %g4, %g3 ! anal... wrpr %g3, %tstate @@ -167,13 +167,13 @@ fpdis_exit2: .globl do_fptrap .align 32 do_fptrap: - ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 - stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr] + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3 + stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] rd %fprs, %g1 or %g3, %g1, %g3 - stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] + stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g3 - stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr] + stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] mov SECONDARY_CONTEXT, %g3 add %g6, AOFF_task_fpregs, %g2 ldxa [%g3] ASI_DMMU, %g5 @@ -478,6 +478,97 @@ __do_instruction_access_exception: ba,pt %xcc, rtrap clr %l6 + /* This is the trap handler entry point for ECC correctable + * errors. They are corrected, but we listen for the trap + * so that the event can be logged. + * + * Disrupting errors are either: + * 1) single-bit ECC errors during UDB reads to system + * memory + * 2) data parity errors during write-back events + * + * As far as I can make out from the manual, the CEE trap + * is only for correctable errors during memory read + * accesses by the front-end of the processor. + * + * The code below is only for trap level 1 CEE events, + * as it is the only situation where we can safely record + * and log. For trap level >1 we just clear the CE bit + * in the AFSR and return. + */ + + /* Our trap handling infrastructure allows us to preserve + * two 64-bit values during etrap for arguments to + * subsequent C code. Therefore we encode the information + * as follows: + * + * value 1) Full 64-bits of AFAR + * value 2) Low 33-bits of AFSR, then bits 33-->42 + * are UDBL error status and bits 43-->52 + * are UDBH error status + */ + .align 64 + .globl cee_trap +cee_trap: + ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR + ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR + sllx %g1, 31, %g1 ! Clear reserved bits + srlx %g1, 31, %g1 ! in AFSR + + /* NOTE: UltraSparc-I/II have high and low UDB error + * registers, corresponding to the two UDB units + * present on those chips. UltraSparc-IIi only + * has a single UDB, called "SDB" in the manual. + * For IIi the upper UDB register always reads + * as zero so for our purposes things will just + * work with the checks below. + */ + ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status + andcc %g3, (1 << 8), %g4 ! Check CE bit + sllx %g3, (64 - 10), %g3 ! Clear reserved bits + srlx %g3, (64 - 10), %g3 ! in UDB-Low error status + + sllx %g3, (33 + 0), %g3 ! Shift up to encoding area + or %g1, %g3, %g1 ! Or it in + be,pn %xcc, 1f ! Branch if CE bit was clear + nop + stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL + membar #Sync ! Synchronize ASI stores +1: mov 0x18, %g5 ! Addr of UDB-High error status + ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it + + andcc %g3, (1 << 8), %g4 ! Check CE bit + sllx %g3, (64 - 10), %g3 ! Clear reserved bits + srlx %g3, (64 - 10), %g3 ! in UDB-High error status + sllx %g3, (33 + 10), %g3 ! Shift up to encoding area + or %g1, %g3, %g1 ! Or it in + be,pn %xcc, 1f ! Branch if CE bit was clear + nop + nop + + stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH + membar #Sync ! Synchronize ASI stores +1: mov 1, %g5 ! AFSR CE bit is + sllx %g5, 20, %g5 ! bit 20 + stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR + membar #Sync ! Synchronize ASI stores + sllx %g2, (64 - 41), %g2 ! Clear reserved bits + srlx %g2, (64 - 41), %g2 ! in latched AFAR + + andn %g2, 0x0f, %g2 ! Finish resv bit clearing + mov %g1, %g4 ! Move AFSR+UDB* into save reg + mov %g2, %g5 ! Move AFAR into save reg + rdpr %pil, %g2 + wrpr %g0, 15, %pil + ba,pt %xcc, etrap_irq + rd %pc, %g7 + mov %l4, %o0 + + mov %l5, %o1 + call cee_log + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + ba,a,pt %xcc, rtrap_clr_l6 + .globl __do_privact __do_privact: mov TLB_SFSR, %g3 @@ -633,41 +724,28 @@ execve_merge: jmpl %g1, %g0 add %sp, STACK_BIAS + REGWIN_SZ, %o0 - .globl sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall + .globl sys_pipe, sys_sigpause, sys_nis_syscall .globl sys_sigsuspend, sys_rt_sigsuspend, sys32_rt_sigsuspend - .globl sys_sigreturn, sys_rt_sigreturn + .globl sys_rt_sigreturn .globl sys32_sigreturn, sys32_rt_sigreturn .globl sys32_execve, sys_ptrace .globl sys_sigaltstack, sys32_sigaltstack .globl sys32_sigstack .align 32 -sys_pipe: sethi %hi(sparc_pipe), %g1 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - jmpl %g1 + %lo(sparc_pipe), %g0 - nop -sys_nis_syscall:sethi %hi(c_sys_nis_syscall), %g1 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - jmpl %g1 + %lo(c_sys_nis_syscall), %g0 - nop - +sys_pipe: ba,pt %xcc, sparc_pipe + add %sp, STACK_BIAS + REGWIN_SZ, %o0 +sys_nis_syscall:ba,pt %xcc, c_sys_nis_syscall + add %sp, STACK_BIAS + REGWIN_SZ, %o0 sys_memory_ordering: - sethi %hi(sparc_memory_ordering), %g1 - add %sp, STACK_BIAS + REGWIN_SZ, %o1 - jmpl %g1 + %lo(sparc_memory_ordering), %g0 - nop -sys_sigaltstack:sethi %hi(do_sigaltstack), %g1 - add %i6, STACK_BIAS, %o2 - jmpl %g1 + %lo(do_sigaltstack), %g1 - nop -sys32_sigstack: sethi %hi(do_sys32_sigstack), %g1 - mov %i6, %o2 - jmpl %g1 + %lo(do_sys32_sigstack), %g1 - nop + ba,pt %xcc, sparc_memory_ordering + add %sp, STACK_BIAS + REGWIN_SZ, %o1 +sys_sigaltstack:ba,pt %xcc, do_sigaltstack + add %i6, STACK_BIAS, %o2 +sys32_sigstack: ba,pt %xcc, do_sys32_sigstack + mov %i6, %o2 sys32_sigaltstack: - sethi %hi(do_sys32_sigaltstack), %g1 - mov %i6, %o2 - jmpl %g1 + %lo(do_sys32_sigaltstack), %g1 - nop + ba,pt %xcc, do_sys32_sigaltstack + mov %i6, %o2 .align 32 sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0 @@ -689,10 +767,6 @@ sys_sigpause: add %sp, STACK_BIAS + REGWIN_SZ, %o1 call do_sigpause add %o7, 1f-.-4, %o7 nop -sys_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0 - call do_sigreturn - add %o7, 1f-.-4, %o7 - nop sys32_sigreturn: add %sp, STACK_BIAS + REGWIN_SZ, %o0 call do_sigreturn32 @@ -761,38 +835,30 @@ sys_clone: flushw ba,pt %xcc, do_fork add %sp, STACK_BIAS + REGWIN_SZ, %o2 ret_from_syscall: - /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in + /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves thread.flags in * %o7 for us. Check performance counter stuff too. */ -#ifdef __SMP__ - andn %o7, 0x100, %l0 + andn %o7, SPARC_FLAG_NEWCHILD, %l0 mov %g5, %o0 /* 'prev' */ call schedule_tail - sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags] -#else - andn %o7, 0x100, %l0 - sth %l0, [%g6 + AOFF_task_tss + AOFF_thread_flags] -#endif - andcc %l0, 0x200, %g0 + stb %l0, [%g6 + AOFF_task_thread + AOFF_thread_flags] + andcc %l0, SPARC_FLAG_PERFCTR, %g0 be,pt %icc, 1f nop - ldx [%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7 + ldx [%g6 + AOFF_task_thread + AOFF_thread_pcr_reg], %o7 wr %g0, %o7, %pcr wr %g0, %g0, %pic 1: b,pt %xcc, ret_sys_call ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 sparc_exit: rdpr %otherwin, %g1 - rdpr %pstate, %g2 - wrpr %g2, PSTATE_IE, %pstate + wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV), %pstate rdpr %cansave, %g3 add %g3, %g1, %g3 wrpr %g3, 0x0, %cansave wrpr %g0, 0x0, %otherwin - wrpr %g2, 0x0, %pstate - mov %o7, %l5 - sth %g0, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] - call sys_exit - mov %l5, %o7 + wrpr %g0, (PSTATE_RMO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE), %pstate + ba,pt %xcc, sys_exit + stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] linux_sparc_ni_syscall: sethi %hi(sys_ni_syscall), %l7 diff --git a/arch/sparc64/kernel/etrap.S b/arch/sparc64/kernel/etrap.S index 6a94cf3ab..d243a43b3 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.41 1999/05/25 16:53:09 jj Exp $ +/* $Id: etrap.S,v 1.42 1999/07/30 09:35: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) @@ -56,7 +56,7 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group wrpr %g0, 0, %canrestore ! Single Group+4bubbles sll %g2, 3, %g2 ! IEU0 Group mov 1, %l5 ! IEU1 - stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store + stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store wrpr %g3, 0, %otherwin ! Single Group+4bubbles wrpr %g2, 0, %wstate ! Single Group+4bubbles stxa %g0, [%l4] ASI_DMMU ! Store Group @@ -89,11 +89,11 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group jmpl %l2 + 0x4, %g0 ! CTI Group mov %l6, %g6 ! IEU0 -3: ldub [%l6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5 ! Load Group - add %l6, AOFF_task_tss + AOFF_thread_fpsaved + 1, %l4 ! IEU0 +3: ldub [%l6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5 ! Load Group + add %l6, AOFF_task_thread + AOFF_thread_fpsaved + 1, %l4 ! IEU0 srl %l5, 1, %l3 ! IEU0 Group add %l5, 2, %l5 ! IEU1 - stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store + stb %l5, [%l6 + AOFF_task_thread + AOFF_thread_fpdepth] ! Store ba,pt %xcc, 2b ! CTI stb %g0, [%l4 + %l3] ! Store Group diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c index 08a4a6b6a..3b6789e09 100644 --- a/arch/sparc64/kernel/idprom.c +++ b/arch/sparc64/kernel/idprom.c @@ -1,4 +1,4 @@ -/* $Id: idprom.c,v 1.2 1997/04/17 02:28:10 miguel Exp $ +/* $Id: idprom.c,v 1.3 1999/08/31 06:54:53 davem Exp $ * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * @@ -16,7 +16,7 @@ struct idprom *idprom; static struct idprom idprom_buffer; /* Calculate the IDPROM checksum (xor of the data bytes). */ -__initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) +static unsigned char __init calc_idprom_cksum(struct idprom *idprom) { unsigned char cksum, i, *ptr = (unsigned char *)idprom; @@ -27,7 +27,7 @@ __initfunc(static unsigned char calc_idprom_cksum(struct idprom *idprom)) } /* Create a local IDPROM copy and verify integrity. */ -__initfunc(void idprom_init(void)) +void __init idprom_init(void) { prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer)); diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c index 66869404d..d256b5761 100644 --- a/arch/sparc64/kernel/init_task.c +++ b/arch/sparc64/kernel/init_task.c @@ -6,7 +6,6 @@ static struct vm_area_struct init_mmap = INIT_MMAP; static struct fs_struct init_fs = INIT_FS; -static struct file * init_fd_array[NR_OPEN] = { NULL, }; static struct files_struct init_files = INIT_FILES; static struct signal_struct init_signals = INIT_SIGNALS; struct mm_struct init_mm = INIT_MM(init_mm); diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 833331202..0affcf0eb 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.63 1999/06/09 04:56:14 davem Exp $ +/* $Id: ioctl32.c,v 1.68 1999/09/10 05:59:25 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -38,6 +38,7 @@ #include <linux/ext2_fs.h> #include <linux/videodev.h> #include <linux/netdevice.h> +#include <linux/raw.h> #include <scsi/scsi.h> /* Ugly hack. */ @@ -409,6 +410,7 @@ struct ifreq32 { int ifru_mtu; struct ifmap32 ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; __kernel_caddr_t32 ifru_data; } ifr_ifru; }; @@ -420,7 +422,7 @@ struct ifconf32 { static int dev_ifname32(unsigned int fd, unsigned long arg) { - struct device *dev; + struct net_device *dev; struct ifreq32 ifr32; int err; @@ -431,6 +433,8 @@ static int dev_ifname32(unsigned int fd, unsigned long arg) if (!dev) return -ENODEV; + strcpy(ifr32.ifr_name, dev->name); + err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); return (err ? -EFAULT : 0); } @@ -570,7 +574,7 @@ static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long ar if(cmd == SIOCETHTOOL) len = sizeof(struct ethtool_cmd); if(cmd == SIOCGPPPVER) - len = strlen(PPP_VERSION) + 1; + len = strlen((char *)ifr.ifr_data) + 1; else if(cmd == SIOCGPPPCSTATS) len = sizeof(struct ppp_comp_stats); else @@ -2366,6 +2370,10 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) case AUTOFS_IOC_PROTOVER: case AUTOFS_IOC_EXPIRE: + /* Raw devices */ + case RAW_SETBIND: + case RAW_GETBIND: + error = sys_ioctl (fd, cmd, arg); goto out; diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 6eccb883a..598cece4e 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.76 1999/04/02 14:54:30 davem Exp $ +/* $Id: irq.c,v 1.78 1999/08/31 06:54:54 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -31,11 +31,6 @@ #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_IMAP_MASKED 0x100 #define SA_DMA_SYNC 0x200 @@ -79,15 +74,6 @@ struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; -/* Only 8-bits are available, be careful. -DaveM */ -#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */ -#define IBF_PCI 0x02 /* Indicates PSYCHO/SCHIZO PCI interrupt. */ -#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */ -#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */ - -#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) -#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) - int get_irq_list(char *buf) { int i, len = 0; @@ -183,67 +169,22 @@ offset(imap_pmgmt), /* Convert Interrupt Mapping register pointer to assosciated * Interrupt Clear register pointer, SYSIO specific version. */ -static unsigned int *sysio_imap_to_iclr(unsigned int *imap) +static volatile unsigned int *sysio_imap_to_iclr(volatile unsigned int *imap) { unsigned long diff; diff = offset(iclr_unused0) - offset(imap_slot0); - return (unsigned int *) (((unsigned long)imap) + diff); + return (volatile unsigned int *) (((unsigned long)imap) + diff); } #undef offset -#ifdef CONFIG_PCI -/* PCI PSYCHO INO number to Sparc PIL level. */ -unsigned char psycho_ino_to_pil[] = { - 7, 5, 4, 2, /* PCI A slot 0 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 1 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 2 Int A, B, C, D */ - 7, 5, 4, 2, /* PCI A slot 3 Int A, B, C, D */ - 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 */ - 3, /* second SCSI */ - 11, /* Floppy */ - 2, /* Spare Hardware */ - 9, /* 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. */ -#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 irq) { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(irq); - unsigned int *imap; + volatile unsigned int *imap; unsigned long tid; imap = bucket->imap; @@ -257,7 +198,7 @@ void enable_irq(unsigned int irq) : "i" (ASI_UPA_CONFIG)); tid = ((tid & UPA_CONFIG_MID) << 9); } else { - extern unsigned int starfire_translate(unsigned int *imap, + extern unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid); tid = (starfire_translate(imap, current->processor) << 26); @@ -278,7 +219,7 @@ void enable_irq(unsigned int irq) void disable_irq(unsigned int irq) { struct ino_bucket *bucket = __bucket(irq); - unsigned int *imap; + volatile unsigned int *imap; imap = bucket->imap; if (imap != NULL) { @@ -306,7 +247,7 @@ static struct ino_bucket pil0_dummy_bucket = { NULL, /* imap */ }; -unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap) +unsigned int build_irq(int pil, int inofixup, volatile unsigned int *iclr, volatile unsigned int *imap) { struct ino_bucket *bucket; int ino; @@ -365,7 +306,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) struct sysio_regs *sregs = sbus->iommu->sysio_regs; unsigned long offset; int pil; - unsigned int *imap, *iclr; + volatile unsigned int *imap, *iclr; int sbus_level = 0; pil = sysio_ino_to_pil[ino]; @@ -380,7 +321,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) panic("BAD SYSIO IRQ offset..."); } offset += ((unsigned long)sregs); - imap = ((unsigned int *)offset); + imap = ((volatile unsigned int *)offset); /* SYSIO inconsistancy. For external SLOTS, we have to select * the right ICLR register based upon the lower SBUS irq level @@ -412,81 +353,11 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) iclraddr = (unsigned long) iclr; iclraddr += ((sbus_level - 1) * 8); - iclr = (unsigned int *) iclraddr; + iclr = (volatile unsigned int *) iclraddr; } return build_irq(pil, sbus_level, iclr, imap); } -#ifdef CONFIG_PCI -unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync) -{ - struct linux_psycho *psycho = (struct linux_psycho *)buscookie; - struct psycho_regs *pregs = psycho->psycho_regs; - unsigned long addr; - struct ino_bucket *bucket; - int pil; - unsigned int *imap, *iclr; - int inofixup = 0; - - pil = psycho_ino_to_pil[ino & PCI_IRQ_INO]; - - addr = (unsigned long) &pregs->imap_a_slot0; - addr = addr + imap_off; - imap = ((unsigned int *)addr) + 1; - - addr = (unsigned long) pregs; - addr += psycho_iclr_offset(ino & (PCI_IRQ_INO)); - iclr = ((unsigned int *)addr) + 1; - - if(!(ino & 0x20)) - inofixup = ino & 0x03; - - /* First check for sharing. */ - ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; - if (ino > NUM_IVECS) { - prom_printf("PSYCHO: Invalid INO %04x (%d:%d:%016lx:%016lx)\n", - ino, pil, inofixup, iclr, imap); - prom_halt(); - } - bucket = &ivector_table[ino]; - if(bucket->flags & IBF_ACTIVE) { - void *old_handler = bucket->irq_info; - unsigned long flags; - - if(old_handler == NULL) { - prom_printf("PSYCHO: Active bucket, but no handler.\n"); - prom_halt(); - } - save_and_cli(flags); - if((bucket->flags & IBF_MULTI) == 0) { - void **vector; - - vector = kmalloc(sizeof(void *) * 4, - GFP_KERNEL); - - /* We might have slept. */ - if((bucket->flags & IBF_MULTI) != 0) { - kfree(vector); - } else { - vector[0] = old_handler; - vector[1] = vector[2] = vector[3] = NULL; - bucket->irq_info = vector; - bucket->flags |= IBF_MULTI; - } - } - restore_flags(flags); - } else { - /* Just init the bucket */ - bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); - } - if (need_dma_sync) - bucket->flags |= IBF_DMA_SYNC; - - bucket->flags |= IBF_PCI; - return __irq(bucket); -} -#endif - static void atomic_bucket_insert(struct ino_bucket *bucket) { unsigned long pstate; @@ -731,7 +602,7 @@ void free_irq(unsigned int irq, void *dev_id) *(bucket->pil + irq_action) = action->next; if(action->flags & SA_IMAP_MASKED) { - unsigned int *imap = bucket->imap; + volatile unsigned int *imap = bucket->imap; void **vector, *orig; int ent; @@ -1286,7 +1157,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu) { extern int this_is_starfire; struct ino_bucket *bucket = __bucket(p->mask); - unsigned int *imap = bucket->imap; + volatile unsigned int *imap = bucket->imap; unsigned int tid; /* Never change this, it causes problems on Ex000 systems. */ @@ -1296,7 +1167,7 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu) if(this_is_starfire == 0) { tid = __cpu_logical_map[goal_cpu] << 26; } else { - extern unsigned int starfire_translate(unsigned int *imap, + extern unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid); tid = (starfire_translate(imap, __cpu_logical_map[goal_cpu]) << 26); @@ -1399,7 +1270,7 @@ void enable_prom_timer(void) prom_timers->count0 = 0; } -__initfunc(void init_IRQ(void)) +void __init init_IRQ(void) { static int called = 0; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c new file mode 100644 index 000000000..1776e6d7e --- /dev/null +++ b/arch/sparc64/kernel/pci.c @@ -0,0 +1,339 @@ +/* $Id: pci.c,v 1.6 1999/09/08 03:40:41 davem Exp $ + * pci.c: UltraSparc PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/capability.h> +#include <linux/errno.h> +#include <linux/smp_lock.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pbm.h> +#include <asm/irq.h> +#include <asm/ebus.h> + +unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_memspace_mask = 0xffffffffUL; + +#ifndef CONFIG_PCI +/* A "nop" PCI implementation. */ +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 + +/* List of all PCI controllers found in the system. */ +spinlock_t pci_controller_lock = SPIN_LOCK_UNLOCKED; +struct pci_controller_info *pci_controller_root = NULL; + +/* Each PCI controller found gets a unique index. */ +int pci_num_controllers = 0; + +/* Given an 8-bit PCI bus number, this yields the + * controlling PBM module info. + * + * Some explanation is in order here. The Linux APIs for + * the PCI subsystem require that the configuration space + * types are enough to signify PCI configuration space + * accesses correctly. This gives us 8-bits for the bus + * number, however we have multiple PCI controllers on + * UltraSparc systems. + * + * So what we do is give the PCI busses under each controller + * a unique portion of the 8-bit PCI bus number space. + * Therefore one can obtain the controller from the bus + * number. For example, say PSYCHO PBM-A a subordinate bus + * space of 0 to 4, and PBM-B has a space of 0 to 2. PBM-A + * will use 0 to 4, and PBM-B will use 5 to 7. + */ +struct pci_pbm_info *pci_bus2pbm[256]; +unsigned char pci_highest_busnum = 0; + +/* At boot time the user can give the kernel a command + * line option which controls if and how PCI devices + * are reordered at PCI bus probing time. + */ +int pci_device_reorder = 0; + +spinlock_t pci_poke_lock = SPIN_LOCK_UNLOCKED; +volatile int pci_poke_in_progress; +volatile int pci_poke_faulted; + +/* Probe for all PCI controllers in the system. */ +extern void sabre_init(int); +extern void psycho_init(int); + +static struct { + char *model_name; + void (*init)(int); +} pci_controller_table[] = { + { "SUNW,sabre", sabre_init }, + { "pci108e,a000", sabre_init }, + { "SUNW,psycho", psycho_init }, + { "pci108e,8000", psycho_init } +}; +#define PCI_NUM_CONTROLLER_TYPES (sizeof(pci_controller_table) / \ + sizeof(pci_controller_table[0])) + +static void pci_controller_init(char *model_name, int namelen, int node) +{ + int i; + + for (i = 0; i < PCI_NUM_CONTROLLER_TYPES; i++) { + if (!strncmp(model_name, + pci_controller_table[i].model_name, + namelen)) { + pci_controller_table[i].init(node); + return; + } + } + printk("PCI: Warning unknown controller, model name [%s]\n", + model_name); + printk("PCI: Ignoring controller...\n"); +} + +/* Find each controller in the system, attach and initialize + * software state structure for each and link into the + * pci_controller_root. Setup the controller enough such + * that bus scanning can be done. + */ +static void pci_controller_probe(void) +{ + char namebuf[16]; + int node; + + printk("PCI: Probing for controllers.\n"); + node = prom_getchild(prom_root_node); + while ((node = prom_searchsiblings(node, "pci")) != 0) { + int len; + + len = prom_getproperty(node, "model", + namebuf, sizeof(namebuf)); + if (len > 0) + pci_controller_init(namebuf, len, node); + else { + len = prom_getproperty(node, "compatible", + namebuf, sizeof(namebuf)); + if (len > 0) + pci_controller_init(namebuf, len, node); + } + node = prom_getsibling(node); + if (!node) + break; + } +} + +static void pci_scan_each_controller_bus(void) +{ + struct pci_controller_info *p; + unsigned long flags; + + spin_lock_irqsave(&pci_controller_lock, flags); + for (p = pci_controller_root; p; p = p->next) + p->scan_bus(p); + spin_unlock_irqrestore(&pci_controller_lock, flags); +} + +/* Reorder the pci_dev chain, so that onboard devices come first + * and then come the pluggable cards. + */ +static void __init pci_reorder_devs(void) +{ + struct pci_dev **pci_onboard = &pci_devices; + struct pci_dev **pci_tail = &pci_devices; + struct pci_dev *pdev = pci_devices, *pci_other = NULL; + + while (pdev) { + if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { + if (pci_other) { + *pci_onboard = pdev; + pci_onboard = &pdev->next; + pdev = pdev->next; + *pci_onboard = pci_other; + *pci_tail = pdev; + continue; + } else + pci_onboard = &pdev->next; + } else if (!pci_other) + pci_other = pdev; + pci_tail = &pdev->next; + pdev = pdev->next; + } +} + +void __init pcibios_init(void) +{ + pci_controller_probe(); + if (pci_controller_root == NULL) + return; + + pci_scan_each_controller_bus(); + + if (pci_device_reorder) + pci_reorder_devs(); + + ebus_init(); +} + +struct pci_fixup pcibios_fixups[] = { + { 0 } +}; + +void pcibios_fixup_bus(struct pci_bus *pbus) +{ +} + +int pcibios_assign_resource(struct pci_dev *pdev, int resource) +{ + return 0; +} + +char * __init pcibios_setup(char *str) +{ + if (!strcmp(str, "onboardfirst")) { + pci_device_reorder = 1; + return NULL; + } + if (!strcmp(str, "noreorder")) { + pci_device_reorder = 0; + return NULL; + } + return str; +} + +asmlinkage int sys_pciconfig_read(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + + dev = pci_find_slot(bus, dfn); + if (!dev) { + /* Xfree86 is such a turd, it does not check the + * return value and just relies on the buffer being + * set to all 1's to mean "device not present". + */ + switch(len) { + case 1: + put_user(0xff, (unsigned char *)buf); + break; + case 2: + put_user(0xffff, (unsigned short *)buf); + break; + case 4: + put_user(0xffffffff, (unsigned int *)buf); + break; + default: + err = -EINVAL; + break; + }; + goto out; + } + + lock_kernel(); + switch(len) { + case 1: + pci_read_config_byte(dev, off, &byte); + put_user(byte, (unsigned char *)buf); + break; + case 2: + pci_read_config_word(dev, off, &word); + put_user(word, (unsigned short *)buf); + break; + case 4: + pci_read_config_dword(dev, off, &dword); + put_user(dword, (unsigned int *)buf); + break; + + default: + err = -EINVAL; + break; + }; + unlock_kernel(); +out: + return err; +} + +asmlinkage int sys_pciconfig_write(unsigned long bus, + unsigned long dfn, + unsigned long off, + unsigned long len, + unsigned char *buf) +{ + struct pci_dev *dev; + u8 byte; + u16 word; + u32 dword; + int err = 0; + + if(!capable(CAP_SYS_ADMIN)) + return -EPERM; + dev = pci_find_slot(bus, dfn); + if (!dev) { + /* See commentary above about Xfree86 */ + goto out; + } + + lock_kernel(); + switch(len) { + case 1: + err = get_user(byte, (u8 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, byte); + break; + + case 2: + err = get_user(word, (u16 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, word); + break; + + case 4: + err = get_user(dword, (u32 *)buf); + if(err) + break; + pci_write_config_byte(dev, off, dword); + break; + + default: + err = -EINVAL; + break; + + }; + unlock_kernel(); + +out: + return err; +} + +#endif /* !(CONFIG_PCI) */ diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c new file mode 100644 index 000000000..a3600df9c --- /dev/null +++ b/arch/sparc64/kernel/pci_common.c @@ -0,0 +1,651 @@ +/* $Id: pci_common.c,v 1.3 1999/09/04 22:26:32 ecd Exp $ + * pci_common.c: PCI controller common support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include <linux/string.h> +#include <linux/malloc.h> +#include <linux/init.h> + +#include <asm/pbm.h> + +/* Find the OBP PROM device tree node for a PCI device. + * Return zero if not found. + */ +static int __init find_device_prom_node(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + int bus_prom_node, + struct linux_prom_pci_registers *pregs, + int *nregs) +{ + int node; + + /* + * Return the PBM's PROM node in case we are it's PCI device, + * as the PBM's reg property is different to standard PCI reg + * properties. We would delete this device entry otherwise, + * which confuses XFree86's device probing... + */ + if ((pdev->bus->number == pbm->pci_bus->number) && (pdev->devfn == 0) && + (pdev->vendor == PCI_VENDOR_ID_SUN) && + (pdev->device == PCI_DEVICE_ID_SUN_PBM)) { + *nregs = 0; + return bus_prom_node; + } + + node = prom_getchild(bus_prom_node); + while (node != 0) { + int err = prom_getproperty(node, "reg", + (char *)pregs, + sizeof(*pregs) * PROMREG_MAX); + if (err == 0 || err == -1) + goto do_next_sibling; + if (((pregs[0].phys_hi >> 8) & 0xff) == pdev->devfn) { + *nregs = err / sizeof(*pregs); + return node; + } + + do_next_sibling: + node = prom_getsibling(node); + } + return 0; +} + +/* Remove a PCI device from the device trees, then + * free it up. Note that this must run before + * the device's resources are registered because we + * do not handle unregistering them here. + */ +static void pci_device_delete(struct pci_dev *pdev) +{ + struct pci_dev **dpp; + + /* First, unlink from list of all devices. */ + dpp = &pci_devices; + while (*dpp != NULL) { + if (*dpp == pdev) { + *dpp = pdev->next; + pdev->next = NULL; + break; + } + dpp = &(*dpp)->next; + } + + /* Next, unlink from bus sibling chain. */ + dpp = &pdev->bus->devices; + while (*dpp != NULL) { + if (*dpp == pdev) { + *dpp = pdev->sibling; + pdev->sibling = NULL; + break; + } + dpp = &(*dpp)->sibling; + } + + /* Ok, all references are gone, free it up. */ + kfree(pdev); +} + +/* Fill in the PCI device cookie sysdata for the given + * PCI device. This cookie is the means by which one + * can get to OBP and PCI controller specific information + * for a PCI device. + */ +static void __init pdev_cookie_fillin(struct pci_pbm_info *pbm, + struct pci_dev *pdev, + int bus_prom_node) +{ + struct linux_prom_pci_registers pregs[PROMREG_MAX]; + struct pcidev_cookie *pcp; + int device_prom_node, nregs, err; + + device_prom_node = find_device_prom_node(pbm, pdev, bus_prom_node, + pregs, &nregs); + if (device_prom_node == 0) { + /* If it is not in the OBP device tree then + * there must be a damn good reason for it. + * + * So what we do is delete the device from the + * PCI device tree completely. This scenerio + * is seen, for example, on CP1500 for the + * second EBUS/HappyMeal pair if the external + * connector for it is not present. + */ + pci_device_delete(pdev); + return; + } + + pcp = kmalloc(sizeof(*pcp), GFP_ATOMIC); + if (pcp == NULL) { + prom_printf("PCI_COOKIE: Fatal malloc error, aborting...\n"); + prom_halt(); + } + pcp->pbm = pbm; + pcp->prom_node = device_prom_node; + memcpy(pcp->prom_regs, pregs, sizeof(pcp->prom_regs)); + pcp->num_prom_regs = nregs; + err = prom_getproperty(device_prom_node, "name", + pcp->prom_name, sizeof(pcp->prom_name)); + if (err > 0) + pcp->prom_name[err] = 0; + else + pcp->prom_name[0] = 0; + if (strcmp(pcp->prom_name, "ebus") == 0) { + struct linux_prom_ebus_ranges erng[PROM_PCIRNG_MAX]; + int iter; + + /* EBUS is special... */ + err = prom_getproperty(device_prom_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(erng[0])); + for(iter = 0; iter < err; iter++) { + struct linux_prom_ebus_ranges *ep = &erng[iter]; + struct linux_prom_pci_registers *ap; + + ap = &pcp->prom_assignments[iter]; + + ap->phys_hi = ep->parent_phys_hi; + ap->phys_mid = ep->parent_phys_mid; + ap->phys_lo = ep->parent_phys_lo; + ap->size_hi = 0; + ap->size_lo = ep->size; + } + pcp->num_prom_assignments = err; + } else { + err = prom_getproperty(device_prom_node, + "assigned-addresses", + (char *)pcp->prom_assignments, + sizeof(pcp->prom_assignments)); + if (err == 0 || err == -1) + pcp->num_prom_assignments = 0; + else + pcp->num_prom_assignments = + (err / sizeof(pcp->prom_assignments[0])); + } + + pdev->sysdata = pcp; +} + +void __init pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + int prom_node) +{ + struct pci_dev *pdev; + + /* This loop is coded like this because the cookie + * fillin routine can delete devices from the tree. + */ + pdev = pbus->devices; + while (pdev != NULL) { + struct pci_dev *next = pdev->sibling; + + pdev_cookie_fillin(pbm, pdev, prom_node); + + pdev = next; + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) { + struct pcidev_cookie *pcp = pbus->self->sysdata; + pci_fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); + } +} + +static void __init bad_assignment(struct linux_prom_pci_registers *ap, + struct resource *res, + int do_prom_halt) +{ + prom_printf("PCI: Bogus PROM assignment.\n"); + if (ap) + prom_printf("PCI: phys[%08x:%08x:%08x] size[%08x:%08x]\n", + ap->phys_hi, ap->phys_mid, ap->phys_lo, + ap->size_hi, ap->size_lo); + if (res) + prom_printf("PCI: RES[%016lx-->%016lx:(%lx)]\n", + res->start, res->end, res->flags); + prom_printf("Please email this information to davem@redhat.com\n"); + if (do_prom_halt) + prom_halt(); +} + +static struct resource * +__init get_root_resource(struct linux_prom_pci_registers *ap, + struct pci_pbm_info *pbm) +{ + int space = (ap->phys_hi >> 24) & 3; + + switch (space) { + case 0: + /* Configuration space, silently ignore it. */ + return NULL; + + case 1: + /* 16-bit IO space */ + return &pbm->io_space; + + case 2: + /* 32-bit MEM space */ + return &pbm->mem_space; + + case 3: + default: + /* 64-bit MEM space, unsupported. */ + printk("PCI: 64-bit MEM assignment??? " + "Tell davem@redhat.com about it!\n"); + return NULL; + }; +} + +static struct resource * +__init get_device_resource(struct linux_prom_pci_registers *ap, + struct pci_dev *pdev) +{ + int breg = (ap->phys_hi & 0xff); + int space = (ap->phys_hi >> 24) & 3; + + switch (breg) { + case PCI_ROM_ADDRESS: + /* It had better be MEM space. */ + if (space != 2) + bad_assignment(ap, NULL, 0); + + return &pdev->resource[PCI_ROM_RESOURCE]; + + case PCI_BASE_ADDRESS_0: + case PCI_BASE_ADDRESS_1: + case PCI_BASE_ADDRESS_2: + case PCI_BASE_ADDRESS_3: + case PCI_BASE_ADDRESS_4: + case PCI_BASE_ADDRESS_5: + return &pdev->resource[(breg - PCI_BASE_ADDRESS_0) / 4]; + + default: + bad_assignment(ap, NULL, 0); + return NULL; + }; +} + +static void __init pdev_record_assignments(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + int i; + + for (i = 0; i < pcp->num_prom_assignments; i++) { + struct linux_prom_pci_registers *ap; + struct resource *root, *res; + + /* The format of this property is specified in + * the PCI Bus Binding to IEEE1275-1994. + */ + ap = &pcp->prom_assignments[i]; + root = get_root_resource(ap, pbm); + res = get_device_resource(ap, pdev); + if (root == NULL || res == NULL) + continue; + + /* Ok we know which resource this PROM assignment is + * for, sanity check it. + */ + if ((res->start & 0xffffffffUL) != ap->phys_lo) + bad_assignment(ap, res, 1); + + /* Adjust the resource into the physical address space + * of this PBM. + */ + pbm->parent->resource_adjust(pdev, res, root); + + if (request_resource(root, res) < 0) { + /* OK, there is some conflict. But this is fine + * since we'll reassign it in the fixup pass. + * Nevertheless notify the user that OBP made + * an error. + */ + printk(KERN_ERR "PCI: Address space collision on region %ld " + "of device %s\n", + (res - &pdev->resource[0]), pdev->name); + } + } +} + +void __init pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_record_assignments(pbm, pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_record_assignments(pbm, pbus); +} + +static void __init pdev_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_dev *pdev) +{ + u32 reg; + u16 cmd; + int i, io_seen, mem_seen; + + io_seen = mem_seen = 0; + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *root, *res; + unsigned long size, min, max, align; + + res = &pdev->resource[i]; + + if (res->flags & IORESOURCE_IO) + io_seen++; + else if (res->flags & IORESOURCE_MEM) + mem_seen++; + + /* If it is already assigned or the resource does + * not exist, there is nothing to do. + */ + if (res->parent != NULL || res->flags == 0UL) + continue; + + /* Determine the root we allocate from. */ + if (res->flags & IORESOURCE_IO) { + root = &pbm->io_space; + min = root->start + 0x400UL; + max = root->end; + } else { + root = &pbm->mem_space; + min = root->start; + max = min + 0x80000000UL; + } + + size = res->end - res->start; + align = size + 1; + if (allocate_resource(root, res, size + 1, min, max, align) < 0) { + /* uh oh */ + prom_printf("PCI: Failed to allocate resource %d for %s\n", + i, pdev->name); + prom_halt(); + } + + /* Update PCI config space. */ + pbm->parent->base_address_update(pdev, i); + } + + /* Special case, disable the ROM. Several devices + * act funny (ie. do not respond to memory space writes) + * when it is left enabled. A good example are Qlogic,ISP + * adapters. + */ + pci_read_config_dword(pdev, PCI_ROM_ADDRESS, ®); + reg &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(pdev, PCI_ROM_ADDRESS, reg); + + /* If we saw I/O or MEM resources, enable appropriate + * bits in PCI command register. + */ + if (io_seen || mem_seen) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + if (io_seen) + cmd |= PCI_COMMAND_IO; + if (mem_seen) + cmd |= PCI_COMMAND_MEMORY; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + + /* If this is a PCI bridge or an IDE controller, + * enable bus mastering. In the former case also + * set the cache line size correctly. + */ + if (((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) || + (((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) && + ((pdev->class & 0x80) != 0))) { + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_MASTER; + pci_write_config_word(pdev, PCI_COMMAND, cmd); + + if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_PCI) + pci_write_config_byte(pdev, + PCI_CACHE_LINE_SIZE, + (64 / sizeof(u32))); + } +} + +void __init pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_assign_unassigned(pbm, pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_assign_unassigned(pbm, pbus); +} + +static int __init pci_intmap_match(struct pci_dev *pdev, unsigned int *interrupt) +{ + struct pcidev_cookie *dev_pcp = pdev->sysdata; + struct pci_pbm_info *pbm = dev_pcp->pbm; + struct linux_prom_pci_registers *pregs = dev_pcp->prom_regs; + unsigned int hi, mid, lo, irq; + int i; + + if (pbm->num_pbm_intmap == 0) + return 0; + + /* If we are underneath a PCI bridge, use PROM register + * property of parent bridge. + */ + if (pdev->bus->number != pbm->pci_first_busno) { + struct pcidev_cookie *bus_pcp; + int offset; + + bus_pcp = pdev->bus->self->sysdata; + pregs = bus_pcp->prom_regs; + offset = prom_getint(bus_pcp->prom_node, + "fcode-rom-offset"); + + /* Did PROM know better and assign an interrupt other + * than #INTA to the device? - We test here for presence of + * FCODE on the card, in this case we assume PROM has set + * correct 'interrupts' property, unless it is quadhme. + */ + if (offset == -1 || + !strcmp(bus_pcp->prom_name, "SUNW,qfe") || + !strcmp(bus_pcp->prom_name, "qfe")) { + /* + * No, use low slot number bits of child as IRQ line. + */ + *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; + } + } + + hi = pregs->phys_hi & pbm->pbm_intmask.phys_hi; + mid = pregs->phys_mid & pbm->pbm_intmask.phys_mid; + lo = pregs->phys_lo & pbm->pbm_intmask.phys_lo; + irq = *interrupt & pbm->pbm_intmask.interrupt; + + for (i = 0; i < pbm->num_pbm_intmap; i++) { + if (pbm->pbm_intmap[i].phys_hi == hi && + pbm->pbm_intmap[i].phys_mid == mid && + pbm->pbm_intmap[i].phys_lo == lo && + pbm->pbm_intmap[i].interrupt == irq) { + *interrupt = pbm->pbm_intmap[i].cinterrupt; + return 1; + } + } + + prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ", + pdev->bus->number, pdev->devfn); + prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", + pregs->phys_hi, pregs->phys_mid, pregs->phys_lo, *interrupt); + prom_printf("Please email this information to davem@redhat.com\n"); + prom_halt(); +} + +static void __init pdev_fixup_irq(struct pci_dev *pdev) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + unsigned int portid = p->portid; + unsigned int prom_irq; + int prom_node = pcp->prom_node; + int err; + + err = prom_getproperty(prom_node, "interrupts", + (char *)&prom_irq, sizeof(prom_irq)); + if (err == 0 || err == -1) { + pdev->irq = 0; + return; + } + + /* Fully specified already? */ + if (((prom_irq & PCI_IRQ_IGN) >> 6) == portid) { + pdev->irq = p->irq_build(p, pdev, prom_irq); + goto have_irq; + } + + /* An onboard device? (bit 5 set) */ + if ((prom_irq & PCI_IRQ_INO) & 0x20) { + pdev->irq = p->irq_build(p, pdev, (portid << 6 | prom_irq)); + goto have_irq; + } + + /* Can we find a matching entry in the interrupt-map? */ + if (pci_intmap_match(pdev, &prom_irq)) { + pdev->irq = p->irq_build(p, pdev, (portid << 6) | prom_irq); + goto have_irq; + } + + /* Ok, we have to do it the hard way. */ + { + unsigned int bus, slot, line; + + bus = (pbm == &pbm->parent->pbm_B) ? (1 << 4) : 0; + + /* If we have a legal interrupt property, use it as + * the IRQ line. + */ + if (prom_irq > 0 && prom_irq < 5) { + line = ((prom_irq - 1) & 3); + } else { + u8 pci_irq_line; + + /* Else just directly consult PCI config space. */ + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); + line = ((pci_irq_line - 1) & 3); + } + + /* Now figure out the slot. */ + if (pdev->bus->number == pbm->pci_first_busno) { + if (pbm == &pbm->parent->pbm_A) + slot = (pdev->devfn >> 3) - 1; + else + slot = (pdev->devfn >> 3) - 2; + } else { + if (pbm == &pbm->parent->pbm_A) + slot = (pdev->bus->self->devfn >> 3) - 1; + else + slot = (pdev->bus->self->devfn >> 3) - 2; + } + slot = slot << 2; + + pdev->irq = p->irq_build(p, pdev, + ((portid << 6) & PCI_IRQ_IGN) | + (bus | slot | line)); + } + +have_irq: + pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, + pdev->irq & PCI_IRQ_INO); +} + +void __init pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) + pdev_fixup_irq(pdev); + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_fixup_irq(pbm, pbus); +} + +/* Generic helper routines for PCI error reporting. */ +void pci_scan_for_target_abort(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_SIG_TARGET_ABORT | + PCI_STATUS_REC_TARGET_ABORT)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] saw Target Abort [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_target_abort(p, pbm, pbus); +} + +void pci_scan_for_master_abort(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_REC_MASTER_ABORT)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] received Master Abort [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_master_abort(p, pbm, pbus); +} + +void pci_scan_for_parity_error(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + struct pci_bus *pbus) +{ + struct pci_dev *pdev; + + for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { + u16 status, error_bits; + + pci_read_config_word(pdev, PCI_STATUS, &status); + error_bits = + (status & (PCI_STATUS_PARITY | + PCI_STATUS_DETECTED_PARITY)); + if (error_bits) { + pci_write_config_word(pdev, PCI_STATUS, error_bits); + printk("PCI%d(PBM%c): Device [%s] saw Parity Error [%016x]\n", + p->index, ((pbm == &p->pbm_A) ? 'A' : 'B'), + pdev->name, status); + } + } + + for (pbus = pbus->children; pbus; pbus = pbus->next) + pci_scan_for_parity_error(p, pbm, pbus); +} diff --git a/arch/sparc64/kernel/pci_impl.h b/arch/sparc64/kernel/pci_impl.h new file mode 100644 index 000000000..24ed0319b --- /dev/null +++ b/arch/sparc64/kernel/pci_impl.h @@ -0,0 +1,166 @@ +/* $Id: pci_impl.h,v 1.3 1999/09/10 10:40:44 davem Exp $ + * pci_impl.h: Helper definitions for PCI controller support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#ifndef PCI_IMPL_H +#define PCI_IMPL_H + +#include <linux/types.h> +#include <linux/spinlock.h> +#include <asm/io.h> + +extern spinlock_t pci_controller_lock; +extern struct pci_controller_info *pci_controller_root; + +extern struct pci_pbm_info *pci_bus2pbm[256]; +extern unsigned char pci_highest_busnum; +extern int pci_num_controllers; + +/* PCI bus scanning and fixup support. */ +extern void pci_fill_in_pbm_cookies(struct pci_bus *pbus, + struct pci_pbm_info *pbm, + int prom_node); +extern void pci_record_assignments(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_assign_unassigned(struct pci_pbm_info *pbm, + struct pci_bus *pbus); +extern void pci_fixup_irq(struct pci_pbm_info *pbm, + struct pci_bus *pbus); + +/* Error reporting support. */ +extern void pci_scan_for_target_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); +extern void pci_scan_for_master_abort(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); +extern void pci_scan_for_parity_error(struct pci_controller_info *, struct pci_pbm_info *, struct pci_bus *); + +/* IOMMU/DVMA initialization. */ +#define PCI_DVMA_HASH_NONE ~0UL +static __inline__ void set_dvma_hash(unsigned long dvma_offset, + unsigned long paddr, + unsigned long daddr) +{ + unsigned long dvma_addr = dvma_offset + daddr; + unsigned long vaddr = (unsigned long)__va(paddr); + + pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; + pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; +} + +/* Configuration space access. */ +extern spinlock_t pci_poke_lock; +extern volatile int pci_poke_in_progress; +extern volatile int pci_poke_faulted; + +static __inline__ void pci_config_read8(u8 *addr, u8 *ret) +{ + unsigned long flags; + u8 byte; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduba [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (byte) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = byte; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_read16(u16 *addr, u16 *ret) +{ + unsigned long flags; + u16 word; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduha [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (word) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = word; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_read32(u32 *addr, u32 *ret) +{ + unsigned long flags; + u32 dword; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "lduwa [%1] %2, %0\n\t" + "membar #Sync" + : "=r" (dword) + : "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + if (!pci_poke_faulted) + *ret = dword; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write8(u8 *addr, u8 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stba %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write16(u16 *addr, u16 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stha %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +static __inline__ void pci_config_write32(u32 *addr, u32 val) +{ + unsigned long flags; + + spin_lock_irqsave(&pci_poke_lock, flags); + pci_poke_in_progress = 1; + pci_poke_faulted = 0; + __asm__ __volatile__("membar #Sync\n\t" + "stwa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (val), "r" (addr), "i" (ASI_PHYS_BYPASS_EC_E_L) + : "memory"); + pci_poke_in_progress = 0; + spin_unlock_irqrestore(&pci_poke_lock, flags); +} + +#endif /* !(PCI_IMPL_H) */ diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c new file mode 100644 index 000000000..a7f469ec8 --- /dev/null +++ b/arch/sparc64/kernel/pci_iommu.c @@ -0,0 +1,510 @@ +/* $Id: pci_iommu.c,v 1.1 1999/08/30 10:00:47 davem Exp $ + * pci_iommu.c: UltraSparc PCI controller IOM/STC support. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include <asm/pbm.h> +#include <asm/iommu.h> +#include <asm/scatterlist.h> + +#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \ + ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) + +/* Accessing IOMMU and Streaming Buffer registers. + * REG parameter is a physical address. All registers + * are 64-bits in size. + */ +#define pci_iommu_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define pci_iommu_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* Find a range of iommu mappings of size NPAGES in page + * table PGT. Return pointer to first iopte. + */ +static iopte_t *iommu_find_range(unsigned long npages, iopte_t *pgt, int pgt_size) +{ + int i; + + pgt_size -= npages; + for (i = 0; i < pgt_size; i++) { + if (!iopte_val(pgt[i]) & IOPTE_VALID) { + int scan; + + for (scan = 1; scan < npages; scan++) { + if (iopte_val(pgt[i + scan]) & IOPTE_VALID) { + i += scan; + goto do_next; + } + } + return &pgt[i]; + } + do_next: + } + return NULL; +} + +#define IOPTE_CONSISTANT(CTX, PADDR) \ + (IOPTE_VALID | IOPTE_CACHE | IOPTE_WRITE | \ + (((CTX) << 47) & IOPTE_CONTEXT) | \ + ((PADDR) & IOPTE_PAGE)) + +#define IOPTE_STREAMING(CTX, PADDR) \ + (IOPTE_CONSISTANT(CTX, PADDR) | IOPTE_STBUF) + +#define IOPTE_INVALID 0UL + +/* Map kernel buffer at ADDR of size SZ using consistant mode + * DMA for PCI device PDEV. Return 32-bit PCI DMA address. + */ +u32 pci_map_consistant(struct pci_dev *pdev, void *addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, oaddr; + u32 ret; + + spin_lock_irqsave(&iommu->lock, flags); + oaddr = (unsigned long)addr; + npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + ret = 0; + if (base != NULL) { + unsigned long i, base_paddr, ctx; + + ret = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + ret |= (oaddr & ~PAGE_MASK); + base_paddr = __pa(oaddr & PAGE_MASK); + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_CONSISTANT(ctx, base_paddr); + } + spin_unlock_irqrestore(&iommu->lock, flags); + + return ret; +} + +/* Unmap a consistant DMA translation. */ +void pci_unmap_consistant(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, i, ctx; + + spin_lock_irqsave(&iommu->lock, flags); + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); + + /* Data for consistant mappings cannot enter the streaming + * buffers, so we only need to update the TSB and flush + * those entries from the IOMMU's TLB. + */ + + /* Step 1: Clear out the TSB entries. Save away + * the context if necessary. + */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + for (i = 0; i < npages; i++, base++) + iopte_val(*base) = IOPTE_INVALID; + + /* Step 2: Flush from IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + bus_addr &= PAGE_MASK; + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, bus_addr); + } + + /* Step 3: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Map a single buffer at PTR of SZ bytes for PCI DMA + * in streaming mode. + */ +u32 pci_map_single(struct pci_dev *pdev, void *ptr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + iopte_t *base; + unsigned long flags, npages, oaddr; + u32 ret; + + spin_lock_irqsave(&iommu->lock, flags); + oaddr = (unsigned long)ptr; + npages = PAGE_ALIGN(oaddr + sz) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + ret = 0; + if (base != NULL) { + unsigned long i, base_paddr, ctx; + + ret = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + ret |= (oaddr & ~PAGE_MASK); + base_paddr = __pa(oaddr & PAGE_MASK); + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + for (i = 0; i < npages; i++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); + } + spin_unlock_irqrestore(&iommu->lock, flags); + + return ret; +} + +/* Unmap a single streaming mode DMA translation. */ +void pci_unmap_single(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + iopte_t *base; + unsigned long flags, npages, i, ctx; + + spin_lock_irqsave(&iommu->lock, flags); + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> PAGE_SHIFT); + bus_addr &= PAGE_MASK; + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + + /* Step 2: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) { + u32 vaddr = bus_addr; + + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_has_ctx_flush && + iommu->iommu_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + for (i = 0; i < npages; i++, vaddr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + } + + /* Step 3: Clear out TSB entries. */ + for (i = 0; i < npages; i++, base++) + iopte_val(*base) = IOPTE_INVALID; + + /* Step 4: Flush the IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, bus_addr); + } + + /* Step 5: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Map a set of buffers described by SGLIST with NELEMS array + * elements in streaming mode for PCI DMA. + */ +void pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + unsigned long flags, ctx, i; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Choose a context if necessary. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) + ctx = iommu->iommu_cur_ctx++; + + /* Step 2: Create the mappings. */ + for (i = 0; i < nelems; i++) { + unsigned long oaddr, npages; + iopte_t *base; + + oaddr = (unsigned long)sglist[i].address; + npages = PAGE_ALIGN(oaddr + sglist[i].length) - (oaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu_find_range(npages, + iommu->page_table, iommu->page_table_sz); + if (base != NULL) { + unsigned long j, base_paddr; + u32 dvma_addr; + + dvma_addr = (iommu->page_table_map_base + + ((base - iommu->page_table) << PAGE_SHIFT)); + dvma_addr |= (oaddr & ~PAGE_MASK); + sglist[i].dvma_address = dvma_addr; + sglist[i].dvma_length = sglist[i].length; + base_paddr = __pa(oaddr & PAGE_MASK); + for (j = 0; j < npages; j++, base++, base_paddr += PAGE_SIZE) + iopte_val(*base) = IOPTE_STREAMING(ctx, base_paddr); + } else { + sglist[i].dvma_address = 0; + sglist[i].dvma_length = 0; + } + } + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Unmap a set of streaming mode DMA translations. */ +void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx, i; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) { + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (strbuf->strbuf_has_ctx_flush && + iommu->iommu_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + vaddr &= PAGE_MASK; + for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, vaddr); + } + + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + } + } + + /* Step 3: Clear out TSB entries. */ + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + iopte_t *base; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + base = iommu->page_table + + ((vaddr - iommu->page_table_map_base) >> PAGE_SHIFT); + for (j = 0; j < npages; j++, base++) + iopte_val(*base) = IOPTE_INVALID; + } + + /* Step 4: Flush the IOMMU TLB. */ + if (iommu->iommu_has_ctx_flush) { + pci_iommu_write(iommu->iommu_ctxflush, ctx); + } else { + for (i = 0; i < nelems; i++) { + unsigned long j, npages; + u32 vaddr; + + j = sglist[i].dvma_length; + if (!j) + break; + vaddr = sglist[i].dvma_address; + npages = PAGE_ALIGN(vaddr + j) - (vaddr & PAGE_MASK); + npages >>= PAGE_SHIFT; + for (j = 0; j < npages; j++, vaddr += PAGE_SIZE) + pci_iommu_write(iommu->iommu_flush, vaddr); + } + } + + /* Step 5: Ensure completion of previous PIO writes. */ + (void) pci_iommu_read(iommu->write_complete_reg); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Make physical memory consistant for a single + * streaming mode DMA translation after a transfer. + */ +void pci_dma_sync_single(struct pci_dev *pdev, u32 bus_addr, int sz) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx, npages; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + npages = PAGE_ALIGN(bus_addr + sz) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + bus_addr &= PAGE_MASK; + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((bus_addr - iommu->page_table_map_base)>>PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while(((long)pci_iommu_read(matchreg)) < 0L); + } else { + unsigned long i; + + for (i = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, bus_addr); + } + + /* Step 3: Perform flush synchronization sequence. */ + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +/* Make physical memory consistant for a set of streaming + * mode DMA translations after a transfer. + */ +void pci_dma_sync_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_iommu *iommu = &pcp->pbm->parent->iommu; + struct pci_strbuf *strbuf = &pcp->pbm->stc; + unsigned long flags, ctx; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((sglist[0].dvma_address - iommu->page_table_map_base) >> PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + PCI_STC_FLUSHFLAG_INIT(strbuf); + if (iommu->iommu_has_ctx_flush && + strbuf->strbuf_has_ctx_flush) { + unsigned long matchreg, flushreg; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); + do { + pci_iommu_write(flushreg, ctx); + } while (((long)pci_iommu_read(matchreg)) < 0L); + } else { + unsigned long i; + + for(i = 0; i < nelems; i++) { + unsigned long bus_addr, npages, j; + + j = sglist[i].dvma_length; + if (!j) + break; + bus_addr = sglist[i].dvma_address; + npages = PAGE_ALIGN(bus_addr + j) - (bus_addr & PAGE_MASK); + npages >>= PAGE_SHIFT; + bus_addr &= PAGE_MASK; + for(j = 0; i < npages; i++, bus_addr += PAGE_SIZE) + pci_iommu_write(strbuf->strbuf_pflush, bus_addr); + } + } + + /* Step 3: Perform flush synchronization sequence. */ + pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) pci_iommu_read(iommu->write_complete_reg); + while (!PCI_STC_FLUSHFLAG_SET(strbuf)) + membar("#LoadLoad"); + + spin_unlock_irqrestore(&iommu->lock, flags); +} diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c new file mode 100644 index 000000000..1afe5a67b --- /dev/null +++ b/arch/sparc64/kernel/pci_psycho.c @@ -0,0 +1,1606 @@ +/* $Id: pci_psycho.c,v 1.4 1999/09/05 09:33:36 ecd Exp $ + * pci_psycho.c: PSYCHO/U2P specific PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/malloc.h> + +#include <asm/pbm.h> +#include <asm/iommu.h> +#include <asm/irq.h> + +#include "pci_impl.h" + +/* All PSYCHO registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define psycho_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define psycho_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* Misc. PSYCHO PCI controller register offsets and definitions. */ +#define PSYCHO_CONTROL 0x0010UL +#define PSYCHO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this PSYCHO*/ +#define PSYCHO_CONTROL_VER 0x0f00000000000000 /* Version of this PSYCHO */ +#define PSYCHO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of PSYCHO */ +#define PSYCHO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */ +#define PSYCHO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */ +#define PSYCHO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */ +#define PSYCHO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */ +#define PSYCHO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */ +#define PSYCHO_CONTROL_MODE 0x0000000000000001 /* PSYCHO clock mode */ +#define PSYCHO_PCIA_CTRL 0x2000UL +#define PSYCHO_PCIB_CTRL 0x4000UL +#define PSYCHO_PCICTRL_RESV1 0xfffffff000000000 /* Reserved */ +#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error */ +#define PSYCHO_PCICTRL_SERR 0x0000000400000000 /* SERR signal asserted */ +#define PSYCHO_PCICTRL_SPEED 0x0000000200000000 /* PCI speed (1 is U2P clock) */ +#define PSYCHO_PCICTRL_RESV2 0x00000001ffc00000 /* Reserved */ +#define PSYCHO_PCICTRL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */ +#define PSYCHO_PCICTRL_RESV3 0x00000000001ff800 /* Reserved */ +#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */ +#define PSYCHO_PCICTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */ +#define PSYCHO_PCICTRL_EEN 0x0000000000000100 /* PCI Error Interrupt Enable */ +#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0 /* Reserved */ +#define PSYCHO_PCICTRL_AEN 0x000000000000003f /* PCI DVMA Arbitration Enable */ + +/* U2P Programmer's Manual, page 13-55, configuration space + * address format: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define PSYCHO_CONFIG_BASE(PBM) \ + ((PBM)->parent->config_space | (1UL << 24)) +#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (PSYCHO_CONFIG_BASE(pbm) | + PSYCHO_CONFIG_ENCODE(bus, devfn, where)); +} + +static int psycho_out_of_range(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned char devfn) +{ + return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8)); +} + +/* PSYCHO PCI configuration space accessors. */ + +static int psycho_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + *value = 0xff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_read8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_read_word(struct pci_dev *dev, int where, u16 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + *value = 0xffff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + *value = 0xffffffff; + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_read_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + + pci_config_read32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_byte(struct pci_dev *dev, int where, u8 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + pci_config_write8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_word(struct pci_dev *dev, int where, u16 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int psycho_write_dword(struct pci_dev *dev, int where, u32 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + addr = psycho_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (psycho_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops psycho_ops = { + psycho_read_byte, + psycho_read_word, + psycho_read_dword, + psycho_write_byte, + psycho_write_word, + psycho_write_dword +}; + +/* PSYCHO interrupt mapping support. */ +#define PSYCHO_IMAP_A_SLOT0 0x0c00UL +#define PSYCHO_IMAP_B_SLOT0 0x0c20UL +static unsigned long psycho_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return PSYCHO_IMAP_A_SLOT0 + (slot * 8); + else + return PSYCHO_IMAP_B_SLOT0 + (slot * 8); +} + +#define PSYCHO_IMAP_SCSI 0x1000UL +#define PSYCHO_IMAP_ETH 0x1008UL +#define PSYCHO_IMAP_BPP 0x1010UL +#define PSYCHO_IMAP_AU_REC 0x1018UL +#define PSYCHO_IMAP_AU_PLAY 0x1020UL +#define PSYCHO_IMAP_PFAIL 0x1028UL +#define PSYCHO_IMAP_KMS 0x1030UL +#define PSYCHO_IMAP_FLPY 0x1038UL +#define PSYCHO_IMAP_SHW 0x1040UL +#define PSYCHO_IMAP_KBD 0x1048UL +#define PSYCHO_IMAP_MS 0x1050UL +#define PSYCHO_IMAP_SER 0x1058UL +#define PSYCHO_IMAP_TIM0 0x1060UL +#define PSYCHO_IMAP_TIM1 0x1068UL +#define PSYCHO_IMAP_UE 0x1070UL +#define PSYCHO_IMAP_CE 0x1078UL +#define PSYCHO_IMAP_A_ERR 0x1080UL +#define PSYCHO_IMAP_B_ERR 0x1088UL +#define PSYCHO_IMAP_PMGMT 0x1090UL +#define PSYCHO_IMAP_GFX 0x1098UL +#define PSYCHO_IMAP_EUPA 0x10a0UL + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ PSYCHO_IMAP_SCSI, +/*0x21*/ PSYCHO_IMAP_ETH, +/*0x22*/ PSYCHO_IMAP_BPP, +/*0x23*/ PSYCHO_IMAP_AU_REC, +/*0x24*/ PSYCHO_IMAP_AU_PLAY, +/*0x25*/ PSYCHO_IMAP_PFAIL, +/*0x26*/ PSYCHO_IMAP_KMS, +/*0x27*/ PSYCHO_IMAP_FLPY, +/*0x28*/ PSYCHO_IMAP_SHW, +/*0x29*/ PSYCHO_IMAP_KBD, +/*0x2a*/ PSYCHO_IMAP_MS, +/*0x2b*/ PSYCHO_IMAP_SER, +/*0x2c*/ PSYCHO_IMAP_TIM0, +/*0x2d*/ PSYCHO_IMAP_TIM1, +/*0x2e*/ PSYCHO_IMAP_UE, +/*0x2f*/ PSYCHO_IMAP_CE, +/*0x30*/ PSYCHO_IMAP_A_ERR, +/*0x31*/ PSYCHO_IMAP_B_ERR, +/*0x32*/ PSYCHO_IMAP_PMGMT +}; +#define PSYCHO_ONBOARD_IRQ_BASE 0x20 +#define PSYCHO_ONBOARD_IRQ_LAST 0x32 +#define psycho_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + +#define PSYCHO_ICLR_A_SLOT0 0x1400UL +#define PSYCHO_ICLR_SCSI 0x1800UL + +#define psycho_iclr_offset(ino) \ + ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +/* PCI PSYCHO INO number to Sparc PIL level. */ +static unsigned char psycho_pil_table[] = { +/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ +/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ +/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ +/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ +/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ +/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ +/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ +/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ +/*0x20*/3, /* SCSI */ +/*0x21*/5, /* Ethernet */ +/*0x22*/8, /* Parallel Port */ +/*0x23*/13, /* Audio Record */ +/*0x24*/14, /* Audio Playback */ +/*0x25*/15, /* PowerFail */ +/*0x26*/3, /* second SCSI */ +/*0x27*/11, /* Floppy */ +/*0x28*/2, /* Spare Hardware */ +/*0x29*/9, /* Keyboard */ +/*0x2a*/4, /* Mouse */ +/*0x2b*/12, /* Serial */ +/*0x2c*/10, /* Timer 0 */ +/*0x2d*/11, /* Timer 1 */ +/*0x2e*/15, /* Uncorrectable ECC */ +/*0x2f*/15, /* Correctable ECC */ +/*0x30*/15, /* PCI Bus A Error */ +/*0x31*/15, /* PCI Bus B Error */ +/*0x32*/1, /* Power Management */ +}; + +static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino) +{ + int ret; + + ret = psycho_pil_table[ino]; + if (ret == 0 && pdev == NULL) { + ret = 1; + } else if (ret == 0) { + switch ((pdev->class >> 16) & 0x0f) { + case PCI_BASE_CLASS_STORAGE: + ret = 4; + + case PCI_BASE_CLASS_NETWORK: + ret = 6; + + case PCI_BASE_CLASS_DISPLAY: + ret = 9; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + ret = 10; + + default: + ret = 1; + }; + } + + return ret; +} + +static unsigned int __init psycho_irq_build(struct pci_controller_info *p, + struct pci_dev *pdev, + unsigned int ino) +{ + struct ino_bucket *bucket; + volatile unsigned int *imap, *iclr; + unsigned long imap_off, iclr_off; + int pil, inofixup = 0; + + ino &= PCI_IRQ_INO; + if (ino < PSYCHO_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = psycho_pcislot_imap_offset(ino); + } else { + /* Onboard device */ + if (ino > PSYCHO_ONBOARD_IRQ_LAST) { + prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = psycho_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + pil = psycho_ino_to_pil(pdev, ino); + imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); + imap += 1; + + iclr_off = psycho_iclr_offset(ino); + iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); + iclr += 1; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket->flags |= IBF_PCI; + + return __irq(bucket); +} + +/* PSYCHO error handling support. */ +enum psycho_error_type { + UE_ERR, CE_ERR, PCI_ERR +}; + +/* Helper function of IOMMU error checking, which checks out + * the state of the streaming buffers. The IOMMU lock is + * held when this is called. + * + * For the PCI error case we know which PBM (and thus which + * streaming buffer) caused the error, but for the uncorrectable + * error case we do not. So we always check both streaming caches. + */ +#define PSYCHO_STRBUF_CONTROL_A 0x2800UL +#define PSYCHO_STRBUF_CONTROL_B 0x4800UL +#define PSYCHO_STRBUF_CTRL_LPTR 0x00000000000000f0 /* LRU Lock Pointer */ +#define PSYCHO_STRBUF_CTRL_LENAB 0x0000000000000008 /* LRU Lock Enable */ +#define PSYCHO_STRBUF_CTRL_RRDIS 0x0000000000000004 /* Rerun Disable */ +#define PSYCHO_STRBUF_CTRL_DENAB 0x0000000000000002 /* Diagnostic Mode Enable */ +#define PSYCHO_STRBUF_CTRL_ENAB 0x0000000000000001 /* Streaming Buffer Enable */ +#define PSYCHO_STRBUF_FLUSH_A 0x2808UL +#define PSYCHO_STRBUF_FLUSH_B 0x4808UL +#define PSYCHO_STRBUF_FSYNC_A 0x2810UL +#define PSYCHO_STRBUF_FSYNC_B 0x4810UL +#define PSYCHO_STC_DATA_A 0xb000UL +#define PSYCHO_STC_DATA_B 0xc000UL +#define PSYCHO_STC_ERR_A 0xb400UL +#define PSYCHO_STC_ERR_B 0xc400UL +#define PSYCHO_STCERR_WRITE 0x0000000000000002 /* Write Error */ +#define PSYCHO_STCERR_READ 0x0000000000000001 /* Read Error */ +#define PSYCHO_STC_TAG_A 0xb800UL +#define PSYCHO_STC_TAG_B 0xc800UL +#define PSYCHO_STCTAG_PPN 0x0fffffff00000000 /* Physical Page Number */ +#define PSYCHO_STCTAG_VPN 0x00000000ffffe000 /* Virtual Page Number */ +#define PSYCHO_STCTAG_VALID 0x0000000000000002 /* Valid */ +#define PSYCHO_STCTAG_WRITE 0x0000000000000001 /* Writable */ +#define PSYCHO_STC_LINE_A 0xb900UL +#define PSYCHO_STC_LINE_B 0xc900UL +#define PSYCHO_STCLINE_LINDX 0x0000000001e00000 /* LRU Index */ +#define PSYCHO_STCLINE_SPTR 0x00000000001f8000 /* Dirty Data Start Pointer */ +#define PSYCHO_STCLINE_LADDR 0x0000000000007f00 /* Line Address */ +#define PSYCHO_STCLINE_EPTR 0x00000000000000fc /* Dirty Data End Pointer */ +#define PSYCHO_STCLINE_VALID 0x0000000000000002 /* Valid */ +#define PSYCHO_STCLINE_FOFN 0x0000000000000001 /* Fetch Outstanding / Flush Necessary */ + +static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED; +static unsigned long stc_error_buf[128]; +static unsigned long stc_tag_buf[16]; +static unsigned long stc_line_buf[16]; + +static void __psycho_check_one_stc(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + struct pci_strbuf *strbuf = &pbm->stc; + unsigned long regbase = p->controller_regs; + unsigned long err_base, tag_base, line_base; + u64 control; + int i; + + if (is_pbm_a) { + err_base = regbase + PSYCHO_STC_ERR_A; + tag_base = regbase + PSYCHO_STC_TAG_A; + line_base = regbase + PSYCHO_STC_LINE_A; + } else { + err_base = regbase + PSYCHO_STC_ERR_A; + tag_base = regbase + PSYCHO_STC_TAG_A; + line_base = regbase + PSYCHO_STC_LINE_A; + } + + spin_lock(&stc_buf_lock); + + /* This is __REALLY__ dangerous. When we put the + * streaming buffer into diagnostic mode to probe + * it's tags and error status, we _must_ clear all + * of the line tag valid bits before re-enabling + * the streaming buffer. If any dirty data lives + * in the STC when we do this, we will end up + * invalidating it before it has a chance to reach + * main memory. + */ + control = psycho_read(strbuf->strbuf_control); + psycho_write(strbuf->strbuf_control, + (control | PSYCHO_STRBUF_CTRL_DENAB)); + for (i = 0; i < 128; i++) { + unsigned long val; + + val = psycho_read(err_base + (i * 8UL)); + psycho_write(err_base + (i * 8UL), 0UL); + stc_error_buf[i] = val; + } + for (i = 0; i < 16; i++) { + stc_tag_buf[i] = psycho_read(tag_base + (i * 8UL)); + stc_line_buf[i] = psycho_read(line_base + (i * 8UL)); + psycho_write(tag_base + (i * 8UL), 0UL); + psycho_write(line_base + (i * 8UL), 0UL); + } + + /* OK, state is logged, exit diagnostic mode. */ + psycho_write(strbuf->strbuf_control, control); + + for (i = 0; i < 16; i++) { + int j, saw_error, first, last; + + saw_error = 0; + first = i * 8; + last = first + 8; + for (j = first; j < last; j++) { + unsigned long errval = stc_error_buf[j]; + if (errval != 0) { + saw_error++; + printk("PSYCHO%d(PBM%c): STC_ERR(%d)[wr(%d)rd(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + j, + (errval & PSYCHO_STCERR_WRITE) ? 1 : 0, + (errval & PSYCHO_STCERR_READ) ? 1 : 0); + } + } + if (saw_error != 0) { + unsigned long tagval = stc_tag_buf[i]; + unsigned long lineval = stc_line_buf[i]; + printk("PSYCHO%d(PBM%c): STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)W(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + i, + ((tagval & PSYCHO_STCTAG_PPN) >> 19UL), + (tagval & PSYCHO_STCTAG_VPN), + ((tagval & PSYCHO_STCTAG_VALID) ? 1 : 0), + ((tagval & PSYCHO_STCTAG_WRITE) ? 1 : 0)); + printk("PSYCHO%d(PBM%c): STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" + "V(%d)FOFN(%d)]\n", + p->index, + (is_pbm_a ? 'A' : 'B'), + i, + ((lineval & PSYCHO_STCLINE_LINDX) >> 21UL), + ((lineval & PSYCHO_STCLINE_SPTR) >> 15UL), + ((lineval & PSYCHO_STCLINE_LADDR) >> 8UL), + ((lineval & PSYCHO_STCLINE_EPTR) >> 2UL), + ((lineval & PSYCHO_STCLINE_VALID) ? 1 : 0), + ((lineval & PSYCHO_STCLINE_FOFN) ? 1 : 0)); + } + } + + spin_unlock(&stc_buf_lock); +} + +static void __psycho_check_stc_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + struct pci_pbm_info *pbm; + + pbm = &p->pbm_A; + if (pbm->stc.strbuf_enabled) + __psycho_check_one_stc(p, pbm, 1); + + pbm = &p->pbm_B; + if (pbm->stc.strbuf_enabled) + __psycho_check_one_stc(p, pbm, 0); +} + +/* When an Uncorrectable Error or a PCI Error happens, we + * interrogate the IOMMU state to see if it is the cause. + */ +#define PSYCHO_IOMMU_CONTROL 0x0200UL +#define PSYCHO_IOMMU_CTRL_RESV 0xfffffffff9000000 /* Reserved */ +#define PSYCHO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status */ +#define PSYCHO_IOMMU_CTRL_XLTEERR 0x0000000001000000 /* Translation Error encountered */ +#define PSYCHO_IOMMU_CTRL_LCKEN 0x0000000000800000 /* Enable translation locking */ +#define PSYCHO_IOMMU_CTRL_LCKPTR 0x0000000000780000 /* Translation lock pointer */ +#define PSYCHO_IOMMU_CTRL_TSBSZ 0x0000000000070000 /* TSB Size */ +#define PSYCHO_IOMMU_TSBSZ_1K 0x0000000000000000 /* TSB Table 1024 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_2K 0x0000000000010000 /* TSB Table 2048 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_4K 0x0000000000020000 /* TSB Table 4096 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_8K 0x0000000000030000 /* TSB Table 8192 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_16K 0x0000000000040000 /* TSB Table 16k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_32K 0x0000000000050000 /* TSB Table 32k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_64K 0x0000000000060000 /* TSB Table 64k 8-byte entries */ +#define PSYCHO_IOMMU_TSBSZ_128K 0x0000000000070000 /* TSB Table 128k 8-byte entries */ +#define PSYCHO_IOMMU_CTRL_RESV2 0x000000000000fff8 /* Reserved */ +#define PSYCHO_IOMMU_CTRL_TBWSZ 0x0000000000000004 /* Assumed page size, 0=8k 1=64k */ +#define PSYCHO_IOMMU_CTRL_DENAB 0x0000000000000002 /* Diagnostic mode enable */ +#define PSYCHO_IOMMU_CTRL_ENAB 0x0000000000000001 /* IOMMU Enable */ +#define PSYCHO_IOMMU_TSBBASE 0x0208UL +#define PSYCHO_IOMMU_FLUSH 0x0210UL +#define PSYCHO_IOMMU_TAG 0xa580UL +#define PSYCHO_IOMMU_TAG_ERRSTS (0x3UL << 23UL) +#define PSYCHO_IOMMU_TAG_ERR (0x1UL << 22UL) +#define PSYCHO_IOMMU_TAG_WRITE (0x1UL << 21UL) +#define PSYCHO_IOMMU_TAG_STREAM (0x1UL << 20UL) +#define PSYCHO_IOMMU_TAG_SIZE (0x1UL << 19UL) +#define PSYCHO_IOMMU_TAG_VPAGE 0x7ffffUL +#define PSYCHO_IOMMU_DATA 0xa600UL +#define PSYCHO_IOMMU_DATA_VALID (1UL << 30UL) +#define PSYCHO_IOMMU_DATA_CACHE (1UL << 28UL) +#define PSYCHO_IOMMU_DATA_PPAGE 0xfffffffUL +static void psycho_check_iommu_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar, + enum psycho_error_type type) +{ + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&p->iommu.lock, flags); + control = psycho_read(p->iommu.iommu_control); + if (control & PSYCHO_IOMMU_CTRL_XLTEERR) { + char *type_string; + + /* Clear the error encountered bit. */ + control &= ~PSYCHO_IOMMU_CTRL_XLTEERR; + psycho_write(p->iommu.iommu_control, control); + + switch((control & PSYCHO_IOMMU_CTRL_XLTESTAT) >> 25UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("PSYCHO%d: IOMMU Error, type[%s]\n", + p->index, type_string); + + /* Put the IOMMU into diagnostic mode and probe + * it's TLB for entries with error status. + * + * It is very possible for another DVMA to occur + * while we do this probe, and corrupt the system + * further. But we are so screwed at this point + * that we are likely to crash hard anyways, so + * get as much diagnostic information to the + * console as we can. + */ + psycho_write(p->iommu.iommu_control, + control | PSYCHO_IOMMU_CTRL_DENAB); + for (i = 0; i < 16; i++) { + unsigned long base = p->controller_regs; + + iommu_tag[i] = + psycho_read(base + PSYCHO_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + psycho_read(base + PSYCHO_IOMMU_DATA + (i * 8UL)); + + /* Now clear out the entry. */ + psycho_write(base + PSYCHO_IOMMU_TAG + (i * 8UL), 0); + psycho_write(base + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + } + + /* Leave diagnostic mode. */ + psycho_write(p->iommu.iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & PSYCHO_IOMMU_TAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & PSYCHO_IOMMU_TAG_ERRSTS) >> 23UL) { + case 0: + type_string = "Protection Error"; + break; + case 1: + type_string = "Invalid Error"; + break; + case 2: + type_string = "TimeOut Error"; + break; + case 3: + default: + type_string = "ECC Error"; + break; + }; + printk("PSYCHO%d: IOMMU TAG(%d)[error(%s) wr(%d) str(%d) sz(%dK) vpg(%08lx)]\n", + p->index, i, type_string, + ((tag & PSYCHO_IOMMU_TAG_WRITE) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_STREAM) ? 1 : 0), + ((tag & PSYCHO_IOMMU_TAG_SIZE) ? 64 : 8), + (tag & PSYCHO_IOMMU_TAG_VPAGE) << PAGE_SHIFT); + printk("PSYCHO%d: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", + p->index, i, + ((data & PSYCHO_IOMMU_DATA_VALID) ? 1 : 0), + ((data & PSYCHO_IOMMU_DATA_CACHE) ? 1 : 0), + (data & PSYCHO_IOMMU_DATA_PPAGE) << PAGE_SHIFT); + } + } + __psycho_check_stc_error(p, afsr, afar, type); + spin_unlock_irqrestore(&p->iommu.lock, flags); +} + +/* Uncorrectable Errors. Cause of the error and the address are + * recorded in the UE_AFSR and UE_AFAR of PSYCHO. They are errors + * relating to UPA interface transactions. + */ +#define PSYCHO_UE_AFSR 0x0030UL +#define PSYCHO_UEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define PSYCHO_UEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define PSYCHO_UEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define PSYCHO_UEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define PSYCHO_UEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define PSYCHO_UEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define PSYCHO_UEAFSR_RESV1 0x03ff000000000000 /* Reserved */ +#define PSYCHO_UEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_UEAFSR_DOFF 0x00000000e0000000 /* Doubleword Offset */ +#define PSYCHO_UEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */ +#define PSYCHO_UEAFSR_BLK 0x0000000000800000 /* Trans was block operation */ +#define PSYCHO_UEAFSR_RESV2 0x00000000007fffff /* Reserved */ +#define PSYCHO_UE_AFAR 0x0038UL + +static void psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + PSYCHO_UE_AFSR; + unsigned long afar_reg = p->controller_regs + PSYCHO_UE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch uncorrectable error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear the primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_UEAFSR_PPIO | PSYCHO_UEAFSR_PDRD | PSYCHO_UEAFSR_PDWR | + PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d: Uncorrectable Error, primary error type[%s]\n", + p->index, + (((error_bits & PSYCHO_UEAFSR_PPIO) ? + "PIO" : + ((error_bits & PSYCHO_UEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & PSYCHO_UEAFSR_PDWR) ? + "DMA Write" : "???"))))); + printk("PSYCHO%d: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n", + p->index, + (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL, + (afsr & PSYCHO_UEAFSR_MID) >> 24UL, + ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0)); + printk("PSYCHO%d: UE AFAR [%016lx]\n", p->index, afar); + printk("PSYCHO%d: UE Secondary errors [", p->index); + reported = 0; + if (afsr & PSYCHO_UEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & PSYCHO_UEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & PSYCHO_UEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* Interrogate IOMMU for error status. */ + psycho_check_iommu_error(p, afsr, afar, UE_ERR); +} + +/* Correctable Errors. */ +#define PSYCHO_CE_AFSR 0x0040UL +#define PSYCHO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */ +#define PSYCHO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */ +#define PSYCHO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */ +#define PSYCHO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */ +#define PSYCHO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */ +#define PSYCHO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/ +#define PSYCHO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */ +#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */ +#define PSYCHO_CEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000 /* Double Offset */ +#define PSYCHO_CEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */ +#define PSYCHO_CEAFSR_BLK 0x0000000000800000 /* Trans was block operation */ +#define PSYCHO_CEAFSR_RESV2 0x00000000007fffff /* Reserved */ +#define PSYCHO_CE_AFAR 0x0040UL + +static void psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + PSYCHO_CE_AFSR; + unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR | + PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d: Correctable Error, primary error type[%s]\n", + p->index, + (((error_bits & PSYCHO_CEAFSR_PPIO) ? + "PIO" : + ((error_bits & PSYCHO_CEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & PSYCHO_CEAFSR_PDWR) ? + "DMA Write" : "???"))))); + printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " + "UPA_MID[%02lx] was_block(%d)\n", + p->index, + (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL, + (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL, + (afsr & PSYCHO_CEAFSR_MID) >> 24UL, + ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0)); + printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar); + printk("PSYCHO%d: CE Secondary errors [", p->index); + reported = 0; + if (afsr & PSYCHO_CEAFSR_SPIO) { + reported++; + printk("(PIO)"); + } + if (afsr & PSYCHO_CEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & PSYCHO_CEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +/* PCI Errors. They are signalled by the PCI bus module since they + * are assosciated with a specific bus segment. + */ +#define PSYCHO_PCI_AFSR_A 0x2010UL +#define PSYCHO_PCI_AFSR_B 0x4010UL +#define PSYCHO_PCIAFSR_PMA 0x8000000000000000 /* Primary Master Abort Error */ +#define PSYCHO_PCIAFSR_PTA 0x4000000000000000 /* Primary Target Abort Error */ +#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000 /* Primary Excessive Retries */ +#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000 /* Primary Parity Error */ +#define PSYCHO_PCIAFSR_SMA 0x0800000000000000 /* Secondary Master Abort Error */ +#define PSYCHO_PCIAFSR_STA 0x0400000000000000 /* Secondary Target Abort Error */ +#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000 /* Secondary Excessive Retries */ +#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000 /* Secondary Parity Error */ +#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000 /* Reserved */ +#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */ +#define PSYCHO_PCIAFSR_BLK 0x0000000080000000 /* Trans was block operation */ +#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000 /* Reserved */ +#define PSYCHO_PCIAFSR_MID 0x000000003e000000 /* MID causing the error */ +#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffff /* Reserved */ +#define PSYCHO_PCI_AFAR_A 0x2018UL +#define PSYCHO_PCI_AFAR_B 0x4018UL + +static void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_pbm_info *pbm = dev_id; + struct pci_controller_info *p = pbm->parent; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int is_pbm_a, reported; + + is_pbm_a = (pbm == &pbm->parent->pbm_A); + if (is_pbm_a) { + afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A; + afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A; + } else { + afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B; + afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B; + } + + /* Latch error status. */ + afar = psycho_read(afar_reg); + afsr = psycho_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA | + PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR | + PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | + PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); + psycho_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n", + p->index, (is_pbm_a ? 'A' : 'B'), + (((error_bits & PSYCHO_PCIAFSR_PMA) ? + "Master Abort" : + ((error_bits & PSYCHO_PCIAFSR_PTA) ? + "Target Abort" : + ((error_bits & PSYCHO_PCIAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & PSYCHO_PCIAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n", + p->index, (is_pbm_a ? 'A' : 'B'), + (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL, + (afsr & PSYCHO_PCIAFSR_MID) >> 25UL, + (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0); + printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n", + p->index, (is_pbm_a ? 'A' : 'B'), afar); + printk("PSYCHO%d(PBM%c): PCI Secondary errors [", + p->index, (is_pbm_a ? 'A' : 'B')); + reported = 0; + if (afsr & PSYCHO_PCIAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & PSYCHO_PCIAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & PSYCHO_PCIAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan PBM's PCI bus for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { + psycho_check_iommu_error(p, afsr, afar, PCI_ERR); + pci_scan_for_target_abort(p, pbm, pbm->pci_bus); + } + if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) + pci_scan_for_master_abort(p, pbm, pbm->pci_bus); + + /* For excessive retries, PSYCHO/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) + pci_scan_for_parity_error(p, pbm, pbm->pci_bus); +} + +/* XXX What about PowerFail/PowerManagement??? -DaveM */ +#define PSYCHO_ECC_CTRL 0x0020 +#define PSYCHO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */ +#define PSYCHO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */ +#define PSYCHO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */ +#define PSYCHO_UE_INO 0x2e +#define PSYCHO_CE_INO 0x2f +#define PSYCHO_PCIERR_A_INO 0x30 +#define PSYCHO_PCIERR_B_INO 0x31 +static void __init psycho_register_error_handlers(struct pci_controller_info *p) +{ + unsigned long base = p->controller_regs; + unsigned int irq, portid = p->portid; + u64 tmp; + + /* Build IRQs and register handlers. */ + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO); + if (request_irq(irq, psycho_ue_intr, + SA_SHIRQ, "PSYCHO UE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO); + if (request_irq(irq, psycho_ce_intr, + SA_SHIRQ, "PSYCHO CE", p) < 0) { + prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { + prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); + if (request_irq(irq, psycho_pcierr_intr, + SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { + prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + /* Enable UE and CE interrupts for controller. */ + psycho_write(base + PSYCHO_ECC_CTRL, + (PSYCHO_ECCCTRL_EE | + PSYCHO_ECCCTRL_UE | + PSYCHO_ECCCTRL_CE)); + + /* Enable PCI Error interrupts and clear error + * bits for each PBM. + */ + tmp = psycho_read(base + PSYCHO_PCIA_CTRL); + tmp |= (PSYCHO_PCICTRL_SBH_ERR | + PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_INT | + PSYCHO_PCICTRL_EEN); + psycho_write(base + PSYCHO_PCIA_CTRL, tmp); + + tmp = psycho_read(base + PSYCHO_PCIB_CTRL); + tmp |= (PSYCHO_PCICTRL_SBH_ERR | + PSYCHO_PCICTRL_SERR | + PSYCHO_PCICTRL_SBH_INT | + PSYCHO_PCICTRL_EEN); + psycho_write(base + PSYCHO_PCIB_CTRL, tmp); +} + +/* PSYCHO boot time probing and initialization. */ +static void __init psycho_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + res->start += root->start; + res->end += root->start; +} + +static void __init psycho_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct resource *res = &pdev->resource[resource]; + struct resource *root; + u32 reg; + int where, size; + + if (res->flags & IORESOURCE_IO) + root = &pbm->io_space; + else + root = &pbm->mem_space; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - root->start)) & ~size)); + pci_write_config_dword(pdev, where, reg); +} + +/* We have to do the config space accesses by hand, thus... */ +#define PBM_BRIDGE_BUS 0x40 +#define PBM_BRIDGE_SUBORDINATE 0x41 +static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno) +{ + u8 *addr, busno; + int nbus; + + busno = pci_highest_busnum; + nbus = pbm->pci_last_busno - pbm->pci_first_busno; + + addr = psycho_pci_config_mkaddr(pbm, orig_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, busno); + addr = psycho_pci_config_mkaddr(pbm, busno, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, busno + nbus); + + pbm->pci_first_busno = busno; + pbm->pci_last_busno = busno + nbus; + pci_highest_busnum = busno + nbus + 1; + + do { + pci_bus2pbm[busno++] = pbm; + } while (nbus--); +} + +/* We have to do the config space accesses by hand here since + * the pci_bus2pbm array is not ready yet. + */ +static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, + u8 busno) +{ + u32 devfn, l, class; + u8 hdr_type; + int is_multi = 0; + + for(devfn = 0; devfn < 0xff; ++devfn) { + u32 *dwaddr; + u8 *baddr; + + if (PCI_FUNC(devfn) != 0 && is_multi == 0) + continue; + + /* Anything there? */ + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); + l = 0xffffffff; + pci_config_read32(dwaddr, &l); + if (l == 0xffffffff || l == 0x00000000 || + l == 0x0000ffff || l == 0xffff0000) { + is_multi = 0; + continue; + } + + baddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); + pci_config_read8(baddr, &hdr_type); + if (PCI_FUNC(devfn) == 0) + is_multi = hdr_type & 0x80; + + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); + class = 0xffffffff; + pci_config_read32(dwaddr, &class); + if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { + u32 buses = 0xffffffff; + + dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, + PCI_PRIMARY_BUS); + pci_config_read32(dwaddr, &buses); + pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); + buses &= 0xff000000; + pci_config_write32(dwaddr, buses); + } + } +} + +static void __init pbm_bridge_reconfigure(struct pci_controller_info *p) +{ + struct pci_pbm_info *pbm; + u8 *addr; + + /* Clear out primary/secondary/subordinate bus numbers on + * all PCI-to-PCI bridges under each PBM. The generic bus + * probing will fix them up. + */ + pbm_pci_bridge_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_pci_bridge_renumber(&p->pbm_A, p->pbm_A.pci_first_busno); + + /* Move PBM A out of the way. */ + pbm = &p->pbm_A; + addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PBM_BRIDGE_BUS); + pci_config_write8(addr, 0xff); + addr = psycho_pci_config_mkaddr(pbm, 0xff, + 0, PBM_BRIDGE_SUBORDINATE); + pci_config_write8(addr, 0xff); + + /* Now we can safely renumber both PBMs. */ + pbm_renumber(&p->pbm_B, p->pbm_B.pci_first_busno); + pbm_renumber(&p->pbm_A, 0xff); +} + +static void __init pbm_scan_bus(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, + p->pci_ops, + pbm); + pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbm->pci_bus); + pci_assign_unassigned(pbm, pbm->pci_bus); + pci_fixup_irq(pbm, pbm->pci_bus); +} + +static void __init psycho_scan_bus(struct pci_controller_info *p) +{ + pbm_bridge_reconfigure(p); + pbm_scan_bus(p, &p->pbm_B); + pbm_scan_bus(p, &p->pbm_A); + + /* After the PCI bus scan is complete, we can register + * the error interrupt handlers. + */ + psycho_register_error_handlers(p); +} + +static void __init psycho_iommu_init(struct pci_controller_info *p, int tsbsize) +{ + extern int this_is_starfire; + extern void *starfire_hookup(int); + struct linux_mlist_p1275 *mlist; + unsigned long tsbbase, i, n, order; + iopte_t *iopte; + u64 control; + + /* Setup initial software IOMMU state. */ + spin_lock_init(&p->iommu.lock); + p->iommu.iommu_cur_ctx = 0; + + /* PSYCHO's IOMMU lacks ctx flushing. */ + p->iommu.iommu_has_ctx_flush = 0; + + /* Register addresses. */ + p->iommu.iommu_control = p->controller_regs + PSYCHO_IOMMU_CONTROL; + p->iommu.iommu_tsbbase = p->controller_regs + PSYCHO_IOMMU_TSBBASE; + p->iommu.iommu_flush = p->controller_regs + PSYCHO_IOMMU_FLUSH; + p->iommu.iommu_ctxflush = 0; + + /* We use the main control register of PSYCHO as the write + * completion register. + */ + p->iommu.write_complete_reg = p->controller_regs + PSYCHO_CONTROL; + + /* + * Invalidate TLB Entries. + */ + control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control |= PSYCHO_IOMMU_CTRL_DENAB; + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + for(i = 0; i < 16; i++) + psycho_write(p->controller_regs + PSYCHO_IOMMU_DATA + (i * 8UL), 0); + + control &= ~(PSYCHO_IOMMU_CTRL_DENAB); + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + + for(order = 0;; order++) + if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) + break; + + tsbbase = __get_free_pages(GFP_DMA, order); + if (!tsbbase) { + prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n"); + prom_halt(); + } + p->iommu.page_table = iopte = (iopte_t *)tsbbase; + p->iommu.page_table_sz = (tsbsize * 1024); + + /* Initialize to "none" settings. */ + for(i = 0; i < PCI_DVMA_HASHSZ; i++) { + pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; + pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; + } + + n = 0; + mlist = *prom_meminfo()->p1275_totphys; + while (mlist) { + unsigned long paddr = mlist->start_adr; + unsigned long num_bytes = mlist->num_bytes; + + if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) + goto next; + + if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) + num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; + + /* Align base and length so we map whole hash table sized chunks + * at a time (and therefore full 64K IOMMU pages). + */ + paddr &= ~((1UL << 24UL) - 1); + num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); + + /* Move up the base for mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != + PCI_DVMA_HASH_NONE) { + paddr += (1UL << 24UL); + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Move down the size for tail mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != + PCI_DVMA_HASH_NONE) { + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Now map the rest. */ + for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { + iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | + IOPTE_CACHE | IOPTE_WRITE) | + (paddr & IOPTE_PAGE)); + + if (!(n & 0xff)) + set_dvma_hash(0x80000000, paddr, (n << 16)); + + if (++n > (tsbsize * 1024)) + goto out; + + paddr += (1 << 16); + iopte++; + } + next: + mlist = mlist->theres_more; + } +out: + if (mlist) { + prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); + prom_printf("Try booting with mem=xxxM or similar\n"); + prom_halt(); + } + + psycho_write(p->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); + + control = psycho_read(p->controller_regs + PSYCHO_IOMMU_CONTROL); + control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ); + control |= (PSYCHO_IOMMU_CTRL_TBWSZ | PSYCHO_IOMMU_CTRL_ENAB); + switch(tsbsize) { + case 8: + p->iommu.page_table_map_base = 0xe0000000; + control |= PSYCHO_IOMMU_TSBSZ_8K; + break; + case 16: + p->iommu.page_table_map_base = 0xc0000000; + control |= PSYCHO_IOMMU_TSBSZ_16K; + break; + case 32: + p->iommu.page_table_map_base = 0x80000000; + control |= PSYCHO_IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } + psycho_write(p->controller_regs + PSYCHO_IOMMU_CONTROL, control); + + /* If necessary, hook us up for starfire IRQ translations. */ + if(this_is_starfire) + p->starfire_cookie = starfire_hookup(p->portid); + else + p->starfire_cookie = NULL; +} + +#define PSYCHO_IRQ_RETRY 0x1a00UL +#define PSYCHO_PCIA_DIAG 0x2020UL +#define PSYCHO_PCIB_DIAG 0x4020UL +#define PSYCHO_PCIDIAG_RESV 0xffffffffffffff80 /* Reserved */ +#define PSYCHO_PCIDIAG_DRETRY 0x0000000000000040 /* Disable retry limit */ +#define PSYCHO_PCIDIAG_DISYNC 0x0000000000000020 /* Disable DMA wr / irq sync */ +#define PSYCHO_PCIDIAG_DDWSYNC 0x0000000000000010 /* Disable DMA wr / PIO rd sync */ +#define PSYCHO_PCIDIAG_IDDPAR 0x0000000000000008 /* Invert DMA data parity */ +#define PSYCHO_PCIDIAG_IPDPAR 0x0000000000000004 /* Invert PIO data parity */ +#define PSYCHO_PCIDIAG_IPAPAR 0x0000000000000002 /* Invert PIO address parity */ +#define PSYCHO_PCIDIAG_LPBACK 0x0000000000000001 /* Enable loopback mode */ + +static void psycho_controller_hwinit(struct pci_controller_info *p) +{ + u64 tmp; + + /* PROM sets the IRQ retry value too low, increase it. */ + psycho_write(p->controller_regs + PSYCHO_IRQ_RETRY, 0xff); + + /* Enable arbiter for all PCI slots. */ + tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_CTRL); + tmp |= PSYCHO_PCICTRL_AEN; + psycho_write(p->controller_regs + PSYCHO_PCIA_CTRL, tmp); + + tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_CTRL); + tmp |= PSYCHO_PCICTRL_AEN; + psycho_write(p->controller_regs + PSYCHO_PCIB_CTRL, tmp); + + /* Disable DMA write / PIO read synchronization on + * both PCI bus segments. + * [ U2P Erratum 1243770, STP2223BGA data sheet ] + */ + tmp = psycho_read(p->controller_regs + PSYCHO_PCIA_DIAG); + tmp |= PSYCHO_PCIDIAG_DDWSYNC; + psycho_write(p->controller_regs + PSYCHO_PCIA_DIAG, tmp); + + tmp = psycho_read(p->controller_regs + PSYCHO_PCIB_DIAG); + tmp |= PSYCHO_PCIDIAG_DDWSYNC; + psycho_write(p->controller_regs + PSYCHO_PCIB_DIAG, tmp); +} + +static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + + sprintf(name, "PSYCHO%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + request_resource(&ioport_resource, &pbm->io_space); + request_resource(&iomem_resource, &pbm->mem_space); +} + +static void psycho_pbm_strbuf_init(struct pci_controller_info *p, + struct pci_pbm_info *pbm, + int is_pbm_a) +{ + unsigned long base = p->controller_regs; + + /* Currently we don't even use it. */ + pbm->stc.strbuf_enabled = 0; + + /* PSYCHO's streaming buffer lacks ctx flushing. */ + pbm->stc.strbuf_has_ctx_flush = 0; + + if (is_pbm_a) { + pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; + pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; + pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; + } else { + pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; + pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; + pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; + } + pbm->stc.strbuf_ctxflush = 0; + pbm->stc.strbuf_ctxmatch_base = 0; + + pbm->stc.strbuf_flushflag = (volatile unsigned long *) + ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + + 63UL) + & ~63UL); + pbm->stc.strbuf_flushflag_pa = (unsigned long) + __pa(pbm->stc.strbuf_flushflag); + +#if 0 + /* And when we do enable it, these are the sorts of things + * we'll do. + */ + control = psycho_read(pbm->stc.strbuf_control); + control |= PSYCHO_SBUFCTRL_SB_EN; + psycho_write(pbm->stc.strbuf_control, control); +#endif +} + +#define PSYCHO_IOSPACE_A 0x002000000UL +#define PSYCHO_IOSPACE_B 0x002010000UL +#define PSYCHO_IOSPACE_SIZE 0x00000ffffUL +#define PSYCHO_MEMSPACE_A 0x100000000UL +#define PSYCHO_MEMSPACE_B 0x180000000UL +#define PSYCHO_MEMSPACE_SIZE 0x07fffffffUL + +static void psycho_pbm_init(struct pci_controller_info *p, + int prom_node, int is_pbm_a) +{ + unsigned int busrange[2]; + struct pci_pbm_info *pbm; + int err; + + if (is_pbm_a) { + pbm = &p->pbm_A; + pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_A; + pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_A; + } else { + pbm = &p->pbm_B; + pbm->io_space.start = p->controller_regs + PSYCHO_IOSPACE_B; + pbm->mem_space.start = p->controller_regs + PSYCHO_MEMSPACE_B; + } + pbm->io_space.end = pbm->io_space.start + PSYCHO_IOSPACE_SIZE; + pbm->io_space.flags = IORESOURCE_IO; + pbm->mem_space.end = pbm->mem_space.start + PSYCHO_MEMSPACE_SIZE; + pbm->mem_space.flags = IORESOURCE_MEM; + pbm_register_toplevel_resources(p, pbm); + + pbm->parent = p; + pbm->prom_node = prom_node; + prom_getstring(prom_node, "name", + pbm->prom_name, + sizeof(pbm->prom_name)); + + err = prom_getproperty(prom_node, "ranges", + (char *)pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err != -1) + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + else + pbm->num_pbm_ranges = 0; + + err = prom_getproperty(prom_node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err != -1) { + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(prom_node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == -1) { + prom_printf("PSYCHO-PBM: Fatal error, no " + "interrupt-map-mask.\n"); + prom_halt(); + } + } else { + pbm->num_pbm_intmap = 0; + memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); + } + + err = prom_getproperty(prom_node, "bus-range", + (char *)&busrange[0], + sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("PSYCHO-PBM: Fatal error, no bus-range.\n"); + prom_halt(); + } + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + + psycho_pbm_strbuf_init(p, pbm, is_pbm_a); +} + +#define PSYCHO_CONFIGSPACE 0x001000000UL + +void __init psycho_init(int node) +{ + struct linux_prom64_registers pr_regs[3]; + struct pci_controller_info *p; + unsigned long flags; + u32 upa_portid; + int is_pbm_a, err; + + upa_portid = prom_getintdefault(node, "upa-portid", 0xff); + + spin_lock_irqsave(&pci_controller_lock, flags); + for(p = pci_controller_root; p; p = p->next) { + if (p->portid == upa_portid) { + spin_unlock_irqrestore(&pci_controller_lock, flags); + is_pbm_a = (p->pbm_A.prom_node == 0); + psycho_pbm_init(p, node, is_pbm_a); + return; + } + } + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); + if (!p) { + prom_printf("PSYCHO: Fatal memory allocation error.\n"); + prom_halt(); + } + memset(p, 0, sizeof(*p)); + + spin_lock_irqsave(&pci_controller_lock, flags); + p->next = pci_controller_root; + pci_controller_root = p; + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p->portid = upa_portid; + p->index = pci_num_controllers++; + p->scan_bus = psycho_scan_bus; + p->irq_build = psycho_irq_build; + p->base_address_update = psycho_base_address_update; + p->resource_adjust = psycho_resource_adjust; + p->pci_ops = &psycho_ops; + + err = prom_getproperty(node, "reg", + (char *)&pr_regs[0], + sizeof(pr_regs)); + if (err == 0 || err == -1) { + prom_printf("PSYCHO: Fatal error, no reg property.\n"); + prom_halt(); + } + + p->controller_regs = pr_regs[2].phys_addr; + printk("PCI: Found PSYCHO, control regs at %016lx\n", + p->controller_regs); + + p->config_space = pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE; + printk("PSYCHO: PCI config space at %016lx\n", p->config_space); + + /* + * Psycho's PCI MEM space is mapped to a 2GB aligned area, so + * we need to adjust our MEM space mask. + */ + pci_memspace_mask = 0x7fffffffUL; + + psycho_controller_hwinit(p); + + psycho_iommu_init(p, 32); + + is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); + psycho_pbm_init(p, node, is_pbm_a); +} diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c new file mode 100644 index 000000000..46a9b31cf --- /dev/null +++ b/arch/sparc64/kernel/pci_sabre.c @@ -0,0 +1,1487 @@ +/* $Id: pci_sabre.c,v 1.2 1999/09/05 04:58:06 davem Exp $ + * pci_sabre.c: Sabre specific PCI controller support. + * + * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/malloc.h> + +#include <asm/apb.h> +#include <asm/pbm.h> +#include <asm/iommu.h> +#include <asm/irq.h> + +#include "pci_impl.h" + +/* All SABRE registers are 64-bits. The following accessor + * routines are how they are accessed. The REG parameter + * is a physical address. + */ +#define sabre_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define sabre_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* SABRE PCI controller register offsets and definitions. */ +#define SABRE_UE_AFSR 0x0030UL +#define SABRE_UEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */ +#define SABRE_UEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */ +#define SABRE_UEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */ +#define SABRE_UEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */ +#define SABRE_UEAFSR_SDTE 0x0200000000000000UL /* Secondary DMA Translation Error */ +#define SABRE_UEAFSR_PDTE 0x0100000000000000UL /* Primary DMA Translation Error */ +#define SABRE_UEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */ +#define SABRE_UEAFSR_OFF 0x00000000e0000000UL /* Offset (AFAR bits [5:3] */ +#define SABRE_UEAFSR_BLK 0x0000000000800000UL /* Was block operation */ +#define SABRE_UECE_AFAR 0x0038UL +#define SABRE_CE_AFSR 0x0040UL +#define SABRE_CEAFSR_PDRD 0x4000000000000000UL /* Primary PCI DMA Read */ +#define SABRE_CEAFSR_PDWR 0x2000000000000000UL /* Primary PCI DMA Write */ +#define SABRE_CEAFSR_SDRD 0x0800000000000000UL /* Secondary PCI DMA Read */ +#define SABRE_CEAFSR_SDWR 0x0400000000000000UL /* Secondary PCI DMA Write */ +#define SABRE_CEAFSR_ESYND 0x00ff000000000000UL /* ECC Syndrome */ +#define SABRE_CEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask */ +#define SABRE_CEAFSR_OFF 0x00000000e0000000UL /* Offset */ +#define SABRE_CEAFSR_BLK 0x0000000000800000UL /* Was block operation */ +#define SABRE_UECE_AFAR_ALIAS 0x0048UL /* Aliases to 0x0038 */ +#define SABRE_IOMMU_CONTROL 0x0200UL +#define SABRE_IOMMUCTRL_ERRSTS 0x0000000006000000UL /* Error status bits */ +#define SABRE_IOMMUCTRL_ERR 0x0000000001000000UL /* Error present in IOTLB */ +#define SABRE_IOMMUCTRL_LCKEN 0x0000000000800000UL /* IOTLB lock enable */ +#define SABRE_IOMMUCTRL_LCKPTR 0x0000000000780000UL /* IOTLB lock pointer */ +#define SABRE_IOMMUCTRL_TSBSZ 0x0000000000070000UL /* TSB Size */ +#define SABRE_IOMMUCTRL_TBWSZ 0x0000000000000004UL /* TSB assumed page size */ +#define SABRE_IOMMUCTRL_DENAB 0x0000000000000002UL /* Diagnostic Mode Enable */ +#define SABRE_IOMMUCTRL_ENAB 0x0000000000000001UL /* IOMMU Enable */ +#define SABRE_IOMMU_TSBBASE 0x0208UL +#define SABRE_IOMMU_FLUSH 0x0210UL +#define SABRE_IMAP_A_SLOT0 0x0c00UL +#define SABRE_IMAP_B_SLOT0 0x0c20UL +#define SABRE_IMAP_SCSI 0x1000UL +#define SABRE_IMAP_ETH 0x1008UL +#define SABRE_IMAP_BPP 0x1010UL +#define SABRE_IMAP_AU_REC 0x1018UL +#define SABRE_IMAP_AU_PLAY 0x1020UL +#define SABRE_IMAP_PFAIL 0x1028UL +#define SABRE_IMAP_KMS 0x1030UL +#define SABRE_IMAP_FLPY 0x1038UL +#define SABRE_IMAP_SHW 0x1040UL +#define SABRE_IMAP_KBD 0x1048UL +#define SABRE_IMAP_MS 0x1050UL +#define SABRE_IMAP_SER 0x1058UL +#define SABRE_IMAP_UE 0x1070UL +#define SABRE_IMAP_CE 0x1078UL +#define SABRE_IMAP_PCIERR 0x1080UL +#define SABRE_IMAP_GFX 0x1098UL +#define SABRE_IMAP_EUPA 0x10a0UL +#define SABRE_ICLR_A_SLOT0 0x1400UL +#define SABRE_ICLR_B_SLOT0 0x1480UL +#define SABRE_ICLR_SCSI 0x1800UL +#define SABRE_ICLR_ETH 0x1808UL +#define SABRE_ICLR_BPP 0x1810UL +#define SABRE_ICLR_AU_REC 0x1818UL +#define SABRE_ICLR_AU_PLAY 0x1820UL +#define SABRE_ICLR_PFAIL 0x1828UL +#define SABRE_ICLR_KMS 0x1830UL +#define SABRE_ICLR_FLPY 0x1838UL +#define SABRE_ICLR_SHW 0x1840UL +#define SABRE_ICLR_KBD 0x1848UL +#define SABRE_ICLR_MS 0x1850UL +#define SABRE_ICLR_SER 0x1858UL +#define SABRE_ICLR_UE 0x1870UL +#define SABRE_ICLR_CE 0x1878UL +#define SABRE_ICLR_PCIERR 0x1880UL +#define SABRE_WRSYNC 0x1c20UL +#define SABRE_PCICTRL 0x2000UL +#define SABRE_PCICTRL_MRLEN 0x0000001000000000UL /* Use MemoryReadLine for block loads/stores */ +#define SABRE_PCICTRL_SERR 0x0000000400000000UL /* Set when SERR asserted on PCI bus */ +#define SABRE_PCICTRL_ARBPARK 0x0000000000200000UL /* Bus Parking 0=Ultra-IIi 1=prev-bus-owner */ +#define SABRE_PCICTRL_CPUPRIO 0x0000000000100000UL /* Ultra-IIi granted every other bus cycle */ +#define SABRE_PCICTRL_ARBPRIO 0x00000000000f0000UL /* Slot which is granted every other bus cycle */ +#define SABRE_PCICTRL_ERREN 0x0000000000000100UL /* PCI Error Interrupt Enable */ +#define SABRE_PCICTRL_RTRYWE 0x0000000000000080UL /* DMA Flow Control 0=wait-if-possible 1=retry */ +#define SABRE_PCICTRL_AEN 0x000000000000000fUL /* Slot PCI arbitration enables */ +#define SABRE_PIOAFSR 0x2010UL +#define SABRE_PIOAFSR_PMA 0x8000000000000000UL /* Primary Master Abort */ +#define SABRE_PIOAFSR_PTA 0x4000000000000000UL /* Primary Target Abort */ +#define SABRE_PIOAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */ +#define SABRE_PIOAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */ +#define SABRE_PIOAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort */ +#define SABRE_PIOAFSR_STA 0x0400000000000000UL /* Secondary Target Abort */ +#define SABRE_PIOAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */ +#define SABRE_PIOAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */ +#define SABRE_PIOAFSR_BMSK 0x0000ffff00000000UL /* Byte Mask */ +#define SABRE_PIOAFSR_BLK 0x0000000080000000UL /* Was Block Operation */ +#define SABRE_PIOAFAR 0x2018UL +#define SABRE_PCIDIAG 0x2020UL +#define SABRE_PCIDIAG_DRTRY 0x0000000000000040UL /* Disable PIO Retry Limit */ +#define SABRE_PCIDIAG_IPAPAR 0x0000000000000008UL /* Invert PIO Address Parity */ +#define SABRE_PCIDIAG_IPDPAR 0x0000000000000004UL /* Invert PIO Data Parity */ +#define SABRE_PCIDIAG_IDDPAR 0x0000000000000002UL /* Invert DMA Data Parity */ +#define SABRE_PCIDIAG_ELPBK 0x0000000000000001UL /* Loopback Enable - not supported */ +#define SABRE_PCITASR 0x2028UL +#define SABRE_PCITASR_EF 0x0000000000000080UL /* Respond to 0xe0000000-0xffffffff */ +#define SABRE_PCITASR_CD 0x0000000000000040UL /* Respond to 0xc0000000-0xdfffffff */ +#define SABRE_PCITASR_AB 0x0000000000000020UL /* Respond to 0xa0000000-0xbfffffff */ +#define SABRE_PCITASR_89 0x0000000000000010UL /* Respond to 0x80000000-0x9fffffff */ +#define SABRE_PCITASR_67 0x0000000000000008UL /* Respond to 0x60000000-0x7fffffff */ +#define SABRE_PCITASR_45 0x0000000000000004UL /* Respond to 0x40000000-0x5fffffff */ +#define SABRE_PCITASR_23 0x0000000000000002UL /* Respond to 0x20000000-0x3fffffff */ +#define SABRE_PCITASR_01 0x0000000000000001UL /* Respond to 0x00000000-0x1fffffff */ +#define SABRE_PIOBUF_DIAG 0x5000UL +#define SABRE_DMABUF_DIAGLO 0x5100UL +#define SABRE_DMABUF_DIAGHI 0x51c0UL +#define SABRE_IMAP_GFX_ALIAS 0x6000UL /* Aliases to 0x1098 */ +#define SABRE_IMAP_EUPA_ALIAS 0x8000UL /* Aliases to 0x10a0 */ +#define SABRE_IOMMU_VADIAG 0xa400UL +#define SABRE_IOMMU_TCDIAG 0xa408UL +#define SABRE_IOMMU_TAG 0xa580UL +#define SABRE_IOMMUTAG_ERRSTS 0x0000000001800000UL /* Error status bits */ +#define SABRE_IOMMUTAG_ERR 0x0000000000400000UL /* Error present */ +#define SABRE_IOMMUTAG_WRITE 0x0000000000200000UL /* Page is writable */ +#define SABRE_IOMMUTAG_STREAM 0x0000000000100000UL /* Streamable bit - unused */ +#define SABRE_IOMMUTAG_SIZE 0x0000000000080000UL /* 0=8k 1=16k */ +#define SABRE_IOMMUTAG_VPN 0x000000000007ffffUL /* Virtual Page Number [31:13] */ +#define SABRE_IOMMU_DATA 0xa600UL +#define SABRE_IOMMUDATA_VALID 0x0000000040000000UL /* Valid */ +#define SABRE_IOMMUDATA_USED 0x0000000020000000UL /* Used (for LRU algorithm) */ +#define SABRE_IOMMUDATA_CACHE 0x0000000010000000UL /* Cacheable */ +#define SABRE_IOMMUDATA_PPN 0x00000000001fffffUL /* Physical Page Number [33:13] */ +#define SABRE_PCI_IRQSTATE 0xa800UL +#define SABRE_OBIO_IRQSTATE 0xa808UL +#define SABRE_FFBCFG 0xf000UL +#define SABRE_FFBCFG_SPRQS 0x000000000f000000 /* Slave P_RQST queue size */ +#define SABRE_FFBCFG_ONEREAD 0x0000000000004000 /* Slave supports one outstanding read */ +#define SABRE_MCCTRL0 0xf010UL +#define SABRE_MCCTRL0_RENAB 0x0000000080000000 /* Refresh Enable */ +#define SABRE_MCCTRL0_EENAB 0x0000000010000000 /* Enable all ECC functions */ +#define SABRE_MCCTRL0_11BIT 0x0000000000001000 /* Enable 11-bit column addressing */ +#define SABRE_MCCTRL0_DPP 0x0000000000000f00 /* DIMM Pair Present Bits */ +#define SABRE_MCCTRL0_RINTVL 0x00000000000000ff /* Refresh Interval */ +#define SABRE_MCCTRL1 0xf018UL +#define SABRE_MCCTRL1_AMDC 0x0000000038000000 /* Advance Memdata Clock */ +#define SABRE_MCCTRL1_ARDC 0x0000000007000000 /* Advance DRAM Read Data Clock */ +#define SABRE_MCCTRL1_CSR 0x0000000000e00000 /* CAS to RAS delay for CBR refresh */ +#define SABRE_MCCTRL1_CASRW 0x00000000001c0000 /* CAS length for read/write */ +#define SABRE_MCCTRL1_RCD 0x0000000000038000 /* RAS to CAS delay */ +#define SABRE_MCCTRL1_CP 0x0000000000007000 /* CAS Precharge */ +#define SABRE_MCCTRL1_RP 0x0000000000000e00 /* RAS Precharge */ +#define SABRE_MCCTRL1_RAS 0x00000000000001c0 /* Length of RAS for refresh */ +#define SABRE_MCCTRL1_CASRW2 0x0000000000000038 /* Must be same as CASRW */ +#define SABRE_MCCTRL1_RSC 0x0000000000000007 /* RAS after CAS hold time */ +#define SABRE_RESETCTRL 0xf020UL + +#define SABRE_CONFIGSPACE 0x001000000UL +#define SABRE_IOSPACE 0x002000000UL +#define SABRE_IOSPACE_SIZE 0x00000ffffUL +#define SABRE_MEMSPACE 0x100000000UL +#define SABRE_MEMSPACE_SIZE 0x07fffffffUL + +/* UltraSparc-IIi Programmer's Manual, page 325, PCI + * configuration space address format: + * + * 32 24 23 16 15 11 10 8 7 2 1 0 + * --------------------------------------------------------- + * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | + * --------------------------------------------------------- + */ +#define SABRE_CONFIG_BASE(PBM) \ + ((PBM)->parent->config_space | (1UL << 24)) +#define SABRE_CONFIG_ENCODE(BUS, DEVFN, REG) \ + (((unsigned long)(BUS) << 16) | \ + ((unsigned long)(DEVFN) << 8) | \ + ((unsigned long)(REG))) + +static void *sabre_pci_config_mkaddr(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned int devfn, + int where) +{ + if (!pbm) + return NULL; + return (void *) + (SABRE_CONFIG_BASE(pbm) | + SABRE_CONFIG_ENCODE(bus, devfn, where)); +} + +static int sabre_out_of_range(unsigned char devfn) +{ + return (((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || + ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) || + (PCI_SLOT(devfn) > 1)); +} + +static int __sabre_out_of_range(struct pci_pbm_info *pbm, + unsigned char bus, + unsigned char devfn) +{ + return ((pbm->parent == 0) || + ((pbm == &pbm->parent->pbm_B) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8) || + ((pbm == &pbm->parent->pbm_A) && + (bus == pbm->pci_first_busno) && + PCI_SLOT(devfn) > 8)); +} + +static int __sabre_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + *value = 0xff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_read8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_read_word(struct pci_dev *dev, int where, u16 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + *value = 0xffff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_read_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + *value = 0xffffffff; + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_read_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_read32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int sabre_read_byte(struct pci_dev *dev, int where, u8 *value) +{ + if (dev->bus->number) + return __sabre_read_byte(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xff; + return PCIBIOS_SUCCESSFUL; + } + + if (where < 8) { + u16 tmp; + + __sabre_read_word(dev, where & ~1, &tmp); + if (where & 1) + *value = tmp >> 8; + else + *value = tmp & 0xff; + return PCIBIOS_SUCCESSFUL; + } else + return __sabre_read_byte(dev, where, value); +} + +static int sabre_read_word(struct pci_dev *dev, int where, u16 *value) +{ + if (dev->bus->number) + return __sabre_read_word(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xffff; + return PCIBIOS_SUCCESSFUL; + } + + if (where < 8) + return __sabre_read_word(dev, where, value); + else { + u8 tmp; + + __sabre_read_byte(dev, where, &tmp); + *value = tmp; + __sabre_read_byte(dev, where + 1, &tmp); + *value |= tmp << 8; + return PCIBIOS_SUCCESSFUL; + } +} + +static int sabre_read_dword(struct pci_dev *dev, int where, u32 *value) +{ + u16 tmp; + + if (dev->bus->number) + return __sabre_read_dword(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) { + *value = 0xffffffff; + return PCIBIOS_SUCCESSFUL; + } + + sabre_read_word(dev, where, &tmp); + *value = tmp; + sabre_read_word(dev, where + 2, &tmp); + *value |= tmp << 16; + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_byte(struct pci_dev *dev, int where, u8 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u8 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + pci_config_write8(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_word(struct pci_dev *dev, int where, u16 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u16 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x01) { + printk("pcibios_write_config_word: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write16(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int __sabre_write_dword(struct pci_dev *dev, int where, u32 value) +{ + struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number]; + unsigned char bus = dev->bus->number; + unsigned int devfn = dev->devfn; + u32 *addr; + + addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + if (__sabre_out_of_range(pbm, bus, devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where & 0x03) { + printk("pcibios_write_config_dword: misaligned reg [%x]\n", + where); + return PCIBIOS_SUCCESSFUL; + } + pci_config_write32(addr, value); + return PCIBIOS_SUCCESSFUL; +} + +static int sabre_write_byte(struct pci_dev *dev, int where, u8 value) +{ + if (dev->bus->number) + return __sabre_write_byte(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where < 8) { + u16 tmp; + + __sabre_read_word(dev, where & ~1, &tmp); + if (where & 1) { + value &= 0x00ff; + value |= tmp << 8; + } else { + value &= 0xff00; + value |= tmp; + } + return __sabre_write_word(dev, where & ~1, tmp); + } else + return __sabre_write_byte(dev, where, value); +} + +static int sabre_write_word(struct pci_dev *dev, int where, u16 value) +{ + if (dev->bus->number) + return __sabre_write_word(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + if (where < 8) + return __sabre_write_word(dev, where, value); + else { + __sabre_write_byte(dev, where, value & 0xff); + __sabre_write_byte(dev, where + 1, value >> 8); + return PCIBIOS_SUCCESSFUL; + } +} + +static int sabre_write_dword(struct pci_dev *dev, int where, u32 value) +{ + if (dev->bus->number) + return __sabre_write_dword(dev, where, value); + + if (sabre_out_of_range(dev->devfn)) + return PCIBIOS_SUCCESSFUL; + + sabre_write_word(dev, where, value & 0xffff); + sabre_write_word(dev, where + 2, value >> 16); + return PCIBIOS_SUCCESSFUL; +} + +static struct pci_ops sabre_ops = { + sabre_read_byte, + sabre_read_word, + sabre_read_dword, + sabre_write_byte, + sabre_write_word, + sabre_write_dword +}; + +static unsigned long sabre_pcislot_imap_offset(unsigned long ino) +{ + unsigned int bus = (ino & 0x10) >> 4; + unsigned int slot = (ino & 0x0c) >> 2; + + if (bus == 0) + return SABRE_IMAP_A_SLOT0 + (slot * 8); + else + return SABRE_IMAP_B_SLOT0 + (slot * 8); +} + +static unsigned long __onboard_imap_off[] = { +/*0x20*/ SABRE_IMAP_SCSI, +/*0x21*/ SABRE_IMAP_ETH, +/*0x22*/ SABRE_IMAP_BPP, +/*0x23*/ SABRE_IMAP_AU_REC, +/*0x24*/ SABRE_IMAP_AU_PLAY, +/*0x25*/ SABRE_IMAP_PFAIL, +/*0x26*/ SABRE_IMAP_KMS, +/*0x27*/ SABRE_IMAP_FLPY, +/*0x28*/ SABRE_IMAP_SHW, +/*0x29*/ SABRE_IMAP_KBD, +/*0x2a*/ SABRE_IMAP_MS, +/*0x2b*/ SABRE_IMAP_SER, +/*0x2c*/ 0 /* reserved */, +/*0x2d*/ 0 /* reserved */, +/*0x2e*/ SABRE_IMAP_UE, +/*0x2f*/ SABRE_IMAP_CE, +/*0x30*/ SABRE_IMAP_PCIERR, +}; +#define SABRE_ONBOARD_IRQ_BASE 0x20 +#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define sabre_onboard_imap_offset(__ino) \ + __onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + +#define sabre_iclr_offset(ino) \ + ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ + (SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3))) + +/* PCI SABRE INO number to Sparc PIL level. */ +static unsigned char sabre_pil_table[] = { +/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D */ +/*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D */ +/*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D */ +/*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D */ +/*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D */ +/*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D */ +/*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D */ +/*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D */ +/*0x20*/3, /* SCSI */ +/*0x21*/5, /* Ethernet */ +/*0x22*/8, /* Parallel Port */ +/*0x23*/13, /* Audio Record */ +/*0x24*/14, /* Audio Playback */ +/*0x25*/15, /* PowerFail */ +/*0x26*/3, /* second SCSI */ +/*0x27*/11, /* Floppy */ +/*0x28*/2, /* Spare Hardware */ +/*0x29*/9, /* Keyboard */ +/*0x2a*/4, /* Mouse */ +/*0x2b*/12, /* Serial */ +/*0x2c*/10, /* Timer 0 */ +/*0x2d*/11, /* Timer 1 */ +/*0x2e*/15, /* Uncorrectable ECC */ +/*0x2f*/15, /* Correctable ECC */ +/*0x30*/15, /* PCI Bus A Error */ +/*0x31*/15, /* PCI Bus B Error */ +/*0x32*/1, /* Power Management */ +}; + +static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino) +{ + int ret; + + ret = sabre_pil_table[ino]; + if (ret == 0 && pdev == NULL) { + ret = 1; + } else if (ret == 0) { + switch ((pdev->class >> 16) & 0x0f) { + case PCI_BASE_CLASS_STORAGE: + ret = 4; + + case PCI_BASE_CLASS_NETWORK: + ret = 6; + + case PCI_BASE_CLASS_DISPLAY: + ret = 9; + + case PCI_BASE_CLASS_MULTIMEDIA: + case PCI_BASE_CLASS_MEMORY: + case PCI_BASE_CLASS_BRIDGE: + ret = 10; + + default: + ret = 1; + }; + } + return ret; +} + +static unsigned int __init sabre_irq_build(struct pci_controller_info *p, + struct pci_dev *pdev, + unsigned int ino) +{ + struct ino_bucket *bucket; + volatile unsigned int *imap, *iclr; + unsigned long imap_off, iclr_off; + int pil, inofixup = 0; + + ino &= PCI_IRQ_INO; + if (ino < SABRE_ONBOARD_IRQ_BASE) { + /* PCI slot */ + imap_off = sabre_pcislot_imap_offset(ino); + } else { + /* onboard device */ + if (ino > SABRE_ONBOARD_IRQ_LAST) { + prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); + prom_halt(); + } + imap_off = sabre_onboard_imap_offset(ino); + } + + /* Now build the IRQ bucket. */ + pil = sabre_ino_to_pil(pdev, ino); + imap = (volatile unsigned int *)__va(p->controller_regs + imap_off); + imap += 1; + + iclr_off = sabre_iclr_offset(ino); + iclr = (volatile unsigned int *)__va(p->controller_regs + iclr_off); + iclr += 1; + + if ((ino & 0x20) == 0) + inofixup = ino & 0x03; + + bucket = __bucket(build_irq(pil, inofixup, iclr, imap)); + bucket->flags |= IBF_PCI; + + /* XXX We still need to code up support for this in irq.c + * XXX It's easy to code up since only one SIMBA can exist + * XXX in a machine and this is where the sync register is. -DaveM + */ + if (pdev) { + struct pcidev_cookie *pcp = pdev->sysdata; + if (pdev->bus->number != pcp->pbm->pci_first_busno) + bucket->flags |= IBF_DMA_SYNC; + } + return __irq(bucket); +} + +/* SABRE error handling support. */ +static void sabre_check_iommu_error(struct pci_controller_info *p, + unsigned long afsr, + unsigned long afar) +{ + unsigned long iommu_tag[16]; + unsigned long iommu_data[16]; + unsigned long flags; + u64 control; + int i; + + spin_lock_irqsave(&p->iommu.lock, flags); + control = sabre_read(p->iommu.iommu_control); + if (control & SABRE_IOMMUCTRL_ERR) { + char *type_string; + + /* Clear the error encountered bit. + * NOTE: On Sabre this is write 1 to clear, + * which is different from Psycho. + */ + sabre_write(p->iommu.iommu_control, control); + switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("SABRE%d: IOMMU Error, type[%s]\n", + p->index, type_string); + + /* Enter diagnostic mode and probe for error'd + * entries in the IOTLB. + */ + control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR); + sabre_write(p->iommu.iommu_control, + (control | SABRE_IOMMUCTRL_DENAB)); + for (i = 0; i < 16; i++) { + unsigned long base = p->controller_regs; + + iommu_tag[i] = + sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL)); + iommu_data[i] = + sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL)); + sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0); + sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0); + } + sabre_write(p->iommu.iommu_control, control); + + for (i = 0; i < 16; i++) { + unsigned long tag, data; + + tag = iommu_tag[i]; + if (!(tag & SABRE_IOMMUTAG_ERR)) + continue; + + data = iommu_data[i]; + switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) { + case 1: + type_string = "Invalid Error"; + break; + case 3: + type_string = "ECC Error"; + break; + default: + type_string = "Unknown"; + break; + }; + printk("SABRE%d: IOMMU TAG(%d)[error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n", + p->index, i, type_string, + ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0), + ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8), + ((tag & SABRE_IOMMUTAG_VPN) << PAGE_SHIFT)); + printk("SABRE%d: IOMMU DATA(%d)[valid(%d)used(%d)cache(%d)ppg(%016lx)\n", + p->index, i, + ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0), + ((data & SABRE_IOMMUDATA_USED) ? 1 : 0), + ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0), + ((data & SABRE_IOMMUDATA_PPN) << PAGE_SHIFT)); + } + } + spin_unlock_irqrestore(&p->iommu.lock, flags); +} + +static void sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SABRE_UE_AFSR; + unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch uncorrectable error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear the primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | + SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | + SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n", + p->index, + ((error_bits & SABRE_UEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SABRE_UEAFSR_PDWR) ? + "DMA Write" : "???")), + ((error_bits & SABRE_UEAFSR_PDTE) ? + ":Translation Error" : "")); + printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n", + p->index, + (afsr & SABRE_UEAFSR_BMSK) >> 32UL, + (afsr & SABRE_UEAFSR_OFF) >> 29UL, + ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0)); + printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: UE Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_UEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & SABRE_UEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (afsr & SABRE_UEAFSR_SDTE) { + reported++; + printk("(Translation Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* Interrogate IOMMU for error status. */ + sabre_check_iommu_error(p, afsr, afar); +} + +static void sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg = p->controller_regs + SABRE_CE_AFSR; + unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; + unsigned long afsr, afar, error_bits; + int reported; + + /* Latch error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | + SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: Correctable Error, primary error type[%s]\n", + p->index, + ((error_bits & SABRE_CEAFSR_PDRD) ? + "DMA Read" : + ((error_bits & SABRE_CEAFSR_PDWR) ? + "DMA Write" : "???"))); + printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " + "was_block(%d)\n", + p->index, + (afsr & SABRE_CEAFSR_ESYND) >> 48UL, + (afsr & SABRE_CEAFSR_BMSK) >> 32UL, + (afsr & SABRE_CEAFSR_OFF) >> 29UL, + ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0)); + printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: CE Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_CEAFSR_SDRD) { + reported++; + printk("(DMA Read)"); + } + if (afsr & SABRE_CEAFSR_SDWR) { + reported++; + printk("(DMA Write)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); +} + +static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct pci_controller_info *p = dev_id; + unsigned long afsr_reg, afar_reg; + unsigned long afsr, afar, error_bits; + int reported; + + afsr_reg = p->controller_regs + SABRE_PIOAFSR; + afar_reg = p->controller_regs + SABRE_PIOAFAR; + + /* Latch error status. */ + afar = sabre_read(afar_reg); + afsr = sabre_read(afsr_reg); + + /* Clear primary/secondary error status bits. */ + error_bits = afsr & + (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA | + SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR | + SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA | + SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR); + sabre_write(afsr_reg, error_bits); + + /* Log the error. */ + printk("SABRE%d: PCI Error, primary error type[%s]\n", + p->index, + (((error_bits & SABRE_PIOAFSR_PMA) ? + "Master Abort" : + ((error_bits & SABRE_PIOAFSR_PTA) ? + "Target Abort" : + ((error_bits & SABRE_PIOAFSR_PRTRY) ? + "Excessive Retries" : + ((error_bits & SABRE_PIOAFSR_PPERR) ? + "Parity Error" : "???")))))); + printk("SABRE%d: bytemask[%04lx] was_block(%d)\n", + p->index, + (afsr & SABRE_PIOAFSR_BMSK) >> 32UL, + (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0); + printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar); + printk("SABRE%d: PCI Secondary errors [", p->index); + reported = 0; + if (afsr & SABRE_PIOAFSR_SMA) { + reported++; + printk("(Master Abort)"); + } + if (afsr & SABRE_PIOAFSR_STA) { + reported++; + printk("(Target Abort)"); + } + if (afsr & SABRE_PIOAFSR_SRTRY) { + reported++; + printk("(Excessive Retries)"); + } + if (afsr & SABRE_PIOAFSR_SPERR) { + reported++; + printk("(Parity Error)"); + } + if (!reported) + printk("(none)"); + printk("]\n"); + + /* For the error types shown, scan both PCI buses for devices + * which have logged that error type. + */ + + /* If we see a Target Abort, this could be the result of an + * IOMMU translation error of some sort. It is extremely + * useful to log this information as usually it indicates + * a bug in the IOMMU support code or a PCI device driver. + */ + if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { + sabre_check_iommu_error(p, afsr, afar); + pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus); + } + if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) { + pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus); + } + /* For excessive retries, SABRE/PBM will abort the device + * and there is no way to specifically check for excessive + * retries in the config space status registers. So what + * we hope is that we'll catch it via the master/target + * abort events. + */ + + if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) { + pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus); + pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus); + } +} + +/* XXX What about PowerFail/PowerManagement??? -DaveM */ +#define SABRE_UE_INO 0x2e +#define SABRE_CE_INO 0x2f +#define SABRE_PCIERR_INO 0x30 +static void __init sabre_register_error_handlers(struct pci_controller_info *p) +{ + unsigned long base = p->controller_regs; + unsigned long irq, portid = p->portid; + u64 tmp; + + /* We clear the error bits in the appropriate AFSR before + * registering the handler so that we don't get spurious + * interrupts. + */ + sabre_write(base + SABRE_UE_AFSR, + (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | + SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | + SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO); + if (request_irq(irq, sabre_ue_intr, + SA_SHIRQ, "SABRE UE", p) < 0) { + prom_printf("SABRE%d: Cannot register UE interrupt.\n", + p->index); + prom_halt(); + } + + sabre_write(base + SABRE_CE_AFSR, + (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | + SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO); + if (request_irq(irq, sabre_ce_intr, + SA_SHIRQ, "SABRE CE", p) < 0) { + prom_printf("SABRE%d: Cannot register CE interrupt.\n", + p->index); + prom_halt(); + } + + irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO); + if (request_irq(irq, sabre_pcierr_intr, + SA_SHIRQ, "SABRE PCIERR", p) < 0) { + prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", + p->index); + prom_halt(); + } + + tmp = sabre_read(base + SABRE_PCICTRL); + tmp |= SABRE_PCICTRL_ERREN; + sabre_write(base + SABRE_PCICTRL, tmp); +} + +static void __init sabre_resource_adjust(struct pci_dev *pdev, + struct resource *res, + struct resource *root) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_controller_info *p = pcp->pbm->parent; + unsigned long base; + + if (res->flags & IORESOURCE_IO) + base = p->controller_regs + SABRE_IOSPACE; + else + base = p->controller_regs + SABRE_MEMSPACE; + + res->start += base; + res->end += base; +} + +static void __init sabre_base_address_update(struct pci_dev *pdev, int resource) +{ + struct pcidev_cookie *pcp = pdev->sysdata; + struct pci_pbm_info *pbm = pcp->pbm; + struct pci_controller_info *p = pbm->parent; + struct resource *res = &pdev->resource[resource]; + unsigned long base; + u32 reg; + int where, size; + + if (res->flags & IORESOURCE_IO) + base = p->controller_regs + SABRE_IOSPACE; + else + base = p->controller_regs + SABRE_MEMSPACE; + + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(pdev, where, ®); + reg = ((reg & size) | + (((u32)(res->start - base)) & ~size)); + pci_write_config_dword(pdev, where, reg); +} + +static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus) +{ + struct pci_dev *pdev; + u32 dword; + u16 word; + + for(pdev = pci_devices; pdev; pdev = pdev->next) { + if(pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_SABRE) { + sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); + break; + } + } + + for (pdev = sabre_bus->devices; pdev; pdev = pdev->sibling) { + if (pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { + sabre_read_word(pdev, PCI_COMMAND, &word); + word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | + PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | + PCI_COMMAND_IO; + sabre_write_word(pdev, PCI_COMMAND, word); + + /* Status register bits are "write 1 to clear". */ + sabre_write_word(pdev, PCI_STATUS, 0xffff); + sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); + + sabre_read_word(pdev, PCI_BRIDGE_CONTROL, &word); + word = PCI_BRIDGE_CTL_MASTER_ABORT | + PCI_BRIDGE_CTL_SERR | + PCI_BRIDGE_CTL_PARITY; + sabre_write_word(pdev, PCI_BRIDGE_CONTROL, word); + + sabre_read_dword(pdev, APB_PCI_CONTROL_HIGH, &dword); + dword = APB_PCI_CTL_HIGH_SERR | + APB_PCI_CTL_HIGH_ARBITER_EN; + sabre_write_dword(pdev, APB_PCI_CONTROL_HIGH, dword); + + /* Systems with SIMBA are usually workstations, so + * we configure to park to SIMBA not to the previous + * bus owner. + */ + sabre_read_dword(pdev, APB_PCI_CONTROL_LOW, &dword); + dword = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; + sabre_write_dword(pdev, APB_PCI_CONTROL_LOW, dword); + + /* Don't mess with the retry limit and PIO/DMA latency + * timer settings. But do set primary and secondary + * latency timers. + */ + sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); + sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); + } + } +} + +static void __init sabre_scan_bus(struct pci_controller_info *p) +{ + static int once = 0; + struct pci_bus *sabre_bus, *pbus; + + /* Unlike for PSYCHO, we can only have one SABRE + * in a system. Having multiple SABREs is thus + * and error, and as a consequence we do not need + * to do any bus renumbering but we do have to have + * the pci_bus2pbm array setup properly. + * + * Also note that the SABRE host bridge is hardwired + * to live at bus 0. + */ + if (once != 0) { + prom_printf("SABRE: Multiple controllers unsupported.\n"); + prom_halt(); + } + once++; + + /* The pci_bus2pbm table has already been setup in sabre_init. */ + sabre_bus = pci_scan_bus(p->pci_first_busno, + p->pci_ops, + &p->pbm_A); + apb_init(p, sabre_bus); + + for (pbus = sabre_bus->children; pbus; pbus = pbus->next) { + struct pci_pbm_info *pbm; + + if (pbus->number == p->pbm_A.pci_first_busno) { + pbm = &p->pbm_A; + } else if (pbus->number == p->pbm_B.pci_first_busno) { + pbm = &p->pbm_B; + } else + continue; + + pbus->sysdata = pbm; + pbm->pci_bus = pbus; + pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); + pci_record_assignments(pbm, pbus); + pci_assign_unassigned(pbm, pbus); + pci_fixup_irq(pbm, pbus); + } + + sabre_register_error_handlers(p); +} + +static void __init sabre_iommu_init(struct pci_controller_info *p, + int tsbsize, unsigned long dvma_offset) +{ + struct linux_mlist_p1275 *mlist; + unsigned long tsbbase, i, n, order; + iopte_t *iopte; + u64 control; + + /* Invalidate TLB Entries. */ + control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control |= IOMMU_CTRL_DENAB; + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + + for(i = 0; i < 16; i++) + sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); + + control &= ~(IOMMU_CTRL_DENAB); + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); + + for(order = 0;; order++) + if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) + break; + tsbbase = __get_free_pages(GFP_DMA, order); + if (!tsbbase) { + prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); + prom_halt(); + } + iopte = (iopte_t *)tsbbase; + + /* Initialize to "none" settings. */ + for(i = 0; i < PCI_DVMA_HASHSZ; i++) { + pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; + pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; + } + + n = 0; + mlist = *prom_meminfo()->p1275_totphys; + while (mlist) { + unsigned long paddr = mlist->start_adr; + unsigned long num_bytes = mlist->num_bytes; + + if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) + goto next; + + if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) + num_bytes = + (((unsigned long) high_memory) - + PAGE_OFFSET) - paddr; + + /* Align base and length so we map whole hash table sized chunks + * at a time (and therefore full 64K IOMMU pages). + */ + paddr &= ~((1UL << 24UL) - 1); + num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); + + /* Move up the base for mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != + PCI_DVMA_HASH_NONE) { + paddr += (1UL << 24UL); + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Move down the size for tail mappings already created. */ + while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != + PCI_DVMA_HASH_NONE) { + num_bytes -= (1UL << 24UL); + if(num_bytes == 0UL) + goto next; + } + + /* Now map the rest. */ + for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { + iopte_val(*iopte) = ((IOPTE_VALID | IOPTE_64K | + IOPTE_CACHE | IOPTE_WRITE) | + (paddr & IOPTE_PAGE)); + + if (!(n & 0xff)) + set_dvma_hash(dvma_offset, paddr, (n << 16)); + if (++n > (tsbsize * 1024)) + goto out; + + paddr += (1 << 16); + iopte++; + } + next: + mlist = mlist->theres_more; + } +out: + if (mlist) { + prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); + prom_printf("Try booting with mem=xxxM or similar\n"); + prom_halt(); + } + + sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); + + control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); + control &= ~(IOMMU_CTRL_TSBSZ); + control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); + switch(tsbsize) { + case 8: + control |= IOMMU_TSBSZ_8K; + break; + case 16: + control |= IOMMU_TSBSZ_16K; + break; + case 32: + control |= IOMMU_TSBSZ_32K; + break; + default: + prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); + prom_halt(); + break; + } + sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); +} + +static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, + struct pci_pbm_info *pbm) +{ + char *name = pbm->name; + unsigned long ibase = p->controller_regs + SABRE_IOSPACE; + unsigned long mbase = p->controller_regs + SABRE_MEMSPACE; + unsigned int devfn; + unsigned long first, last, i; + u8 *addr, map; + + sprintf(name, "SABRE%d PBM%c", + p->index, + (pbm == &p->pbm_A ? 'A' : 'B')); + pbm->io_space.name = pbm->mem_space.name = name; + + devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1); + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->io_space.start = ibase + (first << 21UL); + pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1); + pbm->io_space.flags = IORESOURCE_IO; + + addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP); + map = 0; + pci_config_read8(addr, &map); + + first = 8; + last = 0; + for (i = 0; i < 8; i++) { + if ((map & (1 << i)) != 0) { + if (first > i) + first = i; + if (last < i) + last = i; + } + } + pbm->mem_space.start = mbase + (first << 29UL); + pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1); + pbm->mem_space.flags = IORESOURCE_MEM; + + if (request_resource(&ioport_resource, &pbm->io_space) < 0) { + prom_printf("Cannot register PBM-%c's IO space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } + if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { + prom_printf("Cannot register PBM-%c's MEM space.\n", + (pbm == &p->pbm_A ? 'A' : 'B')); + prom_halt(); + } +} + +static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node) +{ + char namebuf[128]; + u32 busrange[2]; + int node; + + node = prom_getchild(sabre_node); + while ((node = prom_searchsiblings(node, "pci")) != 0) { + struct pci_pbm_info *pbm; + int err; + + err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); + if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) + goto next_pci; + + err = prom_getproperty(node, "bus-range", + (char *)&busrange[0], sizeof(busrange)); + if (err == 0 || err == -1) { + prom_printf("APB: Error, cannot get PCI bus-range.\n"); + prom_halt(); + } + + if (busrange[0] == 1) + pbm = &p->pbm_B; + else + pbm = &p->pbm_A; + pbm->parent = p; + pbm->prom_node = node; + pbm->pci_first_busno = busrange[0]; + pbm->pci_last_busno = busrange[1]; + for (err = pbm->pci_first_busno; + err <= pbm->pci_last_busno; + err++) + pci_bus2pbm[err] = pbm; + + + prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); + err = prom_getproperty(node, "ranges", + (char *)pbm->pbm_ranges, + sizeof(pbm->pbm_ranges)); + if (err != -1) + pbm->num_pbm_ranges = + (err / sizeof(struct linux_prom_pci_ranges)); + else + pbm->num_pbm_ranges = 0; + + err = prom_getproperty(node, "interrupt-map", + (char *)pbm->pbm_intmap, + sizeof(pbm->pbm_intmap)); + if (err != -1) { + pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); + err = prom_getproperty(node, "interrupt-map-mask", + (char *)&pbm->pbm_intmask, + sizeof(pbm->pbm_intmask)); + if (err == -1) { + prom_printf("APB: Fatal error, no interrupt-map-mask.\n"); + prom_halt(); + } + } else { + pbm->num_pbm_intmap = 0; + memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); + } + + pbm_register_toplevel_resources(p, pbm); + + next_pci: + node = prom_getsibling(node); + if (!node) + break; + } +} + +void __init sabre_init(int pnode) +{ + struct linux_prom64_registers pr_regs[2]; + struct pci_controller_info *p; + unsigned long flags; + int tsbsize, err; + u32 busrange[2]; + u32 vdma[2]; + u32 upa_portid; + int bus; + + p = kmalloc(sizeof(*p), GFP_ATOMIC); + if (!p) { + prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); + prom_halt(); + } + + upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); + + memset(p, 0, sizeof(*p)); + + spin_lock_irqsave(&pci_controller_lock, flags); + p->next = pci_controller_root; + pci_controller_root = p; + spin_unlock_irqrestore(&pci_controller_lock, flags); + + p->portid = upa_portid; + p->index = pci_num_controllers++; + p->scan_bus = sabre_scan_bus; + p->irq_build = sabre_irq_build; + p->base_address_update = sabre_base_address_update; + p->resource_adjust = sabre_resource_adjust; + p->pci_ops = &sabre_ops; + + /* + * Map in SABRE register set and report the presence of this SABRE. + */ + err = prom_getproperty(pnode, "reg", + (char *)&pr_regs[0], sizeof(pr_regs)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get U2P registers " + "from PROM.\n"); + prom_halt(); + } + + /* + * First REG in property is base of entire SABRE register space. + */ + p->controller_regs = pr_regs[0].phys_addr; + printk("PCI: Found SABRE, main regs at %016lx\n", p->controller_regs); + + /* Error interrupts are enabled later after the bus scan. */ + sabre_write(p->controller_regs + SABRE_PCICTRL, + (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | + SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); + + /* Now map in PCI config space for entire SABRE. */ + p->config_space = p->controller_regs + SABRE_CONFIGSPACE; + printk("SABRE: PCI config space at %016lx\n", p->config_space); + + err = prom_getproperty(pnode, "virtual-dma", + (char *)&vdma[0], sizeof(vdma)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get virtual-dma property " + "from PROM.\n"); + prom_halt(); + } + + switch(vdma[1]) { + case 0x20000000: + tsbsize = 8; + break; + case 0x40000000: + tsbsize = 16; + break; + case 0x80000000: + tsbsize = 32; + break; + default: + prom_printf("SABRE: strange virtual-dma size.\n"); + prom_halt(); + } + + sabre_iommu_init(p, tsbsize, vdma[0]); + + printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); + + err = prom_getproperty(pnode, "bus-range", + (char *)&busrange[0], sizeof(busrange)); + if(err == 0 || err == -1) { + prom_printf("SABRE: Error, cannot get PCI bus-range " + " from PROM.\n"); + prom_halt(); + } + + p->pci_first_busno = busrange[0]; + p->pci_last_busno = busrange[1]; + + /* + * Handle config space reads through any Simba on APB. + */ + for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++) + pci_bus2pbm[bus] = &p->pbm_A; + + /* + * Look for APB underneath. + */ + sabre_pbm_init(p, pnode); +} diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c new file mode 100644 index 000000000..831011128 --- /dev/null +++ b/arch/sparc64/kernel/power.c @@ -0,0 +1,105 @@ +/* $Id: power.c,v 1.4 1999/08/31 18:22:05 davem Exp $ + * power.c: Power management driver. + * + * Copyright (C) 1999 David S. Miller (davem@redhat.com) + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/signal.h> +#include <linux/delay.h> + +#include <asm/ebus.h> + +#define __KERNEL_SYSCALLS__ +#include <linux/unistd.h> + +#ifdef CONFIG_PCI +static unsigned long power_reg = 0UL; +#define POWER_SYSTEM_OFF (1 << 0) +#define POWER_COURTESY_OFF (1 << 1) + +static DECLARE_WAIT_QUEUE_HEAD(powerd_wait); +static int button_pressed = 0; + +static void power_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (button_pressed == 0) { + wake_up(&powerd_wait); + button_pressed = 1; + } +} +#endif /* CONFIG_PCI */ + +extern void machine_halt(void); + +void machine_power_off(void) +{ +#ifdef CONFIG_PCI + if (power_reg != 0UL) { + /* Both register bits seem to have the + * same effect, so until I figure out + * what the difference is... + */ + writel(POWER_COURTESY_OFF | POWER_SYSTEM_OFF, power_reg); + } +#endif /* CONFIG_PCI */ + machine_halt(); +} + +#ifdef CONFIG_PCI +static int powerd(void *__unused) +{ + static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + char *argv[] = { "/usr/bin/shutdown", "-h", "now", NULL }; + + current->session = 1; + current->pgrp = 1; + sprintf(current->comm, "powerd"); + +again: + while(button_pressed == 0) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + interruptible_sleep_on(&powerd_wait); + } + + /* Ok, down we go... */ + if (execve("/usr/bin/shutdown", argv, envp) < 0) { + printk("powerd: shutdown execution failed\n"); + button_pressed = 0; + goto again; + } + return 0; +} + +void __init power_init(void) +{ + struct linux_ebus *ebus; + struct linux_ebus_device *edev; + + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "power")) + goto found; + } + } + return; + +found: + power_reg = edev->resource[0].start; + printk("power: Control reg at %016lx ... ", power_reg); + if (kernel_thread(powerd, 0, CLONE_FS) < 0) { + printk("Failed to start power daemon.\n"); + return; + } + printk("powerd running.\n"); + if (request_irq(edev->irqs[0], + power_handler, SA_SHIRQ, "power", + (void *) power_reg) < 0) + printk("power: Error, cannot register IRQ handler.\n"); +} +#endif /* CONFIG_PCI */ diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index ace0c1dc0..0e0f540b7 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.94 1999/05/27 04:49:30 davem Exp $ +/* $Id: process.c,v 1.100 1999/08/31 04:39:39 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -46,7 +46,7 @@ /* * the idle loop on a Sparc... ;) */ -asmlinkage int sys_idle(void) +int cpu_idle(void) { if (current->pid != 0) return -EPERM; @@ -77,7 +77,7 @@ asmlinkage int sys_idle(void) */ #define idle_me_harder() (cpu_data[current->processor].idle_volume += 1) #define unidle_me() (cpu_data[current->processor].idle_volume = 0) -asmlinkage int cpu_idle(void) +int cpu_idle(void) { current->priority = 0; current->counter = -100; @@ -99,15 +99,6 @@ asmlinkage int cpu_idle(void) } } -asmlinkage int sys_idle(void) -{ - if(current->pid != 0) - return -EPERM; - - cpu_idle(); - return 0; -} - #endif extern char reboot_command []; @@ -152,11 +143,6 @@ void machine_restart(char * cmd) panic("Reboot failed!"); } -void machine_power_off(void) -{ - machine_halt(); -} - static void show_regwindow32(struct pt_regs *regs) { struct reg_window32 *rw; @@ -189,7 +175,7 @@ static void show_regwindow(struct pt_regs *regs) struct reg_window r_w; mm_segment_t old_fs; - if ((regs->tstate & TSTATE_PRIV) || !(current->tss.flags & SPARC_FLAG_32BIT)) { + if ((regs->tstate & TSTATE_PRIV) || !(current->thread.flags & SPARC_FLAG_32BIT)) { __asm__ __volatile__ ("flushw"); rw = (struct reg_window *)(regs->u_regs[14] + STACK_BIAS); if (!(regs->tstate & TSTATE_PRIV)) { @@ -369,90 +355,96 @@ void show_regs32(struct pt_regs32 *regs) regs->u_regs[15]); } -void show_thread(struct thread_struct *tss) +void show_thread(struct thread_struct *thread) { int i; #if 0 - printk("kregs: 0x%016lx\n", (unsigned long)tss->kregs); - show_regs(tss->kregs); + printk("kregs: 0x%016lx\n", (unsigned long)thread->kregs); + show_regs(thread->kregs); #endif - printk("sig_address: 0x%016lx\n", tss->sig_address); - printk("sig_desc: 0x%016lx\n", tss->sig_desc); - printk("ksp: 0x%016lx\n", tss->ksp); + printk("sig_address: 0x%016lx\n", thread->sig_address); + printk("sig_desc: 0x%016lx\n", thread->sig_desc); + printk("ksp: 0x%016lx\n", thread->ksp); - if (tss->w_saved) { + if (thread->w_saved) { for (i = 0; i < NSWINS; i++) { - if (!tss->rwbuf_stkptrs[i]) + if (!thread->rwbuf_stkptrs[i]) continue; printk("reg_window[%d]:\n", i); - printk("stack ptr: 0x%016lx\n", tss->rwbuf_stkptrs[i]); + printk("stack ptr: 0x%016lx\n", thread->rwbuf_stkptrs[i]); } - printk("w_saved: 0x%04x\n", tss->w_saved); + printk("w_saved: 0x%04x\n", thread->w_saved); } - printk("flags: 0x%08x\n", tss->flags); - printk("current_ds: 0x%x\n", tss->current_ds.seg); + printk("flags: 0x%08x\n", thread->flags); + printk("current_ds: 0x%x\n", thread->current_ds.seg); } /* Free current thread data structures etc.. */ void exit_thread(void) { - if (current->tss.utraps) { - if (current->tss.utraps[0] < 2) - kfree (current->tss.utraps); + struct thread_struct *t = ¤t->thread; + + if (t->utraps) { + if (t->utraps[0] < 2) + kfree (t->utraps); else - current->tss.utraps[0]--; + t->utraps[0]--; } /* Turn off performance counters if on. */ - if (current->tss.flags & SPARC_FLAG_PERFCTR) { - current->tss.user_cntd0 = - current->tss.user_cntd1 = NULL; - current->tss.pcr_reg = 0; - current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + if (t->flags & SPARC_FLAG_PERFCTR) { + t->user_cntd0 = t->user_cntd1 = NULL; + t->pcr_reg = 0; + t->flags &= ~(SPARC_FLAG_PERFCTR); write_pcr(0); } } void flush_thread(void) { - if (!(current->tss.flags & SPARC_FLAG_KTHREAD)) - flush_user_windows(); - current->tss.w_saved = 0; + struct thread_struct *t = ¤t->thread; + + if (current->mm) { + if (t->flags & SPARC_FLAG_32BIT) { + struct mm_struct *mm = current->mm; + pgd_t *pgd0 = &mm->pgd[0]; + unsigned long pgd_cache; + + if (pgd_none(*pgd0)) { + pmd_t *page = get_pmd_fast(); + if (!page) + (void) get_pmd_slow(pgd0, 0); + else + pgd_set(pgd0, page); + } + pgd_cache = pgd_val(*pgd0) << 11UL; + __asm__ __volatile__("stxa %0, [%1] %2" + : /* no outputs */ + : "r" (pgd_cache), + "r" (TSB_REG), + "i" (ASI_DMMU)); + } + } + t->w_saved = 0; /* Turn off performance counters if on. */ - if (current->tss.flags & SPARC_FLAG_PERFCTR) { - current->tss.user_cntd0 = - current->tss.user_cntd1 = NULL; - current->tss.pcr_reg = 0; - current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + if (t->flags & SPARC_FLAG_PERFCTR) { + t->user_cntd0 = t->user_cntd1 = NULL; + t->pcr_reg = 0; + t->flags &= ~(SPARC_FLAG_PERFCTR); write_pcr(0); } - /* No new signal delivery by default. */ - current->tss.new_signal = 0; - current->tss.fpsaved[0] = 0; + /* Clear FPU register state. */ + t->fpsaved[0] = 0; - /* Now, this task is no longer a kernel thread. */ - current->tss.current_ds = USER_DS; - if(current->tss.flags & SPARC_FLAG_KTHREAD) { - current->tss.flags &= ~SPARC_FLAG_KTHREAD; + if (t->current_ds.seg != ASI_AIUS) + set_fs(USER_DS); - /* exec_mmap() set context to NO_CONTEXT, here is - * where we grab a new one. - */ - activate_context(current); - } - if (current->tss.flags & SPARC_FLAG_32BIT) - __asm__ __volatile__("stxa %%g0, [%0] %1" - : /* no outputs */ - : "r"(TSB_REG), "i"(ASI_DMMU)); - __cli(); - current->tss.ctx = current->mm->context & 0x3ff; - spitfire_set_secondary_context (current->tss.ctx); - __asm__ __volatile__("flush %g6"); - __sti(); + /* Init new signal delivery disposition. */ + t->flags &= ~SPARC_FLAG_NEWSIGNALS; } /* It's a bit more tricky when 64-bit tasks are involved... */ @@ -460,12 +452,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) { unsigned long fp, distance, rval; - /* do_fork() grabs the parent semaphore, we must release it - * temporarily so we can build the child clone stack frame - * without deadlocking. - */ - up(¤t->mm->mmap_sem); - if(!(current->tss.flags & SPARC_FLAG_32BIT)) { + if(!(current->thread.flags & SPARC_FLAG_32BIT)) { csp += STACK_BIAS; psp += STACK_BIAS; __get_user(fp, &(((struct reg_window *)psp)->ins[6])); @@ -482,7 +469,7 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) rval = (csp - distance); if(copy_in_user(rval, psp, distance)) rval = 0; - else if(current->tss.flags & SPARC_FLAG_32BIT) { + else if(current->thread.flags & SPARC_FLAG_32BIT) { if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) rval = 0; } else { @@ -492,47 +479,46 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) else rval = rval - STACK_BIAS; } - down(¤t->mm->mmap_sem); return rval; } /* Standard stuff. */ static inline void shift_window_buffer(int first_win, int last_win, - struct thread_struct *tp) + struct thread_struct *t) { int i; for(i = first_win; i < last_win; i++) { - tp->rwbuf_stkptrs[i] = tp->rwbuf_stkptrs[i+1]; - memcpy(&tp->reg_window[i], &tp->reg_window[i+1], + t->rwbuf_stkptrs[i] = t->rwbuf_stkptrs[i+1]; + memcpy(&t->reg_window[i], &t->reg_window[i+1], sizeof(struct reg_window)); } } void synchronize_user_stack(void) { - struct thread_struct *tp = ¤t->tss; + struct thread_struct *t = ¤t->thread; unsigned long window; flush_user_windows(); - if((window = tp->w_saved) != 0) { + if((window = t->w_saved) != 0) { int winsize = REGWIN_SZ; int bias = 0; - if(tp->flags & SPARC_FLAG_32BIT) + if(t->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; else bias = STACK_BIAS; window -= 1; do { - unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); - struct reg_window *rwin = &tp->reg_window[window]; + unsigned long sp = (t->rwbuf_stkptrs[window] + bias); + struct reg_window *rwin = &t->reg_window[window]; if(!copy_to_user((char *)sp, rwin, winsize)) { - shift_window_buffer(window, tp->w_saved - 1, tp); - tp->w_saved--; + shift_window_buffer(window, t->w_saved - 1, t); + t->w_saved--; } } while(window--); } @@ -540,28 +526,28 @@ void synchronize_user_stack(void) void fault_in_user_windows(struct pt_regs *regs) { - struct thread_struct *tp = ¤t->tss; + struct thread_struct *t = ¤t->thread; unsigned long window; int winsize = REGWIN_SZ; int bias = 0; - if(tp->flags & SPARC_FLAG_32BIT) + if(t->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; else bias = STACK_BIAS; flush_user_windows(); - window = tp->w_saved; + window = t->w_saved; if(window != 0) { window -= 1; do { - unsigned long sp = (tp->rwbuf_stkptrs[window] + bias); - struct reg_window *rwin = &tp->reg_window[window]; + unsigned long sp = (t->rwbuf_stkptrs[window] + bias); + struct reg_window *rwin = &t->reg_window[window]; if(copy_to_user((char *)sp, rwin, winsize)) goto barf; } while(window--); } - current->tss.w_saved = 0; + t->w_saved = 0; return; barf: do_exit(SIGILL); @@ -582,65 +568,73 @@ barf: int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct *p, struct pt_regs *regs) { + struct thread_struct *t = &p->thread; char *child_trap_frame; /* Calculate offset to stack_frame & pt_regs */ child_trap_frame = ((char *)p) + ((PAGE_SIZE << 1) - (TRACEREG_SZ+REGWIN_SZ)); memcpy(child_trap_frame, (((struct reg_window *)regs)-1), (TRACEREG_SZ+REGWIN_SZ)); - p->tss.ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; - p->tss.kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); - p->tss.cwp = (regs->tstate + 1) & TSTATE_CWP; - p->tss.fpsaved[0] = 0; - p->mm->segments = (void *) 0; + t->ksp = ((unsigned long) child_trap_frame) - STACK_BIAS; + t->flags |= SPARC_FLAG_NEWCHILD; + t->kregs = (struct pt_regs *)(child_trap_frame+sizeof(struct reg_window)); + t->cwp = (regs->tstate + 1) & TSTATE_CWP; + t->fpsaved[0] = 0; if(regs->tstate & TSTATE_PRIV) { /* Special case, if we are spawning a kernel thread from * a userspace task (via KMOD, NFS, or similar) we must * disable performance counters in the child because the * address space and protection realm are changing. */ - if (current->tss.flags & SPARC_FLAG_PERFCTR) { - p->tss.user_cntd0 = - p->tss.user_cntd1 = NULL; - p->tss.pcr_reg = 0; - p->tss.flags &= ~(SPARC_FLAG_PERFCTR); + if (t->flags & SPARC_FLAG_PERFCTR) { + t->user_cntd0 = t->user_cntd1 = NULL; + t->pcr_reg = 0; + t->flags &= ~(SPARC_FLAG_PERFCTR); } - p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; - p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD); - p->tss.current_ds = KERNEL_DS; - p->tss.ctx = 0; - __asm__ __volatile__("flushw"); - memcpy((void *)(p->tss.ksp + STACK_BIAS), + t->kregs->u_regs[UREG_FP] = p->thread.ksp; + t->current_ds = KERNEL_DS; + flush_register_windows(); + memcpy((void *)(t->ksp + STACK_BIAS), (void *)(regs->u_regs[UREG_FP] + STACK_BIAS), sizeof(struct reg_window)); - p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p; + t->kregs->u_regs[UREG_G6] = (unsigned long) p; } else { - if(current->tss.flags & SPARC_FLAG_32BIT) { + if(t->flags & SPARC_FLAG_32BIT) { sp &= 0x00000000ffffffffUL; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; } - p->tss.kregs->u_regs[UREG_FP] = sp; - p->tss.flags = (p->tss.flags & ~SPARC_FLAG_KTHREAD) | - SPARC_FLAG_NEWCHILD; - p->tss.current_ds = USER_DS; - p->tss.ctx = (p->mm->context & 0x3ff); + t->kregs->u_regs[UREG_FP] = sp; + t->current_ds = USER_DS; if (sp != regs->u_regs[UREG_FP]) { unsigned long csp; csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); if(!csp) return -EFAULT; - p->tss.kregs->u_regs[UREG_FP] = csp; + t->kregs->u_regs[UREG_FP] = csp; } - if (p->tss.utraps) - p->tss.utraps[0]++; + if (t->utraps) + t->utraps[0]++; } /* Set the return value for the child. */ - p->tss.kregs->u_regs[UREG_I0] = current->pid; - p->tss.kregs->u_regs[UREG_I1] = 1; + t->kregs->u_regs[UREG_I0] = current->pid; + t->kregs->u_regs[UREG_I1] = 1; /* Set the second return value for the parent. */ regs->u_regs[UREG_I1] = 0; +#if 0 + printk("\ncopy_thread: c(%p[mm(%p:%p)]) p(%p[mm(%p:%p)])\n", + current, current->mm, current->active_mm, + p, p->mm, p->active_mm); + printk("copy_thread: c MM_ctx(%016lx) MM_pgd(%016lx)\n", + (current->mm ? current->mm->context : 0), + (current->mm ? pgd_val(current->mm->pgd[0]) : 0)); + printk("copy_thread: p MM_ctx(%016lx) MM_pgd(%08x)\n", + (p->mm ? p->mm->context : 0), + (p->mm ? pgd_val(p->mm->pgd[0]) : 0)); + printk("copy_thread: c->flags(%x) p->flags(%x) ", + current->thread.flags, p->thread.flags); +#endif return 0; } @@ -703,10 +697,10 @@ void dump_thread(struct pt_regs * regs, struct user * dump) dump->u_dsize &= ~(PAGE_SIZE - 1); first_stack_page = (regs->u_regs[UREG_FP] & ~(PAGE_SIZE - 1)); dump->u_ssize = (TASK_SIZE - first_stack_page) & ~(PAGE_SIZE - 1); - memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->tss.float_regs[0], (sizeof(unsigned long) * 32)); - dump->fpu.fpstatus.fsr = current->tss.fsr; + memcpy(&dump->fpu.fpstatus.fregs.regs[0], ¤t->thread.float_regs[0], (sizeof(unsigned long) * 32)); + dump->fpu.fpstatus.fsr = current->thread.fsr; dump->fpu.fpstatus.flags = dump->fpu.fpstatus.extra = 0; - dump->sigcode = current->tss.sig_desc; + dump->sigcode = current->thread.sig_desc; #endif } @@ -729,9 +723,9 @@ typedef struct { int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) { unsigned long *kfpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); - unsigned long fprs = current->tss.fpsaved[0]; + unsigned long fprs = current->thread.fpsaved[0]; - if ((current->tss.flags & SPARC_FLAG_32BIT) != 0) { + if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { elf_fpregset_t32 *fpregs32 = (elf_fpregset_t32 *)fpregs; if (fprs & FPRS_DL) @@ -745,7 +739,7 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) memset(&fpregs32->pr_q[0], 0, (sizeof(unsigned int) * 64)); if (fprs & FPRS_FEF) { - fpregs32->pr_fsr = (unsigned int) current->tss.xfsr[0]; + fpregs32->pr_fsr = (unsigned int) current->thread.xfsr[0]; fpregs32->pr_en = 1; } else { fpregs32->pr_fsr = 0; @@ -765,8 +759,8 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs) memset(&fpregs->pr_regs[16], 0, sizeof(unsigned int) * 32); if(fprs & FPRS_FEF) { - fpregs->pr_fsr = current->tss.xfsr[0]; - fpregs->pr_gsr = current->tss.gsr[0]; + fpregs->pr_fsr = current->thread.xfsr[0]; + fpregs->pr_gsr = current->thread.gsr[0]; } else { fpregs->pr_fsr = fpregs->pr_gsr = 0; } @@ -784,6 +778,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs) int error, base = 0; char *filename; + /* User register window flush is done by entry.S */ + /* Check for indirect call. */ if(regs->u_regs[UREG_G1] == 0) base = 1; @@ -798,8 +794,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs) putname(filename); if(!error) { fprs_write(0); - current->tss.xfsr[0] = 0; - current->tss.fpsaved[0] = 0; + current->thread.xfsr[0] = 0; + current->thread.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c deleted file mode 100644 index 392ddab55..000000000 --- a/arch/sparc64/kernel/psycho.c +++ /dev/null @@ -1,2619 +0,0 @@ -/* $Id: psycho.c,v 1.86 1999/07/01 10:39:43 davem Exp $ - * psycho.c: Ultra/AX U2P PCI controller support. - * - * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) - * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1999 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/malloc.h> - -#include <asm/ebus.h> -#include <asm/sbus.h> /* for sanity check... */ -#include <asm/irq.h> -#include <asm/io.h> - -#undef PROM_DEBUG -#undef FIXUP_REGS_DEBUG -#undef FIXUP_IRQ_DEBUG -#undef FIXUP_VMA_DEBUG -#undef PCI_COOKIE_DEBUG - -#ifdef PROM_DEBUG -#define dprintf prom_printf -#else -#define dprintf printk -#endif - -unsigned long pci_dvma_offset = 0x00000000UL; -unsigned long pci_dvma_mask = 0xffffffffUL; - -#define PCI_DVMA_HASH_NONE 0xffffffffffffffffUL -unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; -unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; - -#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/pci.h> - -#include <asm/oplib.h> -#include <asm/pbm.h> -#include <asm/apb.h> -#include <asm/uaccess.h> - -#define PSYCHO_REORDER_ONBOARDFIRST 1 - -struct linux_psycho *psycho_root = NULL; -int linux_num_psycho = 0; -static struct linux_pbm_info *bus2pbm[256]; -static int psycho_reorder __initdata = 0; - -static int pbm_read_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value); -static int pbm_read_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value); -static int pbm_read_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value); -static int pbm_write_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value); -static int pbm_write_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value); -static int pbm_write_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value); - -/* 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__ void set_dvma_hash(unsigned long paddr, unsigned long daddr) -{ - unsigned long dvma_addr = pci_dvma_offset + daddr; - unsigned long vaddr = (unsigned long)__va(paddr); - - pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] = dvma_addr - vaddr; - pci_dvma_p2v_hash[pci_dvma_ahashfn(dvma_addr)] = vaddr - dvma_addr; -} - -static void __init psycho_iommu_init(struct linux_psycho *psycho, int tsbsize) -{ - extern int this_is_starfire; - extern void *starfire_hookup(int); - struct linux_mlist_p1275 *mlist; - unsigned long tsbbase; - unsigned long control, i, n; - unsigned long *iopte; - unsigned long order; - - /* - * Invalidate TLB Entries. - */ - control = psycho->psycho_regs->iommu_control; - control |= IOMMU_CTRL_DENAB; - psycho->psycho_regs->iommu_control = control; - for(i = 0; i < 16; i++) { - psycho->psycho_regs->iommu_data[i] = 0; - } - control &= ~(IOMMU_CTRL_DENAB); - psycho->psycho_regs->iommu_control = control; - - for(order = 0;; order++) { - if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) - break; - } - tsbbase = __get_free_pages(GFP_DMA, order); - if (!tsbbase) { - prom_printf("IOMMU: Error, kmalloc(tsb) failed.\n"); - prom_halt(); - } - iopte = (unsigned long *)tsbbase; - - /* Initialize to "none" settings. */ - for(i = 0; i < PCI_DVMA_HASHSZ; i++) { - pci_dvma_v2p_hash[i] = PCI_DVMA_HASH_NONE; - pci_dvma_p2v_hash[i] = PCI_DVMA_HASH_NONE; - } - - n = 0; - mlist = *prom_meminfo()->p1275_totphys; - while (mlist) { - unsigned long paddr = mlist->start_adr; - unsigned long num_bytes = mlist->num_bytes; - - if(paddr >= (((unsigned long) high_memory) - PAGE_OFFSET)) - goto next; - - if((paddr + num_bytes) >= (((unsigned long) high_memory) - PAGE_OFFSET)) - num_bytes = (((unsigned long) high_memory) - PAGE_OFFSET) - paddr; - - /* Align base and length so we map whole hash table sized chunks - * at a time (and therefore full 64K IOMMU pages). - */ - paddr &= ~((1UL << 24UL) - 1); - num_bytes = (num_bytes + ((1UL << 24UL) - 1)) & ~((1UL << 24) - 1); - - /* Move up the base for mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr)] != - PCI_DVMA_HASH_NONE) { - paddr += (1UL << 24UL); - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Move down the size for tail mappings already created. */ - while(pci_dvma_v2p_hash[pci_dvma_ahashfn(paddr + num_bytes - (1UL << 24UL))] != - PCI_DVMA_HASH_NONE) { - num_bytes -= (1UL << 24UL); - if(num_bytes == 0UL) - goto next; - } - - /* Now map the rest. */ - for (i = 0; i < ((num_bytes + ((1 << 16) - 1)) >> 16); i++) { - *iopte = (IOPTE_VALID | IOPTE_64K | - IOPTE_CACHE | IOPTE_WRITE); - *iopte |= paddr; - - if (!(n & 0xff)) - set_dvma_hash(paddr, (n << 16)); - - if (++n > (tsbsize * 1024)) - goto out; - - paddr += (1 << 16); - iopte++; - } - next: - mlist = mlist->theres_more; - } -out: - if (mlist) { - prom_printf("WARNING: not all physical memory mapped in IOMMU\n"); - prom_printf("Try booting with mem=xxxM or similar\n"); - prom_halt(); - } - - psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase); - - control = psycho->psycho_regs->iommu_control; - control &= ~(IOMMU_CTRL_TSBSZ); - control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); - switch(tsbsize) { - case 8: - pci_dvma_mask = 0x1fffffffUL; - control |= IOMMU_TSBSZ_8K; - break; - case 16: - pci_dvma_mask = 0x3fffffffUL; - control |= IOMMU_TSBSZ_16K; - break; - case 32: - pci_dvma_mask = 0x7fffffffUL; - control |= IOMMU_TSBSZ_32K; - break; - default: - prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); - prom_halt(); - break; - } - psycho->psycho_regs->iommu_control = control; - - /* If necessary, hook us up for starfire IRQ translations. */ - if(this_is_starfire) - psycho->starfire_cookie = starfire_hookup(psycho->upa_portid); - else - psycho->starfire_cookie = NULL; -} - -extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); -extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm); - -/* - * Poor man's PCI... - */ -void __init sabre_init(int pnode) -{ - struct linux_prom64_registers pr_regs[2]; - struct linux_psycho *sabre; - unsigned long ctrl; - int tsbsize, node, err; - u32 busrange[2]; - u32 vdma[2]; - u32 portid; - int bus; - - sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); - if (!sabre) { - prom_printf("SABRE: Error, kmalloc(sabre) failed.\n"); - prom_halt(); - } - - portid = prom_getintdefault(pnode, "upa-portid", 0xff); - - memset(sabre, 0, sizeof(*sabre)); - - sabre->next = psycho_root; - psycho_root = sabre; - - sabre->upa_portid = portid; - sabre->index = linux_num_psycho++; - - /* - * Map in SABRE register set and report the presence of this SABRE. - */ - err = prom_getproperty(pnode, "reg", - (char *)&pr_regs[0], sizeof(pr_regs)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get U2P registers " - "from PROM.\n"); - prom_halt(); - } - - /* - * First REG in property is base of entire SABRE register space. - */ - sabre->psycho_regs = - sparc_alloc_io((pr_regs[0].phys_addr & 0xffffffff), - NULL, sizeof(struct psycho_regs), - "SABRE Registers", - (pr_regs[0].phys_addr >> 32), 0); - if(sabre->psycho_regs == NULL) { - prom_printf("SABRE: Error, cannot map SABRE main registers.\n"); - prom_halt(); - } - - printk("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", - sabre->psycho_regs, sabre->psycho_regs->control); -#ifdef PROM_DEBUG - dprintf("PCI: Found SABRE, main regs at %p CTRL[%016lx]\n", - sabre->psycho_regs, sabre->psycho_regs->control); -#endif - - ctrl = sabre->psycho_regs->pci_a_control; - ctrl = (1UL << 36) | (1UL << 34) | (1UL << 21) | (1UL << 8) | 0x0fUL; - sabre->psycho_regs->pci_a_control = ctrl; - - /* Now map in PCI config space for entire SABRE. */ - sabre->pci_config_space = - sparc_alloc_io(((pr_regs[0].phys_addr & 0xffffffff) - + 0x01000000), - NULL, 0x01000000, - "PCI Config Space", - (pr_regs[0].phys_addr >> 32), 0); - if(sabre->pci_config_space == NULL) { - prom_printf("SABRE: Error, cannot map PCI config space.\n"); - prom_halt(); - } - - /* Report some more info. */ - printk("SABRE: PCI config space at %p\n", sabre->pci_config_space); -#ifdef PROM_DEBUG - dprintf("SABRE: PCI config space at %p\n", sabre->pci_config_space); -#endif - - err = prom_getproperty(pnode, "virtual-dma", - (char *)&vdma[0], sizeof(vdma)); - if(err == 0 || err == -1) { - prom_printf("SABRE: Error, cannot get virtual-dma property " - "from PROM.\n"); - prom_halt(); - } - - switch(vdma[1]) { - case 0x20000000: - tsbsize = 8; - break; - case 0x40000000: - tsbsize = 16; - break; - case 0x80000000: - tsbsize = 32; - break; - default: - prom_printf("SABRE: strange virtual-dma size.\n"); - prom_halt(); - } - - pci_dvma_offset = vdma[0]; - psycho_iommu_init(sabre, tsbsize); - - printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); -#ifdef PROM_DEBUG - dprintf("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); -#endif - - err = prom_getproperty(pnode, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("SIMBA: Error, cannot get PCI bus-range " - " from PROM.\n"); - prom_halt(); - } - - sabre->pci_first_busno = busrange[0]; - sabre->pci_last_busno = busrange[1]; - sabre->pci_bus = &pci_root; - - /* - * Handle config space reads through any Simba on APB. - */ - for (bus = sabre->pci_first_busno; bus <= sabre->pci_last_busno; bus++) - bus2pbm[bus] = &sabre->pbm_A; - - /* - * Look for APB underneath. - */ - node = prom_getchild(pnode); - while ((node = prom_searchsiblings(node, "pci"))) { - struct linux_pbm_info *pbm; - char namebuf[128]; - - err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); - if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) - goto next_pci; - - err = prom_getproperty(node, "bus-range", - (char *)&busrange[0], sizeof(busrange)); - if(err == 0 || err == -1) { - prom_printf("SIMBA: Error, cannot get PCI bus-range " - " from PROM.\n"); - prom_halt(); - } - - if (busrange[0] == 1) - pbm = &sabre->pbm_B; - else - pbm = &sabre->pbm_A; - - pbm->parent = sabre; - 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(pnode, pbm); - prom_pbm_intmap_init(node, pbm); - - pbm->pci_first_busno = busrange[0]; - pbm->pci_last_busno = busrange[1]; - memset(&pbm->pci_bus, 0, sizeof(struct pci_bus)); - - for (bus = pbm->pci_first_busno; - bus <= pbm->pci_last_busno; bus++) - bus2pbm[bus] = pbm; - - next_pci: - node = prom_getsibling(node); - if (!node) - break; - } -} - -static __inline__ int -apb_present(struct linux_psycho *psycho) -{ - return psycho->pci_bus ? 1 : 0; -} - -void __init pcibios_init(void) -{ - struct linux_prom64_registers pr_regs[3]; - struct linux_psycho *psycho; - char namebuf[128]; - u32 portid; - int node; - - printk("PCI: Probing for controllers.\n"); -#ifdef PROM_DEBUG - dprintf("PCI: Probing for controllers.\n"); -#endif - - node = prom_getchild(prom_root_node); - while((node = prom_searchsiblings(node, "pci")) != 0) { - struct linux_psycho *search; - struct linux_pbm_info *pbm = NULL; - u32 busrange[2]; - int err, is_pbm_a; - - err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); - if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) { - sabre_init(node); - goto next_pci; - } - - 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; - } - } - - psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); - if (!psycho) { - prom_printf("PSYCHO: Error, kmalloc(psycho) failed.\n"); - prom_halt(); - } - memset(psycho, 0, sizeof(*psycho)); - - psycho->next = psycho_root; - psycho_root = psycho; - - psycho->upa_portid = portid; - psycho->index = linux_num_psycho++; - - /* - * 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("PCI: Found PSYCHO, main regs at %p\n", - psycho->psycho_regs); -#ifdef PROM_DEBUG - dprintf("PCI: Found PSYCHO, main regs at %p\n", - psycho->psycho_regs); -#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); -#ifdef PROM_DEBUG - dprintf("PSYCHO: PCI config space at %p\n", - psycho->pci_config_space); -#endif - - pci_dvma_offset = 0x80000000UL; - psycho_iommu_init(psycho, 32); - - is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); - - /* Enable arbitration for all PCI slots. */ - psycho->psycho_regs->pci_a_control |= PSYCHO_PCICTRL_AEN; - psycho->psycho_regs->pci_b_control |= PSYCHO_PCICTRL_AEN; - - /* Disable DMA write / PIO rd synchronization on both - * PCI bus segments. - */ - psycho->psycho_regs->pci_a_diag |= PSYCHO_PCIDIAG_DDWSYNC; - psycho->psycho_regs->pci_b_diag |= PSYCHO_PCIDIAG_DDWSYNC; - - 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); - prom_pbm_intmap_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)); - - next_pci: - node = prom_getsibling(node); - if(!node) - break; - } -} - -int pcibios_present(void) -{ - return psycho_root != NULL; -} - -static inline struct pci_vma *pci_find_vma(struct linux_pbm_info *pbm, - unsigned long start, - unsigned int offset, int io) -{ - struct pci_vma *vp = (io ? pbm->IO_assignments : pbm->MEM_assignments); - - while (vp) { - if (offset && (vp->offset != offset)) - goto next; - if (vp->end >= start) - break; - next: - 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 >= new->start && vp->end < 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 inline struct pci_vma *pci_vma_alloc(void) -{ - return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC); -} - -static inline struct pcidev_cookie *pci_devcookie_alloc(void) -{ - return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); -} - - -static void __init -pbm_reconfigure_bridges(struct linux_pbm_info *pbm, unsigned char bus) -{ - unsigned int devfn, l, class; - unsigned char hdr_type = 0; - int is_multi = 0; - - for (devfn = 0; devfn < 0xff; ++devfn) { - if (PCI_FUNC(devfn) != 0 && is_multi == 0) { - /* not a multi-function device */ - continue; - } - pbm_read_config_byte(pbm, bus, devfn, - PCI_HEADER_TYPE, &hdr_type); - if (PCI_FUNC(devfn) == 0) - is_multi = hdr_type & 0x80; - - /* Check if there is anything here. */ - pbm_read_config_dword(pbm, bus, devfn, PCI_VENDOR_ID, &l); - if (l == 0xffffffff || l == 0x00000000 || - l == 0x0000ffff || l == 0xffff0000) { - is_multi = 0; - continue; - } - - /* See if this is a bridge device. */ - pbm_read_config_dword(pbm, bus, devfn, - PCI_CLASS_REVISION, &class); - - if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { - unsigned int buses; - - pbm_read_config_dword(pbm, bus, devfn, - PCI_PRIMARY_BUS, &buses); - - /* - * First reconfigure everything underneath the bridge. - */ - pbm_reconfigure_bridges(pbm, (buses >> 8) & 0xff); - - /* - * Unconfigure this bridges bus numbers, - * pci_scan_bus() will fix this up properly. - */ - buses &= 0xff000000; - pbm_write_config_dword(pbm, bus, devfn, - PCI_PRIMARY_BUS, buses); - } - } -} - -static void __init pbm_fixup_busno(struct linux_pbm_info *pbm, unsigned char bus) -{ - unsigned int nbus; - - /* - * First, reconfigure all bridge devices underneath this pbm. - */ - pbm_reconfigure_bridges(pbm, pbm->pci_first_busno); - - /* - * Now reconfigure the pbm to it's new bus number and set up - * our bus2pbm mapping for this pbm. - */ - nbus = pbm->pci_last_busno - pbm->pci_first_busno; - - pbm_write_config_byte(pbm, pbm->pci_first_busno, 0, 0x40, bus); - - pbm->pci_first_busno = bus; - pbm_write_config_byte(pbm, bus, 0, 0x41, 0xff); - - do { - bus2pbm[bus++] = pbm; - } while (nbus--); -} - -static void __init apb_init(struct linux_psycho *sabre) -{ - struct pci_dev *pdev; - unsigned short stmp; - unsigned int itmp; - -#if 0 - for(pdev = pci_devices; pdev; pdev = pdev->next) { - if(pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SABRE) { - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - break; - } - } -#endif - for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { - if (pdev->vendor == PCI_VENDOR_ID_SUN && - pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { - pci_read_config_word(pdev, PCI_COMMAND, &stmp); - stmp |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | - PCI_COMMAND_IO; - pci_write_config_word(pdev, PCI_COMMAND, stmp); - - /* Status register bits are "write 1 to clear". */ - pci_write_config_word(pdev, PCI_STATUS, 0xffff); - pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); - - pci_read_config_word(pdev, PCI_BRIDGE_CONTROL, &stmp); - stmp = PCI_BRIDGE_CTL_MASTER_ABORT | - PCI_BRIDGE_CTL_SERR | - PCI_BRIDGE_CTL_PARITY; - pci_write_config_word(pdev, PCI_BRIDGE_CONTROL, stmp); - - pci_read_config_dword(pdev, APB_PCI_CONTROL_HIGH, &itmp); - itmp = APB_PCI_CTL_HIGH_SERR | - APB_PCI_CTL_HIGH_ARBITER_EN; - pci_write_config_dword(pdev, APB_PCI_CONTROL_HIGH, itmp); - - /* Systems with SIMBA are usually workstations, so - * we configure to park to SIMBA not to the previous - * bus owner. - */ - pci_read_config_dword(pdev, APB_PCI_CONTROL_LOW, &itmp); - itmp = APB_PCI_CTL_LOW_ERRINT_EN | 0x0f; - pci_write_config_dword(pdev, APB_PCI_CONTROL_LOW, itmp); -#if 0 - /* Don't mess with the retry limit and PIO/DMA latency - * timer settings. But do set primary and secondary - * latency timers. - */ - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); - pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); -#endif - } - } -} - -static void __init sabre_probe(struct linux_psycho *sabre) -{ - struct pci_bus *pbus = sabre->pci_bus; - static unsigned char busno = 0; - - pbus->number = pbus->secondary = busno; - pbus->sysdata = sabre; - - pbus->subordinate = pci_scan_bus(pbus); - busno = pbus->subordinate + 1; - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - if (pbus->number == sabre->pbm_A.pci_first_busno) - memcpy(&sabre->pbm_A.pci_bus, pbus, sizeof(*pbus)); - if (pbus->number == sabre->pbm_B.pci_first_busno) - memcpy(&sabre->pbm_B.pci_bus, pbus, sizeof(*pbus)); - } - - apb_init(sabre); -} - - -static void __init pbm_probe(struct linux_pbm_info *pbm) -{ - static struct pci_bus *pchain = NULL; - struct pci_bus *pbus = &pbm->pci_bus; - static unsigned char busno = 0; - - /* 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 = pbus->secondary = busno; - pbus->sysdata = pbm; - - pbm_fixup_busno(pbm, busno); - - pbus->subordinate = pci_scan_bus(pbus); - - /* - * Set the maximum subordinate bus of this pbm. - */ - pbm->pci_last_busno = pbus->subordinate; - pbm_write_config_byte(pbm, busno, 0, 0x41, pbm->pci_last_busno); - - busno = pbus->subordinate + 1; - - /* - * Fixup the chain of primary PCI busses. - */ - if (pchain) { - pchain->next = &pbm->pci_bus; - pchain = pchain->next; - } else { - pchain = &pci_root; - memcpy(pchain, &pbm->pci_bus, sizeof(pci_root)); - } -} - -static int __init pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - int pnode) -{ - struct linux_prom_pci_registers pregs[PROMREG_MAX]; - int node; - int err; - - node = prom_getchild(pnode); - while (node) { - - 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 __init pdev_cookie_fillin(struct linux_pbm_info *pbm, - struct pci_dev *pdev, int pnode) -{ - struct pcidev_cookie *pcp; - int node; - - node = pdev_to_pnode_sibtraverse(pbm, pdev, pnode); - if(node == 0) - node = -1; - pcp = pci_devcookie_alloc(); - pcp->pbm = pbm; - pcp->prom_node = node; - pdev->sysdata = pcp; -#ifdef PCI_COOKIE_DEBUG - dprintf("pdev_cookie_fillin: pdev [%02x.%02x]: pbm %p, node %x\n", - pdev->bus->number, pdev->devfn, pbm, node); -#endif -} - -static void __init fill_in_pbm_cookies(struct pci_bus *pbus, - struct linux_pbm_info *pbm, - int node) -{ - struct pci_dev *pdev; - - pbus->sysdata = pbm; - -#ifdef PCI_COOKIE_DEBUG - dprintf("fill_in_pbm_cookies: pbus [%02x]: pbm %p\n", - pbus->number, pbm); -#endif - - for(pdev = pbus->devices; pdev; pdev = pdev->sibling) - pdev_cookie_fillin(pbm, pdev, node); - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - struct pcidev_cookie *pcp = pbus->self->sysdata; - fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); - } -} - -static void __init sabre_cookie_fillin(struct linux_psycho *sabre) -{ - struct pci_bus *pbus = sabre->pci_bus; - - for(pbus = pbus->children; pbus; pbus = pbus->next) { - if (pbus->number == sabre->pbm_A.pci_first_busno) - pdev_cookie_fillin(&sabre->pbm_A, pbus->self, - sabre->pbm_A.prom_node); - else if (pbus->number == sabre->pbm_B.pci_first_busno) - pdev_cookie_fillin(&sabre->pbm_B, pbus->self, - sabre->pbm_B.prom_node); - } -} - -/* 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 __init gimme_ebus_assignments(int node, struct linux_prom_pci_registers *aregs) -{ - struct linux_prom_ebus_ranges erng[PROM_PCIRNG_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; - - ap->size_hi = 0; - ap->size_lo = ep->size; - } - return err; -} - -static void __init 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 (err > 0) - pname[err] = 0; -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: %s\n", __FUNCTION__, err > 0 ? pname : "???"); -#endif - if(strcmp(pname, "ebus") == 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_registers)); - } - - 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); - - 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 - 1; - vp->offset = (ap->phys_hi & 0xffffff); - - pci_add_vma(pbm, vp, io); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: BaseReg %02x", pname, breg); - dprintf(" %s vma [%08x,%08x]\n", - io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end); -#endif - } -} - -static void __init 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 inline void record_assignments(struct linux_pbm_info *pbm) -{ - struct pci_vma *vp; - - if (apb_present(pbm->parent)) { - /* - * Disallow anything that is not in our IO/MEM map on SIMBA. - */ - struct pci_bus *pbus = pbm->parent->pci_bus; - struct pci_dev *pdev; - unsigned char map; - int bit; - - for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { - struct pcidev_cookie *pcp = pdev->sysdata; - if (!pcp) - continue; - if (pcp->pbm == pbm) - break; - } - - if (!pdev) { - prom_printf("record_assignments: no pdev for PBM\n"); - prom_halt(); - } - - pci_read_config_byte(pdev, APB_IO_ADDRESS_MAP, &map); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: IO %02x\n", __FUNCTION__, map); -#endif - for (bit = 0; bit < 8; bit++) { - if (!(map & (1 << bit))) { - vp = pci_vma_alloc(); - vp->start = (bit << 21); - vp->end = vp->start + (1 << 21) - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 1); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: IO prealloc vma [%08x,%08x]\n", - __FUNCTION__, vp->start, vp->end); -#endif - } - } - pci_read_config_byte(pdev, APB_MEM_ADDRESS_MAP, &map); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: MEM %02x\n", __FUNCTION__, map); -#endif - for (bit = 0; bit < 8; bit++) { - if (!(map & (1 << bit))) { - vp = pci_vma_alloc(); - vp->start = (bit << 29); - vp->end = vp->start + (1 << 29) - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 0); -#ifdef FIXUP_VMA_DEBUG - dprintf("%s: MEM prealloc vma [%08x,%08x]\n", - __FUNCTION__, vp->start, vp->end); -#endif - } - } - } - - assignment_walk_siblings(pbm, prom_getchild(pbm->prom_node)); - - /* - * Protect ISA IO space from being used. - */ - vp = pci_find_vma(pbm, 0, 0, 1); - if (!vp || 0x400 <= vp->start) { - vp = pci_vma_alloc(); - vp->start = 0; - vp->end = vp->start + 0x400 - 1; - vp->offset = 0; - pci_add_vma(pbm, vp, 1); - } - -#ifdef FIXUP_VMA_DEBUG - dprintf("PROM IO assignments for PBM %s:\n", - pbm == &pbm->parent->pbm_A ? "A" : "B"); - vp = pbm->IO_assignments; - while (vp) { - dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end, - vp->offset ? "Register" : "Unmapped"); - vp = vp->next; - } - dprintf("PROM MEM assignments for PBM %s:\n", - pbm == &pbm->parent->pbm_A ? "A" : "B"); - vp = pbm->MEM_assignments; - while (vp) { - dprintf(" [%08x,%08x] (%s)\n", vp->start, vp->end, - vp->offset ? "Register" : "Unmapped"); - vp = vp->next; - } -#endif -} - -static void __init 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; - unsigned int rtmp; - u64 pci_addr; - - if(bustype == 0) { - /* Config space cookie, nothing to do. */ - if(preg != 0) - printk("%s %02x.%02x [%04x,%04x]: " - "strange, config space not 0\n", - __FUNCTION__, - pdev->bus->number, pdev->devfn, - pdev->vendor, pdev->device); - continue; - } else if(bustype == 3) { - /* XXX add support for this... */ - printk("%s %02x.%02x [%04x,%04x]: " - "Warning, ignoring 64-bit PCI memory space, " - "tell Eddie C. Dost (ecd@skynet.be).\n", - __FUNCTION__, - pdev->bus->number, pdev->devfn, - pdev->vendor, pdev->device); - continue; - } - - bsreg = (pregs[preg].phys_hi & 0xff); - - /* Sanity */ - if((bsreg < PCI_BASE_ADDRESS_0) || - ((bsreg > (PCI_BASE_ADDRESS_5 + 4)) && (bsreg != PCI_ROM_ADDRESS)) || - (bsreg & 3)) { - printk("%s %02x.%02x [%04x:%04x]: " - "Warning, ignoring bogus basereg [%x]\n", - __FUNCTION__, pdev->bus->number, pdev->devfn, - pdev->vendor, pdev->device, bsreg); - printk(" PROM reg: %08x.%08x.%08x %08x.%08x\n", - pregs[preg].phys_hi, pregs[preg].phys_mid, - pregs[preg].phys_lo, pregs[preg].size_hi, - pregs[preg].size_lo); - 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"); - } - if (bsreg == PCI_ROM_ADDRESS) { - pdev->rom_address = (unsigned long)__va(pci_addr); - pdev->rom_address &= ~1UL; - - /* - * Disable access to the ROM. - */ - pci_read_config_dword(pdev, PCI_ROM_ADDRESS, &rtmp); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, rtmp & ~1); - } else - 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) { - unsigned int rtmp, ridx; - unsigned int offset, base; - struct pci_vma *vp; - u64 pci_addr; - int breg; - - for(breg = PCI_BASE_ADDRESS_0; breg <= PCI_BASE_ADDRESS_5; breg += 4) { - int io; - - ridx = ((breg - PCI_BASE_ADDRESS_0) >> 2); - base = (unsigned int)pdev->base_address[ridx]; - - 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)); - offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg; - vp = pci_find_vma(pbm, base, offset, io); - if(!vp || vp->start > base) { - unsigned int size, new_base; - - pci_read_config_dword(pdev, breg, &rtmp); - pci_write_config_dword(pdev, breg, 0xffffffff); - pci_read_config_dword(pdev, breg, &size); - if(io) - size &= ~1; - size = (~(size) + 1); - if(!size) - continue; - - new_base = 0; - for(vp = pci_find_vma(pbm, new_base, 0, 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 - 1; - vp->offset = offset; - - pci_add_vma(pbm, vp, io); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%02x.%02x.%x: BaseReg %02x", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), - breg); - dprintf(" %s vma [%08x,%08x]\n", - io ? "I/O" : breg == PCI_ROM_ADDRESS ? "ROM" : "MEM", vp->start, vp->end); -#endif - rtmp = new_base; - pci_read_config_dword(pdev, breg, &base); - if(io) - rtmp |= (base & ~PCI_BASE_ADDRESS_IO_MASK); - else - rtmp |= (base & ~PCI_BASE_ADDRESS_MEM_MASK); - pci_write_config_dword(pdev, 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; - } - } - } - - /* - * Handle PCI_ROM_ADDRESS. - */ - breg = PCI_ROM_ADDRESS; - base = (unsigned int)pdev->rom_address; - - if(pdev->rom_address > PAGE_OFFSET) - goto rom_address_done; - - base &= PCI_ROM_ADDRESS_MASK; - offset = (pdev->bus->number << 16) | (pdev->devfn << 8) | breg; - vp = pci_find_vma(pbm, base, offset, 0); - if(!vp || vp->start > base) { - unsigned int size, new_base; - - pci_read_config_dword(pdev, breg, &rtmp); - pci_write_config_dword(pdev, breg, 0xffffffff); - pci_read_config_dword(pdev, breg, &size); - size &= ~1; - size = (~(size) + 1); - if(!size) - goto rom_address_done; - - new_base = 0; - for(vp = pci_find_vma(pbm, new_base, 0, 0); ; 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 MEM space.\n"); - prom_halt(); - } - vp = pci_vma_alloc(); - vp->start = new_base; - vp->end = vp->start + size - 1; - vp->offset = offset; - - pci_add_vma(pbm, vp, 0); - -#ifdef FIXUP_VMA_DEBUG - dprintf("%02x.%02x.%x: BaseReg %02x", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn), - breg); - dprintf(" %s vma [%08x,%08x]\n", - "ROM", vp->start, vp->end); -#endif - - rtmp = new_base; - pci_read_config_dword(pdev, breg, &base); - rtmp &= ~(base & ~PCI_ROM_ADDRESS_MASK); - pci_write_config_dword(pdev, 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(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->rom_address = (unsigned long)__va(pci_addr); - pdev->rom_address &= ~(base & ~PCI_ROM_ADDRESS_MASK); - MEM_seen = 1; - } - rom_address_done: - - } - if(IO_seen || MEM_seen) { - unsigned int l; - - pci_read_config_dword(pdev, PCI_COMMAND, &l); -#ifdef FIXUP_REGS_DEBUG - dprintf("["); -#endif - if(IO_seen) { -#ifdef FIXUP_REGS_DEBUG - dprintf("IO "); -#endif - l |= PCI_COMMAND_IO; - } - if(MEM_seen) { -#ifdef FIXUP_REGS_DEBUG - dprintf("MEM"); -#endif - l |= PCI_COMMAND_MEMORY; - } -#ifdef FIXUP_REGS_DEBUG - dprintf("]"); -#endif - pci_write_config_dword(pdev, PCI_COMMAND, l); - } - -#ifdef FIXUP_REGS_DEBUG - dprintf("REG_FIXUP[%04x,%04x]: ", pdev->vendor, pdev->device); - for(preg = 0; preg < 6; preg++) { - if(pdev->base_address[preg] != 0) - dprintf("%d[%016lx] ", preg, pdev->base_address[preg]); - } - dprintf("\n"); -#endif -} - -#define imap_offset(__member) \ - ((unsigned long)(&(((struct psycho_regs *)0)->__member))) - -static unsigned long __init psycho_pcislot_imap_offset(unsigned long ino) -{ - unsigned int bus, slot; - - bus = (ino & 0x10) >> 4; - slot = (ino & 0x0c) >> 2; - - if(bus == 0) { - switch(slot) { - case 0: - return imap_offset(imap_a_slot0); - case 1: - return imap_offset(imap_a_slot1); - case 2: - return imap_offset(imap_a_slot2); - case 3: - default: - return imap_offset(imap_a_slot3); - } - } 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: - default: - return imap_offset(imap_b_slot3); - } - } -} - -/* Exported for EBUS probing layer. */ -unsigned int __init psycho_irq_build(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - unsigned int ino) -{ - unsigned long imap_off; - int need_dma_sync = 0; - - 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 0x2c: - /* Onboard Timer 0 */ - imap_off = imap_offset(imap_tim0); - break; - - case 0x2d: - /* Onboard Timer 1 */ - imap_off = imap_offset(imap_tim1); - break; - - case 0x2e: - /* Psycho UE Interrupt */ - imap_off = imap_offset(imap_ue); - break; - - case 0x2f: - /* Psycho CE Interrupt */ - imap_off = imap_offset(imap_ce); - break; - - case 0x30: - /* Psycho PCI A Error Interrupt */ - imap_off = imap_offset(imap_a_err); - break; - - case 0x31: - /* Psycho PCI B Error Interrupt */ - imap_off = imap_offset(imap_b_err); - break; - - case 0x32: - /* Power Management */ - imap_off = imap_offset(imap_pmgmt); - break; - - default: - /* We don't expect anything else. - */ - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - }; - } - imap_off -= imap_offset(imap_a_slot0); - - if (apb_present(pbm->parent) && (pdev->bus->number != pbm->pci_first_busno)) { - need_dma_sync = 1; - } - - return psycho_build_irq(pbm->parent, imap_off, ino, need_dma_sync); -} - -static int __init pbm_intmap_match(struct linux_pbm_info *pbm, - struct pci_dev *pdev, - struct linux_prom_pci_registers *preg, - unsigned int *interrupt) -{ - struct linux_prom_pci_registers ppreg; - unsigned int hi, mid, lo, irq; - int i; - -#ifdef FIXUP_IRQ_DEBUG - dprintf("pbm_intmap_match: "); -#endif - if (!pbm->num_pbm_intmap) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No intmap UPA[%x:%c]\n", - pbm->parent->upa_portid, - (pbm == &pbm->parent->pbm_A) ? 'A' : 'B'); -#endif - return 0; - } - /* - * Underneath a bridge, use register of parent bridge. - */ - if (pdev->bus->number != pbm->pci_first_busno) { - struct pcidev_cookie *pcp; - int node, offset; - char prom_name[64]; - -#ifdef FIXUP_IRQ_DEBUG - dprintf("UnderBridge, "); -#endif - pcp = pdev->bus->self->sysdata; - if (!pcp) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No bus PCP\n"); -#endif - goto out; - } - node = pcp->prom_node; - - i = prom_getproperty(node, "reg", (char*)&ppreg, sizeof(ppreg)); - if(i == 0 || i == -1) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No reg property.\n"); -#endif - goto out; - } - /* - * Did PROM know better and assign an interrupt different - * to #INTA to the device? - We test here for presence of - * FCODE on the card, in this case we assume PROM has set - * correct 'interrupts' property, unless it is quadhme. - */ - pcp = pdev->sysdata; - if (!pcp) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No dev PCP\n"); -#endif - goto out; - } - node = pcp->prom_node; - - offset = prom_getint(node, "fcode-rom-offset"); - prom_getstring(node, "name", prom_name, sizeof(prom_name)); - if (offset == -1 || - !strcmp(prom_name, "SUNW,qfe") || - !strcmp(prom_name, "qfe")) { - /* - * No, use low slot number bits of child as IRQ line. - */ - *interrupt = ((*interrupt - 1 + PCI_SLOT(pdev->devfn)) & 3) + 1; - } - preg = &ppreg; - } - - hi = preg->phys_hi & pbm->pbm_intmask.phys_hi; - mid = preg->phys_mid & pbm->pbm_intmask.phys_mid; - lo = preg->phys_lo & pbm->pbm_intmask.phys_lo; - irq = *interrupt & pbm->pbm_intmask.interrupt; -#ifdef FIXUP_IRQ_DEBUG - dprintf("intmap_match: [%02x.%02x.%x] key: [%08x.%08x.%08x.%08x] ", - pdev->bus->number, pdev->devfn >> 3, pdev->devfn & 7, - hi, mid, lo, irq); -#endif - for (i = 0; i < pbm->num_pbm_intmap; i++) { - if ((pbm->pbm_intmap[i].phys_hi == hi) && - (pbm->pbm_intmap[i].phys_mid == mid) && - (pbm->pbm_intmap[i].phys_lo == lo) && - (pbm->pbm_intmap[i].interrupt == irq)) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("irq: [%08x]", pbm->pbm_intmap[i].cinterrupt); -#endif - *interrupt = pbm->pbm_intmap[i].cinterrupt; - return 1; - } - } - -out: - prom_printf("pbm_intmap_match: bus %02x, devfn %02x: ", - pdev->bus->number, pdev->devfn); - prom_printf("IRQ [%08x.%08x.%08x.%08x] not found in interrupt-map\n", - preg->phys_hi, preg->phys_mid, preg->phys_lo, *interrupt); - prom_halt(); -} - -static void __init fixup_irq(struct pci_dev *pdev, - struct linux_pbm_info *pbm, - struct linux_prom_pci_registers *preg, - int node) -{ - unsigned int prom_irq, portid = pbm->parent->upa_portid; - int err; - -#ifdef FIXUP_IRQ_DEBUG - dprintf("fixup_irq[%04x:%04x]: ", pdev->vendor, pdev->device); -#endif - err = prom_getproperty(node, "interrupts", (void *)&prom_irq, sizeof(prom_irq)); - if(err == 0 || err == -1) { -#ifdef FIXUP_IRQ_DEBUG - dprintf("No interrupts property.\n"); -#endif - pdev->irq = 0; - return; - } - - /* 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(pbm, pdev, prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("fully specified prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif - /* See if onboard device interrupt (i.e. bit 5 set) */ - } else if((prom_irq & PSYCHO_IMAP_INO) & 0x20) { - pdev->irq = psycho_irq_build(pbm, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("partially specified prom_irq[%x] pdev->irq[%x]", - prom_irq, pdev->irq); -#endif - /* See if we find a matching interrupt-map entry. */ - } else if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { - pdev->irq = psycho_irq_build(pbm, pdev, - (pbm->parent->upa_portid << 6) - | prom_irq); -#ifdef FIXUP_IRQ_DEBUG - dprintf("interrupt-map 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; - - /* Use the given interrupt property value as the line if it - * is non-zero and legal. Legal encodings are INTA=1, INTB=2, - * INTC=3, INTD=4 as per PCI OBP binding spec version 2.1 -DaveM - */ - if(prom_irq > 0 && prom_irq < 5) { - line = ((prom_irq - 1) & 3); - } else { - unsigned char pci_irq_line; - - /* The generic PCI probing layer will read the - * interrupt line into pdev->irq if the interrupt - * pin is non-zero, so we have to explicitly fetch - * the pin here to be certain (the interrupt line is - * typically left at zero by OBP). - */ - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pci_irq_line); - line = ((pci_irq_line - 1) & 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) - 2; - } else { - /* Underneath a bridge, use slot number of parent - * bridge. - */ - if(pbm == &pbm->parent->pbm_A) - slot = (pdev->bus->self->devfn >> 3) - 1; - else - slot = (pdev->bus->self->devfn >> 3) - 2; - - /* Use low slot number bits of child as IRQ line. */ - line = (pdev->devfn >> 3) & 0x03; - } - slot = (slot << 2); - - pdev->irq = psycho_irq_build(pbm, pdev, - (((portid << 6) & PSYCHO_IMAP_IGN) - | (bus | slot | line))); - -#ifdef FIXUP_IRQ_DEBUG - do { - unsigned char iline, ipin; - - pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &ipin); - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &iline); - dprintf("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 - } - - /* - * Write the INO to config space PCI_INTERRUPT_LINE. - */ - pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, - pdev->irq & PCI_IRQ_INO); - -#ifdef FIXUP_IRQ_DEBUG - dprintf("\n"); -#endif -} - -static void __init 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, &pregs[0], node); -} - -static void __init 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. */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - - /* Now, set cache line size to 64-bytes. - * NOTE: Cache line size is in 32-bit word units. - */ - pci_write_config_byte(pdev, - PCI_CACHE_LINE_SIZE, - (64 / sizeof(u32))); - } - - /* 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)) { - /* - * Prevent access to PCI_ROM_ADDRESS, in case present - * as we don't fixup the address. - */ - if (pdev->rom_address) { - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, 0); - pdev->rom_address = 0; - } - 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); - - /* Enable bus mastering on IDE interfaces. */ - if ((pdev->class >> 8 == PCI_CLASS_STORAGE_IDE) - && (pdev->class & 0x80)) { - unsigned short cmd; - - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(pdev, PCI_COMMAND, cmd); - } -} - -static void __init 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->next) - fixup_pci_bus(pbus, pbm); -} - -static void __init 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 __init psycho_final_fixup(struct linux_psycho *psycho) -{ - /* Second, fixup base address registers and IRQ lines... */ - if (psycho->pbm_A.parent) - fixup_addr_irq(&psycho->pbm_A); - if (psycho->pbm_B.parent) - fixup_addr_irq(&psycho->pbm_B); -} - -/* Reorder the pci_dev chain, so that onboard devices come first - and then come the pluggable cards. */ -void __init psycho_reorder_devs(void) -{ - struct pci_dev **pci_onboard = &pci_devices; - struct pci_dev **pci_tail = &pci_devices; - struct pci_dev *pdev = pci_devices, *pci_other = NULL; - - while (pdev) { - if (pdev->irq && (__irq_ino(pdev->irq) & 0x20)) { - if (pci_other) { - *pci_onboard = pdev; - pci_onboard = &pdev->next; - pdev = pdev->next; - *pci_onboard = pci_other; - *pci_tail = pdev; - continue; - } else - pci_onboard = &pdev->next; - } else if (!pci_other) - pci_other = pdev; - pci_tail = &pdev->next; - pdev = pdev->next; - } -} - -void __init pcibios_fixup(void) -{ - struct linux_psycho *psycho; - - 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. - */ - - for (psycho = psycho_root; psycho; psycho = psycho->next) { - /* Probe bus on builtin PCI. */ - if (apb_present(psycho)) { - sabre_probe(psycho); - } else { - /* Probe busses under PBM B. */ - pbm_probe(&psycho->pbm_B); - - /* Probe busses under PBM A. */ - pbm_probe(&psycho->pbm_A); - } - } - - /* 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). - */ - for (psycho = psycho_root; psycho; psycho = psycho->next) { - if (apb_present(psycho)) - sabre_cookie_fillin(psycho); - - fill_in_pbm_cookies(&psycho->pbm_A.pci_bus, - &psycho->pbm_A, - psycho->pbm_A.prom_node); - fill_in_pbm_cookies(&psycho->pbm_B.pci_bus, - &psycho->pbm_B, - psycho->pbm_B.prom_node); - - /* 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); - } - - if (psycho_reorder & PSYCHO_REORDER_ONBOARDFIRST) - psycho_reorder_devs(); - - return ebus_init(); -} - -/* "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 void * -pci_mkaddr(struct linux_pbm_info *pbm, unsigned char bus, - unsigned char devfn, unsigned char where) -{ - unsigned long ret; - - if (!pbm) - return NULL; - - ret = (unsigned long) pbm->parent->pci_config_space; - - ret |= (1 << 24); - ret |= (bus << 16); - ret |= (devfn << 8); - ret |= where; - - return (void *)ret; -} - -static inline int -out_of_range(struct linux_pbm_info *pbm, unsigned char bus, unsigned char devfn) -{ - return ((pbm->parent == 0) || - ((pbm == &pbm->parent->pbm_B) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || - ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8) || - (pci_probe_enable == 0)); -} - -static inline int -sabre_out_of_range(unsigned char devfn) -{ - return ((PCI_SLOT(devfn) == 0) && (PCI_FUNC(devfn) > 0)) || - ((PCI_SLOT(devfn) == 1) && (PCI_FUNC(devfn) > 1)) || - (PCI_SLOT(devfn) > 1); -} - -static int -sabre_read_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - if (bus) - return pbm_read_config_byte(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xff; - return PCIBIOS_SUCCESSFUL; - } - - if (where < 8) { - unsigned short tmp; - - pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp); - if (where & 1) - *value = tmp >> 8; - else - *value = tmp & 0xff; - return PCIBIOS_SUCCESSFUL; - } else - return pbm_read_config_byte(pbm, bus, devfn, where, value); -} - -static int -sabre_read_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - if (bus) - return pbm_read_config_word(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xffff; - return PCIBIOS_SUCCESSFUL; - } - - if (where < 8) - return pbm_read_config_word(pbm, bus, devfn, where, value); - else { - unsigned char tmp; - - pbm_read_config_byte(pbm, bus, devfn, where, &tmp); - *value = tmp; - pbm_read_config_byte(pbm, bus, devfn, where + 1, &tmp); - *value |= tmp << 8; - return PCIBIOS_SUCCESSFUL; - } -} - -static int -sabre_read_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - unsigned short tmp; - - if (bus) - return pbm_read_config_dword(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) { - *value = 0xffffffff; - return PCIBIOS_SUCCESSFUL; - } - - sabre_read_config_word(pbm, bus, devfn, where, &tmp); - *value = tmp; - sabre_read_config_word(pbm, bus, devfn, where + 2, &tmp); - *value |= tmp << 16; - return PCIBIOS_SUCCESSFUL; -} - -static int -sabre_write_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - if (bus) - return pbm_write_config_byte(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where < 8) { - unsigned short tmp; - - pbm_read_config_word(pbm, bus, devfn, where & ~1, &tmp); - if (where & 1) { - value &= 0x00ff; - value |= tmp << 8; - } else { - value &= 0xff00; - value |= tmp; - } - return pbm_write_config_word(pbm, bus, devfn, where & ~1, tmp); - } else - return pbm_write_config_byte(pbm, bus, devfn, where, value); -} - -static int -sabre_write_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - if (bus) - return pbm_write_config_word(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where < 8) - return pbm_write_config_word(pbm, bus, devfn, where, value); - else { - pbm_write_config_byte(pbm, bus, devfn, where, value & 0xff); - pbm_write_config_byte(pbm, bus, devfn, where + 1, value >> 8); - return PCIBIOS_SUCCESSFUL; - } -} - -static int -sabre_write_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - if (bus) - return pbm_write_config_dword(pbm, bus, devfn, where, value); - - if (sabre_out_of_range(devfn)) - return PCIBIOS_SUCCESSFUL; - - sabre_write_config_word(pbm, bus, devfn, where, value & 0xffff); - sabre_write_config_word(pbm, bus, devfn, where + 2, value >> 16); - return PCIBIOS_SUCCESSFUL; -} - -static int -pbm_read_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); - unsigned int trapped; - unsigned char byte; - - *value = 0xff; - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "lduba [%1] %2, %0\n\t" - "membar #Sync" - : "=r" (byte) - : "r" (addr), "i" (ASI_PL)); - pci_poke_in_progress = 0; - trapped = pci_poke_faulted; - pci_poke_faulted = 0; - if(!trapped) - *value = byte; - return PCIBIOS_SUCCESSFUL; -} - -static int -pbm_read_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); - unsigned int trapped; - unsigned short word; - - *value = 0xffff; - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where & 0x01) { - printk("pcibios_read_config_word: misaligned reg [%x]\n", - where); - return PCIBIOS_SUCCESSFUL; - } - - pci_poke_in_progress = 1; - pci_poke_faulted = 0; - __asm__ __volatile__("membar #Sync\n\t" - "lduha [%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; -} - -static int -pbm_read_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); - unsigned int word, trapped; - - *value = 0xffffffff; - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where & 0x03) { - printk("pcibios_read_config_dword: misaligned reg [%x]\n", - where); - 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; -} - -static int -pbm_write_config_byte(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - unsigned char *addr = pci_mkaddr(pbm, bus, devfn, where); - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - 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; -} - -static int -pbm_write_config_word(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - unsigned short *addr = pci_mkaddr(pbm, bus, devfn, where); - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where & 0x01) { - printk("pcibios_write_config_word: misaligned reg [%x]\n", - where); - 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; -} - -static int -pbm_write_config_dword(struct linux_pbm_info *pbm, - unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - unsigned int *addr = pci_mkaddr(pbm, bus, devfn, where); - - if (!addr) - return PCIBIOS_SUCCESSFUL; - - if (out_of_range(pbm, bus, devfn)) - return PCIBIOS_SUCCESSFUL; - - if (where & 0x03) { - printk("pcibios_write_config_dword: misaligned reg [%x]\n", - where); - 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; -} - -int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_byte(pbm, bus, devfn, where, value); - return pbm_read_config_byte(pbm, bus, devfn, where, value); -} - -int pcibios_read_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_word(pbm, bus, devfn, where, value); - return pbm_read_config_word(pbm, bus, devfn, where, value); -} - -int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int *value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_read_config_dword(pbm, bus, devfn, where, value); - return pbm_read_config_dword(pbm, bus, devfn, where, value); -} - -int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned char value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_byte(pbm, bus, devfn, where, value); - return pbm_write_config_byte(pbm, bus, devfn, where, value); -} - -int pcibios_write_config_word (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned short value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_word(pbm, bus, devfn, where, value); - return pbm_write_config_word(bus2pbm[bus], bus, devfn, where, value); -} - -int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, - unsigned char where, unsigned int value) -{ - struct linux_pbm_info *pbm = bus2pbm[bus]; - - if (pbm && pbm->parent && apb_present(pbm->parent)) - return sabre_write_config_dword(pbm, bus, devfn, where, value); - return pbm_write_config_dword(bus2pbm[bus], bus, devfn, where, value); -} - -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; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - - lock_kernel(); - switch(len) { - case 1: - pcibios_read_config_byte(bus, dfn, off, &ubyte); - put_user(ubyte, (unsigned char *)buf); - break; - case 2: - pcibios_read_config_word(bus, dfn, off, &ushort); - put_user(ushort, (unsigned short *)buf); - break; - case 4: - pcibios_read_config_dword(bus, dfn, off, &uint); - put_user(uint, (unsigned int *)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; - - if(!capable(CAP_SYS_ADMIN)) - return -EPERM; - - 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; -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ -} - -char * __init pcibios_setup(char *str) -{ - if (!strcmp(str, "onboardfirst")) { - psycho_reorder |= PSYCHO_REORDER_ONBOARDFIRST; - return NULL; - } - if (!strcmp(str, "noreorder")) { - psycho_reorder = 0; - return NULL; - } - return str; -} - -#endif diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 61a6a6bfa..c582be060 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -52,7 +52,7 @@ static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) static inline void pt_succ_return_linux(struct pt_regs *regs, unsigned long value, long *addr) { - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { if(put_user(value, (unsigned int *)addr)) return pt_error_return(regs, EFAULT); } else { @@ -114,7 +114,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned long addr2 = regs->u_regs[UREG_I4]; struct task_struct *child; - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { addr &= 0xffffffffUL; data &= 0xffffffffUL; addr2 &= 0xffffffffUL; @@ -220,7 +220,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } - if(!(child->tss.flags & SPARC_FLAG_32BIT) && + if(!(child->thread.flags & SPARC_FLAG_32BIT) && ((request == PTRACE_READDATA64) || (request == PTRACE_WRITEDATA64) || (request == PTRACE_READTEXT64) || @@ -242,7 +242,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) int res, copied; res = -EIO; - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { copied = access_process_vm(child, addr, &tmp32, sizeof(tmp32), 0); tmp64 = (unsigned long) tmp32; @@ -267,7 +267,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int tmp32; int copied, res = -EIO; - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { tmp32 = data; copied = access_process_vm(child, addr, &tmp32, sizeof(tmp32), 1); @@ -289,7 +289,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_GETREGS: { struct pt_regs32 *pregs = (struct pt_regs32 *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; int rval; if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || @@ -313,7 +313,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_GETREGS64: { struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; int rval; if (__put_user(cregs->tstate, (&pregs->tstate)) || @@ -337,7 +337,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_SETREGS: { struct pt_regs32 *pregs = (struct pt_regs32 *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; unsigned int psr, pc, npc, y; int i; @@ -370,7 +370,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) case PTRACE_SETREGS64: { struct pt_regs *pregs = (struct pt_regs *) addr; - struct pt_regs *cregs = child->tss.kregs; + struct pt_regs *cregs = child->thread.kregs; unsigned long tstate, tpc, tnpc, y; int i; @@ -418,7 +418,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (copy_to_user(&fps->regs[0], fpregs, (32 * sizeof(unsigned int))) || - __put_user(child->tss.xfsr[0], (&fps->fsr)) || + __put_user(child->thread.xfsr[0], (&fps->fsr)) || __put_user(0, (&fps->fpqd)) || __put_user(0, (&fps->flags)) || __put_user(0, (&fps->extra)) || @@ -439,7 +439,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (copy_to_user(&fps->regs[0], fpregs, (64 * sizeof(unsigned int))) || - __put_user(child->tss.xfsr[0], (&fps->fsr))) { + __put_user(child->thread.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out; } @@ -468,11 +468,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EFAULT); goto out; } - child->tss.xfsr[0] &= 0xffffffff00000000UL; - child->tss.xfsr[0] |= fsr; - if (!(child->tss.fpsaved[0] & FPRS_FEF)) - child->tss.gsr[0] = 0; - child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL); + child->thread.xfsr[0] &= 0xffffffff00000000UL; + child->thread.xfsr[0] |= fsr; + if (!(child->thread.fpsaved[0] & FPRS_FEF)) + child->thread.gsr[0] = 0; + child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL); pt_succ_return(regs, 0); goto out; } @@ -486,13 +486,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (copy_from_user(fpregs, &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(child->tss.xfsr[0], (&fps->fsr))) { + __get_user(child->thread.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out; } - if (!(child->tss.fpsaved[0] & FPRS_FEF)) - child->tss.gsr[0] = 0; - child->tss.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); + if (!(child->thread.fpsaved[0] & FPRS_FEF)) + child->thread.gsr[0] = 0; + child->thread.fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); pt_succ_return(regs, 0); goto out; } @@ -538,11 +538,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) goto out; } #ifdef DEBUG_PTRACE - printk ("Original: %016lx %016lx\n", child->tss.kregs->tpc, child->tss.kregs->tnpc); + printk ("Original: %016lx %016lx\n", child->thread.kregs->tpc, child->thread.kregs->tnpc); printk ("Continuing with %016lx %016lx\n", addr, addr+4); #endif - child->tss.kregs->tpc = addr; - child->tss.kregs->tnpc = addr + 4; + child->thread.kregs->tpc = addr; + child->thread.kregs->tnpc = addr + 4; } if (request == PTRACE_SYSCALL) @@ -554,8 +554,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) #ifdef DEBUG_PTRACE printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, child->pid, child->exit_code, - child->tss.kregs->tpc, - child->tss.kregs->tnpc); + child->thread.kregs->tpc, + child->thread.kregs->tnpc); #endif wake_up_process(child); @@ -634,7 +634,7 @@ asmlinkage void syscall_trace(void) return; current->exit_code = SIGTRAP; current->state = TASK_STOPPED; - current->tss.flags ^= MAGIC_CONSTANT; + current->thread.flags ^= MAGIC_CONSTANT; notify_parent(current, SIGCHLD); schedule(); /* diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 8444bc966..bb6d7398e 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,4 +1,4 @@ -/* $Id: rtrap.S,v 1.46 1999/05/25 16:53:20 jj Exp $ +/* $Id: rtrap.S,v 1.47 1999/07/30 09:35:23 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -11,6 +11,7 @@ #include <asm/spitfire.h> #include <asm/head.h> #include <asm/visasm.h> +#include <asm/processor.h> #define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) @@ -39,13 +40,13 @@ rtrap: sethi %hi(bh_active), %l2 be,pt %icc, to_user andn %l7, PSTATE_IE, %l7 - ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5 + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %l5 brz,pt %l5, rt_continue srl %l5, 1, %o0 - add %g6, AOFF_task_tss + AOFF_thread_fpsaved, %l6 + add %g6, AOFF_task_thread + AOFF_thread_fpsaved, %l6 ldub [%l6 + %o0], %l2 sub %l5, 2, %l5 - add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1 + add %g6, AOFF_task_thread + AOFF_thread_gsr, %o1 andcc %l2, (FPRS_FEF|FPRS_DU), %g0 be,pt %icc, 2f and %l2, FPRS_DL, %l6 @@ -55,7 +56,7 @@ rtrap: sethi %hi(bh_active), %l2 rd %fprs, %g5 wr %g5, FPRS_FEF, %fprs ldub [%o1 + %o0], %g5 - add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1 + add %g6, AOFF_task_thread + AOFF_thread_xfsr, %o1 membar #StoreLoad | #LoadLoad sll %o0, 8, %o2 add %g6, AOFF_task_fpregs, %o3 @@ -71,9 +72,8 @@ rtrap: sethi %hi(bh_active), %l2 ldda [%o4 + %o2] ASI_BLK_P, %f48 1: membar #Sync ldx [%o1 + %o5], %fsr -2: stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] -rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 - ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1 +2: stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] +rt_continue: 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, %o5 @@ -105,10 +105,11 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 wrpr %o2, %g0, %tnpc brnz,pn %l3, kern_rtt mov PRIMARY_CONTEXT, %l7 + ldxa [%l7 + %l7] ASI_DMMU, %l0 stxa %l0, [%l7] ASI_DMMU flush %o5 - rdpr %wstate, %l1 + rdpr %wstate, %l1 rdpr %otherwin, %l2 srl %l1, 3, %l1 wrpr %l2, %g0, %canrestore @@ -116,8 +117,8 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 wrpr %g0, %g0, %otherwin restore rdpr %canrestore, %g1 - wrpr %g1, 0x0, %cleanwin + wrpr %g1, 0x0, %cleanwin retry kern_rtt: restore retry @@ -125,8 +126,8 @@ to_user: ldx [%g6 + AOFF_task_need_resched], %l0 wrpr %l7, PSTATE_IE, %pstate orcc %g0, %l0, %g0 be,a,pt %xcc, check_signal - lduw [%g6 + AOFF_task_sigpending], %l0 + lduw [%g6 + AOFF_task_sigpending], %l0 call schedule nop lduw [%g6 + AOFF_task_sigpending], %l0 @@ -146,7 +147,7 @@ check_signal: brz,a,pt %l0, check_user_wins */ check_user_wins: wrpr %l7, 0x0, %pstate - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2 brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %l6 @@ -162,8 +163,8 @@ check_user_wins: call rtrap_check add %sp, STACK_BIAS + REGWIN_SZ, %o0 #endif - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l5 - andcc %l5, 0x200, %g0 + ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %l5 + andcc %l5, SPARC_FLAG_PERFCTR, %g0 be,pt %xcc, 1f nop @@ -172,7 +173,7 @@ check_user_wins: call update_perfctrs nop wrpr %l7, 0x0, %pstate - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 + ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %o2 brz,pt %o2, 1f sethi %hi(TSTATE_PEF), %l6 wrpr %l7, PSTATE_IE, %pstate @@ -182,14 +183,14 @@ check_user_wins: 1: andcc %l1, %l6, %g0 be,pt %xcc, rt_continue - stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only + stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] ! This is neccessary for non-syscall rtraps only rd %fprs, %l5 andcc %l5, FPRS_FEF, %g0 be,a,pn %icc, rt_continue andn %l1, %l6, %l1 - ba,pt %xcc, rt_continue+4 - lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 + ba,pt %xcc, rt_continue + nop 5: wr %g0, FPRS_FEF, %fprs membar #StoreLoad | #LoadLoad @@ -201,6 +202,6 @@ check_user_wins: 1: membar #Sync wr %g0, FPRS_DU, %fprs ba,pt %xcc, rt_continue - stb %l5, [%g6 + AOFF_task_tss + AOFF_thread_fpdepth] + stb %l5, [%g6 + AOFF_task_thread + AOFF_thread_fpdepth] #undef PTREGS_OFF diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c new file mode 100644 index 000000000..f72aeedd6 --- /dev/null +++ b/arch/sparc64/kernel/semaphore.c @@ -0,0 +1,129 @@ +/* $Id: semaphore.c,v 1.1 1999/08/30 10:00:50 davem Exp $ + * Generic semaphore code. Buyer beware. Do your own + * specific changes in <asm/semaphore-helper.h> + */ + +#include <linux/sched.h> +#include <asm/semaphore-helper.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index d5e980ebf..066850108 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.44 1999/05/28 02:17:29 davem Exp $ +/* $Id: setup.c,v 1.47 1999/08/31 06:54:55 davem Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -135,17 +135,21 @@ int prom_callback(long *args) * Find process owning ctx, lookup mapping. */ struct task_struct *p; + struct mm_struct *mm = NULL; pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - for_each_task(p) - if (p->tss.ctx == ctx) + for_each_task(p) { + mm = p->mm; + if (CTX_HWBITS(mm->context) == ctx) break; - if (p->tss.ctx != ctx) + } + if (!mm || + CTX_HWBITS(mm->context) != ctx) goto done; - pgdp = pgd_offset(p->mm, va); + pgdp = pgd_offset(mm, va); if (pgd_none(*pgdp)) goto done; pmdp = pmd_offset(pgdp, va); @@ -312,7 +316,7 @@ int obp_system_intr(void) * Process kernel command line switches that are specific to the * SPARC or that require special low-level processing. */ -__initfunc(static void process_switch(char c)) +static void __init process_switch(char c) { switch (c) { case 'd': @@ -331,7 +335,7 @@ __initfunc(static void process_switch(char c)) } } -__initfunc(static void boot_flags_init(char *commands)) +static void __init boot_flags_init(char *commands) { while (*commands) { /* Move to the start of the next "argument". */ @@ -434,8 +438,8 @@ static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; extern struct consw sun_serial_con; -__initfunc(void setup_arch(char **cmdline_p, - unsigned long * memory_start_p, unsigned long * memory_end_p)) +void __init setup_arch(char **cmdline_p, + unsigned long * memory_start_p, unsigned long * memory_end_p) { extern int serial_console; /* in console.c, of course */ unsigned long lowest_paddr, end_of_phys_memory = 0; @@ -531,11 +535,10 @@ __initfunc(void setup_arch(char **cmdline_p, #endif /* Due to stack alignment restrictions and assumptions... */ - init_task.mm->mmap->vm_page_prot = PAGE_SHARED; - init_task.mm->mmap->vm_start = PAGE_OFFSET; - init_task.mm->mmap->vm_end = *memory_end_p; - init_task.mm->context = (unsigned long) NO_CONTEXT; - init_task.tss.kregs = &fake_swapper_regs; + init_mm.mmap->vm_page_prot = PAGE_SHARED; + init_mm.mmap->vm_start = PAGE_OFFSET; + init_mm.mmap->vm_end = *memory_end_p; + init_task.thread.kregs = &fake_swapper_regs; #ifdef CONFIG_IP_PNP if (!ic_set_manually) { diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 247afc77c..672e83493 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.41 1999/06/14 05:23:58 davem Exp $ +/* $Id: signal.c,v 1.45 1999/09/06 08:21:59 jj Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -46,7 +46,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, asmlinkage void sparc64_set_context(struct pt_regs *regs) { struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0]; - struct thread_struct *tp = ¤t->tss; + struct thread_struct *tp = ¤t->thread; mc_gregset_t *grp; unsigned long pc, npc, tstate; unsigned long fp, i7; @@ -123,9 +123,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) err |= copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, (sizeof(unsigned int) * 32)); - err |= __get_user(current->tss.xfsr[0], + err |= __get_user(current->thread.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); - err |= __get_user(current->tss.gsr[0], + err |= __get_user(current->thread.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); regs->tstate &= ~TSTATE_PEF; } @@ -141,7 +141,7 @@ do_sigsegv: asmlinkage void sparc64_get_context(struct pt_regs *regs) { struct ucontext *ucp = (struct ucontext *) regs->u_regs[UREG_I0]; - struct thread_struct *tp = ¤t->tss; + struct thread_struct *tp = ¤t->thread; mc_gregset_t *grp; mcontext_t *mcp; unsigned long fp, i7; @@ -155,7 +155,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) #if 1 fenab = 0; /* IMO get_context is like any other system call, thus modifies FPU state -jj */ #else - fenab = (current->tss.fpsaved[0] & FPRS_FEF); + fenab = (current->thread.fpsaved[0] & FPRS_FEF); #endif mcp = &ucp->uc_mcontext; @@ -205,7 +205,7 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; - fprs = current->tss.fpsaved[0]; + fprs = current->thread.fpsaved[0]; if (fprs & FPRS_DL) err |= copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, (sizeof(unsigned int) * 32)); @@ -213,8 +213,8 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) err |= copy_to_user( ((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16, (sizeof(unsigned int) * 32)); - err |= __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr)); - err |= __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr)); + err |= __put_user(current->thread.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr)); + err |= __put_user(current->thread.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr)); err |= __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs)); } if (err) @@ -226,34 +226,17 @@ do_sigsegv: do_exit(SIGSEGV); } -/* - * The new signal frame, intended to be used for Linux applications only - * (we have enough in there to work with clone). - * All the interesting bits are in the info field. - */ - -struct new_signal_frame { - struct sparc_stackf ss; - __siginfo_t info; - __siginfo_fpu_t * fpu_save; - unsigned int insns [2]; - unsigned long extramask[_NSIG_WORDS-1]; - __siginfo_fpu_t fpu_state; -}; - struct rt_signal_frame { struct sparc_stackf ss; siginfo_t info; struct pt_regs regs; - sigset_t mask; __siginfo_fpu_t * fpu_save; - unsigned int insns [2]; stack_t stack; + sigset_t mask; __siginfo_fpu_t fpu_state; }; /* Align macros */ -#define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) /* @@ -265,7 +248,7 @@ asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) sigset_t saveset; #ifdef CONFIG_SPARC32_COMPAT - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { extern asmlinkage void _sigpause32_common(old_sigset_t32, struct pt_regs *); _sigpause32_common(set, regs); @@ -372,65 +355,12 @@ restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); - err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr); - err |= __get_user(current->tss.gsr[0], &fpu->si_gsr); - current->tss.fpsaved[0] |= fprs; + err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr); + err |= __get_user(current->thread.gsr[0], &fpu->si_gsr); + current->thread.fpsaved[0] |= fprs; return err; } -void do_sigreturn(struct pt_regs *regs) -{ - struct new_signal_frame *sf; - unsigned long tpc, tnpc, tstate; - __siginfo_fpu_t *fpu_save; - sigset_t set; - int err; - - synchronize_user_stack (); - sf = (struct new_signal_frame *) - (regs->u_regs [UREG_FP] + STACK_BIAS); - - /* 1. Make sure we are not getting garbage from the user */ - if (((unsigned long) sf) & 3) - goto segv; - - err = get_user(tpc, &sf->info.si_regs.tpc); - err |= __get_user(tnpc, &sf->info.si_regs.tnpc); - err |= ((tpc | tnpc) & 3); - - /* 2. Restore the state */ - err |= __get_user(regs->y, &sf->info.si_regs.y); - err |= __get_user(tstate, &sf->info.si_regs.tstate); - err |= copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs)); - - /* User can only change condition codes in %tstate. */ - regs->tstate &= ~(TSTATE_ICC); - regs->tstate |= (tstate & TSTATE_ICC); - - err |= __get_user(fpu_save, &sf->fpu_save); - if (fpu_save) - err |= restore_fpu_state(regs, &sf->fpu_state); - - err |= __get_user(set.sig[0], &sf->info.si_mask); - if (_NSIG_WORDS > 1) - err |= __copy_from_user(&set.sig[1], &sf->extramask, sizeof(sf->extramask)); - - if (err) - goto segv; - - regs->tpc = tpc; - regs->tnpc = tnpc; - - sigdelsetmask(&set, ~_BLOCKABLE); - spin_lock_irq(¤t->sigmask_lock); - current->blocked = set; - recalc_sigpending(current); - spin_unlock_irq(¤t->sigmask_lock); - return; -segv: - send_sig(SIGSEGV, current, 1); -} - void do_rt_sigreturn(struct pt_regs *regs) { struct rt_signal_frame *sf; @@ -503,15 +433,15 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) unsigned long fprs; int err = 0; - fprs = current->tss.fpsaved[0]; + fprs = current->thread.fpsaved[0]; if (fprs & FPRS_DL) err |= copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); - err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr); - err |= __put_user(current->tss.gsr[0], &fpu->si_gsr); + err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr); + err |= __put_user(current->thread.gsr[0], &fpu->si_gsr); err |= __put_user(fprs, &fpu->si_fprs); return err; @@ -533,77 +463,6 @@ static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, u } static inline void -new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, - int signo, sigset_t *oldset) -{ - struct new_signal_frame *sf; - int sigframe_size, err; - - /* 1. Make sure everything is clean */ - synchronize_user_stack(); - save_and_clear_fpu(); - - sigframe_size = NF_ALIGNEDSZ; - - if (!(current->tss.fpsaved[0] & FPRS_FEF)) - sigframe_size -= sizeof(__siginfo_fpu_t); - - sf = (struct new_signal_frame *)get_sigframe(ka, regs, sigframe_size); - - if (invalid_frame_pointer (sf, sigframe_size)) - goto sigill; - - if (current->tss.w_saved != 0) { -#ifdef DEBUG_SIGNALS - printk ("%s[%d]: Invalid user stack frame for " - "signal delivery.\n", current->comm, current->pid); -#endif - goto sigill; - } - - /* 2. Save the current process state */ - err = copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); - - if (current->tss.fpsaved[0] & FPRS_FEF) { - err |= save_fpu_state(regs, &sf->fpu_state); - err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); - } else { - err |= __put_user(0, &sf->fpu_save); - } - - err |= __put_user(oldset->sig[0], &sf->info.si_mask); - if (_NSIG_WORDS > 1) - err |= __copy_to_user(sf->extramask, &oldset->sig[1], - sizeof(sf->extramask)); - - err |= copy_in_user((u64 *)sf, - (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), - sizeof(struct reg_window)); - if (err) - goto sigsegv; - - /* 3. signal handler back-trampoline and parameters */ - regs->u_regs[UREG_FP] = ((unsigned long) sf) - STACK_BIAS; - regs->u_regs[UREG_I0] = signo; - regs->u_regs[UREG_I1] = (unsigned long) &sf->info; - - /* 5. signal handler */ - regs->tpc = (unsigned long) ka->sa.sa_handler; - regs->tnpc = (regs->tpc + 4); - - /* 4. return to kernel instructions */ - regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; - return; - -sigill: - lock_kernel(); - do_exit(SIGILL); -sigsegv: - lock_kernel(); - do_exit(SIGSEGV); -} - -static inline void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, int signo, sigset_t *oldset, siginfo_t *info) { @@ -615,7 +474,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, save_and_clear_fpu(); sigframe_size = RT_ALIGNEDSZ; - if (!(current->tss.fpsaved[0] & FPRS_FEF)) + if (!(current->thread.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size); @@ -623,7 +482,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, if (invalid_frame_pointer (sf, sigframe_size)) goto sigill; - if (current->tss.w_saved != 0) { + if (current->thread.w_saved != 0) { #ifdef DEBUG_SIGNALS printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); @@ -634,7 +493,7 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, /* 2. Save the current process state */ err = copy_to_user(&sf->regs, regs, sizeof (*regs)); - if (current->tss.fpsaved[0] & FPRS_FEF) { + if (current->thread.fpsaved[0] & FPRS_FEF) { err |= save_fpu_state(regs, &sf->fpu_state); err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { @@ -652,7 +511,12 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), sizeof(struct reg_window)); - err |= copy_to_user(&sf->info, info, sizeof(siginfo_t)); + if (info) + err |= copy_to_user(&sf->info, info, sizeof(siginfo_t)); + else { + err |= __put_user(signo, &sf->info.si_signo); + err |= __put_user(SI_NOINFO, &sf->info.si_code); + } if (err) goto sigsegv; @@ -681,10 +545,7 @@ static inline void handle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) { - if(ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(ka, regs, signr, oldset, info); - else - new_setup_frame(ka, regs, signr, oldset); + setup_rt_frame(ka, regs, signr, oldset, (ka->sa.sa_flags & SA_SIGINFO) ? info : NULL); if(ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if(!(ka->sa.sa_flags & SA_NOMASK)) { @@ -785,7 +646,7 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, oldset = ¤t->blocked; #ifdef CONFIG_SPARC32_COMPAT - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { extern asmlinkage int do_signal32(sigset_t *, struct pt_regs *, unsigned long, int); return do_signal32(oldset, regs, orig_i0, restart_syscall); @@ -866,12 +727,8 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - if(current->binfmt && current->binfmt->core_dump) { - lock_kernel(); - if(current->binfmt->core_dump(signr, regs)) - exit_code |= 0x80; - unlock_kernel(); - } + if (do_coredump(signr, regs)) + exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug the dynamic linker */ printk ("Sig %d going...\n", (int)signr); diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index b1190d244..59388286f 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.48 1999/06/14 05:24:01 davem Exp $ +/* $Id: signal32.c,v 1.50 1999/07/30 09:35:25 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -202,9 +202,9 @@ static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); - err |= __get_user(current->tss.xfsr[0], &fpu->si_fsr); - err |= __get_user(current->tss.gsr[0], &fpu->si_gsr); - current->tss.fpsaved[0] |= fprs; + err |= __get_user(current->thread.xfsr[0], &fpu->si_fsr); + err |= __get_user(current->thread.gsr[0], &fpu->si_gsr); + current->thread.fpsaved[0] |= fprs; return err; } @@ -285,7 +285,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) int err; synchronize_user_stack(); - if (current->tss.new_signal) + if (current->thread.flags & SPARC_FLAG_NEWSIGNALS) return do_new_sigreturn32(regs); scptr = (struct sigcontext32 *) @@ -489,20 +489,20 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, err |= __put_user(pc, &sc->sigc_pc); err |= __put_user(npc, &sc->sigc_npc); psr = tstate_to_psr (regs->tstate); - if(current->tss.fpsaved[0] & FPRS_FEF) + if(current->thread.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; err |= __put_user(psr, &sc->sigc_psr); err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); - err |= __put_user(current->tss.w_saved, &sc->sigc_oswins); + err |= __put_user(current->thread.w_saved, &sc->sigc_oswins); #if 0 /* w_saved is not currently used... */ - if(current->tss.w_saved) - for(window = 0; window < current->tss.w_saved; window++) { + if(current->thread.w_saved) + for(window = 0; window < current->thread.w_saved; window++) { sc->sigc_spbuf[window] = - (char *)current->tss.rwbuf_stkptrs[window]; + (char *)current->thread.rwbuf_stkptrs[window]; err |= copy_to_user(&sc->sigc_wbuf[window], - ¤t->tss.reg_window[window], + ¤t->thread.reg_window[window], sizeof(struct reg_window)); } else @@ -511,15 +511,15 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, (u32 *)(regs->u_regs[UREG_FP]), sizeof(struct reg_window32)); - current->tss.w_saved = 0; /* So process is allowed to execute. */ + current->thread.w_saved = 0; /* So process is allowed to execute. */ err |= __put_user(signr, &sframep->sig_num); if(signr == SIGSEGV || signr == SIGILL || signr == SIGFPE || signr == SIGBUS || signr == SIGEMT) { - err |= __put_user(current->tss.sig_desc, &sframep->sig_code); - err |= __put_user(current->tss.sig_address, &sframep->sig_address); + err |= __put_user(current->thread.sig_desc, &sframep->sig_code); + err |= __put_user(current->thread.sig_address, &sframep->sig_address); } else { err |= __put_user(0, &sframep->sig_code); err |= __put_user(0, &sframep->sig_address); @@ -544,15 +544,15 @@ static inline int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) unsigned long fprs; int err = 0; - fprs = current->tss.fpsaved[0]; + fprs = current->thread.fpsaved[0]; if (fprs & FPRS_DL) err |= copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); - err |= __put_user(current->tss.xfsr[0], &fpu->si_fsr); - err |= __put_user(current->tss.gsr[0], &fpu->si_gsr); + err |= __put_user(current->thread.xfsr[0], &fpu->si_fsr); + err |= __put_user(current->thread.gsr[0], &fpu->si_gsr); err |= __put_user(fprs, &fpu->si_fprs); return err; @@ -572,7 +572,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg save_and_clear_fpu(); sigframe_size = NF_ALIGNEDSZ; - if (!(current->tss.fpsaved[0] & FPRS_FEF)) + if (!(current->thread.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size); @@ -585,7 +585,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg goto sigill; } - if (current->tss.w_saved != 0) { + if (current->thread.w_saved != 0) { #ifdef DEBUG_SIGNALS printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); @@ -598,7 +598,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg err |= __put_user(regs->tnpc, &sf->info.si_regs.npc); err |= __put_user(regs->y, &sf->info.si_regs.y); psr = tstate_to_psr (regs->tstate); - if(current->tss.fpsaved[0] & FPRS_FEF) + if(current->thread.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; err |= __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) @@ -738,7 +738,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, err |= __put_user(regs->tpc, &((*gr) [SVR4_PC])); err |= __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); - if(current->tss.fpsaved[0] & FPRS_FEF) + if(current->thread.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; err |= __put_user(psr, &((*gr) [SVR4_PSR])); err |= __put_user(regs->y, &((*gr) [SVR4_Y])); @@ -760,7 +760,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, err |= __put_user((u32)(long)gw, &mc->gwin); /* 2. Number of windows to restore at setcontext (): */ - err |= __put_user(current->tss.w_saved, &gw->count); + err |= __put_user(current->thread.w_saved, &gw->count); /* 3. Save each valid window * Currently, it makes a copy of the windows from the kernel copy. @@ -774,23 +774,23 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, * to flush the user windows. */ #if 0 - for(window = 0; window < current->tss.w_saved; window++) { + for(window = 0; window < current->thread.w_saved; window++) { err |= __put_user((int *) &(gw->win [window]), (int **)gw->winptr +window ); err |= copy_to_user(&gw->win [window], - ¤t->tss.reg_window [window], + ¤t->thread.reg_window [window], sizeof (svr4_rwindow_t)); err |= __put_user(0, (int *)gw->winptr + window); } #endif /* 4. We just pay attention to the gw->count field on setcontext */ - current->tss.w_saved = 0; /* So process is allowed to execute. */ + current->thread.w_saved = 0; /* So process is allowed to execute. */ /* Setup the signal information. Solaris expects a bunch of * information to be passed to the signal handler, we don't provide * that much currently, should use those that David already - * is providing with tss.sig_desc + * is providing with thread.sig_desc */ err |= __put_user(signr, &si->siginfo.signo); err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); @@ -837,8 +837,8 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) synchronize_user_stack(); save_and_clear_fpu(); - if (current->tss.w_saved){ - printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->tss.w_saved); + if (current->thread.w_saved){ + printk ("Uh oh, w_saved is not zero (%d)\n", (int) current->thread.w_saved); do_exit (SIGSEGV); } err = clear_user(uc, sizeof (*uc)); @@ -863,7 +863,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) err |= __put_user(0, &uc->mcontext.greg [SVR4_PSR]); #else i = tstate_to_psr(regs->tstate) & ~PSR_EF; - if (current->tss.fpsaved[0] & FPRS_FEF) + if (current->thread.fpsaved[0] & FPRS_FEF) i |= PSR_EF; err |= __put_user(i, &uc->mcontext.greg [SVR4_PSR]); #endif @@ -890,7 +890,7 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) /* Set the context for a svr4 application, this is Solaris way to sigreturn */ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) { - struct thread_struct *tp = ¤t->tss; + struct thread_struct *tp = ¤t->thread; svr4_gregset_t *gr; u32 pc, npc, psr; sigset_t set; @@ -990,7 +990,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs save_and_clear_fpu(); sigframe_size = RT_ALIGNEDSZ; - if (!(current->tss.fpsaved[0] & FPRS_FEF)) + if (!(current->thread.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size); @@ -1003,7 +1003,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs goto sigill; } - if (current->tss.w_saved != 0) { + if (current->thread.w_saved != 0) { #ifdef DEBUG_SIGNALS printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); @@ -1016,7 +1016,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs err |= __put_user(regs->tnpc, &sf->regs.npc); err |= __put_user(regs->y, &sf->regs.y); psr = tstate_to_psr (regs->tstate); - if(current->tss.fpsaved[0] & FPRS_FEF) + if(current->thread.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; err |= __put_user(psr, &sf->regs.psr); for (i = 0; i < 16; i++) @@ -1032,6 +1032,42 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs } else { err |= __put_user(0, &sf->fpu_save); } + + err = __put_user (info->si_signo, &sf->info.si_signo); + err |= __put_user (info->si_errno, &sf->info.si_errno); + err |= __put_user (info->si_code, &sf->info.si_code); + if (info->si_code < 0) + err |= __copy_to_user (sf->info._sifields._pad, info->_sifields._pad, SI_PAD_SIZE); + else { + i = info->si_signo; + if (info->si_code == SI_USER) + i = SIGRTMIN; + switch (i) { + case SIGPOLL: + err |= __put_user (info->si_band, &sf->info.si_band); + err |= __put_user (info->si_fd, &sf->info.si_fd); + break; + case SIGCHLD: + err |= __put_user (info->si_pid, &sf->info.si_pid); + err |= __put_user (info->si_uid, &sf->info.si_uid); + err |= __put_user (info->si_status, &sf->info.si_status); + err |= __put_user (info->si_utime, &sf->info.si_utime); + err |= __put_user (info->si_stime, &sf->info.si_stime); + break; + case SIGSEGV: + case SIGILL: + case SIGFPE: + case SIGBUS: + case SIGEMT: + err |= __put_user ((long)info->si_addr, &sf->info.si_addr); + err |= __put_user (info->si_trapno, &sf->info.si_trapno); + break; + default: + err |= __put_user (info->si_pid, &sf->info.si_pid); + err |= __put_user (info->si_uid, &sf->info.si_uid); + break; + } + } /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); @@ -1040,13 +1076,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs switch (_NSIG_WORDS) { case 4: seta.sig[7] = (oldset->sig[3] >> 32); - seta.sig[6] = oldset->sig[3]; + seta.sig[6] = oldset->sig[3]; case 3: seta.sig[5] = (oldset->sig[2] >> 32); - seta.sig[4] = oldset->sig[2]; + seta.sig[4] = oldset->sig[2]; case 2: seta.sig[3] = (oldset->sig[1] >> 32); - seta.sig[2] = oldset->sig[1]; + seta.sig[2] = oldset->sig[1]; case 1: seta.sig[1] = (oldset->sig[0] >> 32); - seta.sig[0] = oldset->sig[0]; + seta.sig[0] = oldset->sig[0]; } err |= __copy_to_user(&sf->mask, &seta, sizeof(sigset_t)); @@ -1113,7 +1149,7 @@ static inline void handle_signal32(unsigned long signr, struct k_sigaction *ka, else { if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame32(ka, regs, signr, oldset, info); - else if (current->tss.new_signal) + else if (current->thread.flags & SPARC_FLAG_NEWSIGNALS) new_setup_frame32(ka, regs, signr, oldset); else setup_frame32(&ka->sa, regs->tpc, regs->tnpc, regs, signr, oldset); @@ -1256,13 +1292,13 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, if(signr != SIGCHLD) continue; - /* sys_wait4() grabs the master kernel lock, so - * we need not do so, that sucker should be - * threaded and would not be that difficult to - * do anyways. - */ - while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0) - ; + /* sys_wait4() grabs the master kernel lock, so + * we need not do so, that sucker should be + * threaded and would not be that difficult to + * do anyways. + */ + while(sys_wait4(-1, NULL, WNOHANG, NULL) > 0) + ; continue; } if(ka->sa.sa_handler == SIG_DFL) { @@ -1291,14 +1327,8 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: - if(current->binfmt && current->binfmt->core_dump) { - lock_kernel(); - if(current->binfmt && - current->binfmt->core_dump && - current->binfmt->core_dump(signr, regs)) - exit_code |= 0x80; - unlock_kernel(); - } + if (do_coredump(signr, regs)) + exit_code |= 0x80; #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); @@ -1318,10 +1348,10 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, { struct reg_window32 *rw = (struct reg_window32 *)(regs->u_regs[UREG_FP] & 0xffffffff); unsigned int ins[8]; - + while(rw && !(((unsigned long) rw) & 0x3)) { - copy_from_user(ins, &rw->ins[0], sizeof(ins)); + copy_from_user(ins, &rw->ins[0], sizeof(ins)); printk("Caller[%08x](%08x,%08x,%08x,%08x,%08x,%08x)\n", ins[7], ins[0], ins[1], ins[2], ins[3], ins[4], ins[5]); rw = (struct reg_window32 *)(unsigned long)ins[6]; } @@ -1380,7 +1410,7 @@ asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp) /* Now see if we want to update the new state. */ if (ssptr) { void *ss_sp; - + if (get_user((long)ss_sp, &ssptr->the_stack)) goto out; /* If the current stack was set with sigaltstack, don't diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index a0e8f7e69..d1adeb2c7 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -7,13 +7,14 @@ #include <linux/sched.h> #include <linux/mm.h> #include <linux/pagemap.h> -#include <linux/tasks.h> +#include <linux/threads.h> #include <linux/smp.h> #include <linux/smp_lock.h> #include <linux/interrupt.h> #include <linux/kernel_stat.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/spinlock.h> #include <asm/head.h> #include <asm/ptrace.h> @@ -23,7 +24,6 @@ #include <asm/page.h> #include <asm/pgtable.h> #include <asm/oplib.h> -#include <asm/spinlock.h> #include <asm/hardirq.h> #include <asm/softirq.h> #include <asm/uaccess.h> @@ -53,7 +53,7 @@ unsigned long cpu_present_map = 0; int smp_num_cpus = 1; int smp_threads_ready = 0; -__initfunc(void smp_setup(char *str, int *ints)) +void __init smp_setup(char *str, int *ints) { /* XXX implement me XXX */ } @@ -83,7 +83,7 @@ int smp_bogo(char *buf) return len; } -__initfunc(void smp_store_cpu_info(int id)) +void __init smp_store_cpu_info(int id) { int i; @@ -103,7 +103,7 @@ __initfunc(void smp_store_cpu_info(int id)) cpu_data[id].irq_worklists[i] = 0; } -__initfunc(void smp_commence(void)) +void __init smp_commence(void) { } @@ -115,7 +115,7 @@ static volatile unsigned long callin_flag = 0; extern void inherit_locked_prom_mappings(int save_p); extern void cpu_probe(void); -__initfunc(void smp_callin(void)) +void __init smp_callin(void) { int cpuid = hard_smp_processor_id(); @@ -151,13 +151,17 @@ __initfunc(void smp_callin(void)) /* Clear this or we will die instantly when we * schedule back to this idler... */ - current->tss.flags &= ~(SPARC_FLAG_NEWCHILD); + current->thread.flags &= ~(SPARC_FLAG_NEWCHILD); + + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; while(!smp_processors_ready) membar("#LoadLoad"); } -extern int cpu_idle(void *unused); +extern int cpu_idle(void); extern void init_IRQ(void); void initialize_secondary(void) @@ -169,7 +173,7 @@ int start_secondary(void *unused) trap_init(); init_IRQ(); smp_callin(); - return cpu_idle(NULL); + return cpu_idle(); } void cpu_panic(void) @@ -188,7 +192,7 @@ extern unsigned long smp_trampoline; */ static struct task_struct *cpu_new_task = NULL; -__initfunc(void smp_boot_cpus(void)) +void __init smp_boot_cpus(void) { int cpucount = 0, i; @@ -216,9 +220,17 @@ __initfunc(void smp_boot_cpus(void)) entry += phys_base - KERNBASE; cookie += phys_base - KERNBASE; kernel_thread(start_secondary, NULL, CLONE_PID); - p = task[++cpucount]; + cpucount++; + + p = init_task.prev_task; + init_tasks[cpucount] = p; + p->processor = i; p->has_cpu = 1; /* we schedule the first task manually */ + + del_from_runqueue(p); + unhash_process(p); + callin_flag = 0; for (no = 0; no < linux_num_cpus; no++) if (linux_cpus[no].mid == i) @@ -384,6 +396,9 @@ void smp_flush_tlb_all(void) * are flush_tlb_*() routines, and these run after flush_cache_*() * which performs the flushw. * + * XXX I diked out the fancy flush avoidance code for the + * XXX swapping cases for now until the new MM code stabilizes. -DaveM + * * The SMP TLB coherency scheme we use works as follows: * * 1) mm->cpu_vm_mask is a bit mask of which cpus an address @@ -395,16 +410,16 @@ void smp_flush_tlb_all(void) * cross calls. * * One invariant is that when a cpu switches to a process, and - * that processes tsk->mm->cpu_vm_mask does not have the current - * cpu's bit set, that tlb context is flushed locally. + * that processes tsk->active_mm->cpu_vm_mask does not have the + * current cpu's bit set, that tlb context is flushed locally. * * If the address space is non-shared (ie. mm->count == 1) we avoid * cross calls when we want to flush the currently running process's * tlb state. This is done by clearing all cpu bits except the current - * processor's in current->mm->cpu_vm_mask and performing the flush - * locally only. This will force any subsequent cpus which run this - * task to flush the context from the local tlb if the process migrates - * to another cpu (again). + * processor's in current->active_mm->cpu_vm_mask and performing the + * flush locally only. This will force any subsequent cpus which run + * this task to flush the context from the local tlb if the process + * migrates to another cpu (again). * * 3) For shared address spaces (threads) and swapping we bite the * bullet for most cases and perform the cross call. @@ -422,13 +437,13 @@ void smp_flush_tlb_all(void) */ void smp_flush_tlb_mm(struct mm_struct *mm) { - u32 ctx = mm->context & 0x3ff; + u32 ctx = CTX_HWBITS(mm->context); - if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - mm->cpu_vm_mask = (1UL << smp_processor_id()); + if (mm == current->active_mm && + atomic_read(&mm->mm_users) == 1 && + (mm->cpu_vm_mask == (1UL << smp_processor_id()))) goto local_flush_and_out; - } + smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); local_flush_and_out: @@ -438,15 +453,15 @@ local_flush_and_out: void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - u32 ctx = mm->context & 0x3ff; + u32 ctx = CTX_HWBITS(mm->context); start &= PAGE_MASK; end &= PAGE_MASK; - if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - mm->cpu_vm_mask = (1UL << smp_processor_id()); + if(mm == current->active_mm && + atomic_read(&mm->mm_users) == 1 && + (mm->cpu_vm_mask == (1UL << smp_processor_id()))) goto local_flush_and_out; - } + smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); local_flush_and_out: @@ -455,30 +470,15 @@ local_flush_and_out: void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) { - u32 ctx = mm->context & 0x3ff; + u32 ctx = CTX_HWBITS(mm->context); page &= PAGE_MASK; - if(mm == current->mm && atomic_read(&mm->count) == 1) { - if(mm->cpu_vm_mask != (1UL << smp_processor_id())) - mm->cpu_vm_mask = (1UL << smp_processor_id()); + if(mm == current->active_mm && + atomic_read(&mm->mm_users) == 1 && + (mm->cpu_vm_mask == (1UL << smp_processor_id()))) { goto local_flush_and_out; - } else { - /* 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) || - (mm->cpu_vm_mask == 0)) { - /* A dead context cannot ever become "alive" until - * a task switch is done to it. - */ - return; /* It's dead, nothing to do. */ - } - if(mm->cpu_vm_mask == (1UL << smp_processor_id())) { - __flush_tlb_page(ctx, page, SECONDARY_CONTEXT); - return; /* Only local flush is necessary. */ - } } + smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); local_flush_and_out: @@ -547,10 +547,18 @@ void smp_penguin_jailcell(void) atomic_dec(&smp_capture_registry); } -static inline void sparc64_do_profile(unsigned long pc) +static inline void sparc64_do_profile(unsigned long pc, unsigned long g3) { if (prof_buffer && current->pid) { extern int _stext; + extern int rwlock_impl_begin, rwlock_impl_end; + extern int atomic_impl_begin, atomic_impl_end; + + if ((pc >= (unsigned long) &rwlock_impl_begin && + pc < (unsigned long) &rwlock_impl_end) || + (pc >= (unsigned long) &atomic_impl_begin && + pc < (unsigned long) &atomic_impl_end)) + pc = g3; pc -= (unsigned long) &_stext; pc >>= prof_shift; @@ -589,7 +597,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) clear_softint((1UL << 0)); do { if(!user) - sparc64_do_profile(regs->tpc); + sparc64_do_profile(regs->tpc, regs->u_regs[UREG_G3]); if(!--prof_counter(cpu)) { if (cpu == boot_cpu_id) { @@ -647,7 +655,7 @@ do { hardirq_enter(cpu); \ } while (tick >= compare); } -__initfunc(static void smp_setup_percpu_timer(void)) +static void __init smp_setup_percpu_timer(void) { int cpu = smp_processor_id(); @@ -661,7 +669,7 @@ __initfunc(static void smp_setup_percpu_timer(void)) : "g1"); } -__initfunc(void smp_tick_init(void)) +void __init smp_tick_init(void) { int i; @@ -707,7 +715,7 @@ static inline unsigned long find_flush_base(unsigned long size) cycles_t cacheflush_time; -__initfunc(static void smp_tune_scheduling (void)) +static void __init smp_tune_scheduling (void) { unsigned long flush_base, flags, *p; unsigned int ecache_size; @@ -775,7 +783,8 @@ __initfunc(static void smp_tune_scheduling (void)) (int) cacheflush_time); } -int __init setup_profiling_timer(unsigned int multiplier) +/* /proc/profile writes can call this, don't __init it please. */ +int setup_profiling_timer(unsigned int multiplier) { unsigned long flags; int i; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 91277fc4a..e57b8d6f7 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.60 1999/07/03 22:11:12 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.64 1999/09/05 09:33:38 ecd Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -190,10 +190,9 @@ EXPORT_SYMBOL(dma_chain); #endif #if CONFIG_PCI EXPORT_SYMBOL(ebus_chain); -EXPORT_SYMBOL(pci_dvma_offset); -EXPORT_SYMBOL(pci_dvma_mask); EXPORT_SYMBOL(pci_dvma_v2p_hash); EXPORT_SYMBOL(pci_dvma_p2v_hash); +EXPORT_SYMBOL(pci_memspace_mask); EXPORT_SYMBOL(empty_zero_page); EXPORT_SYMBOL(outsb); EXPORT_SYMBOL(outsw); @@ -215,7 +214,6 @@ EXPORT_SYMBOL(die_if_kernel); /* Kernel thread creation. */ EXPORT_SYMBOL(kernel_thread); -EXPORT_SYMBOL(init_mm); /* prom symbols */ EXPORT_SYMBOL(idprom); diff --git a/arch/sparc64/kernel/starfire.c b/arch/sparc64/kernel/starfire.c index 38f33ecd6..805dce338 100644 --- a/arch/sparc64/kernel/starfire.c +++ b/arch/sparc64/kernel/starfire.c @@ -1,4 +1,4 @@ -/* $Id: starfire.c,v 1.2 1998/12/09 18:53:11 davem Exp $ +/* $Id: starfire.c,v 1.3 1999/08/30 10:01:13 davem Exp $ * starfire.c: Starfire/E10000 support. * * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) @@ -43,7 +43,7 @@ void starfire_check(void) int starfire_hard_smp_processor_id(void) { - return *((unsigned int *) __va(0x1fff40000d0)); + return *((volatile unsigned int *) __va(0x1fff40000d0)); } /* Each Starfire board has 32 registers which perform translation @@ -52,8 +52,8 @@ int starfire_hard_smp_processor_id(void) * bits than in all previous Sun5 systems. */ struct starfire_irqinfo { - unsigned int *imap_slots[32]; - unsigned int *tregs[32]; + volatile unsigned int *imap_slots[32]; + volatile unsigned int *tregs[32]; struct starfire_irqinfo *next; int upaid, hwmid; }; @@ -80,7 +80,7 @@ void *starfire_hookup(int upaid) treg_base += 0x200UL; for(i = 0; i < 32; i++) { p->imap_slots[i] = NULL; - p->tregs[i] = __va(treg_base + (i * 0x10)); + p->tregs[i] = (volatile unsigned int *)__va(treg_base + (i * 0x10)); } p->upaid = upaid; p->next = sflist; @@ -89,7 +89,7 @@ void *starfire_hookup(int upaid) return (void *) p; } -unsigned int starfire_translate(unsigned int *imap, +unsigned int starfire_translate(volatile unsigned int *imap, unsigned int upaid) { struct starfire_irqinfo *p; diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index 4906cea93..4e87819d4 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.27 1999/06/02 12:06:34 jj Exp $ +/* $Id: sys_sparc.c,v 1.29 1999/08/04 07:04:10 jj Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -41,7 +41,9 @@ extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { - if(brk >= 0x80000000000UL) /* VM hole */ + if((brk >= 0x80000000000UL && brk < PAGE_OFFSET) || + (brk - current->mm->brk > 0x80000000000UL && + brk - current->mm->brk < PAGE_OFFSET)) /* VM hole */ return current->mm->brk; return sys_brk(brk); } @@ -170,7 +172,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, } retval = -EINVAL; - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { if (len > 0xf0000000UL || addr > 0xf0000000UL - len) goto out_putf; } else { @@ -178,7 +180,7 @@ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, (addr < 0x80000000000UL && addr > 0x80000000000UL-len)) goto out_putf; - if (addr >= 0x80000000000ULL && addr < 0xfffff80000000000UL) { + if (addr >= 0x80000000000UL && addr < PAGE_OFFSET) { /* VM hole */ retval = current->mm->brk; goto out_putf; @@ -281,40 +283,40 @@ asmlinkage int sys_utrap_install(utrap_entry_t type, utrap_handler_t new_p, return -EINVAL; if (new_p == (utrap_handler_t)(long)UTH_NOCHANGE) { if (old_p) { - if (!current->tss.utraps) + if (!current->thread.utraps) put_user_ret(NULL, old_p, -EFAULT); else - put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT); } if (old_d) put_user_ret(NULL, old_d, -EFAULT); return 0; } lock_kernel(); - if (!current->tss.utraps) { - current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); - if (!current->tss.utraps) return -ENOMEM; - current->tss.utraps[0] = 1; - memset(current->tss.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long)); + if (!current->thread.utraps) { + current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->thread.utraps) return -ENOMEM; + current->thread.utraps[0] = 1; + memset(current->thread.utraps+1, 0, UT_TRAP_INSTRUCTION_31*sizeof(long)); } else { - if ((utrap_handler_t)current->tss.utraps[type] != new_p && current->tss.utraps[0] > 1) { - long *p = current->tss.utraps; + if ((utrap_handler_t)current->thread.utraps[type] != new_p && current->thread.utraps[0] > 1) { + long *p = current->thread.utraps; - current->tss.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); - if (!current->tss.utraps) { - current->tss.utraps = p; + current->thread.utraps = kmalloc((UT_TRAP_INSTRUCTION_31+1)*sizeof(long), GFP_KERNEL); + if (!current->thread.utraps) { + current->thread.utraps = p; return -ENOMEM; } p[0]--; - current->tss.utraps[0] = 1; - memcpy(current->tss.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long)); + current->thread.utraps[0] = 1; + memcpy(current->thread.utraps+1, p+1, UT_TRAP_INSTRUCTION_31*sizeof(long)); } } if (old_p) - put_user_ret((utrap_handler_t)(current->tss.utraps[type]), old_p, -EFAULT); + put_user_ret((utrap_handler_t)(current->thread.utraps[type]), old_p, -EFAULT); if (old_d) put_user_ret(NULL, old_d, -EFAULT); - current->tss.utraps[type] = (long)new_p; + current->thread.utraps[type] = (long)new_p; unlock_kernel(); return 0; } @@ -363,10 +365,10 @@ update_perfctrs(void) unsigned long pic, tmp; read_pic(pic); - tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); - __put_user(tmp, current->tss.user_cntd0); - tmp = (current->tss.kernel_cntd1 += (pic >> 32)); - __put_user(tmp, current->tss.user_cntd1); + tmp = (current->thread.kernel_cntd0 += (unsigned int)pic); + __put_user(tmp, current->thread.user_cntd0); + tmp = (current->thread.kernel_cntd1 += (pic >> 32)); + __put_user(tmp, current->thread.user_cntd1); reset_pic(); } @@ -377,24 +379,24 @@ sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long ar switch(opcode) { case PERFCTR_ON: - current->tss.pcr_reg = arg2; - current->tss.user_cntd0 = (u64 *) arg0; - current->tss.user_cntd1 = (u64 *) arg1; - current->tss.kernel_cntd0 = - current->tss.kernel_cntd1 = 0; + current->thread.pcr_reg = arg2; + current->thread.user_cntd0 = (u64 *) arg0; + current->thread.user_cntd1 = (u64 *) arg1; + current->thread.kernel_cntd0 = + current->thread.kernel_cntd1 = 0; write_pcr(arg2); reset_pic(); - current->tss.flags |= SPARC_FLAG_PERFCTR; + current->thread.flags |= SPARC_FLAG_PERFCTR; break; case PERFCTR_OFF: err = -EINVAL; - if ((current->tss.flags & SPARC_FLAG_PERFCTR) != 0) { - current->tss.user_cntd0 = - current->tss.user_cntd1 = NULL; - current->tss.pcr_reg = 0; + if ((current->thread.flags & SPARC_FLAG_PERFCTR) != 0) { + current->thread.user_cntd0 = + current->thread.user_cntd1 = NULL; + current->thread.pcr_reg = 0; write_pcr(0); - current->tss.flags &= ~(SPARC_FLAG_PERFCTR); + current->thread.flags &= ~(SPARC_FLAG_PERFCTR); err = 0; } break; @@ -402,50 +404,50 @@ sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1, unsigned long ar case PERFCTR_READ: { unsigned long pic, tmp; - if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) { err = -EINVAL; break; } read_pic(pic); - tmp = (current->tss.kernel_cntd0 += (unsigned int)pic); - err |= __put_user(tmp, current->tss.user_cntd0); - tmp = (current->tss.kernel_cntd1 += (pic >> 32)); - err |= __put_user(tmp, current->tss.user_cntd1); + tmp = (current->thread.kernel_cntd0 += (unsigned int)pic); + err |= __put_user(tmp, current->thread.user_cntd0); + tmp = (current->thread.kernel_cntd1 += (pic >> 32)); + err |= __put_user(tmp, current->thread.user_cntd1); reset_pic(); break; } case PERFCTR_CLRPIC: - if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) { err = -EINVAL; break; } - current->tss.kernel_cntd0 = - current->tss.kernel_cntd1 = 0; + current->thread.kernel_cntd0 = + current->thread.kernel_cntd1 = 0; reset_pic(); break; case PERFCTR_SETPCR: { u64 *user_pcr = (u64 *)arg0; - if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) { err = -EINVAL; break; } - err |= __get_user(current->tss.pcr_reg, user_pcr); - write_pcr(current->tss.pcr_reg); - current->tss.kernel_cntd0 = - current->tss.kernel_cntd1 = 0; + err |= __get_user(current->thread.pcr_reg, user_pcr); + write_pcr(current->thread.pcr_reg); + current->thread.kernel_cntd0 = + current->thread.kernel_cntd1 = 0; reset_pic(); break; } case PERFCTR_GETPCR: { u64 *user_pcr = (u64 *)arg0; - if (!(current->tss.flags & SPARC_FLAG_PERFCTR)) { + if (!(current->thread.flags & SPARC_FLAG_PERFCTR)) { err = -EINVAL; break; } - err |= __put_user(current->tss.pcr_reg, user_pcr); + err |= __put_user(current->thread.pcr_reg, user_pcr); break; } diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 0e42e2c32..a1e0f26dd 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.109 1999/06/03 07:11:31 davem Exp $ +/* $Id: sys_sparc32.c,v 1.118 1999/08/30 10:01:15 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -1663,85 +1663,6 @@ asmlinkage int sys32_rt_sigpending(sigset_t32 *set, __kernel_size_t32 sigsetsize return ret; } -siginfo_t32 * -siginfo64to32(siginfo_t32 *d, siginfo_t *s) -{ - memset (&d, 0, sizeof(siginfo_t32)); - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (long)(s->si_addr); - /* XXX: Do we need to translate this from sparc64 to sparc32 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - -siginfo_t * -siginfo32to64(siginfo_t *d, siginfo_t32 *s) -{ - d->si_signo = s->si_signo; - d->si_errno = s->si_errno; - d->si_code = s->si_code; - if (s->si_signo >= SIGRTMIN) { - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - /* XXX: Ouch, how to find this out??? */ - d->si_int = s->si_int; - } else switch (s->si_signo) { - /* XXX: What about POSIX1.b timers */ - case SIGCHLD: - d->si_pid = s->si_pid; - d->si_status = s->si_status; - d->si_utime = s->si_utime; - d->si_stime = s->si_stime; - break; - case SIGSEGV: - case SIGBUS: - case SIGFPE: - case SIGILL: - d->si_addr = (void *)A(s->si_addr); - /* XXX: Do we need to translate this from sparc32 to sparc64 traps? */ - d->si_trapno = s->si_trapno; - break; - case SIGPOLL: - d->si_band = s->si_band; - d->si_fd = s->si_fd; - break; - default: - d->si_pid = s->si_pid; - d->si_uid = s->si_uid; - break; - } - return d; -} - extern asmlinkage int sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize); @@ -1753,10 +1674,9 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, sigset_t s; sigset_t32 s32; struct timespec t; - int ret; + int ret, err, i; mm_segment_t old_fs = get_fs(); siginfo_t info; - siginfo_t32 info32; if (copy_from_user (&s32, uthese, sizeof(sigset_t32))) return -EFAULT; @@ -1776,8 +1696,43 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo, ret = sys_rt_sigtimedwait(&s, &info, &t, sigsetsize); set_fs (old_fs); if (ret >= 0 && uinfo) { - if (copy_to_user (uinfo, siginfo64to32(&info32, &info), sizeof(siginfo_t32))) - return -EFAULT; + err = put_user (info.si_signo, &uinfo->si_signo); + err |= __put_user (info.si_errno, &uinfo->si_errno); + err |= __put_user (info.si_code, &uinfo->si_code); + if (info.si_code < 0) + err |= __copy_to_user (uinfo->_sifields._pad, info._sifields._pad, SI_PAD_SIZE); + else { + i = info.si_signo; + if (info.si_code == SI_USER) + i = SIGRTMIN; + switch (i) { + case SIGPOLL: + err |= __put_user (info.si_band, &uinfo->si_band); + err |= __put_user (info.si_fd, &uinfo->si_fd); + break; + case SIGCHLD: + err |= __put_user (info.si_pid, &uinfo->si_pid); + err |= __put_user (info.si_uid, &uinfo->si_uid); + err |= __put_user (info.si_status, &uinfo->si_status); + err |= __put_user (info.si_utime, &uinfo->si_utime); + err |= __put_user (info.si_stime, &uinfo->si_stime); + break; + case SIGSEGV: + case SIGILL: + case SIGFPE: + case SIGBUS: + case SIGEMT: + err |= __put_user ((long)info.si_addr, &uinfo->si_addr); + err |= __put_user (info.si_trapno, &uinfo->si_trapno); + break; + default: + err |= __put_user (info.si_pid, &uinfo->si_pid); + err |= __put_user (info.si_uid, &uinfo->si_uid); + break; + } + } + if (err) + ret = -EFAULT; } return ret; } @@ -1789,14 +1744,12 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, siginfo_t32 *uinfo) { siginfo_t info; - siginfo_t32 info32; int ret; mm_segment_t old_fs = get_fs(); - if (copy_from_user (&info32, uinfo, sizeof(siginfo_t32))) + if (copy_from_user (&info, uinfo, 3*sizeof(int)) || + copy_from_user (info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) return -EFAULT; - /* XXX: Is this correct? */ - siginfo32to64(&info, &info32); set_fs (KERNEL_DS); ret = sys_rt_sigqueueinfo(pid, sig, &info); set_fs (old_fs); @@ -2659,7 +2612,7 @@ asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old int ret; if(sig < 0) { - current->tss.new_signal = 1; + current->thread.flags |= SPARC_FLAG_NEWSIGNALS; sig = -sig; } @@ -2703,7 +2656,7 @@ sys32_rt_sigaction(int sig, struct sigaction32 *act, struct sigaction32 *oact, /* All tasks which use RT signals (effectively) use * new style signals. */ - current->tss.new_signal = 1; + current->thread.flags |= SPARC_FLAG_NEWSIGNALS; if (act) { new_ka.ka_restorer = restorer; @@ -2883,6 +2836,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) int error, base = 0; char *filename; + /* User register window flush is done by entry.S */ + /* Check for indirect call. */ if((u32)regs->u_regs[UREG_G1] == 0) base = 1; @@ -2899,8 +2854,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if(!error) { fprs_write(0); - current->tss.xfsr[0] = 0; - current->tss.fpsaved[0] = 0; + current->thread.xfsr[0] = 0; + current->thread.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: @@ -3786,7 +3741,7 @@ asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf, } -extern asmlinkage int sys_personality(unsigned long); +extern asmlinkage long sys_personality(unsigned long); asmlinkage int sys32_personality(unsigned long personality) { diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index 156d1d8ee..0f0c2a536 100644 --- a/arch/sparc64/kernel/sys_sunos32.c +++ b/arch/sparc64/kernel/sys_sunos32.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.26 1999/06/09 08:23:54 davem Exp $ +/* $Id: sys_sunos32.c,v 1.31 1999/08/30 10:01:19 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -557,9 +557,9 @@ asmlinkage int sunos_nosys(void) struct pt_regs *regs; lock_kernel(); - regs = current->tss.kregs; - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = regs->u_regs[UREG_G1]; + regs = current->thread.kregs; + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = regs->u_regs[UREG_G1]; send_sig(SIGSYS, current, 1); printk("Process makes ni_syscall number %d, register dump:\n", (int) regs->u_regs[UREG_G1]); @@ -981,10 +981,6 @@ extern asmlinkage s32 sunos_sysconf (int name) return ret; } -extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); -extern asmlinkage int sys_semget (key_t key, int nsems, int semflg); -extern asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops); - asmlinkage int sunos_semsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 ptr) { union semun arg4; @@ -1119,13 +1115,6 @@ static inline int sunos_msgbuf_put(struct msgbuf32 *user, struct msgbuf *kern, i return 0; } -extern asmlinkage int sys_msgget (key_t key, int msgflg); -extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, - size_t msgsz, long msgtyp, int msgflg); -extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, - size_t msgsz, int msgflg); -extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); - asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { struct sparc_stackf32 *sp; @@ -1159,7 +1148,7 @@ asmlinkage int sunos_msgsys(int op, u32 arg1, u32 arg2, u32 arg3, u32 arg4) if(!kmbuf) break; sp = (struct sparc_stackf32 *) - (current->tss.kregs->u_regs[UREG_FP] & 0xffffffffUL); + (current->thread.kregs->u_regs[UREG_FP] & 0xffffffffUL); if(get_user(arg5, &sp->xxargs[0])) { rval = -EFAULT; break; @@ -1242,11 +1231,6 @@ static inline int sunos_shmid_put(struct shmid_ds32 *user, return 0; } -extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); -extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); -extern asmlinkage int sys_shmdt (char *shmaddr); -extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); - asmlinkage int sunos_shmsys(int op, u32 arg1, u32 arg2, u32 arg3) { struct shmid_ds ksds; diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index e99ae0532..06a827db2 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.54 1999/06/02 12:06:31 jj Exp $ +/* $Id: systbls.S,v 1.56 1999/07/31 00:06:17 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -59,7 +59,7 @@ sys_call_table32: .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask /*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir .word sys_nis_syscall, sys32_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall -/*210*/ .word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo +/*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo .word sys32_ipc, sys32_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 @@ -112,15 +112,15 @@ sys_call_table: .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 +/*180*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, 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_nis_syscall, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask -/*200*/ .word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall +/*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall .word sys_nis_syscall, sys_socketcall, 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 +/*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo + .word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex +/*220*/ .word sys_nis_syscall, 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_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 0b72e6e0b..60d5e4a5f 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.20 1999/03/15 22:13:40 davem Exp $ +/* $Id: time.c,v 1.22 1999/08/30 10:01:22 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -33,9 +33,9 @@ extern rwlock_t xtime_lock; -struct mostek48t02 *mstk48t02_regs = 0; -static struct mostek48t08 *mstk48t08_regs = 0; -static struct mostek48t59 *mstk48t59_regs = 0; +unsigned long mstk48t02_regs = 0UL; +static unsigned long mstk48t08_regs = 0UL; +static unsigned long mstk48t59_regs = 0UL; static int set_rtc_mmss(unsigned long); @@ -47,7 +47,7 @@ static int set_rtc_mmss(unsigned long); */ unsigned long timer_tick_offset; static unsigned long timer_tick_compare; -static unsigned long timer_ticks_per_usec; +static unsigned long timer_ticks_per_usec_quotient; static __inline__ void timer_check_rtc(void) { @@ -146,17 +146,25 @@ static inline unsigned long mktime(unsigned int year, unsigned int mon, /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { - register struct mostek48t02 *regs = mstk48t02_regs; - unsigned char sec; + unsigned long regs = mstk48t02_regs; + u8 sec, tmp; int i, count; prom_printf("CLOCK: Clock was stopped. Kick start "); /* Turn on the kick start bit to start the oscillator. */ - regs->creg |= MSTK_CREG_WRITE; - regs->sec &= ~MSTK_STOP; - regs->hour |= MSTK_KICK_START; - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_SEC); + tmp &= ~MSTK_STOP; + mostek_write(regs + MOSTEK_SEC, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp |= MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); /* Delay to allow the clock oscillator to start. */ sec = MSTK_REG_SEC(regs); @@ -165,13 +173,17 @@ static void __init kick_start_clock(void) for (count = 0; count < 100000; count++) /* nothing */ ; prom_printf("."); - sec = regs->sec; + sec = MSTK_REG_SEC(regs); } prom_printf("\n"); /* Turn off kick start and set a "valid" time and date. */ - regs->creg |= MSTK_CREG_WRITE; - regs->hour &= ~MSTK_KICK_START; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); MSTK_SET_REG_SEC(regs,0); MSTK_SET_REG_MIN(regs,0); MSTK_SET_REG_HOUR(regs,0); @@ -179,14 +191,24 @@ static void __init kick_start_clock(void) MSTK_SET_REG_DOM(regs,1); MSTK_SET_REG_MONTH(regs,8); MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); /* Ensure the kick start bit is off. If it isn't, turn it off. */ - while (regs->hour & MSTK_KICK_START) { + while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) { prom_printf("CLOCK: Kick start still on!\n"); - regs->creg |= MSTK_CREG_WRITE; - regs->hour &= ~MSTK_KICK_START; - regs->creg &= ~MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + tmp = mostek_read(regs + MOSTEK_HOUR); + tmp &= ~MSTK_KICK_START; + mostek_write(regs + MOSTEK_HOUR, tmp); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); } prom_printf("CLOCK: Kick start procedure successful.\n"); @@ -195,13 +217,13 @@ static void __init kick_start_clock(void) /* Return nonzero if the clock chip battery is low. */ static int __init has_low_battery(void) { - register struct mostek48t02 *regs = mstk48t02_regs; - unsigned char data1, data2; + unsigned long regs = mstk48t02_regs; + u8 data1, data2; - data1 = regs->eeprom[0]; /* Read some data. */ - regs->eeprom[0] = ~data1; /* Write back the complement. */ - data2 = regs->eeprom[0]; /* Read back the complement. */ - regs->eeprom[0] = data1; /* Restore the original value. */ + data1 = mostek_read(regs + MOSTEK_EEPROM); /* Read some data. */ + mostek_write(regs + MOSTEK_EEPROM, ~data1); /* Write back the complement. */ + data2 = mostek_read(regs + MOSTEK_EEPROM); /* Read back the complement. */ + mostek_write(regs + MOSTEK_EEPROM, data1); /* Restore original value. */ return (data1 == data2); /* Was the write blocked? */ } @@ -211,17 +233,20 @@ static int __init has_low_battery(void) static void __init set_system_time(void) { unsigned int year, mon, day, hour, min, sec; - struct mostek48t02 *mregs; + unsigned long mregs = mstk48t02_regs; + u8 tmp; do_get_fast_time = do_gettimeofday; - mregs = mstk48t02_regs; if(!mregs) { prom_printf("Something wrong, clock regs not mapped yet.\n"); prom_halt(); } - mregs->creg |= MSTK_CREG_READ; + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); + sec = MSTK_REG_SEC(mregs); min = MSTK_REG_MIN(mregs); hour = MSTK_REG_HOUR(mregs); @@ -230,7 +255,10 @@ static void __init set_system_time(void) 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; + + tmp = mostek_read(mregs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(mregs + MOSTEK_CREG, tmp); } void __init clock_probe(void) @@ -315,19 +343,8 @@ void __init clock_probe(void) 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; + mstk48t59_regs = edev->resource[0].start; + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; break; } #endif @@ -338,22 +355,16 @@ void __init clock_probe(void) } if(model[5] == '0' && model[6] == '2') { - mstk48t02_regs = (struct mostek48t02 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t02_regs), - "clock", clk_reg[0].which_io, 0x0); + mstk48t02_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); } else if(model[5] == '0' && model[6] == '8') { - mstk48t08_regs = (struct mostek48t08 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t08_regs), - "clock", clk_reg[0].which_io, 0x0); - mstk48t02_regs = &mstk48t08_regs->regs; + mstk48t08_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t02_regs = mstk48t08_regs + MOSTEK_48T08_48T02; } else { - mstk48t59_regs = (struct mostek48t59 *) - sparc_alloc_io(clk_reg[0].phys_addr, - (void *) 0, sizeof(*mstk48t59_regs), - "clock", clk_reg[0].which_io, 0x0); - mstk48t02_regs = &mstk48t59_regs->regs; + mstk48t59_regs = (((u64)clk_reg[0].phys_addr) | + (((u64)clk_reg[0].which_io)<<32UL)); + mstk48t02_regs = mstk48t59_regs + MOSTEK_48T59_48T02; } break; } @@ -363,7 +374,7 @@ void __init clock_probe(void) prom_printf("NVRAM: Low battery voltage!\n"); /* Kick start the clock if it is completely stopped. */ - if (mstk48t02_regs->sec & MSTK_STOP) + if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) kick_start_clock(); set_system_time(); @@ -392,7 +403,7 @@ void __init time_init(void) init_timers(timer_interrupt, &clock); timer_tick_offset = clock / HZ; - timer_ticks_per_usec = clock / 1000000; + timer_ticks_per_usec_quotient = ((1UL<<32) / (clock / 1000020)); } static __inline__ unsigned long do_gettimeoffset(void) @@ -408,7 +419,7 @@ static __inline__ unsigned long do_gettimeoffset(void) : "r" (timer_tick_offset), "r" (timer_tick_compare) : "g1", "g2"); - return ticks / timer_ticks_per_usec; + return (ticks * timer_ticks_per_usec_quotient) >> 32UL; } /* This need not obtain the xtime_lock as it is coded in @@ -431,24 +442,22 @@ void do_gettimeofday(struct timeval *tv) or %g2, %lo(xtime), %g2 or %g1, %lo(timer_tick_compare), %g1 1: ldda [%g2] 0x24, %o4 - membar #LoadLoad | #MemIssue rd %tick, %o1 ldx [%g1], %g7 - membar #LoadLoad | #MemIssue ldda [%g2] 0x24, %o2 - membar #LoadLoad xor %o4, %o2, %o2 xor %o5, %o3, %o3 orcc %o2, %o3, %g0 bne,pn %xcc, 1b sethi %hi(lost_ticks), %o2 - sethi %hi(timer_ticks_per_usec), %o3 + sethi %hi(timer_ticks_per_usec_quotient), %o3 ldx [%o2 + %lo(lost_ticks)], %o2 add %g3, %o1, %o1 - ldx [%o3 + %lo(timer_ticks_per_usec)], %o3 + ldx [%o3 + %lo(timer_ticks_per_usec_quotient)], %o3 sub %o1, %g7, %o1 + mulx %o3, %o1, %o1 brz,pt %o2, 1f - udivx %o1, %o3, %o1 + srlx %o1, 32, %o1 sethi %hi(10000), %g2 or %g2, %lo(10000), %g2 add %o1, %g2, %o1 @@ -487,16 +496,23 @@ void do_settimeofday(struct timeval *tv) static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, mostek_minutes; - struct mostek48t02 *regs = mstk48t02_regs; + unsigned long regs = mstk48t02_regs; + u8 tmp; /* Not having a register set can lead to trouble. */ if (!regs) return -1; /* Read the current RTC minutes. */ - regs->creg |= MSTK_CREG_READ; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + mostek_minutes = MSTK_REG_MIN(regs); - regs->creg &= ~MSTK_CREG_READ; + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); /* * since we're only adjusting minutes and seconds, @@ -511,10 +527,16 @@ static int set_rtc_mmss(unsigned long nowtime) real_minutes %= 60; if (abs(real_minutes - mostek_minutes) < 30) { - regs->creg |= MSTK_CREG_WRITE; + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + MSTK_SET_REG_SEC(regs,real_seconds); MSTK_SET_REG_MIN(regs,real_minutes); - regs->creg &= ~MSTK_CREG_WRITE; + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); } else return -1; diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index 0dd40b538..fba910a55 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S @@ -1,9 +1,11 @@ -/* $Id: trampoline.S,v 1.9 1999/05/25 16:53:12 jj Exp $ +/* $Id: trampoline.S,v 1.10 1999/09/10 10:40:48 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> + #include <asm/head.h> #include <asm/asi.h> #include <asm/lsu.h> diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 86ee5b661..f4f2287df 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.60 1999/06/02 19:19:55 jj Exp $ +/* $Id: traps.c,v 1.62 1999/08/31 19:25:35 davem Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -147,12 +147,12 @@ void syscall_trace_entry(unsigned long g1, struct pt_regs *regs) if(i) printk(","); if(!sdp->arg_is_string[i]) { - if (current->tss.flags & SPARC_FLAG_32BIT) + if (current->thread.flags & SPARC_FLAG_32BIT) printk("%08x", (unsigned int)regs->u_regs[UREG_I0 + i]); else printk("%016lx", regs->u_regs[UREG_I0 + i]); } else { - if (current->tss.flags & SPARC_FLAG_32BIT) + if (current->thread.flags & SPARC_FLAG_32BIT) strncpy_from_user(scall_strbuf, (char *)(regs->u_regs[UREG_I0 + i] & 0xffffffff), 512); @@ -178,7 +178,7 @@ unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs) } #endif /* SYSCALL_TRACING */ -#if 0 +#if 1 void rtrap_check(struct pt_regs *regs) { register unsigned long pgd_phys asm("o1"); @@ -219,7 +219,7 @@ void rtrap_check(struct pt_regs *regs) if((pgd_phys != __pa(current->mm->pgd)) || ((pgd_cache != 0) && - (pgd_cache != pgd_val(current->mm->pgd[0]))) || + (pgd_cache != pgd_val(current->mm->pgd[0])<<11UL)) || (g1_or_g3 != (0xfffffffe00000000UL | 0x0000000000000018UL)) || #define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) #define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) @@ -228,18 +228,17 @@ void rtrap_check(struct pt_regs *regs) #undef KERN_LOWBITS ((ctx != (current->mm->context & 0x3ff)) || (ctx == 0) || - (current->tss.ctx != ctx))) { + (CTX_HWBITS(current->mm->context) != ctx))) { printk("SHIT[%s:%d]: " - "(PP[%016lx] CACH[%016lx] CTX[%x] g1g3[%016lx] g2[%016lx]) ", + "(PP[%016lx] CACH[%016lx] CTX[%lx] g1g3[%016lx] g2[%016lx]) ", current->comm, current->pid, pgd_phys, pgd_cache, ctx, g1_or_g3, g2); printk("SHIT[%s:%d]: " - "[PP[%016lx] CACH[%016lx] CTX[%x:%x]] PC[%016lx:%016lx]\n", + "[PP[%016lx] CACH[%016lx] CTX[%lx]] PC[%016lx:%016lx]\n", current->comm, current->pid, __pa(current->mm->pgd), pgd_val(current->mm->pgd[0]), current->mm->context & 0x3ff, - current->tss.ctx, regs->tpc, regs->tnpc); show_regs(regs); #if 1 @@ -262,8 +261,8 @@ void bad_trap (struct pt_regs *regs, long lvl) } if (regs->tstate & TSTATE_PRIV) die_if_kernel ("Kernel bad trap", regs); - current->tss.sig_desc = SUBSIG_BADTRAP(lvl - 0x100); - current->tss.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_BADTRAP(lvl - 0x100); + current->thread.sig_address = regs->tpc; force_sig(SIGILL, current); unlock_kernel (); } @@ -289,8 +288,8 @@ void instruction_access_exception (struct pt_regs *regs, #endif die_if_kernel("Iax", regs); } - current->tss.sig_desc = SUBSIG_ILLINST; - current->tss.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_ILLINST; + current->thread.sig_address = regs->tpc; force_sig(SIGILL, current); unlock_kernel(); } @@ -396,14 +395,132 @@ void do_iae(struct pt_regs *regs) unlock_kernel(); } +static char ecc_syndrome_table[] = { + 0x4c, 0x40, 0x41, 0x48, 0x42, 0x48, 0x48, 0x49, + 0x43, 0x48, 0x48, 0x49, 0x48, 0x49, 0x49, 0x4a, + 0x44, 0x48, 0x48, 0x20, 0x48, 0x39, 0x4b, 0x48, + 0x48, 0x25, 0x31, 0x48, 0x28, 0x48, 0x48, 0x2c, + 0x45, 0x48, 0x48, 0x21, 0x48, 0x3d, 0x04, 0x48, + 0x48, 0x4b, 0x35, 0x48, 0x2d, 0x48, 0x48, 0x29, + 0x48, 0x00, 0x01, 0x48, 0x0a, 0x48, 0x48, 0x4b, + 0x0f, 0x48, 0x48, 0x4b, 0x48, 0x49, 0x49, 0x48, + 0x46, 0x48, 0x48, 0x2a, 0x48, 0x3b, 0x27, 0x48, + 0x48, 0x4b, 0x33, 0x48, 0x22, 0x48, 0x48, 0x2e, + 0x48, 0x19, 0x1d, 0x48, 0x1b, 0x4a, 0x48, 0x4b, + 0x1f, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48, + 0x48, 0x4b, 0x24, 0x48, 0x07, 0x48, 0x48, 0x36, + 0x4b, 0x48, 0x48, 0x3e, 0x48, 0x30, 0x38, 0x48, + 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x16, 0x48, + 0x48, 0x12, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b, + 0x47, 0x48, 0x48, 0x2f, 0x48, 0x3f, 0x4b, 0x48, + 0x48, 0x06, 0x37, 0x48, 0x23, 0x48, 0x48, 0x2b, + 0x48, 0x05, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x32, + 0x26, 0x48, 0x48, 0x3a, 0x48, 0x34, 0x3c, 0x48, + 0x48, 0x11, 0x15, 0x48, 0x13, 0x4a, 0x48, 0x4b, + 0x17, 0x48, 0x4a, 0x4b, 0x48, 0x4b, 0x4b, 0x48, + 0x49, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x1e, 0x48, + 0x48, 0x1a, 0x4b, 0x48, 0x49, 0x48, 0x48, 0x4b, + 0x48, 0x08, 0x0d, 0x48, 0x02, 0x48, 0x48, 0x49, + 0x03, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x4b, 0x48, + 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x10, 0x48, + 0x48, 0x14, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b, + 0x49, 0x48, 0x48, 0x49, 0x48, 0x4b, 0x18, 0x48, + 0x48, 0x1c, 0x4b, 0x48, 0x4b, 0x48, 0x48, 0x4b, + 0x4a, 0x0c, 0x09, 0x48, 0x0e, 0x48, 0x48, 0x4b, + 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a +}; + +/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status + * in the following format. The AFAR is left as is, with + * reserved bits cleared, and is a raw 40-bit physical + * address. + */ +#define CE_STATUS_UDBH_UE (1UL << (43 + 9)) +#define CE_STATUS_UDBH_CE (1UL << (43 + 8)) +#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43) +#define CE_STATUS_UDBH_SHIFT 43 +#define CE_STATUS_UDBL_UE (1UL << (33 + 9)) +#define CE_STATUS_UDBL_CE (1UL << (33 + 8)) +#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33) +#define CE_STATUS_UDBL_SHIFT 33 +#define CE_STATUS_AFSR_MASK (0x1ffffffffUL) +#define CE_STATUS_AFSR_ME (1UL << 32) +#define CE_STATUS_AFSR_PRIV (1UL << 31) +#define CE_STATUS_AFSR_ISAP (1UL << 30) +#define CE_STATUS_AFSR_ETP (1UL << 29) +#define CE_STATUS_AFSR_IVUE (1UL << 28) +#define CE_STATUS_AFSR_TO (1UL << 27) +#define CE_STATUS_AFSR_BERR (1UL << 26) +#define CE_STATUS_AFSR_LDP (1UL << 25) +#define CE_STATUS_AFSR_CP (1UL << 24) +#define CE_STATUS_AFSR_WP (1UL << 23) +#define CE_STATUS_AFSR_EDP (1UL << 22) +#define CE_STATUS_AFSR_UE (1UL << 21) +#define CE_STATUS_AFSR_CE (1UL << 20) +#define CE_STATUS_AFSR_ETS (0xfUL << 16) +#define CE_STATUS_AFSR_ETS_SHIFT 16 +#define CE_STATUS_AFSR_PSYND (0xffffUL << 0) +#define CE_STATUS_AFSR_PSYND_SHIFT 0 + +/* Layout of Ecache TAG Parity Syndrome of AFSR */ +#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */ +#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */ +#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */ +#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */ + +static char *syndrome_unknown = "<Unknown>"; + +asmlinkage void cee_log(unsigned long ce_status, + unsigned long afar, + struct pt_regs *regs) +{ + char memmod_str[64]; + char *p; + unsigned short scode, udb_reg; + + printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " + "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", + smp_processor_id(), + (ce_status & CE_STATUS_AFSR_MASK), + afar, + ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL), + ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL)); + + udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL); + if (udb_reg & (1 << 8)) { + scode = ecc_syndrome_table[udb_reg & 0xff]; + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) + p = syndrome_unknown; + else + p = memmod_str; + printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] " + "Memory Module \"%s\"\n", + smp_processor_id(), scode, p); + } + + udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); + if (udb_reg & (1 << 8)) { + scode = ecc_syndrome_table[udb_reg & 0xff]; + if (prom_getunumber(scode, afar, + memmod_str, sizeof(memmod_str)) == -1) + p = syndrome_unknown; + else + p = memmod_str; + printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] " + "Memory Module \"%s\"\n", + smp_processor_id(), scode, p); + } +} + void do_fpe_common(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) { regs->tpc = regs->tnpc; regs->tnpc += 4; } else { - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = SUBSIG_FPERROR; + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_FPERROR; send_sig(SIGFPE, current, 1); } } @@ -411,7 +528,7 @@ void do_fpe_common(struct pt_regs *regs) void do_fpieee(struct pt_regs *regs) { #ifdef DEBUG_FPU - printk("fpieee %016lx\n", current->tss.xfsr[0]); + printk("fpieee %016lx\n", current->thread.xfsr[0]); #endif do_fpe_common(regs); } @@ -423,7 +540,7 @@ void do_fpother(struct pt_regs *regs) struct fpustate *f = FPUSTATE; int ret = 0; - switch ((current->tss.xfsr[0] & 0x1c000)) { + switch ((current->thread.xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ ret = do_mathemu(regs, f); @@ -431,7 +548,7 @@ void do_fpother(struct pt_regs *regs) } if (ret) return; #ifdef DEBUG_FPU - printk("fpother %016lx\n", current->tss.xfsr[0]); + printk("fpother %016lx\n", current->thread.xfsr[0]); #endif do_fpe_common(regs); } @@ -440,8 +557,8 @@ void do_tof(struct pt_regs *regs) { if(regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = SUBSIG_TAG; /* as good as any */ + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_TAG; /* as good as any */ send_sig(SIGEMT, current, 1); } @@ -540,7 +657,7 @@ void do_illegal_instruction(struct pt_regs *regs) if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); - if(current->tss.flags & SPARC_FLAG_32BIT) + if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ { @@ -551,8 +668,8 @@ void do_illegal_instruction(struct pt_regs *regs) return; } } - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_ILLINST; + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_ILLINST; send_sig(SIGILL, current, 1); } @@ -565,23 +682,23 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr); } else { - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGBUS, current, 1); } } void do_privop(struct pt_regs *regs) { - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); } void do_privact(struct pt_regs *regs) { - current->tss.sig_address = regs->tpc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = regs->tpc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); } @@ -590,8 +707,8 @@ void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long n { if(tstate & TSTATE_PRIV) die_if_kernel("Penguin instruction from Penguin mode??!?!", regs); - current->tss.sig_address = pc; - current->tss.sig_desc = SUBSIG_PRIVINST; + current->thread.sig_address = pc; + current->thread.sig_desc = SUBSIG_PRIVINST; send_sig(SIGILL, current, 1); } @@ -727,4 +844,11 @@ void cache_flush_trap(struct pt_regs *regs) void trap_init(void) { + /* Attach to the address space of init_task. */ + atomic_inc(&init_mm.mm_count); + current->active_mm = &init_mm; + + /* NOTE: Other cpus have this done as they are started + * up on SMP. + */ } diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 3a9fdf4d2..b378756c0 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.28 1999/03/29 12:38:10 jj Exp $ +/* $Id: ttable.S,v 1.29 1999/08/31 19:25:37 davem Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -57,7 +57,7 @@ tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTRAP(0x5e) BTRAP(0x5f) tl0_ivec: TRAP_IVEC tl0_paw: TRAP(do_paw) tl0_vaw: TRAP(do_vaw) -tl0_cee: TRAP(do_cee) +tl0_cee: TRAP_NOSAVE(cee_trap) tl0_iamiss: #include "itlb_base.S" tl0_damiss: @@ -202,7 +202,7 @@ tl1_resv05c: BTRAPTL1(0x5c) BTRAPTL1(0x5d) BTRAPTL1(0x5e) BTRAPTL1(0x5f) tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) -tl1_cee: TRAPTL1(do_cee_tl1) +tl1_cee: TRAPTL1_CEE tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) tl1_damiss: #include "dtlb_backend.S" diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 3b813f415..792334336 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.16 1999/05/25 16:53:15 jj Exp $ +/* $Id: unaligned.c,v 1.18 1999/08/02 08:39:44 davem Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -70,7 +70,7 @@ static inline int decode_access_size(unsigned int insn) return 2; else { printk("Impossible unaligned trap. insn=%08x\n", insn); - die_if_kernel("Byte sized unaligned access?!?!", current->tss.kregs); + die_if_kernel("Byte sized unaligned access?!?!", current->thread.kregs); } } @@ -117,7 +117,7 @@ static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs) struct reg_window *win; win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); value = win->locals[reg - 16]; - } else if (current->tss.flags & SPARC_FLAG_32BIT) { + } else if (current->thread.flags & SPARC_FLAG_32BIT) { struct reg_window32 *win32; win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); get_user(value, &win32->locals[reg - 16]); @@ -137,7 +137,7 @@ static unsigned long *fetch_reg_addr(unsigned int reg, struct pt_regs *regs) struct reg_window *win; win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); return &win->locals[reg - 16]; - } else if (current->tss.flags & SPARC_FLAG_32BIT) { + } else if (current->thread.flags & SPARC_FLAG_32BIT) { struct reg_window32 *win32; win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); return (unsigned long *)&win32->locals[reg - 16]; @@ -164,10 +164,10 @@ static inline unsigned long compute_effective_address(struct pt_regs *regs, } } -/* This is just to make gcc think panic does return... */ -static void unaligned_panic(char *str) +/* This is just to make gcc think die_if_kernel does return... */ +static void unaligned_panic(char *str, struct pt_regs *regs) { - panic(str); + die_if_kernel(str, regs); } #define do_integer_load(dest_reg, size, saddr, is_signed, asi, errh) ({ \ @@ -380,7 +380,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u if(!ok_for_kernel(insn) || dir == both) { printk("Unsupported unaligned load/store trap for kernel at <%016lx>.\n", regs->tpc); - unaligned_panic("Wheee. Kernel does fpu/atomic unaligned load/store."); + unaligned_panic("Kernel does fpu/atomic unaligned load/store.", regs); __asm__ __volatile__ ("\n" "kernel_unaligned_trap_fault:\n\t" @@ -453,7 +453,7 @@ int handle_popc(u32 insn, struct pt_regs *regs) if (rd) regs->u_regs[rd] = ret; } else { - if (current->tss.flags & SPARC_FLAG_32BIT) { + if (current->thread.flags & SPARC_FLAG_32BIT) { struct reg_window32 *win32; win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); put_user(ret, &win32->locals[rd - 16]); @@ -480,9 +480,9 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) int flag = (freg < 32) ? FPRS_DL : FPRS_DU; save_and_clear_fpu(); - current->tss.xfsr[0] &= ~0x1c000; + current->thread.xfsr[0] &= ~0x1c000; if (freg & 3) { - current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; + current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; do_fpother(regs); return 0; } @@ -490,7 +490,7 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) /* STQ */ u64 first = 0, second = 0; - if (current->tss.fpsaved[0] & flag) { + if (current->thread.fpsaved[0] & flag) { first = *(u64 *)&f->regs[freg]; second = *(u64 *)&f->regs[freg+2]; } @@ -565,18 +565,18 @@ int handle_ldf_stq(u32 insn, struct pt_regs *regs) break; } } - if (!(current->tss.fpsaved[0] & FPRS_FEF)) { - current->tss.fpsaved[0] = FPRS_FEF; - current->tss.gsr[0] = 0; + if (!(current->thread.fpsaved[0] & FPRS_FEF)) { + current->thread.fpsaved[0] = FPRS_FEF; + current->thread.gsr[0] = 0; } - if (!(current->tss.fpsaved[0] & flag)) { + if (!(current->thread.fpsaved[0] & flag)) { if (freg < 32) memset(f->regs, 0, 32*sizeof(u32)); else memset(f->regs+32, 0, 32*sizeof(u32)); } memcpy(f->regs + freg, data, size * 4); - current->tss.fpsaved[0] |= flag; + current->thread.fpsaved[0] |= flag; } advance(regs); return 1; @@ -609,7 +609,7 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr if(tstate & TSTATE_PRIV) die_if_kernel("lddfmna from kernel", regs); - if(current->tss.flags & SPARC_FLAG_32BIT) + if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { asi = sfsr >> 16; @@ -629,18 +629,18 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr if (asi & 0x8) /* Little */ value = __swab64p(&value); flag = (freg < 32) ? FPRS_DL : FPRS_DU; - if (!(current->tss.fpsaved[0] & FPRS_FEF)) { - current->tss.fpsaved[0] = FPRS_FEF; - current->tss.gsr[0] = 0; + if (!(current->thread.fpsaved[0] & FPRS_FEF)) { + current->thread.fpsaved[0] = FPRS_FEF; + current->thread.gsr[0] = 0; } - if (!(current->tss.fpsaved[0] & flag)) { + if (!(current->thread.fpsaved[0] & flag)) { if (freg < 32) memset(f->regs, 0, 32*sizeof(u32)); else memset(f->regs+32, 0, 32*sizeof(u32)); } *(u64 *)(f->regs + freg) = value; - current->tss.fpsaved[0] |= flag; + current->thread.fpsaved[0] |= flag; } else { daex: data_access_exception(regs); return; @@ -661,7 +661,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr if(tstate & TSTATE_PRIV) die_if_kernel("stdfmna from kernel", regs); - if(current->tss.flags & SPARC_FLAG_32BIT) + if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); @@ -672,7 +672,7 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr (asi < ASI_P)) goto daex; save_and_clear_fpu(); - if (current->tss.fpsaved[0] & flag) + if (current->thread.fpsaved[0] & flag) value = *(u64 *)&f->regs[freg]; switch (asi) { case ASI_P: diff --git a/arch/sparc64/kernel/winfixup.S b/arch/sparc64/kernel/winfixup.S index 5bf82db59..67653fef1 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.27 1998/09/25 01:09:14 davem Exp $ +/* $Id: winfixup.S,v 1.28 1999/07/30 09:35:34 davem Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -95,56 +95,56 @@ fill_fixup: * do not touch %g7 or %g2 so we handle the two cases fine. */ spill_fixup: - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1 sll %g1, 3, %g3 add %g6, %g3, %g3 - stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs] sll %g1, 7, %g3 bne,pt %xcc, 1f add %g6, %g3, %g3 - stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - - stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] - stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] - - stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] - stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] - stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] + stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + + stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48] + + stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60] + stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68] + stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70] b,pt %xcc, 2f - stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] -1: stw %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - - stw %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x04] - stw %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - stw %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x0c] - stw %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stw %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x14] - stw %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - stw %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x1c] - stw %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - - stw %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x24] - stw %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stw %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x2c] - stw %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stw %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x34] - stw %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - stw %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x3c] + stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78] +1: stw %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + + stw %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x04] + stw %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + stw %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x0c] + stw %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + stw %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x14] + stw %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + stw %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x1c] + stw %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + + stw %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x24] + stw %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + stw %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x2c] + stw %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + stw %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x34] + stw %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] + stw %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x3c] 2: add %g1, 1, %g1 - sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] + stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 saved @@ -208,47 +208,47 @@ fill_fixup_mna: b,pt %xcc, rtrap nop ! yes, the nop is correct spill_fixup_mna: - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1 sll %g1, 3, %g3 add %g6, %g3, %g3 - stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs] sll %g1, 7, %g3 bne,pt %xcc, 1f add %g6, %g3, %g3 - stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - - stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] - stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] - stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] - stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] - stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - - stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] - stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + + stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60] + + stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68] + stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70] + stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f add %g1, 1, %g1 -1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - - std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] +1: std %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + std %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + std %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + + std %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + std %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + std %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + std %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + std %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] add %g1, 1, %g1 -2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] +2: stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 @@ -315,47 +315,47 @@ fill_fixup_dax: b,pt %xcc, rtrap nop ! yes, the nop is correct spill_fixup_dax: - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_flags], %g1 andcc %g1, SPARC_FLAG_32BIT, %g0 - lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_w_saved], %g1 sll %g1, 3, %g3 add %g6, %g3, %g3 - stx %sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs] + stx %sp, [%g3 + AOFF_task_thread + AOFF_thread_rwbuf_stkptrs] sll %g1, 7, %g3 bne,pt %xcc, 1f add %g6, %g3, %g3 - stx %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - stx %l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - stx %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - stx %l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - stx %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - - stx %l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - stx %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - stx %l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] - stx %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40] - stx %i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48] - stx %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50] - stx %i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58] - stx %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60] - - stx %i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68] - stx %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70] - stx %i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78] + stx %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + stx %l1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + stx %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + stx %l3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + stx %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + + stx %l5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + stx %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + stx %l7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] + stx %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x40] + stx %i1, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x48] + stx %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x50] + stx %i3, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x58] + stx %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x60] + + stx %i5, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x68] + stx %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x70] + stx %i7, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x78] b,pt %xcc, 2f add %g1, 1, %g1 -1: std %l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00] - std %l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08] - std %l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10] - - std %l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18] - std %i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20] - std %i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28] - std %i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30] - std %i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38] +1: std %l0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x00] + std %l2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x08] + std %l4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x10] + + std %l6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x18] + std %i0, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x20] + std %i2, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x28] + std %i4, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x30] + std %i6, [%g3 + AOFF_task_thread + AOFF_thread_reg_window + 0x38] add %g1, 1, %g1 -2: sth %g1, [%g6 + AOFF_task_tss + AOFF_thread_w_saved] +2: stb %g1, [%g6 + AOFF_task_thread + AOFF_thread_w_saved] rdpr %tstate, %g1 andcc %g1, TSTATE_PRIV, %g0 diff --git a/arch/sparc64/lib/PeeCeeI.c b/arch/sparc64/lib/PeeCeeI.c index 6677f581a..56c005dfe 100644 --- a/arch/sparc64/lib/PeeCeeI.c +++ b/arch/sparc64/lib/PeeCeeI.c @@ -1,4 +1,4 @@ -/* $Id: PeeCeeI.c,v 1.3 1997/08/28 23:59:52 davem Exp $ +/* $Id: PeeCeeI.c,v 1.4 1999/09/06 01:17:35 davem Exp $ * PeeCeeI.c: The emerging standard... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -9,6 +9,7 @@ #ifdef CONFIG_PCI #include <asm/io.h> +#include <asm/byteorder.h> void outsb(unsigned long addr, const void *src, unsigned long count) { @@ -21,25 +22,29 @@ void outsb(unsigned long addr, const void *src, unsigned long count) void outsw(unsigned long addr, const void *src, unsigned long count) { if(count) { - const u16 *ps = src; - const u32 *pi; + u16 *ps = (u16 *)src; + u32 *pi; if(((u64)src) & 0x2) { - outw(*ps++, addr); + u16 val = le16_to_cpup(ps); + outw(val, addr); + ps++; count--; } - pi = (const u32 *)ps; + pi = (u32 *)ps; while(count >= 2) { - u32 w; + u32 w = le32_to_cpup(pi); - w = *pi++; + pi++; + outw(w >> 0, addr); outw(w >> 16, addr); - outw(w, addr); count -= 2; } - ps = (const u16 *)pi; - if(count) - outw(*ps, addr); + ps = (u16 *)pi; + if(count) { + u16 val = le16_to_cpup(ps); + outw(val, addr); + } } } @@ -47,60 +52,71 @@ 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); + u32 *p = (u32 *)src; + while(count--) { + u32 val = cpu_to_le32p(p); + outl(val, addr); + p++; + } } else { - const u8 *pb; - const u16 *ps = src; + u8 *pb; + u16 *ps = (u16 *)src; u32 l = 0, l2; - const u32 *pi; + u32 *pi; switch(((u64)src) & 0x3) { case 0x2: count -= 1; - l = *ps++; - pi = (const u32 *)ps; + l = cpu_to_le16p(ps) << 16; + ps++; + pi = (u32 *)ps; while(count--) { - l2 = *pi++; - outl(((l <<16) | (l2 >> 16)), addr); + l2 = cpu_to_le32p(pi); + pi++; + outl(((l >> 16) | (l2 << 16)), addr); l = l2; } - ps = (const u16 *)pi; - outl(((l << 16) | (*ps >> 16)), addr); + ps = (u16 *)pi; + l2 = cpu_to_le16p(ps); + outl(((l >> 16) | (l2 << 16)), addr); break; case 0x1: count -= 1; - pb = src; - l = (*pb++ << 16); - ps = (const u16 *)pb; - l |= *ps++; - pi = (const u32 *)ps; + pb = (u8 *)src; + l = (*pb++ << 8); + ps = (u16 *)pb; + l2 = cpu_to_le16p(ps); + ps++; + l |= (l2 << 16); + pi = (u32 *)ps; while(count--) { - l2 = *pi++; - outl(((l << 8) | (l2 >> 24)), addr); + l2 = cpu_to_le32p(pi); + pi++; + outl(((l >> 8) | (l2 << 24)), addr); l = l2; } - pb = (const u8 *)pi; - outl(((l << 8) | (*pb >> 24)), addr); + pb = (u8 *)pi; + outl(((l >> 8) | (*pb << 24)), addr); break; case 0x3: count -= 1; - pb = src; - l = (*pb++ >> 24); - pi = (const u32 *)pb; + pb = (u8 *)src; + l = (*pb++ << 24); + pi = (u32 *)pb; while(count--) { - l2 = *pi++; - outl(((l << 24) | (l2 >> 8)), addr); + l2 = cpu_to_le32p(pi); + 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); + ps = (u16 *)pi; + l2 = cpu_to_le16p(ps); + ps++; + pb = (u8 *)ps; + l2 |= (*pb << 16); + outl(((l >> 24) | (l2 << 8)), addr); break; } } @@ -122,7 +138,7 @@ void insb(unsigned long addr, void *dst, unsigned long count) w = (inb(addr) << 24); w |= (inb(addr) << 16); w |= (inb(addr) << 8); - w |= inb(addr); + w |= (inb(addr) << 0); *pi++ = w; count -= 4; } @@ -139,21 +155,21 @@ void insw(unsigned long addr, void *dst, unsigned long count) u32 *pi; if(((unsigned long)ps) & 0x2) { - *ps++ = inw(addr); + *ps++ = le16_to_cpu(inw(addr)); count--; } pi = (u32 *)ps; while(count >= 2) { u32 w; - w = (inw(addr) << 16); - w |= inw(addr); + w = (le16_to_cpu(inw(addr)) << 16); + w |= (le16_to_cpu(inw(addr)) << 0); *pi++ = w; count -= 2; } ps = (u16 *)pi; if(count) - *ps = inw(addr); + *ps = le16_to_cpu(inw(addr)); } } @@ -163,7 +179,7 @@ void insl(unsigned long addr, void *dst, unsigned long count) if((((unsigned long)dst) & 0x3) == 0) { u32 *pi = dst; while(count--) - *pi++ = inl(addr); + *pi++ = le32_to_cpu(inl(addr)); } else { u32 l = 0, l2, *pi; u16 *ps; @@ -173,47 +189,48 @@ void insl(unsigned long addr, void *dst, unsigned long count) case 0x2: ps = dst; count -= 1; - l = inl(addr); - *ps++ = (l >> 16); + l = le32_to_cpu(inl(addr)); + *ps++ = l; pi = (u32 *)ps; while(count--) { - l2 = inl(addr); + l2 = le32_to_cpu(inl(addr)); *pi++ = (l << 16) | (l2 >> 16); l = l2; } ps = (u16 *)pi; - *ps = (l << 16); + *ps = l; break; case 0x1: pb = dst; count -= 1; - *pb++ = (l >> 24); + l = le32_to_cpu(inl(addr)); + *pb++ = l >> 24; ps = (u16 *)pb; - *ps++ = (l >> 8); + *ps++ = ((l >> 8) & 0xffff); pi = (u32 *)ps; while(count--) { - l2 = inl(addr); - *pi++ = ((l << 24) | (l2 >> 8)); + l2 = le32_to_cpu(inl(addr)); + *pi++ = (l << 24) | (l2 >> 8); l = l2; } pb = (u8 *)pi; - *pb = (l >> 8); + *pb = l; break; case 0x3: pb = (u8 *)dst; count -= 1; - l = inl(addr); + l = le32_to_cpu(inl(addr)); *pb++ = l >> 24; pi = (u32 *)pb; while(count--) { - l2 = inl(addr); - *pi++ = ((l >> 24) | (l2 << 8)); + l2 = le32_to_cpu(inl(addr)); + *pi++ = (l << 8) | (l2 >> 24); l = l2; } ps = (u16 *)pi; - *ps++ = l >> 8; + *ps++ = ((l >> 8) & 0xffff); pb = (u8 *)ps; *pb = l; break; diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index bb1d81acd..57cf6b0f1 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.20 1999/05/25 16:52:57 jj Exp $ +/* $Id: VIScopy.S,v 1.21 1999/07/30 09:35:35 davem Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -29,19 +29,19 @@ #include <asm/asm_offsets.h> #define FPU_CLEAN_RETL \ - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1; \ + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ VISExit \ clr %o0; \ retl; \ wr %o1, %g0, %asi; #define FPU_RETL \ - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1; \ + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ VISExit \ clr %o0; \ retl; \ wr %o1, %g0, %asi; #define NORMAL_RETL \ - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o1; \ + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o1; \ clr %o0; \ retl; \ wr %o1, %g0, %asi; @@ -1009,7 +1009,7 @@ VIScopyfixup_ret: /* If this is copy_from_user(), zero out the rest of the * kernel buffer. */ - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %o4 + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %o4 andcc asi_src, 0x1, %g0 be,pt %icc, 1f VISExit diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S index 0326ff057..aad5d941a 100644 --- a/arch/sparc64/lib/VIScsum.S +++ b/arch/sparc64/lib/VIScsum.S @@ -1,4 +1,4 @@ -/* $Id: VIScsum.S,v 1.4 1999/05/25 16:53:00 jj Exp $ +/* $Id: VIScsum.S,v 1.5 1999/07/30 09:35:36 davem Exp $ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc * Visual Instruction Set. * @@ -341,7 +341,7 @@ csum_partial: DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14) END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) #ifdef __KERNEL__ - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %g7 + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g7 #endif and %o1, 0x3f, %o1 /* IEU0 Group */ #ifdef __KERNEL__ diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S index a189d0db6..2254ba5c5 100644 --- a/arch/sparc64/lib/VISsave.S +++ b/arch/sparc64/lib/VISsave.S @@ -1,4 +1,4 @@ -/* $Id: VISsave.S,v 1.3 1998/10/21 10:36:39 jj Exp $ +/* $Id: VISsave.S,v 1.4 1999/07/30 09:35:37 davem Exp $ * VISsave.S: Code for saving FPU register state for * VIS routines. One should not call this directly, * but use macros provided in <asm/visasm.h>. @@ -19,35 +19,35 @@ .align 32 VISenter: - ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1 brnz,a,pn %g1, 1f cmp %g1, 1 - stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] - stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr] + stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved] + stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] 9: jmpl %g7 + %g0, %g0 nop 1: bne,pn %icc, 2f srl %g1, 1, %g1 -vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 - stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr] +vis1: ldub [%g6 + AOFF_task_thread + AOFF_thread_fpsaved], %g3 + stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] or %g3, %o5, %g3 - stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] + stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g3 clr %g1 ba,pt %xcc, 3f - stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_gsr] + stb %g3, [%g6 + AOFF_task_thread + AOFF_thread_gsr] 2: add %g6, %g1, %g3 cmp %o5, FPRS_DU be,pn %icc, 6f sll %g1, 3, %g1 - stb %o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved] + stb %o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g2 - stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr] + stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] add %g6, %g1, %g2 - stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr] + stx %fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr] sll %g1, 5, %g1 3: andcc %o5, FPRS_DL|FPRS_DU, %g0 be,pn %icc, 9b @@ -69,10 +69,10 @@ vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 jmpl %g7 + %g0, %g0 nop -6: ldub [%g3 + AOFF_task_tss + AOFF_thread_fpsaved], %o5 +6: ldub [%g3 + AOFF_task_thread + AOFF_thread_fpsaved], %o5 or %o5, FPRS_DU, %o5 add %g6, AOFF_task_fpregs+0x80, %g2 - stb %o5, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved] + stb %o5, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved] sll %g1, 5, %g1 add %g6, AOFF_task_fpregs+0xc0, %g3 @@ -87,11 +87,11 @@ vis1: ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g3 .align 32 VISenterhalf: - ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %g1 + ldub [%g6 + AOFF_task_thread + AOFF_thread_fpdepth], %g1 brnz,a,pn %g1, 1f cmp %g1, 1 - stb %g0, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] - stx %fsr, [%g6 + AOFF_task_tss + AOFF_thread_xfsr] + stb %g0, [%g6 + AOFF_task_thread + AOFF_thread_fpsaved] + stx %fsr, [%g6 + AOFF_task_thread + AOFF_thread_xfsr] clr %o5 jmpl %g7 + %g0, %g0 wr %g0, FPRS_FEF, %fprs @@ -103,12 +103,12 @@ VISenterhalf: 2: addcc %g6, %g1, %g3 sll %g1, 3, %g1 andn %o5, FPRS_DU, %g2 - stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved] + stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_fpsaved] rd %gsr, %g2 - stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr] + stb %g2, [%g3 + AOFF_task_thread + AOFF_thread_gsr] add %g6, %g1, %g2 - stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr] + stx %fsr, [%g2 + AOFF_task_thread + AOFF_thread_xfsr] sll %g1, 5, %g1 3: andcc %o5, FPRS_DL, %g0 be,pn %icc, 4f diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S index 3c0dce16a..cac9d15dd 100644 --- a/arch/sparc64/lib/atomic.S +++ b/arch/sparc64/lib/atomic.S @@ -1,4 +1,4 @@ -/* $Id: atomic.S,v 1.1 1999/07/03 22:11:04 davem Exp $ +/* $Id: atomic.S,v 1.2 1999/08/23 05:15:58 davem Exp $ * atomic.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -9,7 +9,10 @@ .text .align 64 + .globl atomic_impl_begin, atomic_impl_end + .globl __atomic_add +atomic_impl_begin: __atomic_add: lduw [%g1], %g5 add %g5, %g2, %g7 @@ -30,3 +33,4 @@ __atomic_sub: nop jmpl %g3 + 8, %g0 sub %g7, %g2, %g2 +atomic_impl_end: diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index 840839c95..202b57270 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,4 +1,4 @@ -/* $Id: blockops.S,v 1.17 1999/05/25 16:52:52 jj Exp $ +/* $Id: blockops.S,v 1.18 1999/07/30 09:35:37 davem Exp $ * blockops.S: UltraSparc block zero optimized routines. * * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) @@ -29,7 +29,7 @@ .type copy_page,@function copy_page: /* %o0=dest, %o1=src */ VISEntry - ldx [%g6 + AOFF_task_mm], %o2 + ldx [%g6 + AOFF_task_active_mm], %o2 sub %o0, %g4, %g1 sethi %uhi(_PAGE_VALID), %g3 sub %o1, %g4, %g2 @@ -107,7 +107,7 @@ copy_page: /* %o0=dest, %o1=src */ .type clear_page,@function clear_page: /* %o0=dest */ VISEntryHalf - ldx [%g6 + AOFF_task_mm], %o2 + ldx [%g6 + AOFF_task_active_mm], %o2 sub %o0, %g4, %g1 sethi %uhi(_PAGE_VALID), %g3 sllx %g3, 32, %g3 diff --git a/arch/sparc64/lib/checksum.S b/arch/sparc64/lib/checksum.S index d720bb55e..07d10ba42 100644 --- a/arch/sparc64/lib/checksum.S +++ b/arch/sparc64/lib/checksum.S @@ -266,7 +266,7 @@ cpc_end: .globl cpc_handler cpc_handler: ldx [%sp + 0x7ff + 128], %g1 - ldub [%g6 + AOFF_task_tss + AOFF_thread_current_ds], %g3 + ldub [%g6 + AOFF_task_thread + AOFF_thread_current_ds], %g3 sub %g0, EFAULT, %g2 brnz,a,pt %g1, 1f st %g2, [%g1] diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c index 69286c4b7..315724ec3 100644 --- a/arch/sparc64/lib/debuglocks.c +++ b/arch/sparc64/lib/debuglocks.c @@ -1,4 +1,4 @@ -/* $Id: debuglocks.c,v 1.2 1998/10/13 09:07:27 davem Exp $ +/* $Id: debuglocks.c,v 1.3 1999/09/10 10:40:50 davem Exp $ * debuglocks.c: Debugging versions of SMP locking primitives. * * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) @@ -6,8 +6,8 @@ #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/spinlock.h> #include <asm/system.h> -#include <asm/spinlock.h> #ifdef __SMP__ diff --git a/arch/sparc64/lib/rwlock.S b/arch/sparc64/lib/rwlock.S index cee94eef0..74360bf68 100644 --- a/arch/sparc64/lib/rwlock.S +++ b/arch/sparc64/lib/rwlock.S @@ -1,4 +1,4 @@ -/* $Id: rwlock.S,v 1.1 1999/07/03 22:11:06 davem Exp $ +/* $Id: rwlock.S,v 1.2 1999/08/23 05:15:58 davem Exp $ * rwlocks.S: These things are too big to do inline. * * Copyright (C) 1999 David S. Miller (davem@redhat.com) @@ -7,10 +7,13 @@ .text .align 64 + .globl rwlock_impl_begin, rwlock_impl_end + /* The non-contention read lock usage is 2 cache lines. */ .globl __read_lock, __read_unlock /* g1=lock, g3=retpc, g5/g7=scratch */ +rwlock_impl_begin: __read_lock: ldsw [%g1], %g5 brlz,pn %g5, __read_wait_for_writer @@ -78,4 +81,5 @@ __write_lock: be,pn %icc, 99b membar #LoadLoad b,a,pt %xcc, 99b +rwlock_impl_end: diff --git a/arch/sparc64/math-emu/.cvsignore b/arch/sparc64/math-emu/.cvsignore deleted file mode 100644 index 857dd22e9..000000000 --- a/arch/sparc64/math-emu/.cvsignore +++ /dev/null @@ -1,2 +0,0 @@ -.depend -.*.flags diff --git a/arch/sparc64/math-emu/Makefile b/arch/sparc64/math-emu/Makefile index 4437032b5..382366da5 100644 --- a/arch/sparc64/math-emu/Makefile +++ b/arch/sparc64/math-emu/Makefile @@ -8,12 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := math-emu.o -O_OBJS := math.o fabsq.o faddq.o fdivq.o fdmulq.o fitoq.o \ - fmovq.o fmulq.o fnegq.o fqtoi.o fqtox.o fsubq.o \ - fxtoq.o fdtoq.o fstoq.o fqtos.o fqtod.o fsqrtq.o \ - fcmpq.o fcmpeq.o \ - fsqrts.o fsqrtd.o fadds.o faddd.o fsubs.o fsubd.o \ - fmuls.o fmuld.o fdivs.o fdivd.o fsmuld.o \ - fstoi.o fdtoi.o fstox.o fdtox.o fstod.o fdtos.o +O_OBJS := math.o +CFLAGS += -I. -I$(TOPDIR)/include/math-emu -w include $(TOPDIR)/Rules.make diff --git a/arch/sparc64/math-emu/double.h b/arch/sparc64/math-emu/double.h deleted file mode 100644 index ee581c2da..000000000 --- a/arch/sparc64/math-emu/double.h +++ /dev/null @@ -1,197 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Double Precision - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel kid. Go buy yourself a real computer." -#endif - -#if _FP_W_TYPE_SIZE < 64 -#define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE) -#else -#define _FP_FRACTBITS_D _FP_W_TYPE_SIZE -#endif - -#define _FP_FRACBITS_D 53 -#define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D) -#define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D) -#define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D) -#define _FP_EXPBITS_D 11 -#define _FP_EXPBIAS_D 1023 -#define _FP_EXPMAX_D 2047 - -#define _FP_QNANBIT_D \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE) -#define _FP_IMPLBIT_D \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE) -#define _FP_OVERFLOW_D \ - ((_FP_W_TYPE)1 << _FP_WFRACBITS_D % _FP_W_TYPE_SIZE) - -#if _FP_W_TYPE_SIZE < 64 - -union _FP_UNION_D -{ - double flt; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_D; - unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; - unsigned frac0 : _FP_W_TYPE_SIZE; -#else - unsigned frac0 : _FP_W_TYPE_SIZE; - unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_D; - unsigned sign : 1; -#endif - } bits __attribute__((packed)); -}; - -#define FP_DECL_D(X) _FP_DECL(2,X) -#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val) -#define FP_UNPACK_RAW_DP(X,val) _FP_UNPACK_RAW_2_P(D,X,val) -#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X) -#define FP_PACK_RAW_DP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(D,val,X); \ - } while (0) - -#define FP_UNPACK_D(X,val) \ - do { \ - _FP_UNPACK_RAW_2(D,X,val); \ - _FP_UNPACK_CANONICAL(D,2,X); \ - } while (0) - -#define FP_UNPACK_DP(X,val) \ - do { \ - _FP_UNPACK_RAW_2_P(D,X,val); \ - _FP_UNPACK_CANONICAL(D,2,X); \ - } while (0) - -#define FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,2,X); \ - _FP_PACK_RAW_2(D,val,X); \ - } while (0) - -#define FP_PACK_DP(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,2,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(D,val,X); \ - } while (0) - -#define FP_ISSIGNAN_D(X) _FP_ISSIGNAN(D,2,X) -#define FP_NEG_D(R,X) _FP_NEG(D,2,R,X) -#define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y) -#define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y) -#define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y) -#define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y) -#define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X) -#define _FP_SQRT_MEAT_D(R,S,T,X,Q) _FP_SQRT_MEAT_2(R,S,T,X,Q) - -#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un) -#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y) - -#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg) -#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt) - -#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_2(X) -#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_2(X) - -#else - -union _FP_UNION_D -{ - double flt; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_D; - unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); -#else - unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0); - unsigned exp : _FP_EXPBITS_D; - unsigned sign : 1; -#endif - } bits __attribute__((packed)); -}; - -#define FP_DECL_D(X) _FP_DECL(1,X) -#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val) -#define FP_UNPACK_RAW_DP(X,val) _FP_UNPACK_RAW_1_P(D,X,val) -#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X) -#define FP_PACK_RAW_DP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(D,val,X); \ - } while (0) - -#define FP_UNPACK_D(X,val) \ - do { \ - _FP_UNPACK_RAW_1(D,X,val); \ - _FP_UNPACK_CANONICAL(D,1,X); \ - } while (0) - -#define FP_UNPACK_DP(X,val) \ - do { \ - _FP_UNPACK_RAW_1_P(D,X,val); \ - _FP_UNPACK_CANONICAL(D,1,X); \ - } while (0) - -#define FP_PACK_D(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,1,X); \ - _FP_PACK_RAW_1(D,val,X); \ - } while (0) - -#define FP_PACK_DP(val,X) \ - do { \ - _FP_PACK_CANONICAL(D,1,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(D,val,X); \ - } while (0) - -#define FP_ISSIGNAN_D(X) _FP_ISSIGNAN(D,1,X) -#define FP_NEG_D(R,X) _FP_NEG(D,1,R,X) -#define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y) -#define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y) -#define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y) -#define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y) -#define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X) -#define _FP_SQRT_MEAT_D(R,S,T,X,Q) _FP_SQRT_MEAT_1(R,S,T,X,Q) - -/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by - the target machine. */ - -#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un) -#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y) - -#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg) -#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt) - -#define _FP_FRAC_HIGH_D(X) _FP_FRAC_HIGH_1(X) -#define _FP_FRAC_HIGH_RAW_D(X) _FP_FRAC_HIGH_1(X) - -#endif /* W_TYPE_SIZE < 64 */ diff --git a/arch/sparc64/math-emu/extended.h b/arch/sparc64/math-emu/extended.h deleted file mode 100644 index 4a1d7e711..000000000 --- a/arch/sparc64/math-emu/extended.h +++ /dev/null @@ -1,388 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Extended Precision. - Copyright (C) 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Jakub Jelinek (jj@ultra.linux.cz). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel, kid. Go buy yourself a real computer." -#endif - -#if _FP_W_TYPE_SIZE < 64 -#define _FP_FRACTBITS_E (4*_FP_W_TYPE_SIZE) -#else -#define _FP_FRACTBITS_E (2*_FP_W_TYPE_SIZE) -#endif - -#define _FP_FRACBITS_E 64 -#define _FP_FRACXBITS_E (_FP_FRACTBITS_E - _FP_FRACBITS_E) -#define _FP_WFRACBITS_E (_FP_WORKBITS + _FP_FRACBITS_E) -#define _FP_WFRACXBITS_E (_FP_FRACTBITS_E - _FP_WFRACBITS_E) -#define _FP_EXPBITS_E 15 -#define _FP_EXPBIAS_E 16383 -#define _FP_EXPMAX_E 32767 - -#define _FP_QNANBIT_E \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-2) % _FP_W_TYPE_SIZE) -#define _FP_IMPLBIT_E \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_E-1) % _FP_W_TYPE_SIZE) -#define _FP_OVERFLOW_E \ - ((_FP_W_TYPE)1 << (_FP_WFRACBITS_E % _FP_W_TYPE_SIZE)) - -#if _FP_W_TYPE_SIZE < 64 - -union _FP_UNION_E -{ - long double flt; - struct - { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned long pad1 : _FP_W_TYPE_SIZE; - unsigned long pad2 : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E); - unsigned long sign : 1; - unsigned long exp : _FP_EXPBITS_E; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac0 : _FP_W_TYPE_SIZE; -#else - unsigned long frac0 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_E; - unsigned sign : 1; -#endif /* not bigendian */ - } bits __attribute__((packed)); -}; - - -#define FP_DECL_E(X) _FP_DECL(4,X) - -#define FP_UNPACK_RAW_E(X, val) \ - do { \ - union _FP_UNION_E _flo; _flo.flt = (val); \ - \ - X##_f[2] = 0; X##_f[3] = 0; \ - X##_f[0] = _flo.bits.frac0; \ - X##_f[1] = _flo.bits.frac1; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - if (!X##_e && (X##_f[1] || X##_f[0]) \ - && !(X##_f[1] & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_UNPACK_RAW_EP(X, val) \ - do { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - X##_f[2] = 0; X##_f[3] = 0; \ - X##_f[0] = _flo->bits.frac0; \ - X##_f[1] = _flo->bits.frac1; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - if (!X##_e && (X##_f[1] || X##_f[0]) \ - && !(X##_f[1] & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_PACK_RAW_E(val, X) \ - do { \ - union _FP_UNION_E _flo; \ - \ - if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \ - else X##_f[1] &= ~(_FP_IMPLBIT_E); \ - _flo.bits.frac0 = X##_f[0]; \ - _flo.bits.frac1 = X##_f[1]; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define FP_PACK_RAW_EP(val, X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - if (X##_e) X##_f[1] |= _FP_IMPLBIT_E; \ - else X##_f[1] &= ~(_FP_IMPLBIT_E); \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } \ - } while (0) - -#define FP_UNPACK_E(X,val) \ - do { \ - FP_UNPACK_RAW_E(X,val); \ - _FP_UNPACK_CANONICAL(E,4,X); \ - } while (0) - -#define FP_UNPACK_EP(X,val) \ - do { \ - FP_UNPACK_RAW_2_P(X,val); \ - _FP_UNPACK_CANONICAL(E,4,X); \ - } while (0) - -#define FP_PACK_E(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,4,X); \ - FP_PACK_RAW_E(val,X); \ - } while (0) - -#define FP_PACK_EP(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,4,X); \ - FP_PACK_RAW_EP(val,X); \ - } while (0) - -#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,4,X) -#define FP_NEG_E(R,X) _FP_NEG(E,4,R,X) -#define FP_ADD_E(R,X,Y) _FP_ADD(E,4,R,X,Y) -#define FP_SUB_E(R,X,Y) _FP_SUB(E,4,R,X,Y) -#define FP_MUL_E(R,X,Y) _FP_MUL(E,4,R,X,Y) -#define FP_DIV_E(R,X,Y) _FP_DIV(E,4,R,X,Y) -#define FP_SQRT_E(R,X) _FP_SQRT(E,4,R,X) - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - * This has special _E version because standard _4 square - * root would not work (it has to start normally with the - * second word and not the first), but as we have to do it - * anyway, we optimize it by doing most of the calculations - * in two UWtype registers instead of four. - */ - -#define _FP_SQRT_MEAT_E(R, S, T, X, q) \ - do { \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_4(X, (_FP_WORKBITS)); \ - while (q) \ - { \ - T##_f[1] = S##_f[1] + q; \ - if (T##_f[1] <= X##_f[1]) \ - { \ - S##_f[1] = T##_f[1] + q; \ - X##_f[1] -= T##_f[1]; \ - R##_f[1] += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[0] = S##_f[0] + q; \ - T##_f[1] = S##_f[1]; \ - if (T##_f[1] < X##_f[1] || \ - (T##_f[1] == X##_f[1] && \ - T##_f[0] <= X##_f[0])) \ - { \ - S##_f[0] = T##_f[0] + q; \ - S##_f[1] += (T##_f[0] > S##_f[0]); \ - _FP_FRAC_DEC_2(X, T); \ - R##_f[0] += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - _FP_FRAC_SLL_4(R, (_FP_WORKBITS)); \ - if (X##_f[0] | X##_f[1]) \ - { \ - if (S##_f[1] < X##_f[1] || \ - (S##_f[1] == X##_f[1] && \ - S##_f[0] < X##_f[0])) \ - R##_f[0] |= _FP_WORK_ROUND; \ - R##_f[0] |= _FP_WORK_STICKY; \ - } \ - } while (0) - -#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,4,r,X,Y,un) -#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,4,r,X,Y) - -#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,4,r,X,rsz,rsg) -#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,4,X,r,rs,rt) - -#define _FP_FRAC_HIGH_E(X) (X##_f[2]) -#define _FP_FRAC_HIGH_RAW_E(X) (X##_f[1]) - -#else /* not _FP_W_TYPE_SIZE < 64 */ -union _FP_UNION_E -{ - long double flt /* __attribute__((mode(TF))) */ ; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned long pad : (_FP_W_TYPE_SIZE - 1 - _FP_EXPBITS_E); - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_E; - unsigned long frac : _FP_W_TYPE_SIZE; -#else - unsigned long frac : _FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_E; - unsigned sign : 1; -#endif - } bits; -}; - -#define FP_DECL_E(X) _FP_DECL(2,X) - -#define FP_UNPACK_RAW_E(X, val) \ - do { \ - union _FP_UNION_E _flo; _flo.flt = (val); \ - \ - X##_f0 = _flo.bits.frac; \ - X##_f1 = 0; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_UNPACK_RAW_EP(X, val) \ - do { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - X##_f0 = _flo->bits.frac; \ - X##_f1 = 0; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - if (!X##_e && X##_f0 && !(X##_f0 & _FP_IMPLBIT_E)) \ - { \ - X##_e++; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - } while (0) - -#define FP_PACK_RAW_E(val, X) \ - do { \ - union _FP_UNION_E _flo; \ - \ - if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \ - else X##_f0 &= ~(_FP_IMPLBIT_E); \ - _flo.bits.frac = X##_f0; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define FP_PACK_RAW_EP(fs, val, X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - { \ - union _FP_UNION_E *_flo = \ - (union _FP_UNION_E *)(val); \ - \ - if (X##_e) X##_f0 |= _FP_IMPLBIT_E; \ - else X##_f0 &= ~(_FP_IMPLBIT_E); \ - _flo->bits.frac = X##_f0; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } \ - } while (0) - - -#define FP_UNPACK_E(X,val) \ - do { \ - FP_UNPACK_RAW_E(X,val); \ - _FP_UNPACK_CANONICAL(E,2,X); \ - } while (0) - -#define FP_UNPACK_EP(X,val) \ - do { \ - FP_UNPACK_RAW_EP(X,val); \ - _FP_UNPACK_CANONICAL(E,2,X); \ - } while (0) - -#define FP_PACK_E(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,2,X); \ - FP_PACK_RAW_E(val,X); \ - } while (0) - -#define FP_PACK_EP(val,X) \ - do { \ - _FP_PACK_CANONICAL(E,2,X); \ - FP_PACK_RAW_EP(val,X); \ - } while (0) - -#define FP_ISSIGNAN_E(X) _FP_ISSIGNAN(E,2,X) -#define FP_NEG_E(R,X) _FP_NEG(E,2,R,X) -#define FP_ADD_E(R,X,Y) _FP_ADD(E,2,R,X,Y) -#define FP_SUB_E(R,X,Y) _FP_SUB(E,2,R,X,Y) -#define FP_MUL_E(R,X,Y) _FP_MUL(E,2,R,X,Y) -#define FP_DIV_E(R,X,Y) _FP_DIV(E,2,R,X,Y) -#define FP_SQRT_E(R,X) _FP_SQRT(E,2,R,X) - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - * We optimize it by doing most of the calculations - * in one UWtype registers instead of two, although we don't - * have to. - */ -#define _FP_SQRT_MEAT_E(R, S, T, X, q) \ - do { \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_2(X, (_FP_WORKBITS)); \ - while (q) \ - { \ - T##_f0 = S##_f0 + q; \ - if (T##_f0 <= X##_f0) \ - { \ - S##_f0 = T##_f0 + q; \ - X##_f0 -= T##_f0; \ - R##_f0 += q; \ - } \ - _FP_FRAC_SLL_1(X, 1); \ - q >>= 1; \ - } \ - _FP_FRAC_SLL_2(R, (_FP_WORKBITS)); \ - if (X##_f0) \ - { \ - if (S##_f0 < X##_f0) \ - R##_f0 |= _FP_WORK_ROUND; \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } while (0) - -#define FP_CMP_E(r,X,Y,un) _FP_CMP(E,2,r,X,Y,un) -#define FP_CMP_EQ_E(r,X,Y) _FP_CMP_EQ(E,2,r,X,Y) - -#define FP_TO_INT_E(r,X,rsz,rsg) _FP_TO_INT(E,2,r,X,rsz,rsg) -#define FP_FROM_INT_E(X,r,rs,rt) _FP_FROM_INT(E,2,X,r,rs,rt) - -#define _FP_FRAC_HIGH_E(X) (X##_f1) -#define _FP_FRAC_HIGH_RAW_E(X) (X##_f0) - -#endif /* not _FP_W_TYPE_SIZE < 64 */ diff --git a/arch/sparc64/math-emu/fabsq.c b/arch/sparc64/math-emu/fabsq.c deleted file mode 100644 index 22da43d71..000000000 --- a/arch/sparc64/math-emu/fabsq.c +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: fabsq.c,v 1.5 1999/05/28 13:42:27 jj Exp $ - * arch/sparc64/math-emu/fabsq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FABSQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0] & 0x7fffffffffffffffUL; - rd[1] = rs2[1]; - return 0; -} diff --git a/arch/sparc64/math-emu/faddd.c b/arch/sparc64/math-emu/faddd.c deleted file mode 100644 index 7ce9de721..000000000 --- a/arch/sparc64/math-emu/faddd.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: faddd.c,v 1.4 1999/05/28 13:43:17 jj Exp $ - * arch/sparc64/math-emu/faddd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FADDD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_ADD_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/faddq.c b/arch/sparc64/math-emu/faddq.c deleted file mode 100644 index c555585af..000000000 --- a/arch/sparc64/math-emu/faddq.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: faddq.c,v 1.4 1999/05/28 13:43:19 jj Exp $ - * arch/sparc64/math-emu/faddq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FADDQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_ADD_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fadds.c b/arch/sparc64/math-emu/fadds.c deleted file mode 100644 index 73e865b4a..000000000 --- a/arch/sparc64/math-emu/fadds.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fadds.c,v 1.4 1999/05/28 13:43:25 jj Exp $ - * arch/sparc64/math-emu/fadds.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FADDS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_ADD_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fcmpeq.c b/arch/sparc64/math-emu/fcmpeq.c deleted file mode 100644 index 3e418b9e5..000000000 --- a/arch/sparc64/math-emu/fcmpeq.c +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id: fcmpeq.c,v 1.5 1999/05/28 13:43:29 jj Exp $ - * arch/sparc64/math-emu/fcmpeq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPEQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - long fccno = (long)rd; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - rd = (void *)(((long)rd)&~3); - if (ret == -1) ret = 2; - fsr = current->tss.xfsr[0]; - switch (fccno) { - case 0: fsr &= ~0xc00; fsr |= (ret << 10); break; - case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break; - case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break; - case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; - } - current->tss.xfsr[0] = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fcmpq.c b/arch/sparc64/math-emu/fcmpq.c deleted file mode 100644 index b95e62d20..000000000 --- a/arch/sparc64/math-emu/fcmpq.c +++ /dev/null @@ -1,39 +0,0 @@ -/* $Id: fcmpq.c,v 1.5 1999/05/28 13:43:33 jj Exp $ - * arch/sparc64/math-emu/fcmpq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FCMPQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); - long ret; - long fccno = (long)rd; - unsigned long fsr; - - FP_UNPACK_RAW_QP(A, rs1); - FP_UNPACK_RAW_QP(B, rs2); - FP_CMP_Q(ret, B, A, 3); - if (ret == 3 && (FP_ISSIGNAN_Q(A) || FP_ISSIGNAN_Q(B))) - FP_SET_EXCEPTION(FP_EX_INVALID); - if (!FP_INHIBIT_RESULTS) { - rd = (void *)(((long)rd)&~3); - if (ret == -1) ret = 2; - fsr = current->tss.xfsr[0]; - switch (fccno) { - case 0: fsr &= ~0xc00; fsr |= (ret << 10); break; - case 1: fsr &= ~0x300000000UL; fsr |= (ret << 32); break; - case 2: fsr &= ~0xc00000000UL; fsr |= (ret << 34); break; - case 3: fsr &= ~0x3000000000UL; fsr |= (ret << 36); break; - } - current->tss.xfsr[0] = fsr; - } - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdivd.c b/arch/sparc64/math-emu/fdivd.c deleted file mode 100644 index c6f4e9810..000000000 --- a/arch/sparc64/math-emu/fdivd.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fdivd.c,v 1.4 1999/05/28 13:43:36 jj Exp $ - * arch/sparc64/math-emu/fdivd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDIVD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_DIV_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdivq.c b/arch/sparc64/math-emu/fdivq.c deleted file mode 100644 index f154bcdb8..000000000 --- a/arch/sparc64/math-emu/fdivq.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fdivq.c,v 1.4 1999/05/28 13:43:41 jj Exp $ - * arch/sparc64/math-emu/fdivq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FDIVQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_DIV_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdivs.c b/arch/sparc64/math-emu/fdivs.c deleted file mode 100644 index dd317751f..000000000 --- a/arch/sparc64/math-emu/fdivs.c +++ /dev/null @@ -1,24 +0,0 @@ -/* $Id: fdivs.c,v 1.4 1999/05/28 13:43:45 jj Exp $ - * arch/sparc64/math-emu/fdivs.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FDIVS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_DIV_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} - diff --git a/arch/sparc64/math-emu/fdmulq.c b/arch/sparc64/math-emu/fdmulq.c deleted file mode 100644 index d8b99ecc0..000000000 --- a/arch/sparc64/math-emu/fdmulq.c +++ /dev/null @@ -1,26 +0,0 @@ -/* $Id: fdmulq.c,v 1.4 1999/05/28 13:43:48 jj Exp $ - * arch/sparc64/math-emu/fdmulq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDMULQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(IN); FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_DP(IN, rs1); - FP_CONV(Q,D,2,1,A,IN); - FP_UNPACK_DP(IN, rs2); - FP_CONV(Q,D,2,1,B,IN); - FP_MUL_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdtoi.c b/arch/sparc64/math-emu/fdtoi.c deleted file mode 100644 index 8c616c07a..000000000 --- a/arch/sparc64/math-emu/fdtoi.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fdtoi.c,v 1.3 1999/05/28 13:43:52 jj Exp $ - * arch/sparc64/math-emu/fdtoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); - int r; - - FP_UNPACK_DP(A, rs2); - FP_TO_INT_D(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdtoq.c b/arch/sparc64/math-emu/fdtoq.c deleted file mode 100644 index 0607525d6..000000000 --- a/arch/sparc64/math-emu/fdtoq.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fdtoq.c,v 1.4 1999/05/28 13:43:56 jj Exp $ - * arch/sparc64/math-emu/fdtoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FDTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_Q(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(Q,D,2,1,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdtos.c b/arch/sparc64/math-emu/fdtos.c deleted file mode 100644 index 1a86a96c7..000000000 --- a/arch/sparc64/math-emu/fdtos.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fdtos.c,v 1.4 1999/05/28 13:43:58 jj Exp $ - * arch/sparc64/math-emu/fdtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FDTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_S(R); - - FP_UNPACK_DP(A, rs2); - FP_CONV(S,D,1,1,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fdtox.c b/arch/sparc64/math-emu/fdtox.c deleted file mode 100644 index 465d9962b..000000000 --- a/arch/sparc64/math-emu/fdtox.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fdtox.c,v 1.3 1999/05/28 13:44:02 jj Exp $ - * arch/sparc64/math-emu/fdtox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FDTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); - long r; - - FP_UNPACK_DP(A, rs2); - FP_TO_INT_D(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fitoq.c b/arch/sparc64/math-emu/fitoq.c deleted file mode 100644 index 3a9af3073..000000000 --- a/arch/sparc64/math-emu/fitoq.c +++ /dev/null @@ -1,22 +0,0 @@ -/* $Id: fitoq.c,v 1.5 1999/05/28 13:44:06 jj Exp $ - * arch/sparc64/math-emu/fitoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FITOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(R); - int a = *(int *)rs2; - - FP_FROM_INT_Q(R, a, 32, int); - FP_PACK_QP(rd, R); - return 0; -} diff --git a/arch/sparc64/math-emu/fmovq.c b/arch/sparc64/math-emu/fmovq.c deleted file mode 100644 index ee5a7e4f5..000000000 --- a/arch/sparc64/math-emu/fmovq.c +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: fmovq.c,v 1.2 1999/05/28 13:44:09 jj Exp $ - * arch/sparc64/math-emu/fmovq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FMOVQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0]; - rd[1] = rs2[1]; - return 0; -} diff --git a/arch/sparc64/math-emu/fmuld.c b/arch/sparc64/math-emu/fmuld.c deleted file mode 100644 index 2dde7c271..000000000 --- a/arch/sparc64/math-emu/fmuld.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fmuld.c,v 1.4 1999/05/28 13:44:11 jj Exp $ - * arch/sparc64/math-emu/fmuld.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FMULD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - FP_MUL_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fmulq.c b/arch/sparc64/math-emu/fmulq.c deleted file mode 100644 index 227d1f928..000000000 --- a/arch/sparc64/math-emu/fmulq.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fmulq.c,v 1.4 1999/05/28 13:44:14 jj Exp $ - * arch/sparc64/math-emu/fmulq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FMULQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - FP_MUL_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fmuls.c b/arch/sparc64/math-emu/fmuls.c deleted file mode 100644 index 623c4aa4c..000000000 --- a/arch/sparc64/math-emu/fmuls.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fmuls.c,v 1.4 1999/05/28 13:44:18 jj Exp $ - * arch/sparc64/math-emu/fmuls.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FMULS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - FP_MUL_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fnegq.c b/arch/sparc64/math-emu/fnegq.c deleted file mode 100644 index 4e4a68795..000000000 --- a/arch/sparc64/math-emu/fnegq.c +++ /dev/null @@ -1,13 +0,0 @@ -/* $Id: fnegq.c,v 1.6 1999/05/28 13:44:21 jj Exp $ - * arch/sparc64/math-emu/fnegq.c - * - * Copyright (C) 1997 Jakub Jelinek (jj@ultra.linux.cz) - * - */ - -int FNEGQ(unsigned long *rd, unsigned long *rs2) -{ - rd[0] = rs2[0] ^ 0x8000000000000000UL; - rd[1] = rs2[1]; - return 0; -} diff --git a/arch/sparc64/math-emu/fqtod.c b/arch/sparc64/math-emu/fqtod.c deleted file mode 100644 index 55b6d4443..000000000 --- a/arch/sparc64/math-emu/fqtod.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fqtod.c,v 1.4 1999/05/28 13:44:24 jj Exp $ - * arch/sparc64/math-emu/fqtod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "double.h" - -int FQTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_D(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(D,Q,1,2,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fqtoi.c b/arch/sparc64/math-emu/fqtoi.c deleted file mode 100644 index a1b8ea741..000000000 --- a/arch/sparc64/math-emu/fqtoi.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fqtoi.c,v 1.4 1999/05/28 13:44:26 jj Exp $ - * arch/sparc64/math-emu/fqtoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FQTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); - int r; - - FP_UNPACK_QP(A, rs2); - FP_TO_INT_Q(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fqtos.c b/arch/sparc64/math-emu/fqtos.c deleted file mode 100644 index 6edb6aaca..000000000 --- a/arch/sparc64/math-emu/fqtos.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fqtos.c,v 1.4 1999/05/28 13:44:30 jj Exp $ - * arch/sparc64/math-emu/fqtos.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FQTOS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_S(R); - - FP_UNPACK_QP(A, rs2); - FP_CONV(S,Q,1,2,R,A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fqtox.c b/arch/sparc64/math-emu/fqtox.c deleted file mode 100644 index 458061fb0..000000000 --- a/arch/sparc64/math-emu/fqtox.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fqtox.c,v 1.4 1999/05/28 13:44:34 jj Exp $ - * arch/sparc64/math-emu/fqtox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FQTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); - long r; - - FP_UNPACK_QP(A, rs2); - FP_TO_INT_Q(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsmuld.c b/arch/sparc64/math-emu/fsmuld.c deleted file mode 100644 index 92b86288f..000000000 --- a/arch/sparc64/math-emu/fsmuld.c +++ /dev/null @@ -1,26 +0,0 @@ -/* $Id: fsmuld.c,v 1.4 1999/05/28 13:44:37 jj Exp $ - * arch/sparc64/math-emu/fsmuld.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSMULD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(IN); FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_SP(IN, rs1); - FP_CONV(D,S,1,1,A,IN); - FP_UNPACK_SP(IN, rs2); - FP_CONV(D,S,1,1,B,IN); - FP_MUL_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsqrtd.c b/arch/sparc64/math-emu/fsqrtd.c deleted file mode 100644 index 5d02ed5c0..000000000 --- a/arch/sparc64/math-emu/fsqrtd.c +++ /dev/null @@ -1,22 +0,0 @@ -/* $Id: fsqrtd.c,v 1.4 1999/05/28 13:44:39 jj Exp $ - * arch/sparc64/math-emu/fsqrtd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FSQRTD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs2); - FP_SQRT_D(R, A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsqrtq.c b/arch/sparc64/math-emu/fsqrtq.c deleted file mode 100644 index bb2e6c51e..000000000 --- a/arch/sparc64/math-emu/fsqrtq.c +++ /dev/null @@ -1,22 +0,0 @@ -/* $Id: fsqrtq.c,v 1.5 1999/05/28 13:44:44 jj Exp $ - * arch/sparc64/math-emu/fsqrtq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FSQRTQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs2); - FP_SQRT_Q(R, A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsqrts.c b/arch/sparc64/math-emu/fsqrts.c deleted file mode 100644 index ee32737ed..000000000 --- a/arch/sparc64/math-emu/fsqrts.c +++ /dev/null @@ -1,22 +0,0 @@ -/* $Id: fsqrts.c,v 1.4 1999/05/28 13:44:48 jj Exp $ - * arch/sparc64/math-emu/fsqrts.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSQRTS(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs2); - FP_SQRT_S(R, A); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fstod.c b/arch/sparc64/math-emu/fstod.c deleted file mode 100644 index 3c7a974ca..000000000 --- a/arch/sparc64/math-emu/fstod.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fstod.c,v 1.4 1999/05/28 13:44:51 jj Exp $ - * arch/sparc64/math-emu/fstod.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" -#include "single.h" - -int FSTOD(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_D(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(D,S,1,1,R,A); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fstoi.c b/arch/sparc64/math-emu/fstoi.c deleted file mode 100644 index 40ef2badd..000000000 --- a/arch/sparc64/math-emu/fstoi.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fstoi.c,v 1.3 1999/05/28 13:44:54 jj Exp $ - * arch/sparc64/math-emu/fstoi.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSTOI(int *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); - int r; - - FP_UNPACK_SP(A, rs2); - FP_TO_INT_S(r, A, 32, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fstoq.c b/arch/sparc64/math-emu/fstoq.c deleted file mode 100644 index d23e187c6..000000000 --- a/arch/sparc64/math-emu/fstoq.c +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id: fstoq.c,v 1.4 1999/05/28 13:44:58 jj Exp $ - * arch/sparc64/math-emu/fstoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" -#include "single.h" - -int FSTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_Q(R); - - FP_UNPACK_SP(A, rs2); - FP_CONV(Q,S,2,1,R,A); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fstox.c b/arch/sparc64/math-emu/fstox.c deleted file mode 100644 index fecca41d3..000000000 --- a/arch/sparc64/math-emu/fstox.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fstox.c,v 1.3 1999/05/28 13:45:01 jj Exp $ - * arch/sparc64/math-emu/fstox.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#define FP_ROUNDMODE FP_RND_ZERO -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSTOX(long *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_S(A); - long r; - - FP_UNPACK_SP(A, rs2); - FP_TO_INT_S(r, A, 64, 1); - if (!FP_INHIBIT_RESULTS) - *rd = r; - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsubd.c b/arch/sparc64/math-emu/fsubd.c deleted file mode 100644 index 66a7c5664..000000000 --- a/arch/sparc64/math-emu/fsubd.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fsubd.c,v 1.4 1999/05/28 13:45:04 jj Exp $ - * arch/sparc64/math-emu/fsubd.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "double.h" - -int FSUBD(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_D(A); FP_DECL_D(B); FP_DECL_D(R); - - FP_UNPACK_DP(A, rs1); - FP_UNPACK_DP(B, rs2); - if (B_c != FP_CLS_NAN) - B_s ^= 1; - FP_ADD_D(R, A, B); - FP_PACK_DP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsubq.c b/arch/sparc64/math-emu/fsubq.c deleted file mode 100644 index 96b2e08dd..000000000 --- a/arch/sparc64/math-emu/fsubq.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fsubq.c,v 1.4 1999/05/28 13:45:09 jj Exp $ - * arch/sparc64/math-emu/fsubq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FSUBQ(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_Q(A); FP_DECL_Q(B); FP_DECL_Q(R); - - FP_UNPACK_QP(A, rs1); - FP_UNPACK_QP(B, rs2); - if (B_c != FP_CLS_NAN) - B_s ^= 1; - FP_ADD_Q(R, A, B); - FP_PACK_QP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fsubs.c b/arch/sparc64/math-emu/fsubs.c deleted file mode 100644 index 3eef72572..000000000 --- a/arch/sparc64/math-emu/fsubs.c +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: fsubs.c,v 1.4 1999/05/28 13:45:12 jj Exp $ - * arch/sparc64/math-emu/fsubs.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "single.h" - -int FSUBS(void *rd, void *rs2, void *rs1) -{ - FP_DECL_EX; - FP_DECL_S(A); FP_DECL_S(B); FP_DECL_S(R); - - FP_UNPACK_SP(A, rs1); - FP_UNPACK_SP(B, rs2); - if (B_c != FP_CLS_NAN) - B_s ^= 1; - FP_ADD_S(R, A, B); - FP_PACK_SP(rd, R); - FP_HANDLE_EXCEPTIONS; -} diff --git a/arch/sparc64/math-emu/fxtoq.c b/arch/sparc64/math-emu/fxtoq.c deleted file mode 100644 index 205567cd9..000000000 --- a/arch/sparc64/math-emu/fxtoq.c +++ /dev/null @@ -1,22 +0,0 @@ -/* $Id: fxtoq.c,v 1.5 1999/05/28 13:45:15 jj Exp $ - * arch/sparc64/math-emu/fxtoq.c - * - * Copyright (C) 1997, 1999 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - * - */ - -#include "sfp-util.h" -#include "soft-fp.h" -#include "quad.h" - -int FXTOQ(void *rd, void *rs2) -{ - FP_DECL_EX; - FP_DECL_Q(R); - long a = *(long *)rs2; - - FP_FROM_INT_Q(R, a, 64, long); - FP_PACK_QP(rd, R); - return 0; -} diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c index 9f2a21f9f..38a846c9f 100644 --- a/arch/sparc64/math-emu/math.c +++ b/arch/sparc64/math-emu/math.c @@ -1,4 +1,4 @@ -/* $Id: math.c,v 1.8 1999/05/28 13:43:11 jj Exp $ +/* $Id: math.c,v 1.10 1999/08/13 16:02:06 jj Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997,1999 Jakub Jelinek (jj@ultra.linux.cz) @@ -17,46 +17,61 @@ #include "sfp-util.h" #include "soft-fp.h" +#include "single.h" +#include "double.h" +#include "quad.h" -#define FLOATFUNC(x) extern int x(void *,void *,void *); - -FLOATFUNC(FMOVQ) -FLOATFUNC(FNEGQ) -FLOATFUNC(FABSQ) -FLOATFUNC(FSQRTQ) -FLOATFUNC(FADDQ) -FLOATFUNC(FSUBQ) -FLOATFUNC(FMULQ) -FLOATFUNC(FDIVQ) -FLOATFUNC(FDMULQ) -FLOATFUNC(FQTOX) -FLOATFUNC(FXTOQ) -FLOATFUNC(FQTOS) -FLOATFUNC(FQTOD) -FLOATFUNC(FITOQ) -FLOATFUNC(FSTOQ) -FLOATFUNC(FDTOQ) -FLOATFUNC(FQTOI) -FLOATFUNC(FCMPQ) -FLOATFUNC(FCMPEQ) - -FLOATFUNC(FSQRTS) -FLOATFUNC(FSQRTD) -FLOATFUNC(FADDS) -FLOATFUNC(FADDD) -FLOATFUNC(FSUBS) -FLOATFUNC(FSUBD) -FLOATFUNC(FMULS) -FLOATFUNC(FMULD) -FLOATFUNC(FDIVS) -FLOATFUNC(FDIVD) -FLOATFUNC(FSMULD) -FLOATFUNC(FSTOX) -FLOATFUNC(FDTOX) -FLOATFUNC(FDTOS) -FLOATFUNC(FSTOD) -FLOATFUNC(FSTOI) -FLOATFUNC(FDTOI) +/* QUAD - ftt == 3 */ +#define FMOVQ 0x003 +#define FNEGQ 0x007 +#define FABSQ 0x00b +#define FSQRTQ 0x02b +#define FADDQ 0x043 +#define FSUBQ 0x047 +#define FMULQ 0x04b +#define FDIVQ 0x04f +#define FDMULQ 0x06e +#define FQTOX 0x083 +#define FXTOQ 0x08c +#define FQTOS 0x0c7 +#define FQTOD 0x0cb +#define FITOQ 0x0cc +#define FSTOQ 0x0cd +#define FDTOQ 0x0ce +#define FQTOI 0x0d3 +/* SUBNORMAL - ftt == 2 */ +#define FSQRTS 0x029 +#define FSQRTD 0x02a +#define FADDS 0x041 +#define FADDD 0x042 +#define FSUBS 0x045 +#define FSUBD 0x046 +#define FMULS 0x049 +#define FMULD 0x04a +#define FDIVS 0x04d +#define FDIVD 0x04e +#define FSMULD 0x069 +#define FSTOX 0x081 +#define FDTOX 0x082 +#define FDTOS 0x0c6 +#define FSTOD 0x0c9 +#define FSTOI 0x0d1 +#define FDTOI 0x0d2 +/* FPOP2 */ +#define FCMPQ 0x053 +#define FCMPEQ 0x057 +#define FMOVQ0 0x003 +#define FMOVQ1 0x043 +#define FMOVQ2 0x083 +#define FMOVQ3 0x0c3 +#define FMOVQI 0x103 +#define FMOVQX 0x183 +#define FMOVQZ 0x027 +#define FMOVQLE 0x047 +#define FMOVQLZ 0x067 +#define FMOVQNZ 0x0a7 +#define FMOVQGZ 0x0c7 +#define FMOVQGE 0x0e7 #define FSR_TEM_SHIFT 23UL #define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT) @@ -73,9 +88,9 @@ FLOATFUNC(FDTOI) * * We return 0 if a SIGFPE should be sent, 1 otherwise. */ -static int record_exception(struct pt_regs *regs, int eflag) +static inline int record_exception(struct pt_regs *regs, int eflag) { - u64 fsr = current->tss.xfsr[0]; + u64 fsr = current->thread.xfsr[0]; int would_trap; /* Determine if this exception would have generated a trap. */ @@ -120,7 +135,7 @@ static int record_exception(struct pt_regs *regs, int eflag) if(would_trap != 0) fsr |= (1UL << 14); - current->tss.xfsr[0] = fsr; + current->thread.xfsr[0] = fsr; /* If we will not trap, advance the program counter over * the instruction being handled. @@ -133,133 +148,321 @@ static int record_exception(struct pt_regs *regs, int eflag) return (would_trap ? 0 : 1); } +typedef union { + u32 s; + u64 d; + u64 q[2]; +} *argp; + int do_mathemu(struct pt_regs *regs, struct fpustate *f) { unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; u32 insn = 0; - int type = 0; /* 01 is single, 10 is double, 11 is quad, - 000011 is rs1, 001100 is rs2, 110000 is rd (00 in rd is fcc) - 111100000000 tells which ftt may that happen in */ + int type = 0; + /* ftt tells which ftt it may happen in, r is rd, b is rs2 and a is rs1. The *u arg tells + whether the argument should be packed/unpacked (0 - do not unpack/pack, 1 - unpack/pack) + non-u args tells the size of the argument (0 - no argument, 1 - single, 2 - double, 3 - quad */ +#define TYPE(ftt, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) | (ftt << 9) int freg; static u64 zero[2] = { 0L, 0L }; int flags; - int (*func)(void *,void *,void *) = NULL; + FP_DECL_EX; + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR); + FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR); + int IR; + long XR, xfsr; if(tstate & TSTATE_PRIV) die_if_kernel("FPQuad from kernel", regs); - if(current->tss.flags & SPARC_FLAG_32BIT) + if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { if ((insn & 0xc1f80000) == 0x81a00000) /* FPOP1 */ { switch ((insn >> 5) & 0x1ff) { /* QUAD - ftt == 3 */ - case 0x003: type = 0x33c; func = FMOVQ; break; - case 0x007: type = 0x33c; func = FNEGQ; break; - case 0x00b: type = 0x33c; func = FABSQ; break; - case 0x02b: type = 0x33c; func = FSQRTQ; break; - case 0x043: type = 0x33f; func = FADDQ; break; - case 0x047: type = 0x33f; func = FSUBQ; break; - case 0x04b: type = 0x33f; func = FMULQ; break; - case 0x04f: type = 0x33f; func = FDIVQ; break; - case 0x06e: type = 0x33a; func = FDMULQ; break; - case 0x083: type = 0x32c; func = FQTOX; break; - case 0x08c: type = 0x338; func = FXTOQ; break; - case 0x0c7: type = 0x31c; func = FQTOS; break; - case 0x0cb: type = 0x32c; func = FQTOD; break; - case 0x0cc: type = 0x334; func = FITOQ; break; - case 0x0cd: type = 0x334; func = FSTOQ; break; - case 0x0ce: type = 0x338; func = FDTOQ; break; - case 0x0d3: type = 0x31c; func = FQTOI; break; + case FMOVQ: + case FNEGQ: + case FABSQ: TYPE(3,3,0,3,0,0,0); break; + case FSQRTQ: TYPE(3,3,1,3,1,0,0); break; + case FADDQ: + case FSUBQ: + case FMULQ: + case FDIVQ: TYPE(3,3,1,3,1,3,1); break; + case FDMULQ: TYPE(3,3,1,2,1,2,1); break; + case FQTOX: TYPE(3,2,0,3,1,0,0); break; + case FXTOQ: TYPE(3,3,1,2,0,0,0); break; + case FQTOS: TYPE(3,1,1,3,1,0,0); break; + case FQTOD: TYPE(3,2,1,3,1,0,0); break; + case FITOQ: TYPE(3,3,1,1,0,0,0); break; + case FSTOQ: TYPE(3,3,1,1,1,0,0); break; + case FDTOQ: TYPE(3,3,1,2,1,0,0); break; + case FQTOI: TYPE(3,1,0,3,1,0,0); break; /* SUBNORMAL - ftt == 2 */ - case 0x029: type = 0x214; func = FSQRTS; break; - case 0x02a: type = 0x228; func = FSQRTD; break; - case 0x041: type = 0x215; func = FADDS; break; - case 0x042: type = 0x22a; func = FADDD; break; - case 0x045: type = 0x215; func = FSUBS; break; - case 0x046: type = 0x22a; func = FSUBD; break; - case 0x049: type = 0x215; func = FMULS; break; - case 0x04a: type = 0x22a; func = FMULD; break; - case 0x04d: type = 0x215; func = FDIVS; break; - case 0x04e: type = 0x22a; func = FDIVD; break; - case 0x069: type = 0x225; func = FSMULD; break; - case 0x081: type = 0x224; func = FSTOX; break; - case 0x082: type = 0x228; func = FDTOX; break; - case 0x0c6: type = 0x218; func = FDTOS; break; - case 0x0c9: type = 0x224; func = FSTOD; break; - case 0x0d1: type = 0x214; func = FSTOI; break; - case 0x0d2: type = 0x218; func = FDTOI; break; + case FSQRTS: TYPE(2,1,1,1,1,0,0); break; + case FSQRTD: TYPE(2,2,1,2,1,0,0); break; + case FADDD: + case FSUBD: + case FMULD: + case FDIVD: TYPE(2,2,1,2,1,2,1); break; + case FADDS: + case FSUBS: + case FMULS: + case FDIVS: TYPE(2,1,1,1,1,1,1); break; + case FSMULD: TYPE(2,2,1,1,1,1,1); break; + case FSTOX: TYPE(2,2,0,1,1,0,0); break; + case FDTOX: TYPE(2,2,0,2,1,0,0); break; + case FDTOS: TYPE(2,1,1,2,1,0,0); break; + case FSTOD: TYPE(2,2,1,1,1,0,0); break; + case FSTOI: TYPE(2,1,0,1,1,0,0); break; + case FDTOI: TYPE(2,1,0,2,1,0,0); break; } } else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { + IR = 2; switch ((insn >> 5) & 0x1ff) { - case 0x053: type = 0x30f; func = FCMPQ; break; - case 0x057: type = 0x30f; func = FCMPEQ; break; + case FCMPQ: TYPE(3,0,0,3,1,3,1); break; + case FCMPEQ: TYPE(3,0,0,3,1,3,1); break; + /* Now the conditional fmovq support */ + case FMOVQ0: + case FMOVQ1: + case FMOVQ2: + case FMOVQ3: + /* fmovq %fccX, %fY, %fZ */ + if (!((insn >> 11) & 3)) + XR = current->thread.xfsr[0] >> 10; + else + XR = current->thread.xfsr[0] >> (30 + ((insn >> 10) & 0x6)); + XR &= 3; + IR = 0; + switch ((insn >> 14) & 0x7) { + /* case 0: IR = 0; break; */ /* Never */ + case 1: if (XR) IR = 1; break; /* Not Equal */ + case 2: if (XR == 1 || XR == 2) IR = 1; break; /* Less or Greater */ + case 3: if (XR & 1) IR = 1; break; /* Unordered or Less */ + case 4: if (XR == 1) IR = 1; break; /* Less */ + case 5: if (XR & 2) IR = 1; break; /* Unordered or Greater */ + case 6: if (XR == 2) IR = 1; break; /* Greater */ + case 7: if (XR == 3) IR = 1; break; /* Unordered */ + } + if ((insn >> 14) & 8) + IR ^= 1; + break; + case FMOVQI: + case FMOVQX: + /* fmovq %[ix]cc, %fY, %fZ */ + XR = regs->tstate >> 32; + if ((insn >> 5) & 0x80) + XR >>= 4; + XR &= 0xf; + IR = 0; + freg = ((XR >> 2) ^ XR) & 2; + switch ((insn >> 14) & 0x7) { + /* case 0: IR = 0; break; */ /* Never */ + case 1: if (XR & 4) IR = 1; break; /* Equal */ + case 2: if ((XR & 4) || freg) IR = 1; break; /* Less or Equal */ + case 3: if (freg) IR = 1; break; /* Less */ + case 4: if (XR & 5) IR = 1; break; /* Less or Equal Unsigned */ + case 5: if (XR & 1) IR = 1; break; /* Carry Set */ + case 6: if (XR & 8) IR = 1; break; /* Negative */ + case 7: if (XR & 2) IR = 1; break; /* Overflow Set */ + } + if ((insn >> 14) & 8) + IR ^= 1; + break; + case FMOVQZ: + case FMOVQLE: + case FMOVQLZ: + case FMOVQNZ: + case FMOVQGZ: + case FMOVQGE: + freg = (insn >> 14) & 0x1f; + if (!freg) + XR = 0; + else if (freg < 16) + XR = regs->u_regs[freg]; + else if (current->thread.flags & SPARC_FLAG_32BIT) { + struct reg_window32 *win32; + flushw_user (); + win32 = (struct reg_window32 *)((unsigned long)((u32)regs->u_regs[UREG_FP])); + get_user(XR, &win32->locals[freg - 16]); + } else { + struct reg_window *win; + flushw_user (); + win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); + get_user(XR, &win->locals[freg - 16]); + } + IR = 0; + switch ((insn >> 10) & 3) { + case 1: if (!XR) IR = 1; break; /* Register Zero */ + case 2: if (XR <= 0) IR = 1; break; /* Register Less Than or Equal to Zero */ + case 3: if (XR < 0) IR = 1; break; /* Register Less Than Zero */ + } + if ((insn >> 10) & 4) + IR ^= 1; + break; + } + if (IR == 0) { + /* The fmov test was false. Do a nop instead */ + current->thread.xfsr[0] &= ~(FSR_CEXC_MASK); + regs->tpc = regs->tnpc; + regs->tnpc += 4; + return 1; + } else if (IR == 1) { + /* Change the instruction into plain fmovq */ + insn = (insn & 0x3e00001f) | 0x81a00060; + TYPE(3,3,0,3,0,0,0); } } } if (type) { - void *rs1 = NULL, *rs2 = NULL, *rd = NULL; + argp rs1 = NULL, rs2 = NULL, rd = NULL; - freg = (current->tss.xfsr[0] >> 14) & 0xf; - if (freg != (type >> 8)) + freg = (current->thread.xfsr[0] >> 14) & 0xf; + if (freg != (type >> 9)) goto err; - current->tss.xfsr[0] &= ~0x1c000; + current->thread.xfsr[0] &= ~0x1c000; freg = ((insn >> 14) & 0x1f); switch (type & 0x3) { case 3: if (freg & 2) { - current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; + current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rs1 = (void *)&f->regs[freg]; + case 1: rs1 = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; - if (!(current->tss.fpsaved[0] & flags)) - rs1 = (void *)&zero; + if (!(current->thread.fpsaved[0] & flags)) + rs1 = (argp)&zero; break; } + switch (type & 0x7) { + case 7: FP_UNPACK_QP (QA, rs1); break; + case 6: FP_UNPACK_DP (DA, rs1); break; + case 5: FP_UNPACK_SP (SA, rs1); break; + } freg = (insn & 0x1f); - switch ((type >> 2) & 0x3) { + switch ((type >> 3) & 0x3) { case 3: if (freg & 2) { - current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; + current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rs2 = (void *)&f->regs[freg]; + case 1: rs2 = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; - if (!(current->tss.fpsaved[0] & flags)) - rs2 = (void *)&zero; + if (!(current->thread.fpsaved[0] & flags)) + rs2 = (argp)&zero; break; } + switch ((type >> 3) & 0x7) { + case 7: FP_UNPACK_QP (QB, rs2); break; + case 6: FP_UNPACK_DP (DB, rs2); break; + case 5: FP_UNPACK_SP (SB, rs2); break; + } freg = ((insn >> 25) & 0x1f); - switch ((type >> 4) & 0x3) { - case 0: rd = (void *)(long)(freg & 3); break; + switch ((type >> 6) & 0x3) { case 3: if (freg & 2) { - current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; + current->thread.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); - case 1: rd = (void *)&f->regs[freg]; + case 1: rd = (argp)&f->regs[freg]; flags = (freg < 32) ? FPRS_DL : FPRS_DU; - if (!(current->tss.fpsaved[0] & FPRS_FEF)) { - current->tss.fpsaved[0] = FPRS_FEF; - current->tss.gsr[0] = 0; + if (!(current->thread.fpsaved[0] & FPRS_FEF)) { + current->thread.fpsaved[0] = FPRS_FEF; + current->thread.gsr[0] = 0; } - if (!(current->tss.fpsaved[0] & flags)) { + if (!(current->thread.fpsaved[0] & flags)) { if (freg < 32) memset(f->regs, 0, 32*sizeof(u32)); else memset(f->regs+32, 0, 32*sizeof(u32)); } - current->tss.fpsaved[0] |= flags; + current->thread.fpsaved[0] |= flags; break; } - flags = func(rd, rs2, rs1); - if(flags != 0) - return record_exception(regs, flags); + switch ((insn >> 5) & 0x1ff) { + /* + */ + case FADDS: FP_ADD_S (SR, SA, SB); break; + case FADDD: FP_ADD_D (DR, DA, DB); break; + case FADDQ: FP_ADD_Q (QR, QA, QB); break; + /* - */ + case FSUBS: FP_SUB_S (SR, SA, SB); break; + case FSUBD: FP_SUB_D (DR, DA, DB); break; + case FSUBQ: FP_SUB_Q (QR, QA, QB); break; + /* * */ + case FMULS: FP_MUL_S (SR, SA, SB); break; + case FSMULD: FP_CONV (D, S, 1, 1, DA, SA); + FP_CONV (D, S, 1, 1, DB, SB); + case FMULD: FP_MUL_D (DR, DA, DB); break; + case FDMULQ: FP_CONV (Q, D, 2, 1, QA, DA); + FP_CONV (Q, D, 2, 1, QB, DB); + case FMULQ: FP_MUL_Q (QR, QA, QB); break; + /* / */ + case FDIVS: FP_DIV_S (SR, SA, SB); break; + case FDIVD: FP_DIV_D (DR, DA, DB); break; + case FDIVQ: FP_DIV_Q (QR, QA, QB); break; + /* sqrt */ + case FSQRTS: FP_SQRT_S (SR, SB); break; + case FSQRTD: FP_SQRT_D (DR, DB); break; + case FSQRTQ: FP_SQRT_Q (QR, QB); break; + /* mov */ + case FMOVQ: rd->q[0] = rs2->q[0]; rd->q[1] = rs2->q[1]; break; + case FABSQ: rd->q[0] = rs2->q[0] & 0x7fffffffffffffffUL; rd->q[1] = rs2->q[1]; break; + case FNEGQ: rd->q[0] = rs2->q[0] ^ 0x8000000000000000UL; rd->q[1] = rs2->q[1]; break; + /* float to int */ + case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break; + case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break; + case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break; + case FSTOX: FP_TO_INT_S (XR, SB, 64, 1); break; + case FDTOX: FP_TO_INT_D (XR, DB, 64, 1); break; + case FQTOX: FP_TO_INT_Q (XR, QB, 64, 1); break; + /* int to float */ + case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break; + case FXTOQ: XR = rs2->d; FP_FROM_INT_Q (QR, XR, 64, long); break; + /* float to float */ + case FSTOD: FP_CONV (D, S, 1, 1, DR, SB); break; + case FSTOQ: FP_CONV (Q, S, 2, 1, QR, SB); break; + case FDTOQ: FP_CONV (Q, D, 2, 1, QR, DB); break; + case FDTOS: FP_CONV (S, D, 1, 1, SR, DB); break; + case FQTOS: FP_CONV (S, Q, 1, 2, SR, QB); break; + case FQTOD: FP_CONV (D, Q, 1, 2, DR, QB); break; + /* comparison */ + case FCMPQ: + case FCMPEQ: + FP_CMP_Q(XR, QB, QA, 3); + if (XR == 3 && + (((insn >> 5) & 0x1ff) == FCMPEQ || + FP_ISSIGNAN_Q(QA) || + FP_ISSIGNAN_Q(QB))) + FP_SET_EXCEPTION (FP_EX_INVALID); + } + if (!FP_INHIBIT_RESULTS) { + switch ((type >> 6) & 0x7) { + case 0: xfsr = current->thread.xfsr[0]; + if (XR == -1) XR = 2; + switch (freg & 3) { + /* fcc0, 1, 2, 3 */ + case 0: xfsr &= ~0xc00; xfsr |= (XR << 10); break; + case 1: xfsr &= ~0x300000000UL; xfsr |= (XR << 32); break; + case 2: xfsr &= ~0xc00000000UL; xfsr |= (XR << 34); break; + case 3: xfsr &= ~0x3000000000UL; xfsr |= (XR << 36); break; + } + current->thread.xfsr[0] = xfsr; + break; + case 1: rd->s = IR; break; + case 2: rd->d = XR; break; + case 5: FP_PACK_SP (rd, SR); break; + case 6: FP_PACK_DP (rd, DR); break; + case 7: FP_PACK_QP (rd, QR); break; + } + } + + if(_fex != 0) + return record_exception(regs, _fex); /* Success and no exceptions detected. */ - current->tss.xfsr[0] &= ~(FSR_CEXC_MASK); + current->thread.xfsr[0] &= ~(FSR_CEXC_MASK); regs->tpc = regs->tnpc; regs->tnpc += 4; return 1; diff --git a/arch/sparc64/math-emu/op-1.h b/arch/sparc64/math-emu/op-1.h deleted file mode 100644 index fe83d376a..000000000 --- a/arch/sparc64/math-emu/op-1.h +++ /dev/null @@ -1,297 +0,0 @@ -/* Software floating-point emulation. - Basic one-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f -#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f) -#define _FP_FRAC_SET_1(X,I) (X##_f = I) -#define _FP_FRAC_HIGH_1(X) (X##_f) -#define _FP_FRAC_LOW_1(X) (X##_f) -#define _FP_FRAC_WORD_1(X,w) (X##_f) - -#define _FP_FRAC_ADDI_1(X,I) (X##_f += I) -#define _FP_FRAC_SLL_1(X,N) \ - do { \ - if (__builtin_constant_p(N) && (N) == 1) \ - X##_f += X##_f; \ - else \ - X##_f <<= (N); \ - } while (0) -#define _FP_FRAC_SRL_1(X,N) (X##_f >>= N) - -/* Right shift with sticky-lsb. */ -#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz) - -#define __FP_FRAC_SRS_1(X,N,sz) \ - (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \ - ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0))) - -#define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f) -#define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f) -#define _FP_FRAC_DEC_1(X,Y) (X##_f -= Y##_f) -#define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f) - -/* Predicates */ -#define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0) -#define _FP_FRAC_ZEROP_1(X) (X##_f == 0) -#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs) -#define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f) -#define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f) -#define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f) - -#define _FP_ZEROFRAC_1 0 -#define _FP_MINFRAC_1 1 -#define _FP_MAXFRAC_1 (~(_FP_WS_TYPE)0) - -/* - * Unpack the raw bits of a native fp value. Do not classify or - * normalize the data. - */ - -#define _FP_UNPACK_RAW_1(fs, X, val) \ - do { \ - union _FP_UNION_##fs _flo; _flo.flt = (val); \ - \ - X##_f = _flo.bits.frac; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - } while (0) - -#define _FP_UNPACK_RAW_1_P(fs, X, val) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - X##_f = _flo->bits.frac; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - } while (0) - -/* - * Repack the raw bits of a native fp value. - */ - -#define _FP_PACK_RAW_1(fs, val, X) \ - do { \ - union _FP_UNION_##fs _flo; \ - \ - _flo.bits.frac = X##_f; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define _FP_PACK_RAW_1_P(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - _flo->bits.frac = X##_f; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - - -/* - * Multiplication algorithms: - */ - -/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the - multiplication immediately. */ - -#define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \ - do { \ - R##_f = X##_f * Y##_f; \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - } while (0) - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \ - do { \ - _FP_W_TYPE _Z_f0, _Z_f1; \ - doit(_Z_f1, _Z_f0, X##_f, Y##_f); \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - R##_f = _Z_f0; \ - } while (0) - -/* Finally, a simple widening multiply algorithm. What fun! */ - -#define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \ - \ - /* split the words in half */ \ - _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \ - _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ - _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \ - _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \ - \ - /* multiply the pieces */ \ - _z_f0 = _xl * _yl; \ - _a_f0 = _xh * _yl; \ - _a_f1 = _xl * _yh; \ - _z_f1 = _xh * _yh; \ - \ - /* reassemble into two full words */ \ - if ((_a_f0 += _a_f1) < _a_f1) \ - _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \ - _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \ - _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \ - _FP_FRAC_ADD_2(_z, _z, _a); \ - \ - /* normalize */ \ - _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \ - R##_f = _z_f0; \ - } while (0) - - -/* - * Division algorithms: - */ - -/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the - division immediately. Give this macro either _FP_DIV_HELP_imm for - C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you - choose will depend on what the compiler does with divrem4. */ - -#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \ - do { \ - _FP_W_TYPE _q, _r; \ - X##_f <<= (X##_f < Y##_f \ - ? R##_e--, _FP_WFRACBITS_##fs \ - : _FP_WFRACBITS_##fs - 1); \ - doit(_q, _r, X##_f, Y##_f); \ - R##_f = _q | (_r != 0); \ - } while (0) - -/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd - that may be useful in this situation. This first is for a primitive - that requires normalization, the second for one that does not. Look - for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */ - -#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _nh, _nl, _q, _r; \ - \ - /* Normalize Y -- i.e. make the most significant bit set. */ \ - Y##_f <<= _FP_WFRACXBITS_##fs - 1; \ - \ - /* Shift X op correspondingly high, that is, up one full word. */ \ - if (X##_f <= Y##_f) \ - { \ - _nl = 0; \ - _nh = X##_f; \ - } \ - else \ - { \ - R##_e++; \ - _nl = X##_f << (_FP_W_TYPE_SIZE-1); \ - _nh = X##_f >> 1; \ - } \ - \ - udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ - R##_f = _q | (_r != 0); \ - } while (0) - -#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _nh, _nl, _q, _r; \ - if (X##_f < Y##_f) \ - { \ - R##_e--; \ - _nl = X##_f << _FP_WFRACBITS_##fs; \ - _nh = X##_f >> _FP_WFRACXBITS_##fs; \ - } \ - else \ - { \ - _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \ - _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \ - } \ - udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \ - R##_f = _q | (_r != 0); \ - } while (0) - - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - */ - -#define _FP_SQRT_MEAT_1(R, S, T, X, q) \ - do { \ - while (q != _FP_WORK_ROUND) \ - { \ - T##_f = S##_f + q; \ - if (T##_f <= X##_f) \ - { \ - S##_f = T##_f + q; \ - X##_f -= T##_f; \ - R##_f += q; \ - } \ - _FP_FRAC_SLL_1(X, 1); \ - q >>= 1; \ - } \ - if (X##_f) \ - { \ - if (S##_f < X##_f) \ - R##_f |= _FP_WORK_ROUND; \ - R##_f |= _FP_WORK_STICKY; \ - } \ - } while (0) - -/* - * Assembly/disassembly for converting to/from integral types. - * No shifting or overflow handled here. - */ - -#define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f) -#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r) - - -/* - * Convert FP values between word sizes - */ - -#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \ - do { \ - D##_f = S##_f; \ - if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \ - { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs)); \ - } \ - else \ - D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \ - } while (0) diff --git a/arch/sparc64/math-emu/op-2.h b/arch/sparc64/math-emu/op-2.h deleted file mode 100644 index 9735244a5..000000000 --- a/arch/sparc64/math-emu/op-2.h +++ /dev/null @@ -1,513 +0,0 @@ -/* Software floating-point emulation. - Basic two-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1 -#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1) -#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I) -#define _FP_FRAC_HIGH_2(X) (X##_f1) -#define _FP_FRAC_LOW_2(X) (X##_f0) -#define _FP_FRAC_WORD_2(X,w) (X##_f##w) - -#define _FP_FRAC_SLL_2(X,N) \ - do { \ - if ((N) < _FP_W_TYPE_SIZE) \ - { \ - if (__builtin_constant_p(N) && (N) == 1) \ - { \ - X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \ - X##_f0 += X##_f0; \ - } \ - else \ - { \ - X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \ - X##_f0 <<= (N); \ - } \ - } \ - else \ - { \ - X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \ - X##_f0 = 0; \ - } \ - } while (0) - -#define _FP_FRAC_SRL_2(X,N) \ - do { \ - if ((N) < _FP_W_TYPE_SIZE) \ - { \ - X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \ - X##_f1 >>= (N); \ - } \ - else \ - { \ - X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \ - X##_f1 = 0; \ - } \ - } while (0) - -/* Right shift with sticky-lsb. */ -#define _FP_FRAC_SRS_2(X,N,sz) \ - do { \ - if ((N) < _FP_W_TYPE_SIZE) \ - { \ - X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \ - (__builtin_constant_p(N) && (N) == 1 \ - ? X##_f0 & 1 \ - : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \ - X##_f1 >>= (N); \ - } \ - else \ - { \ - X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \ - (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \ - X##_f1 = 0; \ - } \ - } while (0) - -#define _FP_FRAC_ADDI_2(X,I) \ - __FP_FRAC_ADDI_2(X##_f1, X##_f0, I) - -#define _FP_FRAC_ADD_2(R,X,Y) \ - __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) - -#define _FP_FRAC_SUB_2(R,X,Y) \ - __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0) - -#define _FP_FRAC_DEC_2(X,Y) \ - __FP_FRAC_DEC_2(X##_f1, X##_f0, Y##_f1, Y##_f0) - -#define _FP_FRAC_CLZ_2(R,X) \ - do { \ - if (X##_f1) \ - __FP_CLZ(R,X##_f1); \ - else \ - { \ - __FP_CLZ(R,X##_f0); \ - R += _FP_W_TYPE_SIZE; \ - } \ - } while(0) - -/* Predicates */ -#define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0) -#define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0) -#define _FP_FRAC_OVERP_2(fs,X) (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs) -#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0) -#define _FP_FRAC_GT_2(X, Y) \ - (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 > Y##_f0) -#define _FP_FRAC_GE_2(X, Y) \ - (X##_f1 > Y##_f1 || X##_f1 == Y##_f1 && X##_f0 >= Y##_f0) - -#define _FP_ZEROFRAC_2 0, 0 -#define _FP_MINFRAC_2 0, 1 -#define _FP_MAXFRAC_2 (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0) - -/* - * Internals - */ - -#define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1) - -#define __FP_CLZ_2(R, xh, xl) \ - do { \ - if (xh) \ - __FP_CLZ(R,xh); \ - else \ - { \ - __FP_CLZ(R,xl); \ - R += _FP_W_TYPE_SIZE; \ - } \ - } while(0) - -#if 0 - -#ifndef __FP_FRAC_ADDI_2 -#define __FP_FRAC_ADDI_2(xh, xl, i) \ - (xh += ((xl += i) < i)) -#endif -#ifndef __FP_FRAC_ADD_2 -#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \ - (rh = xh + yh + ((rl = xl + yl) < xl)) -#endif -#ifndef __FP_FRAC_SUB_2 -#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \ - (rh = xh - yh - ((rl = xl - yl) > xl)) -#endif -#ifndef __FP_FRAC_DEC_2 -#define __FP_FRAC_DEC_2(xh, xl, yh, yl) \ - do { \ - UWtype _t = xl; \ - xh -= yh + ((xl -= yl) > _t); \ - } while (0) -#endif - -#else - -#undef __FP_FRAC_ADDI_2 -#define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i) -#undef __FP_FRAC_ADD_2 -#define __FP_FRAC_ADD_2 add_ssaaaa -#undef __FP_FRAC_SUB_2 -#define __FP_FRAC_SUB_2 sub_ddmmss -#undef __FP_FRAC_DEC_2 -#define __FP_FRAC_DEC_2(xh, xl, yh, yl) sub_ddmmss(xh, xl, xh, xl, yh, yl) - -#endif - -/* - * Unpack the raw bits of a native fp value. Do not classify or - * normalize the data. - */ - -#define _FP_UNPACK_RAW_2(fs, X, val) \ - do { \ - union _FP_UNION_##fs _flo; _flo.flt = (val); \ - \ - X##_f0 = _flo.bits.frac0; \ - X##_f1 = _flo.bits.frac1; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - } while (0) - -#define _FP_UNPACK_RAW_2_P(fs, X, val) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - X##_f0 = _flo->bits.frac0; \ - X##_f1 = _flo->bits.frac1; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - } while (0) - - -/* - * Repack the raw bits of a native fp value. - */ - -#define _FP_PACK_RAW_2(fs, val, X) \ - do { \ - union _FP_UNION_##fs _flo; \ - \ - _flo.bits.frac0 = X##_f0; \ - _flo.bits.frac1 = X##_f1; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - \ - (val) = _flo.flt; \ - } while (0) - -#define _FP_PACK_RAW_2_P(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - _flo->bits.frac0 = X##_f0; \ - _flo->bits.frac1 = X##_f1; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - - -/* - * Multiplication algorithms: - */ - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \ - do { \ - _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ - \ - doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ - doit(_b_f1, _b_f0, X##_f0, Y##_f1); \ - doit(_c_f1, _c_f0, X##_f1, Y##_f0); \ - doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \ - \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _b_f1, _b_f0, \ - _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0, \ - _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1)); \ - \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - R##_f0 = _FP_FRAC_WORD_4(_z,0); \ - R##_f1 = _FP_FRAC_WORD_4(_z,1); \ - } while (0) - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. - Do only 3 multiplications instead of four. This one is for machines - where multiplication is much more expensive than subtraction. */ - -#define _FP_MUL_MEAT_2_wide_3mul(fs, R, X, Y, doit) \ - do { \ - _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ - _FP_W_TYPE _d; \ - int _c1, _c2; \ - \ - _b_f0 = X##_f0 + X##_f1; \ - _c1 = _b_f0 < X##_f0; \ - _b_f1 = Y##_f0 + Y##_f1; \ - _c2 = _b_f1 < Y##_f0; \ - doit(_d, _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \ - doit(_FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1), _b_f0, _b_f1); \ - doit(_c_f1, _c_f0, X##_f1, Y##_f1); \ - \ - _b_f0 &= -_c2; \ - _b_f1 &= -_c1; \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), (_c1 & _c2), 0, _d, \ - 0, _FP_FRAC_WORD_4(_z,2), _FP_FRAC_WORD_4(_z,1)); \ - __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _b_f0); \ - __FP_FRAC_ADDI_2(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _b_f1); \ - __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), \ - 0, _d, _FP_FRAC_WORD_4(_z,0)); \ - __FP_FRAC_DEC_3(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \ - _FP_FRAC_WORD_4(_z,1), 0, _c_f1, _c_f0); \ - __FP_FRAC_ADD_2(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), \ - _c_f1, _c_f0, \ - _FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2)); \ - \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - R##_f0 = _FP_FRAC_WORD_4(_z,0); \ - R##_f1 = _FP_FRAC_WORD_4(_z,1); \ - } while (0) - -#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \ - do { \ - _FP_FRAC_DECL_4(_z); \ - _FP_W_TYPE _x[2], _y[2]; \ - _x[0] = X##_f0; _x[1] = X##_f1; \ - _y[0] = Y##_f0; _y[1] = Y##_f1; \ - \ - mpn_mul_n(_z_f, _x, _y, 2); \ - \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \ - R##_f0 = _z_f[0]; \ - R##_f1 = _z_f[1]; \ - } while (0) - - -/* - * Division algorithms: - */ - -#define _FP_DIV_MEAT_2_udiv(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _n_f2, _n_f1, _n_f0, _r_f1, _r_f0, _m_f1, _m_f0; \ - if (_FP_FRAC_GT_2(X, Y)) \ - { \ - _n_f2 = X##_f1 >> 1; \ - _n_f1 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \ - _n_f0 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \ - } \ - else \ - { \ - R##_e--; \ - _n_f2 = X##_f1; \ - _n_f1 = X##_f0; \ - _n_f0 = 0; \ - } \ - \ - /* Normalize, i.e. make the most significant bit of the \ - denominator set. */ \ - _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs); \ - \ - udiv_qrnnd(R##_f1, _r_f1, _n_f2, _n_f1, Y##_f1); \ - umul_ppmm(_m_f1, _m_f0, R##_f1, Y##_f0); \ - _r_f0 = _n_f0; \ - if (_FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f1--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f1--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - } \ - } \ - _FP_FRAC_DEC_2(_r, _m); \ - \ - if (_r_f1 == Y##_f1) \ - { \ - /* This is a special case, not an optimization \ - (_r/Y##_f1 would not fit into UWtype). \ - As _r is guaranteed to be < Y, R##_f0 can be either \ - (UWtype)-1 or (UWtype)-2. But as we know what kind \ - of bits it is (sticky, guard, round), we don't care. \ - We also don't care what the reminder is, because the \ - guard bit will be set anyway. -jj */ \ - R##_f0 = -1; \ - } \ - else \ - { \ - udiv_qrnnd(R##_f0, _r_f1, _r_f1, _r_f0, Y##_f1); \ - umul_ppmm(_m_f1, _m_f0, R##_f0, Y##_f0); \ - _r_f0 = 0; \ - if (_FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f0--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \ - { \ - R##_f0--; \ - _FP_FRAC_ADD_2(_r, Y, _r); \ - } \ - } \ - if (!_FP_FRAC_EQ_2(_r, _m)) \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } while (0) - - -#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \ - do { \ - _FP_W_TYPE _x[4], _y[2], _z[4]; \ - _y[0] = Y##_f0; _y[1] = Y##_f1; \ - _x[0] = _x[3] = 0; \ - if (_FP_FRAC_GT_2(X, Y)) \ - { \ - R##_e++; \ - _x[1] = (X##_f0 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE) | \ - X##_f1 >> (_FP_W_TYPE_SIZE - \ - (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE))); \ - _x[2] = X##_f1 << (_FP_WFRACBITS_##fs-1 - _FP_W_TYPE_SIZE); \ - } \ - else \ - { \ - _x[1] = (X##_f0 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE) | \ - X##_f1 >> (_FP_W_TYPE_SIZE - \ - (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE))); \ - _x[2] = X##_f1 << (_FP_WFRACBITS_##fs - _FP_W_TYPE_SIZE); \ - } \ - \ - (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \ - R##_f1 = _z[1]; \ - R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \ - } while (0) - - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - */ - -#define _FP_SQRT_MEAT_2(R, S, T, X, q) \ - do { \ - while (q) \ - { \ - T##_f1 = S##_f1 + q; \ - if (T##_f1 <= X##_f1) \ - { \ - S##_f1 = T##_f1 + q; \ - X##_f1 -= T##_f1; \ - R##_f1 += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q != _FP_WORK_ROUND) \ - { \ - T##_f0 = S##_f0 + q; \ - T##_f1 = S##_f1; \ - if (T##_f1 < X##_f1 || \ - (T##_f1 == X##_f1 && T##_f0 <= X##_f0)) \ - { \ - S##_f0 = T##_f0 + q; \ - S##_f1 += (T##_f0 > S##_f0); \ - _FP_FRAC_DEC_2(X, T); \ - R##_f0 += q; \ - } \ - _FP_FRAC_SLL_2(X, 1); \ - q >>= 1; \ - } \ - if (X##_f0 | X##_f1) \ - { \ - if (S##_f1 < X##_f1 || \ - (S##_f1 == X##_f1 && S##_f0 < X##_f0)) \ - R##_f0 |= _FP_WORK_ROUND; \ - R##_f0 |= _FP_WORK_STICKY; \ - } \ - } while (0) - - -/* - * Assembly/disassembly for converting to/from integral types. - * No shifting or overflow handled here. - */ - -#define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \ - do { \ - if (rsize <= _FP_W_TYPE_SIZE) \ - r = X##_f0; \ - else \ - { \ - r = X##_f1; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f0; \ - } \ - } while (0) - -#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \ - do { \ - X##_f0 = r; \ - X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ - } while (0) - -/* - * Convert FP values between word sizes - */ - -#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \ - do { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - D##_f = S##_f0; \ - } while (0) - -#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \ - do { \ - D##_f0 = S##_f; \ - D##_f1 = 0; \ - _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ - } while (0) - diff --git a/arch/sparc64/math-emu/op-4.h b/arch/sparc64/math-emu/op-4.h deleted file mode 100644 index 7f027d580..000000000 --- a/arch/sparc64/math-emu/op-4.h +++ /dev/null @@ -1,661 +0,0 @@ -/* Software floating-point emulation. - Basic four-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4] -#define _FP_FRAC_COPY_4(D,S) \ - (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \ - D##_f[2] = S##_f[2], D##_f[3] = S##_f[3]) -#define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I) -#define _FP_FRAC_HIGH_4(X) (X##_f[3]) -#define _FP_FRAC_LOW_4(X) (X##_f[0]) -#define _FP_FRAC_WORD_4(X,w) (X##_f[w]) - -#define _FP_FRAC_SLL_4(X,N) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _up = (N) % _FP_W_TYPE_SIZE; \ - _down = _FP_W_TYPE_SIZE - _up; \ - if (!_up) \ - for (_i = 3; _i >= _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip]; \ - else \ - { \ - for (_i = 3; _i > _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip] << _up \ - | X##_f[_i-_skip-1] >> _down; \ - X##_f[_i--] = X##_f[0] << _up; \ - } \ - for (; _i >= 0; --_i) \ - X##_f[_i] = 0; \ - } while (0) - -/* This one was broken too */ -#define _FP_FRAC_SRL_4(X,N) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _down = (N) % _FP_W_TYPE_SIZE; \ - _up = _FP_W_TYPE_SIZE - _down; \ - if (!_down) \ - for (_i = 0; _i <= 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[3] >> _down; \ - } \ - for (; _i < 4; ++_i) \ - X##_f[_i] = 0; \ - } while (0) - - -/* Right shift with sticky-lsb. - * What this actually means is that we do a standard right-shift, - * but that if any of the bits that fall off the right hand side - * were one then we always set the LSbit. - */ -#define _FP_FRAC_SRS_4(X,N,size) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _FP_W_TYPE _s; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _down = (N) % _FP_W_TYPE_SIZE; \ - _up = _FP_W_TYPE_SIZE - _down; \ - for (_s = _i = 0; _i < _skip; ++_i) \ - _s |= X##_f[_i]; \ - _s |= X##_f[_i] << _up; \ -/* s is now != 0 if we want to set the LSbit */ \ - if (!_down) \ - for (_i = 0; _i <= 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 3-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[3] >> _down; \ - } \ - for (; _i < 4; ++_i) \ - X##_f[_i] = 0; \ - /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ - X##_f[0] |= (_s != 0); \ - } while (0) - -#define _FP_FRAC_ADD_4(R,X,Y) \ - __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ - X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) - -#define _FP_FRAC_SUB_4(R,X,Y) \ - __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \ - X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) - -#define _FP_FRAC_DEC_4(X,Y) \ - __FP_FRAC_DEC_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0]) - -#define _FP_FRAC_ADDI_4(X,I) \ - __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I) - -#define _FP_ZEROFRAC_4 0,0,0,0 -#define _FP_MINFRAC_4 0,0,0,1 -#define _FP_MAXFRAC_4 (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0), (~(_FP_WS_TYPE)0) - -#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0) -#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0) -#define _FP_FRAC_OVERP_4(fs,X) (_FP_FRAC_HIGH_##fs(X) & _FP_OVERFLOW_##fs) - -#define _FP_FRAC_EQ_4(X,Y) \ - (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \ - && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3]) - -#define _FP_FRAC_GT_4(X,Y) \ - (X##_f[3] > Y##_f[3] || \ - (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ - (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ - (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \ - )) \ - )) \ - ) - -#define _FP_FRAC_GE_4(X,Y) \ - (X##_f[3] > Y##_f[3] || \ - (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \ - (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \ - (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \ - )) \ - )) \ - ) - - -#define _FP_FRAC_CLZ_4(R,X) \ - do { \ - if (X##_f[3]) \ - { \ - __FP_CLZ(R,X##_f[3]); \ - } \ - else if (X##_f[2]) \ - { \ - __FP_CLZ(R,X##_f[2]); \ - R += _FP_W_TYPE_SIZE; \ - } \ - else if (X##_f[1]) \ - { \ - __FP_CLZ(R,X##_f[2]); \ - R += _FP_W_TYPE_SIZE*2; \ - } \ - else \ - { \ - __FP_CLZ(R,X##_f[0]); \ - R += _FP_W_TYPE_SIZE*3; \ - } \ - } while(0) - - -#define _FP_UNPACK_RAW_4(fs, X, val) \ - do { \ - union _FP_UNION_##fs _flo; _flo.flt = (val); \ - X##_f[0] = _flo.bits.frac0; \ - X##_f[1] = _flo.bits.frac1; \ - X##_f[2] = _flo.bits.frac2; \ - X##_f[3] = _flo.bits.frac3; \ - X##_e = _flo.bits.exp; \ - X##_s = _flo.bits.sign; \ - } while (0) - -#define _FP_UNPACK_RAW_4_P(fs, X, val) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - X##_f[0] = _flo->bits.frac0; \ - X##_f[1] = _flo->bits.frac1; \ - X##_f[2] = _flo->bits.frac2; \ - X##_f[3] = _flo->bits.frac3; \ - X##_e = _flo->bits.exp; \ - X##_s = _flo->bits.sign; \ - } while (0) - -#define _FP_PACK_RAW_4(fs, val, X) \ - do { \ - union _FP_UNION_##fs _flo; \ - _flo.bits.frac0 = X##_f[0]; \ - _flo.bits.frac1 = X##_f[1]; \ - _flo.bits.frac2 = X##_f[2]; \ - _flo.bits.frac3 = X##_f[3]; \ - _flo.bits.exp = X##_e; \ - _flo.bits.sign = X##_s; \ - (val) = _flo.flt; \ - } while (0) - -#define _FP_PACK_RAW_4_P(fs, val, X) \ - do { \ - union _FP_UNION_##fs *_flo = \ - (union _FP_UNION_##fs *)(val); \ - \ - _flo->bits.frac0 = X##_f[0]; \ - _flo->bits.frac1 = X##_f[1]; \ - _flo->bits.frac2 = X##_f[2]; \ - _flo->bits.frac3 = X##_f[3]; \ - _flo->bits.exp = X##_e; \ - _flo->bits.sign = X##_s; \ - } while (0) - -/* - * Multiplication algorithms: - */ - -/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */ - -#define _FP_MUL_MEAT_4_wide(fs, R, X, Y, doit) \ - do { \ - _FP_FRAC_DECL_8(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \ - _FP_FRAC_DECL_2(_d); _FP_FRAC_DECL_2(_e); _FP_FRAC_DECL_2(_f); \ - \ - doit(_FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0), X##_f[0], Y##_f[0]); \ - doit(_b_f1, _b_f0, X##_f[0], Y##_f[1]); \ - doit(_c_f1, _c_f0, X##_f[1], Y##_f[0]); \ - doit(_d_f1, _d_f0, X##_f[1], Y##_f[1]); \ - doit(_e_f1, _e_f0, X##_f[0], Y##_f[2]); \ - doit(_f_f1, _f_f0, X##_f[2], Y##_f[0]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), 0,_b_f1,_b_f0, \ - 0,0,_FP_FRAC_WORD_8(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_d_f1,_d_f0, \ - 0,_FP_FRAC_WORD_8(_z,3),_FP_FRAC_WORD_8(_z,2)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_e_f1,_e_f0, \ - _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2), 0,_f_f1,_f_f0, \ - _FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3), \ - _FP_FRAC_WORD_8(_z,2)); \ - doit(_b_f1, _b_f0, X##_f[0], Y##_f[3]); \ - doit(_c_f1, _c_f0, X##_f[3], Y##_f[0]); \ - doit(_d_f1, _d_f0, X##_f[1], Y##_f[2]); \ - doit(_e_f1, _e_f0, X##_f[2], Y##_f[1]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_b_f1,_b_f0, \ - 0,_FP_FRAC_WORD_8(_z,4),_FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_d_f1,_d_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3), 0,_e_f1,_e_f0, \ - _FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4), \ - _FP_FRAC_WORD_8(_z,3)); \ - doit(_b_f1, _b_f0, X##_f[2], Y##_f[2]); \ - doit(_c_f1, _c_f0, X##_f[1], Y##_f[3]); \ - doit(_d_f1, _d_f0, X##_f[3], Y##_f[1]); \ - doit(_e_f1, _e_f0, X##_f[2], Y##_f[3]); \ - doit(_f_f1, _f_f0, X##_f[3], Y##_f[2]); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_b_f1,_b_f0, \ - 0,_FP_FRAC_WORD_8(_z,5),_FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_c_f1,_c_f0, \ - _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4), 0,_d_f1,_d_f0, \ - _FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5), \ - _FP_FRAC_WORD_8(_z,4)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5), 0,_e_f1,_e_f0, \ - 0,_FP_FRAC_WORD_8(_z,6),_FP_FRAC_WORD_8(_z,5)); \ - __FP_FRAC_ADD_3(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5), 0,_f_f1,_f_f0, \ - _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _FP_FRAC_WORD_8(_z,5)); \ - doit(_b_f1, _b_f0, X##_f[3], Y##_f[3]); \ - __FP_FRAC_ADD_2(_FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6), \ - _b_f1,_b_f0, \ - _FP_FRAC_WORD_8(_z,7),_FP_FRAC_WORD_8(_z,6)); \ - \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0)); \ - } while (0) - -#define _FP_MUL_MEAT_4_gmp(fs, R, X, Y) \ - do { \ - _FP_FRAC_DECL_8(_z); \ - \ - mpn_mul_n(_z_f, _x_f, _y_f, 4); \ - \ - /* Normalize since we know where the msb of the multiplicands \ - were (bit B), we know that the msb of the of the product is \ - at either 2B or 2B-1. */ \ - _FP_FRAC_SRS_8(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \ - __FP_FRAC_SET_4(R, _FP_FRAC_WORD_8(_z,3), _FP_FRAC_WORD_8(_z,2), \ - _FP_FRAC_WORD_8(_z,1), _FP_FRAC_WORD_8(_z,0)); \ - } while (0) - -/* - * Helper utility for _FP_DIV_MEAT_4_udiv: - * pppp = m * nnn - */ -#define umul_ppppmnnn(p3,p2,p1,p0,m,n2,n1,n0) \ - do { \ - UWtype _t; \ - umul_ppmm(p1,p0,m,n0); \ - umul_ppmm(p2,_t,m,n1); \ - __FP_FRAC_ADDI_2(p2,p1,_t); \ - umul_ppmm(p3,_t,m,n2); \ - __FP_FRAC_ADDI_2(p3,p2,_t); \ - } while (0) - -/* - * Division algorithms: - */ - -#define _FP_DIV_MEAT_4_udiv(fs, R, X, Y) \ - do { \ - int _i; \ - _FP_FRAC_DECL_4(_n); _FP_FRAC_DECL_4(_m); \ - _FP_FRAC_SET_4(_n, _FP_ZEROFRAC_4); \ - if (_FP_FRAC_GT_4(X, Y)) \ - { \ - _n_f[3] = X##_f[0] << (_FP_W_TYPE_SIZE - 1); \ - _FP_FRAC_SRL_4(X, 1); \ - } \ - else \ - R##_e--; \ - \ - /* Normalize, i.e. make the most significant bit of the \ - denominator set. */ \ - _FP_FRAC_SLL_4(Y, _FP_WFRACXBITS_##fs); \ - \ - for (_i = 3; ; _i--) \ - { \ - if (X##_f[3] == Y##_f[3]) \ - { \ - /* This is a special case, not an optimization \ - (X##_f[3]/Y##_f[3] would not fit into UWtype). \ - As X## is guaranteed to be < Y, R##_f[_i] can be either \ - (UWtype)-1 or (UWtype)-2. */ \ - R##_f[_i] = -1; \ - if (!_i) \ - break; \ - __FP_FRAC_SUB_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], \ - Y##_f[2], Y##_f[1], Y##_f[0], 0, \ - X##_f[2], X##_f[1], X##_f[0], _n_f[_i]); \ - _FP_FRAC_SUB_4(X, Y, X); \ - if (X##_f[3] > Y##_f[3]) \ - { \ - R##_f[_i] = -2; \ - _FP_FRAC_ADD_4(X, Y, X); \ - } \ - } \ - else \ - { \ - udiv_qrnnd(R##_f[_i], X##_f[3], X##_f[3], X##_f[2], Y##_f[3]); \ - umul_ppppmnnn(_m_f[3], _m_f[2], _m_f[1], _m_f[0], \ - R##_f[_i], Y##_f[2], Y##_f[1], Y##_f[0]); \ - X##_f[2] = X##_f[1]; \ - X##_f[1] = X##_f[0]; \ - X##_f[0] = _n_f[_i]; \ - if (_FP_FRAC_GT_4(_m, X)) \ - { \ - R##_f[_i]--; \ - _FP_FRAC_ADD_4(X, Y, X); \ - if (_FP_FRAC_GE_4(X, Y) && _FP_FRAC_GT_4(_m, X)) \ - { \ - R##_f[_i]--; \ - _FP_FRAC_ADD_4(X, Y, X); \ - } \ - } \ - _FP_FRAC_DEC_4(X, _m); \ - if (!_i) \ - { \ - if (!_FP_FRAC_EQ_4(X, _m)) \ - R##_f[0] |= _FP_WORK_STICKY; \ - break; \ - } \ - } \ - } \ - } while (0) - - -/* - * Square root algorithms: - * We have just one right now, maybe Newton approximation - * should be added for those machines where division is fast. - */ - -#define _FP_SQRT_MEAT_4(R, S, T, X, q) \ - do { \ - while (q) \ - { \ - T##_f[3] = S##_f[3] + q; \ - if (T##_f[3] <= X##_f[3]) \ - { \ - S##_f[3] = T##_f[3] + q; \ - X##_f[3] -= T##_f[3]; \ - R##_f[3] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[2] = S##_f[2] + q; \ - T##_f[3] = S##_f[3]; \ - if (T##_f[3] < X##_f[3] || \ - (T##_f[3] == X##_f[3] && T##_f[2] <= X##_f[2])) \ - { \ - S##_f[2] = T##_f[2] + q; \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - __FP_FRAC_DEC_2(X##_f[3], X##_f[2], \ - T##_f[3], T##_f[2]); \ - R##_f[2] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q) \ - { \ - T##_f[1] = S##_f[1] + q; \ - T##_f[2] = S##_f[2]; \ - T##_f[3] = S##_f[3]; \ - if (T##_f[3] < X##_f[3] || \ - (T##_f[3] == X##_f[3] && (T##_f[2] < X##_f[2] || \ - (T##_f[2] == X##_f[2] && T##_f[1] <= X##_f[1])))) \ - { \ - S##_f[1] = T##_f[1] + q; \ - S##_f[2] += (T##_f[1] > S##_f[1]); \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - __FP_FRAC_DEC_3(X##_f[3], X##_f[2], X##_f[1], \ - T##_f[3], T##_f[2], T##_f[1]); \ - R##_f[1] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \ - while (q != _FP_WORK_ROUND) \ - { \ - T##_f[0] = S##_f[0] + q; \ - T##_f[1] = S##_f[1]; \ - T##_f[2] = S##_f[2]; \ - T##_f[3] = S##_f[3]; \ - if (_FP_FRAC_GE_4(X,T)) \ - { \ - S##_f[0] = T##_f[0] + q; \ - S##_f[1] += (T##_f[0] > S##_f[0]); \ - S##_f[2] += (T##_f[1] > S##_f[1]); \ - S##_f[3] += (T##_f[2] > S##_f[2]); \ - _FP_FRAC_DEC_4(X, T); \ - R##_f[0] += q; \ - } \ - _FP_FRAC_SLL_4(X, 1); \ - q >>= 1; \ - } \ - if (!_FP_FRAC_ZEROP_4(X)) \ - { \ - if (_FP_FRAC_GT_4(X,S)) \ - R##_f[0] |= _FP_WORK_ROUND; \ - R##_f[0] |= _FP_WORK_STICKY; \ - } \ - } while (0) - - -/* - * Internals - */ - -#define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \ - (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0) - -#ifndef __FP_FRAC_ADD_3 -#define __FP_FRAC_ADD_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - (r0 = x0 + y0, \ - r1 = x1 + y1 + (r0 < x0), \ - r2 = x2 + y2 + (r1 < x1)) -#endif - -#ifndef __FP_FRAC_ADD_4 -#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ - (r0 = x0 + y0, \ - r1 = x1 + y1 + (r0 < x0), \ - r2 = x2 + y2 + (r1 < x1), \ - r3 = x3 + y3 + (r2 < x2)) -#endif - -#ifndef __FP_FRAC_SUB_3 -#define __FP_FRAC_SUB_3(r2,r1,r0,x2,x1,x0,y2,y1,y0) \ - (r0 = x0 - y0, \ - r1 = x1 - y1 - (r0 > x0), \ - r2 = x2 - y2 - (r1 > x1)) -#endif - -#ifndef __FP_FRAC_SUB_4 -#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \ - (r0 = x0 - y0, \ - r1 = x1 - y1 - (r0 > x0), \ - r2 = x2 - y2 - (r1 > x1), \ - r3 = x3 - y3 - (r2 > x2)) -#endif - -#ifndef __FP_FRAC_DEC_3 -#define __FP_FRAC_DEC_3(x2,x1,x0,y2,y1,y0) \ - do { \ - UWtype _t0, _t1; \ - _t0 = x0; \ - x0 -= y0; \ - _t1 = x1; \ - x1 -= y1 + (x0 > _t0); \ - x2 -= y2 + (x1 > _t1); \ - } while (0) -#endif - -#ifndef __FP_FRAC_DEC_4 -#define __FP_FRAC_DEC_4(x3,x2,x1,x0,y3,y2,y1,y0) \ - do { \ - UWtype _t0, _t1; \ - _t0 = x0; \ - x0 -= y0; \ - _t1 = x1; \ - x1 -= y1 + (x0 > _t0); \ - _t0 = x2; \ - x2 -= y2 + (x1 > _t1); \ - x3 -= y3 + (x2 > _t0); \ - } while (0) -#endif - -#ifndef __FP_FRAC_ADDI_4 -#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \ - do { \ - UWtype _t; \ - _t = ((x0 += i) < i); \ - x1 += _t; _t = (x1 < _t); \ - x2 += _t; _t = (x2 < _t); \ - x3 += _t; \ - } while (0) -#endif - -/* Convert FP values between word sizes. This appears to be more - * complicated than I'd have expected it to be, so these might be - * wrong... These macros are in any case somewhat bogus because they - * use information about what various FRAC_n variables look like - * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do - * the ones in op-2.h and op-1.h. - */ -#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \ - do { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - D##_f = S##_f[0]; \ - } while (0) - -#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \ - do { \ - if (S##_c != FP_CLS_NAN) \ - _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \ - _FP_WFRACBITS_##sfs); \ - else \ - _FP_FRAC_SRL_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs)); \ - D##_f0 = S##_f[0]; \ - D##_f1 = S##_f[1]; \ - } while (0) - -/* Assembly/disassembly for converting to/from integral types. - * No shifting or overflow handled here. - */ -/* Put the FP value X into r, which is an integer of size rsize. */ -#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \ - do { \ - if (rsize <= _FP_W_TYPE_SIZE) \ - r = X##_f[0]; \ - else if (rsize <= 2*_FP_W_TYPE_SIZE) \ - { \ - r = X##_f[1]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[0]; \ - } \ - else \ - { \ - /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \ - /* and int == 4words as a single case. */ \ - r = X##_f[3]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[2]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[1]; \ - r <<= _FP_W_TYPE_SIZE; \ - r += X##_f[0]; \ - } \ - } while (0) - -/* "No disassemble Number Five!" */ -/* move an integer of size rsize into X's fractional part. We rely on - * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid - * having to mask the values we store into it. - */ -#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \ - do { \ - X##_f[0] = r; \ - X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \ - X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \ - X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \ - } while (0); - -#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \ - do { \ - D##_f[0] = S##_f; \ - D##_f[1] = D##_f[2] = D##_f[3] = 0; \ - _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ - } while (0) - -#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \ - do { \ - D##_f[0] = S##_f0; \ - D##_f[1] = S##_f1; \ - D##_f[2] = D##_f[3] = 0; \ - _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \ - } while (0) - diff --git a/arch/sparc64/math-emu/op-8.h b/arch/sparc64/math-emu/op-8.h deleted file mode 100644 index a9d7dbf59..000000000 --- a/arch/sparc64/math-emu/op-8.h +++ /dev/null @@ -1,103 +0,0 @@ -/* Software floating-point emulation. - Basic eight-word fraction declaration and manipulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* We need just a few things from here for op-4, if we ever need some - other macros, they can be added. */ -#define _FP_FRAC_DECL_8(X) _FP_W_TYPE X##_f[8] -#define _FP_FRAC_HIGH_8(X) (X##_f[7]) -#define _FP_FRAC_LOW_8(X) (X##_f[0]) -#define _FP_FRAC_WORD_8(X,w) (X##_f[w]) - -#define _FP_FRAC_SLL_8(X,N) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _up = (N) % _FP_W_TYPE_SIZE; \ - _down = _FP_W_TYPE_SIZE - _up; \ - if (!_up) \ - for (_i = 7; _i >= _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip]; \ - else \ - { \ - for (_i = 7; _i > _skip; --_i) \ - X##_f[_i] = X##_f[_i-_skip] << _up \ - | X##_f[_i-_skip-1] >> _down; \ - X##_f[_i--] = X##_f[0] << _up; \ - } \ - for (; _i >= 0; --_i) \ - X##_f[_i] = 0; \ - } while (0) - -#define _FP_FRAC_SRL_8(X,N) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _down = (N) % _FP_W_TYPE_SIZE; \ - _up = _FP_W_TYPE_SIZE - _down; \ - if (!_down) \ - for (_i = 0; _i <= 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[7] >> _down; \ - } \ - for (; _i < 8; ++_i) \ - X##_f[_i] = 0; \ - } while (0) - - -/* Right shift with sticky-lsb. - * What this actually means is that we do a standard right-shift, - * but that if any of the bits that fall off the right hand side - * were one then we always set the LSbit. - */ -#define _FP_FRAC_SRS_8(X,N,size) \ - do { \ - _FP_I_TYPE _up, _down, _skip, _i; \ - _FP_W_TYPE _s; \ - _skip = (N) / _FP_W_TYPE_SIZE; \ - _down = (N) % _FP_W_TYPE_SIZE; \ - _up = _FP_W_TYPE_SIZE - _down; \ - for (_s = _i = 0; _i < _skip; ++_i) \ - _s |= X##_f[_i]; \ - _s |= X##_f[_i] << _up; \ -/* s is now != 0 if we want to set the LSbit */ \ - if (!_down) \ - for (_i = 0; _i <= 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip]; \ - else \ - { \ - for (_i = 0; _i < 7-_skip; ++_i) \ - X##_f[_i] = X##_f[_i+_skip] >> _down \ - | X##_f[_i+_skip+1] << _up; \ - X##_f[_i++] = X##_f[7] >> _down; \ - } \ - for (; _i < 8; ++_i) \ - X##_f[_i] = 0; \ - /* don't fix the LSB until the very end when we're sure f[0] is stable */ \ - X##_f[0] |= (_s != 0); \ - } while (0) - diff --git a/arch/sparc64/math-emu/op-common.h b/arch/sparc64/math-emu/op-common.h deleted file mode 100644 index 529f0e4b2..000000000 --- a/arch/sparc64/math-emu/op-common.h +++ /dev/null @@ -1,760 +0,0 @@ -/* Software floating-point emulation. Common operations. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#define _FP_DECL(wc, X) \ - _FP_I_TYPE X##_c, X##_s, X##_e; \ - _FP_FRAC_DECL_##wc(X) - -/* - * Finish truely unpacking a native fp value by classifying the kind - * of fp value and normalizing both the exponent and the fraction. - */ - -#define _FP_UNPACK_CANONICAL(fs, wc, X) \ -do { \ - switch (X##_e) \ - { \ - default: \ - _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_IMPLBIT_##fs; \ - _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \ - X##_e -= _FP_EXPBIAS_##fs; \ - X##_c = FP_CLS_NORMAL; \ - break; \ - \ - case 0: \ - if (_FP_FRAC_ZEROP_##wc(X)) \ - X##_c = FP_CLS_ZERO; \ - else \ - { \ - /* a denormalized number */ \ - _FP_I_TYPE _shift; \ - _FP_FRAC_CLZ_##wc(_shift, X); \ - _shift -= _FP_FRACXBITS_##fs; \ - _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \ - X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \ - X##_c = FP_CLS_NORMAL; \ - FP_SET_EXCEPTION(FP_EX_DENORM); \ - } \ - break; \ - \ - case _FP_EXPMAX_##fs: \ - if (_FP_FRAC_ZEROP_##wc(X)) \ - X##_c = FP_CLS_INF; \ - else \ - { \ - X##_c = FP_CLS_NAN; \ - /* Check for signaling NaN */ \ - if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - break; \ - } \ -} while (0) - -/* - * Before packing the bits back into the native fp result, take care - * of such mundane things as rounding and overflow. Also, for some - * kinds of fp values, the original parts may not have been fully - * extracted -- but that is ok, we can regenerate them now. - */ - -#define _FP_PACK_CANONICAL(fs, wc, X) \ -do { \ - switch (X##_c) \ - { \ - case FP_CLS_NORMAL: \ - X##_e += _FP_EXPBIAS_##fs; \ - if (X##_e > 0) \ - { \ - _FP_ROUND(wc, X); \ - if (_FP_FRAC_OVERP_##wc(fs, X)) \ - { \ - _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \ - X##_e++; \ - } \ - else \ - _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ - if (X##_e >= _FP_EXPMAX_##fs) \ - { \ - /* overflow */ \ - switch (FP_ROUNDMODE) \ - { \ - case FP_RND_NEAREST: \ - X##_c = FP_CLS_INF; \ - break; \ - case FP_RND_PINF: \ - if (!X##_s) X##_c = FP_CLS_INF; \ - break; \ - case FP_RND_MINF: \ - if (X##_s) X##_c = FP_CLS_INF; \ - break; \ - } \ - if (X##_c == FP_CLS_INF) \ - { \ - /* Overflow to infinity */ \ - X##_e = _FP_EXPMAX_##fs; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - } \ - else \ - { \ - /* Overflow to maximum normal */ \ - X##_e = _FP_EXPMAX_##fs - 1; \ - _FP_FRAC_SET_##wc(X, _FP_MAXFRAC_##wc); \ - } \ - FP_SET_EXCEPTION(FP_EX_OVERFLOW); \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - } \ - } \ - else \ - { \ - /* we've got a denormalized number */ \ - X##_e = -X##_e + 1; \ - if (X##_e <= _FP_WFRACBITS_##fs) \ - { \ - _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ - _FP_ROUND(wc, X); \ - if (_FP_FRAC_HIGH_##fs(X) \ - & (_FP_OVERFLOW_##fs >> 1)) \ - { \ - X##_e = 1; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - } \ - else \ - { \ - X##_e = 0; \ - _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ - FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ - } \ - } \ - else \ - { \ - /* underflow to zero */ \ - X##_e = 0; \ - if (!_FP_FRAC_ZEROP_##wc(X)) \ - { \ - _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ - _FP_ROUND(wc, X); \ - _FP_FRAC_LOW_##wc(X) >>= (_FP_WORKBITS); \ - } \ - FP_SET_EXCEPTION(FP_EX_UNDERFLOW); \ - } \ - } \ - break; \ - \ - case FP_CLS_ZERO: \ - X##_e = 0; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - break; \ - \ - case FP_CLS_INF: \ - X##_e = _FP_EXPMAX_##fs; \ - _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ - break; \ - \ - case FP_CLS_NAN: \ - X##_e = _FP_EXPMAX_##fs; \ - if (!_FP_KEEPNANFRACP) \ - { \ - _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \ - X##_s = _FP_NANSIGN_##fs; \ - } \ - else \ - _FP_FRAC_HIGH_RAW_##fs(X) |= _FP_QNANBIT_##fs; \ - break; \ - } \ -} while (0) - -/* This one accepts raw argument and not cooked, returns - * 1 if X is a signaling NaN. - */ -#define _FP_ISSIGNAN(fs, wc, X) \ -({ \ - int __ret = 0; \ - if (X##_e == _FP_EXPMAX_##fs) \ - { \ - if (!_FP_FRAC_ZEROP_##wc(X) \ - && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ - __ret = 1; \ - } \ - __ret; \ -}) - - - - - -/* - * Main addition routine. The input values should be cooked. - */ - -#define _FP_ADD(fs, wc, R, X, Y) \ -do { \ - switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ - { \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ - { \ - /* shift the smaller number so that its exponent matches the larger */ \ - _FP_I_TYPE diff = X##_e - Y##_e; \ - \ - if (diff < 0) \ - { \ - diff = -diff; \ - if (diff <= _FP_WFRACBITS_##fs) \ - _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \ - else if (!_FP_FRAC_ZEROP_##wc(X)) \ - _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \ - R##_e = Y##_e; \ - } \ - else \ - { \ - if (diff > 0) \ - { \ - if (diff <= _FP_WFRACBITS_##fs) \ - _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \ - else if (!_FP_FRAC_ZEROP_##wc(Y)) \ - _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \ - } \ - R##_e = X##_e; \ - } \ - \ - R##_c = FP_CLS_NORMAL; \ - \ - if (X##_s == Y##_s) \ - { \ - R##_s = X##_s; \ - _FP_FRAC_ADD_##wc(R, X, Y); \ - if (_FP_FRAC_OVERP_##wc(fs, R)) \ - { \ - _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ - R##_e++; \ - } \ - } \ - else \ - { \ - R##_s = X##_s; \ - _FP_FRAC_SUB_##wc(R, X, Y); \ - if (_FP_FRAC_ZEROP_##wc(R)) \ - { \ - /* return an exact zero */ \ - if (FP_ROUNDMODE == FP_RND_MINF) \ - R##_s |= Y##_s; \ - else \ - R##_s &= Y##_s; \ - R##_c = FP_CLS_ZERO; \ - } \ - else \ - { \ - if (_FP_FRAC_NEGP_##wc(R)) \ - { \ - _FP_FRAC_SUB_##wc(R, Y, X); \ - R##_s = Y##_s; \ - } \ - \ - /* renormalize after subtraction */ \ - _FP_FRAC_CLZ_##wc(diff, R); \ - diff -= _FP_WFRACXBITS_##fs; \ - if (diff) \ - { \ - R##_e -= diff; \ - _FP_FRAC_SLL_##wc(R, diff); \ - } \ - } \ - } \ - break; \ - } \ - \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ - _FP_CHOOSENAN(fs, wc, R, X, Y); \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ - R##_e = X##_e; \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_s = X##_s; \ - R##_c = X##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ - R##_e = Y##_e; \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ - _FP_FRAC_COPY_##wc(R, Y); \ - R##_s = Y##_s; \ - R##_c = Y##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ - if (X##_s != Y##_s) \ - { \ - /* +INF + -INF => NAN */ \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - break; \ - } \ - /* FALLTHRU */ \ - \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ - R##_s = X##_s; \ - R##_c = FP_CLS_INF; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ - R##_s = Y##_s; \ - R##_c = FP_CLS_INF; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ - /* make sure the sign is correct */ \ - if (FP_ROUNDMODE == FP_RND_MINF) \ - R##_s = X##_s | Y##_s; \ - else \ - R##_s = X##_s & Y##_s; \ - R##_c = FP_CLS_ZERO; \ - break; \ - \ - default: \ - abort(); \ - } \ -} while (0) - - -/* - * Main negation routine. FIXME -- when we care about setting exception - * bits reliably, this will not do. We should examine all of the fp classes. - */ - -#define _FP_NEG(fs, wc, R, X) \ - do { \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_c = X##_c; \ - R##_e = X##_e; \ - R##_s = 1 ^ X##_s; \ - } while (0) - - -/* - * Main multiplication routine. The input values should be cooked. - */ - -#define _FP_MUL(fs, wc, R, X, Y) \ -do { \ - R##_s = X##_s ^ Y##_s; \ - switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ - { \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ - R##_c = FP_CLS_NORMAL; \ - R##_e = X##_e + Y##_e + 1; \ - \ - _FP_MUL_MEAT_##fs(R,X,Y); \ - \ - if (_FP_FRAC_OVERP_##wc(fs, R)) \ - _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \ - else \ - R##_e--; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ - _FP_CHOOSENAN(fs, wc, R, X, Y); \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ - R##_s = X##_s; \ - \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_c = X##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ - R##_s = Y##_s; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ - _FP_FRAC_COPY_##wc(R, Y); \ - R##_c = Y##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - break; \ - \ - default: \ - abort(); \ - } \ -} while (0) - - -/* - * Main division routine. The input values should be cooked. - */ - -#define _FP_DIV(fs, wc, R, X, Y) \ -do { \ - R##_s = X##_s ^ Y##_s; \ - switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \ - { \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \ - R##_c = FP_CLS_NORMAL; \ - R##_e = X##_e - Y##_e; \ - \ - _FP_DIV_MEAT_##fs(R,X,Y); \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \ - _FP_CHOOSENAN(fs, wc, R, X, Y); \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \ - R##_s = X##_s; \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_c = X##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \ - R##_s = Y##_s; \ - _FP_FRAC_COPY_##wc(R, Y); \ - R##_c = Y##_c; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \ - R##_c = FP_CLS_ZERO; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \ - FP_SET_EXCEPTION(FP_EX_DIVZERO); \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \ - R##_c = FP_CLS_INF; \ - break; \ - \ - case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \ - case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - break; \ - \ - default: \ - abort(); \ - } \ -} while (0) - - -/* - * Main differential comparison routine. The inputs should be raw not - * cooked. The return is -1,0,1 for normal values, 2 otherwise. - */ - -#define _FP_CMP(fs, wc, ret, X, Y, un) \ - do { \ - /* NANs are unordered */ \ - if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ - || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ - { \ - ret = un; \ - } \ - else \ - { \ - int __is_zero_x; \ - int __is_zero_y; \ - \ - __is_zero_x = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \ - __is_zero_y = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \ - \ - if (__is_zero_x && __is_zero_y) \ - ret = 0; \ - else if (__is_zero_x) \ - ret = Y##_s ? 1 : -1; \ - else if (__is_zero_y) \ - ret = X##_s ? -1 : 1; \ - else if (X##_s != Y##_s) \ - ret = X##_s ? -1 : 1; \ - else if (X##_e > Y##_e) \ - ret = X##_s ? -1 : 1; \ - else if (X##_e < Y##_e) \ - ret = X##_s ? 1 : -1; \ - else if (_FP_FRAC_GT_##wc(X, Y)) \ - ret = X##_s ? -1 : 1; \ - else if (_FP_FRAC_GT_##wc(Y, X)) \ - ret = X##_s ? 1 : -1; \ - else \ - ret = 0; \ - } \ - } while (0) - - -/* Simplification for strict equality. */ - -#define _FP_CMP_EQ(fs, wc, ret, X, Y) \ - do { \ - /* NANs are unordered */ \ - if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \ - || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \ - { \ - ret = 1; \ - } \ - else \ - { \ - ret = !(X##_e == Y##_e \ - && _FP_FRAC_EQ_##wc(X, Y) \ - && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \ - } \ - } while (0) - -/* - * Main square root routine. The input value should be cooked. - */ - -#define _FP_SQRT(fs, wc, R, X) \ -do { \ - _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \ - _FP_W_TYPE q; \ - switch (X##_c) \ - { \ - case FP_CLS_NAN: \ - _FP_FRAC_COPY_##wc(R, X); \ - R##_s = X##_s; \ - R##_c = FP_CLS_NAN; \ - break; \ - case FP_CLS_INF: \ - if (X##_s) \ - { \ - R##_s = _FP_NANSIGN_##fs; \ - R##_c = FP_CLS_NAN; /* NAN */ \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - else \ - { \ - R##_s = 0; \ - R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \ - } \ - break; \ - case FP_CLS_ZERO: \ - R##_s = X##_s; \ - R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \ - break; \ - case FP_CLS_NORMAL: \ - R##_s = 0; \ - if (X##_s) \ - { \ - R##_c = FP_CLS_NAN; /* sNAN */ \ - R##_s = _FP_NANSIGN_##fs; \ - _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - break; \ - } \ - R##_c = FP_CLS_NORMAL; \ - if (X##_e & 1) \ - _FP_FRAC_SLL_##wc(X, 1); \ - R##_e = X##_e >> 1; \ - _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \ - _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \ - q = _FP_OVERFLOW_##fs >> 1; \ - _FP_SQRT_MEAT_##wc(R, S, T, X, q); \ - } \ - } while (0) - -/* - * Convert from FP to integer - */ - -/* RSIGNED can have following values: - * 0: the number is required to be 0..(2^rsize)-1, if not, NV is set plus - * the result is either 0 or (2^rsize)-1 depending on the sign in such case. - * 1: the number is required to be -(2^(rsize-1))..(2^(rsize-1))-1, if not, NV is - * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending - * on the sign in such case. - * -1: the number is required to be -(2^(rsize-1))..(2^rsize)-1, if not, NV is - * set plus the result is either -(2^(rsize-1)) or (2^(rsize-1))-1 depending - * on the sign in such case. - */ -#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \ - do { \ - switch (X##_c) \ - { \ - case FP_CLS_NORMAL: \ - if (X##_e < 0) \ - { \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - case FP_CLS_ZERO: \ - r = 0; \ - } \ - else if (X##_e >= rsize - (rsigned > 0 || X##_s) \ - || (!rsigned && X##_s)) \ - { /* overflow */ \ - case FP_CLS_NAN: \ - case FP_CLS_INF: \ - if (rsigned) \ - { \ - r = 1; \ - r <<= rsize - 1; \ - r -= 1 - X##_s; \ - } else { \ - r = 0; \ - if (X##_s) \ - r = ~r; \ - } \ - FP_SET_EXCEPTION(FP_EX_INVALID); \ - } \ - else \ - { \ - if (_FP_W_TYPE_SIZE*wc < rsize) \ - { \ - _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ - r <<= X##_e - _FP_WFRACBITS_##fs; \ - } \ - else \ - { \ - if (X##_e >= _FP_WFRACBITS_##fs) \ - _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1)); \ - else if (X##_e < _FP_WFRACBITS_##fs - 1) \ - { \ - _FP_FRAC_SRS_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 2), \ - _FP_WFRACBITS_##fs); \ - if (_FP_FRAC_LOW_##wc(X) & 1) \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - _FP_FRAC_SRL_##wc(X, 1); \ - } \ - _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \ - } \ - if (rsigned && X##_s) \ - r = -r; \ - } \ - break; \ - } \ - } while (0) - -#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \ - do { \ - if (r) \ - { \ - X##_c = FP_CLS_NORMAL; \ - \ - if ((X##_s = (r < 0))) \ - r = -r; \ - \ - if (rsize <= _FP_W_TYPE_SIZE) \ - __FP_CLZ(X##_e, r); \ - else \ - __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \ - (_FP_W_TYPE)r); \ - if (rsize < _FP_W_TYPE_SIZE) \ - X##_e -= (_FP_W_TYPE_SIZE - rsize); \ - X##_e = rsize - X##_e - 1; \ - \ - if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \ - __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \ - r &= ~((rtype)1 << X##_e); \ - _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \ - _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \ - } \ - else \ - { \ - X##_c = FP_CLS_ZERO, X##_s = 0; \ - } \ - } while (0) - - -#define FP_CONV(dfs,sfs,dwc,swc,D,S) \ - do { \ - _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \ - D##_e = S##_e; \ - D##_c = S##_c; \ - D##_s = S##_s; \ - } while (0) - -/* - * Helper primitives. - */ - -/* Count leading zeros in a word. */ - -#ifndef __FP_CLZ -#if _FP_W_TYPE_SIZE < 64 -/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */ -#define __FP_CLZ(r, x) \ - do { \ - _FP_W_TYPE _t = (x); \ - r = _FP_W_TYPE_SIZE - 1; \ - if (_t > 0xffff) r -= 16; \ - if (_t > 0xffff) _t >>= 16; \ - if (_t > 0xff) r -= 8; \ - if (_t > 0xff) _t >>= 8; \ - if (_t & 0xf0) r -= 4; \ - if (_t & 0xf0) _t >>= 4; \ - if (_t & 0xc) r -= 2; \ - if (_t & 0xc) _t >>= 2; \ - if (_t & 0x2) r -= 1; \ - } while (0) -#else /* not _FP_W_TYPE_SIZE < 64 */ -#define __FP_CLZ(r, x) \ - do { \ - _FP_W_TYPE _t = (x); \ - r = _FP_W_TYPE_SIZE - 1; \ - if (_t > 0xffffffff) r -= 32; \ - if (_t > 0xffffffff) _t >>= 32; \ - if (_t > 0xffff) r -= 16; \ - if (_t > 0xffff) _t >>= 16; \ - if (_t > 0xff) r -= 8; \ - if (_t > 0xff) _t >>= 8; \ - if (_t & 0xf0) r -= 4; \ - if (_t & 0xf0) _t >>= 4; \ - if (_t & 0xc) r -= 2; \ - if (_t & 0xc) _t >>= 2; \ - if (_t & 0x2) r -= 1; \ - } while (0) -#endif /* not _FP_W_TYPE_SIZE < 64 */ -#endif /* ndef __FP_CLZ */ - -#define _FP_DIV_HELP_imm(q, r, n, d) \ - do { \ - q = n / d, r = n % d; \ - } while (0) - diff --git a/arch/sparc64/math-emu/quad.h b/arch/sparc64/math-emu/quad.h deleted file mode 100644 index 4392a38c1..000000000 --- a/arch/sparc64/math-emu/quad.h +++ /dev/null @@ -1,205 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Quad Precision. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel, kid. Go buy yourself a real computer." -#endif - -#if _FP_W_TYPE_SIZE < 64 -#define _FP_FRACTBITS_Q (4*_FP_W_TYPE_SIZE) -#else -#define _FP_FRACTBITS_Q (2*_FP_W_TYPE_SIZE) -#endif - -#define _FP_FRACBITS_Q 113 -#define _FP_FRACXBITS_Q (_FP_FRACTBITS_Q - _FP_FRACBITS_Q) -#define _FP_WFRACBITS_Q (_FP_WORKBITS + _FP_FRACBITS_Q) -#define _FP_WFRACXBITS_Q (_FP_FRACTBITS_Q - _FP_WFRACBITS_Q) -#define _FP_EXPBITS_Q 15 -#define _FP_EXPBIAS_Q 16383 -#define _FP_EXPMAX_Q 32767 - -#define _FP_QNANBIT_Q \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-2) % _FP_W_TYPE_SIZE) -#define _FP_IMPLBIT_Q \ - ((_FP_W_TYPE)1 << (_FP_FRACBITS_Q-1) % _FP_W_TYPE_SIZE) -#define _FP_OVERFLOW_Q \ - ((_FP_W_TYPE)1 << (_FP_WFRACBITS_Q % _FP_W_TYPE_SIZE)) - -#if _FP_W_TYPE_SIZE < 64 - -union _FP_UNION_Q -{ - long double flt; - struct - { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_Q; - unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3); - unsigned long frac2 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac0 : _FP_W_TYPE_SIZE; -#else - unsigned long frac0 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_W_TYPE_SIZE; - unsigned long frac2 : _FP_W_TYPE_SIZE; - unsigned long frac3 : _FP_FRACBITS_Q - (_FP_IMPLBIT_Q != 0)-(_FP_W_TYPE_SIZE * 3); - unsigned exp : _FP_EXPBITS_Q; - unsigned sign : 1; -#endif /* not bigendian */ - } bits __attribute__((packed)); -}; - - -#define FP_DECL_Q(X) _FP_DECL(4,X) -#define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_4(Q,X,val) -#define FP_UNPACK_RAW_QP(X,val) _FP_UNPACK_RAW_4_P(Q,X,val) -#define FP_PACK_RAW_Q(val,X) _FP_PACK_RAW_4(Q,val,X) -#define FP_PACK_RAW_QP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_4_P(Q,val,X); \ - } while (0) - -#define FP_UNPACK_Q(X,val) \ - do { \ - _FP_UNPACK_RAW_4(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,4,X); \ - } while (0) - -#define FP_UNPACK_QP(X,val) \ - do { \ - _FP_UNPACK_RAW_4_P(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,4,X); \ - } while (0) - -#define FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - _FP_PACK_RAW_4(Q,val,X); \ - } while (0) - -#define FP_PACK_QP(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,4,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_4_P(Q,val,X); \ - } while (0) - -#define FP_ISSIGNAN_Q(X) _FP_ISSIGNAN(Q,4,X) -#define FP_NEG_Q(R,X) _FP_NEG(Q,4,R,X) -#define FP_ADD_Q(R,X,Y) _FP_ADD(Q,4,R,X,Y) -/* single.h and double.h define FP_SUB_t this way too. However, _FP_SUB is - * never defined in op-common.h! Fortunately nobody seems to use the FP_SUB_t - * macros: I suggest a combination of FP_NEG and FP_ADD :-> -- PMM 02/1998 - */ -#define FP_SUB_Q(R,X,Y) _FP_SUB(Q,4,R,X,Y) -#define FP_MUL_Q(R,X,Y) _FP_MUL(Q,4,R,X,Y) -#define FP_DIV_Q(R,X,Y) _FP_DIV(Q,4,R,X,Y) -#define FP_SQRT_Q(R,X) _FP_SQRT(Q,4,R,X) -#define _FP_SQRT_MEAT_Q(R,S,T,X,Q) _FP_SQRT_MEAT_4(R,S,T,X,Q) - -#define FP_CMP_Q(r,X,Y,un) _FP_CMP(Q,4,r,X,Y,un) -#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,4,r,X,Y) - -#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,4,r,X,rsz,rsg) -#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,4,X,r,rs,rt) - -#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_4(X) -#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_4(X) - -#else /* not _FP_W_TYPE_SIZE < 64 */ -union _FP_UNION_Q -{ - long double flt /* __attribute__((mode(TF))) */ ; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_Q; - unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE; - unsigned long frac0 : _FP_W_TYPE_SIZE; -#else - unsigned long frac0 : _FP_W_TYPE_SIZE; - unsigned long frac1 : _FP_FRACBITS_Q-(_FP_IMPLBIT_Q != 0)-_FP_W_TYPE_SIZE; - unsigned exp : _FP_EXPBITS_Q; - unsigned sign : 1; -#endif - } bits; -}; - -#define FP_DECL_Q(X) _FP_DECL(2,X) -#define FP_UNPACK_RAW_Q(X,val) _FP_UNPACK_RAW_2(Q,X,val) -#define FP_UNPACK_RAW_QP(X,val) _FP_UNPACK_RAW_2_P(Q,X,val) -#define FP_PACK_RAW_Q(val,X) _FP_PACK_RAW_2(Q,val,X) -#define FP_PACK_RAW_QP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(Q,val,X); \ - } while (0) - -#define FP_UNPACK_Q(X,val) \ - do { \ - _FP_UNPACK_RAW_2(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,2,X); \ - } while (0) - -#define FP_UNPACK_QP(X,val) \ - do { \ - _FP_UNPACK_RAW_2_P(Q,X,val); \ - _FP_UNPACK_CANONICAL(Q,2,X); \ - } while (0) - -#define FP_PACK_Q(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,2,X); \ - _FP_PACK_RAW_2(Q,val,X); \ - } while (0) - -#define FP_PACK_QP(val,X) \ - do { \ - _FP_PACK_CANONICAL(Q,2,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_2_P(Q,val,X); \ - } while (0) - -#define FP_ISSIGNAN_Q(X) _FP_ISSIGNAN(Q,2,X) -#define FP_NEG_Q(R,X) _FP_NEG(Q,2,R,X) -#define FP_ADD_Q(R,X,Y) _FP_ADD(Q,2,R,X,Y) -#define FP_SUB_Q(R,X,Y) _FP_SUB(Q,2,R,X,Y) -#define FP_MUL_Q(R,X,Y) _FP_MUL(Q,2,R,X,Y) -#define FP_DIV_Q(R,X,Y) _FP_DIV(Q,2,R,X,Y) -#define FP_SQRT_Q(R,X) _FP_SQRT(Q,2,R,X) -#define _FP_SQRT_MEAT_Q(R,S,T,X,Q) _FP_SQRT_MEAT_2(R,S,T,X,Q) - -#define FP_CMP_Q(r,X,Y,un) _FP_CMP(Q,2,r,X,Y,un) -#define FP_CMP_EQ_Q(r,X,Y) _FP_CMP_EQ(Q,2,r,X,Y) - -#define FP_TO_INT_Q(r,X,rsz,rsg) _FP_TO_INT(Q,2,r,X,rsz,rsg) -#define FP_FROM_INT_Q(X,r,rs,rt) _FP_FROM_INT(Q,2,X,r,rs,rt) - -#define _FP_FRAC_HIGH_Q(X) _FP_FRAC_HIGH_2(X) -#define _FP_FRAC_HIGH_RAW_Q(X) _FP_FRAC_HIGH_2(X) - -#endif /* not _FP_W_TYPE_SIZE < 64 */ diff --git a/arch/sparc64/math-emu/sfp-machine.h b/arch/sparc64/math-emu/sfp-machine.h index 958d57786..edb309873 100644 --- a/arch/sparc64/math-emu/sfp-machine.h +++ b/arch/sparc64/math-emu/sfp-machine.h @@ -29,9 +29,12 @@ #define _FP_WS_TYPE signed long #define _FP_I_TYPE long -#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y) -#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm) -#define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide_3mul(Q,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_S(R,X,Y) \ + _FP_MUL_MEAT_1_imm(_FP_WFRACBITS_S,R,X,Y) +#define _FP_MUL_MEAT_D(R,X,Y) \ + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) \ + _FP_MUL_MEAT_2_wide_3mul(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm) #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y) @@ -53,7 +56,7 @@ * CPU instruction emulation this should prefer Y. * (see SPAMv9 B.2.2 section). */ -#define _FP_CHOOSENAN(fs, wc, R, X, Y) \ +#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ do { \ if ((_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs) \ && !(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \ @@ -71,7 +74,7 @@ /* Obtain the current rounding mode. */ #ifndef FP_ROUNDMODE -#define FP_ROUNDMODE ((current->tss.xfsr[0] >> 30) & 0x3) +#define FP_ROUNDMODE ((current->thread.xfsr[0] >> 30) & 0x3) #endif /* Exception flags. */ @@ -83,6 +86,6 @@ #define FP_HANDLE_EXCEPTIONS return _fex -#define FP_INHIBIT_RESULTS ((current->tss.xfsr[0] >> 23) & _fex) +#define FP_INHIBIT_RESULTS ((current->thread.xfsr[0] >> 23) & _fex) #endif diff --git a/arch/sparc64/math-emu/single.h b/arch/sparc64/math-emu/single.h deleted file mode 100644 index 6504e5283..000000000 --- a/arch/sparc64/math-emu/single.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Software floating-point emulation. - Definitions for IEEE Single Precision. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#if _FP_W_TYPE_SIZE < 32 -#error "Here's a nickel kid. Go buy yourself a real computer." -#endif - -#define _FP_FRACBITS_S 24 -#define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S) -#define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S) -#define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S) -#define _FP_EXPBITS_S 8 -#define _FP_EXPBIAS_S 127 -#define _FP_EXPMAX_S 255 -#define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2)) -#define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1)) -#define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S)) - -/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be - chosen by the target machine. */ - -union _FP_UNION_S -{ - float flt; - struct { -#if __BYTE_ORDER == __BIG_ENDIAN - unsigned sign : 1; - unsigned exp : _FP_EXPBITS_S; - unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); -#else - unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0); - unsigned exp : _FP_EXPBITS_S; - unsigned sign : 1; -#endif - } bits __attribute__((packed)); -}; - -#define FP_DECL_S(X) _FP_DECL(1,X) -#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val) -#define FP_UNPACK_RAW_SP(X,val) _FP_UNPACK_RAW_1_P(S,X,val) -#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X) -#define FP_PACK_RAW_SP(val,X) \ - do { \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(S,val,X); \ - } while (0) - -#define FP_UNPACK_S(X,val) \ - do { \ - _FP_UNPACK_RAW_1(S,X,val); \ - _FP_UNPACK_CANONICAL(S,1,X); \ - } while (0) - -#define FP_UNPACK_SP(X,val) \ - do { \ - _FP_UNPACK_RAW_1_P(S,X,val); \ - _FP_UNPACK_CANONICAL(S,1,X); \ - } while (0) - -#define FP_PACK_S(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - _FP_PACK_RAW_1(S,val,X); \ - } while (0) - -#define FP_PACK_SP(val,X) \ - do { \ - _FP_PACK_CANONICAL(S,1,X); \ - if (!FP_INHIBIT_RESULTS) \ - _FP_PACK_RAW_1_P(S,val,X); \ - } while (0) - -#define FP_ISSIGNAN_S(X) _FP_ISSIGNAN(S,1,X) -#define FP_NEG_S(R,X) _FP_NEG(S,1,R,X) -#define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y) -#define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y) -#define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y) -#define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y) -#define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X) -#define _FP_SQRT_MEAT_S(R,S,T,X,Q) _FP_SQRT_MEAT_1(R,S,T,X,Q) - -#define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un) -#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y) - -#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg) -#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt) - -#define _FP_FRAC_HIGH_S(X) _FP_FRAC_HIGH_1(X) -#define _FP_FRAC_HIGH_RAW_S(X) _FP_FRAC_HIGH_1(X) diff --git a/arch/sparc64/math-emu/soft-fp.h b/arch/sparc64/math-emu/soft-fp.h deleted file mode 100644 index 3c5072e51..000000000 --- a/arch/sparc64/math-emu/soft-fp.h +++ /dev/null @@ -1,176 +0,0 @@ -/* Software floating-point emulation. - Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Richard Henderson (rth@cygnus.com), - Jakub Jelinek (jj@ultra.linux.cz), - David S. Miller (davem@redhat.com) and - Peter Maydell (pmaydell@chiark.greenend.org.uk). - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If - not, write to the Free Software Foundation, Inc., - 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#ifndef SOFT_FP_H -#define SOFT_FP_H - -#include "sfp-machine.h" - -/* Allow sfp-machine to have its own byte order definitions. */ -#ifndef __BYTE_ORDER -#include <endian.h> -#endif - -#define _FP_WORKBITS 3 -#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3) -#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2) -#define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1) -#define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0) - -#ifndef FP_RND_NEAREST -# define FP_RND_NEAREST 0 -# define FP_RND_ZERO 1 -# define FP_RND_PINF 2 -# define FP_RND_MINF 3 -#ifndef FP_ROUNDMODE -# define FP_ROUNDMODE FP_RND_NEAREST -#endif -#endif - -/* By default don't care about exceptions. */ -#ifndef FP_EX_INVALID -#define FP_EX_INVALID 0 -#endif -#ifndef FP_EX_OVERFLOW -#define FP_EX_OVERFLOW 0 -#endif -#ifndef FP_EX_UNDERFLOW -#define FP_EX_UNDERFLOW -#endif -#ifndef FP_EX_DIVZERO -#define FP_EX_DIVZERO 0 -#endif -#ifndef FP_EX_INEXACT -#define FP_EX_INEXACT 0 -#endif -#ifndef FP_EX_DENORM -#define FP_EX_DENORM 0 -#endif - -#ifdef _FP_DECL_EX -#define FP_DECL_EX \ - int _fex = 0; \ - _FP_DECL_EX -#else -#define FP_DECL_EX int _fex = 0 -#endif - -#ifndef FP_INIT_ROUNDMODE -#define FP_INIT_ROUNDMODE do {} while (0) -#endif - -#ifndef FP_HANDLE_EXCEPTIONS -#define FP_HANDLE_EXCEPTIONS do {} while (0) -#endif - -#ifndef FP_INHIBIT_RESULTS -/* By default we write the results always. - * sfp-machine may override this and e.g. - * check if some exceptions are unmasked - * and inhibit it in such a case. - */ -#define FP_INHIBIT_RESULTS 0 -#endif - -#define FP_SET_EXCEPTION(ex) \ - _fex |= (ex) - -#define FP_UNSET_EXCEPTION(ex) \ - _fex &= ~(ex) - -#define FP_CLEAR_EXCEPTIONS \ - _fex = 0 - -#define _FP_ROUND_NEAREST(wc, X) \ -do { \ - if ((_FP_FRAC_LOW_##wc(X) & 15) != _FP_WORK_ROUND) \ - _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \ -} while (0) - -#define _FP_ROUND_ZERO(wc, X) 0 - -#define _FP_ROUND_PINF(wc, X) \ -do { \ - if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ - _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ -} while (0) - -#define _FP_ROUND_MINF(wc, X) \ -do { \ - if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \ - _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \ -} while (0) - -#define _FP_ROUND(wc, X) \ -do { \ - if (_FP_FRAC_LOW_##wc(X) & 7) \ - FP_SET_EXCEPTION(FP_EX_INEXACT); \ - switch (FP_ROUNDMODE) \ - { \ - case FP_RND_NEAREST: \ - _FP_ROUND_NEAREST(wc,X); \ - break; \ - case FP_RND_ZERO: \ - _FP_ROUND_ZERO(wc,X); \ - break; \ - case FP_RND_PINF: \ - _FP_ROUND_PINF(wc,X); \ - break; \ - case FP_RND_MINF: \ - _FP_ROUND_MINF(wc,X); \ - break; \ - } \ -} while (0) - -#define FP_CLS_NORMAL 0 -#define FP_CLS_ZERO 1 -#define FP_CLS_INF 2 -#define FP_CLS_NAN 3 - -#define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y)) - -#include "op-1.h" -#include "op-2.h" -#include "op-4.h" -#include "op-8.h" -#include "op-common.h" - -/* Sigh. Silly things longlong.h needs. */ -#define UWtype _FP_W_TYPE -#define W_TYPE_SIZE _FP_W_TYPE_SIZE - -typedef int SItype __attribute__((mode(SI))); -typedef int DItype __attribute__((mode(DI))); -typedef unsigned int USItype __attribute__((mode(SI))); -typedef unsigned int UDItype __attribute__((mode(DI))); -#if _FP_W_TYPE_SIZE == 32 -typedef unsigned int UHWtype __attribute__((mode(HI))); -#elif _FP_W_TYPE_SIZE == 64 -typedef USItype UHWtype; -#endif - -#ifndef umul_ppmm -#include <stdlib/longlong.h> -#endif - -#endif diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c index e9607cb8f..30272e9b5 100644 --- a/arch/sparc64/mm/asyncd.c +++ b/arch/sparc64/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.8 1999/07/04 04:35:55 davem Exp $ +/* $Id: asyncd.c,v 1.9 1999/07/30 09:35:43 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -91,7 +91,8 @@ static void add_to_async_queue(int taskid, void async_fault(unsigned long address, int write, int taskid, void (*callback)(int,unsigned long,int,int)) { - struct task_struct *tsk = task[taskid]; +#warning Need some fixing here... -DaveM + struct task_struct *tsk = current /* XXX task[taskid] */; struct mm_struct *mm = tsk->mm; stats.faults++; @@ -111,7 +112,8 @@ static int fault_in_page(int taskid, { static unsigned last_address; static int last_task, loop_counter; - struct task_struct *tsk = task[taskid]; +#warning Need some fixing here... -DaveM + struct task_struct *tsk = current /* XXX task[taskid] */; pgd_t *pgd; pmd_t *pmd; pte_t *pte; @@ -178,8 +180,8 @@ no_memory: bad_area: stats.failure++; - tsk->tss.sig_address = address; - tsk->tss.sig_desc = SUBSIG_NOMAPPING; + tsk->thread.sig_address = address; + tsk->thread.sig_desc = SUBSIG_NOMAPPING; send_sig(SIGSEGV, tsk, 1); return 1; } diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 04aa8284e..1a20b399b 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.36 1999/07/04 04:35:56 davem Exp $ +/* $Id: fault.c,v 1.39 1999/08/30 10:07:09 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) @@ -84,10 +84,11 @@ void unhandled_fault(unsigned long address, struct task_struct *tsk, printk(KERN_ALERT "Unable to handle kernel paging request " "at virtual address %016lx\n", (unsigned long)address); } - printk(KERN_ALERT "tsk->mm->context = %016lx\n", - (unsigned long) tsk->mm->context); - printk(KERN_ALERT "tsk->mm->pgd = %016lx\n", - (unsigned long) tsk->mm->pgd); + printk(KERN_ALERT "tsk->{mm,active_mm}->context = %016lx\n", + (tsk->mm ? tsk->mm->context : tsk->active_mm->context)); + printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %016lx\n", + (tsk->mm ? (unsigned long) tsk->mm->pgd : + (unsigned long) tsk->active_mm->pgd)); die_if_kernel("Oops", regs); } @@ -154,16 +155,45 @@ asmlinkage void do_sparc64_fault(struct pt_regs *regs, unsigned long address, in * If we're in an interrupt or have no user * context, we must not take the fault.. */ - if (in_interrupt() || mm == &init_mm) + if (in_interrupt() || !mm) goto do_kernel_fault; down(&mm->mmap_sem); #ifdef DEBUG_LOCKUPS - if (regs->tpc == lastpc && address == lastaddr && write == lastwrite) { + if (regs->tpc == lastpc && + address == lastaddr && + write == lastwrite) { lockcnt++; if (lockcnt == 100000) { - printk("do_sparc64_fault: possible fault loop for %016lx %s\n", address, write ? "write" : "read"); + unsigned char tmp; + register unsigned long tmp1 asm("o5"); + register unsigned long tmp2 asm("o4"); + + printk("do_sparc64_fault[%s:%d]: possible fault loop for %016lx %s\n", + current->comm, current->pid, + address, write ? "write" : "read"); + printk("do_sparc64_fault: CHECK[papgd[%016lx],pcac[%016lx]]\n", + __pa(mm->pgd), pgd_val(mm->pgd[0])<<11UL); + __asm__ __volatile__( + "wrpr %%g0, 0x494, %%pstate\n\t" + "mov %3, %%g4\n\t" + "mov %%g7, %0\n\t" + "ldxa [%%g4] %2, %1\n\t" + "wrpr %%g0, 0x096, %%pstate" + : "=r" (tmp1), "=r" (tmp2) + : "i" (ASI_DMMU), "i" (TSB_REG)); + printk("do_sparc64_fault: IS[papgd[%016lx],pcac[%016lx]]\n", + tmp1, tmp2); + printk("do_sparc64_fault: CHECK[ctx(%016lx)] IS[ctx(%016lx)]\n", + mm->context, spitfire_get_secondary_context()); + __asm__ __volatile__("rd %%asi, %0" + : "=r" (tmp)); + printk("do_sparc64_fault: CHECK[seg(%02x)] IS[seg(%02x)]\n", + current->thread.current_ds.seg, tmp); show_regs(regs); + __sti(); + while(1) + barrier(); } } else { lastpc = regs->tpc; @@ -282,8 +312,18 @@ do_kernel_fault: return; } } else { - current->tss.sig_address = address; - current->tss.sig_desc = SUBSIG_NOMAPPING; +#if 0 + extern void __show_regs(struct pt_regs *); + printk("SHIT(%s:%d:cpu(%d)): PC[%016lx] ADDR[%016lx]\n", + current->comm, current->pid, smp_processor_id(), + regs->tpc, address); + __show_regs(regs); + __sti(); + while(1) + barrier(); +#endif + current->thread.sig_address = address; + current->thread.sig_desc = SUBSIG_NOMAPPING; force_sig(SIGSEGV, current); return; } @@ -293,8 +333,8 @@ do_kernel_fault: do_sigbus: up(&mm->mmap_sem); - current->tss.sig_address = address; - current->tss.sig_desc = SUBSIG_MISCERROR; + current->thread.sig_address = address; + current->thread.sig_desc = SUBSIG_MISCERROR; force_sig(SIGBUS, current); if (regs->tstate & TSTATE_PRIV) goto do_kernel_fault; diff --git a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c index ccb0951cc..cf94f4250 100644 --- a/arch/sparc64/mm/generic.c +++ b/arch/sparc64/mm/generic.c @@ -1,4 +1,4 @@ -/* $Id: generic.c,v 1.8 1999/03/12 06:51:50 davem Exp $ +/* $Id: generic.c,v 1.9 1999/07/23 22:32:01 davem Exp $ * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * @@ -95,7 +95,8 @@ static inline void io_remap_pte_range(pte_t * pte, unsigned long address, unsign space); curend = address + 0x10000; offset += 0x10000; - } + } else + offset += PAGE_SIZE; } else offset += PAGE_SIZE; diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 8f176e885..c1d8d24ae 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.128 1999/05/25 16:53:24 jj Exp $ +/* $Id: init.c,v 1.135 1999/09/06 22:55:10 ecd Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996-1999 David S. Miller (davem@caip.rutgers.edu) @@ -42,7 +42,10 @@ unsigned long *sparc64_valid_addr_bitmap; unsigned long phys_base; /* get_new_mmu_context() uses "cache + 1". */ +spinlock_t ctx_alloc_lock = SPIN_LOCK_UNLOCKED; unsigned long tlb_context_cache = CTX_FIRST_VERSION - 1; +#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) +unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; /* References to section boundaries */ extern char __init_begin, __init_end, etext, __bss_start; @@ -163,7 +166,7 @@ static int dvma_pages_current_index; static unsigned long dvmaiobase = 0; static unsigned long dvmaiosz __initdata = 0; -__initfunc(void dvmaio_init(void)) +void __init dvmaio_init(void) { long i; @@ -184,7 +187,7 @@ __initfunc(void dvmaio_init(void)) } } -__initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus)) +void __init iommu_init(int iommu_node, struct linux_sbus *sbus) { extern int this_is_starfire; extern void *starfire_hookup(int); @@ -386,7 +389,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, dvma_pages_current_offset; /* Map the CPU's view. */ - pgdp = pgd_offset(init_task.mm, addr); + pgdp = pgd_offset(&init_mm, addr); pmdp = pmd_alloc_kernel(pgdp, addr); ptep = pte_alloc_kernel(pmdp, addr); pte = mk_pte(the_page, PAGE_KERNEL); @@ -583,7 +586,8 @@ void mmu_set_sbus64(struct linux_sbus_device *sdev, int bursts) struct linux_sbus *sbus = sdev->my_bus; struct sysio_regs *sregs = sbus->iommu->sysio_regs; int slot = sdev->slot; - u64 *cfg, tmp; + volatile u64 *cfg; + u64 tmp; switch(slot) { case 0: @@ -677,7 +681,7 @@ static inline void inherit_prom_mappings(void) for (vaddr = trans[i].virt; vaddr < trans[i].virt + trans[i].size; vaddr += PAGE_SIZE) { - pgdp = pgd_offset(init_task.mm, vaddr); + pgdp = pgd_offset(&init_mm, vaddr); if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PMD_TABLE_SIZE); @@ -739,7 +743,7 @@ void prom_world(int enter) int i; if (!enter) - set_fs(current->tss.current_ds); + set_fs(current->thread.current_ds); if (!prom_ditlb_set) return; @@ -957,9 +961,6 @@ void __flush_tlb_all(void) : : "r" (pstate)); } -#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) -unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; - /* Caller does TLB context flushing on local CPU if necessary. * * We must be careful about boundary cases so that we never @@ -969,14 +970,16 @@ unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; */ void get_new_mmu_context(struct mm_struct *mm) { - unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK); - unsigned long new_ctx; + unsigned long ctx, new_ctx; + spin_lock(&ctx_alloc_lock); + ctx = CTX_HWBITS(tlb_context_cache + 1); if (ctx == 0) ctx = 1; - if ((mm->context != NO_CONTEXT) && - !((mm->context ^ tlb_context_cache) & CTX_VERSION_MASK)) - clear_bit(mm->context & ~(CTX_VERSION_MASK), mmu_context_bmap); + if (CTX_VALID(mm->context)) { + unsigned long nr = CTX_HWBITS(mm->context); + mmu_context_bmap[nr>>6] &= ~(1UL << (nr & 63)); + } new_ctx = find_next_zero_bit(mmu_context_bmap, 1UL << CTX_VERSION_SHIFT, ctx); if (new_ctx >= (1UL << CTX_VERSION_SHIFT)) { new_ctx = find_next_zero_bit(mmu_context_bmap, ctx, 1); @@ -1003,12 +1006,13 @@ void get_new_mmu_context(struct mm_struct *mm) goto out; } } - set_bit(new_ctx, mmu_context_bmap); + mmu_context_bmap[new_ctx>>6] |= (1UL << (new_ctx & 63)); new_ctx |= (tlb_context_cache & CTX_VERSION_MASK); out: tlb_context_cache = new_ctx; + spin_unlock(&ctx_alloc_lock); + mm->context = new_ctx; - mm->cpu_vm_mask = 0; } #ifndef __SMP__ @@ -1041,15 +1045,15 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) return NULL; } -__initfunc(static void -allocate_ptable_skeleton(unsigned long start, unsigned long end)) +static void __init +allocate_ptable_skeleton(unsigned long start, unsigned long end) { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; while (start < end) { - pgdp = pgd_offset(init_task.mm, start); + pgdp = pgd_offset(&init_mm, start); if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PAGE_SIZE); memset(pmdp, 0, PAGE_SIZE); @@ -1073,7 +1077,7 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end)) void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr, int bus, int rdonly) { - pgd_t *pgdp = pgd_offset(init_task.mm, virt_addr); + pgd_t *pgdp = pgd_offset(&init_mm, virt_addr); pmd_t *pmdp = pmd_offset(pgdp, virt_addr); pte_t *ptep = pte_offset(pmdp, virt_addr); pte_t pte; @@ -1095,7 +1099,7 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr) pmd_t *pmdp; pte_t *ptep; - pgdp = pgd_offset(init_task.mm, virt_addr); + pgdp = pgd_offset(&init_mm, virt_addr); pmdp = pmd_offset(pgdp, virt_addr); ptep = pte_offset(pmdp, virt_addr); @@ -1139,8 +1143,8 @@ void sparc_ultra_dump_dtlb(void) extern unsigned long free_area_init(unsigned long, unsigned long); extern unsigned long sun_serial_setup(unsigned long); -__initfunc(unsigned long -paging_init(unsigned long start_mem, unsigned long end_mem)) +unsigned long __init +paging_init(unsigned long start_mem, unsigned long end_mem) { extern pmd_t swapper_pmd_dir[1024]; extern unsigned int sparc64_vpte_patchme1[1]; @@ -1259,7 +1263,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) return device_scan (PAGE_ALIGN (start_mem)); } -__initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) +static void __init taint_real_pages(unsigned long start_mem, unsigned long end_mem) { unsigned long tmp = 0, paddr, endaddr; unsigned long end = __pa(end_mem); @@ -1305,7 +1309,7 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e } } -__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) +void __init mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; int datapages = 0; @@ -1319,6 +1323,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) max_mapnr = MAP_NR(end_mem); high_memory = (void *) end_mem; + start_mem = ((start_mem + 7UL) & ~7UL); sparc64_valid_addr_bitmap = (unsigned long *)start_mem; i = max_mapnr >> ((22 - PAGE_SHIFT) + 6); i += 1; @@ -1472,4 +1477,6 @@ void si_meminfo(struct sysinfo *val) } val->totalram <<= PAGE_SHIFT; val->sharedram <<= PAGE_SHIFT; + val->totalbig = 0; + val->freebig = 0; } diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 3d3d1a289..71e05dc7e 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,9 +1,11 @@ -/* $Id: ultra.S,v 1.32 1999/03/28 08:39:34 davem Exp $ +/* $Id: ultra.S,v 1.34 1999/09/10 10:40:51 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ +#include <linux/config.h> + #include <asm/asi.h> #include <asm/pgtable.h> #include <asm/spitfire.h> @@ -136,36 +138,37 @@ __flush_tlb_range_pbp_slow: flush_icache_page: /* %o0 = phys_page */ sethi %hi(1 << 13), %o2 ! IC_set bit mov 1, %g1 - srlx %o0, 5, %o0 ! phys-addr comparitor + srlx %o0, 5, %o0 clr %o1 ! IC_addr sllx %g1, 36, %g1 sub %g1, 1, %g2 - andn %g2, 0xff, %g2 ! IC_tag mask - nop + or %o0, %g1, %o0 ! VALID+phys-addr comparitor + sllx %g2, 1, %g2 + andn %g2, 0xfe, %g2 ! IC_tag mask 1: ldda [%o1] ASI_IC_TAG, %o4 and %o5, %g2, %o5 cmp %o5, %o0 be,pn %xcc, iflush1 - nop + add %o1, 0x20, %g3 2: ldda [%o1 + %o2] ASI_IC_TAG, %o4 and %o5, %g2, %o5 - cmp %o5, %o0 + cmp %o5, %o0 be,pn %xcc, iflush2 nop -3: add %o1, 0x20, %o1 - cmp %o1, %o2 +3: cmp %g3, %o2 bne,pt %xcc, 1b - nop + mov %g3, %o1 retl nop + iflush1:stxa %g0, [%o1] ASI_IC_TAG - ba,pt %xcc, 2b - flush %g6 + flush %g6 + ba,a,pt %xcc, 2b iflush2:stxa %g0, [%o1 + %o2] ASI_IC_TAG - ba,pt %xcc, 3b - flush %g6 + flush %g6 + ba,a,pt %xcc, 3b #ifdef __SMP__ /* These are all called by the slaves of a cross call, at diff --git a/arch/sparc64/prom/bootstr.c b/arch/sparc64/prom/bootstr.c index 6d53b8be2..064ba2472 100644 --- a/arch/sparc64/prom/bootstr.c +++ b/arch/sparc64/prom/bootstr.c @@ -1,4 +1,4 @@ -/* $Id: bootstr.c,v 1.5 1998/01/23 08:51:39 jj Exp $ +/* $Id: bootstr.c,v 1.6 1999/08/31 06:55:01 davem Exp $ * bootstr.c: Boot string/argument acquisition from the PROM. * * Copyright(C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -14,8 +14,8 @@ int bootstr_len = BARG_LEN; static int bootstr_valid = 0; static char bootstr_buf[BARG_LEN] = { 0 }; -__initfunc(char * -prom_getbootargs(void)) +char * __init +prom_getbootargs(void) { /* This check saves us from a panic when bootfd patches args. */ if (bootstr_valid) return bootstr_buf; diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c index 4c1bd1e00..17166a72c 100644 --- a/arch/sparc64/prom/init.c +++ b/arch/sparc64/prom/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.8 1998/03/15 10:14:44 ecd Exp $ +/* $Id: init.c,v 1.9 1999/08/31 06:55:03 davem Exp $ * init.c: Initialize internal variables used by the PROM * library functions. * @@ -31,7 +31,7 @@ extern void prom_meminit(void); extern void prom_ranges_init(void); extern void prom_cif_init(void *, void *); -__initfunc(void prom_init(void *cif_handler, void *cif_stack)) +void __init prom_init(void *cif_handler, void *cif_stack) { char buffer[80], *p; int ints[3]; diff --git a/arch/sparc64/prom/memory.c b/arch/sparc64/prom/memory.c index 3523c3b1d..92f4ff4fc 100644 --- a/arch/sparc64/prom/memory.c +++ b/arch/sparc64/prom/memory.c @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.4 1998/11/25 10:04:06 jj Exp $ +/* $Id: memory.c,v 1.5 1999/08/31 06:55:04 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * @@ -37,8 +37,8 @@ struct linux_mem_p1275 prom_memlist; /* Internal Prom library routine to sort a linux_mlist_p1275 memory * list. Used below in initialization. */ -__initfunc(static void -prom_sortmemlist(struct linux_mlist_p1275 *thislist)) +static void __init +prom_sortmemlist(struct linux_mlist_p1275 *thislist) { int swapi = 0; int i, mitr; @@ -65,7 +65,7 @@ prom_sortmemlist(struct linux_mlist_p1275 *thislist)) } /* Initialize the memory lists based upon the prom version. */ -__initfunc(void prom_meminit(void)) +void __init prom_meminit(void) { int node = 0; unsigned int iter, num_regs; diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 83af773df..2a45a4bb5 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.14 1998/12/18 10:01:59 davem Exp $ +/* $Id: misc.c,v 1.15 1999/08/31 19:25:41 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -125,15 +125,37 @@ void prom_set_trap_table(unsigned long tba) /* This is only used internally below. */ static int prom_get_mmu_ihandle(void) { - int node; - int ret; + static int mmu_ihandle_cache = 0; + int node, ret; + + if (mmu_ihandle_cache != 0) + return mmu_ihandle_cache; node = prom_finddevice("/chosen"); ret = prom_getint(node, "mmu"); - if(ret == -1 || ret == 0) { - prom_printf("PROMLIB: Fatal error, cannot get mmu ihandle.\n"); - prom_halt(); - } + if(ret == -1 || ret == 0) + mmu_ihandle_cache = -1; + else + mmu_ihandle_cache = ret; + + return ret; +} + +static int prom_get_memory_ihandle(void) +{ + static int memory_ihandle_cache = 0; + int node, ret; + + if (memory_ihandle_cache != 0) + return memory_ihandle_cache; + + node = prom_finddevice("/chosen"); + ret = prom_getint(node, "memory"); + if (ret == -1 || ret == 0) + memory_ihandle_cache = -1; + else + memory_ihandle_cache = ret; + return ret; } @@ -197,12 +219,18 @@ unsigned long prom_retain(char *name, * etched into the motherboard next to the SIMM slot * in question. */ -int prom_getunumber(unsigned long phys_lo, unsigned long phys_hi, +int prom_getunumber(int syndrome_code, + unsigned long phys_addr, char *buf, int buflen) { - return p1275_cmd("SUNW,get-unumber", - (P1275_ARG(2, P1275_ARG_OUT_BUF) | P1275_INOUT(4, 1)), - phys_lo, phys_hi, buf, buflen); + return p1275_cmd("call-method", + (P1275_ARG(0, P1275_ARG_IN_STRING) | + P1275_ARG(3, P1275_ARG_OUT_BUF) | + P1275_ARG(5, P1275_ARG_IN_64B) | + P1275_INOUT(8, 2)), + "SUNW,get-unumber", prom_get_memory_ihandle(), + buflen, buf, P1275_SIZE(buflen), + 0, phys_addr, syndrome_code); } /* Power management extensions. */ diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index 9b1fafa37..f30bdd3a8 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.15 1998/10/13 14:03:47 davem Exp $ +/* $Id: p1275.c,v 1.18 1999/09/10 10:40:53 davem Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -9,13 +9,13 @@ #include <linux/sched.h> #include <linux/smp.h> #include <linux/string.h> +#include <linux/spinlock.h> #include <asm/openprom.h> #include <asm/oplib.h> #include <asm/system.h> #include <asm/spitfire.h> #include <asm/pstate.h> -#include <asm/spinlock.h> struct { long prom_callback; /* 0x00 */ @@ -252,8 +252,8 @@ void prom_cif_callback(void) * the counter is needed. -DaveM */ static int prom_entry_depth = 0; -#ifdef __SMP__ static spinlock_t prom_entry_lock = SPIN_LOCK_UNLOCKED; +#ifdef __SMP__ extern void smp_capture(void); extern void smp_release(void); #endif @@ -321,6 +321,10 @@ long p1275_cmd (char *service, long fmt, ...) p1275buf.prom_args[i + 3] = (unsigned)va_arg(list, long); break; + case P1275_ARG_IN_64B: + p1275buf.prom_args[i + 3] = + va_arg(list, unsigned long); + break; case P1275_ARG_IN_STRING: strcpy (p, va_arg(list, char *)); p1275buf.prom_args[i + 3] = (unsigned long)p; diff --git a/arch/sparc64/prom/ranges.c b/arch/sparc64/prom/ranges.c index 7b889bac1..048e3412a 100644 --- a/arch/sparc64/prom/ranges.c +++ b/arch/sparc64/prom/ranges.c @@ -1,4 +1,4 @@ -/* $Id: ranges.c,v 1.10 1998/03/24 05:54:29 ecd Exp $ +/* $Id: ranges.c,v 1.12 1999/08/31 06:55:05 davem Exp $ * ranges.c: Handle ranges in newer proms for obio/sbus. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -87,11 +87,11 @@ void prom_apply_central_ranges(struct linux_central *central, central->num_central_ranges); } -__initfunc(void prom_ranges_init(void)) +void __init prom_ranges_init(void) { } -__initfunc(void prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus)) +void __init prom_sbus_ranges_init(int iommund, struct linux_sbus *sbus) { int success; @@ -103,7 +103,7 @@ __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)) +void __init prom_central_ranges_init(int cnode, struct linux_central *central) { int success; @@ -115,7 +115,7 @@ __initfunc(void prom_central_ranges_init(int cnode, struct linux_central *centra central->num_central_ranges = (success/sizeof(struct linux_prom_ranges)); } -__initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc)) +void __init prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc) { int success; @@ -128,7 +128,7 @@ __initfunc(void prom_fhc_ranges_init(int fnode, struct linux_fhc *fhc)) } #ifdef CONFIG_PCI -__initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus)) +void __init prom_ebus_ranges_init(struct linux_ebus *ebus) { int success; @@ -140,7 +140,7 @@ __initfunc(void prom_ebus_ranges_init(struct linux_ebus *ebus)) ebus->num_ebus_ranges = (success/sizeof(struct linux_prom_ebus_ranges)); } -__initfunc(void prom_ebus_intmap_init(struct linux_ebus *ebus)) +void __init prom_ebus_intmap_init(struct linux_ebus *ebus) { int success; @@ -161,40 +161,6 @@ __initfunc(void prom_ebus_intmap_init(struct linux_ebus *ebus)) prom_halt(); } } - -__initfunc(void prom_pbm_ranges_init(int pnode, struct linux_pbm_info *pbm)) -{ - int success; - - pbm->num_pbm_ranges = 0; - success = prom_getproperty(pnode, "ranges", - (char *)&pbm->pbm_ranges, - sizeof(pbm->pbm_ranges)); - if(success != -1) - pbm->num_pbm_ranges = (success/sizeof(struct linux_prom_pci_ranges)); -} - -__initfunc(void prom_pbm_intmap_init(int pnode, struct linux_pbm_info *pbm)) -{ - int success; - - pbm->num_pbm_intmap = 0; - success = prom_getproperty(pnode, "interrupt-map", - (char *)pbm->pbm_intmap, - sizeof(pbm->pbm_intmap)); - if (success == -1) - return; - - pbm->num_pbm_intmap = (success/sizeof(struct linux_prom_pci_intmap)); - - success = prom_getproperty(pnode, "interrupt-map-mask", - (char *)&pbm->pbm_intmask, - sizeof(pbm->pbm_intmask)); - if (success == -1) { - prom_printf("%s: can't get interrupt-map-mask\n", __FUNCTION__); - prom_halt(); - } -} #endif void diff --git a/arch/sparc64/solaris/ioctl.c b/arch/sparc64/solaris/ioctl.c index 82a583c29..ac3071b50 100644 --- a/arch/sparc64/solaris/ioctl.c +++ b/arch/sparc64/solaris/ioctl.c @@ -1,4 +1,4 @@ -/* $Id: ioctl.c,v 1.11 1999/05/27 00:36:25 davem Exp $ +/* $Id: ioctl.c,v 1.13 1999/08/20 00:27:15 davem Exp $ * ioctl.c: Solaris ioctl emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -367,7 +367,6 @@ static inline int solaris_sockmod(unsigned int fd, unsigned int cmd, u32 arg) static inline int solaris_timod(unsigned int fd, unsigned int cmd, u32 arg, int len, int *len_p) { - struct inode *ino; int ret; switch (cmd & 0xff) { @@ -459,7 +458,6 @@ static inline int solaris_S(struct file *filp, unsigned int fd, unsigned int cmd mm_segment_t old_fs; struct strioctl si; struct inode *ino; - struct file *filp; struct sol_socket_struct *sock; struct module_info *mi; @@ -665,7 +663,7 @@ static inline int solaris_i(unsigned int fd, unsigned int cmd, u32 arg) #endif case 87: /* SIOCGIFNUM */ { - struct device *d; + struct net_device *d; int i = 0; read_lock_bh(&dev_base_lock); diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 4b3a1ce5d..c3176ac2c 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.13 1998/10/28 08:11:58 jj Exp $ +/* $Id: misc.c,v 1.14 1999/06/25 11:00:53 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) diff --git a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c index f6d31920e..5eef5c208 100644 --- a/arch/sparc64/solaris/socksys.c +++ b/arch/sparc64/solaris/socksys.c @@ -1,4 +1,4 @@ -/* $Id: socksys.c,v 1.8 1998/08/26 10:28:28 davem Exp $ +/* $Id: socksys.c,v 1.10 1999/08/31 06:55:08 davem Exp $ * socksys.c: /dev/inet/ stuff for Solaris emulation. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -174,8 +174,8 @@ static struct file_operations socksys_fops = { socksys_release,/* release */ }; -__initfunc(int -init_socksys(void)) +int __init +init_socksys(void) { int ret; struct file * file; diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index cba34c36d..5ee6df467 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -1,4 +1,4 @@ -/* $Id: timod.c,v 1.2 1999/05/12 11:11:55 davem Exp $ +/* $Id: timod.c,v 1.4 1999/09/01 08:07:47 davem Exp $ * timod.c: timod emulation. * * Copyright (C) 1998 Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz) @@ -33,9 +33,7 @@ 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); -#ifdef __SMP__ spinlock_t timod_pagelock = SPIN_LOCK_UNLOCKED; -#endif static char * page = NULL ; #ifndef DEBUG_SOLARIS_KMALLOC @@ -679,7 +677,7 @@ int timod_getmsg(unsigned int fd, char *ctl_buf, int ctl_maxlen, s32 *ctl_len, wait = &wait_table; for(;;) { SOLD("loop"); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); /* ! ( l<0 || ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ /* ( ! l<0 && ! ( l>=0 && ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ /* ( l>=0 && ( ! l>=0 || ! ( ! pfirst || (flags == HIPRI && pri != HIPRI) ) ) ) */ diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index ec1ca0461..e6f6cf82a 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -39,8 +39,17 @@ SECTIONS __init_begin = .; .text.init : { *(.text.init) } .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup_init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; . = ALIGN(8192); __init_end = .; + . = ALIGN(64); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } __bss_start = .; .sbss : { *(.sbss) *(.scommon) } .bss : |