diff options
Diffstat (limited to 'arch/sparc64')
63 files changed, 3481 insertions, 2551 deletions
diff --git a/arch/sparc64/Makefile b/arch/sparc64/Makefile index e004359c3..d8cc0f76e 100644 --- a/arch/sparc64/Makefile +++ b/arch/sparc64/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.25 1998/04/06 16:10:31 jj Exp $ +# $Id: Makefile,v 1.27 1998/07/27 07:36:16 davem Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -19,13 +19,20 @@ AR = sparc64-linux-ar RANLIB = sparc64-linux-ranlib ELFTOAOUT = elftoaout +IS_EGCS := $(shell if $(CC) --version 2>&1 | grep 'egcs' > /dev/null; then echo y; else echo n; fi) + # # Uncomment the first CFLAGS if you are doing kgdb source level # debugging of the kernel to get the proper debugging information. #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7 -CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \ - -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare +ifneq ($(IS_EGCS),y) + CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mmedlow \ + -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare +else + CFLAGS := $(CFLAGS) -pipe -mno-fpu -mtune=ultrasparc -mcmodel=medlow \ + -ffixed-g4 -fcall-used-g5 -fcall-used-g7 -Wno-sign-compare +endif LINKFLAGS = -T arch/sparc64/vmlinux.lds @@ -57,6 +64,8 @@ vmlinux.aout: vmlinux archclean: rm -f $(TOPDIR)/vmlinux.aout +archmrproper: + archdep: check_asm: diff --git a/arch/sparc64/config.in b/arch/sparc64/config.in index 8cd86f9db..2caead01d 100644 --- a/arch/sparc64/config.in +++ b/arch/sparc64/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.44 1998/04/06 16:10:35 jj Exp $ +# $Id: config.in,v 1.55 1998/08/03 15:28:38 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -26,6 +26,13 @@ define_bool CONFIG_VT_CONSOLE y bool 'Support for AP1000 multicomputer' CONFIG_AP1000 +mainmenu_option next_comment +comment 'Console drivers' +bool 'PROM console' CONFIG_PROM_CONSOLE +bool 'Support Frame buffer devices' CONFIG_FB +source drivers/video/Config.in +endmenu + if [ "$CONFIG_AP1000" = "y" ]; then define_bool CONFIG_NO_KEYBOARD y define_bool CONFIG_APFDDI y @@ -45,7 +52,9 @@ else define_bool CONFIG_SUN_AUXIO y define_bool CONFIG_SUN_IO y define_bool CONFIG_PCI y + define_bool CONFIG_PCI_CONSOLE y source drivers/sbus/char/Config.in + source drivers/sbus/audio/Config.in fi tristate 'Openprom tree appears in /proc/openprom (EXPERIMENTAL)' CONFIG_SUN_OPENPROMFS @@ -67,12 +76,14 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then tristate 'Solaris binary emulation' CONFIG_SOLARIS_EMUL fi -endmenu if [ "$CONFIG_PCI" = "y" ]; then tristate 'Parallel port support' CONFIG_PARPORT if [ "$CONFIG_PARPORT" != "n" ]; then dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT + if [ "$CONFIG_PARPORT_AX" = "m" ]; then + define_bool CONFIG_PARPORT_LOWLEVEL_MODULE y + fi if [ "$CONFIG_PARPORT_AX" != "n" ]; then bool ' Support foreign hardware' CONFIG_PARPORT_OTHER fi @@ -83,6 +94,7 @@ if [ "$CONFIG_PCI" = "y" ]; then fi tristate 'SUNW,envctrl support' CONFIG_ENVCTRL fi +endmenu mainmenu_option next_comment comment 'Floppy, IDE, and other block devices' @@ -115,6 +127,7 @@ 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_AUTO y define_bool CONFIG_BLK_DEV_NS87415 y define_bool CONFIG_BLK_DEV_CMD646 y fi @@ -168,11 +181,11 @@ if [ "$CONFIG_SCSI" != "n" ]; then fi dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then - bool ' detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT - bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE - int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 12 + int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 + int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 10 - if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then + bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE + if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -210,6 +223,7 @@ if [ "$CONFIG_NET" = "y" ]; then tristate 'MyriCOM Gigabit Ethernet support' CONFIG_MYRI_SBUS 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 fi # bool 'FDDI driver support' CONFIG_FDDI # if [ "$CONFIG_FDDI" = "y" ]; then @@ -231,10 +245,6 @@ endmenu mainmenu_option next_comment comment 'Kernel hacking' -bool 'Kernel profiling support' CONFIG_PROFILE -if [ "$CONFIG_PROFILE" = "y" ]; then - int ' Profile shift count' CONFIG_PROFILE_SHIFT 2 -fi bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ bool 'ECache flush trap support at ta 0x72' CONFIG_EC_FLUSH_TRAP endmenu diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index 0a76f100f..35f1219fd 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -20,6 +20,30 @@ CONFIG_KMOD=y CONFIG_VT=y CONFIG_VT_CONSOLE=y # CONFIG_AP1000 is not set + +# +# Console drivers +# +CONFIG_PROM_CONSOLE=y +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +CONFIG_FB_SBUS=y +CONFIG_FB_CREATOR=y +CONFIG_FB_CGSIX=y +# CONFIG_FB_BWTWO is not set +# CONFIG_FB_CGTHREE is not set +# CONFIG_FB_LEO is not set +CONFIG_FB_PCI=y +CONFIG_FB_ATY=y +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FBCON_ADVANCED is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +CONFIG_FBCON_CFB24=y +CONFIG_FBCON_CFB32=y +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FONT_SUN8x16=y +# CONFIG_FBCON_FONTS is not set CONFIG_SBUS=y CONFIG_SBUSCHAR=y CONFIG_SUN_MOUSE=y @@ -31,20 +55,7 @@ CONFIG_SUN_CONSOLE=y CONFIG_SUN_AUXIO=y CONFIG_SUN_IO=y CONFIG_PCI=y - -# -# SBUS Frame Buffer support -# -SUN_FBS_IN_PROCFS=y -CONFIG_SUN_FB_DISPLAY=y -SUN_FB_CGSIX=y -SUN_FB_TCX=y -SUN_FB_CGTHREE=y -SUN_FB_CGFOURTEEN=y -SUN_FB_BWTWO=y -SUN_FB_LEO=y -TADPOLE_FB_WEITEK=y -SUN_FB_CREATOR=y +CONFIG_PCI_CONSOLE=y # # Misc Linux/SPARC drivers @@ -55,6 +66,13 @@ CONFIG_SAB82532=y CONFIG_OBP_FLASH=m # CONFIG_SUN_BPP is not set # CONFIG_SUN_VIDEOPIX is not set + +# +# Linux/SPARC audio subsystem (EXPERIMENTAL) +# +# CONFIG_SPARCAUDIO is not set +# CONFIG_SPARCAUDIO_AMD7930 is not set +# CONFIG_SPARCAUDIO_CS4231 is not set CONFIG_SUN_OPENPROMFS=m CONFIG_PCI_OLD_PROC=y CONFIG_NET=y @@ -64,7 +82,7 @@ CONFIG_SYSCTL=y CONFIG_SPARC32_COMPAT=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_ELF32=y -CONFIG_BINFMT_AOUT32=y +# CONFIG_BINFMT_AOUT32 is not set CONFIG_BINFMT_MISC=m CONFIG_BINFMT_JAVA=m CONFIG_SOLARIS_EMUL=m @@ -96,6 +114,7 @@ CONFIG_BLK_DEV_IDEFLOPPY=m # CONFIG_BLK_DEV_IDESCSI is not set CONFIG_BLK_DEV_IDEPCI=y CONFIG_BLK_DEV_IDEDMA=y +CONFIG_IDEDMA_AUTO=y CONFIG_BLK_DEV_NS87415=y CONFIG_BLK_DEV_CMD646=y @@ -103,7 +122,9 @@ CONFIG_BLK_DEV_CMD646=y # Networking options # CONFIG_PACKET=y -# CONFIG_NETLINK is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +# CONFIG_NETLINK_DEV is not set # CONFIG_FIREWALL is not set CONFIG_NET_ALIAS=y # CONFIG_FILTER is not set @@ -112,11 +133,11 @@ CONFIG_INET=y # CONFIG_IP_MULTICAST is not set # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ACCT is not set # CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set CONFIG_IP_ALIAS=y +# CONFIG_ARPD is not set # CONFIG_SYN_COOKIES is not set # @@ -132,29 +153,30 @@ CONFIG_IPV6=m # # CONFIG_IPX=m - -# -# IPX options -# # CONFIG_IPX_INTERN is not set +# CONFIG_SPX is not set CONFIG_ATALK=m # CONFIG_X25 is not set # CONFIG_LAPB is not set # CONFIG_BRIDGE is not set # CONFIG_LLC is not set +# CONFIG_ECONET is not set # 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 CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBQ=y -CONFIG_NET_SCH_CSZ=y -CONFIG_NET_SCH_RED=y -CONFIG_NET_SCH_SFQ=y -CONFIG_NET_SCH_TBF=y -CONFIG_NET_SCH_PFIFO=y -CONFIG_NET_SCH_PRIO=y -# CONFIG_NET_PROFILE is not set +CONFIG_NETLINK=y +CONFIG_RTNETLINK=y +CONFIG_NET_SCH_CBQ=m +CONFIG_NET_SCH_CSZ=m +CONFIG_NET_SCH_PRIO=m +CONFIG_NET_SCH_RED=m +CONFIG_NET_SCH_SFQ=m +CONFIG_NET_SCH_TEQL=m +CONFIG_NET_SCH_TBF=m +# CONFIG_NET_QOS is not set +# CONFIG_NET_CLS is not set # # SCSI support @@ -188,10 +210,10 @@ CONFIG_SCSI_AIC7XXX=y # CONFIG_AIC7XXX_PROC_STATS is not set CONFIG_AIC7XXX_RESET_DELAY=5 CONFIG_SCSI_NCR53C8XX=y -CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT=y -CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE=y -CONFIG_SCSI_NCR53C8XX_MAX_TAGS=12 +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8 +CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32 CONFIG_SCSI_NCR53C8XX_SYNC=10 +# CONFIG_SCSI_NCR53C8XX_PROFILE is not set # CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT is not set # @@ -228,6 +250,7 @@ CONFIG_HAPPYMEAL=y CONFIG_SUNQE=m CONFIG_MYRI_SBUS=m CONFIG_DE4X5=y +CONFIG_VORTEX=m # # Filesystems @@ -269,6 +292,7 @@ CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y CONFIG_SOLARIS_X86_PARTITION=y # CONFIG_ADFS_FS is not set +# CONFIG_DEVPTS_FS is not set # CONFIG_MAC_PARTITION is not set CONFIG_NLS=y @@ -310,6 +334,5 @@ CONFIG_NLS=y # # Kernel hacking # -# CONFIG_PROFILE is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_EC_FLUSH_TRAP is not set diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index 1c3f459bc..ac61935c8 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.36 1998/02/01 11:15:55 ecd Exp $ +# $Id: Makefile,v 1.38 1998/07/26 03:02:47 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,24 +7,12 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -ifdef SMP - .S.s: $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o -else - -.S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s - -.S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o - -endif - all: kernel.o head.o init_task.o O_TARGET := kernel.o @@ -51,8 +39,8 @@ ifdef CONFIG_BINFMT_AOUT32 O_OBJS += binfmt_aout32.o endif -head.o: head.S ttable.S itlb_miss.S dtlb_miss.S dtlb_prot.S etrap.S rtrap.S \ - winfixup.S entry.S +head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \ + etrap.S rtrap.S winfixup.S entry.S $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $*.S -o $*.o # diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index 91365af85..a674399e4 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -42,9 +42,13 @@ __initfunc(void auxio_probe(void)) struct linux_ebus_device *edev = 0; unsigned long led_auxio; - for_all_ebusdev(edev, ebus) - if (!strcmp(edev->prom_name, "auxio")) - break; + for_each_ebus(ebus) { + for_each_ebusdev(edev, ebus) { + if (!strcmp(edev->prom_name, "auxio")) + goto ebus_done; + } + } + ebus_done: if (edev) { if (check_region(edev->base_address[0], diff --git a/arch/sparc64/kernel/central.c b/arch/sparc64/kernel/central.c index a54e89f2d..1d1cb25e1 100644 --- a/arch/sparc64/kernel/central.c +++ b/arch/sparc64/kernel/central.c @@ -1,4 +1,4 @@ -/* $Id: central.c,v 1.5 1998/02/12 15:57:59 jj Exp $ +/* $Id: central.c,v 1.6 1998/05/14 13:35:45 jj Exp $ * central.c: Central FHC driver for Sunfire/Starfire/Wildfire. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -29,13 +29,10 @@ unsigned long central_probe(unsigned long memory_start) char namebuf[128]; int cnode, fnode, err; - printk("CENTRAL: "); cnode = prom_finddevice("/central"); - if(cnode == 0 || cnode == -1) { - printk("no central found.\n"); + if(cnode == 0 || cnode == -1) return memory_start; - } - printk("found central PROM node.\n"); + printk("CENTRAL: found central PROM node %08x.\n", cnode); /* Ok we got one, grab some memory for software state. */ memory_start = long_align(memory_start); diff --git a/arch/sparc64/kernel/devices.c b/arch/sparc64/kernel/devices.c index 8d3aca325..93ea8ca4f 100644 --- a/arch/sparc64/kernel/devices.c +++ b/arch/sparc64/kernel/devices.c @@ -48,19 +48,23 @@ device_scan(unsigned long mem_start)) prom_getproperty(scan, "upa-portid", (char *) &thismid, sizeof(thismid)); linux_cpus[cpu_ctr].mid = thismid; - prom_printf("Found CPU %d <node=%08x,mid=%d>\n", +#ifdef __SMP__ + prom_printf("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); - printk("Found CPU %d <node=%08x,mid=%d>\n", + printk("Found CPU %d (node=%08x,mid=%d)\n", cpu_ctr, (unsigned) scan, thismid); +#endif cpu_ctr++; } }; if(cpu_ctr == 0) { - printk("No CPU nodes found, cannot continue.\n"); + prom_printf("No CPU nodes found, cannot continue.\n"); prom_halt(); } +#ifdef __SMP__ printk("Found %d CPU prom device tree node(s).\n", cpu_ctr); +#endif }; prom_node_cpu = cpu_nds[0]; diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S new file mode 100644 index 000000000..b3d0a1eb7 --- /dev/null +++ b/arch/sparc64/kernel/dtlb_backend.S @@ -0,0 +1,69 @@ +/* $Id: dtlb_backend.S,v 1.4 1998/06/15 16:59:34 jj Exp $ + * dtlb_backend.S: Back end to DTLB miss replacement strategy. + * This is included directly into the trap table. + * + * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define TAG_CONTEXT_BITS 0x3ff +#define VPTE_SHIFT (PAGE_SHIFT - 3) +#define PMD_SHIFT (23 - PAGE_SHIFT + 3) +#define PGD_SHIFT (34 - PAGE_SHIFT + 3) +#define VPTE_BITS (_PAGE_CP | _PAGE_P | _PAGE_W) + +/* Ways we can get here: + * + * 1) Nucleus loads and stores to/from PA-->VA direct mappings at tl>1. + * 2) Nucleus loads and stores to/from user/kernel window save areas. + * 3) VPTE misses from dtlb_base, dtlb_prot, and itlb_base. But this only + * happens for non-nucleus contexts. Nucleus VPTE's cannot work because + * of how OBP uses the same part of the address space in ctx 0. + */ + +/* TLB1 ** ICACHE line 1: tl1 DTLB and quick VPTE miss */ + ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS + add %g3, %g3, %g5 ! Compute VPTE base + cmp %g4, %g5 ! VPTE miss? + blu,pn %xcc, .-0x4004 ! Fall to tl0 miss + andcc %g4, TAG_CONTEXT_BITS, %g5 ! From Nucleus? (for tl0 miss) + sllx %g6, VPTE_SHIFT, %g4 ! Position TAG_ACCESS + or %g4, %g5, %g4 ! Prepare TAG_ACCESS + mov TSB_REG, %g1 ! Grab TSB reg + +/* TLB1 ** ICACHE line 2: Quick VPTE miss */ + ldxa [%g1] ASI_DMMU, %g5 ! Doing PGD caching? + srlx %g6, (PMD_SHIFT - 1), %g1 ! Position PMD offset + be,pn %xcc, sparc64_vpte_nucleus ! Is it from Nucleus? + and %g1, 0xffe, %g1 ! Mask PMD offset bits + brnz,pt %g5, sparc64_vpte_continue ! Yep, go like smoke + nop ! Pipe bubble... + srlx %g6, (PGD_SHIFT - 2), %g5 ! Position PGD offset + and %g5, 0xffc, %g5 ! Mask PGD offset + +/* TLB1 ** ICACHE line 3: Quick VPTE miss */ + lduwa [%g7 + %g5] ASI_PHYS_USE_EC, %g5! Load PGD + brz,pn %g5, 2f ! Valid? +sparc64_vpte_continue: + add %g1, %g1, %g1 ! Position PMD offset once again + lduwa [%g5 + %g1] ASI_PHYS_USE_EC, %g5! Load PMD + brz,pn %g5, 2f ! Valid? + sllx %g2, 62, %g1 ! Put _PAGE_VALID into %g1 + or %g5, VPTE_BITS, %g5 ! Prepare VPTE data + or %g5, %g1, %g5 ! ... + +/* TLB1 ** ICACHE line 4: Quick VPTE miss */ + mov TLB_SFSR, %g1 ! Restore %g1 value + stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load VPTE into TLB + membar #Sync ! Synchronize ASI stores + stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS + retry ! Load PTE once again +2: mov TLB_SFSR, %g1 ! Restore %g1 value + stxa %g4, [%g1 + %g1] ASI_DMMU ! Restore previous TAG_ACCESS + done ! Slick trick + +#undef TAG_CONTEXT_BITS +#undef VPTE_SHIFT +#undef PMD_SHIFT +#undef PGD_SHIFT +#undef VPTE_BITS diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S new file mode 100644 index 000000000..71e5b14d7 --- /dev/null +++ b/arch/sparc64/kernel/dtlb_base.S @@ -0,0 +1,98 @@ +/* $Id: dtlb_base.S,v 1.4 1998/06/15 16:59:30 jj Exp $ + * dtlb_base.S: Front end to DTLB miss replacement strategy. + * This is included directly into the trap table. + * + * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define TAG_CONTEXT_BITS 0x3ff +#define VPTE_SHIFT (PAGE_SHIFT - 3) +#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) +#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) +#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W) +#define KERN_IOBITS (KERN_LOWBITS ^ KERN_LOWBITS_IO) + +/* %g1 TLB_SFSR (%g1 + %g1 == TLB_TAG_ACCESS) + * %g2 (KERN_HIGHBITS | KERN_LOWBITS) + * %g3 VPTE base (0xfffffffe00000000) Spitfire/Blackbird (44-bit VA space) + * (0xffe0000000000000) Cheetah (64-bit VA space) + * %g7 __pa(current->mm->pgd) + * + * The VPTE base value is completely magic, but note that + * nothing else in the kernel other than these TLB miss + * handlers know anything about the VPTE mechanism or + * how it works. Consider the 44-bit VADDR Ultra-I/II + * case as an example: + * + * VA[0 : (1<<43)] produce VPTE index [%g3 : 0] + * VA[0 : -(1<<43)] produce VPTE index [%g3-(1<<(43-PAGE_SHIFT+3)) : %g3] + * + * For Cheetah's 64-bit VADDR space this is: + * + * VA[0 : (1<<63)] produce VPTE index [%g3 : 0] + * VA[0 : -(1<<63)] produce VPTE index [%g3-(1<<(63-PAGE_SHIFT+3)) : %g3] + * + * If you're paying attention you'll notice that this means half of + * the VPTE table is above %g3 and half is below, low VA addresses + * map progressively upwards from %g3, and high VA addresses map + * progressively downwards from %g3. This trick was needed to make + * the same 8 instruction handler work both for Spitfire/Blackbird's + * peculiar VA space hole configuration and the full 64-bit VA space + * one of Cheetah at the same time. + */ + +/* Ways we can get here: + * + * 1) Nucleus loads and stores to/from PA-->VA direct mappings. + * 2) Nucleus loads and stores to/from vmalloc() areas. + * 3) User loads and stores. + * 4) User space accesses by nucleus at tl0 + */ + +/* DTLB ** ICACHE line 1: Quick user TLB misses */ + ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS + andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? + be,pn %xcc, 3f ! Yep, special processing + srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset + ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE +1: brlz,pt %g5, 2f ! Valid, load into TLB + and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits + ba,a,pt %xcc, 4f ! Invalid, branch out + +/* DTLB ** ICACHE line 2: Quick kernel TLB misses */ +3: brgez,a,pn %g4, 1b ! Kernel virtual map? + ldxa [%g3 + %g6] ASI_N, %g5 ! Yep, load k-vpte + srlx %g4, 40, %g5 ! Else compute phys-kpte + andcc %g5, 1, %g0 ! I/O area? + be,pt %xcc, 2f ! Nope, go and load TLB + xor %g2, %g4, %g5 ! Finish bit twiddles + ba,pt %xcc, 2f ! Yes, I/O space, back back + xor %g5, (KERN_IOBITS), %g5 ! After set E, clear CP/CV + +/* DTLB ** ICACHE line 3: winfixups+real_faults */ +4: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page? + be,pn %xcc, 5f ! Yep, refbit update + sllx %g1, 60, %g4 ! Get valid bit + rdpr %pstate, %g5 ! Move into alternate globals + wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g4 ! See where we came from. + cmp %g4, 1 ! Is etrap/rtrap window fault? + mov TLB_TAG_ACCESS, %g4 ! Prepare for fault processing + +/* DTLB ** ICACHE line 4: padding */ + be,pt %xcc, sparc64_realfault_common ! Jump to normal fault handling + ldxa [%g4] ASI_DMMU, %g5 ! And load faulting VA page + ba,a,pt %xcc, winfix_trampoline ! Call window fixup code +5: or %g5, _PAGE_ACCESSED, %g5 ! Indicate reference + or %g5, %g4, %g5 ! Set valid + stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table (cant trap) +2: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB + retry ! Trap return + +#undef TAG_CONTEXT_BITS +#undef VPTE_SHIFT +#undef KERN_HIGHBITS +#undef KERN_LOWBITS +#undef KERN_LOWBITS_IO +#undef KERN_IOBITS diff --git a/arch/sparc64/kernel/dtlb_miss.S b/arch/sparc64/kernel/dtlb_miss.S deleted file mode 100644 index e5606cf33..000000000 --- a/arch/sparc64/kernel/dtlb_miss.S +++ /dev/null @@ -1,83 +0,0 @@ -/* $Id: dtlb_miss.S,v 1.15 1998/01/14 17:14:44 jj Exp $ - * dtlb_miss.S: Data TLB miss code, this is included directly - * into the trap table. - * - * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -/* The basic algorithm is: - * - * if(faulting_context != 0) { - * pgd = pgd_offset(current->mm.pgd, fault_address); - * page_table_walk_continue: - * pmd = pmd_offset(pgd, fault_address); - * pte = pte_offset(pmd, fault_address); - * if(pte & _PAGE_V) { - * tlb_load(pte, fault_address); - * return_from_trap(); - * } - * goto longer_processing; - * } else { - * if(fault_address >= PAGE_OFFSET) { - * pte_val = PAGE_KERNEL; - * if (fault_address & 0x10000000000) - * pte_val = PAGE_KERNEL_IO; - * tlb_load(__pa(fault_address) | pte_val); - * return_from_trap(); - * } else { - * pgd = pgd_offset(swapper_pg_dir, fault_address); - * goto page_table_walk_continue; - * } - * } - * - * This is optimized for user TLB misses on purpose. - */ - -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) -#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) -#define KERN_LOWBITS_IO (_PAGE_E | _PAGE_P | _PAGE_W) - - /* ICACHE line 1 */ - /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET - /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset - /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits - /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset - /*0x18*/ and %g1, 0xffe, %g4 ! Mask PMD offset - /*0x14*/ be,pn %xcc, 3f ! Context 0 == kernel - /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset - /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset - - /* ICACHE line 2 */ - /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD - /*0x24*/ srlx %g1, 1, %g1 ! PTE offset -2:/*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD - /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brgez,pn %g5, sparc64_dtlb_refbit_catch ! Valid set? - /*0x34*/ nop ! delay - /*0x38*/ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x3c*/ retry ! Trap return - -3: /* ICACHE line 3 */ - /*0x40*/ sllx %g1, 22, %g5 ! This is now physical page + PAGE_OFFSET - /*0x44*/ brgez,pn %g5, 4f ! If >= 0, then walk down page tables - /*0x48*/ or %g2, (KERN_LOWBITS), %g1 ! Construct PTE ^ PAGE_OFFSET - /*0x4c*/ andcc %g3, 0x100, %g0 ! Slick trick... - /*0x50*/ bne,a,pn %icc, 5f ! Is it an IO page? - /*0x54*/ or %g2, (KERN_LOWBITS_IO), %g1 ! Aha, it is IO... -5:/*0x58*/ xor %g1, %g5, %g1 ! Slick trick II... - /*0x5c*/ stxa %g1, [%g0] ASI_DTLB_DATA_IN ! TLB load - - /* ICACHE line 4 */ - /*0x60*/ retry ! Trap return - /*0x64*/ nop - /*0x68*/ nop - /*0x6c*/ nop -4:/*0x70*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset - /*0x74*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD - /*0x78*/ ba,pt %xcc, 2b ! Go back up top - /*0x7c*/ srlx %g1, 1, %g1 - -#undef KERN_HIGHBITS -#undef KERN_LOWBITS -#undef KERN_LOWBITS_IO diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S index 86cbfdc52..c4ce36502 100644 --- a/arch/sparc64/kernel/dtlb_prot.S +++ b/arch/sparc64/kernel/dtlb_prot.S @@ -1,56 +1,62 @@ -/* $Id: dtlb_prot.S,v 1.15 1998/01/14 17:14:46 jj Exp $ - * dtlb_prot.S: Data TLB protection code, this is included directly - * into the trap table. +/* $Id: dtlb_prot.S,v 1.17 1998/05/25 16:59:11 davem Exp $ + * dtlb_prot.S: DTLB protection trap strategy. + * This is included directly into the trap table. * - * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) */ - /* We know kernel never takes protection trap, - * this makes this routine a lot easier than it - * would be otherwise. - */ +#define TAG_CONTEXT_BITS 0x3ff +#define VPTE_SHIFT (PAGE_SHIFT - 3) +#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED) -#define MODIFIED_BITS (_PAGE_WRITE | _PAGE_W | _PAGE_MODIFIED | _PAGE_ACCESSED) +/* Ways we can get here: + * + * [TL == 0] 1) User stores to readonly pages. + * [TL == 0] 2) Nucleus stores to user readonly pages. + * [TL > 0] 3) Nucleus stores to user readonly stack frame. + */ - /* ICACHE line 1 */ - /*0x00*/ ldxa [%g0] ASI_DMMU, %g1 ! Get TAG_TARGET - /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset - /*0x08*/ and %g1, 0xffe, %g4 ! Mask PMD offset - /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset - /*0x10*/ add %g4, %g4, %g4 ! Position PMD offset - /*0x14*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load PGD - /*0x18*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g4 ! Load PMD - /*0x1c*/ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! For PTE offset +/* PROT ** ICACHE line 1: User DTLB protection trap */ + ldxa [%g1] ASI_DMMU, %g6 ! Primary or Secondary ctx? + and %g6, 0x10, %g6 ! Get pri/sec ctx bit + stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit + membar #Sync ! Synchronize ASI stores + ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Load TAG_ACCESS + andn %g4, TAG_CONTEXT_BITS, %g4 ! Clear CTX bits + stxa %g0, [%g4 + %g6] ASI_DMMU_DEMAP ! Perform TLB flush of page + membar #Sync ! Synchronize ASI stores - /* ICACHE line 2 */ - /*0x20*/ srlx %g1, 1, %g1 ! PTE offset - /*0x24*/ ldxa [%g4 + %g1] ASI_PHYS_USE_EC, %g3 ! Load PTE - /*0x28*/ andcc %g3, _PAGE_WRITE, %g0 ! Writable? - /*0x2c*/ be,pt %xcc, sparc64_dtlb_prot_catch ! Nope... - /*0x30*/ or %g3, (MODIFIED_BITS), %g3 ! Yes it is - /*0x34*/ mov TLB_TAG_ACCESS, %g5 ! Get the page - /*0x38*/ add %g1, %g4, %g1 ! to get a tmpreg - /*0x3c*/ ldxa [%g5] ASI_DMMU, %g4 ! From MMU +/* PROT ** ICACHE line 2: Further normal processing */ + srax %g4, VPTE_SHIFT, %g6 ! Compute VPTE offset + ldxa [%g3 + %g6] ASI_S, %g5 ! Load PTE entry + andcc %g5, _PAGE_WRITE, %g0 ! Writable page? + be,pt %xcc, 1f ! Nope, real fault + or %g5, (MODIFIED_BITS), %g5 ! Mark as writable/modified + stxa %g5, [%g3 + %g6] ASI_S ! Update PTE entry + stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load PTE into TLB + retry ! Trap return - /* ICACHE line 3 */ - /*0x40*/ mov TLB_SFSR, %g5 ! read SFSR - /*0x44*/ srlx %g4, 13, %g4 ! Prepare... - /*0x48*/ ldxa [%g5] ASI_DMMU, %g5 ! from DMMU for - /*0x4c*/ sllx %g4, 13, %g4 ! ...and mask page - /*0x50*/ and %g5, 0x10, %g5 ! context bit - /*0x54*/ or %g4, %g5, %g4 ! for prot trap -1:/*0x58*/ stxa %g0, [%g4] ASI_DMMU_DEMAP ! TLB flush page - /*0x5c*/ membar #Sync ! Synchronize +/* PROT ** ICACHE line 3: Real user faults */ +1: rdpr %pstate, %g5 ! Move into alternate globals + wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate + rdpr %tl, %g4 ! Need to do a winfixup? + cmp %g4, 1 ! Trap level >1? + mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr + bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup + ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5 + sethi %hi(1f), %g7 ! Nope, normal fault - /* ICACHE line 4 */ - /*0x60*/ stxa %g3, [%g1] ASI_PHYS_USE_EC ! Update sw PTE - /*0x64*/ stxa %g3, [%g0] ASI_DTLB_DATA_IN ! TLB load - /*0x68*/ retry ! Trap return - /*0x6c*/ nop - /*0x70*/ nop - /*0x74*/ nop - /*0x78*/ nop - /*0x7c*/ nop +/* PROT ** ICACHE line 4: More real fault processing */ + ba,pt %xcc, etrap ! Save state +1: or %g7, %lo(1b), %g7 ! ... + ba,pt %xcc, sparc64_realfault_continue! Now call the fault handler + mov 1, %o2 ! Indicate this was a write + nop + nop + nop + nop +#undef TAG_CONTEXT_BITS +#undef VPTE_SHIFT #undef MODIFIED_BITS diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 954cfd4bc..70465afbd 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -1,4 +1,4 @@ -/* $Id: ebus.c,v 1.23 1998/03/29 16:27:24 ecd Exp $ +/* $Id: ebus.c,v 1.29 1998/07/01 15:39:44 jj Exp $ * ebus.c: PCI to EBus bridge device. * * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) @@ -8,6 +8,7 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/init.h> +#include <linux/malloc.h> #include <linux/string.h> #include <asm/system.h> @@ -30,7 +31,7 @@ struct linux_ebus *ebus_chain = 0; extern void prom_ebus_ranges_init(struct linux_ebus *); extern void prom_ebus_intmap_init(struct linux_ebus *); -extern unsigned long pci_console_init(unsigned long memory_start); +extern void pci_console_init(void); #ifdef CONFIG_SUN_OPENPROMIO extern int openprom_init(void); @@ -48,18 +49,14 @@ extern int flash_init(void); extern int envctrl_init(void); #endif -extern unsigned int psycho_irq_build(struct linux_pbm_info *pbm, - unsigned int full_ino); - -static inline unsigned long -ebus_alloc(unsigned long *memory_start, size_t size) +static inline unsigned long ebus_alloc(size_t size) { unsigned long mem; - *memory_start = (*memory_start + 7) & ~(7); - mem = *memory_start; - *memory_start += size; - memset((void *)mem, 0, size); + mem = (unsigned long)kmalloc(size, GFP_ATOMIC); + if (!mem) + panic(__FUNCTION__ ": out of memory"); + memset((char *)mem, 0, size); return mem; } @@ -117,11 +114,27 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, len = prom_getproperty(node, "interrupts", (char *)&irqs, sizeof(irqs)); if ((len == -1) || (len == 0)) { dev->num_irqs = 0; + /* + * Oh, well, some PROMs don't export interrupts + * property to children of EBus devices... + * + * Be smart about PS/2 keyboard and mouse. + */ + if (!strcmp(dev->parent->prom_name, "8042")) { + if (!strcmp(dev->prom_name, "kb_ps2")) { + dev->num_irqs = 1; + dev->irqs[0] = dev->parent->irqs[0]; + } else { + dev->num_irqs = 1; + dev->irqs[0] = dev->parent->irqs[1]; + } + } } else { dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { ebus_intmap_match(dev->bus, preg, &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, + dev->bus->self, irqs[i]); } } @@ -133,15 +146,13 @@ __initfunc(void fill_ebus_child(int node, struct linux_prom_registers *preg, if (dev->num_irqs) { dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - dprintf(" %08x", dev->irqs[i]); + dprintf(" %s", __irq_itoa(dev->irqs[i])); dprintf("\n"); } #endif } -__initfunc(unsigned long fill_ebus_device(int node, - struct linux_ebus_device *dev, - unsigned long memory_start)) +__initfunc(void fill_ebus_device(int node, struct linux_ebus_device *dev)) { struct linux_prom_registers regs[PROMREG_MAX]; struct linux_ebus_child *child; @@ -176,7 +187,8 @@ __initfunc(unsigned long fill_ebus_device(int node, dev->num_irqs = len / sizeof(irqs[0]); for (i = 0; i < dev->num_irqs; i++) { ebus_intmap_match(dev->bus, ®s[0], &irqs[i]); - dev->irqs[i] = psycho_irq_build(dev->bus->parent, irqs[i]); + dev->irqs[i] = psycho_irq_build(dev->bus->parent, + dev->bus->self, irqs[i]); } } @@ -188,13 +200,13 @@ __initfunc(unsigned long fill_ebus_device(int node, if (dev->num_irqs) { dprintf(" IRQ%s", dev->num_irqs > 1 ? "s" : ""); for (i = 0; i < dev->num_irqs; i++) - dprintf(" %08x", dev->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(&memory_start, sizeof(struct linux_ebus_child)); + ebus_alloc(sizeof(struct linux_ebus_child)); child = dev->children; child->next = 0; @@ -204,7 +216,7 @@ __initfunc(unsigned long fill_ebus_device(int node, while ((node = prom_getsibling(node))) { child->next = (struct linux_ebus_child *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus_child)); + ebus_alloc(sizeof(struct linux_ebus_child)); child = child->next; child->next = 0; @@ -213,15 +225,12 @@ __initfunc(unsigned long fill_ebus_device(int node, fill_ebus_child(node, ®s[0], child); } } - - return memory_start; } extern void sun4u_start_timers(void); extern void clock_probe(void); -__initfunc(unsigned long ebus_init(unsigned long memory_start, - unsigned long memory_end)) +__initfunc(void ebus_init(void)) { struct linux_prom_pci_registers regs[PROMREG_MAX]; struct linux_pbm_info *pbm; @@ -237,7 +246,7 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, int num_ebus = 0; if (!pci_present()) - return memory_start; + return; pdev = pci_find_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, 0); if (!pdev) { @@ -245,14 +254,14 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, #ifdef PROM_DEBUG dprintf("ebus: No EBus's found.\n"); #endif - return memory_start; + return; } cookie = pdev->sysdata; ebusnd = cookie->prom_node; ebus_chain = ebus = (struct linux_ebus *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus)); + ebus_alloc(sizeof(struct linux_ebus)); ebus->next = 0; while (ebusnd) { @@ -323,24 +332,23 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, goto next_ebus; ebus->devices = (struct linux_ebus_device *) - ebus_alloc(&memory_start, - sizeof(struct linux_ebus_device)); + ebus_alloc(sizeof(struct linux_ebus_device)); dev = ebus->devices; dev->next = 0; dev->children = 0; dev->bus = ebus; - memory_start = fill_ebus_device(nd, dev, memory_start); + fill_ebus_device(nd, dev); while ((nd = prom_getsibling(nd))) { dev->next = (struct linux_ebus_device *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus_device)); + ebus_alloc(sizeof(struct linux_ebus_device)); dev = dev->next; dev->next = 0; dev->children = 0; dev->bus = ebus; - memory_start = fill_ebus_device(nd, dev, memory_start); + fill_ebus_device(nd, dev); } next_ebus: @@ -353,13 +361,15 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, ebusnd = cookie->prom_node; ebus->next = (struct linux_ebus *) - ebus_alloc(&memory_start, sizeof(struct linux_ebus)); + ebus_alloc(sizeof(struct linux_ebus)); ebus = ebus->next; ebus->next = 0; ++num_ebus; } - memory_start = pci_console_init(memory_start); +#ifndef CONFIG_FB + pci_console_init(); +#endif #ifdef CONFIG_SUN_OPENPROMIO openprom_init(); @@ -381,5 +391,4 @@ __initfunc(unsigned long ebus_init(unsigned long memory_start, #endif sun4u_start_timers(); clock_probe(); - return memory_start; } diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 76f913ade..774839af6 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1,10 +1,10 @@ -/* $Id: entry.S,v 1.76 1998/01/05 17:00:13 jj Exp $ +/* $Id: entry.S,v 1.87 1998/07/29 16:32:28 jj Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) - * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/config.h> @@ -18,6 +18,7 @@ #include <asm/signal.h> #include <asm/pgtable.h> #include <asm/processor.h> +#include <asm/visasm.h> /* #define SYSCALL_TRACING */ @@ -26,117 +27,23 @@ #define NR_SYSCALLS 256 /* Each OS is different... */ .text - .globl sparc64_dtlb_prot_catch, sparc64_dtlb_refbit_catch - .globl sparc64_itlb_refbit_catch - - /* Note, DMMU SFAR not updated for fast tlb data access miss - * traps, so we must use tag access to find the right page. - * However for DMMU fast protection traps it is updated so - * we use, but we must also clear it _before_ we enable interrupts - * and save state because there is a race where we can push a user - * window right now in etrap, a protection fault happens (for example - * to update the dirty bit) and since we left crap in the sfsr - * it will not get updated properly. - */ - .align 32 -sparc64_dtlb_prot_catch: - wr %g0, ASI_DMMU, %asi - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - rdpr %tl, %g3 - ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - stxa %g0, [%g0 + TLB_SFSR] %asi - membar #Sync - cmp %g3, 1 - - bgu,a,pn %icc, winfix_trampoline - rdpr %tpc, %g3 - sethi %hi(109f), %g7 - ba,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - b,pt %xcc, 1f - mov 1, %o2 - .align 32 -sparc64_dtlb_refbit_catch: - srlx %g5, 9, %g4 - and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 - cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) - be,a,pt %xcc, 2f - mov 1, %g4 - wr %g0, ASI_DMMU, %asi - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - - rdpr %tl, %g3 - ldxa [%g0 + TLB_TAG_ACCESS] %asi, %g5 - cmp %g3, 1 - bgu,pn %icc, winfix_trampoline - rdpr %tpc, %g3 - sethi %hi(109f), %g7 - b,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - - clr %o2 -1: srlx %l5, PAGE_SHIFT, %o1 - add %sp, STACK_BIAS + REGWIN_SZ, %o0 - call do_sparc64_fault - sllx %o1, PAGE_SHIFT, %o1 - b,pt %xcc, rtrap - clr %l6 .align 32 -sparc64_itlb_refbit_catch: - srlx %g5, 9, %g4 - and %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4 - cmp %g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9) - be,a,pt %xcc, 3f - mov 1, %g4 - rdpr %pstate, %g1 - wrpr %g1, PSTATE_AG|PSTATE_MG, %pstate - rdpr %tpc, %g5 - sethi %hi(109f), %g7 - b,pt %xcc, etrap -109: or %g7, %lo(109b), %g7 - b,pt %xcc, 1b - clr %o2 - - .align 32 -2: sllx %g4, 63, %g4 ! _PAGE_VALID - or %g5, _PAGE_ACCESSED, %g5 - or %g5, %g4, %g5 - stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE - stxa %g5, [%g0] ASI_DTLB_DATA_IN ! TLB load - retry - - .align 32 -3: sllx %g4, 63, %g4 ! _PAGE_VALID - or %g5, _PAGE_ACCESSED, %g5 - or %g5, %g4, %g5 - stxa %g5, [%g3 + %g1] ASI_PHYS_USE_EC ! store new PTE - stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load - retry - -#define FPDIS_OFF (((PAGE_SIZE<<1)-((64*4)+(2*8))) & ~(64 - 1)) /* This is trivial with the new code... */ .align 32 .globl do_fpdis do_fpdis: - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %g5 ! Load Group + ldub [%g6 + AOFF_task_tss + AOFF_thread_fpsaved], %g5 ! Load Group sethi %hi(TSTATE_PEF), %g4 ! IEU0 - sethi %hi(FPDIS_OFF), %g3 ! IEU1 wr %g0, FPRS_FEF, %fprs ! LSU Group+4bubbles - andcc %g5, SPARC_FLAG_USEDFPU, %g0 ! IEU1 Group - or %g3, %lo(FPDIS_OFF), %g2 ! IEU0 - sethi %hi(empty_zero_page), %g1 ! IEU0 Group - add %g6, %g2, %g2 ! IEU1 - be,a,pn %icc, 1f ! CTI - clr %g7 ! IEU0 Group - add %g2, 0x100, %g1 ! IEU1 - ldx [%g2 + 0x108], %g7 ! Load -1: andcc %g5, SPARC_FLAG_USEDFPUL, %g0 ! IEU1 Group + 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 +1: andcc %g5, FPRS_DL, %g0 ! IEU1 bne,pn %icc, 2f ! CTI fzero %f0 ! FPA - andcc %g5, SPARC_FLAG_USEDFPUU, %g0 ! IEU1 Group + andcc %g5, FPRS_DU, %g0 ! IEU1 Group bne,pn %icc, 1f ! CTI fzero %f2 ! FPA faddd %f0, %f2, %f4 @@ -170,17 +77,18 @@ do_fpdis: b,pt %xcc, fpdis_exit2 faddd %f0, %f2, %f60 1: mov SECONDARY_CONTEXT, %g3 + add %g6, AOFF_task_fpregs + 0x80, %g1 faddd %f0, %f2, %f4 fmuld %f0, %f2, %f6 ldxa [%g3] ASI_DMMU, %g5 + add %g6, AOFF_task_fpregs + 0xc0, %g2 stxa %g0, [%g3] ASI_DMMU faddd %f0, %f2, %f8 fmuld %f0, %f2, %f10 - flush %g2 - wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + flush %g6 membar #StoreLoad | #LoadLoad - ldda [%g2 + 0x080] %asi, %f32 - ldda [%g2 + 0x0c0] %asi, %f48 + ldda [%g1] ASI_BLK_S, %f32 ! grrr, where is ASI_BLK_NUCLEUS 8-( + ldda [%g2] ASI_BLK_S, %f48 faddd %f0, %f2, %f12 fmuld %f0, %f2, %f14 faddd %f0, %f2, %f16 @@ -193,20 +101,21 @@ do_fpdis: fmuld %f0, %f2, %f30 b,pt %xcc, fpdis_exit membar #Sync -2: andcc %g5, SPARC_FLAG_USEDFPUU, %g0 +2: andcc %g5, FPRS_DU, %g0 bne,pt %icc, 3f fzero %f32 mov SECONDARY_CONTEXT, %g3 fzero %f34 ldxa [%g3] ASI_DMMU, %g5 + add %g6, AOFF_task_fpregs, %g1 stxa %g0, [%g3] ASI_DMMU + add %g6, AOFF_task_fpregs + 0x40, %g2 faddd %f32, %f34, %f36 fmuld %f32, %f34, %f38 - flush %g2 - wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + flush %g6 membar #StoreLoad | #LoadLoad - ldda [%g2 + 0x000] %asi, %f0 - ldda [%g2 + 0x040] %asi, %f16 + ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-( + ldda [%g2] ASI_BLK_S, %f16 faddd %f32, %f34, %f40 fmuld %f32, %f34, %f42 faddd %f32, %f34, %f44 @@ -222,22 +131,24 @@ do_fpdis: b,pt %xcc, fpdis_exit membar #Sync 3: mov SECONDARY_CONTEXT, %g3 + add %g6, AOFF_task_fpregs, %g1 ldxa [%g3] ASI_DMMU, %g5 + mov 0x40, %g2 stxa %g0, [%g3] ASI_DMMU - flush %g2 - wr %g0, ASI_BLK_S, %asi ! grrr, where is ASI_BLK_NUCLEUS 8-( + flush %g6 membar #StoreLoad | #LoadLoad - ldda [%g2 + 0x000] %asi, %f0 - ldda [%g2 + 0x040] %asi, %f16 - ldda [%g2 + 0x080] %asi, %f32 - ldda [%g2 + 0x0c0] %asi, %f48 + ldda [%g1] ASI_BLK_S, %f0 ! grrr, where is ASI_BLK_NUCLEUS 8-( + ldda [%g1 + %g2] ASI_BLK_S, %f16 + add %g1, 0x80, %g1 + ldda [%g1] ASI_BLK_S, %f32 + ldda [%g1 + %g2] ASI_BLK_S, %f48 membar #Sync fpdis_exit: stxa %g5, [%g3] ASI_DMMU - flush %g2 + flush %g6 fpdis_exit2: wr %g7, 0, %gsr - ldx [%g1], %fsr + ldx [%g6 + AOFF_task_tss + AOFF_thread_xfsr], %fsr rdpr %tstate, %g3 or %g3, %g4, %g3 ! anal... wrpr %g3, %tstate @@ -300,8 +211,10 @@ do_ivec_xcall: add %g2, 0x10, %g2 ldxa [%g2] ASI_UDB_INTR_R, %g7 stxa %g0, [%g0] ASI_INTR_RECEIVE + membar #Sync jmpl %g3, %g0 - membar #Sync + nop + do_ivec_spurious: srl %g3, 3, %g3 sethi %hi(ivec_spurious_cookie), %g2 @@ -588,6 +501,8 @@ sunos_execv: .globl sys_sigreturn, 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 @@ -611,6 +526,19 @@ sys_memory_ordering: 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 +sys32_sigaltstack: + sethi %hi(do_sys32_sigaltstack), %g1 + mov %i6, %o2 + jmpl %g1 + %lo(do_sys32_sigaltstack), %g1 + nop .align 32 sys_sigsuspend: add %sp, STACK_BIAS + REGWIN_SZ, %o0 @@ -666,7 +594,7 @@ sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 - /* This is how fork() was meant to be done, 12 instruction entry. + /* This is how fork() was meant to be done, 8 instruction entry. * * I questioned the following code briefly, let me clear things * up so you must not reason on it like I did. @@ -689,26 +617,43 @@ sys_ptrace: add %sp, STACK_BIAS + REGWIN_SZ, %o0 * In fact we should take advantage of that fact for other things * during system calls... */ - .globl sys_fork, sys_vfork, sys_clone - .globl ret_from_syscall, ret_from_smpfork + .globl sys_fork, sys_vfork, sys_clone, sparc_exit + .globl ret_from_syscall .align 32 sys_fork: sys_vfork: mov SIGCHLD, %o0 clr %o1 -sys_clone: mov %o7, %l5 +sys_clone: flushw + mov %o7, %l5 add %sp, STACK_BIAS + REGWIN_SZ, %o2 movrz %o1, %fp, %o1 call do_fork mov %l5, %o7 +ret_from_syscall: + /* Clear SPARC_FLAG_NEWCHILD, switch_to leaves tss.flags in + * %o7 for us. + */ + andn %o7, 0x100, %o7 + sth %o7, [%g6 + AOFF_task_tss + AOFF_thread_flags] #ifdef __SMP__ -ret_from_smpfork: sethi %hi(scheduler_lock), %o4 membar #StoreStore | #LoadStore stb %g0, [%o4 + %lo(scheduler_lock)] #endif -ret_from_syscall: 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 + 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 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 9e7c9e374..1b6a1e2b0 100644 --- a/arch/sparc64/kernel/etrap.S +++ b/arch/sparc64/kernel/etrap.S @@ -1,8 +1,8 @@ -/* $Id: etrap.S,v 1.39 1997/10/24 11:57:47 jj Exp $ +/* $Id: etrap.S,v 1.40 1998/06/12 14:54:03 jj Exp $ * etrap.S: Preparing for entry into the kernel on Sparc V9. * * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <asm/asi.h> @@ -12,41 +12,32 @@ #include <asm/spitfire.h> #include <asm/head.h> -#define FPUREG_SZ ((64 * 4) + (2 * 8)) -#define TASK_REGOFF ((((PAGE_SIZE<<1)-FPUREG_SZ)&~(64-1)) - \ - TRACEREG_SZ-REGWIN_SZ) -#define FPU_OFF (STACK_BIAS + REGWIN_SZ + TRACEREG_SZ) +#define TASK_REGOFF ((PAGE_SIZE<<1)-TRACEREG_SZ-REGWIN_SZ) /* * On entry, %g7 is return address - 0x4. * %g4 and %g5 will be preserved %l4 and %l5 respectively. */ - .text - .align 32 -etrap_priv: or %g1, %g3, %g1 ! IEU0 Group - rd %fprs, %g3 ! Single Group+4bubbles - sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU0 Group - andcc %g3, FPRS_FEF, %g0 ! IEU1 - add %g2, REGWIN_SZ + TRACEREG_SZ - FPUREG_SZ, %g3 ! IEU0 Group - be,pt %icc, 1f ! CTI - andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - andn %g3, (64 - 1), %g3 ! IEU0 Group - ba,pt %xcc, 1f ! CTI - sub %g3, REGWIN_SZ + TRACEREG_SZ, %g2 ! IEU0 Group - + .text .align 32 .globl etrap, etrap_irq, etraptl1 + .globl scetrap etrap: rdpr %pil, %g2 ! Single Group etrap_irq: rdpr %tstate, %g1 ! Single Group sllx %g2, 20, %g3 ! IEU0 Group andcc %g1, TSTATE_PRIV, %g0 ! IEU1 - bne,pn %xcc, etrap_priv ! CTI - sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group - or %g1, %g3, %g1 ! IEU1 + or %g1, %g3, %g1 ! IEU0 Group + bne,a,pn %xcc, 1f ! CTI + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 + sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group + sethi %hi(TSTATE_PEF), %g3 ! IEU1 or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group - add %g6, %g2, %g2 ! IEU0 Group + and %g1, %g3, %g3 ! IEU1 + brnz,pn %g3, 1f ! CTI+IEU1 Group + add %g6, %g2, %g2 ! IEU0 + wr %g0, 0, %fprs ! Single Group+4bubbles 1: rdpr %tpc, %g3 ! Single Group stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group rdpr %tnpc, %g1 ! Single Group @@ -56,62 +47,27 @@ etrap_irq: rdpr %tstate, %g1 ! Single Group st %g3, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles - bne,pn %xcc, 2f ! CTI Group - sethi %hi(TSTATE_PEF), %l2 ! IEU0 - mov PRIMARY_CONTEXT, %l4 ! IEU1 + andn %g6, 0x1f, %l6 ! IEU0 Group + bne,pn %xcc, 3f ! CTI + mov PRIMARY_CONTEXT, %l4 ! IEU1 rdpr %canrestore, %g3 ! Single Group+4bubbles rdpr %wstate, %g2 ! Single Group+4bubbles wrpr %g0, 7, %cleanwin ! Single Group+4bubbles wrpr %g0, 0, %canrestore ! Single Group+4bubbles sll %g2, 3, %g2 ! IEU0 Group - mov SECONDARY_CONTEXT, %l5 ! IEU1 + mov 1, %l5 ! IEU1 + stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store wrpr %g3, 0, %otherwin ! Single Group+4bubbles wrpr %g2, 0, %wstate ! Single Group+4bubbles - rdpr %tstate, %l3 ! Single Group ldxa [%l4] ASI_DMMU, %g2 ! Load Group stxa %g0, [%l4] ASI_DMMU ! Store Group - stxa %g2, [%l5] ASI_DMMU ! Store Group - flush %g6 ! Single Group+9bubbles - andcc %l3, %l2, %g0 ! IEU1 Group - be,a,pt %icc, 6f ! CTI - st %g0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store - rd %fprs, %l0 ! Single Group+4bubbles - andcc %l0, FPRS_FEF, %g0 ! IEU1 Group - be,pn %icc, 6f ! CTI - st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l4 ! Load Group - stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group - or %l4, %l0, %l4 ! IEU0 Group - ba,pt %xcc, 3f ! CTI - sth %l4, [%g6 + AOFF_task_tss + AOFF_thread_flags] ! Store -2: rd %fprs, %l0 ! Single Group+4bubbles - andcc %l0, FPRS_FEF, %g0 ! IEU1 Group - be,pn %icc, 6f ! CTI - st %l0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_FPRS] ! Store - stx %fsr, [%sp + FPU_OFF + 0x100] ! Single Group -3: rd %gsr, %l7 ! Single Group+4bubbles - cmp %l0, FPRS_FEF ! IEU1 Group - be,pn %icc, 6f ! CTI - stx %l7, [%sp + FPU_OFF + 0x108] ! Store - wr %g0, ASI_BLK_P, %asi ! Singe Group+4bubbles - andcc %l0, FPRS_DL, %g0 ! IEU1 Group - be,pn %icc, 4f ! CTI - membar #StoreStore | #LoadStore ! Memory - stda %f0, [%sp + FPU_OFF + 0x000] %asi ! Store Group - stda %f16, [%sp + FPU_OFF + 0x040] %asi ! Store Group - andcc %l0, FPRS_DU, %g0 ! IEU1 - be,pn %icc, 5f ! CTI - nop ! IEU0 Group -4: stda %f32, [%sp + FPU_OFF + 0x080] %asi ! Store Group - stda %f48, [%sp + FPU_OFF + 0x0c0] %asi ! Store Group -5: membar #Sync ! Memory -6: wr %g0, 0x0, %fprs ! Single Group+4bubbles - wrpr %g0, 0x0, %tl ! Single Group+4bubbles + stxa %g2, [%l4 + %l4] ASI_DMMU ! Store Group + flush %l6 ! Single Group+9bubbles +2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles andn %g1, PSTATE_MM, %l1 ! IEU0 Group mov %g4, %l4 ! IEU1 mov %g5, %l5 ! IEU0 Group mov %g7, %l2 ! IEU1 - mov %g6, %l6 ! IEU0 Group wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group @@ -134,8 +90,80 @@ 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 + srl %l5, 1, %l3 ! IEU0 Group + add %l5, 2, %l5 ! IEU1 + stb %l5, [%l6 + AOFF_task_tss + AOFF_thread_fpdepth] ! Store + ba,pt %xcc, 2b ! CTI + stb %g0, [%l4 + %l3] ! Store Group + etraptl1: rdpr %tstate, %g1 ! Single Group+4bubbles - ba,pt %xcc, etrap_priv ! CTI Group - clr %g3 ! IEU0 + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 + ba,pt %xcc, 1b ! CTI Group + andcc %g1, TSTATE_PRIV, %g0 ! IEU0 + +scetrap: rdpr %pil, %g2 ! Single Group + rdpr %tstate, %g1 ! Single Group + sllx %g2, 20, %g3 ! IEU0 Group + andcc %g1, TSTATE_PRIV, %g0 ! IEU1 + or %g1, %g3, %g1 ! IEU0 Group + bne,a,pn %xcc, 1f ! CTI + sub %sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2 ! IEU1 + sethi %hi(TASK_REGOFF), %g2 ! IEU0 Group + sethi %hi(TSTATE_PEF), %g3 ! IEU1 + or %g2, %lo(TASK_REGOFF), %g2 ! IEU0 Group + and %g1, %g3, %g3 ! IEU1 + brnz,pn %g3, 1f ! CTI+IEU1 Group + add %g6, %g2, %g2 ! IEU0 + wr %g0, 0, %fprs ! Single Group+4bubbles +1: rdpr %tpc, %g3 ! Single Group + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TSTATE] ! Store Group + rdpr %tnpc, %g1 ! Single Group + stx %g3, [%g2 + REGWIN_SZ + PT_V9_TPC] ! Store Group + stx %g1, [%g2 + REGWIN_SZ + PT_V9_TNPC] ! Store Group + st %g0, [%g2 + REGWIN_SZ + PT_V9_Y] ! Store Group + save %g2, -STACK_BIAS, %sp ! The ordering here is ! Single Group + rdpr %pstate, %g1 ! critical, see winfixup ! Single Group+9bubbles + andn %g6, 0x1f, %l6 ! IEU0 Group + bne,pn %xcc, 2f ! CTI + mov PRIMARY_CONTEXT, %l4 ! IEU1 + rdpr %canrestore, %g3 ! Single Group+4bubbles + rdpr %wstate, %g2 ! Single Group+4bubbles + wrpr %g0, 7, %cleanwin ! Single Group+4bubbles + wrpr %g0, 0, %canrestore ! Single Group+4bubbles + sll %g2, 3, %g2 ! IEU0 Group + wrpr %g3, 0, %otherwin ! Single Group+4bubbles + wrpr %g2, 0, %wstate ! Single Group+4bubbles + ldxa [%l4] ASI_DMMU, %g2 ! Load Group + stxa %g0, [%l4] ASI_DMMU ! Store Group + stxa %g2, [%l4 + %l4] ASI_DMMU ! Store Group + flush %l6 ! Single Group+9bubbles +2: wrpr %g0, 0x0, %tl ! Single Group+4bubbles + andn %g1, PSTATE_MM, %l1 ! IEU0 Group + mov %g4, %l4 ! IEU1 + mov %g5, %l5 ! IEU0 Group + mov %g7, %l2 ! IEU1 + wrpr %l1, (PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles + stx %g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1] ! Store Group + stx %g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2] ! Store Group + stx %g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3] ! Store Group + stx %g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4] ! Store Group + stx %g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5] ! Store Group + stx %g6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6] ! Store Group + stx %g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7] ! Store Group + stx %i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0] ! Store Group + stx %i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1] ! Store Group + stx %i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2] ! Store Group + stx %i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3] ! Store Group + stx %i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4] ! Store Group + sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 + stx %i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5] ! Store Group + stx %i6, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6] ! Store Group + sllx %g4, 32, %g4 ! IEU0 + stx %i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7] ! Store Group + wrpr %l1, (PSTATE_IE|PSTATE_AG|PSTATE_RMO), %pstate ! Single Group+4bubbles + jmpl %l2 + 0x4, %g0 ! CTI Group + mov %l6, %g6 ! IEU0 + #undef TASK_REGOFF -#undef FPUREG_SZ diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index c0531f30a..f1e9c62fd 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.49 1998/03/03 12:31:17 jj Exp $ +/* $Id: head.S,v 1.53 1998/06/15 16:59:35 jj Exp $ * head.S: Initial boot code for the Sparc64 port of Linux. * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -89,6 +89,7 @@ sparc64_boot: * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate. */ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate + wr %g0, 0, %fprs #ifdef __SMP__ /* Ugly but necessary... */ @@ -348,17 +349,30 @@ setup_tba: /* Set up MMU globals */ wrpr %o1, (PSTATE_MG|PSTATE_IE), %pstate - /* Set KERN_HIGHBITS used by dTLB miss handler. */ -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) + /* Set fixed globals used by dTLB miss handler. */ +#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) +#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) +#ifdef THIS_IS_CHEETAH +#error Dave, make sure you took care of other issues in rest of sparc64 code... +#define VPTE_BASE 0xffe0000000000000 +#else /* Spitfire/Blackbird */ +#define VPTE_BASE 0xfffffffe00000000 +#endif + mov TSB_REG, %g1 + stxa %g0, [%g1] ASI_DMMU + membar #Sync + mov TLB_SFSR, %g1 sethi %uhi(KERN_HIGHBITS), %g2 + or %g2, %ulo(KERN_HIGHBITS), %g2 sllx %g2, 32, %g2 -#undef KERN_HIGHBITS - - /* Kernel PGDIR used by TLB miss handlers. */ - mov %i0, %g6 - - /* To catch bootup bugs, this is user PGDIR for TLB miss handlers. */ + or %g2, KERN_LOWBITS, %g2 + sethi %uhi(VPTE_BASE), %g3 + or %g3, %ulo(VPTE_BASE), %g3 + sllx %g3, 32, %g3 clr %g7 +#undef KERN_HIGHBITS +#undef KERN_LOWBITS +#undef VPTE_BASE /* Setup Interrupt globals */ wrpr %o1, (PSTATE_IG|PSTATE_IE), %pstate @@ -372,14 +386,6 @@ setup_tba: wrpr %g0, %g0, %wstate wrpr %o1, PSTATE_IE, %pstate - /* Zap TSB BASE to zero with TSB_size==1. */ - mov TSB_REG, %o4 - mov 1, %o5 - stxa %o5, [%o4] ASI_DMMU - stxa %o5, [%o4] ASI_IMMU - - membar #Sync - sethi %hi(sparc64_ttable_tl0), %g5 call prom_set_trap_table mov %g5, %o0 @@ -403,6 +409,12 @@ empty_bad_page: #include "ttable.S" #include "systbls.S" + + .align 1024 + .globl swapper_pg_dir +swapper_pg_dir: + .word 0 + #include "etrap.S" #include "rtrap.S" #include "winfixup.S" @@ -420,3 +432,4 @@ prom_tba: .xword 0 __ret_efault: ret restore %g0, -EFAULT, %o0 + diff --git a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c index 17e904f25..51fbd6ce5 100644 --- a/arch/sparc64/kernel/ioctl32.c +++ b/arch/sparc64/kernel/ioctl32.c @@ -1,7 +1,8 @@ -/* $Id: ioctl32.c,v 1.35 1998/04/10 02:01:46 davem Exp $ +/* $Id: ioctl32.c,v 1.48 1998/08/03 23:58:04 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * These routines maintain argument size conversion between 32bit and 64bit * ioctls. @@ -28,6 +29,11 @@ #include <linux/if_ppp.h> #include <linux/mtio.h> #include <linux/cdrom.h> +#include <linux/loop.h> +#include <linux/auto_fs.h> +#include <linux/tty.h> +#include <linux/vt_kern.h> +#include <linux/fb.h> #include <scsi/scsi.h> /* Ugly hack. */ @@ -42,6 +48,8 @@ #include <asm/vuid_event.h> #include <asm/rtc.h> #include <asm/openpromio.h> +#include <asm/envctrl.h> +#include <asm/audioio.h> /* As gcc will warn about casting u32 to some ptr, we have to cast it to * unsigned long first, and that's what is A() for. @@ -66,6 +74,22 @@ static int w_long(unsigned int fd, unsigned int cmd, u32 arg) return err; } +static int rw_long(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + int err; + unsigned long val; + + if(get_user(val, (u32 *)A(arg))) + return -EFAULT; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)A(arg))) + return -EFAULT; + return err; +} + struct timeval32 { int tv_sec; int tv_usec; @@ -374,7 +398,7 @@ static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) } f.red = red; f.green = green; f.blue = blue; set_fs (KERNEL_DS); - ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP : FBIOGETCMAP, (long)&f); + ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP_SPARC : FBIOGETCMAP_SPARC, (long)&f); set_fs (old_fs); if (!ret && cmd == FBIOGETCMAP32) { if (copy_to_user ((char *)A(r), red, f.count) || @@ -440,7 +464,162 @@ static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) set_fs (old_fs); return ret; } - + +struct fb_fix_screeninfo32 { + char id[16]; + __kernel_caddr_t32 smem_start; + __u32 smem_len; + __u32 type; + __u32 type_aux; + __u32 visual; + __u16 xpanstep; + __u16 ypanstep; + __u16 ywrapstep; + __u32 line_length; + __kernel_caddr_t32 mmio_start; + __u32 mmio_len; + __u32 accel; + __u16 reserved[3]; +}; + +struct fb_cmap32 { + __u32 start; + __u32 len; + __kernel_caddr_t32 red; + __kernel_caddr_t32 green; + __kernel_caddr_t32 blue; + __kernel_caddr_t32 transp; +}; + +static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + u32 red = 0, green = 0, blue = 0, transp = 0; + struct fb_fix_screeninfo fix; + struct fb_cmap cmap; + void *karg; + int err = 0; + + switch (cmd) { + case FBIOGET_FSCREENINFO: + karg = &fix; + break; + case FBIOGETCMAP: + case FBIOPUTCMAP: + karg = &cmap; + if (__get_user(cmap.start, &((struct fb_cmap32 *)A(arg))->start) || + __get_user(cmap.len, &((struct fb_cmap32 *)A(arg))->len) || + __get_user(red, &((struct fb_cmap32 *)A(arg))->red) || + __get_user(green, &((struct fb_cmap32 *)A(arg))->green) || + __get_user(blue, &((struct fb_cmap32 *)A(arg))->blue) || + __get_user(transp, &((struct fb_cmap32 *)A(arg))->transp)) + return -EFAULT; + cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); + if (!cmap.red) + return -ENOMEM; + cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); + if (!cmap.green) { + kfree(cmap.red); + return -ENOMEM; + } + cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); + if (!cmap.blue) { + kfree(cmap.red); + kfree(cmap.green); + return -ENOMEM; + } + if (transp) { + cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); + if (!cmap.transp) { + kfree(cmap.red); + kfree(cmap.green); + kfree(cmap.blue); + return -ENOMEM; + } + } else { + cmap.transp = NULL; + } + if (cmd == FBIOGETCMAP) + break; + + if (__copy_from_user(cmap.red, (char *)A(((struct fb_cmap32 *)A(arg))->red), + cmap.len * sizeof(__u16)) || + __copy_from_user(cmap.green, (char *)A(((struct fb_cmap32 *)A(arg))->green), + cmap.len * sizeof(__u16)) || + __copy_from_user(cmap.blue, (char *)A(((struct fb_cmap32 *)A(arg))->blue), + cmap.len * sizeof(__u16)) || + (cmap.transp && + __copy_from_user(cmap.transp, (char *)A(((struct fb_cmap32 *)A(arg))->transp), + cmap.len * sizeof(__u16)))) { + kfree(cmap.red); + kfree(cmap.green); + kfree(cmap.blue); + if (cmap.transp) + kfree(cmap.transp); + return -EFAULT; + } + break; + default: + printk("%s: Unknown fb ioctl cmd fd(%d) cmd(%08x) arg(%08x)\n", + __FUNCTION__, fd, cmd, arg); + return -ENOSYS; + } + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)karg); + set_fs(old_fs); + if (err) + return err; + switch (cmd) { + case FBIOGET_FSCREENINFO: + if (__copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->id, + (char *)fix.id, sizeof(fix.id)) || + __put_user((__u32)(unsigned long)fix.smem_start, + &((struct fb_fix_screeninfo32 *)A(arg))->smem_start) || + __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)A(arg))->smem_len) || + __put_user(fix.type, &((struct fb_fix_screeninfo32 *)A(arg))->type) || + __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)A(arg))->type_aux) || + __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)A(arg))->visual) || + __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)A(arg))->xpanstep) || + __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)A(arg))->ypanstep) || + __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)A(arg))->ywrapstep) || + __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)A(arg))->line_length) || + __put_user((__u32)(unsigned long)fix.mmio_start, + &((struct fb_fix_screeninfo32 *)A(arg))->mmio_start) || + __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)A(arg))->mmio_len) || + __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)A(arg))->accel) || + __copy_to_user((char *)((struct fb_fix_screeninfo32 *)A(arg))->reserved, + (char *)fix.reserved, sizeof(fix.reserved))) + return -EFAULT; + break; + case FBIOGETCMAP: + if (__copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->red), cmap.red, + cmap.len * sizeof(__u16)) || + __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->green), cmap.blue, + cmap.len * sizeof(__u16)) || + __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->blue), cmap.blue, + cmap.len * sizeof(__u16)) || + (cmap.transp && + __copy_to_user((char *)A(((struct fb_cmap32 *)A(arg))->transp), cmap.transp, + cmap.len * sizeof(__u16)))) { + kfree(cmap.red); + kfree(cmap.green); + kfree(cmap.blue); + if (cmap.transp) + kfree(cmap.transp); + return -EFAULT; + } + /* fall through */ + case FBIOPUTCMAP: + kfree(cmap.red); + kfree(cmap.green); + kfree(cmap.blue); + if (cmap.transp) + kfree(cmap.transp); + break; + } + return 0; +} + static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); @@ -1059,6 +1238,190 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) return 0; } +struct loop_info32 { + int lo_number; /* ioctl r/o */ + __kernel_dev_t32 lo_device; /* ioctl r/o */ + unsigned int lo_inode; /* ioctl r/o */ + __kernel_dev_t32 lo_rdevice; /* ioctl r/o */ + int lo_offset; + int lo_encrypt_type; + int lo_encrypt_key_size; /* ioctl w/o */ + int lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + unsigned int lo_init[2]; + char reserved[4]; +}; + +static int loop_status(unsigned int fd, unsigned int cmd, u32 arg) +{ + mm_segment_t old_fs = get_fs(); + struct loop_info l; + int err = 0; + + switch(cmd) { + case LOOP_SET_STATUS: + if ((get_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) || + __get_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) || + __get_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) || + __get_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) || + __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)A(arg))->lo_offset, + 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset))) + return -EFAULT; + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + break; + case LOOP_GET_STATUS: + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + if (!err && + (put_user(l.lo_number, &((struct loop_info32 *)A(arg))->lo_number) || + __put_user(l.lo_device, &((struct loop_info32 *)A(arg))->lo_device) || + __put_user(l.lo_inode, &((struct loop_info32 *)A(arg))->lo_inode) || + __put_user(l.lo_rdevice, &((struct loop_info32 *)A(arg))->lo_rdevice) || + __copy_to_user((char *)&((struct loop_info32 *)A(arg))->lo_offset, + (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset))) + err = -EFAULT; + break; + } + return err; +} + +extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); + +static int vt_check(struct file *file) +{ + struct tty_struct *tty; + struct inode *inode = file->f_dentry->d_inode; + + if (file->f_op->ioctl != tty_ioctl) + return -EINVAL; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) + return -EINVAL; + + if (tty->driver.ioctl != vt_ioctl) + return -EINVAL; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + if (current->tty == tty || suser()) + return 1; + return 0; +} + +struct consolefontdesc32 { + unsigned short charcount; /* characters in font (256 or 512) */ + unsigned short charheight; /* scan lines per character (1-32) */ + u32 chardata; /* font data in expanded form */ +}; + +static int do_fontx_ioctl(struct file *file, int cmd, struct consolefontdesc32 *user_cfd) +{ + struct consolefontdesc cfdarg; + struct console_font_op op; + int i, perm; + + perm = vt_check(file); + if (perm < 0) return perm; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) + return -EFAULT; + + cfdarg.chardata = (unsigned char *)A(((struct consolefontdesc32 *)&cfdarg)->chardata); + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + return con_font_op(fg_console, &op); + case GIO_FONTX: + if (!cfdarg.chardata) + return 0; + op.op = KD_FONT_OP_GET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + i = con_font_op(fg_console, &op); + if (i) + return i; + cfdarg.charheight = op.height; + cfdarg.charcount = op.charcount; + ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32))) + return -EFAULT; + return 0; + } + return -EINVAL; +} + +struct console_font_op32 { + unsigned int op; /* operation code KD_FONT_OP_* */ + unsigned int flags; /* KD_FONT_FLAG_* */ + unsigned int width, height; /* font size */ + unsigned int charcount; + u32 data; /* font data with height fixed to 32 */ +}; + +static int do_kdfontop_ioctl(struct file *file, struct console_font_op32 *fontop) +{ + struct console_font_op op; + int perm = vt_check(file), i; + struct vt_struct *vt; + + if (perm < 0) return perm; + + if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + op.data = (unsigned char *)A(((struct console_font_op32 *)&op)->data); + op.flags |= KD_FONT_FLAG_OLD; + vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; + i = con_font_op(vt->vc_num, &op); + if (i) return i; + ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; + if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) + return -EFAULT; + return 0; +} + +struct unimapdesc32 { + unsigned short entry_ct; + u32 entries; +}; + +static int do_unimap_ioctl(struct file *file, int cmd, struct unimapdesc32 *user_ud) +{ + struct unimapdesc32 tmp; + int perm = vt_check(file); + + if (perm < 0) return perm; + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) return -EPERM; + return con_set_unimap(fg_console, tmp.entry_ct, (struct unipair *)A(tmp.entries)); + case GIO_UNIMAP: + return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), (struct unipair *)A(tmp.entries)); + } + return 0; +} + asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; @@ -1131,6 +1494,10 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case BLKRAGET: case BLKGETSIZE: + case 0x1260: + /* The mkswap binary hard codes it to Intel value :-((( */ + if(cmd == 0x1260) + cmd = BLKGETSIZE; error = w_long(fd, cmd, arg); goto out; @@ -1143,6 +1510,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) error = fbiogscursor(fd, cmd, arg); goto out; + case FBIOGET_FSCREENINFO: + case FBIOGETCMAP: + case FBIOPUTCMAP: + error = fb_ioctl_trans(fd, cmd, arg); + goto out; + case HDIO_GET_KEEPSETTINGS: case HDIO_GET_UNMASKINTR: case HDIO_GET_DMA: @@ -1185,7 +1558,30 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case CDROMREADALL: error = cdrom_ioctl_trans(fd, cmd, arg); goto out; + + case LOOP_SET_STATUS: + case LOOP_GET_STATUS: + error = loop_status(fd, cmd, arg); + goto out; + + case AUTOFS_IOC_SETTIMEOUT: + error = rw_long(fd, cmd, arg); + goto out; + + case PIO_FONTX: + case GIO_FONTX: + error = do_fontx_ioctl(filp, cmd, (struct consolefontdesc32 *)A(arg)); + goto out; + + case PIO_UNIMAP: + case GIO_UNIMAP: + error = do_unimap_ioctl(filp, cmd, (struct unimapdesc32 *)A(arg)); + goto out; + case KDFONTOP: + error = do_kdfontop_ioctl(filp, (struct console_font_op32 *)A(arg)); + goto out; + /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ @@ -1237,6 +1633,17 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case FBIOGCURPOS: case FBIOGCURMAX: + case FBIOGET_VSCREENINFO: + case FBIOPUT_VSCREENINFO: + case FBIOPAN_DISPLAY: + case FBIOGET_FCURSORINFO: + case FBIOGET_VCURSORINFO: + case FBIOPUT_VCURSORINFO: + case FBIOGET_CURSORSTATE: + case FBIOPUT_CURSORSTATE: + case FBIOGET_CON2FBMAP: + case FBIOPUT_CON2FBMAP: + /* Little f */ case FIOCLEX: case FIONCLEX: @@ -1319,6 +1726,12 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case KDSKBLED: case KDGETLED: case KDSETLED: + case GIO_SCRNMAP: + case PIO_SCRNMAP: + case GIO_UNISCRNMAP: + case PIO_UNISCRNMAP: + case PIO_FONTRESET: + case PIO_UNIMAPCLR: /* Little k */ case KIOCTYPE: @@ -1360,9 +1773,11 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case VUIDSFORMAT: case VUIDGFORMAT: - /* Little p (/dev/rtc etc.) */ + /* Little p (/dev/rtc, /dev/envctrl, etc.) */ case RTCGET: case RTCSET: + case I2CIOCSADR: + case I2CIOCGADR: /* Little m */ case MTIOCTOP: @@ -1455,6 +1870,25 @@ asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) case CDROM_DRIVE_STATUS: case CDROM_DISC_STATUS: case CDROM_CHANGER_NSLOTS: + + /* Big L */ + case LOOP_SET_FD: + case LOOP_CLR_FD: + + /* Big A */ + case AUDIO_GETINFO: + case AUDIO_SETINFO: + case AUDIO_DRAIN: + case AUDIO_GETDEV: + case AUDIO_GETDEV_SUNOS: + case AUDIO_FLUSH: + + /* AUTOFS */ + case AUTOFS_IOC_READY: + case AUTOFS_IOC_FAIL: + case AUTOFS_IOC_CATATONIC: + case AUTOFS_IOC_PROTOVER: + case AUTOFS_IOC_EXPIRE: error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; diff --git a/arch/sparc64/kernel/ioport.c b/arch/sparc64/kernel/ioport.c index 7ae12df11..84b097d3f 100644 --- a/arch/sparc64/kernel/ioport.c +++ b/arch/sparc64/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.13 1997/08/18 01:20:22 davem Exp $ +/* $Id: ioport.c,v 1.14 1998/05/11 06:23:36 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -20,7 +20,6 @@ /* This points to the next to use virtual memory for io mappings */ static unsigned long dvma_next_free = DVMA_VADDR; -unsigned long sparc_iobase_vaddr = IOBASE_VADDR; extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr); @@ -33,7 +32,9 @@ extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr); * Input: * address: Physical address to map * virtual: if non zero, specifies a fixed virtual address where - * the mapping should take place. + * the mapping should take place, not supported on Ultra + * and this feature is scheduled to be removed as nobody + * uses it. -DaveM * len: the length of the mapping * bus_type: Optional high word of physical address. * @@ -44,59 +45,24 @@ extern void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr); void *sparc_alloc_io (u32 address, void *virtual, int len, char *name, u32 bus_type, int rdonly) { - unsigned long vaddr, base_address; unsigned long addr = ((unsigned long)address) + (((unsigned long)bus_type)<<32); - unsigned long offset = (addr & (~PAGE_MASK)); - - if (virtual) { - vaddr = (unsigned long) virtual; - - len += offset; - if(((unsigned long) virtual + len) > (IOBASE_VADDR + IOBASE_LEN)) { - prom_printf("alloc_io: Mapping outside IOBASE area\n"); - prom_halt(); - } - if(check_region ((vaddr | offset), len)) { - prom_printf("alloc_io: 0x%lx is already in use\n", vaddr); - prom_halt(); - } - - /* Tell Linux resource manager about the mapping */ - request_region ((vaddr | offset), len, name); - } else { - unsigned long vaddr = (unsigned long) __va(addr); - - if(!check_region(vaddr, len)) - request_region(vaddr, len, name); - - return (void *) vaddr; - } + unsigned long vaddr = (unsigned long) __va(addr); - base_address = vaddr; - /* Do the actual mapping */ - for (; len > 0; len -= PAGE_SIZE) { - mapioaddr(addr, vaddr, bus_type, rdonly); - vaddr += PAGE_SIZE; - addr += PAGE_SIZE; - } + if(virtual) + panic("sparc_alloc_io: Fixed virtual mappings unsupported on Ultra."); - return (void *) (base_address | offset); + if(!check_region(vaddr, len)) + request_region(vaddr, len, name); + + return (void *) vaddr; } void sparc_free_io (void *virtual, int len) { unsigned long vaddr = (unsigned long) virtual & PAGE_MASK; - unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + len + PAGE_SIZE-1) & PAGE_MASK; - + unsigned long plen = (((unsigned long)virtual & ~PAGE_MASK) + + len + PAGE_SIZE-1) & PAGE_MASK; release_region(vaddr, plen); - - if (((unsigned long)virtual) >= PAGE_OFFSET + 0x10000000000UL) - return; - - for (; plen != 0;) { - plen -= PAGE_SIZE; - unmapioaddr(vaddr + plen); - } } /* Does DVMA allocations with PAGE_SIZE granularity. How this basically diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 176079643..eaa7ad7d4 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -1,8 +1,9 @@ -/* $Id: irq.c,v 1.52 1998/03/19 00:22:54 ecd Exp $ +/* $Id: irq.c,v 1.61 1998/08/02 14:51:38 ecd Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #include <linux/config.h> @@ -36,6 +37,7 @@ /* Internal flag, should not be visible elsewhere at all. */ #define SA_IMAP_MASKED 0x100 +#define SA_DMA_SYNC 0x200 #ifdef __SMP__ void distribute_irqs(void); @@ -53,35 +55,6 @@ static int irqs_have_been_distributed = 0; unsigned long ivector_to_mask[NUM_IVECS]; -struct ino_bucket { - struct ino_bucket *next; - unsigned int ino; - unsigned int *imap; - unsigned int *iclr; - unsigned char *imap_refcnt; -}; - -#define INO_HASHSZ (NUM_HARD_IVECS >> 2) -#define NUM_INO_STATIC 4 -static struct ino_bucket *ino_hash[INO_HASHSZ] = { NULL, }; -static struct ino_bucket static_ino_buckets[NUM_INO_STATIC]; -static int static_ino_bucket_count = 0; - -static inline struct ino_bucket *__ino_lookup(unsigned int hash, unsigned int ino) -{ - struct ino_bucket *ret = ino_hash[hash]; - - for(ret = ino_hash[hash]; ret && ret->ino != ino; ret = ret->next) - ; - - return ret; -} - -static inline struct ino_bucket *ino_lookup(unsigned int ino) -{ - return __ino_lookup((ino & (INO_HASHSZ - 1)), ino); -} - /* This is based upon code in the 32-bit Sparc kernel written mostly by * David Redman (djhr@tadpole.co.uk). */ @@ -95,6 +68,24 @@ struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; +#define IBF_DMA_SYNC 0x01 +#define IBF_PCI 0x02 +#define IBF_ACTIVE 0x04 + +#define __imap(bucket) ((bucket)->iclr + (bucket)->imap_off) +#define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) +#define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) + +static struct ino_bucket *bucket_base, *buckets, *endbuckets; + +__initfunc(unsigned long irq_init(unsigned long start_mem, unsigned long end_mem)) +{ + start_mem = (start_mem + 15) & ~15; + bucket_base = buckets = (struct ino_bucket *)start_mem; + endbuckets = buckets + 2048; + return (unsigned long)endbuckets; +} + int get_irq_list(char *buf) { int i, len = 0; @@ -187,22 +178,6 @@ offset(imap_pmgmt), #define NUM_SYSIO_OFFSETS (sizeof(sysio_irq_offsets) / sizeof(sysio_irq_offsets[0])) -/* XXX Old compatability cruft, get rid of me when all drivers have been - * XXX converted to dcookie registry calls... -DaveM - */ -static unsigned int *sysio_irq_to_imap(unsigned int irq) -{ - unsigned long offset; - struct sysio_regs *sregs; - - if((irq >= NUM_SYSIO_OFFSETS) || - ((offset = sysio_irq_offsets[irq]) == ((unsigned long)-1))) - return NULL; - sregs = SBus_chain->iommu->sysio_regs; - offset += ((unsigned long) sregs); - return ((unsigned int *)offset); -} - /* Convert Interrupt Mapping register pointer to assosciated * Interrupt Clear register pointer, SYSIO specific version. */ @@ -219,10 +194,10 @@ static unsigned int *sysio_imap_to_iclr(unsigned int *imap) #ifdef CONFIG_PCI /* PCI PSYCHO INO number to Sparc PIL level. */ unsigned char psycho_ino_to_pil[] = { - 7, 5, 5, 2, /* PCI A slot 0 Int A, B, C, D */ - 7, 5, 5, 2, /* PCI A slot 1 Int A, B, C, D */ - 7, 5, 5, 2, /* PCI A slot 2 Int A, B, C, D */ - 7, 5, 5, 2, /* PCI A slot 3 Int A, B, C, D */ + 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 */ @@ -263,21 +238,14 @@ unsigned char psycho_ino_to_pil[] = { #endif /* Now these are always passed a true fully specified sun4u INO. */ -void enable_irq(unsigned int ino) +void enable_irq(unsigned int irq) { - struct ino_bucket *bucket; + struct ino_bucket *bucket = __bucket(irq); unsigned long tid; unsigned int *imap; -#ifdef CONFIG_PCI - if(PCI_IRQ_P(ino)) - ino &= (PCI_IRQ_IGN | PCI_IRQ_INO); -#endif - bucket = ino_lookup(ino); - if(!bucket) - return; - - imap = bucket->imap; + imap = __imap(bucket); + if (!imap) return; /* We send it to our UPA MID, for SMP this will be different. */ __asm__ __volatile__("ldxa [%%g0] %1, %0" : "=r" (tid) : "i" (ASI_UPA_CONFIG)); @@ -289,26 +257,19 @@ void enable_irq(unsigned int ino) * However for Graphics and UPA Slave devices the full * SYSIO_IMAP_INR field can be set by the programmer here. * - * Things like FFB can now be handled via the dcookie mechanism. + * Things like FFB can now be handled via the new IRQ mechanism. */ *imap = SYSIO_IMAP_VALID | (tid & SYSIO_IMAP_TID); } /* This now gets passed true ino's as well. */ -void disable_irq(unsigned int ino) +void disable_irq(unsigned int irq) { - struct ino_bucket *bucket; + struct ino_bucket *bucket = __bucket(irq); unsigned int *imap; -#ifdef CONFIG_PCI - if(PCI_IRQ_P(ino)) - ino &= (PCI_IRQ_IGN | PCI_IRQ_INO); -#endif - bucket = ino_lookup(ino); - if(!bucket) - return; - - imap = bucket->imap; + imap = __imap(bucket); + if (!imap) return; /* NOTE: We do not want to futz with the IRQ clear registers * and move the state to IDLE, the SCSI code does call @@ -318,265 +279,156 @@ void disable_irq(unsigned int ino) *imap &= ~(SYSIO_IMAP_VALID); } -static void get_irq_translations(int *cpu_irq, int *ivindex_fixup, - unsigned int **imap, unsigned int **iclr, - void *busp, unsigned long flags, - unsigned int irq) +unsigned int build_irq(int pil, int inofixup, unsigned int *iclr, unsigned int *imap) { - if(*cpu_irq != -1 && *imap != NULL && *iclr != NULL) - return; - - if(*cpu_irq != -1 || *imap != NULL || *iclr != NULL || busp == NULL) { - printk("get_irq_translations: Partial specification, this is bad.\n"); - printk("get_irq_translations: cpu_irq[%d] imap[%p] iclr[%p] busp[%p]\n", - *cpu_irq, *imap, *iclr, busp); - panic("Bad IRQ translations..."); + if (buckets == endbuckets) + panic("Out of IRQ buckets. Should not happen.\n"); + buckets->pil = pil; + if (pil && (!iclr || !imap)) { + prom_printf("Invalid build_irq %d %d %016lx %016lx\n", pil, inofixup, iclr, imap); + prom_halt(); } + if (imap) + buckets->ino = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)) + inofixup; + else + buckets->ino = 0; + + buckets->iclr = iclr; + buckets->flags = 0; + buckets->imap_off = imap - iclr; + return __irq(buckets++); +} - if(SA_BUS(flags) == SA_SBUS) { - struct linux_sbus *sbusp = busp; - struct sysio_regs *sregs = sbusp->iommu->sysio_regs; - unsigned long offset; - - *cpu_irq = sysio_ino_to_pil[irq]; - if(*cpu_irq == 0) { - printk("get_irq_translations: Bad SYSIO INO[%x]\n", irq); - panic("Bad SYSIO IRQ translations..."); - } - offset = sysio_irq_offsets[irq]; - if(offset == ((unsigned long)-1)) { - printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", - irq, *cpu_irq); - panic("BAD SYSIO IRQ offset..."); - } - offset += ((unsigned long)sregs); - *imap = ((unsigned int *)offset); - - /* SYSIO inconsistancy. For external SLOTS, we have to select - * the right ICLR register based upon the lower SBUS irq level - * bits. - */ - if(irq >= 0x20) { - *iclr = sysio_imap_to_iclr(*imap); - } else { - unsigned long iclraddr; - int sbus_slot = (irq & 0x18)>>3; - int sbus_level = irq & 0x7; - - switch(sbus_slot) { - case 0: - *iclr = &sregs->iclr_slot0; - break; - case 1: - *iclr = &sregs->iclr_slot1; - break; - case 2: - *iclr = &sregs->iclr_slot2; - break; - case 3: - *iclr = &sregs->iclr_slot3; - break; - }; - - iclraddr = (unsigned long) *iclr; - iclraddr += ((sbus_level - 1) * 8); - *iclr = (unsigned int *) iclraddr; - -#if 0 /* DEBUGGING */ - printk("SYSIO_FIXUP: slot[%x] level[%x] iclr[%p] ", - sbus_slot, sbus_level, *iclr); -#endif +unsigned int sbus_build_irq(void *buscookie, unsigned int ino) +{ + struct linux_sbus *sbus = (struct linux_sbus *)buscookie; + struct sysio_regs *sregs = sbus->iommu->sysio_regs; + unsigned long offset; + int pil; + unsigned int *imap, *iclr; + int sbus_level = 0; - /* Also, make sure this is accounted for in ivindex - * computations done by the caller. - */ - *ivindex_fixup = sbus_level; - } - return; + pil = sysio_ino_to_pil[ino]; + if(!pil) { + printk("sbus_irq_build: Bad SYSIO INO[%x]\n", ino); + panic("Bad SYSIO IRQ translations..."); } -#ifdef CONFIG_PCI - if(SA_BUS(flags) == SA_PCI) { - struct pci_bus *pbusp = busp; - struct linux_pbm_info *pbm = pbusp->sysdata; - struct psycho_regs *pregs = pbm->parent->psycho_regs; - unsigned long offset; - - *cpu_irq = psycho_ino_to_pil[irq & 0x3f]; - if(*cpu_irq == 0) { - printk("get_irq_translations: Bad PSYCHO INO[%x]\n", irq); - panic("Bad PSYCHO IRQ translations..."); - } - offset = psycho_imap_offset(irq); - if(offset == ((unsigned long)-1)) { - printk("get_irq_translations: Bad PSYCHO INO[%x] cpu[%d]\n", - irq, *cpu_irq); - panic("Bad PSYCHO IRQ offset..."); - } - offset += ((unsigned long)pregs); - *imap = ((unsigned int *)offset) + 1; - *iclr = (unsigned int *) - (((unsigned long)pregs) + psycho_iclr_offset(irq)); - return; + offset = sysio_irq_offsets[ino]; + if(offset == ((unsigned long)-1)) { + printk("get_irq_translations: Bad SYSIO INO[%x] cpu[%d]\n", + ino, pil); + panic("BAD SYSIO IRQ offset..."); } -#endif -#if 0 /* XXX More to do before we can use this. -DaveM */ - if(SA_BUS(flags) == SA_FHC) { - struct fhc_bus *fbusp = busp; - struct fhc_regs *fregs = fbusp->regs; - unsigned long offset; - - *cpu_irq = fhc_ino_to_pil[irq]; - if(*cpu_irq == 0) { - printk("get_irq_translations: Bad FHC INO[%x]\n", irq); - panic("Bad FHC IRQ translations..."); - } - offset = fhc_irq_offset[*cpu_irq]; - if(offset == ((unsigned long)-1)) { - printk("get_irq_translations: Bad FHC INO[%x] cpu[%d]\n", - irq, *cpu_irq); - panic("Bad FHC IRQ offset..."); - } - offset += ((unsigned long)pregs); - *imap = (((unsigned int *)offset)+1); - *iclr = fhc_imap_to_iclr(*imap); - return; + offset += ((unsigned long)sregs); + imap = ((unsigned int *)offset); + + /* SYSIO inconsistancy. For external SLOTS, we have to select + * the right ICLR register based upon the lower SBUS irq level + * bits. + */ + if(ino >= 0x20) { + iclr = sysio_imap_to_iclr(imap); + } else { + unsigned long iclraddr; + int sbus_slot = (ino & 0x18)>>3; + + sbus_level = ino & 0x7; + + switch(sbus_slot) { + case 0: + iclr = &sregs->iclr_slot0; + break; + case 1: + iclr = &sregs->iclr_slot1; + break; + case 2: + iclr = &sregs->iclr_slot2; + break; + default: + case 3: + iclr = &sregs->iclr_slot3; + break; + }; + + iclraddr = (unsigned long) iclr; + iclraddr += ((sbus_level - 1) * 8); + iclr = (unsigned int *) iclraddr; } -#endif - printk("get_irq_translations: IRQ register for unknown bus type.\n"); - printk("get_irq_translations: BUS[%lx] IRQ[%x]\n", - SA_BUS(flags), irq); - panic("Bad IRQ bus type..."); + return build_irq(pil, sbus_level, iclr, imap); } #ifdef CONFIG_PCI -static void pci_irq_frobnicate(int *cpu_irq, int *ivindex_fixup, - unsigned int **imap, unsigned int **iclr, - unsigned int irq) +unsigned int psycho_build_irq(void *buscookie, int imap_off, int ino, int need_dma_sync) { - struct linux_psycho *psycho; - struct psycho_regs *pregs; - unsigned long addr, imoff; - - psycho = psycho_by_index((irq & PCI_IRQ_BUSNO) >> PCI_IRQ_BUSNO_SHFT); - if (!psycho) { - printk("get_irq_translations: BAD PSYCHO BUSNO[%x]\n", irq); - panic("Bad PSYCHO IRQ frobnication..."); - } - pregs = psycho->psycho_regs; + 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; - imoff = (irq & PCI_IRQ_IMAP_OFF) >> PCI_IRQ_IMAP_OFF_SHFT; - addr = addr + imoff; - - *imap = ((unsigned int *)addr) + 1; + addr = addr + imap_off; + imap = ((unsigned int *)addr) + 1; addr = (unsigned long) pregs; - addr += psycho_iclr_offset(irq & (PCI_IRQ_INO)); - *iclr = ((unsigned int *)addr) + 1; + addr += psycho_iclr_offset(ino & (PCI_IRQ_INO)); + iclr = ((unsigned int *)addr) + 1; - *cpu_irq = psycho_ino_to_pil[irq & (PCI_IRQ_INO)]; - if(*cpu_irq == 0) { - printk("get_irq_translations: BAD PSYCHO INO[%x]\n", irq); - panic("Bad PSYCHO IRQ frobnication..."); - } + if(!(ino & 0x20)) + inofixup = ino & 0x03; - /* IVINDEX fixup only needed for PCI slot irq lines. */ - if(!(irq & 0x20)) - *ivindex_fixup = irq & 0x03; + 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 -/* Once added, they are never removed. */ -static struct ino_bucket *add_ino_hash(unsigned int ivindex, - unsigned int *imap, unsigned int *iclr, - unsigned long flags) -{ - struct ino_bucket *new = NULL, **hashp; - unsigned int hash = (ivindex & (INO_HASHSZ - 1)); - - new = __ino_lookup(hash, ivindex); - if(new) - return new; - if(flags & SA_STATIC_ALLOC) { - if(static_ino_bucket_count < NUM_INO_STATIC) - new = &static_ino_buckets[static_ino_bucket_count++]; - else - printk("Request for ino bucket SA_STATIC_ALLOC failed " - "using kmalloc\n"); - } - if(new == NULL) - new = kmalloc(sizeof(struct ino_bucket), GFP_KERNEL); - if(new) { - hashp = &ino_hash[hash]; - new->imap = imap; - new->iclr = iclr; - new->ino = ivindex; - new->next = *hashp; - *hashp = new; - } - return new; -} - int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action, *tmp = NULL; - struct devid_cookie *dcookie = NULL; - struct ino_bucket *bucket = NULL; + struct ino_bucket *bucket = __bucket(irq); unsigned long flags; - unsigned int *imap, *iclr; - void *bus_id = NULL; - int ivindex = -1, ivindex_fixup, cpu_irq = -1, pending = 0; + int pending = 0; + + if (irq < 0x400000 || (irq & 0x80000000)) { + prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler); + prom_halt(); + } if(!handler) return -EINVAL; - imap = iclr = NULL; - - ivindex_fixup = 0; - - if (irq == 0) { - cpu_irq = irq; - irqflags &= ~(SA_IMAP_MASKED); - } else { + if (!bucket->pil) + irqflags &= ~SA_IMAP_MASKED; + else { irqflags |= SA_IMAP_MASKED; -#ifdef CONFIG_PCI - if(PCI_IRQ_P(irq)) { - pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); - } else -#endif - if(irqflags & SA_DCOOKIE) { - if(!dev_id) { - printk("request_irq: SA_DCOOKIE but dev_id is NULL!\n"); - panic("Bogus irq registry."); - } - dcookie = dev_id; - dev_id = dcookie->real_dev_id; - cpu_irq = dcookie->pil; - imap = dcookie->imap; - iclr = dcookie->iclr; - bus_id = dcookie->bus_cookie; - get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, - &iclr, bus_id, irqflags, irq); - } else { - /* XXX NOTE: This code is maintained for compatability until I can - * XXX verify that all drivers sparc64 will use are updated - * XXX to use the new IRQ registry dcookie interface. -DaveM + if (bucket->flags & IBF_PCI) { + /* + * PCI IRQs should never use SA_INTERRUPT. */ - cpu_irq = sysio_ino_to_pil[irq]; - imap = sysio_irq_to_imap(irq); - if(!imap) { - printk("request_irq: BAD, null imap for old style " - "irq registry IRQ[%x].\n", irq); - panic("Bad IRQ registery..."); - } - iclr = sysio_imap_to_iclr(imap); + irqflags &= ~(SA_INTERRUPT); + + /* + * Check wether we _should_ use DMA Write Sync + * (for devices behind bridges behind APB). + * + * XXX: Not implemented, yet. + */ + if (bucket->flags & IBF_DMA_SYNC) + irqflags |= SA_DMA_SYNC; } - ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - ivindex += ivindex_fixup; } - action = *(cpu_irq + irq_action); + action = *(bucket->pil + irq_action); if(action) { if((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) for (tmp = action; tmp->next; tmp = tmp->next) @@ -586,7 +438,7 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) if((action->flags & SA_INTERRUPT) ^ (irqflags & SA_INTERRUPT)) { printk("Attempt to mix fast and slow interrupts on IRQ%d " - "denied\n", irq); + "denied\n", bucket->pil); return -EBUSY; } action = NULL; /* Or else! */ @@ -614,22 +466,11 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) } if (irqflags & SA_IMAP_MASKED) { - bucket = add_ino_hash(ivindex, imap, iclr, irqflags); - if(!bucket) { - kfree(action); - restore_flags(flags); - return -ENOMEM; - } - - pending = ((ivector_to_mask[ivindex] & 0x80000000) != 0); - ivector_to_mask[ivindex] = (1 << cpu_irq); + pending = ((ivector_to_mask[bucket->ino] & 0x80000000) != 0); + ivector_to_mask[bucket->ino] = (1 << bucket->pil); if(pending) - ivector_to_mask[ivindex] |= 0x80000000; - - if(dcookie) { - dcookie->ret_ino = ivindex; - dcookie->ret_pil = cpu_irq; - } + ivector_to_mask[bucket->ino] |= 0x80000000; + bucket->flags |= IBF_ACTIVE; } action->mask = (unsigned long) bucket; @@ -642,13 +483,13 @@ int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *) if(tmp) tmp->next = action; else - *(cpu_irq + irq_action) = action; + *(bucket->pil + irq_action) = action; - enable_irq(ivindex); + enable_irq(irq); /* We ate the IVEC already, this makes sure it does not get lost. */ if(pending) - set_softint(1 << cpu_irq); + set_softint(1 << bucket->pil); restore_flags(flags); #ifdef __SMP__ @@ -663,23 +504,16 @@ void free_irq(unsigned int irq, void *dev_id) struct irqaction *action; struct irqaction *tmp = NULL; unsigned long flags; - unsigned int *imap = NULL; - unsigned int cpu_irq; - int ivindex = -1; + struct ino_bucket *bucket = __bucket(irq), *bp; - if(irq == 0) { - cpu_irq = irq; - } else { -#ifdef CONFIG_PCI - if(PCI_IRQ_P(irq)) - cpu_irq = psycho_ino_to_pil[irq & PCI_IRQ_INO]; - else -#endif - cpu_irq = sysio_ino_to_pil[irq]; + if (irq < 0x400000 || (irq & 0x80000000)) { + prom_printf("free_irq with old style irq %08x\n", irq); + prom_halt(); } - action = *(cpu_irq + irq_action); + + action = *(bucket->pil + irq_action); if(!action->handler) { - printk("Freeing free IRQ %d\n", irq); + printk("Freeing free IRQ %d\n", bucket->pil); return; } if(dev_id) { @@ -689,17 +523,17 @@ void free_irq(unsigned int irq, void *dev_id) tmp = action; } if(!action) { - printk("Trying to free free shared IRQ %d\n", irq); + printk("Trying to free free shared IRQ %d\n", bucket->pil); return; } } else if(action->flags & SA_SHIRQ) { - printk("Trying to free shared IRQ %d with NULL device ID\n", irq); + printk("Trying to free shared IRQ %d with NULL device ID\n", bucket->pil); return; } if(action->flags & SA_STATIC_ALLOC) { printk("Attempt to free statically allocated IRQ %d (%s)\n", - irq, action->name); + bucket->pil, action->name); return; } @@ -707,43 +541,35 @@ void free_irq(unsigned int irq, void *dev_id) if(action && tmp) tmp->next = action->next; else - *(cpu_irq + irq_action) = action->next; + *(bucket->pil + irq_action) = action->next; if(action->flags & SA_IMAP_MASKED) { - struct ino_bucket *bucket = (struct ino_bucket *)action->mask; + unsigned int *imap = __imap(bucket); - imap = bucket->imap; - if(imap != NULL) { - ivindex = bucket->ino; - ivector_to_mask[ivindex] = 0; - } - else - printk("free_irq: WHeee, SYSIO_MASKED yet no imap reg.\n"); - } - - kfree(action); + /* + * Only free when no other shared irq uses this bucket. + */ + tmp = *(bucket->pil + irq_action); + for( ; tmp; tmp = tmp->next) + if ((struct ino_bucket *)tmp->mask == bucket) + goto out; - if(ivindex != -1) { - struct ino_bucket *bp; - int i, count = 0; + ivector_to_mask[bucket->ino] = 0; - /* The trick is that we can't turn the thing off when there - * are potentially other sub-irq level references. + bucket->flags &= ~IBF_ACTIVE; + for (bp = bucket_base; bp < endbuckets; bp++) + if (__imap(bp) == imap && (bp->flags & IBF_ACTIVE)) + break; + /* + * Only disable when no other sub-irq levels of + * the same imap are active. */ - if(imap != NULL) { - for(i = 0; i < INO_HASHSZ; i++) { - bp = ino_hash[i]; - while(bp) { - if(bp->imap == imap) - count++; - bp = bp->next; - } - } - } - if(count < 2) - disable_irq(ivindex); + if (bp == endbuckets) + disable_irq(irq); } +out: + kfree(action); restore_flags(flags); } @@ -979,7 +805,7 @@ void handler_irq(int irq, struct pt_regs *regs) if(!(ivector_to_mask[bucket->ino] & 0x80000000)) continue; } - act->handler(irq, act->dev_id, regs); + act->handler(__irq(bucket), act->dev_id, regs); } while((act = act->next) != NULL); act = action; do { @@ -1044,61 +870,23 @@ int request_fast_irq(unsigned int irq, unsigned long irqflags, const char *name, void *dev_id) { struct irqaction *action; - struct devid_cookie *dcookie = NULL; - struct ino_bucket *bucket = NULL; + struct ino_bucket *bucket = __bucket(irq); unsigned long flags; - unsigned int *imap, *iclr; - void *bus_id = NULL; - int ivindex = -1, ivindex_fixup, cpu_irq = -1; + if (irq < 0x400000 || (irq & 0x80000000)) { + prom_printf("request_irq with old style irq %08x %016lx\n", irq, handler); + prom_halt(); + } + if(!handler) return -EINVAL; - imap = iclr = NULL; - ivindex_fixup = 0; - - if ((irq == 0) || (irq == 14)) { + if ((bucket->pil == 0) || (bucket->pil == 14)) { printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n"); return -EBUSY; } -#ifdef CONFIG_PCI - if(PCI_IRQ_P(irq)) { - pci_irq_frobnicate(&cpu_irq, &ivindex_fixup, &imap, &iclr, irq); - } else -#endif - if(irqflags & SA_DCOOKIE) { - if(!dev_id) { - printk("request_fast_irq: SA_DCOOKIE but dev_id is NULL!\n"); - panic("Bogus irq registry."); - } - dcookie = dev_id; - dev_id = dcookie->real_dev_id; - cpu_irq = dcookie->pil; - imap = dcookie->imap; - iclr = dcookie->iclr; - bus_id = dcookie->bus_cookie; - get_irq_translations(&cpu_irq, &ivindex_fixup, &imap, - &iclr, bus_id, irqflags, irq); - } else { - /* XXX NOTE: This code is maintained for compatability until I can - * XXX verify that all drivers sparc64 will use are updated - * XXX to use the new IRQ registry dcookie interface. -DaveM - */ - cpu_irq = sysio_ino_to_pil[irq]; - imap = sysio_irq_to_imap(irq); - if(!imap) { - printk("request_irq: BAD, null imap for old style " - "irq registry IRQ[%x].\n", irq); - panic("Bad IRQ registery..."); - } - iclr = sysio_imap_to_iclr(imap); - } - - ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); - ivindex += ivindex_fixup; - - action = *(cpu_irq + irq_action); + action = *(bucket->pil + irq_action); if(action) { if(action->flags & SA_SHIRQ) panic("Trying to register fast irq when already shared.\n"); @@ -1113,7 +901,7 @@ int request_fast_irq(unsigned int irq, action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " - "using kmalloc\n", irq, name); + "using kmalloc\n", bucket->pil, name); } if(action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), @@ -1122,21 +910,9 @@ int request_fast_irq(unsigned int irq, restore_flags(flags); return -ENOMEM; } - install_fast_irq(cpu_irq, handler); - - bucket = add_ino_hash(ivindex, imap, iclr, irqflags); - if(!bucket) { - kfree(action); - restore_flags(flags); - return -ENOMEM; - } + install_fast_irq(bucket->pil, handler); - ivector_to_mask[ivindex] = (1 << cpu_irq); - - if(dcookie) { - dcookie->ret_ino = ivindex; - dcookie->ret_pil = cpu_irq; - } + ivector_to_mask[bucket->ino] = (1 << bucket->pil); action->mask = (unsigned long) bucket; action->handler = handler; @@ -1145,8 +921,8 @@ int request_fast_irq(unsigned int irq, action->name = name; action->next = NULL; - *(cpu_irq + irq_action) = action; - enable_irq(ivindex); + *(bucket->pil + irq_action) = action; + enable_irq(irq); restore_flags(flags); #ifdef __SMP__ @@ -1174,15 +950,21 @@ void init_timers(void (*cfunc)(int, void *, struct pt_regs *), unsigned long *clock) { unsigned long flags; - unsigned long timer_tick_offset; + extern unsigned long timer_tick_offset; int node, err; +#ifdef __SMP__ + extern void smp_tick_init(void); +#endif node = linux_cpus[0].prom_node; *clock = prom_getint(node, "clock-frequency"); timer_tick_offset = *clock / HZ; +#ifdef __SMP__ + smp_tick_init(); +#endif /* Register IRQ handler. */ - err = request_irq(0, cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), + err = request_irq(build_irq(0, 0, NULL, NULL), cfunc, (SA_INTERRUPT | SA_STATIC_ALLOC), "timer", NULL); if(err) { @@ -1236,7 +1018,7 @@ void distribute_irqs(void) while(p) { if(p->flags & SA_IMAP_MASKED) { struct ino_bucket *bucket = (struct ino_bucket *)p->mask; - unsigned int *imap = bucket->imap; + unsigned int *imap = __imap(bucket); unsigned int val; unsigned long tid = __cpu_logical_map[cpu] << 9; diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S new file mode 100644 index 000000000..34a542ac5 --- /dev/null +++ b/arch/sparc64/kernel/itlb_base.S @@ -0,0 +1,69 @@ +/* $Id: itlb_base.S,v 1.5 1998/06/15 16:59:32 jj Exp $ + * itlb_base.S: Front end to ITLB miss replacement strategy. + * This is included directly into the trap table. + * + * Copyright (C) 1996,1998 David S. Miller (davem@dm.cobaltmicro.com) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define TAG_CONTEXT_BITS 0x3ff +#define VPTE_SHIFT (PAGE_SHIFT - 3) + +/* Ways we can get here: + * + * 1) Nucleus instruction misses from module code. + * 2) All user instruction misses. + * + * All real page faults merge their code paths to the + * sparc64_realfault_* labels below. + */ + + .globl sparc64_vpte_patchme + +/* ITLB ** ICACHE line 1: Quick user TLB misses */ + ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS + srax %g4, VPTE_SHIFT, %g6 ! Create VPTE offset + ldxa [%g3 + %g6] ASI_P, %g5 ! Load VPTE +1: brgez,pn %g5, 3f ! Not valid, branch out + and %g5, (_PAGE_PRESENT|_PAGE_READ), %g4 ! Mask readable bits +2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB + retry ! Trap return +3: cmp %g4, (_PAGE_PRESENT|_PAGE_READ) ! Readable page? + +/* ITLB ** ICACHE line 2: Quick user ref updates */ + bne,pn %xcc, 4f ! Nope, real missing page + sllx %g1, 60, %g4 ! Sliiickkk... + or %g5, _PAGE_ACCESSED, %g5 ! Mark as touched + or %g5, %g4, %g5 ! Allow user to see it + ba,pt %xcc, 2b ! Branch to load TLB + stxa %g5, [%g3 + %g6] ASI_S ! Update PTE table +4: rdpr %pstate, %g4 ! Move into alternate globals + wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate + +/* ITLB ** ICACHE line 3: Real faults */ + rdpr %tpc, %g5 ! And load faulting VA +sparc64_realfault_common: ! Called by TL0 dtlb_miss too + sethi %hi(1f), %g7 ! Save state + ba,pt %xcc, etrap ! ... +1: or %g7, %lo(1b), %g7 ! ... + clr %o2 ! It was read +sparc64_realfault_continue: ! Called by dtlb_prot handler + srlx %l5, PAGE_SHIFT, %o1 ! Page align faulting VA + add %sp, STACK_BIAS + REGWIN_SZ, %o0! Compute pt_regs arg + call do_sparc64_fault ! Call fault handler + +/* ITLB ** ICACHE line 4: Call fault processing code */ + sllx %o1, PAGE_SHIFT, %o1 ! Finish page alignment + ba,a,pt %xcc, rtrap_clr_l6 ! Restore cpu state +winfix_trampoline: + rdpr %tpc, %g3 ! Prepare winfixup TNPC + or %g3, 0x7c, %g3 ! Compute offset to branch + wrpr %g3, %tnpc ! Write it into TNPC + done ! Do it to it +sparc64_vpte_nucleus: + ba,pt %xcc, sparc64_vpte_continue ! Part of dtlb_backend +sparc64_vpte_patchme: + sethi %hi(0), %g5 ! This has to be patched + +#undef TAG_CONTEXT_BITS +#undef VPTE_SHIFT diff --git a/arch/sparc64/kernel/itlb_miss.S b/arch/sparc64/kernel/itlb_miss.S deleted file mode 100644 index 94e3f44f6..000000000 --- a/arch/sparc64/kernel/itlb_miss.S +++ /dev/null @@ -1,49 +0,0 @@ -/* $Id: itlb_miss.S,v 1.12 1998/01/14 17:14:47 jj Exp $ - * itlb_miss.S: Instruction TLB miss code, this is included directly - * into the trap table. - * - * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - */ - -/* Gratuitous comment. */ - - /* ICACHE line 1 */ - /*0x00*/ ldxa [%g0] ASI_IMMU, %g1 ! Get TAG_TARGET - /*0x04*/ srlx %g1, 10, %g3 ! Position PGD offset - /*0x08*/ andcc %g1, %g2, %g0 ! Test CONTEXT bits - /*0x0c*/ and %g3, 0xffc, %g3 ! Mask PGD offset - /*0x10*/ and %g1, 0xffe, %g4 ! Mask PMD offset - /*0x14*/ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! For PTE offset - /*0x18*/ be,pn %xcc, 3f ! Context 0 == kernel - /*0x1c*/ add %g4, %g4, %g4 ! Position PMD offset - - /* ICACHE line 2 */ - /*0x20*/ lduwa [%g7 + %g3] ASI_PHYS_USE_EC, %g5 ! Load user PGD - /*0x24*/ srlx %g1, 1, %g1 ! PTE offset - /*0x28*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD - /*0x2c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x30*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set? - /*0x34*/ nop ! delay - /*0x38*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load - /*0x3c*/ retry ! Trap return - -3: /* ICACHE line 3 */ - /*0x40*/ lduwa [%g6 + %g3] ASI_PHYS_USE_EC, %g5 ! Load kern PGD - /*0x44*/ srlx %g1, 1, %g1 ! PTE offset - /*0x48*/ lduwa [%g5 + %g4] ASI_PHYS_USE_EC, %g3 ! Load PMD - /*0x4c*/ ldxa [%g3 + %g1] ASI_PHYS_USE_EC, %g5 ! Load PTE - /*0x50*/ brgez,pn %g5, sparc64_itlb_refbit_catch ! Valid set? - /*0x54*/ nop ! delay - /*0x58*/ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! TLB load - /*0x5c*/ retry ! Trap return - - /* ICACHE line 4 */ - /*0x60*/ nop - /*0x64*/ nop - /*0x68*/ nop - /*0x6c*/ nop - /*0x70*/ nop - /*0x74*/ nop - /*0x78*/ nop - /*0x7c*/ nop diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index c0058afd9..373d122c3 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -1,9 +1,9 @@ -/* $Id: process.c,v 1.52 1998/03/29 12:57:53 ecd Exp $ +/* $Id: process.c,v 1.70 1998/08/04 20:49:15 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ /* @@ -52,8 +52,8 @@ asmlinkage int sys_idle(void) return -EPERM; /* endless idle loop with no priority at all */ - current->priority = -100; - current->counter = -100; + current->priority = 0; + current->counter = 0; for (;;) { check_pgt_cache(); run_task_queue(&tq_scheduler); @@ -69,17 +69,13 @@ asmlinkage int sys_idle(void) */ asmlinkage int cpu_idle(void) { - current->priority = -100; + current->priority = 0; while(1) { check_pgt_cache(); - if(tq_scheduler) { - lock_kernel(); - run_task_queue(&tq_scheduler); - unlock_kernel(); - } + run_task_queue(&tq_scheduler); barrier(); - current->counter = -100; - if(need_resched) + current->counter = 0; + if(current->need_resched) schedule(); barrier(); } @@ -99,18 +95,18 @@ asmlinkage int sys_idle(void) extern char reboot_command []; #ifdef CONFIG_SUN_CONSOLE -extern void console_restore_palette (void); +extern void (*prom_palette)(int); extern int serial_console; #endif void machine_halt(void) { sti(); - udelay(8000); + mdelay(8); cli(); #ifdef CONFIG_SUN_CONSOLE - if (!serial_console) - console_restore_palette (); + if (!serial_console && prom_palette) + prom_palette (1); #endif prom_halt(); panic("Halt failed!"); @@ -121,14 +117,14 @@ void machine_restart(char * cmd) char *p; sti(); - udelay(8000); + mdelay(8); cli(); p = strchr (reboot_command, '\n'); if (p) *p = 0; #ifdef CONFIG_SUN_CONSOLE - if (!serial_console) - console_restore_palette (); + if (!serial_console && prom_palette) + prom_palette (1); #endif if (cmd) prom_reboot(cmd); @@ -272,7 +268,7 @@ void __show_regs(struct pt_regs * regs) smp_processor_id(), local_irq_count, atomic_read(&global_irq_count)); #endif - printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, + printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], @@ -295,22 +291,22 @@ void __show_regs(struct pt_regs * regs) #ifdef VERBOSE_SHOWREGS static void idump_from_user (unsigned int *pc) { - int i; - int code; - - if((((unsigned long) pc) & 3)) - return; - - pc -= 3; - for(i = -3; i < 6; i++) { - get_user(code, pc); - printk("%c%08x%c",i?' ':'<',code,i?' ':'>'); - pc++; - } - printk("\n"); + int i; + int code; + + if((((unsigned long) pc) & 3)) + return; + + pc -= 3; + for(i = -3; i < 6; i++) { + get_user(code, pc); + printk("%c%08x%c",i?' ':'<',code,i?' ':'>'); + pc++; + } + printk("\n"); } #endif - + void show_regs(struct pt_regs *regs) { #ifdef VERBOSE_SHOWREGS @@ -339,7 +335,7 @@ void show_regs(struct pt_regs *regs) void show_regs32(struct pt_regs32 *regs) { - printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, + printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", regs->u_regs[0], regs->u_regs[1], regs->u_regs[2], @@ -366,7 +362,6 @@ void show_thread(struct thread_struct *tss) 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("kpc: 0x%08x\n", tss->kpc); if (tss->w_saved) { for (i = 0; i < NSWINS; i++) { @@ -378,10 +373,6 @@ void show_thread(struct thread_struct *tss) printk("w_saved: 0x%04x\n", tss->w_saved); } - printk("sstk_info.stack: 0x%016lx\n", - (unsigned long)tss->sstk_info.the_stack); - printk("sstk_info.status: 0x%016lx\n", - (unsigned long)tss->sstk_info.cur_status); printk("flags: 0x%08x\n", tss->flags); printk("current_ds: 0x%016lx\n", tss->current_ds.seg); } @@ -400,13 +391,10 @@ void exit_thread(void) void flush_thread(void) { current->tss.w_saved = 0; - current->tss.sstk_info.cur_status = 0; - current->tss.sstk_info.the_stack = 0; /* No new signal delivery by default. */ current->tss.new_signal = 0; - current->tss.flags &= ~(SPARC_FLAG_USEDFPU | SPARC_FLAG_USEDFPUL | - SPARC_FLAG_USEDFPUU); + current->tss.fpsaved[0] = 0; /* Now, this task is no longer a kernel thread. */ current->tss.current_ds = USER_DS; @@ -422,7 +410,9 @@ void flush_thread(void) get_mmu_context(current); spin_unlock(&scheduler_lock); } - current->tss.ctx = current->mm->context & 0x1fff; + if (current->tss.flags & SPARC_FLAG_32BIT) + __asm__ __volatile__("stxa %%g0, [%0] %1" : : "r"(TSB_REG), "i"(ASI_DMMU)); + current->tss.ctx = current->mm->context & 0x3ff; spitfire_set_secondary_context (current->tss.ctx); __asm__ __volatile__("flush %g6"); } @@ -438,6 +428,13 @@ static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) __get_user(fp, &(((struct reg_window *)psp)->ins[6])); } else __get_user(fp, &(((struct reg_window32 *)psp)->ins[6])); + + /* Now 8-byte align the stack as this is mandatory in the + * Sparc ABI due to how register windows work. This hides + * the restriction from thread libraries etc. -DaveM + */ + csp &= ~7UL; + distance = fp - psp; rval = (csp - distance); if(copy_in_user(rval, psp, distance)) @@ -537,38 +534,21 @@ barf: * allocate the task_struct and kernel stack in * do_fork(). */ -#ifdef __SMP__ -extern void ret_from_smpfork(void); -#else -extern void ret_from_syscall(void); -#endif - int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, struct task_struct *p, struct pt_regs *regs) { - unsigned long stack_offset; char *child_trap_frame; - int tframe_size; /* Calculate offset to stack_frame & pt_regs */ - stack_offset = (((PAGE_SIZE << 1) - - ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) & - ~(64 - 1)) - (TRACEREG_SZ+REGWIN_SZ); - tframe_size = (TRACEREG_SZ + REGWIN_SZ) + - (sizeof(unsigned int) * 64) + (2 * sizeof(unsigned long)); - child_trap_frame = ((char *)p) + stack_offset; - memcpy(child_trap_frame, (((struct reg_window *)regs)-1), tframe_size); + 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; -#ifdef __SMP__ - p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_smpfork)) - 0x8; -#else - p->tss.kpc = ((unsigned int) ((unsigned long) ret_from_syscall)) - 0x8; -#endif 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; if(regs->tstate & TSTATE_PRIV) { p->tss.kregs->u_regs[UREG_FP] = p->tss.ksp; - p->tss.flags |= SPARC_FLAG_KTHREAD; + p->tss.flags |= (SPARC_FLAG_KTHREAD | SPARC_FLAG_NEWCHILD); p->tss.current_ds = KERNEL_DS; p->tss.ctx = 0; __asm__ __volatile__("flushw"); @@ -578,13 +558,14 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, p->tss.kregs->u_regs[UREG_G6] = (unsigned long) p; } else { if(current->tss.flags & SPARC_FLAG_32BIT) { - sp &= 0x00000000ffffffff; - regs->u_regs[UREG_FP] &= 0x00000000ffffffff; + sp &= 0x00000000ffffffffUL; + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; } p->tss.kregs->u_regs[UREG_FP] = sp; - p->tss.flags &= ~SPARC_FLAG_KTHREAD; + p->tss.flags = (p->tss.flags & ~SPARC_FLAG_KTHREAD) | + SPARC_FLAG_NEWCHILD; p->tss.current_ds = USER_DS; - p->tss.ctx = (p->mm->context & 0x1fff); + p->tss.ctx = (p->mm->context & 0x3ff); if (sp != regs->u_regs[UREG_FP]) { unsigned long csp; @@ -667,7 +648,8 @@ asmlinkage int sparc_execve(struct pt_regs *regs) putname(filename); if(!error) { fprs_write(0); - regs->fprs = 0; + current->tss.xfsr[0] = 0; + current->tss.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: diff --git a/arch/sparc64/kernel/psycho.c b/arch/sparc64/kernel/psycho.c index bec1e9fef..32d9b13c1 100644 --- a/arch/sparc64/kernel/psycho.c +++ b/arch/sparc64/kernel/psycho.c @@ -1,4 +1,4 @@ -/* $Id: psycho.c,v 1.50 1998/04/10 12:29:47 ecd Exp $ +/* $Id: psycho.c,v 1.63 1998/08/02 05:55:42 ecd Exp $ * psycho.c: Ultra/AX U2P PCI controller support. * * Copyright (C) 1997 David S. Miller (davem@caipfs.rutgers.edu) @@ -9,14 +9,19 @@ #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 @@ -24,8 +29,13 @@ #define dprintf printk #endif + unsigned long pci_dvma_offset = 0x00000000UL; -unsigned long pci_dvma_mask = 0xffffffffUL; +unsigned long pci_dvma_mask = 0xffffffffUL; + +unsigned long pci_dvma_v2p_hash[PCI_DVMA_HASHSZ]; +unsigned long pci_dvma_p2v_hash[PCI_DVMA_HASHSZ]; + #ifndef CONFIG_PCI @@ -94,19 +104,22 @@ static int pbm_write_config_dword(struct linux_pbm_info *pbm, */ static int pci_probe_enable = 0; -static inline unsigned long long_align(unsigned long addr) +static __inline__ void set_dvma_hash(unsigned long paddr, unsigned long daddr) { - return ((addr + (sizeof(unsigned long) - 1)) & - ~(sizeof(unsigned long) - 1)); + 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; } -__initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho, - int tsbsize, - unsigned long memory_start)) +__initfunc(static void psycho_iommu_init(struct linux_psycho *psycho, int tsbsize)) { - unsigned long tsbbase = PAGE_ALIGN(memory_start); - unsigned long control, i; + struct linux_mlist_p1275 *mlist; + unsigned long tsbbase; + unsigned long control, i, n; unsigned long *iopte; + unsigned long order; /* * Invalidate TLB Entries. @@ -120,15 +133,42 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho, control &= ~(IOMMU_CTRL_DENAB); psycho->psycho_regs->iommu_control = control; - memory_start = (tsbbase + ((tsbsize * 1024) * 8)); + for(order = 0;; order++) { + if((PAGE_SIZE << order) >= ((tsbsize * 1024) * 8)) + break; + } + tsbbase = __get_free_pages(GFP_DMA, order); iopte = (unsigned long *)tsbbase; - for(i = 0; i < (tsbsize * 1024); i++) { - *iopte = (IOPTE_VALID | IOPTE_64K | - IOPTE_CACHE | IOPTE_WRITE); - *iopte |= (i << 16); - iopte++; + memset(pci_dvma_v2p_hash, 0, sizeof(pci_dvma_v2p_hash)); + memset(pci_dvma_p2v_hash, 0, sizeof(pci_dvma_p2v_hash)); + + n = 0; + mlist = *prom_meminfo()->p1275_totphys; + while (mlist) { + unsigned long paddr = mlist->start_adr; + + for (i = 0; i < (mlist->num_bytes >> 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++; + } + + mlist = mlist->theres_more; } +out: + if (mlist) + printk("WARNING: not all physical memory mapped in IOMMU\n"); psycho->psycho_regs->iommu_tsbbase = __pa(tsbbase); @@ -137,15 +177,15 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho, control |= (IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); switch(tsbsize) { case 8: - pci_dvma_mask = 0x1fffffffUL; + pci_dvma_mask = 0x1fffffffUL; control |= IOMMU_TSBSZ_8K; break; case 16: - pci_dvma_mask = 0x3fffffffUL; + pci_dvma_mask = 0x3fffffffUL; control |= IOMMU_TSBSZ_16K; break; case 32: - pci_dvma_mask = 0x7fffffffUL; + pci_dvma_mask = 0x7fffffffUL; control |= IOMMU_TSBSZ_32K; break; default: @@ -154,8 +194,6 @@ __initfunc(static unsigned long psycho_iommu_init(struct linux_psycho *psycho, break; } psycho->psycho_regs->iommu_control = control; - - return memory_start; } extern void prom_pbm_ranges_init(int node, struct linux_pbm_info *pbm); @@ -164,7 +202,7 @@ extern void prom_pbm_intmap_init(int node, struct linux_pbm_info *pbm); /* * Poor man's PCI... */ -__initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start)) +__initfunc(void sabre_init(int pnode)) { struct linux_prom64_registers pr_regs[2]; struct linux_psycho *sabre; @@ -175,8 +213,7 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start)) u32 portid; int bus; - sabre = (struct linux_psycho *)memory_start; - memory_start = long_align(memory_start + sizeof(struct linux_psycho)); + sabre = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); portid = prom_getintdefault(pnode, "upa-portid", 0xff); @@ -262,8 +299,8 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start)) prom_halt(); } - memory_start = psycho_iommu_init(sabre, tsbsize, memory_start); pci_dvma_offset = vdma[0]; + psycho_iommu_init(sabre, tsbsize); printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); #ifdef PROM_DEBUG @@ -338,11 +375,15 @@ __initfunc(unsigned long sabre_init(int pnode, unsigned long memory_start)) if (!node) break; } +} - return memory_start; +static __inline__ int +apb_present(struct linux_psycho *psycho) +{ + return psycho->pci_bus ? 1 : 0; } -__initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long memory_end)) +__initfunc(void pcibios_init(void)) { struct linux_prom64_registers pr_regs[3]; struct linux_psycho *psycho; @@ -355,7 +396,6 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long dprintf("PCI: Probing for controllers.\n"); #endif - memory_start = long_align(memory_start); node = prom_getchild(prom_root_node); while((node = prom_searchsiblings(node, "pci")) != 0) { struct linux_psycho *search; @@ -365,11 +405,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); if ((err > 0) && !strncmp(namebuf, "SUNW,sabre", err)) { - memory_start = sabre_init(node, memory_start); + sabre_init(node); goto next_pci; } - psycho = (struct linux_psycho *)memory_start; + psycho = kmalloc(sizeof(struct linux_psycho), GFP_ATOMIC); portid = prom_getintdefault(node, "upa-portid", 0xff); for(search = psycho_root; search; search = search->next) { @@ -385,9 +425,6 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long } } - memory_start = long_align(memory_start + - sizeof(struct linux_psycho)); - memset(psycho, 0, sizeof(*psycho)); psycho->next = psycho_root; @@ -452,8 +489,8 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long psycho->pci_config_space); #endif - memory_start = psycho_iommu_init(psycho, 32, memory_start); pci_dvma_offset = 0x80000000UL; + psycho_iommu_init(psycho, 32); is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); @@ -504,14 +541,11 @@ __initfunc(unsigned long pcibios_init(unsigned long memory_start, unsigned long prom_halt(); } - psycho_index_map = (struct linux_psycho **)long_align(memory_start); - memory_start = long_align(memory_start + linux_num_psycho - * sizeof(struct linux_psycho *)); + psycho_index_map = kmalloc(sizeof(struct linux_psycho *) * linux_num_psycho, + GFP_ATOMIC); for (psycho = psycho_root; psycho; psycho = psycho->next) psycho_index_map[psycho->index] = psycho; - - return memory_start; } int pcibios_present(void) @@ -577,40 +611,14 @@ static inline void pci_add_vma(struct linux_pbm_info *pbm, struct pci_vma *new, } } -static unsigned long *pci_alloc_arena = NULL; - -static inline void pci_init_alloc_init(unsigned long *mstart) -{ - pci_alloc_arena = mstart; -} - -static inline void pci_init_alloc_fini(void) -{ - pci_alloc_arena = NULL; -} - -__initfunc(static void *pci_init_alloc(int size)) -{ - unsigned long start = long_align(*pci_alloc_arena); - void *mp = (void *)start; - - if(!pci_alloc_arena) { - prom_printf("pci_init_alloc: pci_vma arena not init'd\n"); - prom_halt(); - } - start += size; - *pci_alloc_arena = start; - return mp; -} - static inline struct pci_vma *pci_vma_alloc(void) { - return pci_init_alloc(sizeof(struct pci_vma)); + return kmalloc(sizeof(struct pci_vma), GFP_ATOMIC); } static inline struct pcidev_cookie *pci_devcookie_alloc(void) { - return pci_init_alloc(sizeof(struct pcidev_cookie)); + return kmalloc(sizeof(struct pcidev_cookie), GFP_ATOMIC); } @@ -694,6 +702,14 @@ __initfunc(static void apb_init(struct linux_psycho *sabre)) unsigned short stmp; unsigned int itmp; + for(pdev = pci_devices; pdev; pdev = pdev->next) { + if(pdev->vendor == PCI_VENDOR_ID_SUN && + pdev->device == PCI_DEVICE_ID_SUN_SABRE) { + /* Increase latency timer on top level bridge. */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8); + break; + } + } for (pdev = sabre->pci_bus->devices; pdev; pdev = pdev->sibling) { if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { @@ -732,12 +748,14 @@ __initfunc(static void apb_init(struct linux_psycho *sabre)) pci_write_config_byte(pdev, APB_PIO_TARGET_LATENCY_TIMER, 0); pci_write_config_byte(pdev, APB_DMA_TARGET_RETRY_LIMIT, 0x80); pci_write_config_byte(pdev, APB_DMA_TARGET_LATENCY_TIMER, 0); + + /* Increase primary latency timer. */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8); } } } -__initfunc(static void sabre_probe(struct linux_psycho *sabre, - unsigned long *mstart)) +__initfunc(static void sabre_probe(struct linux_psycho *sabre)) { struct pci_bus *pbus = sabre->pci_bus; static unsigned char busno = 0; @@ -745,7 +763,7 @@ __initfunc(static void sabre_probe(struct linux_psycho *sabre, pbus->number = pbus->secondary = busno; pbus->sysdata = sabre; - pbus->subordinate = pci_scan_bus(pbus, mstart); + pbus->subordinate = pci_scan_bus(pbus); busno = pbus->subordinate + 1; for(pbus = pbus->children; pbus; pbus = pbus->next) { @@ -759,8 +777,7 @@ __initfunc(static void sabre_probe(struct linux_psycho *sabre, } -__initfunc(static void pbm_probe(struct linux_pbm_info *pbm, - unsigned long *mstart)) +__initfunc(static void pbm_probe(struct linux_pbm_info *pbm)) { static struct pci_bus *pchain = NULL; struct pci_bus *pbus = &pbm->pci_bus; @@ -777,7 +794,7 @@ __initfunc(static void pbm_probe(struct linux_pbm_info *pbm, pbm_fixup_busno(pbm, busno); - pbus->subordinate = pci_scan_bus(pbus, mstart); + pbus->subordinate = pci_scan_bus(pbus); /* * Set the maximum subordinate bus of this pbm. @@ -801,22 +818,15 @@ __initfunc(static void pbm_probe(struct linux_pbm_info *pbm, __initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, struct pci_dev *pdev, - int node)) + int pnode)) { struct linux_prom_pci_registers pregs[PROMREG_MAX]; + int node; int err; - while(node) { - int child; - - child = prom_getchild(node); - if(child != 0 && child != -1) { - int res; + node = prom_getchild(pnode); + while (node) { - res = pdev_to_pnode_sibtraverse(pbm, pdev, child); - if(res != 0 && res != -1) - return res; - } err = prom_getproperty(node, "reg", (char *)&pregs[0], sizeof(pregs)); if(err != 0 && err != -1) { u32 devfn = (pregs[0].phys_hi >> 8) & 0xff; @@ -830,32 +840,45 @@ __initfunc(static int pdev_to_pnode_sibtraverse(struct linux_pbm_info *pbm, return 0; } -__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, struct pci_dev *pdev)) +__initfunc(static void pdev_cookie_fillin(struct linux_pbm_info *pbm, + struct pci_dev *pdev, int pnode)) { struct pcidev_cookie *pcp; - int node = prom_getchild(pbm->prom_node); + int node; - node = pdev_to_pnode_sibtraverse(pbm, pdev, 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 } __initfunc(static void fill_in_pbm_cookies(struct pci_bus *pbus, - struct linux_pbm_info *pbm)) + 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); + pdev_cookie_fillin(pbm, pdev, node); - for(pbus = pbus->children; pbus; pbus = pbus->next) - fill_in_pbm_cookies(pbus, pbm); + for(pbus = pbus->children; pbus; pbus = pbus->next) { + struct pcidev_cookie *pcp = pbus->self->sysdata; + fill_in_pbm_cookies(pbus, pbm, pcp->prom_node); + } } __initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre)) @@ -864,9 +887,11 @@ __initfunc(static void sabre_cookie_fillin(struct linux_psycho *sabre)) 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); + 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); + pdev_cookie_fillin(&sabre->pbm_B, pbus->self, + sabre->pbm_B.prom_node); } } @@ -973,7 +998,7 @@ static inline void record_assignments(struct linux_pbm_info *pbm) { struct pci_vma *vp; - if (pbm->parent->pci_bus) { + if (apb_present(pbm->parent)) { /* * Disallow anything that is not in our IO/MEM map on SIMBA. */ @@ -984,12 +1009,8 @@ static inline void record_assignments(struct linux_pbm_info *pbm) for (pdev = pbus->devices; pdev; pdev = pdev->sibling) { struct pcidev_cookie *pcp = pdev->sysdata; - if (!pcp) { - prom_printf("record_assignments: " - "no pcidev_cookie for pdev %02x\n", - pdev->devfn); - prom_halt(); - } + if (!pcp) + continue; if (pcp->pbm == pbm) break; } @@ -1448,12 +1469,14 @@ __initfunc(static unsigned long psycho_pcislot_imap_offset(unsigned long ino)) } /* Exported for EBUS probing layer. */ -__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned int full_ino)) +__initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, + struct pci_dev *pdev, + unsigned int ino)) { - unsigned long imap_off, ign, ino; + unsigned long imap_off; + int need_dma_sync = 0; - ign = (full_ino & PSYCHO_IMAP_IGN) >> 6; - ino = (full_ino & PSYCHO_IMAP_INO); + 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 @@ -1529,10 +1552,7 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned in break; default: - /* We don't expect anything else. The other possible - * values are not found in PCI device nodes, and are - * so hardware specific that they should use DCOOKIE's - * anyways. + /* We don't expect anything else. */ prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); prom_halt(); @@ -1540,7 +1560,11 @@ __initfunc(unsigned int psycho_irq_build(struct linux_pbm_info *pbm, unsigned in } imap_off -= imap_offset(imap_a_slot0); - return pci_irq_encode(imap_off, pbm->parent->index, ign, ino); + 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); } __initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm, @@ -1571,6 +1595,9 @@ __initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm, if(i == 0 || i == -1) goto out; + /* Use low slot number bits of child as IRQ line. */ + *interrupt = ((pdev->devfn >> 3) & 3) + 1; + preg = &ppreg; } @@ -1578,20 +1605,29 @@ __initfunc(static int pbm_intmap_match(struct linux_pbm_info *pbm, 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 *interrupt; + return 1; } } out: - prom_printf("pbm_intmap_match: IRQ [%08x.%08x.%08x.%08x] " - "not found in interrupt-map\n", preg->phys_hi, - preg->phys_mid, preg->phys_lo, *interrupt); + 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(); } @@ -1618,23 +1654,23 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, /* See if we find a matching interrupt-map entry. */ if (pbm_intmap_match(pbm, pdev, preg, &prom_irq)) { - pdev->irq = psycho_irq_build(pbm, + 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); + dprintf("interrupt-map specified: prom_irq[%x] pdev->irq[%x]", + prom_irq, pdev->irq); #endif /* See if fully specified already (ie. for onboard devices like hme) */ } else if(((prom_irq & PSYCHO_IMAP_IGN) >> 6) == pbm->parent->upa_portid) { - pdev->irq = psycho_irq_build(pbm, prom_irq); + 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->irq = psycho_irq_build(pbm, pdev, (pbm->parent->upa_portid << 6) | prom_irq); #ifdef FIXUP_IRQ_DEBUG @@ -1669,7 +1705,7 @@ __initfunc(static void fixup_irq(struct pci_dev *pdev, } slot = (slot << 2); - pdev->irq = psycho_irq_build(pbm, + pdev->irq = psycho_irq_build(pbm, pdev, (((portid << 6) & PSYCHO_IMAP_IGN) | (bus | slot | line))); @@ -1818,7 +1854,7 @@ __initfunc(static void psycho_final_fixup(struct linux_psycho *psycho)) fixup_addr_irq(&psycho->pbm_B); } -__initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long memory_end)) +__initfunc(void pcibios_fixup(void)) { struct linux_psycho *psycho; @@ -1838,32 +1874,32 @@ __initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long for (psycho = psycho_root; psycho; psycho = psycho->next) { /* Probe bus on builtin PCI. */ - if (psycho->pci_bus) - sabre_probe(psycho, &memory_start); + if (apb_present(psycho)) + sabre_probe(psycho); else { /* Probe busses under PBM B. */ - pbm_probe(&psycho->pbm_B, &memory_start); + pbm_probe(&psycho->pbm_B); /* Probe busses under PBM A. */ - pbm_probe(&psycho->pbm_A, &memory_start); + pbm_probe(&psycho->pbm_A); } } - pci_init_alloc_init(&memory_start); - /* Walk all PCI devices found. For each device, and * PCI bridge which is not one of the PSYCHO PBM's, fill in the * sysdata with a pointer to the PBM (for pci_bus's) or * a pci_dev cookie (PBM+PROM_NODE, for pci_dev's). */ for (psycho = psycho_root; psycho; psycho = psycho->next) { - if (psycho->pci_bus) + if (apb_present(psycho)) sabre_cookie_fillin(psycho); fill_in_pbm_cookies(&psycho->pbm_A.pci_bus, - &psycho->pbm_A); + &psycho->pbm_A, + psycho->pbm_A.prom_node); fill_in_pbm_cookies(&psycho->pbm_B.pci_bus, - &psycho->pbm_B); + &psycho->pbm_B, + psycho->pbm_B.prom_node); /* See what OBP has taken care of already. */ record_assignments(&psycho->pbm_A); @@ -1873,9 +1909,7 @@ __initfunc(unsigned long pcibios_fixup(unsigned long memory_start, unsigned long psycho_final_fixup(psycho); } - pci_init_alloc_fini(); - - return ebus_init(memory_start, memory_end); + return ebus_init(); } /* "PCI: The emerging standard..." 8-( */ @@ -2257,7 +2291,7 @@ int pcibios_read_config_byte (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2267,7 +2301,7 @@ int pcibios_read_config_word (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2277,7 +2311,7 @@ int pcibios_read_config_dword (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2287,7 +2321,7 @@ int pcibios_write_config_byte (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2297,7 +2331,7 @@ int pcibios_write_config_word (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2307,7 +2341,7 @@ int pcibios_write_config_dword (unsigned char bus, unsigned char devfn, { struct linux_pbm_info *pbm = bus2pbm[bus]; - if (pbm && pbm->parent && pbm->parent->pci_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); } @@ -2397,6 +2431,10 @@ asmlinkage int sys_pciconfig_write(unsigned long bus, return err; } +__initfunc(void pcibios_fixup_bus(struct pci_bus *bus)) +{ +} + __initfunc(char *pcibios_setup(char *str)) { return str; diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 5d3c6f46a..07ee212a3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -19,10 +19,12 @@ #include <linux/smp.h> #include <linux/smp_lock.h> +#include <asm/asi.h> #include <asm/pgtable.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/psrcompat.h> +#include <asm/visasm.h> #define MAGIC_CONSTANT 0x80000000 @@ -72,6 +74,41 @@ repeat: return pgtable; } +/* We must bypass the L1-cache to avoid alias issues. -DaveM */ +static __inline__ unsigned long read_user_long(unsigned long kvaddr) +{ + unsigned long ret; + + __asm__ __volatile__("ldxa [%1] %2, %0" + : "=r" (ret) + : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); + return ret; +} + +static __inline__ unsigned int read_user_int(unsigned long kvaddr) +{ + unsigned int ret; + + __asm__ __volatile__("lduwa [%1] %2, %0" + : "=r" (ret) + : "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); + return ret; +} + +static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val) +{ + __asm__ __volatile__("stxa %0, [%1] %2" + : /* no outputs */ + : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); +} + +static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val) +{ + __asm__ __volatile__("stwa %0, [%1] %2" + : /* no outputs */ + : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC)); +} + static inline unsigned long get_long(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long addr) { @@ -84,7 +121,7 @@ static inline unsigned long get_long(struct task_struct * tsk, if (MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; - retval = *(unsigned long *) page; + retval = read_user_long(page); flush_page_to_ram(page); return retval; } @@ -103,14 +140,12 @@ static inline void put_long(struct task_struct * tsk, struct vm_area_struct * vm unsigned long pgaddr; pgaddr = page + (addr & ~PAGE_MASK); - *(unsigned long *) (pgaddr) = data; + write_user_long(pgaddr, data); __asm__ __volatile__(" membar #StoreStore flush %0 " : : "r" (pgaddr & ~7) : "memory"); - - flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ /* this should also re-instate whatever read-only mode there was before */ @@ -131,7 +166,7 @@ static inline unsigned int get_int(struct task_struct * tsk, if (MAP_NR(page) >= max_mapnr) return 0; page += addr & ~PAGE_MASK; - retval = *(unsigned int *) page; + retval = read_user_int(page); flush_page_to_ram(page); return retval; } @@ -150,14 +185,12 @@ static inline void put_int(struct task_struct * tsk, struct vm_area_struct * vma unsigned long pgaddr; pgaddr = page + (addr & ~PAGE_MASK); - *(unsigned int *) (pgaddr) = data; + write_user_int(pgaddr, data); __asm__ __volatile__(" membar #StoreStore flush %0 " : : "r" (pgaddr & ~7) : "memory"); - - flush_page_to_ram(page); } /* we're bypassing pagetables, so we have to set the dirty bit ourselves */ /* this should also re-instate whatever read-only mode there was before */ @@ -323,9 +356,11 @@ static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, case 0: v = t->ksp; break; +#if 0 case 4: v = t->kpc; break; +#endif case 8: v = t->kpsr; break; @@ -800,11 +835,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int insn; } fpq[16]; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_to_user(&fps->regs[0], fpregs, (32 * sizeof(unsigned int))) || - __put_user(((unsigned int)fpregs[32]), (&fps->fsr)) || + __put_user(child->tss.xfsr[0], (&fps->fsr)) || __put_user(0, (&fps->fpqd)) || __put_user(0, (&fps->flags)) || __put_user(0, (&fps->extra)) || @@ -821,11 +856,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int regs[64]; unsigned long fsr; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_to_user(&fps->regs[0], fpregs, (64 * sizeof(unsigned int))) || - __put_user(fpregs[32], (&fps->fsr))) { + __put_user(child->tss.xfsr[0], (&fps->fsr))) { pt_error_return(regs, EFAULT); goto out; } @@ -845,7 +880,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int insn; } fpq[16]; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); unsigned fsr; if (copy_from_user(fpregs, &fps->regs[0], @@ -854,8 +889,11 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EFAULT); goto out; } - fpregs[32] &= 0xffffffff00000000UL; - fpregs[32] |= fsr; + 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); pt_succ_return(regs, 0); goto out; } @@ -865,14 +903,17 @@ asmlinkage void do_ptrace(struct pt_regs *regs) unsigned int regs[64]; unsigned long fsr; } *fps = (struct fps *) addr; - unsigned long *fpregs = (unsigned long *)(child->tss.kregs+1); + unsigned long *fpregs = (unsigned long *)(((char *)child) + AOFF_task_fpregs); if (copy_from_user(fpregs, &fps->regs[0], (64 * sizeof(unsigned int))) || - __get_user(fpregs[32], (&fps->fsr))) { + __get_user(child->tss.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); pt_succ_return(regs, 0); goto out; } @@ -890,7 +931,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) vma = find_extend_vma(child, src); if (!vma) { pt_error_return(regs, EIO); - goto out; + goto flush_and_out; } pgtable = get_page (child, vma, src, 0); if (src & ~PAGE_MASK) { @@ -904,13 +945,13 @@ asmlinkage void do_ptrace(struct pt_regs *regs) if (copy_to_user (dest, ((char *)page) + (src & ~PAGE_MASK), curlen)) { flush_page_to_ram(page); pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } flush_page_to_ram(page); } else { if (clear_user (dest, curlen)) { pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } } src += curlen; @@ -918,7 +959,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) len -= curlen; } pt_succ_return(regs, 0); - goto out; + goto flush_and_out; } case PTRACE_WRITETEXT: @@ -934,7 +975,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) vma = find_extend_vma(child, dest); if (!vma) { pt_error_return(regs, EIO); - goto out; + goto flush_and_out; } pgtable = get_page (child, vma, dest, 1); if (dest & ~PAGE_MASK) { @@ -951,7 +992,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); flush_tlb_page(vma, dest); pt_error_return(regs, EFAULT); - goto out; + goto flush_and_out; } flush_page_to_ram(page); set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); @@ -962,7 +1003,7 @@ asmlinkage void do_ptrace(struct pt_regs *regs) len -= curlen; } pt_succ_return(regs, 0); - goto out; + goto flush_and_out; } case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ @@ -1041,6 +1082,12 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EIO); goto out; } +flush_and_out: + { + unsigned long va; + for(va = 0; va < (PAGE_SIZE << 1); va += 32) + spitfire_put_dcache_tag(va, 0x0); + } out: unlock_kernel(); } diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index 685182473..85732960f 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -1,7 +1,7 @@ -/* $Id: rtrap.S,v 1.37 1997/12/11 15:14:54 jj Exp $ +/* $Id: rtrap.S,v 1.39 1998/07/26 03:02:49 davem Exp $ * rtrap.S: Preparing for return from trap on Sparc V9. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ @@ -10,13 +10,15 @@ #include <asm/ptrace.h> #include <asm/spitfire.h> #include <asm/head.h> +#include <asm/visasm.h> + +#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) .text .align 32 .globl rtrap_clr_l6, rtrap -#define PTREGS_OFF (STACK_BIAS + REGWIN_SZ) -rtrap_clr_l6: ba,pt %xcc, rtrap - clr %l6 +rtrap_clr_l6: clr %l6 + /* Fall through */ rtrap: sethi %hi(bh_active), %l2 sethi %hi(bh_mask), %l1 ldx [%l2 + %lo(bh_active)], %l4 @@ -37,24 +39,37 @@ rtrap: sethi %hi(bh_active), %l2 be,pt %icc, to_user andn %l7, PSTATE_IE, %l7 - ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 + ldub [%g6 + AOFF_task_tss + AOFF_thread_fpdepth], %l5 + brz,pt %l5, rt_continue + srl %l5, 1, %o0 + add %g6, AOFF_task_tss + AOFF_thread_fpsaved, %l6 + ldub [%l6 + %o0], %l2 + sub %l5, 2, %l5 + add %g6, AOFF_task_tss + AOFF_thread_gsr, %o1 andcc %l2, FPRS_FEF, %g0 - be,pt %icc, rt_continue + be,pt %icc, 2f and %l2, FPRS_DL, %l6 - wr %g0, FPRS_FEF, %fprs - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %g5 + rd %fprs, %g5 + wr %g5, FPRS_FEF, %fprs + ldub [%o1 + %o0], %g5 + sll %o0, 3, %o5 + add %g6, AOFF_task_tss + AOFF_thread_xfsr, %o1 membar #StoreLoad | #LoadLoad + sll %o0, 8, %o2 + add %g6, AOFF_task_fpregs, %o3 brz,pn %l6, 1f - wr %g0, ASI_BLK_P, %asi - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 + add %g6, AOFF_task_fpregs+0x40, %o4 + ldda [%o3 + %o2] ASI_BLK_P, %f0 + ldda [%o4 + %o2] ASI_BLK_P, %f16 1: andcc %l2, FPRS_DU, %g0 be,pn %icc, 1f wr %g5, 0, %gsr - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 + add %o2, 0x80, %o2 + ldda [%o3 + %o2] ASI_BLK_P, %f32 + ldda [%o4 + %o2] ASI_BLK_P, %f48 1: membar #Sync - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr + 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 ldx [%sp + PTREGS_OFF + PT_V9_G2], %g2 @@ -86,11 +101,10 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 wrpr %l1, %g0, %tstate wrpr %l2, %g0, %tpc wrpr %o2, %g0, %tnpc - mov PRIMARY_CONTEXT, %l7 brnz,pn %l3, kern_rtt - mov SECONDARY_CONTEXT, %o4 + mov PRIMARY_CONTEXT, %l7 stxa %l0, [%l7] ASI_DMMU - stxa %l0, [%o4] ASI_DMMU + stxa %l0, [%l7 + %l7] ASI_DMMU flush %o5 rdpr %wstate, %l1 @@ -106,8 +120,7 @@ rt_continue: lduh [%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0 retry kern_rtt: restore retry -to_user: sethi %hi(need_resched), %l0 - ldx [%l0 + %lo(need_resched)], %l0 +to_user: ldx [%g6 + AOFF_task_need_resched], %l0 wrpr %l7, PSTATE_IE, %pstate orcc %g0, %l0, %g0 be,a,pt %xcc, check_signal @@ -116,8 +129,7 @@ to_user: sethi %hi(need_resched), %l0 call schedule nop lduw [%g6 + AOFF_task_sigpending], %l0 -check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 - brz,a,pt %l0, check_user_wins +check_signal: brz,a,pt %l0, check_user_wins lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %o0 mov %l5, %o2 @@ -127,112 +139,20 @@ check_signal: ld [%sp + PTREGS_OFF + PT_V9_FPRS], %l2 lduh [%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2 clr %l6 check_user_wins:brz,pt %o2, 1f - sethi %hi(TSTATE_PEF), %o3 + sethi %hi(TSTATE_PEF), %l6 call fault_in_user_windows add %sp, STACK_BIAS + REGWIN_SZ, %o0 - sethi %hi(TSTATE_PEF), %o3 -1: andcc %l2, FPRS_FEF, %g0 - be,a,pt %icc, rt_continue - andn %l1, %o3, %l1 ! If fprs.FEF is not set, disable tstate.PEF - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x108], %o3 - lduh [%g6 + AOFF_task_tss + AOFF_thread_flags], %l2 - wr %g0, FPRS_FEF, %fprs - wr %o3, 0, %gsr - andcc %l2, SPARC_FLAG_USEDFPUL, %g0 - bne,pn %icc, 2f - andcc %l2, SPARC_FLAG_USEDFPUU, %g0 - fzero %f0 - bne,pn %icc, 1f - fzero %f2 - faddd %f0, %f2, %f4 - fmuld %f0, %f2, %f6 - faddd %f0, %f2, %f8 - fmuld %f0, %f2, %f10 - faddd %f0, %f2, %f12 - fmuld %f0, %f2, %f14 - faddd %f0, %f2, %f16 - fmuld %f0, %f2, %f18 - faddd %f0, %f2, %f20 - fmuld %f0, %f2, %f22 - faddd %f0, %f2, %f24 - fmuld %f0, %f2, %f26 - faddd %f0, %f2, %f28 - fmuld %f0, %f2, %f30 - faddd %f0, %f2, %f32 - fmuld %f0, %f2, %f34 - faddd %f0, %f2, %f36 - fmuld %f0, %f2, %f38 - faddd %f0, %f2, %f40 - fmuld %f0, %f2, %f42 - faddd %f0, %f2, %f44 - fmuld %f0, %f2, %f46 - faddd %f0, %f2, %f48 - fmuld %f0, %f2, %f50 - faddd %f0, %f2, %f52 - fmuld %f0, %f2, %f54 - faddd %f0, %f2, %f56 - fmuld %f0, %f2, %f58 - faddd %f0, %f2, %f60 - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr - ba,pt %xcc, rt_continue - wr %g0, FPRS_FEF, %fprs -1: wr %g0, ASI_BLK_P, %asi - membar #StoreLoad | #LoadLoad - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 - faddd %f0, %f2, %f4 - fmuld %f0, %f2, %f6 - faddd %f0, %f2, %f8 - fmuld %f0, %f2, %f10 - faddd %f0, %f2, %f12 - fmuld %f0, %f2, %f14 - faddd %f0, %f2, %f16 - fmuld %f0, %f2, %f18 - faddd %f0, %f2, %f20 - fmuld %f0, %f2, %f22 - faddd %f0, %f2, %f24 - fmuld %f0, %f2, %f26 - faddd %f0, %f2, %f28 - fmuld %f0, %f2, %f30 - membar #Sync - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr - ba,pt %xcc, rt_continue - wr %g0, FPRS_FEF, %fprs -2: membar #StoreLoad | #LoadLoad - andcc %l2, SPARC_FLAG_USEDFPUU, %g0 - bne,pt %icc, 3f - wr %g0, ASI_BLK_P, %asi - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 - fzero %f32 - fzero %f34 - faddd %f32, %f34, %f36 - fmuld %f32, %f34, %f38 - faddd %f32, %f34, %f40 - fmuld %f32, %f34, %f42 - faddd %f32, %f34, %f44 - fmuld %f32, %f34, %f46 - faddd %f32, %f34, %f48 - fmuld %f32, %f34, %f50 - faddd %f32, %f34, %f52 - fmuld %f32, %f34, %f54 - faddd %f32, %f34, %f56 - fmuld %f32, %f34, %f58 - faddd %f32, %f34, %f60 - fmuld %f32, %f34, %f62 - membar #Sync - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr - ba,pt %xcc, rt_continue - wr %g0, FPRS_FEF, %fprs -3: ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x000] %asi, %f0 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x040] %asi, %f16 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x080] %asi, %f32 - ldda [%sp + PTREGS_OFF + TRACEREG_SZ + 0x0c0] %asi, %f48 - membar #Sync - ldx [%sp + PTREGS_OFF + TRACEREG_SZ + 0x100], %fsr - ba,pt %xcc, rt_continue - wr %g0, FPRS_FEF, %fprs +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 + + 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 #undef PTREGS_OFF diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index cdc8f47de..de0124f52 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.20 1998/02/24 17:02:39 jj Exp $ +/* $Id: setup.c,v 1.30 1998/07/24 09:50:08 jj Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -26,6 +26,7 @@ #include <linux/blk.h> #include <linux/init.h> #include <linux/inet.h> +#include <linux/console.h> #include <asm/segment.h> #include <asm/system.h> @@ -41,13 +42,15 @@ #include <net/ipconfig.h> #endif +#undef PROM_DEBUG_CONSOLE + struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ - { 0, 0, }, /* unused */ + 0, /* unused */ 0, /* orig-video-page */ 0, /* orig-video-mode */ 128, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ + 0, 0, 0, /* unused, ega_bx, unused */ 54, /* orig-video-lines */ 0, /* orig-video-isVGA */ 16 /* orig-video-points */ @@ -63,7 +66,7 @@ unsigned int phys_bytes_of_ram, end_of_phys_memory; extern unsigned long sparc64_ttable_tl0; #if CONFIG_SUN_CONSOLE -extern void console_restore_palette(void); +void (*prom_palette)(int); #endif asmlinkage void sys_sync(void); /* it's really int */ @@ -77,7 +80,8 @@ void prom_sync_me(long *args) __asm__ __volatile__("wrpr %0, 0x0, %%tba\n\t" : : "r" (&sparc64_ttable_tl0)); #ifdef CONFIG_SUN_CONSOLE - console_restore_palette (); + if (prom_palette) + prom_palette (1); #endif prom_printf("PROM SYNC COMMAND...\n"); show_free_areas(); @@ -102,8 +106,7 @@ unsigned int boot_flags = 0; #define BOOTME_KGDB 0x4 #ifdef CONFIG_SUN_CONSOLE -extern char *console_fb_path; -static int console_fb = 0; +static int console_fb __initdata = 0; #endif static unsigned long memory_size = 0; @@ -189,9 +192,17 @@ __initfunc(static void boot_flags_init(char *commands)) } else if (!strncmp (commands, "ttyb", 4)) { console_fb = 3; prom_printf ("Using /dev/ttyb as console.\n"); +#if defined(CONFIG_PROM_CONSOLE) + } else if (!strncmp (commands, "prom", 4)) { + char *p; + + for (p = commands - 8; *p && *p != ' '; p++) + *p = ' '; + conswitchp = &prom_con; + console_fb = 1; +#endif } else { console_fb = 1; - console_fb_path = commands; } } else #endif @@ -235,21 +246,31 @@ extern int root_mountflags; char saved_command_line[256]; char reboot_command[256]; -unsigned long phys_base; +extern unsigned long phys_base; static struct pt_regs fake_swapper_regs = { { 0, }, 0, 0, 0, 0 }; -#if 0 -#include <linux/console.h> +extern struct consw sun_serial_con; -static void prom_cons_write(struct console *con, const char *str, unsigned count) +#ifdef PROM_DEBUG_CONSOLE +static void +prom_console_write(struct console *con, const char *s, unsigned n) { - while (count--) - prom_printf("%c", *str++); + prom_printf("%s", s); } static struct console prom_console = { - "PROM", prom_cons_write, 0, 0, 0, 0, 0, CON_PRINTBUFFER, 0, 0, 0 + "prom", + prom_console_write, + NULL, + NULL, + NULL, + NULL, + NULL, + CON_PRINTBUFFER, + -1, + 0, + NULL }; #endif @@ -260,7 +281,7 @@ __initfunc(void setup_arch(char **cmdline_p, unsigned long lowest_paddr; int total, i; -#if 0 +#ifdef PROM_DEBUG_CONSOLE register_console(&prom_console); #endif @@ -270,6 +291,12 @@ __initfunc(void setup_arch(char **cmdline_p, printk("ARCH: SUN4U\n"); +#ifdef CONFIG_DUMMY_CONSOLE + conswitchp = &dummy_con; +#elif defined(CONFIG_PROM_CONSOLE) + conswitchp = &prom_con; +#endif + boot_flags_init(*cmdline_p); idprom_init(); @@ -396,6 +423,8 @@ __initfunc(void setup_arch(char **cmdline_p, #else serial_console = 0; #endif + if (serial_console) + conswitchp = NULL; } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 94bf90398..004e0e81e 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -1,11 +1,11 @@ -/* $Id: signal.c,v 1.27 1997/12/15 15:04:44 jj Exp $ +/* $Id: signal.c,v 1.30 1998/07/30 11:29:34 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/config.h> @@ -17,6 +17,7 @@ #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/mm.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -25,8 +26,8 @@ #include <asm/pgtable.h> #include <asm/fpumacro.h> #include <asm/uctx.h> -#include <asm/smp_lock.h> #include <asm/siginfo.h> +#include <asm/visasm.h> #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -104,8 +105,10 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) __get_user(fenab, &(ucp->uc_mcontext.mc_fpregs.mcfpu_enab)); if(fenab) { - unsigned long *fpregs = (unsigned long *)(regs+1); + unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; + + fprs_write(0); __get_user(fprs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fprs)); if (fprs & FPRS_DL) copy_from_user(fpregs, &(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs), @@ -113,10 +116,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) if (fprs & FPRS_DU) copy_from_user(fpregs+16, ((unsigned long *)&(ucp->uc_mcontext.mc_fpregs.mcfpu_fregs))+16, (sizeof(unsigned int) * 32)); - __get_user(fpregs[32], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); - __get_user(fpregs[33], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); - regs->fprs = fprs; - regs->tstate |= TSTATE_PEF; + __get_user(current->tss.xfsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_fsr)); + __get_user(current->tss.gsr[0], &(ucp->uc_mcontext.mc_fpregs.mcfpu_gsr)); + regs->tstate &= ~TSTATE_PEF; } return; do_sigsegv: @@ -131,11 +133,18 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) mc_gregset_t *grp; mcontext_t *mcp; unsigned long fp, i7; - unsigned char fenab = (current->tss.flags & SPARC_FLAG_USEDFPU); + unsigned char fenab; synchronize_user_stack(); if(tp->w_saved || clear_user(ucp, sizeof(*ucp))) goto do_sigsegv; + +#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); +#endif + mcp = &ucp->uc_mcontext; grp = &mcp->mc_gregs; @@ -175,25 +184,18 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs) __put_user(fenab, &(mcp->mc_fpregs.mcfpu_enab)); if(fenab) { - unsigned long *fpregs = (unsigned long *)(regs+1); + unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; - fprs = (regs->fprs & FPRS_FEF) | - (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) copy_to_user(&(mcp->mc_fpregs.mcfpu_fregs), fpregs, (sizeof(unsigned int) * 32)); - else - clear_user(&(mcp->mc_fpregs.mcfpu_fregs), - (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) copy_to_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, fpregs+16, (sizeof(unsigned int) * 32)); - else - clear_user(((unsigned long *)&(mcp->mc_fpregs.mcfpu_fregs))+16, - (sizeof(unsigned int) * 32)); - __put_user(fpregs[32], &(mcp->mc_fpregs.mcfpu_fsr)); - __put_user(fpregs[33], &(mcp->mc_fpregs.mcfpu_gsr)); + __put_user(current->tss.xfsr[0], &(mcp->mc_fpregs.mcfpu_fsr)); + __put_user(current->tss.gsr[0], &(mcp->mc_fpregs.mcfpu_gsr)); __put_user(fprs, &(mcp->mc_fpregs.mcfpu_fprs)); } return; @@ -224,6 +226,7 @@ struct rt_signal_frame { sigset_t mask; __siginfo_fpu_t * fpu_save; unsigned int insns [2]; + stack_t stack; __siginfo_fpu_t fpu_state; }; @@ -331,23 +334,26 @@ asmlinkage void do_rt_sigsuspend(sigset_t *uset, size_t sigsetsize, struct pt_re } } -static inline void +static inline int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) { - unsigned long *fpregs = (unsigned long *)(regs+1); + unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; - - __get_user(fprs, &fpu->si_fprs); + int err; + + err = __get_user(fprs, &fpu->si_fprs); + fprs_write(0); + regs->tstate &= ~TSTATE_PEF; if (fprs & FPRS_DL) - copy_from_user(fpregs, &fpu->si_float_regs[0], + err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_from_user(fpregs+16, &fpu->si_float_regs[32], + err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); - __get_user(fpregs[32], &fpu->si_fsr); - __get_user(fpregs[33], &fpu->si_gsr); - regs->fprs = fprs; - regs->tstate |= TSTATE_PEF; + 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; + return err; } void do_sigreturn(struct pt_regs *regs) @@ -356,6 +362,7 @@ void do_sigreturn(struct pt_regs *regs) unsigned long tpc, tnpc, tstate; __siginfo_fpu_t *fpu_save; sigset_t set; + int err; synchronize_user_stack (); sf = (struct new_signal_frame *) @@ -365,34 +372,33 @@ void do_sigreturn(struct pt_regs *regs) if (((unsigned long) sf) & 3) goto segv; - if (get_user(tpc, &sf->info.si_regs.tpc) || - __get_user(tnpc, &sf->info.si_regs.tnpc) || - ((tpc | tnpc) & 3)) - goto segv; - - regs->tpc = tpc; - regs->tnpc = tnpc; + 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 */ - if (__get_user(regs->y, &sf->info.si_regs.y) || - __get_user(tstate, &sf->info.si_regs.tstate) || - copy_from_user(regs->u_regs, sf->info.si_regs.u_regs, sizeof(regs->u_regs))) - goto segv; + 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); - if (__get_user(fpu_save, &sf->fpu_save)) - goto segv; + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - restore_fpu_state(regs, &sf->fpu_state); - if (__get_user(set.sig[0], &sf->info.si_mask) || - (_NSIG_WORDS > 1 && - __copy_from_user(&set.sig[1], &sf->extramask, - sizeof(sf->extramask)))) + 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; @@ -400,8 +406,7 @@ void do_sigreturn(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); return; segv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } void do_rt_sigreturn(struct pt_regs *regs) @@ -410,6 +415,8 @@ void do_rt_sigreturn(struct pt_regs *regs) unsigned long tpc, tnpc, tstate; __siginfo_fpu_t *fpu_save; sigset_t set; + stack_t st; + int err; synchronize_user_stack (); sf = (struct rt_signal_frame *) @@ -419,31 +426,36 @@ void do_rt_sigreturn(struct pt_regs *regs) if (((unsigned long) sf) & 3) goto segv; - if (get_user(tpc, &sf->regs.tpc) || - __get_user(tnpc, &sf->regs.tnpc) || - ((tpc | tnpc) & 3)) - goto segv; - - regs->tpc = tpc; - regs->tnpc = tnpc; + err = get_user(tpc, &sf->regs.tpc); + err |= __get_user(tnpc, &sf->regs.tnpc); + err |= ((tpc | tnpc) & 3); /* 2. Restore the state */ - if (__get_user(regs->y, &sf->regs.y) || - __get_user(tstate, &sf->regs.tstate) || - copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs))) - goto segv; + err |= __get_user(regs->y, &sf->regs.y); + err |= __get_user(tstate, &sf->regs.tstate); + err |= copy_from_user(regs->u_regs, sf->regs.u_regs, sizeof(regs->u_regs)); /* User can only change condition codes in %tstate. */ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= (tstate & TSTATE_ICC); - if (__get_user(fpu_save, &sf->fpu_save)) - goto segv; + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - restore_fpu_state(regs, &sf->fpu_state); + err |= restore_fpu_state(regs, &sf->fpu_state); - if (__copy_from_user(&set, &sf->mask, sizeof(sigset_t))) + err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); + err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); + + if (err) goto segv; + + regs->tpc = tpc; + regs->tnpc = tnpc; + + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, (unsigned long)sf); + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; @@ -451,8 +463,7 @@ void do_rt_sigreturn(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); return; segv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } /* Checks if the fp is valid */ @@ -469,24 +480,30 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t *fpu) unsigned long *fpregs = (unsigned long *)(regs+1); unsigned long fprs; - fprs = (regs->fprs & FPRS_FEF) | - (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); - else - clear_user(&fpu->si_float_regs[0], - (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); - else - clear_user(&fpu->si_float_regs[32], - (sizeof(unsigned int) * 32)); - __put_user(fpregs[32], &fpu->si_fsr); - __put_user(fpregs[33], &fpu->si_gsr); + __put_user(current->tss.xfsr[0], &fpu->si_fsr); + __put_user(current->tss.gsr[0], &fpu->si_gsr); __put_user(fprs, &fpu->si_fprs); - regs->tstate &= ~TSTATE_PEF; +} + +static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize) +{ + unsigned long sp; + + sp = regs->u_regs[UREG_FP] + STACK_BIAS; + + /* This is the X/Open sanctioned signal stack switching. */ + if (ka->sa.sa_flags & SA_ONSTACK) { + if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + sp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)(sp - framesize); } static inline void @@ -498,12 +515,14 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, /* 1. Make sure everything is clean */ synchronize_user_stack(); + save_and_clear_fpu(); + sigframe_size = NF_ALIGNEDSZ; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + + if (!(current->tss.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); - sf = (struct new_signal_frame *) - (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); + sf = (struct new_signal_frame *)get_sigframe(ka, regs, sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)) goto sigill; @@ -516,8 +535,8 @@ new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, /* 2. Save the current process state */ copy_to_user(&sf->info.si_regs, regs, sizeof (*regs)); - - if (current->tss.flags & SPARC_FLAG_USEDFPU) { + + if (current->tss.fpsaved[0] & FPRS_FEF) { save_fpu_state(regs, &sf->fpu_state); __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { @@ -582,12 +601,13 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, /* 1. Make sure everything is clean */ synchronize_user_stack(); + save_and_clear_fpu(); + sigframe_size = RT_ALIGNEDSZ; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + if (!(current->tss.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); - sf = (struct rt_signal_frame *) - (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); + sf = (struct rt_signal_frame *)get_sigframe(ka, regs, sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)) goto sigill; @@ -601,12 +621,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, /* 2. Save the current process state */ copy_to_user(&sf->regs, regs, sizeof (*regs)); - if (current->tss.flags & SPARC_FLAG_USEDFPU) { + if (current->tss.fpsaved[0] & FPRS_FEF) { save_fpu_state(regs, &sf->fpu_state); __put_user((u64)&sf->fpu_state, &sf->fpu_save); } else { __put_user(0, &sf->fpu_save); } + + /* Setup sigaltstack */ + __put_user(current->sas_ss_sp, &sf->stack.ss_sp); + __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); + __put_user(current->sas_ss_size, &sf->stack.ss_size); copy_to_user(&sf->mask, oldset, sizeof(sigset_t)); @@ -828,28 +853,3 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, } return 0; } - -asmlinkage int -sys_sigstack(struct sigstack *ssptr, struct sigstack *ossptr) -{ - int ret = -EFAULT; - - lock_kernel(); - /* First see if old state is wanted. */ - if(ossptr) { - if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) || - __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status)) - goto out; - } - - /* Now see if we want to update the new state. */ - if(ssptr) { - if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) || - __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status)) - goto out; - } - ret = 0; -out: - unlock_kernel(); - return ret; -} diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 269ff413d..b62ab65ff 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -1,11 +1,11 @@ -/* $Id: signal32.c,v 1.35 1998/04/01 07:00:43 davem Exp $ +/* $Id: signal32.c,v 1.41 1998/07/30 11:29:32 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include <linux/sched.h> @@ -16,6 +16,7 @@ #include <linux/ptrace.h> #include <linux/unistd.h> #include <linux/mm.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/bitops.h> @@ -24,7 +25,7 @@ #include <asm/pgtable.h> #include <asm/psrcompat.h> #include <asm/fpumacro.h> -#include <asm/smp_lock.h> +#include <asm/visasm.h> #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -36,6 +37,8 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs, /* This turned off for production... */ /* #define DEBUG_SIGNALS 1 */ +/* #define DEBUG_SIGNALS_TRACE 1 */ +/* #define DEBUG_SIGNALS_MAPS 1 */ /* Signal frames: the original one (compatible with SunOS): * @@ -82,6 +85,7 @@ struct rt_signal_frame32 { sigset_t32 mask; /* __siginfo_fpu32_t * */ u32 fpu_save; unsigned int insns [2]; + stack_t32 stack; __siginfo_fpu_t fpu_state; }; @@ -178,20 +182,23 @@ asmlinkage void do_rt_sigsuspend32(u32 uset, size_t sigsetsize, struct pt_regs * } } -static inline void restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) +static inline int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { - unsigned long *fpregs = (unsigned long *)(regs + 1); + unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; + int err; - __get_user(fprs, &fpu->si_fprs); + err = __get_user(fprs, &fpu->si_fprs); + fprs_write(0); + regs->tstate &= ~TSTATE_PEF; if (fprs & FPRS_DL) - copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); + err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) - copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); - __get_user(fpregs[32], &fpu->si_fsr); - __get_user(fpregs[33], &fpu->si_gsr); - regs->fprs = fprs; - regs->tstate |= TSTATE_PEF; + 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; + return err; } void do_new_sigreturn32(struct pt_regs *regs) @@ -201,6 +208,7 @@ void do_new_sigreturn32(struct pt_regs *regs) unsigned pc, npc, fpu_save; sigset_t set; unsigned seta[_NSIG_WORDS32]; + int err; regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP]; @@ -220,34 +228,35 @@ void do_new_sigreturn32(struct pt_regs *regs) regs->tnpc = npc; /* 2. Restore the state */ - __get_user(regs->y, &sf->info.si_regs.y); - __get_user(psr, &sf->info.si_regs.psr); - - __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]); - __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]); - __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]); - __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]); - __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]); - __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]); - __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]); - __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]); - __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]); - __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]); - __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]); - __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]); - __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]); - __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); - __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); + err = __get_user(regs->y, &sf->info.si_regs.y); + err |= __get_user(psr, &sf->info.si_regs.psr); + + err |= __get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]); + err |= __get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]); + err |= __get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]); + err |= __get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]); + err |= __get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]); + err |= __get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]); + err |= __get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]); + err |= __get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]); + err |= __get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]); + err |= __get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]); + err |= __get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]); + err |= __get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]); + err |= __get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]); + err |= __get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]); + err |= __get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]); /* User can only change condition codes in %tstate. */ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); - __get_user(fpu_save, &sf->fpu_save); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - restore_fpu_state32(regs, &sf->fpu_state); - if (__get_user(seta[0], &sf->info.si_mask) || - copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + err |= restore_fpu_state32(regs, &sf->fpu_state); + err |= __get_user(seta[0], &sf->info.si_mask); + err |= copy_from_user(seta+1, &sf->extramask, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); + if (err) goto segv; switch (_NSIG_WORDS) { case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); @@ -262,8 +271,7 @@ void do_new_sigreturn32(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); return; segv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } asmlinkage void do_sigreturn32(struct pt_regs *regs) @@ -272,6 +280,7 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) unsigned pc, npc, psr; sigset_t set; unsigned seta[_NSIG_WORDS32]; + int err; synchronize_user_stack(); if (current->tss.new_signal) @@ -284,15 +293,16 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) (((unsigned long) scptr) & 3)) goto segv; - __get_user(pc, &scptr->sigc_pc); - __get_user(npc, &scptr->sigc_npc); + err = __get_user(pc, &scptr->sigc_pc); + err |= __get_user(npc, &scptr->sigc_npc); if((pc | npc) & 3) goto segv; /* Nice try. */ - if (__get_user(seta[0], &scptr->sigc_mask) || - /* Note that scptr + 1 points to extramask */ - copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned))) + err |= __get_user(seta[0], &scptr->sigc_mask); + /* Note that scptr + 1 points to extramask */ + err |= copy_from_user(seta+1, scptr + 1, (_NSIG_WORDS32 - 1) * sizeof(unsigned)); + if (err) goto segv; switch (_NSIG_WORDS) { case 4: set.sig[3] = seta[6] + (((long)seta[7]) << 32); @@ -306,22 +316,21 @@ asmlinkage void do_sigreturn32(struct pt_regs *regs) recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - __get_user(current->tss.sstk_info.cur_status, &scptr->sigc_onstack); - current->tss.sstk_info.cur_status &= 1; regs->tpc = pc; regs->tnpc = npc; - __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); - __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); - __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); + err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); + err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); + err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); /* User can only change condition codes in %tstate. */ - __get_user(psr, &scptr->sigc_psr); + err |= __get_user(psr, &scptr->sigc_psr); + if (err) + goto segv; regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); return; segv: - lock_kernel (); - do_exit (SIGSEGV); + send_sig(SIGSEGV, current, 1); } asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) @@ -331,6 +340,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) unsigned pc, npc, fpu_save; sigset_t set; sigset_t32 seta; + stack_t st; + int err; synchronize_user_stack(); regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; @@ -351,34 +362,43 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) regs->tnpc = npc; /* 2. Restore the state */ - __get_user(regs->y, &sf->regs.y); - __get_user(psr, &sf->regs.psr); - - __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); - __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); - __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); - __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); - __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); - __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); - __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); - __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); - __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); - __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); - __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); - __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); - __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); - __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); - __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); + err = __get_user(regs->y, &sf->regs.y); + err |= __get_user(psr, &sf->regs.psr); + + err |= __get_user(regs->u_regs[UREG_G1], &sf->regs.u_regs[UREG_G1]); + err |= __get_user(regs->u_regs[UREG_G2], &sf->regs.u_regs[UREG_G2]); + err |= __get_user(regs->u_regs[UREG_G3], &sf->regs.u_regs[UREG_G3]); + err |= __get_user(regs->u_regs[UREG_G4], &sf->regs.u_regs[UREG_G4]); + err |= __get_user(regs->u_regs[UREG_G5], &sf->regs.u_regs[UREG_G5]); + err |= __get_user(regs->u_regs[UREG_G6], &sf->regs.u_regs[UREG_G6]); + err |= __get_user(regs->u_regs[UREG_G7], &sf->regs.u_regs[UREG_G7]); + err |= __get_user(regs->u_regs[UREG_I0], &sf->regs.u_regs[UREG_I0]); + err |= __get_user(regs->u_regs[UREG_I1], &sf->regs.u_regs[UREG_I1]); + err |= __get_user(regs->u_regs[UREG_I2], &sf->regs.u_regs[UREG_I2]); + err |= __get_user(regs->u_regs[UREG_I3], &sf->regs.u_regs[UREG_I3]); + err |= __get_user(regs->u_regs[UREG_I4], &sf->regs.u_regs[UREG_I4]); + err |= __get_user(regs->u_regs[UREG_I5], &sf->regs.u_regs[UREG_I5]); + err |= __get_user(regs->u_regs[UREG_I6], &sf->regs.u_regs[UREG_I6]); + err |= __get_user(regs->u_regs[UREG_I7], &sf->regs.u_regs[UREG_I7]); /* User can only change condition codes in %tstate. */ regs->tstate &= ~(TSTATE_ICC); regs->tstate |= psr_to_tstate_icc(psr); - __get_user(fpu_save, &sf->fpu_save); + err |= __get_user(fpu_save, &sf->fpu_save); if (fpu_save) - restore_fpu_state32(regs, &sf->fpu_state); - if (copy_from_user(&seta, &sf->mask, sizeof(sigset_t32))) - goto segv; + err |= restore_fpu_state32(regs, &sf->fpu_state); + err |= copy_from_user(&seta, &sf->mask, sizeof(sigset_t32)); + err |= __get_user((long)st.ss_sp, &sf->stack.ss_sp); + err |= __get_user(st.ss_flags, &sf->stack.ss_flags); + err |= __get_user(st.ss_size, &sf->stack.ss_size); + if (err) + goto segv; + + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, (unsigned long)sf); + switch (_NSIG_WORDS) { case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32); case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32); @@ -392,8 +412,7 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) spin_unlock_irq(¤t->sigmask_lock); return; segv: - lock_kernel(); - do_exit(SIGSEGV); + send_sig(SIGSEGV, current, 1); } /* Checks if the fp is valid */ @@ -404,6 +423,21 @@ static int invalid_frame_pointer(void *fp, int fplen) return 0; } +static inline void *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) +{ + unsigned long sp; + + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; + sp = regs->u_regs[UREG_FP]; + + /* This is the X/Open sanctioned signal stack switching. */ + if (sa->sa_flags & SA_ONSTACK) { + if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) + sp = current->sas_ss_sp + current->sas_ss_size; + } + return (void *)(sp - framesize); +} + static void setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, struct pt_regs *regs, int signr, sigset_t *oldset) @@ -415,13 +449,12 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, #if 0 int window = 0; #endif - int old_status = current->tss.sstk_info.cur_status; unsigned psr; synchronize_user_stack(); - regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP]; - sframep = (struct signal_sframe32 *) (((unsigned long) sframep)-SF_ALIGNEDSZ); + save_and_clear_fpu(); + + sframep = (struct signal_sframe32 *)get_sigframe(sa, regs, SF_ALIGNEDSZ); if (invalid_frame_pointer (sframep, sizeof(*sframep))){ #ifdef DEBUG_SIGNALS /* fills up the console logs during crashme runs, yuck... */ printk("%s [%d]: User has trashed signal stack\n", @@ -439,7 +472,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, sc = &sframep->sig_context; /* We've already made sure frame pointer isn't in kernel space... */ - __put_user(old_status, &sc->sigc_onstack); + __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), &sc->sigc_onstack); switch (_NSIG_WORDS) { case 4: seta[7] = (oldset->sig[3] >> 32); @@ -457,7 +490,7 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(pc, &sc->sigc_pc); __put_user(npc, &sc->sigc_npc); psr = tstate_to_psr (regs->tstate); - if(current->tss.flags & SPARC_FLAG_USEDFPU) + if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; __put_user(psr, &sc->sigc_psr); __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); @@ -501,23 +534,17 @@ setup_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, static inline void save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t *fpu) { - unsigned long *fpregs = (unsigned long *)(regs+1); + unsigned long *fpregs = (unsigned long *)(((char *)current) + AOFF_task_fpregs); unsigned long fprs; - fprs = (regs->fprs & FPRS_FEF) | - (current->tss.flags & (SPARC_FLAG_USEDFPUL | SPARC_FLAG_USEDFPUU)); + fprs = current->tss.fpsaved[0]; if (fprs & FPRS_DL) copy_to_user(&fpu->si_float_regs[0], fpregs, (sizeof(unsigned int) * 32)); - else - clear_user(&fpu->si_float_regs[0], (sizeof(unsigned int) * 32)); if (fprs & FPRS_DU) copy_to_user(&fpu->si_float_regs[32], fpregs+16, (sizeof(unsigned int) * 32)); - else - clear_user(&fpu->si_float_regs[32], (sizeof(unsigned int) * 32)); - __put_user(fpregs[32], &fpu->si_fsr); - __put_user(fpregs[33], &fpu->si_gsr); + __put_user(current->tss.xfsr[0], &fpu->si_fsr); + __put_user(current->tss.gsr[0], &fpu->si_gsr); __put_user(fprs, &fpu->si_fprs); - regs->tstate &= ~TSTATE_PEF; } static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *regs, @@ -531,12 +558,13 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg /* 1. Make sure everything is clean */ synchronize_user_stack(); + save_and_clear_fpu(); + sigframe_size = NF_ALIGNEDSZ; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + if (!(current->tss.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); - regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); + sf = (struct new_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)) { #ifdef DEBUG_SIGNALS @@ -559,7 +587,7 @@ static inline void new_setup_frame32(struct k_sigaction *ka, struct pt_regs *reg __put_user(regs->tnpc, &sf->info.si_regs.npc); __put_user(regs->y, &sf->info.si_regs.y); psr = tstate_to_psr (regs->tstate); - if(current->tss.flags & SPARC_FLAG_USEDFPU) + if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; __put_user(psr, &sf->info.si_regs.psr); for (i = 0; i < 16; i++) @@ -649,9 +677,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, int i; synchronize_user_stack(); + save_and_clear_fpu(); + regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - sfp = (svr4_signal_frame_t *) regs->u_regs[UREG_FP] - REGWIN_SZ; - sfp = (svr4_signal_frame_t *) (((unsigned long) sfp)-SVR4_SF_ALIGNED); + sfp = (svr4_signal_frame_t *) get_sigframe(sa, regs, REGWIN_SZ + SVR4_SF_ALIGNED); if (invalid_frame_pointer (sfp, sizeof (*sfp))){ #ifdef DEBUG_SIGNALS @@ -688,7 +717,7 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, __put_user(regs->tpc, &((*gr) [SVR4_PC])); __put_user(regs->tnpc, &((*gr) [SVR4_NPC])); psr = tstate_to_psr (regs->tstate); - if(current->tss.flags & SPARC_FLAG_USEDFPU) + if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; __put_user(psr, &((*gr) [SVR4_PSR])); __put_user(regs->y, &((*gr) [SVR4_Y])); @@ -699,10 +728,10 @@ setup_svr4_frame32(struct sigaction *sa, unsigned long pc, unsigned long npc, for (i = 0; i < 8; i++) __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); - /* Setup sigaltstack, FIXME */ - __put_user(0xdeadbeef, &uc->stack.sp); - __put_user(0, &uc->stack.size); - __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */ + /* Setup sigaltstack */ + __put_user(current->sas_ss_sp, &uc->stack.sp); + __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + __put_user(current->sas_ss_size, &uc->stack.size); /* Save the currently window file: */ @@ -773,6 +802,8 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) int i; 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); lock_kernel(); @@ -797,9 +828,14 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) /* Store registers */ __put_user(regs->tpc, &uc->mcontext.greg [SVR4_PC]); __put_user(regs->tnpc, &uc->mcontext.greg [SVR4_NPC]); - __put_user((tstate_to_psr(regs->tstate) | - ((current->tss.flags & SPARC_FLAG_USEDFPU) ? PSR_EF : 0)), - &uc->mcontext.greg [SVR4_PSR]); +#if 1 + __put_user(0, &uc->mcontext.greg [SVR4_PSR]); +#else + i = tstate_to_psr(regs->tstate) & ~PSR_EF; + if (current->tss.fpsaved[0] & FPRS_FEF) + i |= PSR_EF; + __put_user(i, &uc->mcontext.greg [SVR4_PSR]); +#endif __put_user(regs->y, &uc->mcontext.greg [SVR4_Y]); /* Copy g [1..7] and o [0..7] registers */ @@ -808,10 +844,10 @@ svr4_getcontext(svr4_ucontext_t *uc, struct pt_regs *regs) for (i = 0; i < 8; i++) __put_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); - /* Setup sigaltstack, FIXME */ - __put_user(0xdeadbeef, &uc->stack.sp); - __put_user(0, &uc->stack.size); - __put_user(0, &uc->stack.flags); /* Possible: ONSTACK, DISABLE */ + /* Setup sigaltstack */ + __put_user(current->sas_ss_sp, &uc->stack.sp); + __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); + __put_user(current->sas_ss_size, &uc->stack.size); /* The register file is not saved * we have already stuffed all of it with sync_user_stack @@ -828,7 +864,8 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) u32 pc, npc, psr; sigset_t set; svr4_sigset_t setv; - int i; + int i, err; + stack_t st; /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? @@ -851,20 +888,34 @@ asmlinkage int svr4_setcontext(svr4_ucontext_t *c, struct pt_regs *regs) /* Check for valid PC and nPC */ gr = &c->mcontext.greg; - __get_user(pc, &((*gr)[SVR4_PC])); - __get_user(npc, &((*gr)[SVR4_NPC])); + err = __get_user(pc, &((*gr)[SVR4_PC])); + err |= __get_user(npc, &((*gr)[SVR4_NPC])); if((pc | npc) & 3) { +#ifdef DEBUG_SIGNALS printk ("setcontext, PC or nPC were bogus\n"); +#endif goto sigsegv; } + /* Retrieve information from passed ucontext */ - /* note that nPC is ored a 1, this is used to inform entry.S */ - /* that we don't want it to mess with our PC and nPC */ - if (copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t))) - goto sigsegv; + /* note that nPC is ored a 1, this is used to inform entry.S */ + /* that we don't want it to mess with our PC and nPC */ + + err |= copy_from_user (&setv, &c->sigmask, sizeof(svr4_sigset_t)); set.sig[0] = setv.sigbits[0] | (((long)setv.sigbits[1]) << 32); if (_NSIG_WORDS >= 2) set.sig[1] = setv.sigbits[2] | (((long)setv.sigbits[3]) << 32); + + err |= __get_user((long)st.ss_sp, &c->stack.sp); + err |= __get_user(st.ss_flags, &c->stack.flags); + err |= __get_user(st.ss_size, &c->stack.size); + if (err) + goto sigsegv; + + /* It is more difficult to avoid calling this function than to + call it and ignore errors. */ + do_sigaltstack(&st, NULL, regs->u_regs[UREG_I6]); + sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sigmask_lock); current->blocked = set; @@ -904,12 +955,13 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs /* 1. Make sure everything is clean */ synchronize_user_stack(); + save_and_clear_fpu(); + sigframe_size = RT_ALIGNEDSZ; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) + if (!(current->tss.fpsaved[0] & FPRS_FEF)) sigframe_size -= sizeof(__siginfo_fpu_t); - regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; - sf = (struct rt_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size); + sf = (struct rt_signal_frame32 *)get_sigframe(&ka->sa, regs, sigframe_size); if (invalid_frame_pointer (sf, sigframe_size)) { #ifdef DEBUG_SIGNALS @@ -932,7 +984,7 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs __put_user(regs->tnpc, &sf->regs.npc); __put_user(regs->y, &sf->regs.y); psr = tstate_to_psr (regs->tstate); - if(current->tss.flags & SPARC_FLAG_USEDFPU) + if(current->tss.fpsaved[0] & FPRS_FEF) psr |= PSR_EF; __put_user(psr, &sf->regs.psr); for (i = 0; i < 16; i++) @@ -944,6 +996,11 @@ static inline void setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs } else { __put_user(0, &sf->fpu_save); } + + /* Setup sigaltstack */ + __put_user(current->sas_ss_sp, &sf->stack.ss_sp); + __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); + __put_user(current->sas_ss_size, &sf->stack.ss_size); switch (_NSIG_WORDS) { case 4: seta.sig[7] = (oldset->sig[3] >> 32); @@ -1048,6 +1105,60 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs } } +#ifdef DEBUG_SIGNALS_MAPS + +#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %s %lu " + +static inline void read_maps (void) +{ + struct vm_area_struct * map, * next; + char * buffer; + ssize_t i; + + buffer = (char*)__get_free_page(GFP_KERNEL); + if (!buffer) + return; + + for (map = current->mm->mmap ; map ; map = next ) { + /* produce the next line */ + char *line; + char str[5], *cp = str; + int flags; + kdev_t dev; + unsigned long ino; + + /* + * Get the next vma now (but it won't be used if we sleep). + */ + next = map->vm_next; + flags = map->vm_flags; + + *cp++ = flags & VM_READ ? 'r' : '-'; + *cp++ = flags & VM_WRITE ? 'w' : '-'; + *cp++ = flags & VM_EXEC ? 'x' : '-'; + *cp++ = flags & VM_MAYSHARE ? 's' : 'p'; + *cp++ = 0; + + dev = 0; + ino = 0; + if (map->vm_file != NULL) { + dev = map->vm_file->f_dentry->d_inode->i_dev; + ino = map->vm_file->f_dentry->d_inode->i_ino; + line = d_path(map->vm_file->f_dentry, buffer, PAGE_SIZE); + } + printk(MAPS_LINE_FORMAT, map->vm_start, map->vm_end, str, map->vm_offset, + kdevname(dev), ino); + if (map->vm_file != NULL) + printk("%s\n", line); + else + printk("\n"); + } + free_page((unsigned long)buffer); + return; +} + +#endif + /* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. @@ -1144,8 +1255,25 @@ asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs * regs, } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ - printk ("Sig ILL going...\n"); + printk ("Sig %ld going for %s[%d]...\n", signr, current->comm, current->pid); show_regs (regs); +#ifdef DEBUG_SIGNALS_TRACE + { + 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)); + 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]; + } + } +#endif +#ifdef DEBUG_SIGNALS_MAPS + printk("Maps:\n"); + read_maps(); +#endif #endif /* fall through */ default: @@ -1178,28 +1306,60 @@ struct sigstack32 { int cur_status; }; -asmlinkage int sys32_sigstack(u32 u_ssptr, u32 u_ossptr) +asmlinkage int do_sys32_sigstack(u32 u_ssptr, u32 u_ossptr, unsigned long sp) { struct sigstack32 *ssptr = (struct sigstack32 *)((unsigned long)(u_ssptr)); struct sigstack32 *ossptr = (struct sigstack32 *)((unsigned long)(u_ossptr)); int ret = -EFAULT; - lock_kernel(); /* First see if old state is wanted. */ - if(ossptr) { - if (put_user ((u64)current->tss.sstk_info.the_stack, &ossptr->the_stack) || - __put_user (current->tss.sstk_info.cur_status, &ossptr->cur_status)) + if (ossptr) { + if (put_user(current->sas_ss_sp + current->sas_ss_size, &ossptr->the_stack) || + __put_user(on_sig_stack(sp), &ossptr->cur_status)) goto out; } - + /* Now see if we want to update the new state. */ - if(ssptr) { - if (get_user ((u64)current->tss.sstk_info.the_stack, &ssptr->the_stack) || - __put_user (current->tss.sstk_info.cur_status, &ssptr->cur_status)) + 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 + swap stacks while we are on it. */ + ret = -EPERM; + if (current->sas_ss_sp && on_sig_stack(sp)) + goto out; + + /* Since we don't know the extent of the stack, and we don't + track onstack-ness, but rather calculate it, we must + presume a size. Ho hum this interface is lossy. */ + current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; + current->sas_ss_size = SIGSTKSZ; } + ret = 0; out: - unlock_kernel(); + return ret; +} + +asmlinkage int do_sys32_sigaltstack(u32 ussa, u32 uossa, unsigned long sp) +{ + stack_t uss, uoss; + int ret; + mm_segment_t old_fs; + + if (ussa && (get_user((long)uss.ss_sp, &((stack_t32 *)(long)ussa)->ss_sp) || + __get_user(uss.ss_flags, &((stack_t32 *)(long)ussa)->ss_flags) || + __get_user(uss.ss_size, &((stack_t32 *)(long)ussa)->ss_size))) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = do_sigaltstack(ussa ? &uss : NULL, uossa ? &uoss : NULL, sp); + set_fs(old_fs); + if (!ret && uossa && (put_user((long)uoss.ss_sp, &((stack_t32 *)(long)uossa)->ss_sp) || + __put_user(uoss.ss_flags, &((stack_t32 *)(long)uossa)->ss_flags) || + __put_user(uoss.ss_size, &((stack_t32 *)(long)uossa)->ss_size))) + return -EFAULT; return ret; } diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index ca2aa4360..3ec32e92b 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -3,7 +3,6 @@ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) */ -#include <linux/config.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/tasks.h> @@ -48,7 +47,8 @@ static int smp_activated = 0; volatile int cpu_number_map[NR_CPUS]; volatile int __cpu_logical_map[NR_CPUS]; -struct klock_info klock_info = { KLOCK_CLEAR, 0 }; +/* Kernel spinlock */ +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; __initfunc(void smp_setup(char *str, int *ints)) { @@ -63,8 +63,7 @@ int smp_info(char *buf) for (i = 0; i < NR_CPUS; i++) if(cpu_present_map & (1UL << i)) len += sprintf(buf + len, - "CPU%d:\t\t%s\n", - i, klock_info.akp == i ? "akp" : "online"); + "CPU%d:\t\tonline\n", i return len; } @@ -85,10 +84,9 @@ __initfunc(void smp_store_cpu_info(int id)) { cpu_data[id].udelay_val = loops_per_sec; cpu_data[id].irq_count = 0; - cpu_data[id].last_tlbversion_seen = tlb_context_cache & CTX_VERSION_MASK; cpu_data[id].pgcache_size = 0; + cpu_data[id].pgdcache_size = 0; cpu_data[id].pgd_cache = NULL; - cpu_data[id].pmd_cache = NULL; cpu_data[id].pte_cache = NULL; } @@ -164,8 +162,6 @@ void cpu_panic(void) panic("SMP bolixed\n"); } -static void smp_tickoffset_init(void); - extern struct prom_cpuinfo linux_cpus[NR_CPUS]; extern unsigned long smp_trampoline; @@ -175,23 +171,8 @@ __initfunc(void smp_boot_cpus(void)) int cpucount = 0, i; printk("Entering UltraSMPenguin Mode...\n"); - boot_cpu_id = hard_smp_processor_id(); - smp_tickoffset_init(); __sti(); - cpu_present_map = 0; - for(i = 0; i < linux_num_cpus; i++) - cpu_present_map |= (1UL << linux_cpus[i].mid); - for(i = 0; i < NR_CPUS; i++) { - cpu_number_map[i] = -1; - __cpu_logical_map[i] = -1; - } - cpu_number_map[boot_cpu_id] = 0; - prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node; - __cpu_logical_map[0] = boot_cpu_id; - klock_info.akp = boot_cpu_id; - current->processor = boot_cpu_id; smp_store_cpu_info(boot_cpu_id); - smp_setup_percpu_timer(); if(linux_num_cpus == 1) return; @@ -368,16 +349,28 @@ void smp_flush_tlb_all(void) __flush_tlb_all(); } +/* We know that the window frames of the user have been flushed + * to the stack before we get here because all callers of us + * are flush_tlb_*() routines, and these run after flush_cache_*() + * which performs the flushw. + */ static void smp_cross_call_avoidance(struct mm_struct *mm) { + u32 ctx; + spin_lock(&scheduler_lock); - get_new_mmu_context(mm, &tlb_context_cache); + get_new_mmu_context(mm); mm->cpu_vm_mask = (1UL << smp_processor_id()); - if(segment_eq(current->tss.current_ds,USER_DS)) { - u32 ctx = mm->context & 0x1fff; - - current->tss.ctx = ctx; - spitfire_set_secondary_context(ctx); + current->tss.ctx = ctx = mm->context & 0x3ff; + spitfire_set_secondary_context(ctx); + __asm__ __volatile__("flush %g6"); + spitfire_flush_dtlb_secondary_context(); + spitfire_flush_itlb_secondary_context(); + __asm__ __volatile__("flush %g6"); + if(!segment_eq(current->tss.current_ds,USER_DS)) { + /* Rarely happens. */ + current->tss.ctx = 0; + spitfire_set_secondary_context(0); __asm__ __volatile__("flush %g6"); } spin_unlock(&scheduler_lock); @@ -385,7 +378,7 @@ static void smp_cross_call_avoidance(struct mm_struct *mm) void smp_flush_tlb_mm(struct mm_struct *mm) { - u32 ctx = mm->context & 0x1fff; + u32 ctx = mm->context & 0x3ff; if(mm == current->mm && mm->count == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) @@ -395,13 +388,13 @@ void smp_flush_tlb_mm(struct mm_struct *mm) smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); local_flush_and_out: - __flush_tlb_mm(ctx); + __flush_tlb_mm(ctx, SECONDARY_CONTEXT); } void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - u32 ctx = mm->context & 0x1fff; + u32 ctx = mm->context & 0x3ff; if(mm == current->mm && mm->count == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) @@ -411,12 +404,14 @@ void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); local_flush_and_out: - __flush_tlb_range(ctx, start, end); + start &= PAGE_MASK; + end &= PAGE_MASK; + __flush_tlb_range(ctx, start, SECONDARY_CONTEXT, end, PAGE_SIZE, (end-start)); } void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) { - u32 ctx = mm->context & 0x1fff; + u32 ctx = mm->context & 0x3ff; if(mm == current->mm && mm->count == 1) { if(mm->cpu_vm_mask == (1UL << smp_processor_id())) @@ -424,7 +419,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) return smp_cross_call_avoidance(mm); } #if 0 /* XXX Disabled until further notice... */ - else if(mm != current->mm && mm->count == 1) { + else if(mm->count == 1) { /* Try to handle two special cases to avoid cross calls * in common scenerios where we are swapping process * pages out. @@ -438,7 +433,7 @@ void smp_flush_tlb_page(struct mm_struct *mm, unsigned long page) smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); local_flush_and_out: - __flush_tlb_page(ctx, page); + __flush_tlb_page(ctx, (page & PAGE_MASK), SECONDARY_CONTEXT); } /* CPU capture. */ @@ -500,8 +495,7 @@ void smp_penguin_jailcell(void) static inline void sparc64_do_profile(unsigned long pc) { -#ifdef CONFIG_PROFILE - if(prof_buffer && current->pid) { + if (prof_buffer && current->pid) { extern int _stext; pc -= (unsigned long) &_stext; @@ -511,7 +505,6 @@ static inline void sparc64_do_profile(unsigned long pc) pc = prof_len - 1; atomic_inc((atomic_t *)&prof_buffer[pc]); } -#endif } static unsigned long current_tick_offset; @@ -543,8 +536,8 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) do { if(!user) sparc64_do_profile(regs->tpc); - if(!--prof_counter(cpu)) { - + if(!--prof_counter(cpu)) + { if (cpu == boot_cpu_id) { extern void irq_enter(int, int); extern void irq_exit(int, int); @@ -563,7 +556,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) update_one_process(current, 1, user, !user, cpu); if(--current->counter < 0) { current->counter = 0; - need_resched = 1; + current->need_resched = 1; } if(user) { @@ -581,7 +574,6 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs) atomic_inc((atomic_t *)inc); atomic_inc((atomic_t *)inc2); } - prof_counter(cpu) = prof_multiplier(cpu); } @@ -600,49 +592,6 @@ __initfunc(static void smp_setup_percpu_timer(void)) prof_counter(cpu) = prof_multiplier(cpu) = 1; - if (cpu == boot_cpu_id) { - extern unsigned long tl0_itick; - extern unsigned long tl0_smp_itick; - unsigned long flags; - - save_flags(flags); cli(); - - /* - * Steal TICK_INT interrupts from timer_interrupt(). - */ - __asm__ __volatile__(" - .globl tl0_smp_itick - b,pt %%xcc, 1f - nop - - tl0_smp_itick: - rdpr %%pil, %%g2 - wrpr %%g0, 15, %%pil - b,pt %%xcc, etrap_irq - rd %%pc, %%g7 - call smp_percpu_timer_interrupt - add %%sp, %0, %%o0 - b,pt %%xcc, rtrap - clr %%l6 - - 1:" - : /* no outputs */ - : "i" (STACK_BIAS + REGWIN_SZ)); - - memcpy(&tl0_itick, &tl0_smp_itick, 8 * 4); - - __asm__ __volatile__(" - membar #StoreStore - flush %0 + 0x00 - flush %0 + 0x08 - flush %0 + 0x10 - flush %0 + 0x18" - : /* no outputs */ - : "r" (&tl0_itick)); - - restore_flags(flags); - } - __asm__ __volatile__("rd %%tick, %%g1\n\t" "add %%g1, %0, %%g1\n\t" "wr %%g1, 0x0, %%tick_cmpr" @@ -651,12 +600,27 @@ __initfunc(static void smp_setup_percpu_timer(void)) : "g1"); } -__initfunc(static void smp_tickoffset_init(void)) +__initfunc(void smp_tick_init(void)) { + int i; + + boot_cpu_id = hard_smp_processor_id(); current_tick_offset = timer_tick_offset; + cpu_present_map = 0; + for(i = 0; i < linux_num_cpus; i++) + cpu_present_map |= (1UL << linux_cpus[i].mid); + for(i = 0; i < NR_CPUS; i++) { + cpu_number_map[i] = -1; + __cpu_logical_map[i] = -1; + } + cpu_number_map[boot_cpu_id] = 0; + prom_cpu_nodes[boot_cpu_id] = linux_cpus[0].prom_node; + __cpu_logical_map[0] = boot_cpu_id; + current->processor = boot_cpu_id; + prof_counter(boot_cpu_id) = prof_multiplier(boot_cpu_id) = 1; } -__initfunc(int setup_profiling_timer(unsigned int multiplier)) +int __init 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 0eb16d7bb..0bdd42775 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.33 1998/04/06 16:09:40 jj Exp $ +/* $Id: sparc64_ksyms.c,v 1.39 1998/07/04 12:35:59 ecd Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -113,10 +113,10 @@ EXPORT_SYMBOL_PRIVATE(global_restore_flags); #else EXPORT_SYMBOL(local_irq_count); #endif -EXPORT_SYMBOL(enable_irq); -EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL_PRIVATE(_lock_kernel); EXPORT_SYMBOL_PRIVATE(_unlock_kernel); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL_PRIVATE(flushw_user); @@ -139,7 +139,15 @@ EXPORT_SYMBOL(dma_chain); 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(empty_zero_page); +EXPORT_SYMBOL(outsb); +EXPORT_SYMBOL(outsw); +EXPORT_SYMBOL(outsl); +EXPORT_SYMBOL(insb); +EXPORT_SYMBOL(insw); +EXPORT_SYMBOL(insl); #endif /* Solaris/SunOS binary compatibility */ diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S index 44f17ca01..ec23e92a0 100644 --- a/arch/sparc64/kernel/sys32.S +++ b/arch/sparc64/kernel/sys32.S @@ -1,4 +1,4 @@ -/* $Id: sys32.S,v 1.5 1998/03/24 05:57:56 ecd Exp $ +/* $Id: sys32.S,v 1.6 1998/06/28 08:28:22 ecd Exp $ * sys32.S: I-cache tricks for 32-bit compatability layer simple * conversions. * @@ -84,7 +84,7 @@ sys32_getsockopt: srl %o3, 0, %o3 mov %o7, %g1 srl %o4, 0, %o4 - call sys_setsockopt + call sys_getsockopt mov %g1, %o7 .globl sys32_bdflush diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index b5198074d..1d9c0457e 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.13 1998/03/29 10:10:52 davem Exp $ +/* $Id: sys_sparc.c,v 1.20 1998/08/03 20:03:26 davem Exp $ * linux/arch/sparc64/kernel/sys_sparc.c * * This file contains various random system calls that @@ -38,17 +38,9 @@ extern asmlinkage unsigned long sys_brk(unsigned long brk); asmlinkage unsigned long sparc_brk(unsigned long brk) { - unsigned long ret; - - lock_kernel(); - if(brk >= 0x80000000000UL) { /* VM hole */ - ret = current->mm->brk; - goto out; - } - ret = sys_brk(brk); -out: - unlock_kernel(); - return ret; + if(brk >= 0x80000000000UL) /* VM hole */ + return current->mm->brk; + return sys_brk(brk); } /* @@ -129,16 +121,6 @@ asmlinkage int sys_ipc (unsigned call, int first, int second, unsigned long thir if (call <= SHMCTL) switch (call) { case SHMAT: - if (first >= 0) { - extern struct shmid_ds *shm_segs[]; - struct shmid_ds *shp = shm_segs[(unsigned int) first % SHMMNI]; - if (shp == IPC_UNUSED || shp == IPC_NOID) { - err = -ENOMEM; - if ((unsigned long)ptr >= 0x80000000000UL - shp->shm_segsz && - (unsigned long)ptr < 0xfffff80000000000UL) - goto out; /* Somebody is trying to fool us */ - } - } err = sys_shmat (first, (char *) ptr, second, (ulong *) third); goto out; case SHMDT: @@ -161,8 +143,6 @@ out: return err; } -extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); - /* Linux version of mmap */ asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, @@ -245,15 +225,23 @@ extern void check_pending(int signum); asmlinkage int sys_getdomainname(char *name, int len) { - int nlen = strlen(system_utsname.domainname); + int nlen; + int err = -EFAULT; + + down(&uts_sem); + + nlen = strlen(system_utsname.domainname) + 1; if (nlen < len) len = nlen; if(len > __NEW_UTS_LEN) - return -EFAULT; + goto done; if(copy_to_user(name, system_utsname.domainname, len)) - return -EFAULT; - return 0; + goto done; + err = 0; +done: + up(&uts_sem); + return err; } /* only AP+ systems have sys_aplib */ diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index caad42736..a5043b3ac 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.77 1998/03/29 10:10:50 davem Exp $ +/* $Id: sys_sparc32.c,v 1.90 1998/07/29 16:32:30 jj Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -58,27 +58,10 @@ */ #define A(x) ((unsigned long)x) -extern char * getname_quicklist; -extern int getname_quickcount; -extern struct semaphore getname_quicklock; - -/* Tuning: increase locality by reusing same pages again... - * if getname_quicklist becomes too long on low memory machines, either a limit - * should be added or after a number of cycles some pages should - * be released again ... - */ static inline char * get_page(void) { char * res; - down(&getname_quicklock); - res = getname_quicklist; - if (res) { - getname_quicklist = *(char**)res; - getname_quickcount--; - } - else - res = (char*)__get_free_page(GFP_KERNEL); - up(&getname_quicklock); + res = (char *)__get_free_page(GFP_KERNEL); return res; } @@ -845,9 +828,6 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count) ret = do_readv_writev32(VERIFY_WRITE, file, (struct iovec32 *)A(vector), count); - if (ret > 0) - current->io_usage += ret; - out: fput(file); bad_file: @@ -872,9 +852,6 @@ asmlinkage long sys32_writev(int fd, u32 vector, u32 count) ret = do_readv_writev32(VERIFY_READ, file, (struct iovec32 *)A(vector), count); up(&file->f_dentry->d_inode->i_sem); - if (ret > 0) - current->io_usage += ret; - out: fput(file); bad_file: @@ -1148,6 +1125,7 @@ asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp_x) put_user(sec, &tvp->tv_sec); put_user(usec, &tvp->tv_usec); } + current->timeout = 0; if (ret < 0) goto out; @@ -1247,27 +1225,6 @@ asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf) return ret; } -extern asmlinkage int sys_xstat(int ver, char *filename, struct stat64 * statbuf); - -asmlinkage int sys32_xstat(int ver, u32 file, u32 statbuf) -{ - switch (ver & __XSTAT_VER_MASK) { - case __XSTAT_VER_1: - switch (ver & __XSTAT_VER_TYPEMASK) { - case __XSTAT_VER_XSTAT: - return sys32_newstat(file, statbuf); - case __XSTAT_VER_LXSTAT: - return sys32_newlstat(file, statbuf); - case __XSTAT_VER_FXSTAT: - return sys32_newfstat(file, statbuf); - } - return -EINVAL; - case __XSTAT_VER_2: - return sys_xstat(ver, (char *)A(file), (struct stat64 *)A(statbuf)); - } - return -EINVAL; -} - extern asmlinkage int sys_sysfs(int option, unsigned long arg1, unsigned long arg2); asmlinkage int sys32_sysfs(int option, u32 arg1, u32 arg2) @@ -2662,7 +2619,8 @@ asmlinkage int sparc32_execve(struct pt_regs *regs) if(!error) { fprs_write(0); - regs->fprs = 0; + current->tss.xfsr[0] = 0; + current->tss.fpsaved[0] = 0; regs->tstate &= ~TSTATE_PEF; } out: @@ -2703,119 +2661,274 @@ struct module_info32 { s32 usecount; }; -extern asmlinkage int sys_query_module(const char *name_user, int which, char *buf, size_t bufsize, size_t *ret); +/* Query various bits about modules. */ + +extern long get_mod_name(const char *user_name, char **buf); +extern void put_mod_name(char *buf); +extern struct module *find_module(const char *name); +extern struct module kernel_module; -asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 retv) +static int +qm_modules(char *buf, size_t bufsize, __kernel_size_t32 *ret) { - char *buff; - mm_segment_t old_fs = get_fs(); - size_t val; - int ret, i, j; - unsigned long *p; - char *usernam = NULL; - int bufsiz = bufsize; - struct module_info mi; - - switch (which) { - case 0: return sys_query_module ((const char *)A(name_user), which, (char *)A(buf), (size_t)bufsize, (size_t *)A(retv)); - case QM_SYMBOLS: - bufsiz <<= 1; - case QM_MODULES: - case QM_REFS: - case QM_DEPS: - if (name_user) { - usernam = getname32 (name_user); - ret = PTR_ERR(usernam); - if (IS_ERR(usernam)) - return ret; - } - buff = kmalloc (bufsiz, GFP_KERNEL); - if (!buff) { - if (name_user) putname32 (usernam); - return -ENOMEM; + struct module *mod; + size_t nmod, space, len; + + nmod = space = 0; + + for (mod=module_list; mod != &kernel_module; mod=mod->next, ++nmod) { + len = strlen(mod->name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, mod->name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nmod, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((mod = mod->next) != &kernel_module) + space += strlen(mod->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_deps(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t i, space, len; + + if (mod == &kernel_module) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (i = 0; i < mod->ndeps; ++i) { + const char *dep_name = mod->deps[i].dep->name; + + len = strlen(dep_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, dep_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while (++i < mod->ndeps) + space += strlen(mod->deps[i].dep->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static int +qm_refs(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t nrefs, space, len; + struct module_ref *ref; + + if (mod == &kernel_module) + return -EINVAL; + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = 0; + for (nrefs = 0, ref = mod->refs; ref ; ++nrefs, ref = ref->next_ref) { + const char *ref_name = ref->ref->name; + + len = strlen(ref_name)+1; + if (len > bufsize) + goto calc_space_needed; + if (copy_to_user(buf, ref_name, len)) + return -EFAULT; + buf += len; + bufsize -= len; + space += len; + } + + if (put_user(nrefs, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + space += len; + while ((ref = ref->next_ref) != NULL) + space += strlen(ref->ref->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_symbols(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + size_t i, space, len; + struct module_symbol *s; + char *strings; + unsigned *vals; + + if ((mod->flags & (MOD_RUNNING | MOD_DELETED)) != MOD_RUNNING) + if (put_user(0, ret)) + return -EFAULT; + else + return 0; + + space = mod->nsyms * 2*sizeof(u32); + + i = len = 0; + s = mod->syms; + + if (space > bufsize) + goto calc_space_needed; + + if (!access_ok(VERIFY_WRITE, buf, space)) + return -EFAULT; + + bufsize -= space; + vals = (unsigned *)buf; + strings = buf+space; + + for (; i < mod->nsyms ; ++i, ++s, vals += 2) { + len = strlen(s->name)+1; + if (len > bufsize) + goto calc_space_needed; + + if (copy_to_user(strings, s->name, len) + || __put_user(s->value, vals+0) + || __put_user(space, vals+1)) + return -EFAULT; + + strings += len; + bufsize -= len; + space += len; + } + + if (put_user(i, ret)) + return -EFAULT; + else + return 0; + +calc_space_needed: + for (; i < mod->nsyms; ++i, ++s) + space += strlen(s->name)+1; + + if (put_user(space, ret)) + return -EFAULT; + else + return -ENOSPC; +} + +static inline int +qm_info(struct module *mod, char *buf, size_t bufsize, __kernel_size_t32 *ret) +{ + int error = 0; + + if (mod == &kernel_module) + return -EINVAL; + + if (sizeof(struct module_info32) <= bufsize) { + struct module_info32 info; + info.addr = (unsigned long)mod; + info.size = mod->size; + info.flags = mod->flags; + info.usecount = (mod_member_present(mod, can_unload) + && mod->can_unload ? -1 : mod->usecount); + + if (copy_to_user(buf, &info, sizeof(struct module_info32))) + return -EFAULT; + } else + error = -ENOSPC; + + if (put_user(sizeof(struct module_info32), ret)) + return -EFAULT; + + return error; +} + +asmlinkage int sys32_query_module(u32 name_user, int which, u32 buf, __kernel_size_t32 bufsize, u32 ret) +{ + struct module *mod; + int err; + + lock_kernel(); + if (name_user == 0) + mod = &kernel_module; + else { + long namelen; + char *name; + + if ((namelen = get_mod_name((char *)A(name_user), &name)) < 0) { + err = namelen; + goto out; } -qmsym_toshort: - set_fs (KERNEL_DS); - ret = sys_query_module (usernam, which, buff, bufsiz, &val); - set_fs (old_fs); - if (which != QM_SYMBOLS) { - if (ret == -ENOSPC || !ret) { - if (put_user (val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - if (!ret) { - if (copy_to_user ((char *)A(buf), buff, bufsize)) - ret = -EFAULT; - } - } else { - if (ret == -ENOSPC) { - if (put_user (2 * val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - p = (unsigned long *)buff; - if (!ret) { - if (put_user (val, (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - } - if (!ret) { - j = val * 8; - for (i = 0; i < val; i++, p += 2) { - if (bufsize < (2 * sizeof (u32))) { - bufsiz = 0; - goto qmsym_toshort; - } - if (put_user (p[0], (u32 *)A(buf)) || - __put_user (p[1] - j, (((u32 *)A(buf))+1))) { - ret = -EFAULT; - break; - } - bufsize -= (2 * sizeof (u32)); - buf += (2 * sizeof (u32)); - } - } - if (!ret && val) { - char *strings = buff + ((unsigned long *)buff)[1]; - j = *(p - 1) - ((unsigned long *)buff)[1]; - j = j + strlen (strings + j) + 1; - if (bufsize < j) { - bufsiz = 0; - goto qmsym_toshort; - } - if (copy_to_user ((char *)A(buf), strings, j)) - ret = -EFAULT; - } + err = -ENOENT; + if (namelen == 0) + mod = &kernel_module; + else if ((mod = find_module(name)) == NULL) { + put_mod_name(name); + goto out; } - kfree (buff); - if (name_user) putname32 (usernam); - return ret; + put_mod_name(name); + } + + switch (which) + { + case 0: + err = 0; + break; + case QM_MODULES: + err = qm_modules((char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_DEPS: + err = qm_deps(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_REFS: + err = qm_refs(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; + case QM_SYMBOLS: + err = qm_symbols(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; case QM_INFO: - if (name_user) { - usernam = getname32 (name_user); - ret = PTR_ERR(usernam); - if (IS_ERR(usernam)) - return ret; - } - set_fs (KERNEL_DS); - ret = sys_query_module (usernam, which, (char *)&mi, sizeof (mi), &val); - set_fs (old_fs); - if (!ret) { - if (put_user (sizeof (struct module_info32), (__kernel_size_t32 *)A(retv))) - ret = -EFAULT; - else if (bufsize < sizeof (struct module_info32)) - ret = -ENOSPC; - } - if (!ret) { - if (put_user (mi.addr, &(((struct module_info32 *)A(buf))->addr)) || - __put_user (mi.size, &(((struct module_info32 *)A(buf))->size)) || - __put_user (mi.flags, &(((struct module_info32 *)A(buf))->flags)) || - __put_user (mi.usecount, &(((struct module_info32 *)A(buf))->usecount))) - ret = -EFAULT; - } - if (name_user) putname32 (usernam); - return ret; + err = qm_info(mod, (char *)A(buf), bufsize, (__kernel_size_t32 *)A(ret)); + break; default: - return -EINVAL; + err = -EINVAL; + break; } +out: + unlock_kernel(); + return err; } struct kernel_sym32 { @@ -3356,3 +3469,24 @@ asmlinkage int sys32_personality(unsigned long personality) ret = PER_LINUX; return ret; } + +extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count); + +asmlinkage int sys32_sendfile(int out_fd, int in_fd, u32 offset, s32 count) +{ + mm_segment_t old_fs = get_fs(); + int ret; + off_t of; + + if (offset && get_user(of, (__kernel_off_t32 *)A(offset))) + return -EFAULT; + + set_fs(KERNEL_DS); + ret = sys_sendfile(out_fd, in_fd, offset ? &of : NULL, count); + set_fs(old_fs); + + if (!ret && offset && put_user(of, (__kernel_off_t32 *)A(offset))) + return -EFAULT; + + return ret; +} diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c index ad7bac534..ec965972f 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.11 1998/03/29 10:10:55 davem Exp $ +/* $Id: sys_sunos32.c,v 1.16 1998/06/16 04:37:06 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -56,8 +56,6 @@ #define SUNOS_NR_OPEN 256 -extern unsigned long get_unmapped_area(unsigned long addr, unsigned long len); - asmlinkage u32 sunos_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off) { struct file *file = NULL; @@ -259,12 +257,12 @@ asmlinkage void sunos_madvise(u32 address, u32 len, u32 strategy) * *or* the passed base address is not aligned on a page boundary you * get an error. */ -asmlinkage int sunos_mincore(u32 addr, u32 len, u32 u_array) +asmlinkage int sunos_mincore(u32 __addr, u32 len, u32 u_array) { pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; - unsigned long limit; + unsigned long limit, addr = (unsigned long)__addr; int num_pages, pnum, retval = -EINVAL; char *array = (char *)A(u_array); @@ -523,26 +521,6 @@ out: return error; } -asmlinkage int sunos_getdomainname(u32 u_name, int len) -{ - int nlen = strlen(system_utsname.domainname); - int ret = -EFAULT; - char *name = (char *)A(u_name); - - lock_kernel(); - if (nlen < len) - len = nlen; - - if(len > __NEW_UTS_LEN) - goto out; - if(copy_to_user(name, system_utsname.domainname, len)) - goto out; - ret = 0; -out: - unlock_kernel(); - return ret; -} - struct sunos_utsname { char sname[9]; char nname[9]; @@ -557,7 +535,7 @@ asmlinkage int sunos_uname(u32 u_name) struct sunos_utsname *name = (struct sunos_utsname *)A(u_name); int ret = -EFAULT; - lock_kernel(); + down(&uts_sem); if(!name) goto out; if(copy_to_user(&name->sname[0], @@ -573,7 +551,7 @@ asmlinkage int sunos_uname(u32 u_name) copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); ret = 0; out: - unlock_kernel(); + up(&uts_sem); return ret; } diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 6389681dd..beed61bd7 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.41 1998/03/24 05:57:57 ecd Exp $ +/* $Id: systbls.S,v 1.47 1998/07/28 13:07:55 jj Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -17,14 +17,14 @@ .globl sys_call_table32 sys_call_table32: -/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write +/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys32_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_xstat, sys32_mknod -/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_xmknod, sys32_lseek -/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys32_pause +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys32_mknod +/*15*/ .word sys32_chmod, sys32_lchown, sparc_brk, sys_nis_syscall, sys32_lseek +/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice - .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys_nis_syscall + .word sys_nis_syscall, sys_sync, sys_kill, sys32_newstat, sys32_sendfile /*40*/ .word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl @@ -40,11 +40,11 @@ sys_call_table32: /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending .word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd /*120*/ .word sys32_readv, sys32_writev, sys32_settimeofday, sys_fchown, sys_fchmod .word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall + .word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit .word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write /*150*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall @@ -65,8 +65,8 @@ sys_call_table32: .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid /*230*/ .word sys32_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall .word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall -/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep +/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler + .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl .word sys_aplib @@ -76,14 +76,14 @@ sys_call_table32: .globl sys_call_table64, sys_call_table sys_call_table64: sys_call_table: -/*0*/ .word sys_setup, sys_exit, sys_fork, sys_read, sys_write +/*0*/ .word sys_setup, sparc_exit, sys_fork, sys_read, sys_write /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_xstat, sys_mknod -/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_xmknod, sys_lseek -/*20*/ .word sys_getpid, sys_nis_syscall, sys_nis_syscall, sys_setuid, sys_getuid -/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_nis_syscall, sys_nis_syscall +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_nis_syscall, sys_mknod +/*15*/ .word sys_chmod, sys_lchown, sparc_brk, sys_nis_syscall, sys_lseek +/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid +/*25*/ .word sys_time, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice - .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_nis_syscall + .word sys_nis_syscall, sys_sync, sys_kill, sys_newstat, sys_sendfile /*40*/ .word sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall .word sys_nis_syscall, sys_setgid, sys_getgid, sys_signal, sys_geteuid /*50*/ .word sys_getegid, sys_acct, sys_memory_ordering, sys_nis_syscall, sys_ioctl @@ -99,11 +99,11 @@ sys_call_table: /*100*/ .word sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending .word sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_nis_syscall, sys_nis_syscall /*110*/ .word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_recvmsg, sys_sendmsg - .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_nis_syscall + .word sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd /*120*/ .word sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod .word sys_recvfrom, sys_setreuid, sys_setregid, sys_rename, sys_truncate /*130*/ .word sys_ftruncate, sys_flock, sys_nis_syscall, sys_sendto, sys_shutdown - .word sys_socketpair, sys_mkdir, sys_rmdir, sys_nis_syscall, sys_nis_syscall + .word sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_nis_syscall /*140*/ .word sys_nis_syscall, sys_getpeername, sys_nis_syscall, sys_nis_syscall, sys_getrlimit .word sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write /*150*/ .word sys_getsockname, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall @@ -124,8 +124,8 @@ sys_call_table: .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 -/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_nis_syscall, sys_nis_syscall - .word sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep +/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler + .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_aplib @@ -134,7 +134,7 @@ sys_call_table: .align 1024 .globl sunos_sys_table sunos_sys_table: -/*0*/ .word sunos_indir, sys_exit, sys_fork +/*0*/ .word sunos_indir, sparc_exit, sys_fork .word sunos_read, sunos_write, sunos_open .word sys_close, sunos_wait4, sys_creat .word sys_link, sys_unlink, sunos_execv @@ -189,7 +189,7 @@ sunos_sys_table: .word sys_poll, sunos_nosys, sunos_nosys .word sunos_getdirentries, sys32_statfs, sys32_fstatfs .word sys_umount, sunos_nosys, sunos_nosys - .word sunos_getdomainname, sys_setdomainname + .word sys_getdomainname, sys_setdomainname .word sunos_nosys, sys32_quotactl, sunos_nosys .word sunos_mount, sys_ustat, sunos_semsys .word sunos_nosys, sunos_shmsys, sunos_audit diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index debb08888..364f2b4a1 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1,4 +1,4 @@ -/* $Id: time.c,v 1.13 1998/03/15 17:23:47 ecd Exp $ +/* $Id: time.c,v 1.15 1998/05/12 22:38:29 ecd Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -227,13 +227,17 @@ __initfunc(void clock_probe(void)) struct linux_prom_registers clk_reg[2]; char model[128]; int node, busnd = -1, err; +#ifdef CONFIG_PCI + struct linux_ebus *ebus = 0; +#endif if(central_bus != NULL) { busnd = central_bus->child->prom_node; } #ifdef CONFIG_PCI else if (ebus_chain != NULL) { - busnd = ebus_chain->prom_node; + ebus = ebus_chain; + busnd = ebus->prom_node; } #endif else { @@ -253,6 +257,15 @@ __initfunc(void clock_probe(void)) strcmp(model, "mk48t08") && strcmp(model, "mk48t59")) { node = prom_getsibling(node); +#ifdef CONFIG_PCI + if ((node == 0) && ebus) { + ebus = ebus->next; + if (ebus) { + busnd = ebus->prom_node; + node = prom_getchild(busnd); + } + } +#endif if(node == 0) { prom_printf("clock_probe: Cannot find timer chip\n"); prom_halt(); @@ -275,7 +288,7 @@ __initfunc(void clock_probe(void)) else if (ebus_chain) { struct linux_ebus_device *edev; - for_each_ebusdev(edev, ebus_chain) + for_each_ebusdev(edev, ebus) if (edev->prom_node == node) break; if (!edev) { diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S index 8604b3301..797d4047e 100644 --- a/arch/sparc64/kernel/trampoline.S +++ b/arch/sparc64/kernel/trampoline.S @@ -1,4 +1,4 @@ -/* $Id: trampoline.S,v 1.3 1998/02/22 21:06:11 jj Exp $ +/* $Id: trampoline.S,v 1.5 1998/05/25 05:31:45 davem Exp $ * trampoline.S: Jump start slave processors on sparc64. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -172,13 +172,29 @@ bounce: mov %o2, %g6 wrpr %o1, (PSTATE_MG | PSTATE_IE), %pstate -#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) - sethi %uhi(KERN_HIGHBITS), %g2 - sllx %g2, 32, %g2 -#undef KERN_HIGHBITS - ldx [%o2 + AOFF_task_mm], %g6 - ldx [%g6 + AOFF_mm_pgd], %g6 +#define KERN_HIGHBITS ((_PAGE_VALID | _PAGE_SZ4MB) ^ 0xfffff80000000000) +#define KERN_LOWBITS (_PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_W) +#ifdef THIS_IS_CHEETAH +#error Dave, make sure you took care of other issues in rest of sparc64 code... +#define VPTE_BASE 0xffe0000000000000 +#else /* Spitfire/Blackbird */ +#define VPTE_BASE 0xfffffffe00000000 +#endif + mov TSB_REG, %g1 + stxa %g0, [%g1] ASI_DMMU + membar #Sync + mov TLB_SFSR, %g1 + sethi %uhi(KERN_HIGHBITS), %g2 + or %g2, %ulo(KERN_HIGHBITS), %g2 + sllx %g2, 32, %g2 + or %g2, KERN_LOWBITS, %g2 + sethi %uhi(VPTE_BASE), %g3 + or %g3, %ulo(VPTE_BASE), %g3 + sllx %g3, 32, %g3 clr %g7 +#undef KERN_HIGHBITS +#undef KERN_LOWBITS +#undef VPTE_BASE wrpr %o1, (PSTATE_IG | PSTATE_IE), %pstate sethi %hi(ivector_to_mask), %g5 @@ -186,14 +202,6 @@ bounce: mov 0x40, %g2 wrpr %g0, 0, %wstate - wrpr %o1, PSTATE_IE, %pstate - - mov TSB_REG, %o4 - mov 1, %o5 - stxa %o5, [%o4] ASI_DMMU - stxa %o5, [%o4] ASI_IMMU - membar #Sync - or %o1, PSTATE_IE, %o1 wrpr %o1, 0, %pstate diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 069e908d0..e1d652841 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.49 1998/04/06 16:09:38 jj Exp $ +/* $Id: traps.c,v 1.51 1998/06/12 14:54:20 jj Exp $ * arch/sparc64/kernel/traps.c * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -316,10 +316,10 @@ void do_fpe_common(struct pt_regs *regs) void do_fpieee(struct pt_regs *regs) { -#ifdef DEBUG_FPU - struct fpustate *f = FPUSTATE; - - printk("fpieee %016lx\n", f->fsr); +#ifdef DEBUG_FPU + save_and_clear_fpu(); + + printk("fpieee %016lx\n", current->tss.xfsr[0]); #endif do_fpe_common(regs); } @@ -331,7 +331,8 @@ void do_fpother(struct pt_regs *regs) struct fpustate *f = FPUSTATE; int ret = 0; - switch ((f->fsr & 0x1c000)) { + save_and_clear_fpu(); + switch ((current->tss.xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ ret = do_mathemu(regs, f); @@ -339,7 +340,7 @@ void do_fpother(struct pt_regs *regs) } if (ret) return; #ifdef DEBUG_FPU - printk("fpother %016lx\n", f->fsr); + printk("fpother %016lx\n", current->tss.xfsr[0]); #endif do_fpe_common(regs); } diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S index 3d17fb3cb..87f282fa1 100644 --- a/arch/sparc64/kernel/ttable.S +++ b/arch/sparc64/kernel/ttable.S @@ -1,4 +1,4 @@ -/* $Id: ttable.S,v 1.23 1998/03/15 17:23:48 ecd Exp $ +/* $Id: ttable.S,v 1.25 1998/05/23 18:24:53 jj Exp $ * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -6,7 +6,7 @@ #include <linux/config.h> - .globl sparc64_ttable_tl0, tl0_itick, sparc64_ttable_tl1, + .globl sparc64_ttable_tl0, sparc64_ttable_tl1, sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) @@ -45,7 +45,11 @@ tl0_irq7: TRAP_IRQ(handler_irq, 7) TRAP_IRQ(handler_irq, 8) tl0_irq9: TRAP_IRQ(handler_irq, 9) TRAP_IRQ(handler_irq, 10) tl0_irq11: TRAP_IRQ(handler_irq, 11) TRAP_IRQ(handler_irq, 12) tl0_irq13: TRAP_IRQ(handler_irq, 13) -tl0_itick: TRAP_IRQ(handler_irq, 14) +#ifndef __SMP__ +tl0_irq14: TRAP_IRQ(handler_irq, 14) +#else +tl0_irq14: TICK_SMP_IRQ +#endif tl0_irq15: TRAP_IRQ(handler_irq, 15) tl0_resv050: BTRAP(0x50) BTRAP(0x51) BTRAP(0x52) BTRAP(0x53) BTRAP(0x54) BTRAP(0x55) tl0_resv056: BTRAP(0x56) BTRAP(0x57) BTRAP(0x58) BTRAP(0x59) BTRAP(0x5a) BTRAP(0x5b) @@ -55,9 +59,9 @@ tl0_paw: TRAP(do_paw) tl0_vaw: TRAP(do_vaw) tl0_cee: TRAP(do_cee) tl0_iamiss: -#include "itlb_miss.S" +#include "itlb_base.S" tl0_damiss: -#include "dtlb_miss.S" +#include "dtlb_base.S" tl0_daprot: #include "dtlb_prot.S" tl0_resv070: BTRAP(0x70) BTRAP(0x71) BTRAP(0x72) BTRAP(0x73) BTRAP(0x74) BTRAP(0x75) @@ -199,10 +203,9 @@ tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) tl1_cee: TRAPTL1(do_cee_tl1) -tl1_iamiss: -#include "itlb_miss.S" +tl1_iamiss: BTRAPTL1(0x64) BTRAPTL1(0x65) BTRAPTL1(0x66) BTRAPTL1(0x67) tl1_damiss: -#include "dtlb_miss.S" +#include "dtlb_backend.S" tl1_daprot: #include "dtlb_prot.S" tl1_resv070: BTRAPTL1(0x70) BTRAPTL1(0x71) BTRAPTL1(0x72) BTRAPTL1(0x73) diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index 1c433d793..50de6cfd5 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -1,4 +1,4 @@ -/* $Id: unaligned.c,v 1.8 1997/10/14 16:21:24 jj Exp $ +/* $Id: unaligned.c,v 1.10 1998/06/19 13:00:32 jj Exp $ * unaligned.c: Unaligned load/store trap handling with special * cases for the kernel to do them more quickly. * @@ -453,7 +453,7 @@ int handle_popc(u32 insn, struct pt_regs *regs) } else { struct reg_window *win; win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS); - get_user(ret, &win->locals[rd - 16]); + put_user(ret, &win->locals[rd - 16]); } } advance(regs); @@ -470,11 +470,12 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs) int freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); struct fpustate *f = FPUSTATE; int asi = decode_asi(insn, regs); - int flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + int flag = (freg < 32) ? FPRS_DL : FPRS_DU; - f->fsr &= ~0x1c000; + save_and_clear_fpu(); + current->tss.xfsr[0] &= ~0x1c000; if (freg & 3) { - f->fsr |= (6 << 14) /* invalid_fp_register */; + current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; do_fpother(regs); return 0; } @@ -482,7 +483,7 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs) /* STQ */ u64 first = 0, second = 0; - if (current->tss.flags & flag) { + if (current->tss.fpsaved[0] & flag) { first = *(u64 *)&f->regs[freg]; second = *(u64 *)&f->regs[freg+2]; } @@ -545,13 +546,11 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs) second = le32_to_cpup(&third); third = tmp; } - regs->fprs |= FPRS_FEF; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { - current->tss.flags |= SPARC_FLAG_USEDFPU; - f->fsr = 0; - f->gsr = 0; + if (!(current->tss.fpsaved[0] & FPRS_FEF)) { + current->tss.fpsaved[0] = FPRS_FEF; + current->tss.gsr[0] = 0; } - if (!(current->tss.flags & flag)) { + if (!(current->tss.fpsaved[0] & flag)) { if (freg < 32) memset(f->regs, 0, 32*sizeof(u32)); else @@ -561,7 +560,7 @@ int handle_ldq_stq(u32 insn, struct pt_regs *regs) f->regs[freg+1] = second; f->regs[freg+2] = third; f->regs[freg+3] = fourth; - current->tss.flags |= flag; + current->tss.fpsaved[0] |= flag; } advance(regs); return 1; @@ -593,25 +592,24 @@ void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr } else goto daex; } + save_and_clear_fpu(); freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); value = (((u64)first) << 32) | second; if (asi & 0x8) /* Little */ value = __swab64p(&value); - flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; - regs->fprs |= FPRS_FEF; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { - current->tss.flags |= SPARC_FLAG_USEDFPU; - f->fsr = 0; - f->gsr = 0; + 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->tss.flags & flag)) { + if (!(current->tss.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.flags |= flag; + current->tss.fpsaved[0] |= flag; } else { daex: data_access_exception(regs); return; @@ -638,10 +636,11 @@ void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr freg = ((insn >> 25) & 0x1e) | ((insn >> 20) & 0x20); asi = sfsr >> 16; value = 0; - flag = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; + flag = (freg < 32) ? FPRS_DL : FPRS_DU; if (asi > ASI_SNFL) goto daex; - if (current->tss.flags & flag) + save_and_clear_fpu(); + if (current->tss.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 6e3f6193a..fd75011fd 100644 --- a/arch/sparc64/kernel/winfixup.S +++ b/arch/sparc64/kernel/winfixup.S @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.22 1997/10/24 11:57:48 jj Exp $ +/* $Id: winfixup.S,v 1.24 1998/06/12 14:54:19 jj Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -60,15 +60,14 @@ fill_fixup: sll %g2, 3, %g2 ! NORMAL-->OTHER wrpr %g0, 0x0, %canrestore ! Standard etrap stuff. - wr %g0, 0x0, %fprs ! zap FPU just in case... wrpr %g2, 0x0, %wstate ! This must be consistant. wrpr %g0, 0x0, %otherwin ! We know this. mov PRIMARY_CONTEXT, %g1 ! Change contexts... stxa %g0, [%g1] ASI_DMMU ! Back into the nucleus. flush %g6 ! Flush instruction buffers rdpr %pstate, %l1 ! Prepare to change globals. - mov %g6, %o7 ! Get current. + andn %l1, PSTATE_MM, %l1 ! We want to be in RMO srlx %g5, PAGE_SHIFT, %o1 ! Fault address wrpr %g0, 0x0, %tl ! Out of trap levels. @@ -166,12 +165,6 @@ window_scheisse_from_user_common: add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 -winfix_trampoline: - andn %g3, 0x7f, %g3 - add %g3, 0x7c, %g3 - - wrpr %g3, %tnpc - done .globl winfix_mna, fill_fixup_mna, spill_fixup_mna winfix_mna: diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index 9f8729ee5..a580f7ae4 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.15 1997/08/19 03:11:50 davem Exp $ +# $Id: Makefile,v 1.16 1998/06/12 14:53:53 jj Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ CFLAGS := $(CFLAGS) OBJS = PeeCeeI.o blockops.o locks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o + VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o VISsave.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff --git a/arch/sparc64/lib/VISbzero.S b/arch/sparc64/lib/VISbzero.S index ede87843b..3992da997 100644 --- a/arch/sparc64/lib/VISbzero.S +++ b/arch/sparc64/lib/VISbzero.S @@ -1,4 +1,4 @@ -/* $Id: VISbzero.S,v 1.8 1997/08/22 15:54:50 jj Exp $ +/* $Id: VISbzero.S,v 1.9 1998/06/12 14:53:50 jj Exp $ * VISbzero.S: High speed clear operations utilizing the UltraSparc * Visual Instruction Set. * @@ -9,6 +9,8 @@ #include "VIS.h" #ifdef __KERNEL__ +#include <asm/visasm.h> + #define EXN(x,y,a,b,z) \ 98: x,y; \ .section .fixup; \ @@ -141,9 +143,9 @@ bzero: 6: andncc %o1, 0x3f, %o3 7: be,pn %xcc, 9f #ifdef __KERNEL__ - rd %asi, %g7 - wr %g0, FPRS_FEF, %fprs - wr %g7, ASI_BLK_XOR, %asi + rd %asi, %o4 + wr %o4, ASI_BLK_XOR, %asi + VISEntryHalf #else wr %g0, ASI_BLK_P, %asi #endif @@ -178,8 +180,8 @@ bzero: add %o0, 256, %o0 12: #ifdef __KERNEL__ - wr %g0, 0, %fprs - wr %g7, 0x0, %asi + VISExitHalf + wr %o4, 0x0, %asi #else #ifndef REGS_64BIT wr %g0, FPRS_FEF, %fprs diff --git a/arch/sparc64/lib/VIScopy.S b/arch/sparc64/lib/VIScopy.S index 40b781e73..7f2f497cd 100644 --- a/arch/sparc64/lib/VIScopy.S +++ b/arch/sparc64/lib/VIScopy.S @@ -1,9 +1,9 @@ -/* $Id: VIScopy.S,v 1.14 1997/08/22 15:54:53 jj Exp $ +/* $Id: VIScopy.S,v 1.18 1998/06/12 14:53:55 jj Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1996, 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) */ #include "VIS.h" @@ -24,12 +24,15 @@ */ #ifdef __KERNEL__ + +#include <asm/visasm.h> + #define FPU_CLEAN_RETL \ - wr %g0, 0, %fprs; \ + VISExit \ retl; \ clr %o0; #define FPU_RETL \ - wr %g0, 0, %fprs; \ + VISExit \ retl; \ clr %o0; #define NORMAL_RETL \ @@ -40,7 +43,7 @@ .section .fixup; \ .align 4; \ 99: ba VIScopyfixup_ret; \ - a, b, %o0; \ + a, b, %o1; \ .section __ex_table; \ .align 4; \ .word 98b, 99b; \ @@ -52,7 +55,7 @@ .align 4; \ 99: c, d, e; \ ba VIScopyfixup_ret; \ - a, b, %o0; \ + a, b, %o1; \ .section __ex_table; \ .align 4; \ .word 98b, 99b; \ @@ -298,10 +301,6 @@ .globl __memcpy_entry .type __memcpy_entry,@function - - .globl copy_page - .type copy_page,@function - memcpy_private: __memcpy: memcpy: mov ASI_BLK_P, asi_src ! IEU0 Group @@ -310,12 +309,6 @@ memcpy: mov ASI_BLK_P, asi_src ! IEU0 Group retl clr %o0 -copy_page: wr %g0, FPRS_FEF, %fprs ! FPU Group - sethi %hi(8192), %o2 ! IEU0 Group - mov ASI_BLK_P, asi_src ! IEU1 - b,pt %xcc, dest_is_64byte_aligned ! CTI - mov ASI_BLK_P, asi_dest ! IEU0 Group - .align 32 .globl __copy_from_user .type __copy_from_user,@function @@ -355,7 +348,11 @@ __memcpy_384plus: #endif VIS_enter: be,pt %xcc, dest_is_8byte_aligned ! CTI +#ifdef __KERNEL__ + nop ! IEU0 Group +#else andcc %o0, 0x38, %g5 ! IEU1 Group +#endif do_dest_8byte_align: mov 8, %g1 ! IEU0 sub %g1, %g2, %g2 ! IEU0 Group @@ -377,7 +374,8 @@ do_dest_8byte_align: EX(LDUB [%o1] ASINORMAL, %o5, add %o2, %g2) ! Load Group add %o0, 2, %o0 ! IEU0 - EX(LDUB [%o1 + 1] ASINORMAL, %g3, + EX2(LDUB [%o1 + 1] ASINORMAL, %g3, + sub %o0, 2, %o0, add %o2, %g2) ! Load Group ASI_SETDST_NOBLK ! LSU Group subcc %g2, 2, %g2 ! IEU1 Group @@ -389,17 +387,17 @@ do_dest_8byte_align: EX2(STB %g3, [%o0 - 1] ASINORMAL, add %g2, 1, %g2, add %o2, %g2) ! Store -3: andcc %o0, 0x38, %g5 ! IEU1 Group -dest_is_8byte_aligned: - be,pt %icc, dest_is_64byte_aligned ! CTI #ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs ! FPU Group -do_dest_64byte_align: - mov 64, %g1 ! IEU0 Group +3: +dest_is_8byte_aligned: + VISEntry + andcc %o0, 0x38, %g5 ! IEU1 Group #else - mov 64, %g1 ! IEU0 Group -do_dest_64byte_align: +3: andcc %o0, 0x38, %g5 ! IEU1 Group +dest_is_8byte_aligned: #endif + be,pt %icc, dest_is_64byte_aligned ! CTI + mov 64, %g1 ! IEU0 fmovd %f0, %f2 ! FPU sub %g1, %g5, %g5 ! IEU0 Group ASI_SETSRC_NOBLK ! LSU Group @@ -646,7 +644,9 @@ __memcpy_short: 2: ASI_SETSRC_NOBLK ! LSU Group EXO2(LDUB [%o1] ASINORMAL, %g5) ! LOAD Group add %o0, 2, %o0 ! IEU0 - EXO2(LDUB [%o1 + 1] ASINORMAL, %o5) ! LOAD Group + EX2(LDUB [%o1 + 1] ASINORMAL, %o5, + sub %o0, 2, %o0, + add %o2, %g0) ! LOAD Group add %o1, 2, %o1 ! IEU0 ASI_SETDST_NOBLK ! LSU Group subcc %o2, 2, %o2 ! IEU1 Group @@ -866,9 +866,9 @@ normal_retl: ASI_SETSRC_NOBLK ! LSU Group EX(LDX [%o1] ASINORMAL, %g2, and %o2, 0xf) ! Load Group - add %o1, 8, %o1 ! IEU0 + add %o0, 8, %o0 ! IEU0 ASI_SETDST_NOBLK ! LSU Group - add %o0, 8, %o0 ! IEU0 Group + add %o1, 8, %o1 ! IEU0 Group EX(STX %g2, [%o0 - 0x8] ASINORMAL, and %o2, 0xf) ! Store 85: be,pt %xcc, 1f ! CTI @@ -876,9 +876,9 @@ normal_retl: ASI_SETSRC_NOBLK ! LSU Group EX(LDUW [%o1] ASINORMAL, %g2, and %o2, 0x7) ! Load Group - add %o1, 4, %o1 ! IEU0 + add %o0, 4, %o0 ! IEU0 ASI_SETDST_NOBLK ! LSU Group - add %o0, 4, %o0 ! IEU0 Group + add %o1, 4, %o1 ! IEU0 Group EX(STW %g2, [%o0 - 0x4] ASINORMAL, and %o2, 0x7) ! Store 1: be,pt %xcc, 1f ! CTI @@ -886,9 +886,9 @@ normal_retl: ASI_SETSRC_NOBLK ! LSU Group EX(LDUH [%o1] ASINORMAL, %g2, and %o2, 0x3) ! Load Group - add %o1, 2, %o1 ! IEU0 + add %o0, 2, %o0 ! IEU0 ASI_SETDST_NOBLK ! LSU Group - add %o0, 2, %o0 ! IEU0 Group + add %o1, 2, %o1 ! IEU0 Group EX(STH %g2, [%o0 - 0x2] ASINORMAL, and %o2, 0x3) ! Store 1: be,pt %xcc, 1f ! CTI @@ -920,7 +920,7 @@ memcpy_noVIS_misaligned: add %o2, 1) ! Store 2: #ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs ! FPU Group + VISEntry #endif andn %o2, 7, %g5 ! IEU0 Group and %o2, 7, %o2 ! IEU1 @@ -976,16 +976,31 @@ fpu_retl: .section .fixup .align 4 VIScopyfixup_reto2: - mov %o2, %o0 + mov %o2, %o1 VIScopyfixup_ret: + /* If this is copy_from_user(), zero out the rest of the + * kernel buffer. + */ + andcc asi_src, 0x1, %g0 + be,pt %icc, 1f + andcc asi_dest, 0x1, %g0 + bne,pn %icc, 1f + VISExit + save %sp, -160, %sp + mov %i0, %o0 + call __bzero + mov %i1, %o1 + restore +1: mov %o1, %o0 retl - wr %g0, 0, %fprs + nop VIScopyfixup1: subcc %g2, 18, %g2 + add %o0, 32, %o0 bgeu,a,pt %icc, VIScopyfixup1 sub %g7, 32, %g7 + sub %o0, 32, %o0 rd %pc, %g5 - add %g2, 18, %g2 - add %g2, 20, %g2 + add %g2, (18 + 16), %g2 ldub [%g5 + %g2], %g2 ba,a,pt %xcc, 2f .byte 0, 0, 0, 0, 0, 0, 0, 4, 4, 8, 12, 12, 16, 20, 20, 24, 28, 28 @@ -994,41 +1009,43 @@ VIScopyfixup2: mov (7 * 16), %g7 1: subcc %g2, 10, %g2 bgeu,a,pt %icc, 1b sub %g7, 16, %g7 + sub %o0, %g7, %o0 rd %pc, %g5 - add %g2, 10, %g2 - add %g2, 20, %g2 + add %g2, (10 + 16), %g2 ldub [%g5 + %g2], %g2 ba,a,pt %xcc, 4f .byte 0, 0, 0, 0, 0, 4, 4, 8, 12, 12 .align 4 VIScopyfixup3: subcc %g2, 10, %g2 + add %o0, 32, %o0 bgeu,a,pt %icc, VIScopyfixup3 sub %g7, 32, %g7 + sub %o0, 32, %o0 rd %pc, %g5 - add %g2, 10, %g2 - add %g2, 20, %g2 + add %g2, (10 + 16), %g2 ldub [%g5 + %g2], %g2 ba,a,pt %xcc, 2f .byte 0, 0, 0, 0, 0, 0, 0, 8, 16, 24 .align 4 -2: and %g1, 0x7f, %g1 +2: and %o2, 0x7f, %o2 sub %g7, %g2, %g7 ba,pt %xcc, VIScopyfixup_ret - add %g7, %g1, %o0 + add %g7, %o2, %o1 VIScopyfixup4: mov (7 * 16), %g7 3: subcc %g2, 6, %g2 bgeu,a,pt %icc, 3b sub %g7, 16, %g7 + sub %o0, %g7, %o0 rd %pc, %g5 - add %g2, 6, %g2 - add %g2, 20, %g2 + add %g2, (6 + 16), %g2 ldub [%g5 + %g2], %g2 ba,a,pt %xcc, 4f .byte 0, 0, 0, 0, 0, 8 .align 4 -4: and %g1, 7, %g1 +4: and %o2, 0xf, %o2 + sub %g7, %g2, %g7 ba,pt %xcc, VIScopyfixup_ret - add %g7, %g1, %o0 + add %g7, %o2, %o1 VIScopyfixup_vis3: sub %o2, 0x80, %o2 VIScopyfixup_vis2: @@ -1038,13 +1055,13 @@ VIScopyfixup_vis0: VIScopyfixup_vis1: add %g7, %g3, %g7 ba,pt %xcc, VIScopyfixup_ret - add %o2, %g7, %o0 + add %o2, %g7, %o1 VIScopyfixup_vis5: add %g3, 8, %g3 VIScopyfixup_vis4: add %g3, 8, %g3 ba,pt %xcc, VIScopyfixup_ret - add %o2, %g3, %o0 + add %o2, %g3, %o1 #endif #ifdef __KERNEL__ diff --git a/arch/sparc64/lib/VIScsum.S b/arch/sparc64/lib/VIScsum.S index 81b020c49..a370bdff3 100644 --- a/arch/sparc64/lib/VIScsum.S +++ b/arch/sparc64/lib/VIScsum.S @@ -1,4 +1,4 @@ -/* $Id: VIScsum.S,v 1.2 1997/08/08 08:34:05 jj Exp $ +/* $Id: VIScsum.S,v 1.3 1998/06/12 14:53:57 jj Exp $ * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc * Visual Instruction Set. * @@ -26,6 +26,7 @@ #ifdef __KERNEL__ #include <asm/head.h> #include <asm/asi.h> +#include <asm/visasm.h> #else #define ASI_BLK_P 0xf0 #define FRPS_FEF 0x04 @@ -278,13 +279,13 @@ csum_partial: add %o2, 1, %o2 /* IEU0 */ 3: cmp %o1, 0xc0 /* IEU1 Group */ blu,pn %icc, 20f /* CTI */ - sllx %o2, 32, %g1 /* IEU0 */ - addcc %o2, %g1, %o2 /* IEU1 Group */ - sub %o1, 0xc0, %o1 /* IEU0 */ - wr %g0, ASI_BLK_P, %asi /* LSU Group */ + sllx %o2, 32, %g5 /* IEU0 */ #ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs /* LSU Group */ + VISEntry #endif + addcc %o2, %g5, %o2 /* IEU1 Group */ + sub %o1, 0xc0, %o1 /* IEU0 */ + wr %g0, ASI_BLK_P, %asi /* LSU Group */ membar #StoreLoad /* LSU Group */ srlx %o2, 32, %o2 /* IEU0 Group */ bcs,a,pn %xcc, 1f /* CTI */ @@ -340,7 +341,7 @@ csum_partial: END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) and %o1, 0x3f, %o1 /* IEU0 Group */ #ifdef __KERNEL__ - wr %g0, 0, %fprs /* LSU Group */ + VISExit #endif 20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ be,pn %icc, 23f /* CTI */ diff --git a/arch/sparc64/lib/VIScsumcopy.S b/arch/sparc64/lib/VIScsumcopy.S index fff41bab2..469b007fc 100644 --- a/arch/sparc64/lib/VIScsumcopy.S +++ b/arch/sparc64/lib/VIScsumcopy.S @@ -1,4 +1,4 @@ -/* $Id: VIScsumcopy.S,v 1.4 1998/04/01 08:29:52 davem Exp $ +/* $Id: VIScsumcopy.S,v 1.5 1998/06/12 14:53:48 jj Exp $ * VIScsumcopy.S: High bandwidth IP checksumming with simultaneous * copying utilizing the UltraSparc Visual Instruction Set. * @@ -27,6 +27,7 @@ #include <asm/head.h> #include <asm/asi.h> #include <asm/page.h> +#include <asm/visasm.h> #else #define ASI_P 0x80 #define ASI_BLK_P 0xf0 @@ -42,11 +43,11 @@ #define sum o3 #define x1 g1 #define x2 g2 -#define x3 g3 +#define x3 o4 #define x4 g4 #define x5 g5 #define x6 g7 -#define x7 o4 +#define x7 g3 #define x8 o5 /* Dobrou noc, SunSoft engineers. Spete sladce. @@ -248,7 +249,7 @@ csum_partial_copy_vis: andcc %dst, 7, %g0 /* IEU1 Group */ be,pt %icc, 4f /* CTI */ - and %dst, 0x38, %g3 /* IEU0 */ + and %dst, 0x38, %o4 /* IEU0 */ mov 1, %g5 /* IEU0 Group */ andcc %dst, 2, %g0 /* IEU1 */ be,pt %icc, 1f /* CTI */ @@ -266,18 +267,18 @@ csum_partial_copy_vis: add %sum, %g5, %sum /* IEU0 */ 1: lduwa [%src] %asi, %g2 /* Load */ brz,a,pn %g7, 4f /* CTI+IEU1 Group */ - and %dst, 0x38, %g3 /* IEU0 */ + and %dst, 0x38, %o4 /* IEU0 */ add %dst, 4, %dst /* IEU0 Group */ sub %len, 4, %len /* IEU1 */ addcc %g2, %sum, %sum /* IEU1 Group */ bcs,a,pn %icc, 1f /* CTI */ add %sum, 1, %sum /* IEU0 */ -1: and %dst, 0x38, %g3 /* IEU0 Group */ +1: and %dst, 0x38, %o4 /* IEU0 Group */ stw %g2, [%dst - 4] /* Store */ add %src, 4, %src /* IEU1 */ 4: #ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs /* LSU Group */ + VISEntry #endif mov %src, %g7 /* IEU1 Group */ fzero %f48 /* FPA */ @@ -291,10 +292,10 @@ csum_partial_copy_vis: sub %sum, 1, %sum /* IEU0 */ 1: srl %sum, 0, %sum /* IEU0 Group */ clr %g5 /* IEU1 */ - brz,pn %g3, 3f /* CTI+IEU1 Group */ - sub %g1, %g3, %g1 /* IEU0 */ + brz,pn %o4, 3f /* CTI+IEU1 Group */ + sub %g1, %o4, %g1 /* IEU0 */ ldda [%src] %asi, %f0 /* Load */ - clr %g3 /* IEU0 Group */ + clr %o4 /* IEU0 Group */ andcc %dst, 8, %g0 /* IEU1 */ be,pn %icc, 1f /* CTI */ ldda [%src + 8] %asi, %f2 /* Load Group */ @@ -303,7 +304,7 @@ csum_partial_copy_vis: fpadd32 %f0, %f48, %f50 /* FPA */ addcc %dst, 8, %dst /* IEU1 Group */ faligndata %f0, %f2, %f16 /* FPA */ - fcmpgt32 %f48, %f50, %g3 /* FPM Group */ + fcmpgt32 %f48, %f50, %o4 /* FPM Group */ fmovd %f2, %f0 /* FPA Group */ ldda [%src + 8] %asi, %f2 /* Load */ std %f16, [%dst - 8] /* Store */ @@ -318,13 +319,13 @@ csum_partial_copy_vis: faligndata %f0, %f2, %f16 /* FPA */ fcmpgt32 %f48, %f50, %g5 /* FPM Group */ sub %len, 16, %len /* IEU0 */ - inc %g3 /* IEU1 */ + inc %o4 /* IEU1 */ std %f16, [%dst - 16] /* Store Group */ fpadd32 %f2, %f50, %f48 /* FPA */ - srl %g3, 1, %o5 /* IEU0 */ + srl %o4, 1, %o5 /* IEU0 */ faligndata %f2, %f4, %f18 /* FPA Group */ std %f18, [%dst - 8] /* Store */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ add %o5, %sum, %sum /* IEU0 */ ldda [%src + 8] %asi, %f2 /* Load */ fmovd %f4, %f0 /* FPA */ @@ -337,18 +338,18 @@ csum_partial_copy_vis: add %dst, 32, %dst /* IEU1 */ faligndata %f0, %f2, %f16 /* FPA */ fcmpgt32 %f48, %f50, %o5 /* FPM Group */ - inc %g3 /* IEU0 */ + inc %o4 /* IEU0 */ ldda [%src + 24] %asi, %f6 /* Load */ - srl %g3, 1, %g3 /* IEU0 Group */ + srl %o4, 1, %o4 /* IEU0 Group */ add %g5, %sum, %sum /* IEU1 */ ldda [%src + 32] %asi, %f8 /* Load */ fpadd32 %f2, %f50, %f48 /* FPA */ faligndata %f2, %f4, %f18 /* FPA Group */ sub %len, 32, %len /* IEU0 */ std %f16, [%dst - 32] /* Store */ - fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + fcmpgt32 %f50, %f48, %g3 /* FPM Group */ inc %o5 /* IEU0 */ - add %g3, %sum, %sum /* IEU1 */ + add %o4, %sum, %sum /* IEU1 */ fpadd32 %f4, %f48, %f50 /* FPA */ faligndata %f4, %f6, %f20 /* FPA Group */ srl %o5, 1, %o5 /* IEU0 */ @@ -356,14 +357,14 @@ csum_partial_copy_vis: add %o5, %sum, %sum /* IEU0 */ std %f18, [%dst - 24] /* Store */ fpadd32 %f6, %f50, %f48 /* FPA */ - inc %o4 /* IEU0 Group */ + inc %g3 /* IEU0 Group */ std %f20, [%dst - 16] /* Store */ add %src, 32, %src /* IEU1 */ faligndata %f6, %f8, %f22 /* FPA */ - fcmpgt32 %f50, %f48, %g3 /* FPM Group */ - srl %o4, 1, %o4 /* IEU0 */ + fcmpgt32 %f50, %f48, %o4 /* FPM Group */ + srl %g3, 1, %g3 /* IEU0 */ std %f22, [%dst - 8] /* Store */ - add %o4, %sum, %sum /* IEU0 Group */ + add %g3, %sum, %sum /* IEU0 Group */ 3: rd %asi, %g2 /* LSU Group + 4 bubbles */ #ifdef __KERNEL__ 4: sethi %hi(vis0s), %g7 /* IEU0 Group */ @@ -371,16 +372,16 @@ csum_partial_copy_vis: 4: rd %pc, %g7 /* LSU Group + 4 bubbles */ #endif inc %g5 /* IEU0 Group */ - and %src, 0x38, %o4 /* IEU1 */ + and %src, 0x38, %g3 /* IEU1 */ membar #StoreLoad /* LSU Group */ srl %g5, 1, %g5 /* IEU0 */ - inc %g3 /* IEU1 */ - sll %o4, 8, %o4 /* IEU0 Group */ + inc %o4 /* IEU1 */ + sll %g3, 8, %g3 /* IEU0 Group */ sub %len, 0xc0, %len /* IEU1 */ addcc %g5, %sum, %sum /* IEU1 Group */ - srl %g3, 1, %g3 /* IEU0 */ - add %g7, %o4, %g7 /* IEU0 Group */ - add %g3, %sum, %sum /* IEU1 */ + srl %o4, 1, %o4 /* IEU0 */ + add %g7, %g3, %g7 /* IEU0 Group */ + add %o4, %sum, %sum /* IEU1 */ #ifdef __KERNEL__ jmpl %g7 + %lo(vis0s), %g0 /* CTI+IEU1 Group */ #else @@ -815,7 +816,7 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */ END_THE_TRICK2( f48,f50,f52,f54,f56,f58,f60,f10,f12,f62) membar #Sync /* LSU Group */ #ifdef __KERNEL__ - wr %g0, 0, %fprs /* LSU Group */ + VISExit add %sp, 8, %sp /* IEU0 Group */ #endif 23: brnz,pn %len, 26f /* CTI+IEU1 Group */ @@ -834,12 +835,12 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */ #endif 26: andcc %len, 8, %g0 /* IEU1 Group */ be,pn %icc, 1f /* CTI */ - lduwa [%src] %asi, %g3 /* Load */ + lduwa [%src] %asi, %o4 /* Load */ lduwa [%src+4] %asi, %g2 /* Load Group */ add %src, 8, %src /* IEU0 */ add %dst, 8, %dst /* IEU1 */ - sllx %g3, 32, %g5 /* IEU0 Group */ - stw %g3, [%dst - 8] /* Store */ + sllx %o4, 32, %g5 /* IEU0 Group */ + stw %o4, [%dst - 8] /* Store */ or %g5, %g2, %g5 /* IEU0 Group */ stw %g2, [%dst - 4] /* Store */ addcc %g5, %sum, %sum /* IEU1 Group */ @@ -855,11 +856,11 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */ stw %g7, [%dst - 4] /* Store */ 1: andcc %len, 2, %g0 /* IEU1 */ be,a,pn %icc, 1f /* CTI */ - clr %o4 /* IEU0 Group */ + clr %g3 /* IEU0 Group */ lduha [%src] %asi, %g7 /* Load */ add %src, 2, %src /* IEU1 */ add %dst, 2, %dst /* IEU0 Group */ - sll %g7, 16, %o4 /* IEU0 Group */ + sll %g7, 16, %g3 /* IEU0 Group */ sth %g7, [%dst - 2] /* Store */ 1: andcc %len, 1, %g0 /* IEU1 */ be,a,pn %icc, 1f /* CTI */ @@ -867,9 +868,9 @@ ett: rd %gsr, %x3 /* LSU Group+4bubbles */ lduba [%src] %asi, %g7 /* Load */ sll %g7, 8, %o5 /* IEU0 Group */ stb %g7, [%dst] /* Store */ -1: or %g2, %o4, %o4 /* IEU1 */ - or %o5, %o4, %o4 /* IEU0 Group (regdep) */ - addcc %o4, %sum, %sum /* IEU1 Group (regdep) */ +1: or %g2, %g3, %g3 /* IEU1 */ + or %o5, %g3, %g3 /* IEU0 Group (regdep) */ + addcc %g3, %sum, %sum /* IEU1 Group (regdep) */ bcs,a,pn %xcc, 1f /* CTI */ add %sum, 1, %sum /* IEU0 */ 1: ba,pt %xcc, 25b /* CTI Group */ diff --git a/arch/sparc64/lib/VISmemset.S b/arch/sparc64/lib/VISmemset.S index 4c24931ba..9be111134 100644 --- a/arch/sparc64/lib/VISmemset.S +++ b/arch/sparc64/lib/VISmemset.S @@ -1,4 +1,4 @@ -/* $Id: VISmemset.S,v 1.7 1997/08/22 15:54:56 jj Exp $ +/* $Id: VISmemset.S,v 1.8 1998/06/12 14:53:59 jj Exp $ * VISmemset.S: High speed memset operations utilizing the UltraSparc * Visual Instruction Set. * @@ -32,6 +32,9 @@ #endif #ifdef __KERNEL__ + +#include <asm/visasm.h> + #define RETL clr %o0 #else #define RETL mov %g3, %o0 @@ -135,8 +138,9 @@ memset: #endif add %o0, 32, %o0 7: be,pn %xcc, 9f + nop #ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs + VISEntryHalf #endif ldd [%o0 - 8], %f0 18: wr %g0, ASI_BLK_P, %asi @@ -170,7 +174,7 @@ memset: add %o0, 256, %o0 12: #ifdef __KERNEL__ - wr %g0, 0, %fprs + VISExitHalf #else #ifndef REGS_64BIT wr %g0, FPRS_FEF, %fprs @@ -231,10 +235,9 @@ memset: #endif andncc %o2, 0x3f, %o3 be,pn %xcc, 9b -#ifdef __KERNEL__ - wr %g0, FPRS_FEF, %fprs -#else nop +#ifdef __KERNEL__ + VISEntryHalf #endif ba,pt %xcc, 18b ldd [%o0], %f0 diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S new file mode 100644 index 000000000..10d127bb5 --- /dev/null +++ b/arch/sparc64/lib/VISsave.S @@ -0,0 +1,122 @@ +/* $Id: VISsave.S,v 1.2 1998/06/19 12:14:25 jj 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>. + * + * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#include <asm/asi.h> +#include <asm/page.h> +#include <asm/ptrace.h> +#include <asm/visasm.h> + + .text + .globl VISenter, VISenterhalf + + /* On entry: %o5=current FPRS value, %g7 is callers address */ + /* May clobber %o5, %g1, %g2, %g3, %g7, %icc, %xcc */ + + .align 32 +VISenter: + ldub [%g6 + AOFF_task_tss + 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] +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] + or %g3, %o5, %g3 + stb %g3, [%g6 + AOFF_task_tss + AOFF_thread_fpsaved] + rd %gsr, %g3 + clr %g1 + ba,pt %xcc, 3f + + stb %g3, [%g6 + AOFF_task_tss + 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] + rd %gsr, %g2 + stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr] + + add %g6, %g1, %g2 + stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr] + sll %g1, 5, %g1 +3: andcc %o5, FPRS_DL|FPRS_DU, %g0 + be,pn %icc, 9b + add %g6, AOFF_task_fpregs, %g2 + andcc %o5, FPRS_DL, %g0 + membar #StoreStore | #LoadStore + + be,pn %icc, 4f + add %g6, AOFF_task_fpregs+0x40, %g3 + stda %f0, [%g2 + %g1] ASI_BLK_P + stda %f16, [%g3 + %g1] ASI_BLK_P + andcc %o5, FPRS_DU, %g0 + be,pn %icc, 5f +4: add %g1, 128, %g1 + stda %f32, [%g2 + %g1] ASI_BLK_P + + stda %f48, [%g3 + %g1] ASI_BLK_P +5: membar #Sync + jmpl %g7 + %g0, %g0 + nop + +6: ldub [%g3 + AOFF_task_tss + 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] + + sll %g1, 5, %g1 + add %g6, AOFF_task_fpregs+0xc0, %g3 + membar #StoreStore | #LoadStore + stda %f32, [%g2 + %g1] ASI_BLK_P + stda %f48, [%g3 + %g1] ASI_BLK_P + membar #Sync + jmpl %g7 + %g0, %g0 + nop + + .align 32 +VISenterhalf: + ldub [%g6 + AOFF_task_tss + 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] + clr %o5 + jmpl %g7 + %g0, %g0 + wr %g0, FPRS_FEF, %fprs + +1: bne,pn %icc, 2f + srl %g1, 1, %g1 + ba,pt %xcc, vis1 + sub %g7, 8, %g7 +2: addcc %g6, %g1, %g3 + sll %g1, 3, %g1 + andn %o5, FPRS_DU, %g2 + stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_fpsaved] + + rd %gsr, %g2 + stb %g2, [%g3 + AOFF_task_tss + AOFF_thread_gsr] + add %g6, %g1, %g2 + stx %fsr, [%g2 + AOFF_task_tss + AOFF_thread_xfsr] + sll %g1, 5, %g1 +3: andcc %o5, FPRS_DL, %g0 + be,pn %icc, 4f + add %g6, AOFF_task_fpregs, %g2 + + membar #StoreStore | #LoadStore + add %g6, AOFF_task_fpregs+0x40, %g3 + stda %f0, [%g2 + %g1] ASI_BLK_P + stda %f16, [%g3 + %g1] ASI_BLK_P + membar #Sync +4: and %o5, FPRS_DU, %o5 + jmpl %g7 + %g0, %g0 + wr %o5, FPRS_FEF, %fprs diff --git a/arch/sparc64/lib/blockops.S b/arch/sparc64/lib/blockops.S index 7d5b240ad..c57f0aefc 100644 --- a/arch/sparc64/lib/blockops.S +++ b/arch/sparc64/lib/blockops.S @@ -1,52 +1,66 @@ -/* $Id: blockops.S,v 1.11 1997/07/29 09:35:36 davem Exp $ - * arch/sparc64/lib/blockops.S: UltraSparc block zero optimized routines. +/* $Id: blockops.S,v 1.14 1998/06/12 14:53:46 jj Exp $ + * blockops.S: UltraSparc block zero optimized routines. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996,1998 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include "VIS.h" +#include <asm/visasm.h> + +#define TOUCH(reg0, reg1, reg2, reg3, reg4, reg5, reg6, reg7) \ + fmovd %reg0, %f48; fmovd %reg1, %f50; \ + fmovd %reg2, %f52; fmovd %reg3, %f54; \ + fmovd %reg4, %f56; fmovd %reg5, %f58; \ + fmovd %reg6, %f60; fmovd %reg7, %f62; .text .align 32 - - .globl __bfill64 -__bfill64: /* %o0 = buf, %o1= ptr to pattern */ - wr %g0, FPRS_FEF, %fprs ! FPU Group - ldd [%o1], %f48 ! Load Group - wr %g0, ASI_BLK_P, %asi ! LSU Group - membar #StoreLoad | #StoreStore | #LoadStore ! LSU Group - mov 32, %g2 ! IEU0 Group - - /* Cannot perform real arithmatic on the pattern, that can - * lead to fp_exception_other ;-) - */ - fmovd %f48, %f50 ! FPA Group - fmovd %f48, %f52 ! FPA Group - fmovd %f48, %f54 ! FPA Group - fmovd %f48, %f56 ! FPA Group - fmovd %f48, %f58 ! FPA Group - fmovd %f48, %f60 ! FPA Group - fmovd %f48, %f62 ! FPA Group - -1: stda %f48, [%o0 + 0x00] %asi ! Store Group - stda %f48, [%o0 + 0x40] %asi ! Store Group - stda %f48, [%o0 + 0x80] %asi ! Store Group - stda %f48, [%o0 + 0xc0] %asi ! Store Group - subcc %g2, 1, %g2 ! IEU1 Group - bne,pt %icc, 1b ! CTI - add %o0, 0x100, %o0 ! IEU0 - membar #StoreLoad | #StoreStore ! LSU Group - - jmpl %o7 + 0x8, %g0 ! CTI Group brk forced - wr %g0, 0, %fprs ! FPU Group + .globl copy_page + .type copy_page,@function +copy_page: /* %o0=dest, %o1=src */ + VISEntry + membar #LoadStore | #StoreStore | #StoreLoad + ldda [%o1] ASI_BLK_P, %f0 + add %o1, 0x40, %o1 + ldda [%o1] ASI_BLK_P, %f16 + add %o1, 0x40, %o1 + sethi %hi(8192), %o2 +1: TOUCH(f0, f2, f4, f6, f8, f10, f12, f14) + ldda [%o1] ASI_BLK_P, %f32 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + TOUCH(f16, f18, f20, f22, f24, f26, f28, f30) + ldda [%o1] ASI_BLK_P, %f0 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + TOUCH(f32, f34, f36, f38, f40, f42, f44, f46) + ldda [%o1] ASI_BLK_P, %f16 + add %o1, 0x40, %o1 + sub %o2, 0x40, %o2 + stda %f48, [%o0] ASI_BLK_P + cmp %o2, 0x80 + bne,pt %xcc, 1b + add %o0, 0x40, %o0 + membar #Sync + stda %f0, [%o0] ASI_BLK_P + add %o0, 0x40, %o0 + stda %f16, [%o0] ASI_BLK_P + membar #StoreStore | #StoreLoad + jmpl %o7 + 0x8, %g0 + VISExit .align 32 .globl __bzero_1page -__bzero_1page: - wr %g0, FPRS_FEF, %fprs ! FPU Group + .type __bzero_1page,@function +__bzero_1page: /* %o0=dest */ + VISEntryHalf fzero %f0 ! FPA Group - mov 32, %g1 ! IEU0 + mov 32, %o1 ! IEU0 fzero %f2 ! FPA Group faddd %f0, %f2, %f4 ! FPA Group fmuld %f0, %f2, %f6 ! FPM @@ -62,9 +76,9 @@ __bzero_1page: stda %f0, [%o0 + 0x80] %asi ! Store Group stda %f0, [%o0 + 0xc0] %asi ! Store Group - subcc %g1, 1, %g1 ! IEU1 + subcc %o1, 1, %o1 ! IEU1 bne,pt %icc, 1b ! CTI add %o0, 0x100, %o0 ! IEU0 Group - membar #StoreLoad | #StoreStore ! LSU Group + membar #StoreStore | #StoreLoad ! LSU Group jmpl %o7 + 0x8, %g0 ! CTI Group brk forced - wr %g0, 0, %fprs ! FPU Group + VISExitHalf diff --git a/arch/sparc64/lib/memscan.S b/arch/sparc64/lib/memscan.S index 83abe4040..423bc1409 100644 --- a/arch/sparc64/lib/memscan.S +++ b/arch/sparc64/lib/memscan.S @@ -1,116 +1,129 @@ -/* $Id: memscan.S,v 1.1 1997/03/14 21:04:24 jj Exp $ - * memscan.S: Optimized memscan for the Sparc64. +/* $Id: memscan.S,v 1.2 1998/05/21 14:42:22 jj Exp $ + * memscan.S: Optimized memscan for Sparc64. * - * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz) + * Copyright (C) 1998 David S. Miller (davem@dm.cobaltmicro.com) */ -/* In essence, this is just a fancy strlen. */ - -#define LO_MAGIC 0x01010101 -#define HI_MAGIC 0x80808080 +#define HI_MAGIC 0x8080808080808080 +#define LO_MAGIC 0x0101010101010101 +#define ASI_PL 0x88 .text - .align 4 - .globl __memscan_zero, __memscan_generic - .globl memscan + .align 32 + .globl __memscan_zero, __memscan_generic + .globl memscan + __memscan_zero: - /* %o0 = addr, %o1 = size */ - brlez,pn %o1, 0f - andcc %o0, 3, %g0 - be,pt %icc, 9f - sethi %hi(HI_MAGIC), %o4 - ldub [%o0], %o5 - subcc %o1, 1, %o1 - brz,pn %o5, 10f - add %o0, 1, %o0 - be,pn %xcc, 0f - andcc %o0, 3, %g0 - be,pn %icc, 4f - or %o4, %lo(HI_MAGIC), %o3 - ldub [%o0], %o5 - subcc %o1, 1, %o1 - brz,pn %o5, 10f - add %o0, 1, %o0 - be,pn %xcc, 0f - andcc %o0, 3, %g0 - be,pt %icc, 5f - sethi %hi(LO_MAGIC), %o4 - ldub [%o0], %o5 - subcc %o1, 1, %o1 - brz,pn %o5, 10f - add %o0, 1, %o0 - be,pn %xcc, 0f - or %o4, %lo(LO_MAGIC), %o2 - ba,pt %xcc, 2f - ld [%o0], %o5 -9: - or %o4, %lo(HI_MAGIC), %o3 -4: - sethi %hi(LO_MAGIC), %o4 -5: - or %o4, %lo(LO_MAGIC), %o2 - ld [%o0], %o5 -2: - sub %o5, %o2, %o4 - sub %o1, 4, %o1 - andcc %o4, %o3, %g0 - be,pn %icc, 1f - add %o0, 4, %o0 - brgz,pt %o1, 2b - ld [%o0], %o5 + /* %o0 = bufp, %o1 = size */ + brlez,pn %o1, szzero + andcc %o0, 7, %g0 + be,pt %icc, we_are_aligned + sethi %hi(HI_MAGIC), %o4 + ldub [%o0], %o5 +1: subcc %o1, 1, %o1 + brz,pn %o5, 10f + add %o0, 1, %o0 + be,pn %xcc, szzero + andcc %o0, 7, %g0 + bne,a,pn %icc, 1b + ldub [%o0], %o5 +we_are_aligned: + ldxa [%o0] ASI_PL, %o5 + or %o4, %lo(HI_MAGIC), %o3 + sllx %o3, 32, %o4 + or %o4, %o3, %o3 + + srlx %o3, 7, %o2 +msloop: + sub %o1, 8, %o1 + add %o0, 8, %o0 + sub %o5, %o2, %o4 + xor %o4, %o5, %o4 + andcc %o4, %o3, %g3 + bne,pn %xcc, check_bytes + srlx %o4, 32, %g3 + + brgz,a,pt %o1, msloop + ldxa [%o0] ASI_PL, %o5 +check_bytes: + bne,a,pn %icc, 2f + andcc %o5, 0xff, %g0 + add %o0, -5, %g2 + ba,pt %xcc, 3f + srlx %o5, 32, %g5 + +2: srlx %o5, 8, %g5 + be,pn %icc, 1f + add %o0, -8, %g2 + andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + be,pn %icc, 1f + inc %g2 + andcc %g5, 0xff, %g0 + + srlx %g5, 8, %g5 + be,pn %icc, 1f + inc %g2 + andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + be,pn %icc, 1f + inc %g2 + andcc %g3, %o3, %g0 + + be,a,pn %icc, 2f + mov %o0, %g2 +3: andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + be,pn %icc, 1f + inc %g2 + andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + + be,pn %icc, 1f + inc %g2 + andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + be,pn %icc, 1f + inc %g2 + andcc %g5, 0xff, %g0 + srlx %g5, 8, %g5 + + be,pn %icc, 1f + inc %g2 +2: brgz,a,pt %o1, msloop + ldxa [%o0] ASI_PL, %o5 + inc %g2 +1: add %o0, %o1, %o0 + cmp %g2, %o0 retl - add %o0, %o1, %o0 -1: - /* Check every byte. */ - srl %o5, 24, %g5 - andcc %g5, 0xff, %g0 - be,pn %icc, 1f - add %o0, -4, %o4 - srl %o5, 16, %g5 - andcc %g5, 0xff, %g0 - be,pn %icc, 1f - add %o4, 1, %o4 - srl %o5, 8, %g5 - andcc %g5, 0xff, %g0 - be,pn %icc, 1f - add %o4, 1, %o4 - andcc %o5, 0xff, %g0 - be,pn %icc, 1f - add %o4, 1, %o4 - brgz,pt %o1, 2b - ld [%o0], %o5 -1: - add %o0, %o1, %o0 - cmp %o4, %o0 - retl - movle %xcc, %o4, %o0 -0: - retl + + movle %xcc, %g2, %o0 +10: retl + sub %o0, 1, %o0 +szzero: retl nop -10: - retl - sub %o0, 1, %o0 memscan: __memscan_generic: /* %o0 = addr, %o1 = c, %o2 = size */ - brz,pn %o2, 3f - add %o0, %o2, %o3 - ldub [%o0], %o5 - sub %g0, %o2, %o4 + brz,pn %o2, 3f + add %o0, %o2, %o3 + ldub [%o0], %o5 + sub %g0, %o2, %o4 1: - cmp %o5, %o1 - be,pn %icc, 2f - addcc %o4, 1, %o4 - bne,a,pt %xcc, 1b - ldub [%o3 + %o4], %o5 + cmp %o5, %o1 + be,pn %icc, 2f + addcc %o4, 1, %o4 + bne,a,pt %xcc, 1b + ldub [%o3 + %o4], %o5 retl /* The delay slot is the same as the next insn, this is just to make it look more awful */ 2: - add %o3, %o4, %o0 + add %o3, %o4, %o0 retl - sub %o0, 1, %o0 + sub %o0, 1, %o0 3: retl nop diff --git a/arch/sparc64/math-emu/math.c b/arch/sparc64/math-emu/math.c index e0380720f..5a71804b9 100644 --- a/arch/sparc64/math-emu/math.c +++ b/arch/sparc64/math-emu/math.c @@ -1,4 +1,4 @@ -/* $Id: math.c,v 1.4 1998/04/06 16:09:57 jj Exp $ +/* $Id: math.c,v 1.5 1998/06/12 14:54:27 jj Exp $ * arch/sparc64/math-emu/math.c * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -122,59 +122,57 @@ int do_mathemu(struct pt_regs *regs, struct fpustate *f) if (type) { void *rs1 = NULL, *rs2 = NULL, *rd = NULL; - freg = (f->fsr >> 14) & 0xf; + freg = (current->tss.xfsr[0] >> 14) & 0xf; if (freg != (type >> 8)) goto err; - f->fsr &= ~0x1c000; + current->tss.xfsr[0] &= ~0x1c000; freg = ((insn >> 14) & 0x1f); switch (type & 0x3) { case 3: if (freg & 2) { - f->fsr |= (6 << 14) /* invalid_fp_register */; + current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); case 1: rs1 = (void *)&f->regs[freg]; - flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; - if (!(current->tss.flags & flags)) - rs1 = (void *)&zero; + flags = (freg < 32) ? FPRS_DL : FPRS_DU; + if (!(current->tss.fpsaved[0] & flags)) + rs1 = (void *)&zero; break; } freg = (insn & 0x1f); switch ((type >> 2) & 0x3) { case 3: if (freg & 2) { - f->fsr |= (6 << 14) /* invalid_fp_register */; + current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); case 1: rs2 = (void *)&f->regs[freg]; - flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; - if (!(current->tss.flags & flags)) + flags = (freg < 32) ? FPRS_DL : FPRS_DU; + if (!(current->tss.fpsaved[0] & flags)) rs2 = (void *)&zero; break; } freg = ((insn >> 25) & 0x1f); switch ((type >> 4) & 0x3) { - case 0: rd = (void *)(((long)&f->fsr) | (freg & 3)); break; + case 0: rd = (void *)(((long)¤t->tss.xfsr[0]) | (freg & 3)); break; case 3: if (freg & 2) { - f->fsr |= (6 << 14) /* invalid_fp_register */; + current->tss.xfsr[0] |= (6 << 14) /* invalid_fp_register */; goto err; } case 2: freg = ((freg & 1) << 5) | (freg & 0x1e); case 1: rd = (void *)&f->regs[freg]; - flags = (freg < 32) ? SPARC_FLAG_USEDFPUL : SPARC_FLAG_USEDFPUU; - regs->fprs |= FPRS_FEF; - if (!(current->tss.flags & SPARC_FLAG_USEDFPU)) { - current->tss.flags |= SPARC_FLAG_USEDFPU; - f->fsr = 0; - f->gsr = 0; + 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->tss.flags & flags)) { + if (!(current->tss.fpsaved[0] & flags)) { if (freg < 32) memset(f->regs, 0, 32*sizeof(u32)); else memset(f->regs+32, 0, 32*sizeof(u32)); } - current->tss.flags |= flags; + current->tss.fpsaved[0] |= flags; break; } func(rd, rs2, rs1); diff --git a/arch/sparc64/math-emu/op-common.h b/arch/sparc64/math-emu/op-common.h index d4ce104f6..ac49cd6c2 100644 --- a/arch/sparc64/math-emu/op-common.h +++ b/arch/sparc64/math-emu/op-common.h @@ -83,8 +83,17 @@ do { \ { \ _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \ _FP_ROUND(wc, X); \ - X##_e = _FP_FRAC_OVERP_##wc(fs, X); \ - _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \ + _FP_FRAC_SLL_##wc(X, 1); \ + if (_FP_FRAC_OVERP_##wc(fs, X)) \ + { \ + X##_e = 1; \ + _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \ + } \ + else \ + { \ + X##_e = 0; \ + _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \ + } \ } \ else \ { \ diff --git a/arch/sparc64/mm/Makefile b/arch/sparc64/mm/Makefile index 72f4fa079..a7448f1db 100644 --- a/arch/sparc64/mm/Makefile +++ b/arch/sparc64/mm/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.4 1997/07/24 12:15:08 davem Exp $ +# $Id: Makefile,v 1.5 1998/07/26 03:02:54 davem Exp $ # Makefile for the linux Sparc64-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also @@ -7,24 +7,12 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -ifdef SMP - .S.s: $(CPP) -D__ASSEMBLY__ $(AFLAGS) -ansi $< -o $*.s .S.o: $(CC) -D__ASSEMBLY__ $(AFLAGS) -ansi -c $< -o $*.o -else - -.S.s: - $(CPP) -D__ASSEMBLY__ -ansi $< -o $*.s - -.S.o: - $(CC) -D__ASSEMBLY__ -ansi -c $< -o $*.o - -endif - O_TARGET := mm.o O_OBJS := ultra.o fault.o init.o generic.o asyncd.o extable.o modutil.o diff --git a/arch/sparc64/mm/asyncd.c b/arch/sparc64/mm/asyncd.c index ae7e3233c..9308e41fc 100644 --- a/arch/sparc64/mm/asyncd.c +++ b/arch/sparc64/mm/asyncd.c @@ -1,4 +1,4 @@ -/* $Id: asyncd.c,v 1.3 1997/12/11 15:15:58 jj Exp $ +/* $Id: asyncd.c,v 1.4 1998/05/24 02:53:58 davem Exp $ * The asyncd kernel daemon. This handles paging on behalf of * processes that receive page faults due to remote (async) memory * accesses. @@ -108,7 +108,7 @@ void async_fault(unsigned long address, int write, int taskid, static int fault_in_page(int taskid, struct vm_area_struct *vma, - unsigned address,int write) + unsigned long address, int write) { static unsigned last_address; static int last_task, loop_counter; diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index e7d863997..035b023fc 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.71 1998/03/27 07:00:08 davem Exp $ +/* $Id: init.c,v 1.93 1998/08/04 20:49:25 davem Exp $ * arch/sparc64/mm/init.c * * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu) @@ -8,6 +8,8 @@ #include <linux/config.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/mm.h> +#include <linux/malloc.h> #include <linux/blk.h> #include <linux/swap.h> #include <linux/swapctl.h> @@ -34,27 +36,54 @@ struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS]; /* Ugly, but necessary... -DaveM */ unsigned long phys_base; -unsigned int null_pte_table; -unsigned long two_null_pmd_table, two_null_pte_table; - -extern unsigned long empty_null_pmd_table; -extern unsigned long empty_null_pte_table; unsigned long tlb_context_cache = CTX_FIRST_VERSION; /* References to section boundaries */ extern char __init_begin, __init_end, etext, __bss_start; -extern void __bfill64(void *, unsigned long *); - -static __inline__ void __init_pmd(pmd_t *pmdp) -{ - __bfill64((void *)pmdp, &two_null_pte_table); -} - -static __inline__ void __init_pgd(pgd_t *pgdp) +int do_check_pgt_cache(int low, int high) { - __bfill64((void *)pgdp, &two_null_pmd_table); + struct page *page, *page2; + int freed = 0; + + if(pgtable_cache_size > high) { + do { +#ifdef __SMP__ + if(pgd_quicklist) + free_pgd_slow(get_pgd_fast()), freed++; +#endif + if(pte_quicklist) + free_pte_slow(get_pte_fast()), freed++; + } while(pgtable_cache_size > low); + } +#ifndef __SMP__ + if (pgd_cache_size > high / 4) { + for (page2 = NULL, page = (struct page *)pgd_quicklist; page;) { + if ((unsigned long)page->pprev_hash == 3) { + if (page2) + page2->next_hash = page->next_hash; + else + (struct page *)pgd_quicklist = page->next_hash; + page->next_hash = NULL; + page->pprev_hash = NULL; + pgd_cache_size -= 2; + free_page(PAGE_OFFSET + (page->map_nr << PAGE_SHIFT)); + freed++; + if (page2) + page = page2->next_hash; + else + page = (struct page *)pgd_quicklist; + if (pgd_cache_size <= low / 4) + break; + continue; + } + page2 = page; + page = page->next_hash; + } + } +#endif + return freed; } /* @@ -70,21 +99,6 @@ static __inline__ void __init_pgd(pgd_t *pgdp) * ZERO_PAGE is a special page that is used for zero-initialized * data and COW. */ -pmd_t *__bad_pmd(void) -{ - pmd_t *pmdp = (pmd_t *) &empty_bad_pmd_table; - - __init_pmd(pmdp); - return pmdp; -} - -pte_t *__bad_pte(void) -{ - memset((void *) &empty_bad_pte_table, 0, PAGE_SIZE); - return (pte_t *) (((unsigned long)&empty_bad_pte_table) - - ((unsigned long)&empty_zero_page) + phys_base + PAGE_OFFSET); -} - pte_t __bad_page(void) { memset((void *) &empty_bad_page, 0, PAGE_SIZE); @@ -125,6 +139,9 @@ void show_mem(void) printk("%d pages shared\n",shared); printk("%d pages swap cached\n",cached); printk("%ld pages in page table cache\n",pgtable_cache_size); +#ifndef __SMP__ + printk("%ld entries in page dir cache\n",pgd_cache_size); +#endif show_buffers(); #ifdef CONFIG_NET show_net_buffers(); @@ -135,27 +152,47 @@ void show_mem(void) /* This keeps track of pages used in sparc_alloc_dvma() invocations. */ /* NOTE: All of these are inited to 0 in bss, don't need to make data segment bigger */ -static unsigned long dvma_map_pages[0x10000000 >> 16]; +#define DVMAIO_SIZE 0x2000000 +static unsigned long dvma_map_pages[DVMAIO_SIZE >> 16]; static unsigned long dvma_pages_current_offset; static int dvma_pages_current_index; +static unsigned long dvmaiobase = 0; +static unsigned long dvmaiosz __initdata = 0; /* #define E3000_DEBUG */ -__initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, - unsigned long memory_end, struct linux_sbus *sbus)) +__initfunc(void dvmaio_init(void)) +{ + int i; + + if (!dvmaiobase) { + for (i = 0; sp_banks[i].num_bytes != 0; i++) + if (sp_banks[i].base_addr + sp_banks[i].num_bytes > dvmaiobase) + dvmaiobase = sp_banks[i].base_addr + sp_banks[i].num_bytes; + dvmaiobase = (dvmaiobase + DVMAIO_SIZE + 0x400000 - 1) & ~(0x400000 - 1); + for (i = 0; i < 6; i++) + if (dvmaiobase <= ((1024 * 64 * 1024) << i)) + break; + dvmaiobase = ((1024 * 64 * 1024) << i) - DVMAIO_SIZE; + dvmaiosz = i; + } +} + +__initfunc(void iommu_init(int iommu_node, struct linux_sbus *sbus)) { struct iommu_struct *iommu; struct sysio_regs *sregs; struct linux_prom64_registers rprop; unsigned long impl, vers; unsigned long control, tsbbase; + unsigned long tsbbases[32]; unsigned long *iopte; - u32 rlow, rhigh; - int err, i; - + int err, i, j; + + dvmaio_init(); #ifdef E3000_DEBUG - prom_printf("\niommu_init: [%x:%016lx:%016lx:%p] ", - iommu_node, memory_start, memory_end, sbus); + prom_printf("\niommu_init: [%x:%p] ", + iommu_node, sbus); #endif err = prom_getproperty(iommu_node, "reg", (char *)&rprop, sizeof(rprop)); @@ -163,14 +200,8 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, prom_printf("iommu_init: Cannot map SYSIO control registers.\n"); prom_halt(); } - rlow = (rprop.phys_addr & 0xffffffff); - rhigh = (rprop.phys_addr >> 32); -#ifdef E3000_DEBUG - prom_printf("rlow[%08x] rhigh[%08x] ", rlow, rhigh); -#endif - sregs = (struct sysio_regs *) sparc_alloc_io(rlow, (void *)0, - sizeof(struct sysio_regs), - "SYSIO Regs", rhigh, 0x0); + sregs = (struct sysio_regs *) __va(rprop.phys_addr); + #ifdef E3000_DEBUG prom_printf("sregs[%p]\n"); #endif @@ -179,9 +210,7 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, prom_halt(); } - memory_start = (memory_start + 7) & ~7; - iommu = (struct iommu_struct *) memory_start; - memory_start += sizeof(struct iommu_struct); + iommu = kmalloc(sizeof(struct iommu_struct), GFP_ATOMIC); #ifdef E3000_DEBUG prom_printf("iommu_init: iommu[%p] ", iommu); @@ -203,26 +232,54 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, (unsigned int) impl, (unsigned int)vers, (unsigned long) sregs); control &= ~(IOMMU_CTRL_TSBSZ); - control |= (IOMMU_TSBSZ_64K | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); + control |= ((IOMMU_TSBSZ_2K * dvmaiosz) | IOMMU_CTRL_TBWSZ | IOMMU_CTRL_ENAB); /* Use only 64k pages, things are layed out in the 32-bit SBUS * address space like this: * - * 0x00000000 ---------------------------------------- - * | Direct physical mappings for most | - * | DVMA to paddr's within this range | - * 0xf0000000 ---------------------------------------- - * | For mappings requested via | - * | sparc_alloc_dvma() | - * 0xffffffff ---------------------------------------- - */ - tsbbase = PAGE_ALIGN(memory_start); - memory_start = (tsbbase + ((64 * 1024) * 8)); + * 0x00000000 ---------------------------------------- + * | Direct physical mappings for most | + * | DVMA to paddr's within this range | + * dvmaiobase ---------------------------------------- + * | For mappings requested via | + * | sparc_alloc_dvma() | + * dvmaiobase+32M ---------------------------------------- + * + * NOTE: we need to order 2 contiguous order 5, that's the largest + * chunk page_alloc will give us. -JJ */ + tsbbase = 0; + if (dvmaiosz == 6) { + memset (tsbbases, 0, sizeof(tsbbases)); + for (i = 0; i < 32; i++) { + tsbbases[i] = __get_free_pages(GFP_DMA, 5); + for (j = 0; j < i; j++) + if (tsbbases[j] == tsbbases[i] + 32768*sizeof(iopte_t)) { + tsbbase = tsbbases[i]; + break; + } else if (tsbbases[i] == tsbbases[j] + 32768*sizeof(iopte_t)) { + tsbbase = tsbbases[j]; + break; + } + if (tsbbase) { + tsbbases[i] = 0; + tsbbases[j] = 0; + break; + } + } + for (i = 0; i < 32; i++) + if (tsbbases[i]) + free_pages(tsbbases[i], 5); + } else + tsbbase = __get_free_pages(GFP_DMA, dvmaiosz); + if (!tsbbase) { + prom_printf("Strange. Could not allocate 512K of contiguous RAM.\n"); + prom_halt(); + } iommu->page_table = (iopte_t *) tsbbase; iopte = (unsigned long *) tsbbase; /* Setup aliased mappings... */ - for(i = 0; i < (65536 - 4096); i++) { + for(i = 0; i < (dvmaiobase >> 16); i++) { *iopte = (IOPTE_VALID | IOPTE_64K | IOPTE_STBUF | IOPTE_CACHE | IOPTE_WRITE); *iopte |= (i << 16); @@ -230,7 +287,7 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, } /* Clear all sparc_alloc_dvma() maps. */ - for( ; i < 65536; i++) + for( ; i < ((dvmaiobase + DVMAIO_SIZE) >> 16); i++) *iopte++ = 0; #ifdef E3000_DEBUG @@ -252,23 +309,19 @@ __initfunc(unsigned long iommu_init(int iommu_node, unsigned long memory_start, #endif printk("IOMMU: Streaming Buffer IMPL[%x] REV[%x] ", (unsigned int)impl, (unsigned int)vers); - printk("FlushFLAG[%p,%016lx] ... ", - (iommu->sbuf_flushflag_va = (unsigned int *)memory_start), - (iommu->sbuf_flushflag_pa = __pa(memory_start))); + iommu->sbuf_flushflag_va = kmalloc(sizeof(unsigned long), GFP_DMA); + printk("FlushFLAG[%016lx] ... ", (iommu->sbuf_flushflag_pa = __pa(iommu->sbuf_flushflag_va))); *(iommu->sbuf_flushflag_va) = 0; - memory_start += sizeof(unsigned long); /* yes, unsigned long, for alignment */ sregs->sbuf_control = (control | SYSIO_SBUFCTRL_SB_EN); #ifdef E3000_DEBUG - prom_printf("done, returning %016lx\n", memory_start); + prom_printf("done, returning\n"); #endif printk("ENABLED\n"); /* Finally enable DVMA arbitration for all devices, just in case. */ sregs->sbus_control |= SYSIO_SBCNTRL_AEN; - - return memory_start; } void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, @@ -300,7 +353,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, } /* Stick it in the IOMMU. */ - i = (65536 - 4096) + i; + i = (dvmaiobase >> 16) + i; for_each_sbus(sbus) { struct iommu_struct *iommu = sbus->iommu; unsigned long flags; @@ -314,7 +367,7 @@ void mmu_map_dma_area(unsigned long addr, int len, __u32 *dvma_addr, } /* Get this out of the way. */ - *dvma_addr = (__u32) ((0xf0000000) + + *dvma_addr = (__u32) ((dvmaiobase) + (dvma_pages_current_index << 16) + (dvma_pages_current_offset)); @@ -345,13 +398,17 @@ __u32 mmu_get_scsi_one(char *vaddr, unsigned long len, struct linux_sbus *sbus) { __u32 sbus_addr = (__u32) __pa(vaddr); - if((sbus_addr < 0xf0000000) && - ((sbus_addr + len) < 0xf0000000)) +#ifndef DEBUG_IOMMU + return sbus_addr; +#else + if((sbus_addr < dvmaiobase) && + ((sbus_addr + len) < dvmaiobase)) return sbus_addr; /* "can't happen"... GFP_DMA assures this. */ panic("Very high scsi_one mappings should never happen."); return (__u32)0; +#endif } void mmu_release_scsi_one(u32 vaddr, unsigned long len, struct linux_sbus *sbus) @@ -385,13 +442,17 @@ void mmu_get_scsi_sgl(struct mmu_sglist *sg, int sz, struct linux_sbus *sbus) { while(sz >= 0) { __u32 page = (__u32) __pa(((unsigned long) sg[sz].addr)); - if((page < 0xf0000000) && - (page + sg[sz].len) < 0xf0000000) { +#ifndef DEBUG_IOMMU + sg[sz].dvma_addr = page; +#else + if((page < dvmaiobase) && + (page + sg[sz].len) < dvmaiobase) { sg[sz].dvma_addr = page; } else { /* "can't happen"... GFP_DMA assures this. */ panic("scsi_sgl high mappings should never happen."); } +#endif sz--; } } @@ -440,35 +501,42 @@ struct linux_prom_translation { unsigned long data; }; -#define MAX_TRANSLATIONS 64 static inline void inherit_prom_mappings(void) { - struct linux_prom_translation transl[MAX_TRANSLATIONS]; + struct linux_prom_translation *trans; pgd_t *pgdp; pmd_t *pmdp; pte_t *ptep; int node, n, i; node = prom_finddevice("/virtual-memory"); - if ((n = prom_getproperty(node, "translations", (char *) transl, - sizeof(transl))) == -1) { + n = prom_getproplen(node, "translations"); + if (n == 0 || n == -1) { + prom_printf("Couldn't get translation property\n"); + prom_halt(); + } + + for (i = 1; i < n; i <<= 1) /* empty */; + trans = sparc_init_alloc(&mempool, i); + + if (prom_getproperty(node, "translations", (char *)trans, i) == -1) { prom_printf("Couldn't get translation property\n"); prom_halt(); } - n = n / sizeof(transl[0]); + n = n / sizeof(*trans); for (i = 0; i < n; i++) { unsigned long vaddr; - if (transl[i].virt >= 0xf0000000 && transl[i].virt < 0x100000000) { - for (vaddr = transl[i].virt; - vaddr < transl[i].virt + transl[i].size; + if (trans[i].virt >= 0xf0000000 && trans[i].virt < 0x100000000) { + for (vaddr = trans[i].virt; + vaddr < trans[i].virt + trans[i].size; vaddr += PAGE_SIZE) { pgdp = pgd_offset(init_task.mm, vaddr); if (pgd_none(*pgdp)) { pmdp = sparc_init_alloc(&mempool, PMD_TABLE_SIZE); - __init_pmd(pmdp); + clear_page(pmdp); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, vaddr); @@ -478,17 +546,89 @@ static inline void inherit_prom_mappings(void) pmd_set(pmdp, ptep); } ptep = pte_offset(pmdp, vaddr); - set_pte (ptep, __pte(transl[i].data | _PAGE_MODIFIED)); - transl[i].data += PAGE_SIZE; + set_pte (ptep, __pte(trans[i].data | _PAGE_MODIFIED)); + trans[i].data += PAGE_SIZE; } } } } +/* The OBP specifications for sun4u mark 0xfffffffc00000000 and + * upwards as reserved for use by the firmware (I wonder if this + * will be the same on Cheetah...). We use this virtual address + * range for the VPTE table mappings of the nucleus so we need + * to zap them when we enter the PROM. -DaveM + */ +static void __flush_nucleus_vptes(void) +{ + unsigned long pstate; + unsigned long prom_reserved_base = 0xfffffffc00000000UL; + int i; + + __asm__ __volatile__("rdpr %%pstate, %0\n\t" + "wrpr %0, %1, %%pstate\n\t" + "flushw" + : "=r" (pstate) + : "i" (PSTATE_IE)); + + /* Only DTLB must be checked for VPTE entries. */ + for(i = 0; i < 63; i++) { + unsigned long tag = spitfire_get_dtlb_tag(i); + + if(((tag & ~(PAGE_MASK)) == 0) && + ((tag & (PAGE_MASK)) >= prom_reserved_base)) { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : /* no outputs */ + : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(i, 0x0UL); + membar("#Sync"); + } + } + __asm__ __volatile__("wrpr %0, 0, %%pstate" + : : "r" (pstate)); +} + +static int prom_ditlb_set = 0; int prom_itlb_ent, prom_dtlb_ent; unsigned long prom_itlb_tag, prom_itlb_data; unsigned long prom_dtlb_tag, prom_dtlb_data; +void prom_world(int enter) +{ + if (!prom_ditlb_set) + return; + if (enter) { + /* Kick out nucleus VPTEs. */ + __flush_nucleus_vptes(); + + /* Install PROM world. */ + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_dtlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(62, prom_dtlb_data); + membar("#Sync"); + __asm__ __volatile__("stxa %0, [%1] %2" + : : "r" (prom_itlb_tag), "r" (TLB_TAG_ACCESS), + "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(62, prom_itlb_data); + membar("#Sync"); + } else { + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_DMMU)); + membar("#Sync"); + spitfire_put_dtlb_data(62, 0x0UL); + membar("#Sync"); + __asm__ __volatile__("stxa %%g0, [%0] %1" + : : "r" (TLB_TAG_ACCESS), "i" (ASI_IMMU)); + membar("#Sync"); + spitfire_put_itlb_data(62, 0x0UL); + membar("#Sync"); + } +} + void inherit_locked_prom_mappings(int save_p) { int i; @@ -500,8 +640,7 @@ void inherit_locked_prom_mappings(int save_p) * translations property. The only ones that matter are * the locked PROM tlb entries, so we impose the following * irrecovable rule on the PROM, it is allowed 1 locked - * entry in the ITLB and 1 in the DTLB. We move those - * (if necessary) up into tlb entry 62. + * entry in the ITLB and 1 in the DTLB. * * Supposedly the upper 16GB of the address space is * reserved for OBP, BUT I WISH THIS WAS DOCUMENTED @@ -510,7 +649,7 @@ void inherit_locked_prom_mappings(int save_p) * systems to coordinate mmu mappings is also COMPLETELY * UNDOCUMENTED!!!!!! Thanks S(t)un! */ - for(i = 0; i < 62; i++) { + for(i = 0; i < 63; i++) { unsigned long data; data = spitfire_get_dtlb_data(i); @@ -528,13 +667,6 @@ void inherit_locked_prom_mappings(int save_p) spitfire_put_dtlb_data(i, 0x0UL); membar("#Sync"); - /* Re-install it. */ - __asm__ __volatile__("stxa %0, [%1] %2" - : : "r" (tag), "r" (TLB_TAG_ACCESS), - "i" (ASI_DMMU)); - membar("#Sync"); - spitfire_put_dtlb_data(62, data); - membar("#Sync"); dtlb_seen = 1; if(itlb_seen) break; @@ -566,6 +698,8 @@ void inherit_locked_prom_mappings(int save_p) break; } } + if (save_p) + prom_ditlb_set = 1; } /* Give PROM back his world, done during reboots... */ @@ -628,44 +762,76 @@ void __flush_tlb_all(void) : : "r" (pstate)); } -/* We are always protected by scheduler_lock under SMP. */ -void get_new_mmu_context(struct mm_struct *mm, unsigned long *ctx) +#define CTX_BMAP_SLOTS (1UL << (CTX_VERSION_SHIFT - 6)) +unsigned long mmu_context_bmap[CTX_BMAP_SLOTS]; + +/* We are always protected by scheduler_lock under SMP. + * Caller does TLB context flushing on local CPU if necessary. + * + * We must be careful about boundary cases so that we never + * let the user have CTX 0 (nucleus) or we ever use a CTX + * version of zero (and thus NO_CONTEXT would not be caught + * by version mis-match tests in mmu_context.h). + */ +void get_new_mmu_context(struct mm_struct *mm) { - unsigned int new_ctx = *ctx; - - if((new_ctx & ~(CTX_VERSION_MASK)) == 0) { - new_ctx += CTX_FIRST_VERSION; - if(new_ctx == 1) - new_ctx = CTX_FIRST_VERSION; - *ctx = new_ctx; - DO_LOCAL_FLUSH(smp_processor_id()); + unsigned long ctx = (tlb_context_cache + 1) & ~(CTX_VERSION_MASK); + unsigned long new_ctx; + + 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); + 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); + if (new_ctx >= ctx) { + int i; + new_ctx = (tlb_context_cache & CTX_VERSION_MASK) + + CTX_FIRST_VERSION; + if (new_ctx == 1) + new_ctx = CTX_FIRST_VERSION; + + /* Don't call memset, for 16 entries that's just + * plain silly... + */ + mmu_context_bmap[0] = 3; + mmu_context_bmap[1] = 0; + mmu_context_bmap[2] = 0; + mmu_context_bmap[3] = 0; + for(i = 4; i < CTX_BMAP_SLOTS; i += 4) { + mmu_context_bmap[i + 0] = 0; + mmu_context_bmap[i + 1] = 0; + mmu_context_bmap[i + 2] = 0; + mmu_context_bmap[i + 3] = 0; + } + goto out; + } } + set_bit(new_ctx, mmu_context_bmap); + new_ctx |= (tlb_context_cache & CTX_VERSION_MASK); +out: + tlb_context_cache = new_ctx; mm->context = new_ctx; - mm->cpu_vm_mask = 0; /* Callers sets it properly. */ - (*ctx)++; + mm->cpu_vm_mask = 0; } #ifndef __SMP__ struct pgtable_cache_struct pgt_quicklists; #endif -pgd_t *get_pgd_slow(void) -{ - pgd_t *pgd; - - pgd = (pgd_t *) __get_free_page(GFP_KERNEL); - if(pgd) - __init_pgd(pgd); - return pgd; -} - +/* XXX Add __GFP_HIGH to these calls to "fool" page allocator + * XXX so we don't go to swap so quickly... then do the same + * XXX for get_user_page as well -DaveM + */ pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset) { pmd_t *pmd; pmd = (pmd_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pmd) { - __init_pmd(pmd); + clear_page(pmd); pgd_set(pgd, pmd); return pmd + offset; } @@ -678,7 +844,7 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) pte = (pte_t *) __get_free_page(GFP_DMA|GFP_KERNEL); if(pte) { - memset((void *)pte, 0, PTE_TABLE_SIZE); + clear_page(pte); pmd_set(pmd, pte); return pte + offset; } @@ -695,15 +861,14 @@ allocate_ptable_skeleton(unsigned long start, unsigned long end)) while (start < end) { pgdp = pgd_offset(init_task.mm, start); if (pgd_none(*pgdp)) { - pmdp = sparc_init_alloc(&mempool, - PMD_TABLE_SIZE); - __init_pmd(pmdp); + pmdp = sparc_init_alloc(&mempool, PAGE_SIZE); + clear_page(pmdp); pgd_set(pgdp, pmdp); } pmdp = pmd_offset(pgdp, start); if (pmd_none(*pmdp)) { - ptep = sparc_init_alloc(&mempool, - PTE_TABLE_SIZE); + ptep = sparc_init_alloc(&mempool, PAGE_SIZE); + clear_page(ptep); pmd_set(pmdp, ptep); } start = (start + PMD_SIZE) & PMD_MASK; @@ -733,6 +898,7 @@ void sparc_ultra_mapioaddr(unsigned long physaddr, unsigned long virt_addr, set_pte(ptep, pte); } +/* XXX no longer used, remove me... -DaveM */ void sparc_ultra_unmapioaddr(unsigned long virt_addr) { pgd_t *pgdp; @@ -747,7 +913,7 @@ void sparc_ultra_unmapioaddr(unsigned long virt_addr) pte_clear(ptep); } -#if NOTUSED +#ifdef NOTUSED void sparc_ultra_dump_itlb(void) { int slot; @@ -767,11 +933,11 @@ void sparc_ultra_dump_dtlb(void) { int slot; - printk ("Contents of dtlb: "); + prom_printf ("Contents of dtlb: "); for (slot = 0; slot < 14; slot++) printk (" "); - printk ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); + prom_printf ("%2x:%016lx,%016lx\n", 0, spitfire_get_dtlb_tag(0), spitfire_get_dtlb_data(0)); for (slot = 1; slot < 64; slot+=3) { - printk ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", + prom_printf ("%2x:%016lx,%016lx %2x:%016lx,%016lx %2x:%016lx,%016lx\n", slot, spitfire_get_dtlb_tag(slot), spitfire_get_dtlb_data(slot), slot+1, spitfire_get_dtlb_tag(slot+1), spitfire_get_dtlb_data(slot+1), slot+2, spitfire_get_dtlb_tag(slot+2), spitfire_get_dtlb_data(slot+2)); @@ -786,16 +952,16 @@ extern unsigned long free_area_init(unsigned long, unsigned long); __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { - extern unsigned long phys_base; - extern void setup_tba(unsigned long kpgdir); - extern void __bfill64(void *, unsigned long *); - pmd_t *pmdp; - int i; + extern void setup_tba(void); + extern pmd_t swapper_pmd_dir[1024]; + extern unsigned long irq_init(unsigned long start_mem, unsigned long end_mem); + extern unsigned int sparc64_vpte_patchme[1]; unsigned long alias_base = phys_base + PAGE_OFFSET; unsigned long pt; unsigned long flags; unsigned long shift = alias_base - ((unsigned long)&empty_zero_page); - + + set_bit(0, mmu_context_bmap); /* We assume physical memory starts at some 4mb multiple, * if this were not true we wouldn't boot up to this point * anyways. @@ -821,44 +987,28 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) * work. */ init_mm.pgd += ((shift) / (sizeof(pgd_t))); - - /* The funny offsets are to make page table operations much quicker and - * requite less state, see pgtable.h for gory details. - * pgtable.h assumes null_pmd_table is null_pte_table - PAGE_SIZE, lets - * check it now. - */ - null_pte_table=__pa(((unsigned long)&empty_null_pte_table)+shift); - if (null_pmd_table != __pa(((unsigned long)&empty_null_pmd_table)+shift)) { - prom_printf("null_p{md|te}_table broken.\n"); - prom_halt(); - } - two_null_pmd_table = (((unsigned long)null_pmd_table) << 32) | null_pmd_table; - two_null_pte_table = (((unsigned long)null_pte_table) << 32) | null_pte_table; - - pmdp = (pmd_t *) &empty_null_pmd_table; - for(i = 0; i < PTRS_PER_PMD; i++) - pmd_val(pmdp[i]) = null_pte_table; - - memset((void *) &empty_null_pte_table, 0, PTE_TABLE_SIZE); + + memset(swapper_pmd_dir, 0, sizeof(swapper_pmd_dir)); /* Now can init the kernel/bad page tables. */ - __bfill64((void *)swapper_pg_dir, &two_null_pmd_table); - __bfill64((void *)&empty_bad_pmd_table, &two_null_pte_table); + pgd_set(&swapper_pg_dir[0], swapper_pmd_dir + (shift / sizeof(pgd_t))); + + sparc64_vpte_patchme[0] |= (init_mm.pgd[0] >> 10); + + start_mem = irq_init(start_mem, end_mem); /* We use mempool to create page tables, therefore adjust it up * such that __pa() macros etc. work. */ mempool = PAGE_ALIGN(start_mem) + shift; - /* FIXME: This should be done much nicer. - * Just now we allocate 64M for each. - */ - allocate_ptable_skeleton(IOBASE_VADDR, IOBASE_VADDR + 0x4000000); + /* Allocate 64M for dynamic DVMA mapping area. */ allocate_ptable_skeleton(DVMA_VADDR, DVMA_VADDR + 0x4000000); inherit_prom_mappings(); + /* Ok, we can use our TLB miss and window trap handlers safely. */ - setup_tba((unsigned long)init_mm.pgd); + setup_tba(); /* Really paranoid. */ flushi((long)&empty_zero_page); @@ -884,11 +1034,16 @@ paging_init(unsigned long start_mem, unsigned long end_mem)) return device_scan (PAGE_ALIGN (start_mem)); } +/* XXX Add also PG_Hole flag, set it in the page structs here, + * XXX remove FREE_UNUSED_MEM_MAP code, and the nfsd file handle + * problems will all be gone. -DaveM + */ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long end_mem)) { unsigned long tmp = 0, paddr, endaddr; unsigned long end = __pa(end_mem); + dvmaio_init(); for (paddr = __pa(start_mem); paddr < end; ) { for (; sp_banks[tmp].num_bytes != 0; tmp++) if (sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes > paddr) @@ -911,7 +1066,7 @@ __initfunc(static void taint_real_pages(unsigned long start_mem, unsigned long e endaddr = sp_banks[tmp].base_addr + sp_banks[tmp].num_bytes; while (paddr < endaddr) { mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_reserved); - if (paddr >= 0xf0000000) + if (paddr >= dvmaiobase) mem_map[paddr>>PAGE_SHIFT].flags &= ~(1<<PG_DMA); paddr += PAGE_SIZE; } @@ -926,6 +1081,7 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) unsigned long addr; unsigned long alias_base = phys_base + PAGE_OFFSET - (long)(&empty_zero_page); struct page *page, *end; + int i; end_mem &= PAGE_MASK; max_mapnr = MAP_NR(end_mem); @@ -998,6 +1154,19 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) #endif free_page(addr); } + +#ifndef __SMP__ + { + /* Put empty_pg_dir on pgd_quicklist */ + extern pgd_t empty_pg_dir[1024]; + unsigned long addr = (unsigned long)empty_pg_dir; + + memset(empty_pg_dir, 0, sizeof(empty_pg_dir)); + addr += alias_base; + mem_map[MAP_NR(addr)].pprev_hash = 0; + free_pgd_fast((pgd_t *)addr); + } +#endif printk("Memory: %uk available (%dk kernel code, %dk data, %dk init) [%016lx,%016lx]\n", nr_free_pages << (PAGE_SHIFT-10), @@ -1006,11 +1175,18 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) initpages << (PAGE_SHIFT-10), PAGE_OFFSET, end_mem); - freepages.low = nr_free_pages >> 7; - if(freepages.low < 48) - freepages.low = 48; - freepages.low = freepages.low + (freepages.low >> 1); - freepages.high = freepages.low + freepages.low; + /* NOTE NOTE NOTE NOTE + * Please keep track of things and make sure this + * always matches the code in mm/page_alloc.c -DaveM + */ + i = nr_free_pages >> 7; + if (i < 48) + i = 48; + if (i > 256) + i = 256; + freepages.min = i; + freepages.low = i << 1; + freepages.high = freepages.low + i; } void free_initmem (void) diff --git a/arch/sparc64/mm/modutil.c b/arch/sparc64/mm/modutil.c index 303b98996..6d68d7468 100644 --- a/arch/sparc64/mm/modutil.c +++ b/arch/sparc64/mm/modutil.c @@ -1,4 +1,4 @@ -/* $Id: modutil.c,v 1.3 1998/01/16 16:35:02 jj Exp $ +/* $Id: modutil.c,v 1.4 1998/07/26 06:29:08 davem Exp $ * arch/sparc64/mm/modutil.c * * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -35,32 +35,6 @@ void module_unmap (void * addr) printk("Trying to unmap nonexistent module vm area (%p)\n", addr); } -void module_shrink(void * addr, unsigned long size) -{ - struct vm_struct *tmp; - - if (!addr) - return; - if ((PAGE_SIZE-1) & (unsigned long) addr) { - printk("Trying to shrink module with bad address (%p)\n", addr); - return; - } - size = PAGE_ALIGN(size); - if (!size) - module_unmap(addr); - for (tmp = modvmlist; tmp; tmp = tmp->next) { - if (tmp->addr == addr) { - if (size > tmp->size - PAGE_SIZE) { - printk("Trying to expand module with module_shrink()\n"); - return; - } - vmfree_area_pages(VMALLOC_VMADDR(tmp->addr)+size, tmp->size-size); - return; - } - } - printk("Trying to shrink nonexistent module vm area (%p)\n", addr); -} - void * module_map (unsigned long size) { void * addr; diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index ea0faa16b..683f4bcb1 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.20 1997/10/03 20:42:46 davem Exp $ +/* $Id: ultra.S,v 1.24 1998/05/22 11:02:56 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -8,90 +8,119 @@ #include <asm/pgtable.h> #include <asm/spitfire.h> - /* All callers check mm->context != NO_CONTEXT for us. */ + /* This file is meant to be read efficiently by the CPU, not humans. + * Staraj sie tego nikomu nie pierdolnac... + */ .text .align 32 - .globl __flush_tlb_mm, __flush_tlb_range, __flush_tlb_page -__flush_tlb_mm: /* %o0 == (mm->context & 0x1fff) */ - mov SECONDARY_CONTEXT, %g7 -9: ldxa [%g7] ASI_DMMU, %g2 + .globl __flush_tlb_page, __flush_tlb_mm, __flush_tlb_range +__flush_tlb_page: /* %o0=(ctx & 0x3ff), %o1=page&PAGE_MASK, %o2=SECONDARY_CONTEXT */ +/*IC1*/ ldxa [%o2] ASI_DMMU, %g2 + cmp %g2, %o0 + bne,pn %icc, __flush_tlb_page_slow + or %o1, 0x10, %g3 + stxa %g0, [%g3] ASI_DMMU_DEMAP + stxa %g0, [%g3] ASI_IMMU_DEMAP + retl + flush %g6 +__flush_tlb_mm: /* %o0=(ctx & 0x3ff), %o1=SECONDARY_CONTEXT */ +/*IC2*/ ldxa [%o1] ASI_DMMU, %g2 cmp %g2, %o0 - bne,pn %icc, 1f + bne,pn %icc, __flush_tlb_mm_slow mov 0x50, %g3 stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP retl flush %g6 -1: rdpr %pstate, %g1 +__flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT, + * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start) + */ +#define TLB_MAGIC 206 /* Students, do you know how I calculated this? -DaveM */ +/*IC3*/ cmp %o5, %o4 + be,pt %xcc, __flush_tlb_page + srlx %o5, 13, %g5 + cmp %g5, TLB_MAGIC + bgeu,pn %icc, __flush_tlb_range_constant_time + or %o1, 0x10, %g5 + ldxa [%o2] ASI_DMMU, %g2 + cmp %g2, %o0 +__flush_tlb_range_page_by_page: +/*IC4*/ bne,pn %icc, __flush_tlb_range_pbp_slow + sub %o5, %o4, %o5 +1: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP + stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP + brnz,pt %o5, 1b + sub %o5, %o4, %o5 + retl + flush %g6 +__flush_tlb_range_constant_time: /* %o0=ctx, %o1=start, %o3=end */ +/*IC5*/ rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate - stxa %o0, [%g7] ASI_DMMU + mov (62 << 3), %g2 +1: ldxa [%g2] ASI_ITLB_TAG_READ, %o4 + and %o4, 0x3ff, %o5 + cmp %o5, %o0 + bne,pt %icc, 2f + andn %o4, 0x3ff, %o4 +/*IC6*/ cmp %o4, %o1 + blu,pt %xcc, 2f + cmp %o4, %o3 + blu,pn %xcc, 4f +2: ldxa [%g2] ASI_DTLB_TAG_READ, %o4 + and %o4, 0x3ff, %o5 + cmp %o5, %o0 + andn %o4, 0x3ff, %o4 +/*IC7*/ bne,pt %icc, 3f + cmp %o4, %o1 + blu,pt %xcc, 3f + cmp %o4, %o3 + blu,pn %xcc, 5f + nop +3: brnz,pt %g2, 1b + sub %g2, (1 << 3), %g2 +/*IC8*/ retl + wrpr %g1, 0x0, %pstate +4: stxa %g0, [%g2] ASI_ITLB_DATA_ACCESS + ba,pt %xcc, 2b + flush %g6 +5: stxa %g0, [%g2] ASI_DTLB_DATA_ACCESS + ba,pt %xcc, 3b + flush %g6 +__flush_tlb_mm_slow: +/*IC9*/ rdpr %pstate, %g1 + wrpr %g1, PSTATE_IE, %pstate + stxa %o0, [%o1] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP flush %g6 - stxa %g2, [%g7] ASI_DMMU + stxa %g2, [%o1] ASI_DMMU flush %g6 - retl +/*IC10*/retl wrpr %g1, 0, %pstate - nop -__flush_tlb_range: /* %o0 == (mm->context & 0x1fff), %o1 == start, %o2 == end */ - sethi %hi(8192 - 1), %g5 - or %g5, %lo(8192 - 1), %g5 - andn %o1, %g5, %o1 - andn %o2, %g5, %o2 - - sub %o2, %o1, %o3 - add %g5, 1, %g5 - orcc %o1, 0x10, %o1 - srlx %o3, 13, %o4 - cmp %o4, 96 - bgu,pn %icc, 9b - mov SECONDARY_CONTEXT, %g7 - ldxa [%g7] ASI_DMMU, %g2 - - nop - nop - cmp %g2, %o0 - be,pt %icc, 1f - sub %o3, %g5, %o3 +__flush_tlb_page_slow: rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate - stxa %o0, [%g7] ASI_DMMU - -1: stxa %g0, [%o1 + %o3] ASI_DMMU_DEMAP - stxa %g0, [%o1 + %o3] ASI_IMMU_DEMAP - brnz,pt %o3, 1b - sub %o3, %g5, %o3 - flush %g6 - be,pt %icc, 1f - nop - stxa %g2, [%g7] ASI_DMMU - - flush %g6 - wrpr %g1, 0, %pstate -1: retl - nop - - .align 32 -__flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */ - mov SECONDARY_CONTEXT, %g7 - ldxa [%g7] ASI_DMMU, %g2 - cmp %g2, %o0 - bne,pt %icc, 1f - or %o1, 0x10, %g3 + stxa %o0, [%o2] ASI_DMMU stxa %g0, [%g3] ASI_DMMU_DEMAP stxa %g0, [%g3] ASI_IMMU_DEMAP + flush %g6 +/*IC11*/stxa %g2, [%o2] ASI_DMMU + flush %g6 retl - flush %g6 -1: rdpr %pstate, %g1 + wrpr %g1, 0, %pstate +__flush_tlb_range_pbp_slow: + rdpr %pstate, %g1 wrpr %g1, PSTATE_IE, %pstate - stxa %o0, [%g7] ASI_DMMU - stxa %g0, [%g3] ASI_DMMU_DEMAP - stxa %g0, [%g3] ASI_IMMU_DEMAP + stxa %o0, [%o2] ASI_DMMU +2: stxa %g0, [%g5 + %o5] ASI_DMMU_DEMAP + stxa %g0, [%g5 + %o5] ASI_IMMU_DEMAP + brnz,pt %o5, 2b + sub %o5, %o4, %o5 flush %g6 - stxa %g2, [%g7] ASI_DMMU +/*IC13*/stxa %g2, [%o2] ASI_DMMU flush %g6 retl - wrpr %g1, 0, %pstate + wrpr %g1, 0x0, %pstate #ifdef __SMP__ /* These are all called by the slaves of a cross call, at @@ -106,6 +135,8 @@ __flush_tlb_page: /* %o0 == (mm->context & 0x1fff), %o1 == page & PAGE_MASK */ * %g2 scratch 1 * %g3 scratch 2 * %g4 scratch 3 + * + * TODO: Make xcall TLB range flushes use the tricks above... -DaveM */ .align 32 .globl xcall_flush_tlb_page, xcall_flush_tlb_mm, xcall_flush_tlb_range diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 9720f1a70..8e7ff7700 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.9 1997/07/24 12:15:11 davem Exp $ +/* $Id: misc.c,v 1.10 1998/07/21 10:36:29 jj Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -33,8 +33,7 @@ prom_feval(char *fstring) /* We want to do this more nicely some day. */ #ifdef CONFIG_SUN_CONSOLE -extern void console_restore_palette(void); -extern void set_palette(void); +extern void (*prom_palette)(int); extern int serial_console; #endif @@ -52,10 +51,8 @@ prom_cmdline(void) /* kernel_enter_debugger(); */ #ifdef CONFIG_SUN_CONSOLE -#if 0 - if(!serial_console) - console_restore_palette (); -#endif + if(!serial_console && prom_palette) + prom_palette (1); #endif /* install_obp_ticker(); */ save_flags(flags); cli(); @@ -63,10 +60,8 @@ prom_cmdline(void) restore_flags(flags); /* install_linux_ticker(); */ #ifdef CONFIG_SUN_CONSOLE -#if 0 - if(!serial_console) - set_palette (); -#endif + if(!serial_console && prom_palette) + prom_palette (0); #endif } diff --git a/arch/sparc64/prom/p1275.c b/arch/sparc64/prom/p1275.c index 9c5bce294..722243e99 100644 --- a/arch/sparc64/prom/p1275.c +++ b/arch/sparc64/prom/p1275.c @@ -1,4 +1,4 @@ -/* $Id: p1275.c,v 1.12 1997/07/26 18:39:01 davem Exp $ +/* $Id: p1275.c,v 1.13 1998/04/24 15:45:35 jj Exp $ * p1275.c: Sun IEEE 1275 PROM low level interface routines * * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -24,6 +24,8 @@ struct { char prom_buffer [3000]; } p1275buf; +extern void prom_world(int); + void prom_cif_interface (void) { __asm__ __volatile__ (" @@ -115,7 +117,11 @@ long p1275_cmd (char *service, long fmt, ...) } va_end(list); + prom_world(1); + prom_cif_interface(); + + prom_world(0); attrs = fmt >> 8; va_start(list, fmt); diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 6df97c7c4..3980f1d67 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -1,4 +1,4 @@ -/* $Id: fs.c,v 1.8 1998/03/29 10:11:02 davem Exp $ +/* $Id: fs.c,v 1.10 1998/05/09 06:15:45 davem Exp $ * fs.c: fs related syscall emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -523,7 +523,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group) newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } - DQUOT_TRANSFER(dentry, newattrs); + error = DQUOT_TRANSFER(dentry, &newattrs); out: return error; } diff --git a/arch/sparc64/solaris/ipc.c b/arch/sparc64/solaris/ipc.c index 4788e9944..9c95a9234 100644 --- a/arch/sparc64/solaris/ipc.c +++ b/arch/sparc64/solaris/ipc.c @@ -1,9 +1,10 @@ -/* $Id: ipc.c,v 1.2 1997/09/18 10:38:27 rth Exp $ +/* $Id: ipc.c,v 1.3 1998/07/30 11:29:47 davem Exp $ * ipc.c: Solaris IPC emulation * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include <linux/kernel.h> #include <linux/types.h> #include <linux/smp_lock.h> #include <linux/shm.h> diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index 4179f54b3..8e0ce81da 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.10 1998/04/01 05:16:06 davem Exp $ +/* $Id: misc.c,v 1.12 1998/06/16 04:37:08 davem Exp $ * misc.c: Miscelaneous syscall emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -164,7 +164,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) { switch (which) { case 0: /* old uname */ - /* Lets cheat */ + /* Let's cheat */ set_utsfield(((struct sol_uname *)A(buf))->sysname, "SunOS", 1, 0); set_utsfield(((struct sol_uname *)A(buf))->nodename, @@ -188,6 +188,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2) asmlinkage int solaris_utsname(u32 buf) { /* Why should we not lie a bit? */ + down(&uts_sem); set_utsfield(((struct sol_utsname *)A(buf))->sysname, "SunOS", 0, 0); set_utsfield(((struct sol_utsname *)A(buf))->nodename, @@ -198,6 +199,7 @@ asmlinkage int solaris_utsname(u32 buf) "Generic", 0, 0); set_utsfield(((struct sol_utsname *)A(buf))->machine, machine(), 0, 0); + up(&uts_sem); return 0; } diff --git a/arch/sparc64/solaris/signal.h b/arch/sparc64/solaris/signal.h index 2e948c788..e91570803 100644 --- a/arch/sparc64/solaris/signal.h +++ b/arch/sparc64/solaris/signal.h @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.2 1997/09/03 12:29:21 jj Exp $ +/* $Id: signal.h,v 1.3 1998/04/12 06:20:33 davem Exp $ * signal.h: Signal emulation for Solaris * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -106,4 +106,3 @@ struct sol_siginfo { #define SOLARIS_POLL_ERR 4 #define SOLARIS_POLL_PRI 5 #define SOLARIS_POLL_HUP 6 - diff --git a/arch/sparc64/vmlinux.lds b/arch/sparc64/vmlinux.lds index d2c08f0fe..ec1ca0461 100644 --- a/arch/sparc64/vmlinux.lds +++ b/arch/sparc64/vmlinux.lds @@ -6,7 +6,8 @@ ENTRY(_start) SECTIONS { empty_zero_page = 0x0000000000400000; - swapper_pg_dir = 0x0000000000402000; + swapper_pmd_dir = 0x0000000000402000; + empty_pg_dir = 0x0000000000403000; . = 0x4000; .text 0x0000000000404000 : { @@ -47,16 +48,6 @@ SECTIONS *(.dynbss) *(.bss) *(COMMON) - . = ALIGN(8192); - empty_bad_pmd_table = .; - . += 8192; - empty_bad_pte_table = .; - . += 8192; - . += 0x40; - empty_null_pmd_table = .; - . += 8192; - empty_null_pte_table = .; - . += 8192; } _end = . ; PROVIDE (end = .); |