Commit a3a543a5 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/sparcwork-2.5

into nuts.ninka.net:/home/davem/src/BK/sparc-2.5
parents b46aedbc b60ccde5
......@@ -152,7 +152,7 @@ void free_irq(unsigned int irq, void *dev_id)
return sun4d_free_irq(irq, dev_id);
}
cpu_irq = irq & NR_IRQS;
cpu_irq = irq & (NR_IRQS - 1);
action = *(cpu_irq + irq_action);
if (cpu_irq > 14) { /* 14 irq levels on the sparc */
printk("Trying to free bogus IRQ %d\n", irq);
......@@ -391,7 +391,7 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
struct irqaction * action;
unsigned int cpu_irq;
cpu_irq = irq & NR_IRQS;
cpu_irq = irq & (NR_IRQS - 1);
action = *(cpu_irq + irq_action);
printk("IO device interrupt, irq = %d\n", irq);
......@@ -469,7 +469,7 @@ int request_fast_irq(unsigned int irq,
extern struct tt_entry trapbase_cpu1, trapbase_cpu2, trapbase_cpu3;
#endif
cpu_irq = irq & NR_IRQS;
cpu_irq = irq & (NR_IRQS - 1);
if(cpu_irq > 14)
return -EINVAL;
if(!handler)
......@@ -559,7 +559,7 @@ int request_irq(unsigned int irq,
unsigned long, const char *, void *);
return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
}
cpu_irq = irq & NR_IRQS;
cpu_irq = irq & (NR_IRQS - 1);
if(cpu_irq > 14)
return -EINVAL;
......
......@@ -57,7 +57,7 @@ static void sun4c_disable_irq(unsigned int irq_nr)
unsigned char current_mask, new_mask;
save_and_cli(flags);
irq_nr &= NR_IRQS;
irq_nr &= (NR_IRQS - 1);
current_mask = *interrupt_enable;
switch(irq_nr) {
case 1:
......@@ -86,7 +86,7 @@ static void sun4c_enable_irq(unsigned int irq_nr)
unsigned char current_mask, new_mask;
save_and_cli(flags);
irq_nr &= NR_IRQS;
irq_nr &= (NR_IRQS - 1);
current_mask = *interrupt_enable;
switch(irq_nr) {
case 1:
......
......@@ -1646,6 +1646,7 @@ config SOFT_WATCHDOG
endmenu
source "arch/sparc64/oprofile/Kconfig"
menu "Kernel hacking"
......
......@@ -68,6 +68,9 @@ core-$(CONFIG_SOLARIS_EMUL) += arch/sparc64/solaris/
core-y += arch/sparc64/math-emu/
libs-y += arch/sparc64/prom/ arch/sparc64/lib/
# FIXME: is drivers- right?
drivers-$(CONFIG_OPROFILE) += arch/sparc64/oprofile/
makeboot =$(Q)$(MAKE) -f scripts/Makefile.build obj=arch/sparc64/boot $(1)
tftpboot.img vmlinux.aout:
......
......@@ -955,6 +955,12 @@ CONFIG_BT_HCIVHCI=m
#
# CONFIG_SOFT_WATCHDOG is not set
#
# Profiling support
#
CONFIG_PROFILING=y
CONFIG_OPROFILE=m
#
# Kernel hacking
#
......
......@@ -16,6 +16,7 @@ obj-y := process.o setup.o cpu.o idprom.o \
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
pci_psycho.o pci_sabre.o pci_schizo.o
obj-$(CONFIG_SMP) += smp.o trampoline.o
obj-$(CONFIG_PROFILING) += profile.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o ioctl32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
obj-$(CONFIG_BINFMT_AOUT32) += binfmt_aout32.o
......
/* arch/sparc64/kernel/profile.c
*
* Almost entirely copied from ppc64 which is:
* (C) 2002 John Levon <levon@movementarian.org>
*/
#include <linux/profile.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <asm/irq.h>
static struct notifier_block *profile_listeners;
static rwlock_t profile_lock = RW_LOCK_UNLOCKED;
int register_profile_notifier(struct notifier_block *nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_register(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
int unregister_profile_notifier(struct notifier_block *nb)
{
int err;
write_lock_irq(&profile_lock);
err = notifier_chain_unregister(&profile_listeners, nb);
write_unlock_irq(&profile_lock);
return err;
}
void sparc64_profile_hook(struct pt_regs *regs)
{
read_lock(&profile_lock);
notifier_call_chain(&profile_listeners, 0, regs);
read_unlock(&profile_lock);
}
......@@ -926,7 +926,7 @@ void smp_promstop_others(void)
smp_cross_call(&xcall_promstop, 0, 0, 0);
}
extern void sparc64_do_profile(unsigned long pc, unsigned long o7);
extern void sparc64_do_profile(struct pt_regs *regs);
static unsigned long current_tick_offset;
......@@ -960,9 +960,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
}
do {
if (!user)
sparc64_do_profile(regs->tpc,
regs->u_regs[UREG_RETPC]);
sparc64_do_profile(regs);
if (!--prof_counter(cpu)) {
if (cpu == boot_cpu_id) {
irq_enter();
......
......@@ -190,6 +190,7 @@ EXPORT_SYMBOL(tlb_type);
EXPORT_SYMBOL(get_fb_unmapped_area);
EXPORT_SYMBOL(flush_icache_range);
EXPORT_SYMBOL(flush_dcache_page);
EXPORT_SYMBOL(__flush_dcache_range);
EXPORT_SYMBOL(mostek_lock);
EXPORT_SYMBOL(mstk48t02_regs);
......@@ -373,3 +374,8 @@ EXPORT_SYMBOL(do_BUG);
/* for ns8703 */
EXPORT_SYMBOL(ns87303_lock);
#ifdef CONFIG_PROFILING
EXPORT_SYMBOL_GPL(register_profile_notifier);
EXPORT_SYMBOL_GPL(unregister_profile_notifier);
#endif
......@@ -952,25 +952,40 @@ static long do_readv_writev32(int type, struct file *file,
io_fn_t fn;
iov_fn_t fnv;
/*
* SuS says "The readv() function *may* fail if the iovcnt argument
* was less than or equal to 0, or greater than {IOV_MAX}. Linux has
* traditionally returned zero for zero segments, so...
*/
retval = 0;
if (count == 0)
goto out;
/* First get the "struct iovec" from user memory and
* verify all the pointers
*/
retval = 0;
if (!count)
goto out_nofree;
retval = -EFAULT;
if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
goto out_nofree;
retval = -EINVAL;
if (count > UIO_MAXIOV)
goto out_nofree;
goto out;
if (!file->f_op)
goto out;
if (count > UIO_FASTIOV) {
retval = -ENOMEM;
iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
if (!iov)
goto out_nofree;
goto out;
}
retval = -EFAULT;
if (verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
goto out;
/*
* Single unix specification:
* We should -EINVAL if an element length is not >= 0 and fitting an
* ssize_t. The total length is fitting an ssize_t
*
* Be careful here because iov_len is a size_t not an ssize_t
*/
tot_len = 0;
i = count;
ivp = iov;
......@@ -980,9 +995,12 @@ static long do_readv_writev32(int type, struct file *file,
compat_ssize_t len;
u32 buf;
__get_user(len, &vector->iov_len);
__get_user(buf, &vector->iov_base);
if (len < 0) /* size_t not fittina an compat_ssize_t .. */
if (__get_user(len, &vector->iov_len) ||
__get_user(buf, &vector->iov_base)) {
retval = -EFAULT;
goto out;
}
if (len < 0) /* size_t not fitting an ssize_t32 .. */
goto out;
tot_len += len;
if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
......@@ -993,25 +1011,32 @@ static long do_readv_writev32(int type, struct file *file,
ivp++;
i--;
}
if (tot_len == 0) {
retval = 0;
goto out;
}
inode = file->f_dentry->d_inode;
/* VERIFY_WRITE actually means a read, as we write to user space */
retval = locks_verify_area((type == VERIFY_WRITE
retval = locks_verify_area((type == READ
? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
inode, file, file->f_pos, tot_len);
if (retval)
goto out;
/* VERIFY_WRITE actually means a read, as we write to user space */
fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
if (type == READ) {
fn = file->f_op->read;
fnv = file->f_op->readv;
} else {
fn = (io_fn_t)file->f_op->write;
fnv = file->f_op->writev;
}
if (fnv) {
retval = fnv(file, iov, count, &file->f_pos);
goto out;
}
fn = (type == VERIFY_WRITE ? file->f_op->read :
(io_fn_t) file->f_op->write);
/* Do it by hand, with file-ops */
ivp = iov;
while (count > 0) {
void * base;
......@@ -1021,7 +1046,9 @@ static long do_readv_writev32(int type, struct file *file,
len = ivp->iov_len;
ivp++;
count--;
nr = fn(file, base, len, &file->f_pos);
if (nr < 0) {
if (!retval)
retval = nr;
......@@ -1034,11 +1061,9 @@ static long do_readv_writev32(int type, struct file *file,
out:
if (iov != iovstack)
kfree(iov);
out_nofree:
/* VERIFY_WRITE actually means a read, as we write to user space */
if ((retval + (type == VERIFY_WRITE)) > 0)
if ((retval + (type == READ)) > 0)
dnotify_parent(file->f_dentry,
(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
(type == READ) ? DN_ACCESS : DN_MODIFY);
return retval;
}
......@@ -1046,35 +1071,46 @@ static long do_readv_writev32(int type, struct file *file,
asmlinkage long sys32_readv(int fd, struct iovec32 *vector, u32 count)
{
struct file *file;
long ret = -EBADF;
int ret;
file = fget(fd);
if(!file)
goto bad_file;
return -EBADF;
if (file->f_op && (file->f_mode & FMODE_READ) &&
(file->f_op->readv || file->f_op->read))
ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
fput(file);
ret = -EBADF;
if (!(file->f_mode & FMODE_READ))
goto out;
ret = -EINVAL;
if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
goto out;
ret = do_readv_writev32(READ, file, vector, count);
bad_file:
out:
fput(file);
return ret;
}
asmlinkage long sys32_writev(int fd, struct iovec32 *vector, u32 count)
{
struct file *file;
int ret = -EBADF;
int ret;
file = fget(fd);
if(!file)
goto bad_file;
if (file->f_op && (file->f_mode & FMODE_WRITE) &&
(file->f_op->writev || file->f_op->write))
ret = do_readv_writev32(VERIFY_READ, file, vector, count);
fput(file);
return -EBADF;
ret = -EBADF;
if (!(file->f_mode & FMODE_WRITE))
goto out;
ret = -EINVAL;
if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
goto out;
ret = do_readv_writev32(WRITE, file, vector, count);
bad_file:
out:
fput(file);
return ret;
}
......@@ -3835,3 +3871,11 @@ asmlinkage int sys32_sched_getaffinity(__kernel_pid_t32 pid, unsigned int len,
return ret;
}
extern int sys_lookup_dcookie(u64 cookie64, char *buf, size_t len);
int sys32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char *buf, size_t len)
{
return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low,
buf, len);
}
......@@ -60,7 +60,7 @@ sys_call_table32:
/*190*/ .word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
.word sys_epoll_wait, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
.word sys32_readahead, sys32_socketcall, sys_syslog, sys_lookup_dcookie, sys_nis_syscall
.word sys32_readahead, sys32_socketcall, sys_syslog, sys32_lookup_dcookie, sys_nis_syscall
/*210*/ .word sys_nis_syscall, sys_nis_syscall, sys_waitpid, sys_swapoff, sys32_sysinfo
.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
/*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys_getpgid
......
......@@ -84,9 +84,23 @@ static __inline__ void timer_check_rtc(void)
}
}
void sparc64_do_profile(unsigned long pc, unsigned long o7)
void sparc64_do_profile(struct pt_regs *regs)
{
if (prof_buffer && current->pid) {
unsigned long pc = regs->tpc;
unsigned long o7 = regs->u_regs[UREG_RETPC];
#ifdef CONFIG_PROFILING
extern void sparc64_profile_hook(struct pt_regs *);
sparc64_profile_hook(regs);
#endif
if (user_mode(regs))
return;
if (!prof_buffer)
return;
{
extern int _stext;
extern int rwlock_impl_begin, rwlock_impl_end;
extern int atomic_impl_begin, atomic_impl_end;
......@@ -123,8 +137,7 @@ static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
do {
#ifndef CONFIG_SMP
if ((regs->tstate & TSTATE_PRIV) != 0)
sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);
sparc64_do_profile(regs);
#endif
do_timer(regs);
......
menu "Profiling support"
depends on EXPERIMENTAL
config PROFILING
bool "Profiling support (EXPERIMENTAL)"
help
Say Y here to enable the extended profiling support mechanisms used
by profilers such as OProfile.
config OPROFILE
tristate "OProfile system profiling (EXPERIMENTAL)"
depends on PROFILING
help
OProfile is a profiling system capable of profiling the
whole system, include the kernel, kernel modules, libraries,
and applications.
If unsure, say N.
endmenu
obj-$(CONFIG_OPROFILE) += oprofile.o
DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprof.o cpu_buffer.o buffer_sync.o \
event_buffer.o oprofile_files.o \
oprofilefs.o oprofile_stats.o )
oprofile-y := $(DRIVER_OBJS) init.o timer_int.o
/**
* @file init.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/oprofile.h>
#include <linux/init.h>
extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
{
timer_init(ops, cpu);
return 0;
}
/**
* @file timer_int.c
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author John Levon <levon@movementarian.org>
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/notifier.h>
#include <linux/smp.h>
#include <linux/irq.h>
#include <linux/oprofile.h>
#include <asm/ptrace.h>
static int timer_notify(struct notifier_block * self, unsigned long val, void * data)
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
oprofile_add_sample(instruction_pointer(regs), 0, cpu);
return 0;
}
static struct notifier_block timer_notifier = {
.notifier_call = timer_notify,
};
static int timer_start(void)
{
return register_profile_notifier(&timer_notifier);
}
static void timer_stop(void)
{
unregister_profile_notifier(&timer_notifier);
}
static struct oprofile_operations timer_ops = {
.start = timer_start,
.stop = timer_stop
};
void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
{
*ops = &timer_ops;
*cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
......@@ -11,6 +11,7 @@
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <asm/pil.h>
#include <asm/ptrace.h>
......@@ -156,4 +157,25 @@ static __inline__ unsigned long get_softint(void)
return retval;
}
struct notifier_block;
#ifdef CONFIG_PROFILING
int register_profile_notifier(struct notifier_block *nb);
int unregister_profile_notifier(struct notifier_block *nb);
#else
static inline int register_profile_notifier(struct notifier_block *nb)
{
return -ENOSYS;
}
static inline int unregister_profile_notifier(struct notifier_block *nb)
{
return -ENOSYS;
}
#endif /* CONFIG_PROFILING */
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment