diff options
Diffstat (limited to 'arch/sparc64')
28 files changed, 1385 insertions, 1455 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index a8c6366f05a1..3af378ddb6ae 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -14,6 +14,7 @@ config SPARC config SPARC64 bool default y + select HAVE_IDE help SPARC is a family of RISC microprocessors designed and marketed by Sun Microsystems, incorporated. This port covers the newer 64-bit @@ -40,6 +41,10 @@ config MMU bool default y +config IOMMU_HELPER + bool + default y + config QUICKLIST bool default y @@ -81,6 +86,9 @@ config GENERIC_HARDIRQS_NO__DO_IRQ bool def_bool y +config ARCH_SUPPORTS_AOUT + def_bool y + choice prompt "Kernel page size" default SPARC64_PAGE_SIZE_8KB @@ -380,17 +388,11 @@ config COMPAT bool depends on SPARC32_COMPAT default y - -config BINFMT_ELF32 - bool "Kernel support for 32-bit ELF binaries" - depends on SPARC32_COMPAT - help - This allows you to run 32-bit Linux/ELF binaries on your Ultra. - Everybody wants this; say Y. + select COMPAT_BINFMT_ELF config BINFMT_AOUT32 bool "Kernel support for 32-bit (ie. SunOS) a.out binaries" - depends on SPARC32_COMPAT + depends on SPARC32_COMPAT && ARCH_SUPPORTS_AOUT help This allows you to run 32-bit a.out format binaries on your Ultra. If you want to run SunOS binaries (see SunOS binary emulation below) diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index f62d9f6c5e2a..833d74b2b192 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc4 -# Tue Dec 4 00:37:59 2007 +# Linux kernel version: 2.6.24 +# Tue Feb 5 17:28:19 2008 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -17,6 +17,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_AUDIT_ARCH=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_OF=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y @@ -30,13 +31,15 @@ CONFIG_HZ_100=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 +# CONFIG_SCHED_HRTICK is not set +CONFIG_HOTPLUG_CPU=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # General setup # CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set @@ -76,6 +79,7 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y @@ -83,6 +87,14 @@ CONFIG_SLUB_DEBUG=y # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -92,6 +104,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_BSG=y @@ -109,6 +122,8 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set CONFIG_SYSVIPC_COMPAT=y CONFIG_GENERIC_HARDIRQS=y @@ -119,7 +134,8 @@ CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -# CONFIG_SMP is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=64 # CONFIG_CPU_FREQ is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -169,9 +185,12 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m CONFIG_SOLARIS_EMUL=y +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set +# CONFIG_RCU_TRACE is not set # CONFIG_CMDLINE_BOOL is not set # @@ -189,6 +208,7 @@ CONFIG_XFRM=y CONFIG_XFRM_USER=m # CONFIG_XFRM_SUB_POLICY is not set CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y @@ -249,9 +269,9 @@ CONFIG_IP_DCCP_ACKVEC=y CONFIG_IP_DCCP_CCID2=m # CONFIG_IP_DCCP_CCID2_DEBUG is not set CONFIG_IP_DCCP_CCID3=m -CONFIG_IP_DCCP_TFRC_LIB=m # CONFIG_IP_DCCP_CCID3_DEBUG is not set CONFIG_IP_DCCP_CCID3_RTO=100 +CONFIG_IP_DCCP_TFRC_LIB=m # # DCCP Kernel Hacking @@ -279,6 +299,7 @@ CONFIG_VLAN_8021Q=m CONFIG_NET_PKTGEN=m CONFIG_NET_TCPPROBE=m # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -343,6 +364,7 @@ CONFIG_BLK_DEV_IDE=y CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set @@ -359,7 +381,6 @@ CONFIG_IDE_GENERIC=y # PCI IDE chipsets support # CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_IDEPCI_PCIBUS_ORDER=y # CONFIG_BLK_DEV_GENERIC is not set # CONFIG_BLK_DEV_OPTI621 is not set @@ -389,7 +410,6 @@ CONFIG_BLK_DEV_ALI15X3=y # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_TC86C001 is not set -# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDE_ARCH_OBSOLETE_INIT=y # CONFIG_BLK_DEV_HD is not set @@ -501,7 +521,6 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_VETH is not set -# CONFIG_IP1000 is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set CONFIG_NET_ETHERNET=y @@ -533,6 +552,7 @@ CONFIG_NET_PCI=y # CONFIG_NE2K_PCI is not set # CONFIG_8139CP is not set # CONFIG_8139TOO is not set +# CONFIG_R6040 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -545,6 +565,9 @@ CONFIG_E1000=m CONFIG_E1000_NAPI=y # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set # CONFIG_E1000E is not set +# CONFIG_E1000E_ENABLED is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -570,6 +593,7 @@ CONFIG_NETDEV_10000=y CONFIG_NIU=m # CONFIG_MLX4_CORE is not set # CONFIG_TEHUTI is not set +# CONFIG_BNX2X is not set # CONFIG_TR is not set # @@ -602,7 +626,6 @@ CONFIG_PPPOE=m # CONFIG_SLIP is not set CONFIG_SLHC=m # CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -679,6 +702,7 @@ CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # # Serial drivers @@ -747,13 +771,13 @@ CONFIG_I2C_ALGOBIT=y # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set # CONFIG_DS1682 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -990,6 +1014,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_BT87X is not set # CONFIG_SND_CA0106 is not set # CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_DARLA20 is not set @@ -1014,6 +1039,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set +# CONFIG_SND_HIFIER is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set @@ -1031,6 +1057,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set # CONFIG_SND_YMFPCI is not set # CONFIG_SND_AC97_POWER_SAVE is not set @@ -1058,6 +1085,10 @@ CONFIG_SND_SUN_CS4231=m # # +# ALSA SoC audio for Freescale SOCs +# + +# # Open Sound System # # CONFIG_SOUND_PRIME is not set @@ -1080,6 +1111,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y # CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set # # Miscellaneous USB options @@ -1093,7 +1125,6 @@ CONFIG_USB_DEVICEFS=y # USB Host Controller Drivers # CONFIG_USB_EHCI_HCD=m -# CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set # CONFIG_USB_ISP116X_HCD is not set @@ -1143,10 +1174,6 @@ CONFIG_USB_STORAGE=m # # USB port drivers # - -# -# USB Serial Converter support -# # CONFIG_USB_SERIAL is not set # @@ -1172,14 +1199,6 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_TRANCEVIBRATOR is not set # CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set - -# -# USB DSL modem support -# - -# -# USB Gadget Support -# # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set @@ -1332,11 +1351,6 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set # CONFIG_DLM is not set -CONFIG_INSTRUMENTATION=y -CONFIG_PROFILING=y -CONFIG_OPROFILE=m -CONFIG_KPROBES=y -# CONFIG_MARKERS is not set # # Kernel hacking @@ -1374,6 +1388,8 @@ CONFIG_DEBUG_BUGVERBOSE=y CONFIG_FORCED_INLINING=y # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_SAMPLES is not set @@ -1396,8 +1412,9 @@ CONFIG_ASYNC_MEMCPY=m CONFIG_ASYNC_XOR=m CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y @@ -1416,6 +1433,9 @@ CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_FCRYPT=m @@ -1431,13 +1451,16 @@ CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_SEED=m +# CONFIG_CRYPTO_SALSA20 is not set CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_LZO is not set CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set # # Library routines diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index ef50d217432f..1bf5b187de49 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -11,7 +11,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ - power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ + power.o sbus.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o @@ -21,7 +21,6 @@ obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \ obj-$(CONFIG_PCI_MSI) += pci_msi.o obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o -obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c index 92c1b36a2e16..9877f2d7672d 100644 --- a/arch/sparc64/kernel/binfmt_aout32.c +++ b/arch/sparc64/kernel/binfmt_aout32.c @@ -32,6 +32,7 @@ #include <asm/uaccess.h> #include <asm/pgalloc.h> #include <asm/mmu_context.h> +#include <asm/a.out-core.h> static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout32_library(struct file*); @@ -101,7 +102,7 @@ static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file, current->flags |= PF_DUMPCORE; strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); dump.signal = signr; - dump_thread(regs, &dump); + aout_dump_thread(regs, &dump); /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ diff --git a/arch/sparc64/kernel/binfmt_elf32.c b/arch/sparc64/kernel/binfmt_elf32.c deleted file mode 100644 index 1587a29a4b0e..000000000000 --- a/arch/sparc64/kernel/binfmt_elf32.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * binfmt_elf32.c: Support 32-bit Sparc ELF binaries on Ultra. - * - * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@davemloft.net) - * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) - */ - -#define ELF_ARCH EM_SPARC -#define ELF_CLASS ELFCLASS32 -#define ELF_DATA ELFDATA2MSB; - -/* For the most part we present code dumps in the format - * Solaris does. - */ -typedef unsigned int elf_greg_t; -#define ELF_NGREG 38 -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* Format is: - * G0 --> G7 - * O0 --> O7 - * L0 --> L7 - * I0 --> I7 - * PSR, PC, nPC, Y, WIM, TBR - */ -#include <asm/psrcompat.h> -#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs) \ -do { unsigned int *dest = &(__elf_regs[0]); \ - struct pt_regs *src = (__pt_regs); \ - unsigned int __user *sp; \ - int i; \ - for(i = 0; i < 16; i++) \ - dest[i] = (unsigned int) src->u_regs[i];\ - /* Don't try this at home kids... */ \ - sp = (unsigned int __user *) (src->u_regs[14] & \ - 0x00000000fffffffc); \ - for(i = 0; i < 16; i++) \ - __get_user(dest[i+16], &sp[i]); \ - dest[32] = tstate_to_psr(src->tstate); \ - dest[33] = (unsigned int) src->tpc; \ - dest[34] = (unsigned int) src->tnpc; \ - dest[35] = src->y; \ - dest[36] = dest[37] = 0; /* XXX */ \ -} while(0); - -typedef struct { - union { - unsigned int pr_regs[32]; - unsigned long pr_dregs[16]; - } pr_fr; - unsigned int __unused; - unsigned int pr_fsr; - unsigned char pr_qcnt; - unsigned char pr_q_entrysize; - unsigned char pr_en; - unsigned int pr_q[64]; -} elf_fpregset_t; - -/* UltraSparc extensions. Still unused, but will be eventually. */ -typedef struct { - unsigned int pr_type; - unsigned int pr_align; - union { - struct { - union { - unsigned int pr_regs[32]; - unsigned long pr_dregs[16]; - long double pr_qregs[8]; - } pr_xfr; - } pr_v8p; - unsigned int pr_xfsr; - unsigned int pr_fprs; - unsigned int pr_xg[8]; - unsigned int pr_xo[8]; - unsigned long pr_tstate; - unsigned int pr_filler[8]; - } pr_un; -} elf_xregset_t; - -#define elf_check_arch(x) (((x)->e_machine == EM_SPARC) || ((x)->e_machine == EM_SPARC32PLUS)) - -#define ELF_ET_DYN_BASE 0x70000000 - - -#include <asm/processor.h> -#include <linux/module.h> -#include <linux/elfcore.h> -#include <linux/compat.h> - -#define elf_prstatus elf_prstatus32 -struct elf_prstatus32 -{ - struct elf_siginfo pr_info; /* Info associated with signal */ - short pr_cursig; /* Current signal */ - unsigned int pr_sigpend; /* Set of pending signals */ - unsigned int pr_sighold; /* Set of held signals */ - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pr_sid; - struct compat_timeval pr_utime; /* User time */ - struct compat_timeval pr_stime; /* System time */ - struct compat_timeval pr_cutime; /* Cumulative user time */ - struct compat_timeval pr_cstime; /* Cumulative system time */ - elf_gregset_t pr_reg; /* GP registers */ - int pr_fpvalid; /* True if math co-processor being used. */ -}; - -#define elf_prpsinfo elf_prpsinfo32 -struct elf_prpsinfo32 -{ - char pr_state; /* numeric process state */ - char pr_sname; /* char for pr_state */ - char pr_zomb; /* zombie */ - char pr_nice; /* nice val */ - unsigned int pr_flag; /* flags */ - u16 pr_uid; - u16 pr_gid; - pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; - /* Lots missing */ - char pr_fname[16]; /* filename of executable */ - char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ -}; - -#include <linux/highuid.h> - -#undef NEW_TO_OLD_UID -#undef NEW_TO_OLD_GID -#define NEW_TO_OLD_UID(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid) -#define NEW_TO_OLD_GID(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid) - -#include <linux/time.h> - -#undef cputime_to_timeval -#define cputime_to_timeval cputime_to_compat_timeval -static inline void -cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) -{ - unsigned long jiffies = cputime_to_jiffies(cputime); - value->tv_usec = (jiffies % HZ) * (1000000L / HZ); - value->tv_sec = jiffies / HZ; -} - -#undef start_thread -#define start_thread start_thread32 -#define init_elf_binfmt init_elf32_binfmt - -MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit SparcLinux binaries on the Ultra"); -MODULE_AUTHOR("Eric Youngdale, David S. Miller, Jakub Jelinek"); - -#undef MODULE_DESCRIPTION -#undef MODULE_AUTHOR - -#include <asm/a.out.h> - -#undef TASK_SIZE -#define TASK_SIZE STACK_TOP32 - -#include "../../../fs/binfmt_elf.c" diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index ea257e828364..6be4d2d2904e 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -1477,10 +1477,6 @@ sys32_rt_sigreturn: add %o7, 1f-.-4, %o7 nop #endif -sys_ptrace: add %sp, PTREGS_OFF, %o0 - call do_ptrace - add %o7, 1f-.-4, %o7 - nop .align 32 1: ldx [%curptr + TI_FLAGS], %l5 andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0 diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index c4147ad8677b..44b105c04dd3 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S @@ -632,11 +632,36 @@ tlb_fixup_done: /* Not reached... */ 1: + /* If we boot on a non-zero cpu, all of the per-cpu + * variable references we make before setting up the + * per-cpu areas will use a bogus offset. Put a + * compensating factor into __per_cpu_base to handle + * this cleanly. + * + * What the per-cpu code calculates is: + * + * __per_cpu_base + (cpu << __per_cpu_shift) + * + * These two variables are zero initially, so to + * make it all cancel out to zero we need to put + * "0 - (cpu << 0)" into __per_cpu_base so that the + * above formula evaluates to zero. + * + * We cannot even perform a printk() until this stuff + * is setup as that calls cpu_clock() which uses + * per-cpu variables. + */ + sub %g0, %o0, %o1 + sethi %hi(__per_cpu_base), %o2 + stx %o1, [%o2 + %lo(__per_cpu_base)] #else mov 0, %o0 #endif sth %o0, [%g6 + TI_CPU] + call prom_init_report + nop + /* Off we go.... */ call start_kernel nop diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 4b9115a4d92e..d3276ebcfb47 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c @@ -1,6 +1,6 @@ /* iommu.c: Generic sparc64 IOMMU support. * - * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com) */ @@ -10,6 +10,7 @@ #include <linux/device.h> #include <linux/dma-mapping.h> #include <linux/errno.h> +#include <linux/iommu-helper.h> #ifdef CONFIG_PCI #include <linux/pci.h> @@ -41,7 +42,7 @@ "i" (ASI_PHYS_BYPASS_EC_E)) /* Must be invoked under the IOMMU lock. */ -static void __iommu_flushall(struct iommu *iommu) +static void iommu_flushall(struct iommu *iommu) { if (iommu->iommu_flushinv) { iommu_write(iommu->iommu_flushinv, ~(u64)0); @@ -83,54 +84,91 @@ static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) iopte_val(*iopte) = val; } -/* Based largely upon the ppc64 iommu allocator. */ -static long arena_alloc(struct iommu *iommu, unsigned long npages) +/* Based almost entirely upon the ppc64 iommu allocator. If you use the 'handle' + * facility it must all be done in one pass while under the iommu lock. + * + * On sun4u platforms, we only flush the IOMMU once every time we've passed + * over the entire page table doing allocations. Therefore we only ever advance + * the hint and cannot backtrack it. + */ +unsigned long iommu_range_alloc(struct device *dev, + struct iommu *iommu, + unsigned long npages, + unsigned long *handle) { + unsigned long n, end, start, limit, boundary_size; struct iommu_arena *arena = &iommu->arena; - unsigned long n, i, start, end, limit; - int pass; + int pass = 0; + + /* This allocator was derived from x86_64's bit string search */ + + /* Sanity check */ + if (unlikely(npages == 0)) { + if (printk_ratelimit()) + WARN_ON(1); + return DMA_ERROR_CODE; + } + + if (handle && *handle) + start = *handle; + else + start = arena->hint; limit = arena->limit; - start = arena->hint; - pass = 0; -again: - n = find_next_zero_bit(arena->map, limit, start); - end = n + npages; - if (unlikely(end >= limit)) { + /* The case below can happen if we have a small segment appended + * to a large, or when the previous alloc was at the very end of + * the available space. If so, go back to the beginning and flush. + */ + if (start >= limit) { + start = 0; + if (iommu->flush_all) + iommu->flush_all(iommu); + } + + again: + + if (dev) + boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1, + 1 << IO_PAGE_SHIFT); + else + boundary_size = ALIGN(1UL << 32, 1 << IO_PAGE_SHIFT); + + n = iommu_area_alloc(arena->map, limit, start, npages, 0, + boundary_size >> IO_PAGE_SHIFT, 0); + if (n == -1) { if (likely(pass < 1)) { - limit = start; + /* First failure, rescan from the beginning. */ start = 0; - __iommu_flushall(iommu); + if (iommu->flush_all) + iommu->flush_all(iommu); pass++; goto again; } else { - /* Scanned the whole thing, give up. */ - return -1; + /* Second failure, give up */ + return DMA_ERROR_CODE; } } - for (i = n; i < end; i++) { - if (test_bit(i, arena->map)) { - start = i + 1; - goto again; - } - } - - for (i = n; i < end; i++) - __set_bit(i, arena->map); + end = n + npages; arena->hint = end; + /* Update handle for SG allocations */ + if (handle) + *handle = end; + return n; } -static void arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long npages) { - unsigned long i; + struct iommu_arena *arena = &iommu->arena; + unsigned long entry; - for (i = base; i < (base + npages); i++) - __clear_bit(i, arena->map); + entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; + + iommu_area_free(arena->map, entry, npages); } int iommu_table_init(struct iommu *iommu, int tsbsize, @@ -156,6 +194,9 @@ int iommu_table_init(struct iommu *iommu, int tsbsize, } iommu->arena.limit = num_tsb_entries; + if (tlb_type != hypervisor) + iommu->flush_all = iommu_flushall; + /* Allocate and initialize the dummy page which we * set inactive IO PTEs to point to. */ @@ -192,22 +233,18 @@ out_free_map: return -ENOMEM; } -static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) +static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu, + unsigned long npages) { - long entry; + unsigned long entry; - entry = arena_alloc(iommu, npages); - if (unlikely(entry < 0)) + entry = iommu_range_alloc(dev, iommu, npages, NULL); + if (unlikely(entry == DMA_ERROR_CODE)) return NULL; return iommu->page_table + entry; } -static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) -{ - arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); -} - static int iommu_alloc_ctx(struct iommu *iommu) { int lowest = iommu->ctx_lowest_free; @@ -258,7 +295,7 @@ static void *dma_4u_alloc_coherent(struct device *dev, size_t size, iommu = dev->archdata.iommu; spin_lock_irqsave(&iommu->lock, flags); - iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); + iopte = alloc_npages(dev, iommu, size >> IO_PAGE_SHIFT); spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(iopte == NULL)) { @@ -296,7 +333,7 @@ static void dma_4u_free_coherent(struct device *dev, size_t size, spin_lock_irqsave(&iommu->lock, flags); - free_npages(iommu, dvma - iommu->page_table_map_base, npages); + iommu_range_free(iommu, dvma, npages); spin_unlock_irqrestore(&iommu->lock, flags); @@ -327,7 +364,7 @@ static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, npages >>= IO_PAGE_SHIFT; spin_lock_irqsave(&iommu->lock, flags); - base = alloc_npages(iommu, npages); + base = alloc_npages(dev, iommu, npages); ctx = 0; if (iommu->iommu_ctxflush) ctx = iommu_alloc_ctx(iommu); @@ -465,224 +502,219 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, for (i = 0; i < npages; i++) iopte_make_dummy(iommu, base + i); - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + iommu_range_free(iommu, bus_addr, npages); iommu_free_ctx(iommu, ctx); spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) - -static void fill_sg(iopte_t *iopte, struct scatterlist *sg, - int nused, int nelems, - unsigned long iopte_protection) -{ - struct scatterlist *dma_sg = sg; - int i; - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg = sg_next(sg); - nelems--; - } - - pteval = iopte_protection | (pteval & IOPTE_PAGE); - while (len > 0) { - *iopte++ = __iopte(pteval); - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } - - pteval = (pteval & IOPTE_PAGE) + len; - sg = sg_next(sg); - nelems--; - - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (nelems && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg = sg_next(sg); - nelems--; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg = sg_next(dma_sg); - } -} - static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - struct iommu *iommu; + struct scatterlist *s, *outs, *segstart; + unsigned long flags, handle, prot, ctx; + dma_addr_t dma_next = 0, dma_addr; + unsigned int max_seg_size; + int outcount, incount, i; struct strbuf *strbuf; - unsigned long flags, ctx, npages, iopte_protection; - iopte_t *base; - u32 dma_base; - struct scatterlist *sgtmp; - int used; - - /* Fast path single entry scatterlists. */ - if (nelems == 1) { - sglist->dma_address = - dma_4u_map_single(dev, sg_virt(sglist), - sglist->length, direction); - if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) - return 0; - sglist->dma_length = sglist->length; - return 1; - } + struct iommu *iommu; + + BUG_ON(direction == DMA_NONE); iommu = dev->archdata.iommu; strbuf = dev->archdata.stc; - - if (unlikely(direction == DMA_NONE)) - goto bad_no_ctx; - - /* Step 1: Prepare scatter list. */ - - npages = prepare_sg(dev, sglist, nelems); - - /* Step 2: Allocate a cluster and context, if necessary. */ + if (nelems == 0 || !iommu) + return 0; spin_lock_irqsave(&iommu->lock, flags); - base = alloc_npages(iommu, npages); ctx = 0; if (iommu->iommu_ctxflush) ctx = iommu_alloc_ctx(iommu); - spin_unlock_irqrestore(&iommu->lock, flags); + if (strbuf->strbuf_enabled) + prot = IOPTE_STREAMING(ctx); + else + prot = IOPTE_CONSISTENT(ctx); + if (direction != DMA_TO_DEVICE) + prot |= IOPTE_WRITE; + + outs = s = segstart = &sglist[0]; + outcount = 1; + incount = nelems; + handle = 0; + + /* Init first segment length for backout at failure */ + outs->dma_length = 0; + + max_seg_size = dma_get_max_seg_size(dev); + for_each_sg(sglist, s, nelems, i) { + unsigned long paddr, npages, entry, slen; + iopte_t *base; + + slen = s->length; + /* Sanity check */ + if (slen == 0) { + dma_next = 0; + continue; + } + /* Allocate iommu entries for that segment */ + paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s); + npages = iommu_num_pages(paddr, slen); + entry = iommu_range_alloc(dev, iommu, npages, &handle); + + /* Handle failure */ + if (unlikely(entry == DMA_ERROR_CODE)) { + if (printk_ratelimit()) + printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx" + " npages %lx\n", iommu, paddr, npages); + goto iommu_map_failed; + } - if (base == NULL) - goto bad; + base = iommu->page_table + entry; - dma_base = iommu->page_table_map_base + - ((base - iommu->page_table) << IO_PAGE_SHIFT); + /* Convert entry to a dma_addr_t */ + dma_addr = iommu->page_table_map_base + + (entry << IO_PAGE_SHIFT); + dma_addr |= (s->offset & ~IO_PAGE_MASK); - /* Step 3: Normalize DMA addresses. */ - used = nelems; + /* Insert into HW table */ + paddr &= IO_PAGE_MASK; + while (npages--) { + iopte_val(*base) = prot | paddr; + base++; + paddr += IO_PAGE_SIZE; + } - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp = sg_next(sgtmp); - used--; + /* If we are in an open segment, try merging */ + if (segstart != s) { + /* We cannot merge if: + * - allocated dma_addr isn't contiguous to previous allocation + */ + if ((dma_addr != dma_next) || + (outs->dma_length + s->length > max_seg_size)) { + /* Can't merge: create a new segment */ + segstart = s; + outcount++; + outs = sg_next(outs); + } else { + outs->dma_length += s->length; + } + } + + if (segstart == s) { + /* This is a new segment, fill entries */ + outs->dma_address = dma_addr; + outs->dma_length = slen; + } + + /* Calculate next page pointer for contiguous check */ + dma_next = dma_addr + slen; } - used = nelems - used; - /* Step 4: Create the mappings. */ - if (strbuf->strbuf_enabled) - iopte_protection = IOPTE_STREAMING(ctx); - else - iopte_protection = IOPTE_CONSISTENT(ctx); - if (direction != DMA_TO_DEVICE) - iopte_protection |= IOPTE_WRITE; + spin_unlock_irqrestore(&iommu->lock, flags); - fill_sg(base, sglist, used, nelems, iopte_protection); + if (outcount < incount) { + outs = sg_next(outs); + outs->dma_address = DMA_ERROR_CODE; + outs->dma_length = 0; + } -#ifdef VERIFY_SG - verify_sglist(sglist, nelems, base, npages); -#endif + return outcount; - return used; +iommu_map_failed: + for_each_sg(sglist, s, nelems, i) { + if (s->dma_length != 0) { + unsigned long vaddr, npages, entry, i; + iopte_t *base; + + vaddr = s->dma_address & IO_PAGE_MASK; + npages = iommu_num_pages(s->dma_address, s->dma_length); + iommu_range_free(iommu, vaddr, npages); + + entry = (vaddr - iommu->page_table_map_base) + >> IO_PAGE_SHIFT; + base = iommu->page_table + entry; + + for (i = 0; i < npages; i++) + iopte_make_dummy(iommu, base + i); + + s->dma_address = DMA_ERROR_CODE; + s->dma_length = 0; + } + if (s == outs) + break; + } + spin_unlock_irqrestore(&iommu->lock, flags); -bad: - iommu_free_ctx(iommu, ctx); -bad_no_ctx: - if (printk_ratelimit()) - WARN_ON(1); return 0; } +/* If contexts are being used, they are the same in all of the mappings + * we make for a particular SG. + */ +static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg) +{ + unsigned long ctx = 0; + + if (iommu->iommu_ctxflush) { + iopte_t *base; + u32 bus_addr; + + bus_addr = sg->dma_address & IO_PAGE_MASK; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + } + return ctx; +} + static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - struct iommu *iommu; + unsigned long flags, ctx; + struct scatterlist *sg; struct strbuf *strbuf; - iopte_t *base; - unsigned long flags, ctx, i, npages; - struct scatterlist *sg, *sgprv; - u32 bus_addr; + struct iommu *iommu; - if (unlikely(direction == DMA_NONE)) { - if (printk_ratelimit()) - WARN_ON(1); - } + BUG_ON(direction == DMA_NONE); iommu = dev->archdata.iommu; strbuf = dev->archdata.stc; - bus_addr = sglist->dma_address & IO_PAGE_MASK; - - sgprv = NULL; - for_each_sg(sglist, sg, nelems, i) { - if (sg->dma_length == 0) - break; - sgprv = sg; - } + ctx = fetch_sg_ctx(iommu, sglist); - npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - - bus_addr) >> IO_PAGE_SHIFT; + spin_lock_irqsave(&iommu->lock, flags); - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + sg = sglist; + while (nelems--) { + dma_addr_t dma_handle = sg->dma_address; + unsigned int len = sg->dma_length; + unsigned long npages, entry; + iopte_t *base; + int i; - spin_lock_irqsave(&iommu->lock, flags); + if (!len) + break; + npages = iommu_num_pages(dma_handle, len); + iommu_range_free(iommu, dma_handle, npages); - /* Record the context, if any. */ - ctx = 0; - if (iommu->iommu_ctxflush) - ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + entry = ((dma_handle - iommu->page_table_map_base) + >> IO_PAGE_SHIFT); + base = iommu->page_table + entry; - /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) - strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); + dma_handle &= IO_PAGE_MASK; + if (strbuf->strbuf_enabled) + strbuf_flush(strbuf, iommu, dma_handle, ctx, + npages, direction); - /* Step 2: Clear out the TSB entries. */ - for (i = 0; i < npages; i++) - iopte_make_dummy(iommu, base + i); + for (i = 0; i < npages; i++) + iopte_make_dummy(iommu, base + i); - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + sg = sg_next(sg); + } iommu_free_ctx(iommu, ctx); diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c deleted file mode 100644 index 72a4acfe8c7b..000000000000 --- a/arch/sparc64/kernel/iommu_common.c +++ /dev/null @@ -1,248 +0,0 @@ -/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $ - * iommu_common.c: UltraSparc SBUS/PCI common iommu code. - * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - */ - -#include <linux/dma-mapping.h> -#include "iommu_common.h" - -/* You are _strongly_ advised to enable the following debugging code - * any time you make changes to the sg code below, run it for a while - * with filesystems mounted read-only before buying the farm... -DaveM - */ - -#ifdef VERIFY_SG -static int verify_lengths(struct scatterlist *sglist, int nents, int npages) -{ - int sg_len, dma_len; - int i, pgcount; - struct scatterlist *sg; - - sg_len = 0; - for_each_sg(sglist, sg, nents, i) - sg_len += sg->length; - - dma_len = 0; - for_each_sg(sglist, sg, nents, i) { - if (!sg->dma_length) - break; - dma_len += sg->dma_length; - } - - if (sg_len != dma_len) { - printk("verify_lengths: Error, different, sg[%d] dma[%d]\n", - sg_len, dma_len); - return -1; - } - - pgcount = 0; - for_each_sg(sglist, sg, nents, i) { - unsigned long start, end; - - if (!sg->dma_length) - break; - - start = sg->dma_address; - start = start & IO_PAGE_MASK; - - end = sg->dma_address + sg->dma_length; - end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK; - - pgcount += ((end - start) >> IO_PAGE_SHIFT); - } - - if (pgcount != npages) { - printk("verify_lengths: Error, page count wrong, " - "npages[%d] pgcount[%d]\n", - npages, pgcount); - return -1; - } - - /* This test passes... */ - return 0; -} - -static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte) -{ - struct scatterlist *sg = *__sg; - iopte_t *iopte = *__iopte; - u32 dlen = dma_sg->dma_length; - u32 daddr; - unsigned int sglen; - unsigned long sgaddr; - - daddr = dma_sg->dma_address; - sglen = sg->length; - sgaddr = (unsigned long) sg_virt(sg); - while (dlen > 0) { - unsigned long paddr; - - /* SG and DMA_SG must begin at the same sub-page boundary. */ - if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) { - printk("verify_one_map: Wrong start offset " - "sg[%08lx] dma[%08x]\n", - sgaddr, daddr); - nents = -1; - goto out; - } - - /* Verify the IOPTE points to the right page. */ - paddr = iopte_val(*iopte) & IOPTE_PAGE; - if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) { - printk("verify_one_map: IOPTE[%08lx] maps the " - "wrong page, should be [%08lx]\n", - iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET); - nents = -1; - goto out; - } - - /* If this SG crosses a page, adjust to that next page - * boundary and loop. - */ - if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) { - unsigned long next_page, diff; - - next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK; - diff = next_page - sgaddr; - sgaddr += diff; - daddr += diff; - sglen -= diff; - dlen -= diff; - if (dlen > 0) - iopte++; - continue; - } - - /* SG wholly consumed within this page. */ - daddr += sglen; - dlen -= sglen; - - if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0)) - iopte++; - - sg = sg_next(sg); - if (--nents <= 0) - break; - sgaddr = (unsigned long) sg_virt(sg); - sglen = sg->length; - } - if (dlen < 0) { - /* Transfer overrun, big problems. */ - printk("verify_one_map: Transfer overrun by %d bytes.\n", - -dlen); - nents = -1; - } else { - /* Advance to next dma_sg implies that the next iopte will - * begin it. - */ - iopte++; - } - -out: - *__sg = sg; - *__iopte = iopte; - return nents; -} - -static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte) -{ - struct scatterlist *dma_sg = sg; - struct scatterlist *orig_dma_sg = dma_sg; - int orig_nents = nents; - - for (;;) { - nents = verify_one_map(dma_sg, &sg, nents, &iopte); - if (nents <= 0) - break; - dma_sg = sg_next(dma_sg); - if (dma_sg->dma_length == 0) - break; - } - - if (nents > 0) { - printk("verify_maps: dma maps consumed by some sgs remain (%d)\n", - nents); - return -1; - } - - if (nents < 0) { - printk("verify_maps: Error, messed up mappings, " - "at sg %d dma_sg %d\n", - (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg)); - return -1; - } - - /* This test passes... */ - return 0; -} - -void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int npages) -{ - struct scatterlist *sg; - - if (verify_lengths(sglist, nents, npages) < 0 || - verify_maps(sglist, nents, iopte) < 0) { - int i; - - printk("verify_sglist: Crap, messed up mappings, dumping, iodma at "); - printk("%016lx.\n", sglist->dma_address & IO_PAGE_MASK); - - for_each_sg(sglist, sg, nents, i) { - printk("sg(%d): page_addr(%p) off(%x) length(%x) " - "dma_address[%016x] dma_length[%016x]\n", - i, - page_address(sg_page(sg)), sg->offset, - sg->length, - sg->dma_address, sg->dma_length); - } - } - - /* Seems to be ok */ -} -#endif - -unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents) -{ - struct scatterlist *dma_sg = sg; - unsigned long prev; - u32 dent_addr, dent_len; - unsigned int max_seg_size; - - prev = (unsigned long) sg_virt(sg); - prev += (unsigned long) (dent_len = sg->length); - dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); - max_seg_size = dma_get_max_seg_size(dev); - while (--nents) { - unsigned long addr; - - sg = sg_next(sg); - addr = (unsigned long) sg_virt(sg); - if (! VCONTIG(prev, addr) || - dent_len + sg->length > max_seg_size) { - dma_sg->dma_address = dent_addr; - dma_sg->dma_length = dent_len; - dma_sg = sg_next(dma_sg); - - dent_addr = ((dent_addr + - dent_len + - (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT); - dent_addr <<= IO_PAGE_SHIFT; - dent_addr += addr & (IO_PAGE_SIZE - 1UL); - dent_len = 0; - } - dent_len += sg->length; - prev = addr + sg->length; - } - dma_sg->dma_address = dent_addr; - dma_sg->dma_length = dent_len; - - if (dma_sg != sg) { - dma_sg = sg_next(dma_sg); - dma_sg->dma_length = 0; - } - - return ((unsigned long) dent_addr + - (unsigned long) dent_len + - (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT; -} diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h index a90d046e8024..0713bd58499c 100644 --- a/arch/sparc64/kernel/iommu_common.h +++ b/arch/sparc64/kernel/iommu_common.h @@ -1,9 +1,11 @@ -/* $Id: iommu_common.h,v 1.5 2001/12/11 09:41:01 davem Exp $ - * iommu_common.h: UltraSparc SBUS/PCI common iommu declarations. +/* iommu_common.h: UltraSparc SBUS/PCI common iommu declarations. * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1999, 2008 David S. Miller (davem@davemloft.net) */ +#ifndef _IOMMU_COMMON_H +#define _IOMMU_COMMON_H + #include <linux/kernel.h> #include <linux/types.h> #include <linux/sched.h> @@ -30,21 +32,38 @@ */ #define IOMMU_PAGE_SHIFT 13 -/* You are _strongly_ advised to enable the following debugging code - * any time you make changes to the sg code below, run it for a while - * with filesystems mounted read-only before buying the farm... -DaveM - */ -#undef VERIFY_SG +#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) -#ifdef VERIFY_SG -extern void verify_sglist(struct scatterlist *sg, int nents, iopte_t *iopte, int npages); -#endif +static inline unsigned long iommu_num_pages(unsigned long vaddr, + unsigned long slen) +{ + unsigned long npages; -/* Two addresses are "virtually contiguous" if and only if: - * 1) They are equal, or... - * 2) They are both on a page boundary - */ -#define VCONTIG(__X, __Y) (((__X) == (__Y)) || \ - (((__X) | (__Y)) << (64UL - PAGE_SHIFT)) == 0UL) + npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK); + npages >>= IO_PAGE_SHIFT; + + return npages; +} + +static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems) +{ + unsigned long i, npages = 0; + struct scatterlist *sg; + + for_each_sg(sglist, sg, nelems, i) { + unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg); + npages += iommu_num_pages(paddr, sg->length); + } + + return npages; +} + +extern unsigned long iommu_range_alloc(struct device *dev, + struct iommu *iommu, + unsigned long npages, + unsigned long *handle); +extern void iommu_range_free(struct iommu *iommu, + dma_addr_t dma_addr, + unsigned long npages); -extern unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents); +#endif /* _IOMMU_COMMON_H */ diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 30431bd24e1e..5ec06c8c7fea 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -522,7 +522,7 @@ static struct irq_chip sun4v_virq = { .set_affinity = sun4v_virt_set_affinity, }; -static void fastcall pre_flow_handler(unsigned int virt_irq, +static void pre_flow_handler(unsigned int virt_irq, struct irq_desc *desc) { struct irq_handler_data *data = get_irq_chip_data(virt_irq); diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index d94f901d321e..34fc3ddd5002 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c @@ -480,8 +480,117 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) return 0; } -/* architecture specific initialization */ -int arch_init_kprobes(void) +/* Called with kretprobe_lock held. The value stored in the return + * address register is actually 2 instructions before where the + * callee will return to. Sequences usually look something like this + * + * call some_function <--- return register points here + * nop <--- call delay slot + * whatever <--- where callee returns to + * + * To keep trampoline_probe_handler logic simpler, we normalize the + * value kept in ri->ret_addr so we don't need to keep adjusting it + * back and forth. + */ +void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8); + + /* Replace the return addr with trampoline addr */ + regs->u_regs[UREG_RETPC] = + ((unsigned long)kretprobe_trampoline) - 8; +} + +/* + * Called when the probe at kretprobe trampoline is hit + */ +int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct kretprobe_instance *ri = NULL; + struct hlist_head *head, empty_rp; + struct hlist_node *node, *tmp; + unsigned long flags, orig_ret_address = 0; + unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; + + INIT_HLIST_HEAD(&empty_rp); + spin_lock_irqsave(&kretprobe_lock, flags); + head = kretprobe_inst_table_head(current); + + /* + * It is possible to have multiple instances associated with a given + * task either because an multiple functions in the call path + * have a return probe installed on them, and/or more then one return + * return probe was registered for a target function. + * + * We can handle this because: + * - instances are always inserted at the head of the list + * - when multiple return probes are registered for the same + * function, the first instance's ret_addr will point to the + * real return address, and all the rest will point to + * kretprobe_trampoline + */ + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + if (ri->rp && ri->rp->handler) + ri->rp->handler(ri, regs); + + orig_ret_address = (unsigned long)ri->ret_addr; + recycle_rp_inst(ri, &empty_rp); + + if (orig_ret_address != trampoline_address) + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + + kretprobe_assert(ri, orig_ret_address, trampoline_address); + regs->tpc = orig_ret_address; + regs->tnpc = orig_ret_address + 4; + + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); + preempt_enable_no_resched(); + + hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { + hlist_del(&ri->hlist); + kfree(ri); + } + /* + * By returning a non-zero value, we are telling + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) + */ + return 1; +} + +void kretprobe_trampoline_holder(void) +{ + asm volatile(".global kretprobe_trampoline\n" + "kretprobe_trampoline:\n" + "\tnop\n" + "\tnop\n"); +} +static struct kprobe trampoline_p = { + .addr = (kprobe_opcode_t *) &kretprobe_trampoline, + .pre_handler = trampoline_probe_handler +}; + +int __init arch_init_kprobes(void) { + return register_kprobe(&trampoline_p); +} + +int __kprobes arch_trampoline_kprobe(struct kprobe *p) +{ + if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline) + return 1; + return 0; } diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index fc5c0cc793b8..0fd9db95b896 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -868,29 +868,3 @@ static int __init of_debug(char *str) } __setup("of_debug=", of_debug); - -struct of_device* of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent, - struct bus_type *bus) -{ - struct of_device *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->dev.parent = parent; - dev->dev.bus = bus; - dev->dev.release = of_release_dev; - - strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE); - - if (of_device_register(dev) != 0) { - kfree(dev); - return NULL; - } - - return dev; -} -EXPORT_SYMBOL(of_platform_device_create); diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 5ea2eab1ccda..ddca6c6c0b49 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -1,6 +1,6 @@ /* pci_sun4v.c: SUN4V specific PCI controller support. * - * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 2006, 2007, 2008 David S. Miller (davem@davemloft.net) */ #include <linux/kernel.h> @@ -89,6 +89,17 @@ static long iommu_batch_flush(struct iommu_batch *p) return 0; } +static inline void iommu_batch_new_entry(unsigned long entry) +{ + struct iommu_batch *p = &__get_cpu_var(iommu_batch); + + if (p->entry + p->npages == entry) + return; + if (p->entry != ~0UL) + iommu_batch_flush(p); + p->entry = entry; +} + /* Interrupts must be disabled. */ static inline long iommu_batch_add(u64 phys_page) { @@ -113,54 +124,6 @@ static inline long iommu_batch_end(void) return iommu_batch_flush(p); } -static long arena_alloc(struct iommu_arena *arena, unsigned long npages) -{ - unsigned long n, i, start, end, limit; - int pass; - - limit = arena->limit; - start = arena->hint; - pass = 0; - -again: - n = find_next_zero_bit(arena->map, limit, start); - end = n + npages; - if (unlikely(end >= limit)) { - if (likely(pass < 1)) { - limit = start; - start = 0; - pass++; - goto again; - } else { - /* Scanned the whole thing, give up. */ - return -1; - } - } - - for (i = n; i < end; i++) { - if (test_bit(i, arena->map)) { - start = i + 1; - goto again; - } - } - - for (i = n; i < end; i++) - __set_bit(i, arena->map); - - arena->hint = end; - - return n; -} - -static void arena_free(struct iommu_arena *arena, unsigned long base, - unsigned long npages) -{ - unsigned long i; - - for (i = base; i < (base + npages); i++) - __clear_bit(i, arena->map); -} - static void *dma_4v_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) { @@ -185,11 +148,11 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, iommu = dev->archdata.iommu; spin_lock_irqsave(&iommu->lock, flags); - entry = arena_alloc(&iommu->arena, npages); + entry = iommu_range_alloc(dev, iommu, npages, NULL); spin_unlock_irqrestore(&iommu->lock, flags); - if (unlikely(entry < 0L)) - goto arena_alloc_fail; + if (unlikely(entry == DMA_ERROR_CODE)) + goto range_alloc_fail; *dma_addrp = (iommu->page_table_map_base + (entry << IO_PAGE_SHIFT)); @@ -219,10 +182,10 @@ static void *dma_4v_alloc_coherent(struct device *dev, size_t size, iommu_map_fail: /* Interrupts are disabled. */ spin_lock(&iommu->lock); - arena_free(&iommu->arena, entry, npages); + iommu_range_free(iommu, *dma_addrp, npages); spin_unlock_irqrestore(&iommu->lock, flags); -arena_alloc_fail: +range_alloc_fail: free_pages(first_page, order); return NULL; } @@ -243,7 +206,7 @@ static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, spin_lock_irqsave(&iommu->lock, flags); - arena_free(&iommu->arena, entry, npages); + iommu_range_free(iommu, dvma, npages); do { unsigned long num; @@ -281,10 +244,10 @@ static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, npages >>= IO_PAGE_SHIFT; spin_lock_irqsave(&iommu->lock, flags); - entry = arena_alloc(&iommu->arena, npages); + entry = iommu_range_alloc(dev, iommu, npages, NULL); spin_unlock_irqrestore(&iommu->lock, flags); - if (unlikely(entry < 0L)) + if (unlikely(entry == DMA_ERROR_CODE)) goto bad; bus_addr = (iommu->page_table_map_base + @@ -319,7 +282,7 @@ bad: iommu_map_fail: /* Interrupts are disabled. */ spin_lock(&iommu->lock); - arena_free(&iommu->arena, entry, npages); + iommu_range_free(iommu, bus_addr, npages); spin_unlock_irqrestore(&iommu->lock, flags); return DMA_ERROR_CODE; @@ -350,9 +313,9 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_lock_irqsave(&iommu->lock, flags); - entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; - arena_free(&iommu->arena, entry, npages); + iommu_range_free(iommu, bus_addr, npages); + entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; do { unsigned long num; @@ -365,174 +328,134 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) - -static long fill_sg(long entry, struct device *dev, - struct scatterlist *sg, - int nused, int nelems, unsigned long prot) +static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction) { - struct scatterlist *dma_sg = sg; - unsigned long flags; - int i; - - local_irq_save(flags); - - iommu_batch_start(dev, prot, entry); - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg = sg_next(sg); - nelems--; - } - - pteval = (pteval & IOPTE_PAGE); - while (len > 0) { - long err; + struct scatterlist *s, *outs, *segstart; + unsigned long flags, handle, prot; + dma_addr_t dma_next = 0, dma_addr; + unsigned int max_seg_size; + int outcount, incount, i; + struct iommu *iommu; + long err; - err = iommu_batch_add(pteval); - if (unlikely(err < 0L)) - goto iommu_map_failed; + BUG_ON(direction == DMA_NONE); - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } + iommu = dev->archdata.iommu; + if (nelems == 0 || !iommu) + return 0; + + prot = HV_PCI_MAP_ATTR_READ; + if (direction != DMA_TO_DEVICE) + prot |= HV_PCI_MAP_ATTR_WRITE; - pteval = (pteval & IOPTE_PAGE) + len; - sg = sg_next(sg); - nelems--; + outs = s = segstart = &sglist[0]; + outcount = 1; + incount = nelems; + handle = 0; - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (nelems && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg = sg_next(sg); - nelems--; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg = sg_next(dma_sg); - } + /* Init first segment length for backout at failure */ + outs->dma_length = 0; - if (unlikely(iommu_batch_end() < 0L)) - goto iommu_map_failed; + spin_lock_irqsave(&iommu->lock, flags); - local_irq_restore(flags); - return 0; + iommu_batch_start(dev, prot, ~0UL); -iommu_map_failed: - local_irq_restore(flags); - return -1L; -} + max_seg_size = dma_get_max_seg_size(dev); + for_each_sg(sglist, s, nelems, i) { + unsigned long paddr, npages, entry, slen; -static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, - int nelems, enum dma_data_direction direction) -{ - struct iommu *iommu; - unsigned long flags, npages, prot; - u32 dma_base; - struct scatterlist *sgtmp; - long entry, err; - int used; - - /* Fast path single entry scatterlists. */ - if (nelems == 1) { - sglist->dma_address = - dma_4v_map_single(dev, sg_virt(sglist), - sglist->length, direction); - if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) - return 0; - sglist->dma_length = sglist->length; - return 1; - } + slen = s->length; + /* Sanity check */ + if (slen == 0) { + dma_next = 0; + continue; + } + /* Allocate iommu entries for that segment */ + paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s); + npages = iommu_num_pages(paddr, slen); + entry = iommu_range_alloc(dev, iommu, npages, &handle); - iommu = dev->archdata.iommu; - - if (unlikely(direction == DMA_NONE)) - goto bad; + /* Handle failure */ + if (unlikely(entry == DMA_ERROR_CODE)) { + if (printk_ratelimit()) + printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx" + " npages %lx\n", iommu, paddr, npages); + goto iommu_map_failed; + } - /* Step 1: Prepare scatter list. */ - npages = prepare_sg(dev, sglist, nelems); + iommu_batch_new_entry(entry); - /* Step 2: Allocate a cluster and context, if necessary. */ - spin_lock_irqsave(&iommu->lock, flags); - entry = arena_alloc(&iommu->arena, npages); - spin_unlock_irqrestore(&iommu->lock, flags); + /* Convert entry to a dma_addr_t */ + dma_addr = iommu->page_table_map_base + + (entry << IO_PAGE_SHIFT); + dma_addr |= (s->offset & ~IO_PAGE_MASK); - if (unlikely(entry < 0L)) - goto bad; + /* Insert into HW table */ + paddr &= IO_PAGE_MASK; + while (npages--) { + err = iommu_batch_add(paddr); + if (unlikely(err < 0L)) + goto iommu_map_failed; + paddr += IO_PAGE_SIZE; + } - dma_base = iommu->page_table_map_base + - (entry << IO_PAGE_SHIFT); + /* If we are in an open segment, try merging */ + if (segstart != s) { + /* We cannot merge if: + * - allocated dma_addr isn't contiguous to previous allocation + */ + if ((dma_addr != dma_next) || + (outs->dma_length + s->length > max_seg_size)) { + /* Can't merge: create a new segment */ + segstart = s; + outcount++; + outs = sg_next(outs); + } else { + outs->dma_length += s->length; + } + } - /* Step 3: Normalize DMA addresses. */ - used = nelems; + if (segstart == s) { + /* This is a new segment, fill entries */ + outs->dma_address = dma_addr; + outs->dma_length = slen; + } - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp = sg_next(sgtmp); - used--; + /* Calculate next page pointer for contiguous check */ + dma_next = dma_addr + slen; } - used = nelems - used; - /* Step 4: Create the mappings. */ - prot = HV_PCI_MAP_ATTR_READ; - if (direction != DMA_TO_DEVICE) - prot |= HV_PCI_MAP_ATTR_WRITE; + err = iommu_batch_end(); - err = fill_sg(entry, dev, sglist, used, nelems, prot); if (unlikely(err < 0L)) goto iommu_map_failed; - return used; + spin_unlock_irqrestore(&iommu->lock, flags); -bad: - if (printk_ratelimit()) - WARN_ON(1); - return 0; + if (outcount < incount) { + outs = sg_next(outs); + outs->dma_address = DMA_ERROR_CODE; + outs->dma_length = 0; + } + + return outcount; iommu_map_failed: - spin_lock_irqsave(&iommu->lock, flags); - arena_free(&iommu->arena, entry, npages); + for_each_sg(sglist, s, nelems, i) { + if (s->dma_length != 0) { + unsigned long vaddr, npages; + + vaddr = s->dma_address & IO_PAGE_MASK; + npages = iommu_num_pages(s->dma_address, s->dma_length); + iommu_range_free(iommu, vaddr, npages); + /* XXX demap? XXX */ + s->dma_address = DMA_ERROR_CODE; + s->dma_length = 0; + } + if (s == outs) + break; + } spin_unlock_irqrestore(&iommu->lock, flags); return 0; @@ -542,47 +465,42 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { struct pci_pbm_info *pbm; + struct scatterlist *sg; struct iommu *iommu; - unsigned long flags, i, npages; - struct scatterlist *sg, *sgprv; - long entry; - u32 devhandle, bus_addr; + unsigned long flags; + u32 devhandle; - if (unlikely(direction == DMA_NONE)) { - if (printk_ratelimit()) - WARN_ON(1); - } + BUG_ON(direction == DMA_NONE); iommu = dev->archdata.iommu; pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; - bus_addr = sglist->dma_address & IO_PAGE_MASK; - sgprv = NULL; - for_each_sg(sglist, sg, nelems, i) { - if (sg->dma_length == 0) - break; - - sgprv = sg; - } - - npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - - bus_addr) >> IO_PAGE_SHIFT; + spin_lock_irqsave(&iommu->lock, flags); - entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + sg = sglist; + while (nelems--) { + dma_addr_t dma_handle = sg->dma_address; + unsigned int len = sg->dma_length; + unsigned long npages, entry; - spin_lock_irqsave(&iommu->lock, flags); + if (!len) + break; + npages = iommu_num_pages(dma_handle, len); + iommu_range_free(iommu, dma_handle, npages); - arena_free(&iommu->arena, entry, npages); + entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + while (npages) { + unsigned long num; - do { - unsigned long num; + num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), + npages); + entry += num; + npages -= num; + } - num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), - npages); - entry += num; - npages -= num; - } while (npages != 0); + sg = sg_next(sg); + } spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index ca7cdfd55f72..1b2379174988 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -24,7 +24,6 @@ #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/reboot.h> #include <linux/delay.h> #include <linux/compat.h> @@ -725,17 +724,6 @@ pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) return retval; } -/* - * fill in the user structure for a core dump.. - */ -void dump_thread(struct pt_regs * regs, struct user * dump) -{ - /* Only should be used for SunOS and ancient a.out - * SparcLinux binaries... Not worth implementing. - */ - memset(dump, 0, sizeof(struct user)); -} - typedef struct { union { unsigned int pr_regs[32]; diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 81111a12f0a8..9a1ba1fe859d 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -1,6 +1,6 @@ /* ptrace.c: Sparc process tracing support. * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * Copyright (C) 1996, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, @@ -22,6 +22,9 @@ #include <linux/seccomp.h> #include <linux/audit.h> #include <linux/signal.h> +#include <linux/regset.h> +#include <linux/compat.h> +#include <linux/elf.h> #include <asm/asi.h> #include <asm/pgtable.h> @@ -33,70 +36,7 @@ #include <asm/page.h> #include <asm/cpudata.h> -/* Returning from ptrace is a bit tricky because the syscall return - * low level code assumes any value returned which is negative and - * is a valid errno will mean setting the condition codes to indicate - * an error return. This doesn't work, so we have this hook. - */ -static inline void pt_error_return(struct pt_regs *regs, unsigned long error) -{ - regs->u_regs[UREG_I0] = error; - regs->tstate |= (TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) -{ - regs->u_regs[UREG_I0] = value; - regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static inline void -pt_succ_return_linux(struct pt_regs *regs, unsigned long value, void __user *addr) -{ - if (test_thread_flag(TIF_32BIT)) { - if (put_user(value, (unsigned int __user *) addr)) { - pt_error_return(regs, EFAULT); - return; - } - } else { - if (put_user(value, (long __user *) addr)) { - pt_error_return(regs, EFAULT); - return; - } - } - regs->u_regs[UREG_I0] = 0; - regs->tstate &= ~(TSTATE_ICARRY | TSTATE_XCARRY); - regs->tpc = regs->tnpc; - regs->tnpc += 4; -} - -static void -pt_os_succ_return (struct pt_regs *regs, unsigned long val, void __user *addr) -{ - if (current->personality == PER_SUNOS) - pt_succ_return (regs, val); - else - pt_succ_return_linux (regs, val, addr); -} - /* #define ALLOW_INIT_TRACING */ -/* #define DEBUG_PTRACE */ - -#ifdef DEBUG_PTRACE -char *pt_rq [] = { - /* 0 */ "TRACEME", "PEEKTEXT", "PEEKDATA", "PEEKUSR", - /* 4 */ "POKETEXT", "POKEDATA", "POKEUSR", "CONT", - /* 8 */ "KILL", "SINGLESTEP", "SUNATTACH", "SUNDETACH", - /* 12 */ "GETREGS", "SETREGS", "GETFPREGS", "SETFPREGS", - /* 16 */ "READDATA", "WRITEDATA", "READTEXT", "WRITETEXT", - /* 20 */ "GETFPAREGS", "SETFPAREGS", "unknown", "unknown", - /* 24 */ "SYSCALL", "" -}; -#endif /* * Called by kernel/ptrace.c when detaching.. @@ -167,481 +107,784 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, } } -asmlinkage void do_ptrace(struct pt_regs *regs) +enum sparc_regset { + REGSET_GENERAL, + REGSET_FP, +}; + +static int genregs64_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) { - int request = regs->u_regs[UREG_I0]; - pid_t pid = regs->u_regs[UREG_I1]; - unsigned long addr = regs->u_regs[UREG_I2]; - unsigned long data = regs->u_regs[UREG_I3]; - unsigned long addr2 = regs->u_regs[UREG_I4]; - struct task_struct *child; + const struct pt_regs *regs = task_pt_regs(target); int ret; - if (test_thread_flag(TIF_32BIT)) { - addr &= 0xffffffffUL; - data &= 0xffffffffUL; - addr2 &= 0xffffffffUL; + if (target == current) + flushw_user(); + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs->u_regs, + 0, 16 * sizeof(u64)); + if (!ret) { + unsigned long __user *reg_window = (unsigned long __user *) + (regs->u_regs[UREG_I6] + STACK_BIAS); + unsigned long window[16]; + + if (copy_from_user(window, reg_window, sizeof(window))) + return -EFAULT; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + window, + 16 * sizeof(u64), + 32 * sizeof(u64)); } - lock_kernel(); -#ifdef DEBUG_PTRACE - { - char *s; - if ((request >= 0) && (request <= 24)) - s = pt_rq [request]; - else - s = "unknown"; - - if (request == PTRACE_POKEDATA && data == 0x91d02001){ - printk ("do_ptrace: breakpoint pid=%d, addr=%016lx addr2=%016lx\n", - pid, addr, addr2); - } else - printk("do_ptrace: rq=%s(%d) pid=%d addr=%016lx data=%016lx addr2=%016lx\n", - s, request, pid, addr, data, addr2); + if (!ret) { + /* TSTATE, TPC, TNPC */ + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + ®s->tstate, + 32 * sizeof(u64), + 35 * sizeof(u64)); } -#endif - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - if (ret < 0) - pt_error_return(regs, -ret); - else - pt_succ_return(regs, 0); - goto out; + + if (!ret) { + unsigned long y = regs->y; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &y, + 35 * sizeof(u64), + 36 * sizeof(u64)); } - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - pt_error_return(regs, -ret); - goto out; + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 36 * sizeof(u64), -1); + + return ret; +} + +static int genregs64_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + if (target == current) + flushw_user(); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs->u_regs, + 0, 16 * sizeof(u64)); + if (!ret && count > 0) { + unsigned long __user *reg_window = (unsigned long __user *) + (regs->u_regs[UREG_I6] + STACK_BIAS); + unsigned long window[16]; + + if (copy_from_user(window, reg_window, sizeof(window))) + return -EFAULT; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + window, + 16 * sizeof(u64), + 32 * sizeof(u64)); + if (!ret && + copy_to_user(reg_window, window, sizeof(window))) + return -EFAULT; } - if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) - || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { - if (ptrace_attach(child)) { - pt_error_return(regs, EPERM); - goto out_tsk; + if (!ret && count > 0) { + unsigned long tstate; + + /* TSTATE */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &tstate, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) { + /* Only the condition codes can be modified + * in the %tstate register. + */ + tstate &= (TSTATE_ICC | TSTATE_XCC); + regs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); + regs->tstate |= tstate; } - pt_succ_return(regs, 0); - goto out_tsk; } - ret = ptrace_check_attach(child, request == PTRACE_KILL); - if (ret < 0) { - pt_error_return(regs, -ret); - goto out_tsk; + if (!ret) { + /* TPC, TNPC */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + ®s->tpc, + 33 * sizeof(u64), + 35 * sizeof(u64)); } - if (!(test_thread_flag(TIF_32BIT)) && - ((request == PTRACE_READDATA64) || - (request == PTRACE_WRITEDATA64) || - (request == PTRACE_READTEXT64) || - (request == PTRACE_WRITETEXT64) || - (request == PTRACE_PEEKTEXT64) || - (request == PTRACE_POKETEXT64) || - (request == PTRACE_PEEKDATA64) || - (request == PTRACE_POKEDATA64))) { - addr = regs->u_regs[UREG_G2]; - addr2 = regs->u_regs[UREG_G3]; - request -= 30; /* wheee... */ - } + if (!ret) { + unsigned long y; - switch(request) { - case PTRACE_PEEKUSR: - if (addr != 0) - pt_error_return(regs, EIO); - else - pt_succ_return(regs, 0); - goto out_tsk; - - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA: { - unsigned long tmp64; - unsigned int tmp32; - int res, copied; - - res = -EIO; - if (test_thread_flag(TIF_32BIT)) { - copied = access_process_vm(child, addr, - &tmp32, sizeof(tmp32), 0); - tmp64 = (unsigned long) tmp32; - if (copied == sizeof(tmp32)) - res = 0; - } else { - copied = access_process_vm(child, addr, - &tmp64, sizeof(tmp64), 0); - if (copied == sizeof(tmp64)) - res = 0; - } - if (res < 0) - pt_error_return(regs, -res); - else - pt_os_succ_return(regs, tmp64, (void __user *) data); - goto out_tsk; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &y, + 35 * sizeof(u64), + 36 * sizeof(u64)); + if (!ret) + regs->y = y; } - case PTRACE_POKETEXT: /* write the word at location addr. */ - case PTRACE_POKEDATA: { - unsigned long tmp64; - unsigned int tmp32; - int copied, res = -EIO; - - if (test_thread_flag(TIF_32BIT)) { - tmp32 = data; - copied = access_process_vm(child, addr, - &tmp32, sizeof(tmp32), 1); - if (copied == sizeof(tmp32)) - res = 0; - } else { - tmp64 = data; - copied = access_process_vm(child, addr, - &tmp64, sizeof(tmp64), 1); - if (copied == sizeof(tmp64)) - res = 0; - } - if (res < 0) - pt_error_return(regs, -res); + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 36 * sizeof(u64), -1); + + return ret; +} + +static int fpregs64_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const unsigned long *fpregs = task_thread_info(target)->fpregs; + unsigned long fprs, fsr, gsr; + int ret; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + + if (fprs & FPRS_DL) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 16 * sizeof(u64)); + else + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 0, + 16 * sizeof(u64)); + + if (!ret) { + if (fprs & FPRS_DU) + ret = user_regset_copyout(&pos, &count, + &kbuf, &ubuf, + fpregs + 16, + 16 * sizeof(u64), + 32 * sizeof(u64)); else - pt_succ_return(regs, res); - goto out_tsk; + ret = user_regset_copyout_zero(&pos, &count, + &kbuf, &ubuf, + 16 * sizeof(u64), + 32 * sizeof(u64)); } - case PTRACE_GETREGS: { - struct pt_regs32 __user *pregs = - (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - int rval; - - if (__put_user(tstate_to_psr(cregs->tstate), (&pregs->psr)) || - __put_user(cregs->tpc, (&pregs->pc)) || - __put_user(cregs->tnpc, (&pregs->npc)) || - __put_user(cregs->y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - for (rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); -#ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); -#endif - goto out_tsk; + if (fprs & FPRS_FEF) { + fsr = task_thread_info(target)->xfsr[0]; + gsr = task_thread_info(target)->gsr[0]; + } else { + fsr = gsr = 0; } - case PTRACE_GETREGS64: { - struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned long tpc = cregs->tpc; - int rval; - - if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) - tpc &= 0xffffffff; - if (__put_user(cregs->tstate, (&pregs->tstate)) || - __put_user(tpc, (&pregs->tpc)) || - __put_user(cregs->tnpc, (&pregs->tnpc)) || - __put_user(cregs->y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - for (rval = 1; rval < 16; rval++) - if (__put_user(cregs->u_regs[rval], (&pregs->u_regs[rval - 1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); -#ifdef DEBUG_PTRACE - printk ("PC=%lx nPC=%lx o7=%lx\n", cregs->tpc, cregs->tnpc, cregs->u_regs [15]); -#endif - goto out_tsk; + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fsr, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &gsr, + 33 * sizeof(u64), + 34 * sizeof(u64)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fprs, + 34 * sizeof(u64), + 35 * sizeof(u64)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u64), -1); + + return ret; +} + +static int fpregs64_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *fpregs = task_thread_info(target)->fpregs; + unsigned long fprs; + int ret; + + if (target == current) + save_and_clear_fpu(); + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u64)); + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + task_thread_info(target)->xfsr, + 32 * sizeof(u64), + 33 * sizeof(u64)); + if (!ret) + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + task_thread_info(target)->gsr, + 33 * sizeof(u64), + 34 * sizeof(u64)); + + fprs = task_thread_info(target)->fpsaved[0]; + if (!ret && count > 0) { + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &fprs, + 34 * sizeof(u64), + 35 * sizeof(u64)); } - case PTRACE_SETREGS: { - struct pt_regs32 __user *pregs = - (struct pt_regs32 __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned int psr, pc, npc, y; - int i; - - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - if (__get_user(psr, (&pregs->psr)) || - __get_user(pc, (&pregs->pc)) || - __get_user(npc, (&pregs->npc)) || - __get_user(y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; + fprs |= (FPRS_FEF | FPRS_DL | FPRS_DU); + task_thread_info(target)->fpsaved[0] = fprs; + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u64), -1); + return ret; +} + +static const struct user_regset sparc64_regsets[] = { + /* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * TSTATE, TPC, TNPC, Y + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = 36 * sizeof(u64), + .size = sizeof(u64), .align = sizeof(u64), + .get = genregs64_get, .set = genregs64_set + }, + /* Format is: + * F0 --> F63 + * FSR + * GSR + * FPRS + */ + [REGSET_FP] = { + .core_note_type = NT_PRFPREG, + .n = 35 * sizeof(u64), + .size = sizeof(u64), .align = sizeof(u64), + .get = fpregs64_get, .set = fpregs64_set + }, +}; + +static const struct user_regset_view user_sparc64_view = { + .name = "sparc64", .e_machine = EM_SPARCV9, + .regsets = sparc64_regsets, .n = ARRAY_SIZE(sparc64_regsets) +}; + +static int genregs32_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const struct pt_regs *regs = task_pt_regs(target); + compat_ulong_t __user *reg_window; + compat_ulong_t *k = kbuf; + compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target == current) + flushw_user(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + *k++ = regs->u_regs[pos++]; + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(*k++, ®_window[pos++])) + return -EFAULT; } - cregs->tstate &= ~(TSTATE_ICC); - cregs->tstate |= psr_to_tstate_icc(psr); - if (!((pc | npc) & 3)) { - cregs->tpc = pc; - cregs->tnpc = npc; + } else { + for (; count > 0 && pos < 16; count--) { + if (put_user((compat_ulong_t) regs->u_regs[pos++], u++)) + return -EFAULT; } - cregs->y = y; - for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, ®_window[pos++]) || + put_user(reg, u++)) + return -EFAULT; + } + } + while (count > 0) { + switch (pos) { + case 32: /* PSR */ + reg = tstate_to_psr(regs->tstate); + break; + case 33: /* PC */ + reg = regs->tpc; + break; + case 34: /* NPC */ + reg = regs->tnpc; + break; + case 35: /* Y */ + reg = regs->y; + break; + case 36: /* WIM */ + case 37: /* TBR */ + reg = 0; + break; + default: + goto finish; } - pt_succ_return(regs, 0); - goto out_tsk; + + if (kbuf) + *k++ = reg; + else if (put_user(reg, u++)) + return -EFAULT; + pos++; + count--; } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} - case PTRACE_SETREGS64: { - struct pt_regs __user *pregs = (struct pt_regs __user *) addr; - struct pt_regs *cregs = task_pt_regs(child); - unsigned long tstate, tpc, tnpc, y; - int i; - - /* Must be careful, tracing process can only set certain - * bits in the psr. - */ - if (__get_user(tstate, (&pregs->tstate)) || - __get_user(tpc, (&pregs->tpc)) || - __get_user(tnpc, (&pregs->tnpc)) || - __get_user(y, (&pregs->y))) { - pt_error_return(regs, EFAULT); - goto out_tsk; +static int genregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + compat_ulong_t __user *reg_window; + const compat_ulong_t *k = kbuf; + const compat_ulong_t __user *u = ubuf; + compat_ulong_t reg; + + if (target == current) + flushw_user(); + + pos /= sizeof(reg); + count /= sizeof(reg); + + if (kbuf) { + for (; count > 0 && pos < 16; count--) + regs->u_regs[pos++] = *k++; + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (put_user(*k++, ®_window[pos++])) + return -EFAULT; } - if ((task_thread_info(child)->flags & _TIF_32BIT) != 0) { - tpc &= 0xffffffff; - tnpc &= 0xffffffff; + } else { + for (; count > 0 && pos < 16; count--) { + if (get_user(reg, u++)) + return -EFAULT; + regs->u_regs[pos++] = reg; } - tstate &= (TSTATE_ICC | TSTATE_XCC); - cregs->tstate &= ~(TSTATE_ICC | TSTATE_XCC); - cregs->tstate |= tstate; - if (!((tpc | tnpc) & 3)) { - cregs->tpc = tpc; - cregs->tnpc = tnpc; + + reg_window = (compat_ulong_t __user *) regs->u_regs[UREG_I6]; + for (; count > 0 && pos < 32; count--) { + if (get_user(reg, u++) || + put_user(reg, ®_window[pos++])) + return -EFAULT; } - cregs->y = y; - for (i = 1; i < 16; i++) { - if (__get_user(cregs->u_regs[i], (&pregs->u_regs[i-1]))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } + } + while (count > 0) { + unsigned long tstate; + + if (kbuf) + reg = *k++; + else if (get_user(reg, u++)) + return -EFAULT; + + switch (pos) { + case 32: /* PSR */ + tstate = regs->tstate; + tstate &= ~(TSTATE_ICC | TSTATE_XCC); + tstate |= psr_to_tstate_icc(reg); + regs->tstate = tstate; + break; + case 33: /* PC */ + regs->tpc = reg; + break; + case 34: /* NPC */ + regs->tnpc = reg; + break; + case 35: /* Y */ + regs->y = reg; + break; + case 36: /* WIM */ + case 37: /* TBR */ + break; + default: + goto finish; } - pt_succ_return(regs, 0); - goto out_tsk; + + pos++; + count--; } +finish: + pos *= sizeof(reg); + count *= sizeof(reg); - case PTRACE_GETFPREGS: { - struct fps { - unsigned int regs[32]; - unsigned int fsr; - unsigned int flags; - unsigned int extra; - unsigned int fpqd; - struct fq { - unsigned int insnaddr; - unsigned int insn; - } fpq[16]; - }; - struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - - if (copy_to_user(&fps->regs[0], fpregs, - (32 * sizeof(unsigned int))) || - __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr)) || - __put_user(0, (&fps->fpqd)) || - __put_user(0, (&fps->flags)) || - __put_user(0, (&fps->extra)) || - clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 38 * sizeof(reg), -1); +} + +static int fpregs32_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + const unsigned long *fpregs = task_thread_info(target)->fpregs; + compat_ulong_t enabled; + unsigned long fprs; + compat_ulong_t fsr; + int ret = 0; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + if (fprs & FPRS_FEF) { + fsr = task_thread_info(target)->xfsr[0]; + enabled = 1; + } else { + fsr = 0; + enabled = 0; } - case PTRACE_GETFPREGS64: { - struct fps { - unsigned int regs[64]; - unsigned long fsr; - }; - struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - - if (copy_to_user(&fps->regs[0], fpregs, - (64 * sizeof(unsigned int))) || - __put_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; - } - pt_succ_return(regs, 0); - goto out_tsk; + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u32)); + + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret) + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + + if (!ret) { + compat_ulong_t val; + + val = (enabled << 8) | (8 << 16); + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + &val, + 34 * sizeof(u32), + 35 * sizeof(u32)); } - case PTRACE_SETFPREGS: { - struct fps { - unsigned int regs[32]; - unsigned int fsr; - unsigned int flags; - unsigned int extra; - unsigned int fpqd; - struct fq { - unsigned int insnaddr; - unsigned int insn; - } fpq[16]; - }; - struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - unsigned fsr; - - if (copy_from_user(fpregs, &fps->regs[0], - (32 * sizeof(unsigned int))) || - __get_user(fsr, (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; + if (!ret) + ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + 35 * sizeof(u32), -1); + + return ret; +} + +static int fpregs32_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long *fpregs = task_thread_info(target)->fpregs; + unsigned long fprs; + int ret; + + if (target == current) + save_and_clear_fpu(); + + fprs = task_thread_info(target)->fpsaved[0]; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + fpregs, + 0, 32 * sizeof(u32)); + if (!ret) + user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 32 * sizeof(u32), + 33 * sizeof(u32)); + if (!ret && count > 0) { + compat_ulong_t fsr; + unsigned long val; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + &fsr, + 33 * sizeof(u32), + 34 * sizeof(u32)); + if (!ret) { + val = task_thread_info(target)->xfsr[0]; + val &= 0xffffffff00000000UL; + val |= fsr; + task_thread_info(target)->xfsr[0] = val; } - task_thread_info(child)->xfsr[0] &= 0xffffffff00000000UL; - task_thread_info(child)->xfsr[0] |= fsr; - if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) - task_thread_info(child)->gsr[0] = 0; - task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL); - pt_succ_return(regs, 0); - goto out_tsk; } - case PTRACE_SETFPREGS64: { - struct fps { - unsigned int regs[64]; - unsigned long fsr; - }; - struct fps __user *fps = (struct fps __user *) addr; - unsigned long *fpregs = task_thread_info(child)->fpregs; - - if (copy_from_user(fpregs, &fps->regs[0], - (64 * sizeof(unsigned int))) || - __get_user(task_thread_info(child)->xfsr[0], (&fps->fsr))) { - pt_error_return(regs, EFAULT); - goto out_tsk; + fprs |= (FPRS_FEF | FPRS_DL); + task_thread_info(target)->fpsaved[0] = fprs; + + if (!ret) + ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + 34 * sizeof(u32), -1); + return ret; +} + +static const struct user_regset sparc32_regsets[] = { + /* Format is: + * G0 --> G7 + * O0 --> O7 + * L0 --> L7 + * I0 --> I7 + * PSR, PC, nPC, Y, WIM, TBR + */ + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = 38 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = genregs32_get, .set = genregs32_set + }, + /* Format is: + * F0 --> F31 + * empty 32-bit word + * FSR (32--bit word) + * FPU QUEUE COUNT (8-bit char) + * FPU QUEUE ENTRYSIZE (8-bit char) + * FPU ENABLED (8-bit char) + * empty 8-bit char + * FPU QUEUE (64 32-bit ints) + */ + [REGSET_FP] = { + .core_note_type = NT_PRFPREG, + .n = 99 * sizeof(u32), + .size = sizeof(u32), .align = sizeof(u32), + .get = fpregs32_get, .set = fpregs32_set + }, +}; + +static const struct user_regset_view user_sparc32_view = { + .name = "sparc", .e_machine = EM_SPARC, + .regsets = sparc32_regsets, .n = ARRAY_SIZE(sparc32_regsets) +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + if (test_tsk_thread_flag(task, TIF_32BIT)) + return &user_sparc32_view; + return &user_sparc64_view; +} + +struct compat_fps { + unsigned int regs[32]; + unsigned int fsr; + unsigned int flags; + unsigned int extra; + unsigned int fpqd; + struct compat_fq { + unsigned int insnaddr; + unsigned int insn; + } fpq[16]; +}; + +long compat_arch_ptrace(struct task_struct *child, compat_long_t request, + compat_ulong_t caddr, compat_ulong_t cdata) +{ + const struct user_regset_view *view = task_user_regset_view(child); + compat_ulong_t caddr2 = task_pt_regs(current)->u_regs[UREG_I4]; + struct pt_regs32 __user *pregs; + struct compat_fps __user *fps; + unsigned long addr2 = caddr2; + unsigned long addr = caddr; + unsigned long data = cdata; + int ret; + + pregs = (struct pt_regs32 __user *) addr; + fps = (struct compat_fps __user *) addr; + + switch (request) { + case PTRACE_PEEKUSR: + ret = (addr != 0) ? -EIO : 0; + break; + + case PTRACE_GETREGS: + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 32 * sizeof(u32), + 4 * sizeof(u32), + &pregs->psr); + if (!ret) + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 1 * sizeof(u32), + 15 * sizeof(u32), + &pregs->u_regs[0]); + break; + + case PTRACE_SETREGS: + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 32 * sizeof(u32), + 4 * sizeof(u32), + &pregs->psr); + if (!ret) + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 1 * sizeof(u32), + 15 * sizeof(u32), + &pregs->u_regs[0]); + break; + + case PTRACE_GETFPREGS: + ret = copy_regset_to_user(child, view, REGSET_FP, + 0 * sizeof(u32), + 32 * sizeof(u32), + &fps->regs[0]); + if (!ret) + ret = copy_regset_to_user(child, view, REGSET_FP, + 33 * sizeof(u32), + 1 * sizeof(u32), + &fps->fsr); + if (!ret) { + if (__put_user(0, &fps->flags) || + __put_user(0, &fps->extra) || + __put_user(0, &fps->fpqd) || + clear_user(&fps->fpq[0], 32 * sizeof(unsigned int))) + ret = -EFAULT; } - if (!(task_thread_info(child)->fpsaved[0] & FPRS_FEF)) - task_thread_info(child)->gsr[0] = 0; - task_thread_info(child)->fpsaved[0] |= (FPRS_FEF | FPRS_DL | FPRS_DU); - pt_succ_return(regs, 0); - goto out_tsk; - } + break; + + case PTRACE_SETFPREGS: + ret = copy_regset_from_user(child, view, REGSET_FP, + 0 * sizeof(u32), + 32 * sizeof(u32), + &fps->regs[0]); + if (!ret) + ret = copy_regset_from_user(child, view, REGSET_FP, + 33 * sizeof(u32), + 1 * sizeof(u32), + &fps->fsr); + break; case PTRACE_READTEXT: - case PTRACE_READDATA: { - int res = ptrace_readdata(child, addr, - (char __user *)addr2, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; - } + case PTRACE_READDATA: + ret = ptrace_readdata(child, addr, + (char __user *)addr2, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; case PTRACE_WRITETEXT: - case PTRACE_WRITEDATA: { - int res = ptrace_writedata(child, (char __user *) addr2, - addr, data); - if (res == data) { - pt_succ_return(regs, 0); - goto out_tsk; - } - if (res >= 0) - res = -EIO; - pt_error_return(regs, -res); - goto out_tsk; + case PTRACE_WRITEDATA: + ret = ptrace_writedata(child, (char __user *) addr2, + addr, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; + + default: + ret = compat_ptrace_request(child, request, addr, data); + break; } - case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ - addr = 1; - case PTRACE_CONT: { /* restart after signal. */ - if (!valid_signal(data)) { - pt_error_return(regs, EIO); - goto out_tsk; - } + return ret; +} - if (request == PTRACE_SYSCALL) { - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } else { - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } +struct fps { + unsigned int regs[64]; + unsigned long fsr; +}; - child->exit_code = data; -#ifdef DEBUG_PTRACE - printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n", child->comm, - child->pid, child->exit_code, - task_pt_regs(child)->tpc, - task_pt_regs(child)->tnpc); - -#endif - wake_up_process(child); - pt_succ_return(regs, 0); - goto out_tsk; - } +long arch_ptrace(struct task_struct *child, long request, long addr, long data) +{ + const struct user_regset_view *view = task_user_regset_view(child); + struct pt_regs __user *pregs = (struct pt_regs __user *) addr; + unsigned long addr2 = task_pt_regs(current)->u_regs[UREG_I4]; + struct fps __user *fps = (struct fps __user *) addr; + int ret; -/* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: { - if (child->exit_state == EXIT_ZOMBIE) { /* already dead */ - pt_succ_return(regs, 0); - goto out_tsk; + switch (request) { + case PTRACE_PEEKUSR: + ret = (addr != 0) ? -EIO : 0; + break; + + case PTRACE_GETREGS64: + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 1 * sizeof(u64), + 15 * sizeof(u64), + &pregs->u_regs[0]); + if (!ret) { + /* XXX doesn't handle 'y' register correctly XXX */ + ret = copy_regset_to_user(child, view, REGSET_GENERAL, + 32 * sizeof(u64), + 4 * sizeof(u64), + &pregs->tstate); } - child->exit_code = SIGKILL; - wake_up_process(child); - pt_succ_return(regs, 0); - goto out_tsk; - } + break; - case PTRACE_SUNDETACH: { /* detach a process that was attached. */ - int error = ptrace_detach(child, data); - if (error) { - pt_error_return(regs, EIO); - goto out_tsk; + case PTRACE_SETREGS64: + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 1 * sizeof(u64), + 15 * sizeof(u64), + &pregs->u_regs[0]); + if (!ret) { + /* XXX doesn't handle 'y' register correctly XXX */ + ret = copy_regset_from_user(child, view, REGSET_GENERAL, + 32 * sizeof(u64), + 4 * sizeof(u64), + &pregs->tstate); } - pt_succ_return(regs, 0); - goto out_tsk; - } + break; - /* PTRACE_DUMPCORE unsupported... */ + case PTRACE_GETFPREGS64: + ret = copy_regset_to_user(child, view, REGSET_FP, + 0 * sizeof(u64), + 33 * sizeof(u64), + fps); + break; - case PTRACE_GETEVENTMSG: { - int err; + case PTRACE_SETFPREGS64: + ret = copy_regset_to_user(child, view, REGSET_FP, + 0 * sizeof(u64), + 33 * sizeof(u64), + fps); + break; - if (test_thread_flag(TIF_32BIT)) - err = put_user(child->ptrace_message, - (unsigned int __user *) data); - else - err = put_user(child->ptrace_message, - (unsigned long __user *) data); - if (err) - pt_error_return(regs, -err); - else - pt_succ_return(regs, 0); + case PTRACE_READTEXT: + case PTRACE_READDATA: + ret = ptrace_readdata(child, addr, + (char __user *)addr2, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; break; - } - default: { - int err = ptrace_request(child, request, addr, data); - if (err) - pt_error_return(regs, -err); - else - pt_succ_return(regs, 0); - goto out_tsk; - } + case PTRACE_WRITETEXT: + case PTRACE_WRITEDATA: + ret = ptrace_writedata(child, (char __user *) addr2, + addr, data); + if (ret == data) + ret = 0; + else if (ret >= 0) + ret = -EIO; + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; } -out_tsk: - if (child) - put_task_struct(child); -out: - unlock_kernel(); + + return ret; } asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c index a813441b358f..5964d8653ade 100644 --- a/arch/sparc64/kernel/setup.c +++ b/arch/sparc64/kernel/setup.c @@ -15,7 +15,6 @@ #include <linux/slab.h> #include <asm/smp.h> #include <linux/user.h> -#include <linux/a.out.h> #include <linux/screen_info.h> #include <linux/delay.h> #include <linux/fs.h> diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c39944927f1a..a8052b76df41 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -46,8 +46,6 @@ #include <asm/ldc.h> #include <asm/hypervisor.h> -extern void calibrate_delay(void); - int sparc64_multi_core __read_mostly; cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 60765e314bd8..68db08930399 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -53,7 +53,6 @@ #include <asm/ebus.h> #include <asm/isa.h> #endif -#include <asm/a.out.h> #include <asm/ns87303.h> #include <asm/timer.h> #include <asm/cpudata.h> @@ -277,6 +276,7 @@ EXPORT_SYMBOL(sys_getpid); EXPORT_SYMBOL(sys_geteuid); EXPORT_SYMBOL(sys_getuid); EXPORT_SYMBOL(sys_getegid); +EXPORT_SYMBOL(sysctl_nr_open); EXPORT_SYMBOL(sys_getgid); EXPORT_SYMBOL(svr4_getcontext); EXPORT_SYMBOL(svr4_setcontext); diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c index c56573a10eee..134d801579f9 100644 --- a/arch/sparc64/kernel/sys_sparc.c +++ b/arch/sparc64/kernel/sys_sparc.c @@ -28,7 +28,6 @@ #include <asm/uaccess.h> #include <asm/utrap.h> #include <asm/perfctr.h> -#include <asm/a.out.h> #include <asm/unistd.h> /* #define DEBUG_UNIMP_SYSCALL */ diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 98c468803ce3..deaba2bd0535 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -57,7 +57,6 @@ #include <asm/fpumacro.h> #include <asm/semaphore.h> #include <asm/mmu_context.h> -#include <asm/a.out.h> #include <asm/compat_signal.h> asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group) diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index b8058906e727..6b9b718e24af 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -23,7 +23,7 @@ sys_call_table32: /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod /*15*/ .word sys_chmod, sys32_lchown16, sparc_brk, sys32_perfctr, sys32_lseek /*20*/ .word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16 -/*25*/ .word sys32_vmsplice, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause +/*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid @@ -80,7 +80,8 @@ sys_call_table32: .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare /*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait -/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate +/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate + .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime #endif /* CONFIG_COMPAT */ @@ -152,7 +153,8 @@ sys_call_table: .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare /*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait -/*310*/ .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate +/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate + .word sys_timerfd_settime, sys_timerfd_gettime #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) @@ -271,6 +273,7 @@ sunos_sys_table: .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys /*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys - .word sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys #endif diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 4352ee4d8dac..d204f1ab1d4c 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1707,6 +1707,11 @@ static void __exit rtc_mini_exit(void) misc_deregister(&rtc_mini_dev); } +int __devinit read_current_timer(unsigned long *timer_val) +{ + *timer_val = tick_ops->get_tick(); + return 0; +} module_init(rtc_mini_init); module_exit(rtc_mini_exit); diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 523e993ee90c..e726c45645ff 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -997,7 +997,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, prom_printf("reserve_bootmem(initrd): base[%llx] size[%lx]\n", initrd_start, initrd_end); #endif - reserve_bootmem(initrd_start, size); + reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT); initrd_start += PAGE_OFFSET; initrd_end += PAGE_OFFSET; @@ -1007,7 +1007,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, #ifdef CONFIG_DEBUG_BOOTMEM prom_printf("reserve_bootmem(kernel): base[%lx] size[%lx]\n", kern_base, kern_size); #endif - reserve_bootmem(kern_base, kern_size); + reserve_bootmem(kern_base, kern_size, BOOTMEM_DEFAULT); *pages_avail -= PAGE_ALIGN(kern_size) >> PAGE_SHIFT; /* Add back in the initmem pages. */ @@ -1024,7 +1024,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail, prom_printf("reserve_bootmem(bootmap): base[%lx] size[%lx]\n", (bootmap_pfn << PAGE_SHIFT), size); #endif - reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size); + reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT); for (i = 0; i < pavail_ents; i++) { unsigned long start_pfn, end_pfn; @@ -1489,7 +1489,7 @@ static void __init taint_real_pages(void) goto do_next_page; } } - reserve_bootmem(old_start, PAGE_SIZE); + reserve_bootmem(old_start, PAGE_SIZE, BOOTMEM_DEFAULT); do_next_page: old_start += PAGE_SIZE; diff --git a/arch/sparc64/prom/init.c b/arch/sparc64/prom/init.c index 1c0db842a6f4..87e7c7ea0ee6 100644 --- a/arch/sparc64/prom/init.c +++ b/arch/sparc64/prom/init.c @@ -48,7 +48,10 @@ void __init prom_init(void *cif_handler, void *cif_stack) prom_getstring(node, "version", prom_version, sizeof(prom_version)); prom_printf("\n"); +} +void __init prom_init_report(void) +{ printk("PROMLIB: Sun IEEE Boot Prom '%s'\n", prom_version); printk("PROMLIB: Root node compatible: %s\n", prom_root_compatible); } diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 61be597bf430..7d035f0d3ae1 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -434,9 +434,9 @@ asmlinkage int solaris_statvfs(u32 path, u32 buf) error = user_path_walk(A(path),&nd); if (!error) { - struct inode * inode = nd.dentry->d_inode; - error = report_statvfs(nd.mnt, inode, buf); - path_release(&nd); + struct inode *inode = nd.path.dentry->d_inode; + error = report_statvfs(nd.path.mnt, inode, buf); + path_put(&nd.path); } return error; } @@ -464,9 +464,9 @@ asmlinkage int solaris_statvfs64(u32 path, u32 buf) lock_kernel(); error = user_path_walk(A(path), &nd); if (!error) { - struct inode * inode = nd.dentry->d_inode; - error = report_statvfs64(nd.mnt, inode, buf); - path_release(&nd); + struct inode *inode = nd.path.dentry->d_inode; + error = report_statvfs64(nd.path.mnt, inode, buf); + path_put(&nd.path); } unlock_kernel(); return error; @@ -624,7 +624,7 @@ asmlinkage int solaris_ulimit(int cmd, int val) case 3: /* UL_GMEMLIM */ return current->signal->rlim[RLIMIT_DATA].rlim_cur; case 4: /* UL_GDESLIM */ - return NR_OPEN; + return sysctl_nr_open; } return -EINVAL; } diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c index c86cb3091a8e..d3e48e9701bf 100644 --- a/arch/sparc64/solaris/misc.c +++ b/arch/sparc64/solaris/misc.c @@ -415,7 +415,7 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) switch (cmd) { case 0: /* getpgrp */ - return task_pgrp_nr(current); + return task_pgrp_vnr(current); case 1: /* setpgrp */ { int (*sys_setpgid)(pid_t,pid_t) = @@ -426,7 +426,7 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid) ret = sys_setpgid(0, 0); if (ret) return ret; proc_clear_tty(current); - return task_pgrp_nr(current); + return task_pgrp_vnr(current); } case 2: /* getsid */ { diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index a9d32ceabf26..f53123c02c2b 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -859,7 +859,8 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if (fd >= sysctl_nr_open) + goto out; fdt = files_fdtable(current->files); filp = fdt->fd[fd]; @@ -927,7 +928,8 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if (fd >= sysctl_nr_open) + goto out; fdt = files_fdtable(current->files); filp = fdt->fd[fd]; |