Commit 56d7957e authored by David Mosberger's avatar David Mosberger

ia64-patches

parent efe80e09
IRQ affinity on IA64 platforms
------------------------------
07.01.2002, Erich Focht <efocht@ess.nec.de>
By writing to /proc/irq/IRQ#/smp_affinity the interrupt routing can be
controlled. The behavior on IA64 platforms is slightly different from
that described in Documentation/IRQ-affinity.txt for i386 systems.
Because of the usage of SAPIC mode and physical destination mode the
IRQ target is one particular CPU and cannot be a mask of several
CPUs. Only the first non-zero bit is taken into account.
Usage examples:
The target CPU has to be specified as a hexadecimal CPU mask. The
first non-zero bit is the selected CPU. This format has been kept for
compatibility reasons with i386.
Set the delivery mode of interrupt 41 to fixed and route the
interrupts to CPU #3 (logical CPU number) (2^3=0x08):
echo "8" >/proc/irq/41/smp_affinity
Set the default route for IRQ number 41 to CPU 6 in lowest priority
delivery mode (redirectable):
echo "r 40" >/proc/irq/41/smp_affinity
The output of the command
cat /proc/irq/IRQ#/smp_affinity
gives the target CPU mask for the specified interrupt vector. If the CPU
mask is preceeded by the character "r", the interrupt is redirectable
(i.e. lowest priority mode routing is used), otherwise its route is
fixed.
Initialization and default behavior:
If the platform features IRQ redirection (info provided by SAL) all
IO-SAPIC interrupts are initialized with CPU#0 as their default target
and the routing is the so called "lowest priority mode" (actually
fixed SAPIC mode with hint). The XTP chipset registers are used as hints
for the IRQ routing. Currently in Linux XTP registers can have three
values:
- minimal for an idle task,
- normal if any other task runs,
- maximal if the CPU is going to be switched off.
The IRQ is routed to the CPU with lowest XTP register value, the
search begins at the default CPU. Therefore most of the interrupts
will be handled by CPU #0.
If the platform doesn't feature interrupt redirection IOSAPIC fixed
routing is used. The target CPUs are distributed in a round robin
manner. IRQs will be routed only to the selected target CPUs. Check
with
cat /proc/interrupts
Comments:
On large (multi-node) systems it is recommended to route the IRQs to
the node to which the corresponding device is connected.
For systems like the NEC AzusA we get IRQ node-affinity for free. This
is because usually the chipsets on each node redirect the interrupts
only to their own CPUs (as they cannot see the XTP registers on the
other nodes).
...@@ -25,7 +25,7 @@ CFLAGS_KERNEL := -mconstant-gp ...@@ -25,7 +25,7 @@ CFLAGS_KERNEL := -mconstant-gp
GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
ifneq ($(GCC_VERSION),2) ifneq ($(GCC_VERSION),2)
CFLAGS += -frename-registers --param max-inline-insns=400 CFLAGS += -frename-registers --param max-inline-insns=2000
endif endif
ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y)
...@@ -58,7 +58,7 @@ ifdef CONFIG_IA64_SGI_SN ...@@ -58,7 +58,7 @@ ifdef CONFIG_IA64_SGI_SN
CFLAGS += -DBRINGUP CFLAGS += -DBRINGUP
SUBDIRS := arch/$(ARCH)/sn/kernel \ SUBDIRS := arch/$(ARCH)/sn/kernel \
arch/$(ARCH)/sn/io \ arch/$(ARCH)/sn/io \
arch/$(ARCH)/sn/fprom \ arch/$(ARCH)/sn/fakeprom \
$(SUBDIRS) $(SUBDIRS)
CORE_FILES := arch/$(ARCH)/sn/kernel/sn.o \ CORE_FILES := arch/$(ARCH)/sn/kernel/sn.o \
arch/$(ARCH)/sn/io/sgiio.o \ arch/$(ARCH)/sn/io/sgiio.o \
......
...@@ -119,6 +119,7 @@ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then ...@@ -119,6 +119,7 @@ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then
source drivers/mtd/Config.in source drivers/mtd/Config.in
source drivers/pnp/Config.in source drivers/pnp/Config.in
source drivers/block/Config.in source drivers/block/Config.in
source drivers/ieee1394/Config.in
source drivers/message/i2o/Config.in source drivers/message/i2o/Config.in
source drivers/md/Config.in source drivers/md/Config.in
...@@ -230,7 +231,7 @@ if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then ...@@ -230,7 +231,7 @@ if [ "$CONFIG_IA64_HP_SIM" != "n" -o "$CONFIG_IA64_GENERIC" != "n" ]; then
mainmenu_option next_comment mainmenu_option next_comment
comment 'Simulated drivers' comment 'Simulated drivers'
tristate 'Simulated Ethernet ' CONFIG_SIMETH bool 'Simulated Ethernet ' CONFIG_SIMETH
bool 'Simulated serial driver support' CONFIG_SIM_SERIAL bool 'Simulated serial driver support' CONFIG_SIM_SERIAL
if [ "$CONFIG_SCSI" != "n" ]; then if [ "$CONFIG_SCSI" != "n" ]; then
bool 'Simulated SCSI disk' CONFIG_SCSI_SIM bool 'Simulated SCSI disk' CONFIG_SCSI_SIM
...@@ -252,13 +253,20 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then ...@@ -252,13 +253,20 @@ if [ "$CONFIG_DEBUG_KERNEL" != "n" ]; then
bool ' Disable VHPT' CONFIG_DISABLE_VHPT bool ' Disable VHPT' CONFIG_DISABLE_VHPT
bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ
# early printk is currently broken for SMP: the secondary processors get stuck... bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
# bool ' Early printk support (requires VGA!)' CONFIG_IA64_EARLY_PRINTK
bool ' Debug memory allocations' CONFIG_DEBUG_SLAB bool ' Debug memory allocations' CONFIG_DEBUG_SLAB
bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK
bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG bool ' Turn on compare-and-exchange bug checking (slow!)' CONFIG_IA64_DEBUG_CMPXCHG
bool ' Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ bool ' Turn on irq debug checks (slow!)' CONFIG_IA64_DEBUG_IRQ
bool ' Built-in Kernel Debugger support' CONFIG_KDB
dep_tristate ' KDB modules' CONFIG_KDB_MODULES $CONFIG_KDB
if [ "$CONFIG_KDB" = "y" ]; then
bool ' KDB off by default' CONFIG_KDB_OFF
comment ' Load all symbols for debugging is required for KDB'
define_bool CONFIG_KALLSYMS y
else
bool ' Load all symbols for debugging' CONFIG_KALLSYMS
fi
fi fi
endmenu endmenu
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
* is sufficient (the IDE driver will autodetect the drive geometry). * is sufficient (the IDE driver will autodetect the drive geometry).
*/ */
char drive_info[4*16]; char drive_info[4*16];
extern int pcat_compat;
unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */ unsigned char aux_device_present = 0xaa; /* XXX remove this when legacy I/O is gone */
...@@ -81,13 +82,19 @@ dig_setup (char **cmdline_p) ...@@ -81,13 +82,19 @@ dig_setup (char **cmdline_p)
screen_info.orig_video_ega_bx = 3; /* XXX fake */ screen_info.orig_video_ega_bx = 3; /* XXX fake */
} }
void void __init
dig_irq_init (void) dig_irq_init (void)
{ {
/* if (pcat_compat) {
* Disable the compatibility mode interrupts (8259 style), needs IN/OUT support /*
* enabled. * Disable the compatibility mode interrupts (8259 style), needs IN/OUT support
*/ * enabled.
outb(0xff, 0xA1); */
outb(0xff, 0x21); printk("%s: Disabling PC-AT compatible 8259 interrupts\n", __FUNCTION__);
outb(0xff, 0xA1);
outb(0xff, 0x21);
} else {
printk("%s: System doesn't have PC-AT compatible dual-8259 setup. "
"Nothing to be done\n", __FUNCTION__);
}
} }
/* /*
* Platform dependent support for HP simulator. * Platform dependent support for HP simulator.
* *
* Copyright (C) 1998, 1999 Hewlett-Packard Co * Copyright (C) 1998, 1999, 2002 Hewlett-Packard Co
* Copyright (C) 1998, 1999 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com> * Copyright (C) 1999 Vijay Chander <vijay@engr.sgi.com>
*/ */
#include <linux/config.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/param.h> #include <linux/param.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/tty.h>
#include <linux/kdev_t.h> #include <linux/kdev_t.h>
#include <linux/console.h> #include <linux/console.h>
...@@ -57,5 +60,5 @@ simcons_write (struct console *cons, const char *buf, unsigned count) ...@@ -57,5 +60,5 @@ simcons_write (struct console *cons, const char *buf, unsigned count)
static kdev_t static kdev_t
simcons_console_device (struct console *c) simcons_console_device (struct console *c)
{ {
return MKDEV(TTY_MAJOR, 64 + c->index); return mk_kdev(TTY_MAJOR, 64 + c->index);
} }
...@@ -142,10 +142,11 @@ ia64_elf32_init (struct pt_regs *regs) ...@@ -142,10 +142,11 @@ ia64_elf32_init (struct pt_regs *regs)
/* /*
* Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor
* format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32
* architecture manual. * architecture manual. Also note that the only fields that are not ignored are
* `base', `limit', 'G', `P' (must be 1) and `S' (must be 0).
*/ */
regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1,
0, 0, 0, 0, 0, 0)); 0, 0, 0, 1, 0, 0, 0));
/* Setup the segment selectors */ /* Setup the segment selectors */
regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */
regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */
...@@ -206,6 +207,7 @@ elf32_set_personality (void) ...@@ -206,6 +207,7 @@ elf32_set_personality (void)
set_personality(PER_LINUX32); set_personality(PER_LINUX32);
current->thread.map_base = IA32_PAGE_OFFSET/3; current->thread.map_base = IA32_PAGE_OFFSET/3;
current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */
current->thread.flags |= IA64_THREAD_XSTACK; /* data must be executable */
set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ set_fs(USER_DS); /* set addr limit for new TASK_SIZE */
} }
......
...@@ -37,7 +37,7 @@ ENTRY(ia32_clone) ...@@ -37,7 +37,7 @@ ENTRY(ia32_clone)
mov loc1=r16 // save ar.pfs across do_fork mov loc1=r16 // save ar.pfs across do_fork
.body .body
zxt4 out1=in1 // newsp zxt4 out1=in1 // newsp
mov out3=0 // stacksize mov out3=16 // stacksize (compensates for 16-byte scratch area)
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
zxt4 out0=in0 // out0 = clone_flags zxt4 out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork br.call.sptk.many rp=do_fork
...@@ -98,7 +98,7 @@ GLOBAL_ENTRY(ia32_ret_from_clone) ...@@ -98,7 +98,7 @@ GLOBAL_ENTRY(ia32_ret_from_clone)
ld8 r2=[r2] ld8 r2=[r2]
;; ;;
mov r8=0 mov r8=0
tbit.nz p6,p0=r2,PT_TRACESYS_BIT tbit.nz p6,p0=r2,PT_SYSCALLTRACE_BIT
(p6) br.cond.spnt .ia32_strace_check_retval (p6) br.cond.spnt .ia32_strace_check_retval
;; // prevent RAW on r8 ;; // prevent RAW on r8
END(ia32_ret_from_clone) END(ia32_ret_from_clone)
...@@ -220,7 +220,7 @@ ia32_syscall_table: ...@@ -220,7 +220,7 @@ ia32_syscall_table:
data8 sys32_pipe data8 sys32_pipe
data8 sys32_times data8 sys32_times
data8 sys32_ni_syscall /* old prof syscall holder */ data8 sys32_ni_syscall /* old prof syscall holder */
data8 sys_brk /* 45 */ data8 sys32_brk /* 45 */
data8 sys_setgid /* 16-bit version */ data8 sys_setgid /* 16-bit version */
data8 sys_getgid /* 16-bit version */ data8 sys_getgid /* 16-bit version */
data8 sys32_signal data8 sys32_signal
......
...@@ -3,12 +3,14 @@ ...@@ -3,12 +3,14 @@
* *
* Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 VA Linux Co
* Copyright (C) 2000 Don Dugger <n0ano@valinux.com> * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
* Copyright (C) 2001 Hewlett-Packard Co * Copyright (C) 2001-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/types.h> #include <linux/types.h>
#include <linux/dirent.h> #include <linux/dirent.h>
#include <linux/fs.h> /* argh, msdos_fs.h isn't self-contained... */
#include <linux/msdos_fs.h> #include <linux/msdos_fs.h>
#include <linux/mtio.h> #include <linux/mtio.h>
#include <linux/ncp_fs.h> #include <linux/ncp_fs.h>
...@@ -79,6 +81,38 @@ sys32_ioctl (unsigned int fd, unsigned int cmd, unsigned int arg) ...@@ -79,6 +81,38 @@ sys32_ioctl (unsigned int fd, unsigned int cmd, unsigned int arg)
return ret; return ret;
} }
case IOCTL_NR(SIOCGIFCONF):
{
struct ifconf32 {
int ifc_len;
unsigned int ifc_ptr;
} ifconf32;
struct ifconf ifconf;
int i, n;
char *p32, *p64;
char buf[32]; /* sizeof IA32 ifreq structure */
if (copy_from_user(&ifconf32, P(arg), sizeof(ifconf32)))
return -EFAULT;
ifconf.ifc_len = ifconf32.ifc_len;
ifconf.ifc_req = P(ifconf32.ifc_ptr);
ret = DO_IOCTL(fd, SIOCGIFCONF, &ifconf);
ifconf32.ifc_len = ifconf.ifc_len;
if (copy_to_user(P(arg), &ifconf32, sizeof(ifconf32)))
return -EFAULT;
n = ifconf.ifc_len / sizeof(struct ifreq);
p32 = P(ifconf32.ifc_ptr);
p64 = P(ifconf32.ifc_ptr);
for (i = 0; i < n; i++) {
if (copy_from_user(buf, p64, sizeof(struct ifreq)))
return -EFAULT;
if (copy_to_user(p32, buf, sizeof(buf)))
return -EFAULT;
p32 += sizeof(buf);
p64 += sizeof(struct ifreq);
}
return ret;
}
case IOCTL_NR(DRM_IOCTL_VERSION): case IOCTL_NR(DRM_IOCTL_VERSION):
{ {
......
/* /*
* IA32 Architecture-specific signal handling support. * IA32 Architecture-specific signal handling support.
* *
* Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999, 2001-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
* Copyright (C) 2000 VA Linux Co * Copyright (C) 2000 VA Linux Co
...@@ -522,6 +522,7 @@ get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) ...@@ -522,6 +522,7 @@ get_sigframe (struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size)
static int static int
setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs)
{ {
struct exec_domain *ed = current_thread_info()->exec_domain;
struct sigframe_ia32 *frame; struct sigframe_ia32 *frame;
int err = 0; int err = 0;
...@@ -530,12 +531,8 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs ...@@ -530,12 +531,8 @@ setup_frame_ia32 (int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
err |= __put_user((current->exec_domain err |= __put_user((ed && ed->signal_invmap && sig < 32
&& current->exec_domain->signal_invmap ? (int)(ed->signal_invmap[sig]) : sig), &frame->sig);
&& sig < 32
? (int)(current->exec_domain->signal_invmap[sig])
: sig),
&frame->sig);
err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]); err |= setup_sigcontext_ia32(&frame->sc, &frame->fpstate, regs, set->sig[0]);
...@@ -590,6 +587,7 @@ static int ...@@ -590,6 +587,7 @@ static int
setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs * regs) sigset_t *set, struct pt_regs * regs)
{ {
struct exec_domain *ed = current_thread_info()->exec_domain;
struct rt_sigframe_ia32 *frame; struct rt_sigframe_ia32 *frame;
int err = 0; int err = 0;
...@@ -598,12 +596,8 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info, ...@@ -598,12 +596,8 @@ setup_rt_frame_ia32 (int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv; goto give_sigsegv;
err |= __put_user((current->exec_domain err |= __put_user((ed && ed->signal_invmap
&& current->exec_domain->signal_invmap && sig < 32 ? ed->signal_invmap[sig] : sig), &frame->sig);
&& sig < 32
? current->exec_domain->signal_invmap[sig]
: sig),
&frame->sig);
err |= __put_user((long)&frame->info, &frame->pinfo); err |= __put_user((long)&frame->info, &frame->pinfo);
err |= __put_user((long)&frame->uc, &frame->puc); err |= __put_user((long)&frame->uc, &frame->puc);
err |= copy_siginfo_to_user32(&frame->info, info); err |= copy_siginfo_to_user32(&frame->info, info);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
* Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com> * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
* Copyright (C) 2001 Hewlett-Packard Co * Copyright (C) 2001-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context
...@@ -153,10 +153,12 @@ ia32_gdt_init (void) ...@@ -153,10 +153,12 @@ ia32_gdt_init (void)
/* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */ /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */
ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE);
for (nr = 0; nr < NR_CPUS; ++nr) { for (nr = 0; nr < NR_CPUS; ++nr) {
ia32_gdt[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, ia32_gdt[_TSS(nr) >> IA32_SEGSEL_INDEX_SHIFT]
0xb, 0, 3, 1, 1, 1, 0); = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235,
ia32_gdt[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, 0xb, 0, 3, 1, 1, 1, 0);
0x2, 0, 3, 1, 1, 1, 0); ia32_gdt[_LDT(nr) >> IA32_SEGSEL_INDEX_SHIFT]
= IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1,
0x2, 0, 3, 1, 1, 1, 0);
} }
} }
...@@ -172,6 +174,10 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) ...@@ -172,6 +174,10 @@ ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs)
siginfo.si_signo = SIGTRAP; siginfo.si_signo = SIGTRAP;
siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_addr = 0;
siginfo.si_imm = 0;
siginfo.si_code = TRAP_BRKPT; siginfo.si_code = TRAP_BRKPT;
force_sig_info(SIGTRAP, &siginfo, current); force_sig_info(SIGTRAP, &siginfo, current);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* IA-32 exception handlers * IA-32 exception handlers
* *
* Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com> * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
* Copyright (C) 2001 Hewlett-Packard Co * Copyright (C) 2001-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* 06/16/00 A. Mallick added siginfo for most cases (close to IA32) * 06/16/00 A. Mallick added siginfo for most cases (close to IA32)
...@@ -40,7 +40,11 @@ ia32_exception (struct pt_regs *regs, unsigned long isr) ...@@ -40,7 +40,11 @@ ia32_exception (struct pt_regs *regs, unsigned long isr)
{ {
struct siginfo siginfo; struct siginfo siginfo;
/* initialize these fields to avoid leaking kernel bits to user space: */
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_imm = 0;
switch ((isr >> 16) & 0xff) { switch ((isr >> 16) & 0xff) {
case 1: case 1:
case 2: case 2:
...@@ -103,6 +107,8 @@ ia32_exception (struct pt_regs *regs, unsigned long isr) ...@@ -103,6 +107,8 @@ ia32_exception (struct pt_regs *regs, unsigned long isr)
* and it will suffer the consequences since we won't be able to * and it will suffer the consequences since we won't be able to
* fully reproduce the context of the exception * fully reproduce the context of the exception
*/ */
siginfo.si_isr = isr;
siginfo.si_flags = __ISR_VALID;
switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) { switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
case 0x000: case 0x000:
default: default:
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com> * Copyright (C) 1999 Arun Sharma <arun.sharma@intel.com>
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 2000-2001 Hewlett-Packard Co * Copyright (C) 2000-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* These routines maintain argument size conversion between 32bit and 64bit * These routines maintain argument size conversion between 32bit and 64bit
...@@ -74,6 +74,9 @@ ...@@ -74,6 +74,9 @@
#define PAGE_START(addr) ((addr) & PAGE_MASK) #define PAGE_START(addr) ((addr) & PAGE_MASK)
#define PAGE_OFF(addr) ((addr) & ~PAGE_MASK) #define PAGE_OFF(addr) ((addr) & ~PAGE_MASK)
#define high2lowuid(uid) ((uid) > 65535 ? 65534 : (uid))
#define high2lowgid(gid) ((gid) > 65535 ? 65534 : (gid))
extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *); extern asmlinkage long sys_execve (char *, char **, char **, struct pt_regs *);
extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long); extern asmlinkage long sys_mprotect (unsigned long, size_t, unsigned long);
extern asmlinkage long sys_munmap (unsigned long, size_t); extern asmlinkage long sys_munmap (unsigned long, size_t);
...@@ -82,6 +85,7 @@ extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsig ...@@ -82,6 +85,7 @@ extern unsigned long arch_get_unmapped_area (struct file *, unsigned long, unsig
/* forward declaration: */ /* forward declaration: */
asmlinkage long sys32_mprotect (unsigned int, unsigned int, int); asmlinkage long sys32_mprotect (unsigned int, unsigned int, int);
asmlinkage unsigned long sys_brk(unsigned long);
/* /*
* Anything that modifies or inspects ia32 user virtual memory must hold this semaphore * Anything that modifies or inspects ia32 user virtual memory must hold this semaphore
...@@ -400,7 +404,7 @@ emulate_mmap (struct file *file, unsigned long start, unsigned long len, int pro ...@@ -400,7 +404,7 @@ emulate_mmap (struct file *file, unsigned long start, unsigned long len, int pro
return -EINVAL; return -EINVAL;
} }
if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0) if (!(prot & PROT_WRITE) && sys_mprotect(pstart, pend - pstart, prot) < 0)
return EINVAL; return -EINVAL;
} }
return start; return start;
} }
...@@ -2578,6 +2582,7 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) ...@@ -2578,6 +2582,7 @@ sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
default: default:
return -EINVAL; return -EINVAL;
} }
return -EINVAL;
} }
/* /*
...@@ -3783,6 +3788,19 @@ sys32_personality (unsigned int personality) ...@@ -3783,6 +3788,19 @@ sys32_personality (unsigned int personality)
return ret; return ret;
} }
asmlinkage unsigned long
sys32_brk (unsigned int brk)
{
unsigned long ret, obrk;
struct mm_struct *mm = current->mm;
obrk = mm->brk;
ret = sys_brk(brk);
if (ret < obrk)
clear_user((void *) ret, PAGE_ALIGN(ret) - ret);
return ret;
}
#ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */
struct ncp_mount_data32 { struct ncp_mount_data32 {
......
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
* 'IA-64 Extensions to ACPI Specification' Revision 0.6 * 'IA-64 Extensions to ACPI Specification' Revision 0.6
* *
* Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999, 2000 Walt Drummond <drummond@valinux.com>
* Copyright (C) 2000 Hewlett-Packard Co. * Copyright (C) 2000, 2002 Hewlett-Packard Co.
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 2000 Intel Corp. * Copyright (C) 2000 Intel Corp.
* Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com> * Copyright (C) 2000, 2001 J.I. Lee <jung-ik.lee@intel.com>
* ACPI based kernel configuration manager. * ACPI based kernel configuration manager.
* ACPI 2.0 & IA64 ext 0.71 * ACPI 2.0 & IA64 ext 0.71
*/ */
...@@ -44,6 +44,8 @@ int platform_irq_list[ACPI_MAX_PLATFORM_IRQS]; ...@@ -44,6 +44,8 @@ int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];
int __initdata available_cpus; int __initdata available_cpus;
int __initdata total_cpus; int __initdata total_cpus;
int __initdata pcat_compat;
void (*pm_idle) (void); void (*pm_idle) (void);
void (*pm_power_off) (void); void (*pm_power_off) (void);
...@@ -293,6 +295,16 @@ acpi20_parse_madt (acpi_madt_t *madt) ...@@ -293,6 +295,16 @@ acpi20_parse_madt (acpi_madt_t *madt)
} else } else
printk("Lapic address set to default 0x%lx\n", ipi_base_addr); printk("Lapic address set to default 0x%lx\n", ipi_base_addr);
/*
* The PCAT_COMPAT flag indicates that the system has a dual-8259 compatible
* setup.
*/
#ifdef CONFIG_ITANIUM
pcat_compat = 1; /* fw on some Itanium systems is broken... */
#else
pcat_compat = (madt->flags & MADT_PCAT_COMPAT);
#endif
p = (char *) (madt + 1); p = (char *) (madt + 1);
end = p + (madt->header.length - sizeof(acpi_madt_t)); end = p + (madt->header.length - sizeof(acpi_madt_t));
...@@ -319,17 +331,7 @@ acpi20_parse_madt (acpi_madt_t *madt) ...@@ -319,17 +331,7 @@ acpi20_parse_madt (acpi_madt_t *madt)
case ACPI20_ENTRY_IO_SAPIC: case ACPI20_ENTRY_IO_SAPIC:
iosapic = (acpi_entry_iosapic_t *) p; iosapic = (acpi_entry_iosapic_t *) p;
if (iosapic_init) if (iosapic_init)
/* iosapic_init(iosapic->address, iosapic->irq_base, pcat_compat);
* The PCAT_COMPAT flag indicates that the system has a
* dual-8259 compatible setup.
*/
iosapic_init(iosapic->address, iosapic->irq_base,
#ifdef CONFIG_ITANIUM
1 /* fw on some Itanium systems is broken... */
#else
(madt->flags & MADT_PCAT_COMPAT)
#endif
);
break; break;
case ACPI20_ENTRY_PLATFORM_INT_SOURCE: case ACPI20_ENTRY_PLATFORM_INT_SOURCE:
...@@ -401,7 +403,7 @@ acpi20_parse (acpi20_rsdp_t *rsdp20) ...@@ -401,7 +403,7 @@ acpi20_parse (acpi20_rsdp_t *rsdp20)
# ifdef CONFIG_ACPI # ifdef CONFIG_ACPI
acpi_xsdt_t *xsdt; acpi_xsdt_t *xsdt;
acpi_desc_table_hdr_t *hdrp; acpi_desc_table_hdr_t *hdrp;
acpi_madt_t *madt; acpi_madt_t *madt = NULL;
int tables, i; int tables, i;
if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) { if (strncmp(rsdp20->signature, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN)) {
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
* Emulation of the "brl" instruction for IA64 processors that * Emulation of the "brl" instruction for IA64 processors that
* don't support it in hardware. * don't support it in hardware.
* Author: Stephan Zeisset, Intel Corp. <Stephan.Zeisset@intel.com> * Author: Stephan Zeisset, Intel Corp. <Stephan.Zeisset@intel.com>
*
* 02/22/02 D. Mosberger Clear si_flgs, si_isr, and si_imm to avoid
* leaking kernel bits.
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -195,6 +198,9 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) ...@@ -195,6 +198,9 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
printk("Woah! Unimplemented Instruction Address Trap!\n"); printk("Woah! Unimplemented Instruction Address Trap!\n");
siginfo.si_signo = SIGILL; siginfo.si_signo = SIGILL;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_imm = 0;
siginfo.si_code = ILL_BADIADDR; siginfo.si_code = ILL_BADIADDR;
force_sig_info(SIGILL, &siginfo, current); force_sig_info(SIGILL, &siginfo, current);
} else if (ia64_psr(regs)->tb) { } else if (ia64_psr(regs)->tb) {
...@@ -205,6 +211,10 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) ...@@ -205,6 +211,10 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
siginfo.si_signo = SIGTRAP; siginfo.si_signo = SIGTRAP;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_code = TRAP_BRANCH; siginfo.si_code = TRAP_BRANCH;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_addr = 0;
siginfo.si_imm = 0;
force_sig_info(SIGTRAP, &siginfo, current); force_sig_info(SIGTRAP, &siginfo, current);
} else if (ia64_psr(regs)->ss) { } else if (ia64_psr(regs)->ss) {
/* /*
...@@ -214,6 +224,10 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec) ...@@ -214,6 +224,10 @@ ia64_emulate_brl (struct pt_regs *regs, unsigned long ar_ec)
siginfo.si_signo = SIGTRAP; siginfo.si_signo = SIGTRAP;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_code = TRAP_TRACE; siginfo.si_code = TRAP_TRACE;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_addr = 0;
siginfo.si_imm = 0;
force_sig_info(SIGTRAP, &siginfo, current); force_sig_info(SIGTRAP, &siginfo, current);
} }
return rv; return rv;
......
...@@ -29,6 +29,11 @@ ...@@ -29,6 +29,11 @@
* *
* Changelog: * Changelog:
* *
* 12 Feb 2002 - Matt Domsch <Matt_Domsch@dell.com>
* use list_for_each_safe when deleting vars.
* remove ifdef CONFIG_SMP around include <linux/smp.h>
* v0.04 release to linux-ia64@linuxia64.org
*
* 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com> * 20 April 2001 - Matt Domsch <Matt_Domsch@dell.com>
* Moved vars from /proc/efi to /proc/efi/vars, and made * Moved vars from /proc/efi to /proc/efi/vars, and made
* efi.c own the /proc/efi directory. * efi.c own the /proc/efi directory.
...@@ -56,18 +61,16 @@ ...@@ -56,18 +61,16 @@
#include <linux/sched.h> /* for capable() */ #include <linux/sched.h> /* for capable() */
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/smp.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#ifdef CONFIG_SMP
#include <linux/smp.h>
#endif
MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>"); MODULE_AUTHOR("Matt Domsch <Matt_Domsch@Dell.com>");
MODULE_DESCRIPTION("/proc interface to EFI Variables"); MODULE_DESCRIPTION("/proc interface to EFI Variables");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define EFIVARS_VERSION "0.03 2001-Apr-20" #define EFIVARS_VERSION "0.04 2002-Feb-12"
static int static int
efivar_read(char *page, char **start, off_t off, efivar_read(char *page, char **start, off_t off,
...@@ -265,7 +268,7 @@ efivar_write(struct file *file, const char *buffer, ...@@ -265,7 +268,7 @@ efivar_write(struct file *file, const char *buffer,
{ {
unsigned long strsize1, strsize2; unsigned long strsize1, strsize2;
int found=0; int found=0;
struct list_head *pos; struct list_head *pos, *n;
unsigned long size = sizeof(efi_variable_t); unsigned long size = sizeof(efi_variable_t);
efi_status_t status; efi_status_t status;
efivar_entry_t *efivar = data, *search_efivar = NULL; efivar_entry_t *efivar = data, *search_efivar = NULL;
...@@ -297,7 +300,7 @@ efivar_write(struct file *file, const char *buffer, ...@@ -297,7 +300,7 @@ efivar_write(struct file *file, const char *buffer,
This allows any properly formatted data structure to This allows any properly formatted data structure to
be written to any of the files in /proc/efi/vars and it will work. be written to any of the files in /proc/efi/vars and it will work.
*/ */
list_for_each(pos, &efivar_list) { list_for_each_safe(pos, n, &efivar_list) {
search_efivar = efivar_entry(pos); search_efivar = efivar_entry(pos);
strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024); strsize1 = utf8_strsize(search_efivar->var.VariableName, 1024);
strsize2 = utf8_strsize(var_data->VariableName, 1024); strsize2 = utf8_strsize(var_data->VariableName, 1024);
...@@ -413,12 +416,12 @@ efivars_init(void) ...@@ -413,12 +416,12 @@ efivars_init(void)
static void __exit static void __exit
efivars_exit(void) efivars_exit(void)
{ {
struct list_head *pos; struct list_head *pos, *n;
efivar_entry_t *efivar; efivar_entry_t *efivar;
spin_lock(&efivars_lock); spin_lock(&efivars_lock);
list_for_each(pos, &efivar_list) { list_for_each_safe(pos, n, &efivar_list) {
efivar = efivar_entry(pos); efivar = efivar_entry(pos);
remove_proc_entry(efivar->entry->name, efi_vars_dir); remove_proc_entry(efivar->entry->name, efi_vars_dir);
list_del(&efivar->list); list_del(&efivar->list);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Kernel entry points. * Kernel entry points.
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
...@@ -30,14 +30,15 @@ ...@@ -30,14 +30,15 @@
#include <linux/config.h> #include <linux/config.h>
#include <asm/asmmacro.h>
#include <asm/cache.h> #include <asm/cache.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <asm/kregs.h> #include <asm/kregs.h>
#include <asm/offsets.h> #include <asm/offsets.h>
#include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/thread_info.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/asmmacro.h>
#include <asm/pgtable.h>
#include "minstate.h" #include "minstate.h"
...@@ -115,7 +116,7 @@ GLOBAL_ENTRY(sys_clone) ...@@ -115,7 +116,7 @@ GLOBAL_ENTRY(sys_clone)
mov loc1=r16 // save ar.pfs across do_fork mov loc1=r16 // save ar.pfs across do_fork
.body .body
mov out1=in1 mov out1=in1
mov out3=0 mov out3=16 // stacksize (compensates for 16-byte scratch area)
adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs adds out2=IA64_SWITCH_STACK_SIZE+16,sp // out2 = &regs
mov out0=in0 // out0 = clone_flags mov out0=in0 // out0 = clone_flags
br.call.sptk.many rp=do_fork br.call.sptk.many rp=do_fork
...@@ -128,6 +129,9 @@ END(sys_clone) ...@@ -128,6 +129,9 @@ END(sys_clone)
/* /*
* prev_task <- ia64_switch_to(struct task_struct *next) * prev_task <- ia64_switch_to(struct task_struct *next)
* With Ingo's new scheduler, interrupts are disabled when this routine gets
* called. The code starting at .map relies on this. The rest of the code
* doesn't care about the interrupt masking status.
*/ */
GLOBAL_ENTRY(ia64_switch_to) GLOBAL_ENTRY(ia64_switch_to)
.prologue .prologue
...@@ -158,10 +162,8 @@ GLOBAL_ENTRY(ia64_switch_to) ...@@ -158,10 +162,8 @@ GLOBAL_ENTRY(ia64_switch_to)
(p6) srlz.d (p6) srlz.d
ld8 sp=[r21] // load kernel stack pointer of new task ld8 sp=[r21] // load kernel stack pointer of new task
mov IA64_KR(CURRENT)=r20 // update "current" application register mov IA64_KR(CURRENT)=r20 // update "current" application register
mov r8=r13 // return pointer to previously running task
mov r13=in0 // set "current" pointer mov r13=in0 // set "current" pointer
;; ;;
(p6) ssm psr.i // renable psr.i AFTER the ic bit is serialized
DO_LOAD_SWITCH_STACK DO_LOAD_SWITCH_STACK
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -170,7 +172,7 @@ GLOBAL_ENTRY(ia64_switch_to) ...@@ -170,7 +172,7 @@ GLOBAL_ENTRY(ia64_switch_to)
br.ret.sptk.many rp // boogie on out in new context br.ret.sptk.many rp // boogie on out in new context
.map: .map:
rsm psr.i | psr.ic rsm psr.ic // interrupts (psr.i) are already disabled here
movl r25=PAGE_KERNEL movl r25=PAGE_KERNEL
;; ;;
srlz.d srlz.d
...@@ -433,7 +435,7 @@ GLOBAL_ENTRY(invoke_syscall_trace) ...@@ -433,7 +435,7 @@ GLOBAL_ENTRY(invoke_syscall_trace)
.body .body
mov loc2=b6 mov loc2=b6
;; ;;
#error br.call.sptk.many rp=syscall_trace br.call.sptk.many rp=syscall_trace
.ret3: mov rp=loc0 .ret3: mov rp=loc0
mov ar.pfs=loc1 mov ar.pfs=loc1
mov b6=loc2 mov b6=loc2
...@@ -454,7 +456,7 @@ END(invoke_syscall_trace) ...@@ -454,7 +456,7 @@ END(invoke_syscall_trace)
GLOBAL_ENTRY(ia64_trace_syscall) GLOBAL_ENTRY(ia64_trace_syscall)
PT_REGS_UNWIND_INFO(0) PT_REGS_UNWIND_INFO(0)
#error br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch syscall args
.ret6: br.call.sptk.many rp=b6 // do the syscall .ret6: br.call.sptk.many rp=b6 // do the syscall
strace_check_retval: strace_check_retval:
cmp.lt p6,p0=r8,r0 // syscall failed? cmp.lt p6,p0=r8,r0 // syscall failed?
...@@ -467,7 +469,7 @@ strace_save_retval: ...@@ -467,7 +469,7 @@ strace_save_retval:
.mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8 .mem.offset 0,0; st8.spill [r2]=r8 // store return value in slot for r8
.mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10 .mem.offset 8,0; st8.spill [r3]=r10 // clear error indication in slot for r10
ia64_strace_leave_kernel: ia64_strace_leave_kernel:
#error br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value br.call.sptk.many rp=invoke_syscall_trace // give parent a chance to catch return value
.rety: br.cond.sptk ia64_leave_kernel .rety: br.cond.sptk ia64_leave_kernel
strace_error: strace_error:
...@@ -491,12 +493,12 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ...@@ -491,12 +493,12 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
*/ */
br.call.sptk.many rp=ia64_invoke_schedule_tail br.call.sptk.many rp=ia64_invoke_schedule_tail
.ret8: .ret8:
adds r2=IA64_TASK_PTRACE_OFFSET,r13 adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
;; ;;
ld8 r2=[r2] ld4 r2=[r2]
;; ;;
mov r8=0 mov r8=0
tbit.nz p6,p0=r2,PT_TRACESYS_BIT tbit.nz p6,p0=r2,TIF_SYSCALL_TRACE
(p6) br.cond.spnt strace_check_retval (p6) br.cond.spnt strace_check_retval
;; // added stop bits to prevent r8 dependency ;; // added stop bits to prevent r8 dependency
END(ia64_ret_from_clone) END(ia64_ret_from_clone)
...@@ -516,50 +518,29 @@ END(ia64_ret_from_syscall) ...@@ -516,50 +518,29 @@ END(ia64_ret_from_syscall)
// fall through // fall through
GLOBAL_ENTRY(ia64_leave_kernel) GLOBAL_ENTRY(ia64_leave_kernel)
PT_REGS_UNWIND_INFO(0) PT_REGS_UNWIND_INFO(0)
lfetch.fault [sp] // work.need_resched etc. mustn't get changed by this CPU before it returns to userspace:
movl r14=.restart (pUser) cmp.eq.unc p6,p0=r0,r0 // p6 <- pUser
;; (pUser) rsm psr.i
mov.ret.sptk rp=r14,.restart
.restart:
adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13
adds r18=IA64_TASK_SIGPENDING_OFFSET,r13
#ifdef CONFIG_PERFMON
adds r19=IA64_TASK_PFM_MUST_BLOCK_OFFSET,r13
#endif
;;
#ifdef CONFIG_PERFMON
(pUser) ld8 r19=[r19] // load current->thread.pfm_must_block
#endif
#error (pUser) ld8 r17=[r17] // load current->need_resched
#error (pUser) ld4 r18=[r18] // load current->sigpending
;; ;;
#ifdef CONFIG_PERFMON (pUser) adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
(pUser) cmp.ne.unc p9,p0=r19,r0 // current->thread.pfm_must_block != 0?
#endif
#error (pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0?
#errror (pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0?
;; ;;
.work_processed:
(p6) ld4 r18=[r17] // load current_thread_info()->flags
adds r2=PT(R8)+16,r12 adds r2=PT(R8)+16,r12
adds r3=PT(R9)+16,r12 adds r3=PT(R9)+16,r12
#ifdef CONFIG_PERFMON
(p9) br.call.spnt.many b7=pfm_block_on_overflow
#endif
#if __GNUC__ < 3
(p7) br.call.spnt.many b7=invoke_schedule
#else
(p7) br.call.spnt.many b7=schedule
#endif
(p8) br.call.spnt.many b7=handle_signal_delivery // check & deliver pending signals
;; ;;
// start restoring the state saved on the kernel stack (struct pt_regs): // start restoring the state saved on the kernel stack (struct pt_regs):
ld8.fill r8=[r2],16 ld8.fill r8=[r2],16
ld8.fill r9=[r3],16 ld8.fill r9=[r3],16
(p6) and r19=TIF_WORK_MASK,r18 // any work other than TIF_SYSCALL_TRACE?
;; ;;
ld8.fill r10=[r2],16 ld8.fill r10=[r2],16
ld8.fill r11=[r3],16 ld8.fill r11=[r3],16
(p6) cmp4.ne.unc p6,p0=r19, r0 // any special work pending?
;; ;;
ld8.fill r16=[r2],16 ld8.fill r16=[r2],16
ld8.fill r17=[r3],16 ld8.fill r17=[r3],16
(p6) br.cond.spnt .work_pending
;; ;;
ld8.fill r18=[r2],16 ld8.fill r18=[r2],16
ld8.fill r19=[r3],16 ld8.fill r19=[r3],16
...@@ -582,7 +563,7 @@ GLOBAL_ENTRY(ia64_leave_kernel) ...@@ -582,7 +563,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
ld8.fill r30=[r2],16 ld8.fill r30=[r2],16
ld8.fill r31=[r3],16 ld8.fill r31=[r3],16
;; ;;
rsm psr.i | psr.ic // initiate turning off of interrupts & interruption collection rsm psr.i | psr.ic // initiate turning off of interrupt and interruption collection
invala // invalidate ALAT invala // invalidate ALAT
;; ;;
ld8 r1=[r2],16 // ar.ccv ld8 r1=[r2],16 // ar.ccv
...@@ -601,7 +582,7 @@ GLOBAL_ENTRY(ia64_leave_kernel) ...@@ -601,7 +582,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
mov ar.fpsr=r13 mov ar.fpsr=r13
mov b0=r14 mov b0=r14
;; ;;
srlz.i // ensure interrupts & interruption collection are off srlz.i // ensure interruption collection is off
mov b7=r15 mov b7=r15
;; ;;
bsw.0 // switch back to bank 0 bsw.0 // switch back to bank 0
...@@ -729,6 +710,25 @@ skip_rbs_switch: ...@@ -729,6 +710,25 @@ skip_rbs_switch:
mov ar.unat=rARUNAT mov ar.unat=rARUNAT
mov pr=rARPR,-1 mov pr=rARPR,-1
rfi rfi
.work_pending:
tbit.z p6,p0=r18,TIF_NEED_RESCHED // current_thread_info()->need_resched==0?
(p6) br.cond.sptk.few .notify
#if __GNUC__ < 3
br.call.spnt.many rp=invoke_schedule
#else
br.call.spnt.many rp=schedule
#endif
.ret9: cmp.eq p6,p0=r0,r0 // p6 <- 1
rsm psr.i
;;
adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
br.cond.sptk.many .work_processed // re-check
.notify:
br.call.spnt.many rp=notify_resume_user
.ret10: cmp.ne p6,p0=r0,r0 // p6 <- 0
br.cond.sptk.many .work_processed // don't re-check
END(ia64_leave_kernel) END(ia64_leave_kernel)
ENTRY(handle_syscall_error) ENTRY(handle_syscall_error)
...@@ -802,7 +802,7 @@ END(invoke_schedule) ...@@ -802,7 +802,7 @@ END(invoke_schedule)
* be set up by the caller. We declare 8 input registers so the system call * be set up by the caller. We declare 8 input registers so the system call
* args get preserved, in case we need to restart a system call. * args get preserved, in case we need to restart a system call.
*/ */
ENTRY(handle_signal_delivery) ENTRY(notify_resume_user)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart! alloc loc1=ar.pfs,8,2,3,0 // preserve all eight input regs in case of syscall restart!
mov r9=ar.unat mov r9=ar.unat
...@@ -816,17 +816,17 @@ ENTRY(handle_signal_delivery) ...@@ -816,17 +816,17 @@ ENTRY(handle_signal_delivery)
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
st8 [sp]=r9,-16 // allocate space for ar.unat and save it st8 [sp]=r9,-16 // allocate space for ar.unat and save it
.body .body
#error br.call.sptk.many rp=ia64_do_signal br.call.sptk.many rp=do_notify_resume_user
.ret15: .restore sp .ret15: .restore sp
adds sp=16,sp // pop scratch stack space adds sp=16,sp // pop scratch stack space
;; ;;
ld8 r9=[sp] // load new unat from sw->caller_unat ld8 r9=[sp] // load new unat from sigscratch->scratch_unat
mov rp=loc0 mov rp=loc0
;; ;;
mov ar.unat=r9 mov ar.unat=r9
mov ar.pfs=loc1 mov ar.pfs=loc1
br.ret.sptk.many rp br.ret.sptk.many rp
END(handle_signal_delivery) END(do_notify_resume_user)
GLOBAL_ENTRY(sys_rt_sigsuspend) GLOBAL_ENTRY(sys_rt_sigsuspend)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
...@@ -1033,9 +1033,9 @@ sys_call_table: ...@@ -1033,9 +1033,9 @@ sys_call_table:
data8 sys_syslog data8 sys_syslog
data8 sys_setitimer data8 sys_setitimer
data8 sys_getitimer data8 sys_getitimer
data8 ia64_oldstat // 1120 data8 ia64_ni_syscall // 1120 /* was: ia64_oldstat */
data8 ia64_oldlstat data8 ia64_ni_syscall /* was: ia64_oldlstat */
data8 ia64_oldfstat data8 ia64_ni_syscall /* was: ia64_oldfstat */
data8 sys_vhangup data8 sys_vhangup
data8 sys_lchown data8 sys_lchown
data8 sys_vm86 // 1125 data8 sys_vm86 // 1125
...@@ -1130,19 +1130,23 @@ sys_call_table: ...@@ -1130,19 +1130,23 @@ sys_call_table:
data8 sys_getdents64 data8 sys_getdents64
data8 sys_getunwind // 1215 data8 sys_getunwind // 1215
data8 sys_readahead data8 sys_readahead
data8 sys_setxattr
data8 sys_lsetxattr
data8 sys_fsetxattr
data8 sys_getxattr // 1220
data8 sys_lgetxattr
data8 sys_fgetxattr
data8 sys_listxattr
data8 sys_llistxattr
data8 sys_flistxattr // 1225
data8 sys_removexattr
data8 sys_lremovexattr
data8 sys_fremovexattr
#if 0
data8 sys_tkill data8 sys_tkill
#else
data8 ia64_ni_syscall data8 ia64_ni_syscall
data8 ia64_ni_syscall #endif
data8 ia64_ni_syscall // 1220
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall // 1225
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall
data8 ia64_ni_syscall // 1230 data8 ia64_ni_syscall // 1230
data8 ia64_ni_syscall data8 ia64_ni_syscall
data8 ia64_ni_syscall data8 ia64_ni_syscall
......
...@@ -90,7 +90,7 @@ GLOBAL_ENTRY(ia64_sigtramp) ...@@ -90,7 +90,7 @@ GLOBAL_ENTRY(ia64_sigtramp)
(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16) (p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16)
back_from_setup_rbs: back_from_setup_rbs:
.save ar.pfs, r8 .spillreg ar.pfs, r8
alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8
ld8 out0=[base0],16 // load arg0 (signum) ld8 out0=[base0],16 // load arg0 (signum)
adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1 adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
......
...@@ -127,23 +127,21 @@ start_ap: ...@@ -127,23 +127,21 @@ start_ap:
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
/* /*
* Find the init_task for the currently booting CPU. At poweron, and in * Find the init_task for the currently booting CPU. At poweron, and in
* UP mode, cpucount is 0. * UP mode, task_for_booting_cpu is NULL.
*/ */
movl r3=cpucount movl r3=task_for_booting_cpu
;; ;;
ld4 r3=[r3] // r3 <- smp_processor_id() ld8 r3=[r3]
movl r2=init_tasks movl r2=init_thread_union
;; ;;
shladd r2=r3,3,r2 cmp.eq isBP,isAP=r3,r0
;; ;;
ld8 r2=[r2] (isAP) mov r2=r3
#else #else
mov r3=0 movl r2=init_thread_union
movl r2=init_task_union cmp.eq isBP,isAP=r0,r0
;;
#endif #endif
cmp4.ne isAP,isBP=r3,r0 ;;
;; // RAW on r2
extr r3=r2,0,61 // r3 == phys addr of task struct extr r3=r2,0,61 // r3 == phys addr of task struct
mov r16=KERNEL_TR_PAGE_NUM mov r16=KERNEL_TR_PAGE_NUM
;; ;;
...@@ -180,10 +178,12 @@ start_ap: ...@@ -180,10 +178,12 @@ start_ap:
.rodata .rodata
alive_msg: alive_msg:
stringz "I'm alive and well\n" stringz "I'm alive and well\n"
alive_msg_end:
.previous .previous
alloc r2=ar.pfs,0,0,2,0 alloc r2=ar.pfs,0,0,2,0
movl out0=alive_msg movl out0=alive_msg
movl out1=alive_msg_end-alive_msg-1
;; ;;
br.call.sptk.many rp=early_printk br.call.sptk.many rp=early_printk
1: // force new bundle 1: // force new bundle
......
...@@ -24,6 +24,7 @@ EXPORT_SYMBOL(strnlen); ...@@ -24,6 +24,7 @@ EXPORT_SYMBOL(strnlen);
EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strtok); EXPORT_SYMBOL(strtok);
EXPORT_SYMBOL(strpbrk);
#include <linux/irq.h> #include <linux/irq.h>
EXPORT_SYMBOL(isa_irq_to_vector_map); EXPORT_SYMBOL(isa_irq_to_vector_map);
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* This is where we statically allocate and initialize the initial * This is where we statically allocate and initialize the initial
* task. * task.
* *
* Copyright (C) 1999 Hewlett-Packard Co * Copyright (C) 1999, 2002 Hewlett-Packard Co
* Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/init.h> #include <linux/init.h>
...@@ -22,10 +22,20 @@ struct mm_struct init_mm = INIT_MM(init_mm); ...@@ -22,10 +22,20 @@ struct mm_struct init_mm = INIT_MM(init_mm);
/* /*
* Initial task structure. * Initial task structure.
* *
* We need to make sure that this is page aligned due to the way * We need to make sure that this is properly aligned due to the way process stacks are
* process stacks are handled. This is done by having a special * handled. This is done by having a special ".data.init_task" section...
* "init_task" linker map entry..
*/ */
union task_union init_task_union #define init_thread_info init_thread_union.s.thread_info
__attribute__((section("init_task"))) =
{ INIT_TASK(init_task_union.task) }; union init_thread {
struct {
struct task_struct task;
struct thread_info thread_info;
} s;
unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)];
} init_thread_union __attribute__((section(".data.init_task"))) = {{
task: INIT_TASK(init_thread_union.s.task),
thread_info: INIT_THREAD_INFO(init_thread_union.s.thread_info)
}};
asm (".global init_task; init_task = init_thread_union");
This diff is collapsed.
...@@ -161,7 +161,7 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -161,7 +161,7 @@ int show_interrupts(struct seq_file *p, void *v)
for (action=action->next; action; action = action->next) for (action=action->next; action; action = action->next)
seq_printf(p, ", %s", action->name); seq_printf(p, ", %s", action->name);
seq_putc('\n'); seq_putc(p, '\n');
} }
seq_puts(p, "NMI: "); seq_puts(p, "NMI: ");
for (j = 0; j < smp_num_cpus; j++) for (j = 0; j < smp_num_cpus; j++)
...@@ -287,10 +287,11 @@ static inline void wait_on_irq(void) ...@@ -287,10 +287,11 @@ static inline void wait_on_irq(void)
* already executing in one.. * already executing in one..
*/ */
if (!irqs_running()) if (!irqs_running())
if (local_bh_count() || !spin_is_locked(&global_bh_lock)) if (really_local_bh_count() || !spin_is_locked(&global_bh_lock))
break; break;
/* Duh, we have to loop. Release the lock to avoid deadlocks */ /* Duh, we have to loop. Release the lock to avoid deadlocks */
smp_mb__before_clear_bit(); /* need barrier before releasing lock... */
clear_bit(0,&global_irq_lock); clear_bit(0,&global_irq_lock);
for (;;) { for (;;) {
...@@ -305,7 +306,7 @@ static inline void wait_on_irq(void) ...@@ -305,7 +306,7 @@ static inline void wait_on_irq(void)
continue; continue;
if (global_irq_lock) if (global_irq_lock)
continue; continue;
if (!local_bh_count() && spin_is_locked(&global_bh_lock)) if (!really_local_bh_count() && spin_is_locked(&global_bh_lock))
continue; continue;
if (!test_and_set_bit(0,&global_irq_lock)) if (!test_and_set_bit(0,&global_irq_lock))
break; break;
...@@ -378,14 +379,14 @@ void __global_cli(void) ...@@ -378,14 +379,14 @@ void __global_cli(void)
__save_flags(flags); __save_flags(flags);
if (flags & IA64_PSR_I) { if (flags & IA64_PSR_I) {
__cli(); __cli();
if (!local_irq_count()) if (!really_local_irq_count())
get_irqlock(); get_irqlock();
} }
#else #else
__save_flags(flags); __save_flags(flags);
if (flags & (1 << EFLAGS_IF_SHIFT)) { if (flags & (1 << EFLAGS_IF_SHIFT)) {
__cli(); __cli();
if (!local_irq_count()) if (!really_local_irq_count())
get_irqlock(); get_irqlock();
} }
#endif #endif
...@@ -393,7 +394,7 @@ void __global_cli(void) ...@@ -393,7 +394,7 @@ void __global_cli(void)
void __global_sti(void) void __global_sti(void)
{ {
if (!local_irq_count()) if (!really_local_irq_count())
release_irqlock(smp_processor_id()); release_irqlock(smp_processor_id());
__sti(); __sti();
} }
...@@ -422,7 +423,7 @@ unsigned long __global_save_flags(void) ...@@ -422,7 +423,7 @@ unsigned long __global_save_flags(void)
retval = 2 + local_enabled; retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */ /* check for global flags if we're not in an interrupt */
if (!local_irq_count()) { if (!really_local_irq_count()) {
if (local_enabled) if (local_enabled)
retval = 1; retval = 1;
if (global_irq_holder == cpu) if (global_irq_holder == cpu)
...@@ -529,7 +530,7 @@ void disable_irq(unsigned int irq) ...@@ -529,7 +530,7 @@ void disable_irq(unsigned int irq)
disable_irq_nosync(irq); disable_irq_nosync(irq);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (!local_irq_count()) { if (!really_local_irq_count()) {
do { do {
barrier(); barrier();
} while (irq_desc(irq)->status & IRQ_INPROGRESS); } while (irq_desc(irq)->status & IRQ_INPROGRESS);
...@@ -1009,6 +1010,11 @@ int setup_irq(unsigned int irq, struct irqaction * new) ...@@ -1009,6 +1010,11 @@ int setup_irq(unsigned int irq, struct irqaction * new)
rand_initialize_irq(irq); rand_initialize_irq(irq);
} }
if (new->flags & SA_PERCPU_IRQ) {
desc->status |= IRQ_PER_CPU;
desc->handler = &irq_type_ia64_lsapic;
}
/* /*
* The following block of code has to be executed atomically * The following block of code has to be executed atomically
*/ */
...@@ -1089,13 +1095,25 @@ static unsigned int parse_hex_value (const char *buffer, ...@@ -1089,13 +1095,25 @@ static unsigned int parse_hex_value (const char *buffer,
static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL };
static char irq_redir [NR_IRQS]; // = { [0 ... NR_IRQS-1] = 1 };
void set_irq_affinity_info(int irq, int hwid, int redir)
{
unsigned long mask = 1UL<<cpu_logical_id(hwid);
if (irq >= 0 && irq < NR_IRQS) {
irq_affinity[irq] = mask;
irq_redir[irq] = (char) (redir & 0xff);
}
}
static int irq_affinity_read_proc (char *page, char **start, off_t off, static int irq_affinity_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data) int count, int *eof, void *data)
{ {
if (count < HEX_DIGITS+1) if (count < HEX_DIGITS+3)
return -EINVAL; return -EINVAL;
return sprintf (page, "%08lx\n", irq_affinity[(long)data]); return sprintf (page, "%s%08lx\n", irq_redir[(long)data] ? "r " : "",
irq_affinity[(long)data]);
} }
static int irq_affinity_write_proc (struct file *file, const char *buffer, static int irq_affinity_write_proc (struct file *file, const char *buffer,
...@@ -1103,11 +1121,20 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, ...@@ -1103,11 +1121,20 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
{ {
int irq = (long) data, full_count = count, err; int irq = (long) data, full_count = count, err;
unsigned long new_value; unsigned long new_value;
const char *buf = buffer;
int redir;
if (!irq_desc(irq)->handler->set_affinity) if (!irq_desc(irq)->handler->set_affinity)
return -EIO; return -EIO;
err = parse_hex_value(buffer, count, &new_value); if (buf[0] == 'r' || buf[0] == 'R') {
++buf;
while (*buf == ' ') ++buf;
redir = 1;
} else
redir = 0;
err = parse_hex_value(buf, count, &new_value);
/* /*
* Do not allow disabling IRQs completely - it's a too easy * Do not allow disabling IRQs completely - it's a too easy
...@@ -1117,8 +1144,7 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer, ...@@ -1117,8 +1144,7 @@ static int irq_affinity_write_proc (struct file *file, const char *buffer,
if (!(new_value & cpu_online_map)) if (!(new_value & cpu_online_map))
return -EINVAL; return -EINVAL;
irq_affinity[irq] = new_value; irq_desc(irq)->handler->set_affinity(irq | (redir?(1<<31):0), new_value);
irq_desc(irq)->handler->set_affinity(irq, new_value);
return full_count; return full_count;
} }
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/thread_info.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#if 1 #if 1
...@@ -275,6 +276,7 @@ ENTRY(alt_itlb_miss) ...@@ -275,6 +276,7 @@ ENTRY(alt_itlb_miss)
mov r16=cr.ifa // get address that caused the TLB miss mov r16=cr.ifa // get address that caused the TLB miss
movl r17=PAGE_KERNEL movl r17=PAGE_KERNEL
mov r21=cr.ipsr mov r21=cr.ipsr
movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
mov r31=pr mov r31=pr
;; ;;
#ifdef CONFIG_DISABLE_VHPT #ifdef CONFIG_DISABLE_VHPT
...@@ -289,12 +291,12 @@ ENTRY(alt_itlb_miss) ...@@ -289,12 +291,12 @@ ENTRY(alt_itlb_miss)
(p8) br.cond.dptk itlb_fault (p8) br.cond.dptk itlb_fault
#endif #endif
extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
shr.u r18=r16,57 // move address bit 61 to bit 4 shr.u r18=r16,57 // move address bit 61 to bit 4
dep r19=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits
;; ;;
andcm r18=0x10,r18 // bit 4=~address-bit(61) andcm r18=0x10,r18 // bit 4=~address-bit(61)
cmp.ne p8,p0=r0,r23 // psr.cpl != 0? cmp.ne p8,p0=r0,r23 // psr.cpl != 0?
dep r19=r17,r19,0,12 // insert PTE control bits into r19 or r19=r17,r19 // insert PTE control bits into r19
;; ;;
or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6
(p8) br.cond.spnt page_fault (p8) br.cond.spnt page_fault
...@@ -312,6 +314,7 @@ ENTRY(alt_dtlb_miss) ...@@ -312,6 +314,7 @@ ENTRY(alt_dtlb_miss)
mov r16=cr.ifa // get address that caused the TLB miss mov r16=cr.ifa // get address that caused the TLB miss
movl r17=PAGE_KERNEL movl r17=PAGE_KERNEL
mov r20=cr.isr mov r20=cr.isr
movl r19=(((1 << IA64_MAX_PHYS_BITS) - 1) & ~0xfff)
mov r21=cr.ipsr mov r21=cr.ipsr
mov r31=pr mov r31=pr
;; ;;
...@@ -328,15 +331,15 @@ ENTRY(alt_dtlb_miss) ...@@ -328,15 +331,15 @@ ENTRY(alt_dtlb_miss)
#endif #endif
extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl extr.u r23=r21,IA64_PSR_CPL0_BIT,2 // extract psr.cpl
tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on? tbit.nz p6,p7=r20,IA64_ISR_SP_BIT // is speculation bit on?
and r19=r19,r16 // clear ed, reserved bits, and PTE control bits
shr.u r18=r16,57 // move address bit 61 to bit 4 shr.u r18=r16,57 // move address bit 61 to bit 4
dep r19=0,r16,IA64_MAX_PHYS_BITS,(64-IA64_MAX_PHYS_BITS) // clear ed & reserved bits
;; ;;
andcm r18=0x10,r18 // bit 4=~address-bit(61) andcm r18=0x10,r18 // bit 4=~address-bit(61)
cmp.ne p8,p0=r0,r23 cmp.ne p8,p0=r0,r23
(p8) br.cond.spnt page_fault (p8) br.cond.spnt page_fault
dep r21=-1,r21,IA64_PSR_ED_BIT,1 dep r21=-1,r21,IA64_PSR_ED_BIT,1
dep r19=r17,r19,0,12 // insert PTE control bits into r19 or r19=r19,r17 // insert PTE control bits into r19
;; ;;
or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6 or r19=r19,r18 // set bit 4 (uncached) if the access was to region 6
(p6) mov cr.ipsr=r21 (p6) mov cr.ipsr=r21
...@@ -654,16 +657,16 @@ ENTRY(break_fault) ...@@ -654,16 +657,16 @@ ENTRY(break_fault)
ld8 r16=[r16] // load address of syscall entry point ld8 r16=[r16] // load address of syscall entry point
mov rp=r15 // set the real return addr mov rp=r15 // set the real return addr
;; ;;
ld8 r2=[r2] // r2 = current->ptrace
mov b6=r16 mov b6=r16
// arrange things so we skip over break instruction when returning: // arrange things so we skip over break instruction when returning:
adds r16=16,sp // get pointer to cr_ipsr adds r16=16,sp // get pointer to cr_ipsr
adds r17=24,sp // get pointer to cr_iip adds r17=24,sp // get pointer to cr_iip
add r2=TI_FLAGS+IA64_TASK_SIZE,r13
;; ;;
ld8 r18=[r16] // fetch cr_ipsr ld8 r18=[r16] // fetch cr_ipsr
tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PF_TRACESYS) == 0? ld4 r2=[r2] // r2 = current_thread_info()->flags
;; ;;
ld8 r19=[r17] // fetch cr_iip ld8 r19=[r17] // fetch cr_iip
extr.u r20=r18,41,2 // extract ei field extr.u r20=r18,41,2 // extract ei field
...@@ -676,6 +679,7 @@ ENTRY(break_fault) ...@@ -676,6 +679,7 @@ ENTRY(break_fault)
;; ;;
(p6) st8 [r17]=r19 // store new cr.iip if cr.isr.ei wrapped around (p6) st8 [r17]=r19 // store new cr.iip if cr.isr.ei wrapped around
dep r18=r20,r18,41,2 // insert new ei into cr.isr dep r18=r20,r18,41,2 // insert new ei into cr.isr
tbit.z p8,p0=r2,TIF_SYSCALL_TRACE
;; ;;
st8 [r16]=r18 // store new value for cr.isr st8 [r16]=r18 // store new value for cr.isr
...@@ -855,16 +859,16 @@ ENTRY(dispatch_to_ia32_handler) ...@@ -855,16 +859,16 @@ ENTRY(dispatch_to_ia32_handler)
ld4 out5=[r14],8 // r13 == ebp ld4 out5=[r14],8 // r13 == ebp
;; ;;
ld4 out3=[r14],8 // r14 == esi ld4 out3=[r14],8 // r14 == esi
adds r2=IA64_TASK_PTRACE_OFFSET,r13 // r2 = &current->ptrace adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
;; ;;
ld4 out4=[r14] // r15 == edi ld4 out4=[r14] // r15 == edi
movl r16=ia32_syscall_table movl r16=ia32_syscall_table
;; ;;
(p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number (p6) shladd r16=r8,3,r16 // force ni_syscall if not valid syscall number
ld8 r2=[r2] // r2 = current->ptrace ld4 r2=[r2] // r2 = current_thread_info()->flags
;; ;;
ld8 r16=[r16] ld8 r16=[r16]
tbit.z p8,p0=r2,PT_TRACESYS_BIT // (current->ptrace & PT_TRACESYS) == 0? tbit.z p8,p0=r2,TIF_SYSCALL_TRACE
;; ;;
mov b6=r16 mov b6=r16
movl r15=ia32_ret_from_syscall movl r15=ia32_ret_from_syscall
......
This diff is collapsed.
This diff is collapsed.
...@@ -92,7 +92,6 @@ ...@@ -92,7 +92,6 @@
* *
* Assumed state upon entry: * Assumed state upon entry:
* psr.ic: off * psr.ic: off
* psr.dt: off
* r31: contains saved predicates (pr) * r31: contains saved predicates (pr)
* *
* Upon exit, the state is as follows: * Upon exit, the state is as follows:
...@@ -186,7 +185,6 @@ ...@@ -186,7 +185,6 @@
* *
* Assumed state upon entry: * Assumed state upon entry:
* psr.ic: on * psr.ic: on
* psr.dt: on
* r2: points to &pt_regs.r16 * r2: points to &pt_regs.r16
* r3: points to &pt_regs.r17 * r3: points to &pt_regs.r17
*/ */
......
...@@ -724,7 +724,7 @@ tr_info(char *page) ...@@ -724,7 +724,7 @@ tr_info(char *page)
status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
if (status != 0) { if (status != 0) {
printk(__FUNCTION__ " pal call failed on tr[%d:%d]=%ld\n", i, j, status); printk("palinfo: pal call failed on tr[%d:%d]=%ld\n", i, j, status);
continue; continue;
} }
...@@ -842,9 +842,8 @@ static void ...@@ -842,9 +842,8 @@ static void
palinfo_smp_call(void *info) palinfo_smp_call(void *info)
{ {
palinfo_smp_data_t *data = (palinfo_smp_data_t *)info; palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
/* printk(__FUNCTION__" called on CPU %d\n", smp_processor_id());*/
if (data == NULL) { if (data == NULL) {
printk(KERN_ERR __FUNCTION__" data pointer is NULL\n"); printk("%s palinfo: data pointer is NULL\n", KERN_ERR);
data->ret = 0; /* no output */ data->ret = 0; /* no output */
return; return;
} }
...@@ -868,11 +867,10 @@ int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) ...@@ -868,11 +867,10 @@ int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
ptr.page = page; ptr.page = page;
ptr.ret = 0; /* just in case */ ptr.ret = 0; /* just in case */
/*printk(__FUNCTION__" calling CPU %d from CPU %d for function %d\n", f->req_cpu,smp_processor_id(), f->func_id);*/
/* will send IPI to other CPU and wait for completion of remote call */ /* will send IPI to other CPU and wait for completion of remote call */
if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) { if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
printk(__FUNCTION__" remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); printk("palinfo: remote CPU call from %d to %d on function %d: error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
return 0; return 0;
} }
return ptr.ret; return ptr.ret;
...@@ -881,7 +879,7 @@ int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) ...@@ -881,7 +879,7 @@ int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
static static
int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
{ {
printk(__FUNCTION__" should not be called with non SMP kernel\n"); printk("palinfo: should not be called with non SMP kernel\n");
return 0; return 0;
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
......
This diff is collapsed.
/* /*
* Architecture-specific setup. * Architecture-specific setup.
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2002 Hewlett-Packard Co
* Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */ #define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */
#include <linux/config.h> #include <linux/config.h>
...@@ -12,14 +12,17 @@ ...@@ -12,14 +12,17 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/personality.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/thread_info.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/elf.h>
#include <asm/perfmon.h> #include <asm/perfmon.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/processor.h> #include <asm/processor.h>
...@@ -28,6 +31,16 @@ ...@@ -28,6 +31,16 @@
#include <asm/unwind.h> #include <asm/unwind.h>
#include <asm/user.h> #include <asm/user.h>
#ifdef CONFIG_IA64_SGI_SN
#include <asm/sn/idle.h>
#endif
#ifdef CONFIG_PERFMON
# include <asm/perfmon.h>
#endif
#include "sigframe.h"
static void static void
do_show_stack (struct unw_frame_info *info, void *arg) do_show_stack (struct unw_frame_info *info, void *arg)
{ {
...@@ -45,6 +58,15 @@ do_show_stack (struct unw_frame_info *info, void *arg) ...@@ -45,6 +58,15 @@ do_show_stack (struct unw_frame_info *info, void *arg)
} while (unw_unwind(info) >= 0); } while (unw_unwind(info) >= 0);
} }
void
show_trace_task (struct task_struct *task)
{
struct unw_frame_info info;
unw_init_from_blocked_task(&info, task);
do_show_stack(&info, 0);
}
void void
show_stack (struct task_struct *task) show_stack (struct task_struct *task)
{ {
...@@ -90,8 +112,8 @@ show_regs (struct pt_regs *regs) ...@@ -90,8 +112,8 @@ show_regs (struct pt_regs *regs)
printk("r26 : %016lx r27 : %016lx r28 : %016lx\n", regs->r26, regs->r27, regs->r28); printk("r26 : %016lx r27 : %016lx r28 : %016lx\n", regs->r26, regs->r27, regs->r28);
printk("r29 : %016lx r30 : %016lx r31 : %016lx\n", regs->r29, regs->r30, regs->r31); printk("r29 : %016lx r30 : %016lx r31 : %016lx\n", regs->r29, regs->r30, regs->r31);
/* print the stacked registers if cr.ifs is valid: */ if (user_mode(regs)) {
if (regs->cr_ifs & 0x8000000000000000) { /* print the stacked registers */
unsigned long val, sof, *bsp, ndirty; unsigned long val, sof, *bsp, ndirty;
int i, is_nat = 0; int i, is_nat = 0;
...@@ -103,32 +125,61 @@ show_regs (struct pt_regs *regs) ...@@ -103,32 +125,61 @@ show_regs (struct pt_regs *regs)
printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val, printk("r%-3u:%c%016lx%s", 32 + i, is_nat ? '*' : ' ', val,
((i == sof - 1) || (i % 3) == 2) ? "\n" : " "); ((i == sof - 1) || (i % 3) == 2) ? "\n" : " ");
} }
} } else
if (!user_mode(regs))
show_stack(0); show_stack(0);
} }
void
do_notify_resume_user (sigset_t *oldset, struct sigscratch *scr, long in_syscall)
{
#ifdef CONFIG_PERFMON
if (current->thread.pfm_ovfl_block_reset)
pfm_ovfl_block_reset();
#endif
/* deal with pending signal delivery */
if (test_thread_flag(TIF_SIGPENDING))
ia64_do_signal(oldset, scr, in_syscall);
}
/*
* We use this if we don't have any better idle routine..
*/
static void
default_idle (void)
{
/* may want to do PAL_LIGHT_HALT here... */
}
void __attribute__((noreturn)) void __attribute__((noreturn))
cpu_idle (void *unused) cpu_idle (void *unused)
{ {
/* endless idle loop with no priority at all */ /* endless idle loop with no priority at all */
init_idle();
current->nice = 20;
while (1) { while (1) {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (!need_resched()) if (!need_resched())
min_xtp(); min_xtp();
#endif #endif
while (!need_resched())
continue; while (!need_resched()) {
#ifdef CONFIG_IA64_SGI_SN
snidle();
#endif
if (pm_idle)
(*pm_idle)();
else
default_idle();
}
#ifdef CONFIG_IA64_SGI_SN
snidleoff();
#endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
normal_xtp(); normal_xtp();
#endif #endif
schedule(); schedule();
check_pgt_cache(); check_pgt_cache();
if (pm_idle)
(*pm_idle)();
} }
} }
...@@ -137,10 +188,14 @@ ia64_save_extra (struct task_struct *task) ...@@ -137,10 +188,14 @@ ia64_save_extra (struct task_struct *task)
{ {
if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
ia64_save_debug_regs(&task->thread.dbr[0]); ia64_save_debug_regs(&task->thread.dbr[0]);
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
pfm_save_regs(task); pfm_save_regs(task);
if (local_cpu_data->pfm_syst_wide) pfm_syst_wide_update_task(task, 0);
#endif #endif
if (IS_IA32_PROCESS(ia64_task_regs(task))) if (IS_IA32_PROCESS(ia64_task_regs(task)))
ia32_save_state(task); ia32_save_state(task);
} }
...@@ -150,10 +205,14 @@ ia64_load_extra (struct task_struct *task) ...@@ -150,10 +205,14 @@ ia64_load_extra (struct task_struct *task)
{ {
if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0) if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
ia64_load_debug_regs(&task->thread.dbr[0]); ia64_load_debug_regs(&task->thread.dbr[0]);
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0) if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
pfm_load_regs(task); pfm_load_regs(task);
if (local_cpu_data->pfm_syst_wide) pfm_syst_wide_update_task(task, 1);
#endif #endif
if (IS_IA32_PROCESS(ia64_task_regs(task))) if (IS_IA32_PROCESS(ia64_task_regs(task)))
ia32_load_state(task); ia32_load_state(task);
} }
...@@ -233,7 +292,7 @@ copy_thread (int nr, unsigned long clone_flags, ...@@ -233,7 +292,7 @@ copy_thread (int nr, unsigned long clone_flags,
if (user_mode(child_ptregs)) { if (user_mode(child_ptregs)) {
if (user_stack_base) { if (user_stack_base) {
child_ptregs->r12 = user_stack_base + user_stack_size; child_ptregs->r12 = user_stack_base + user_stack_size - 16;
child_ptregs->ar_bspstore = user_stack_base; child_ptregs->ar_bspstore = user_stack_base;
child_ptregs->ar_rnat = 0; child_ptregs->ar_rnat = 0;
child_ptregs->loadrs = 0; child_ptregs->loadrs = 0;
...@@ -286,9 +345,15 @@ copy_thread (int nr, unsigned long clone_flags, ...@@ -286,9 +345,15 @@ copy_thread (int nr, unsigned long clone_flags,
if (IS_IA32_PROCESS(ia64_task_regs(current))) if (IS_IA32_PROCESS(ia64_task_regs(current)))
ia32_save_state(p); ia32_save_state(p);
#endif #endif
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
if (p->thread.pfm_context) /*
retval = pfm_inherit(p, child_ptregs); * reset notifiers and owner check (may not have a perfmon context)
*/
atomic_set(&p->thread.pfm_notifiers_check, 0);
atomic_set(&p->thread.pfm_owners_check, 0);
if (current->thread.pfm_context) retval = pfm_inherit(p, child_ptregs);
#endif #endif
return retval; return retval;
} }
...@@ -412,6 +477,16 @@ sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs) ...@@ -412,6 +477,16 @@ sys_execve (char *filename, char **argv, char **envp, struct pt_regs *regs)
return error; return error;
} }
void
ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter)
{
set_personality(PER_LINUX);
if (elf_ex->e_flags & EF_IA_64_LINUX_EXECUTABLE_STACK)
current->thread.flags |= IA64_THREAD_XSTACK;
else
current->thread.flags &= ~IA64_THREAD_XSTACK;
}
pid_t pid_t
kernel_thread (int (*fn)(void *), void *arg, unsigned long flags) kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
{ {
...@@ -443,15 +518,15 @@ flush_thread (void) ...@@ -443,15 +518,15 @@ flush_thread (void)
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
/* /*
* By the time we get here, the task is detached from the tasklist. This is important * by the time we get here, the task is detached from the tasklist. This is important
* because it means that no other tasks can ever find it as a notifiied task, therfore * because it means that no other tasks can ever find it as a notified task, therfore there
* there is no race condition between this code and let's say a pfm_context_create(). * is no race condition between this code and let's say a pfm_context_create().
* Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if * Conversely, the pfm_cleanup_notifiers() cannot try to access a task's pfm context if this
* this other task is in the middle of its own pfm_context_exit() because it would alreayd * other task is in the middle of its own pfm_context_exit() because it would already be out of
* be out of the task list. Note that this case is very unlikely between a direct child * the task list. Note that this case is very unlikely between a direct child and its parents
* and its parents (if it is the notified process) because of the way the exit is notified * (if it is the notified process) because of the way the exit is notified via SIGCHLD.
* via SIGCHLD.
*/ */
void void
release_thread (struct task_struct *task) release_thread (struct task_struct *task)
{ {
...@@ -460,6 +535,12 @@ release_thread (struct task_struct *task) ...@@ -460,6 +535,12 @@ release_thread (struct task_struct *task)
if (atomic_read(&task->thread.pfm_notifiers_check) > 0) if (atomic_read(&task->thread.pfm_notifiers_check) > 0)
pfm_cleanup_notifiers(task); pfm_cleanup_notifiers(task);
if (atomic_read(&task->thread.pfm_owners_check) > 0)
pfm_cleanup_owners(task);
if (task->thread.pfm_smpl_buf_list)
pfm_cleanup_smpl_buf(task);
} }
#endif #endif
...@@ -475,21 +556,13 @@ exit_thread (void) ...@@ -475,21 +556,13 @@ exit_thread (void)
ia64_set_fpu_owner(0); ia64_set_fpu_owner(0);
#endif #endif
#ifdef CONFIG_PERFMON #ifdef CONFIG_PERFMON
/* stop monitoring */ /* if needed, stop monitoring and flush state to perfmon context */
if ((current->thread.flags & IA64_THREAD_PM_VALID) != 0) { if (current->thread.pfm_context)
/*
* we cannot rely on switch_to() to save the PMU
* context for the last time. There is a possible race
* condition in SMP mode between the child and the
* parent. by explicitly saving the PMU context here
* we garantee no race. this call we also stop
* monitoring
*/
pfm_flush_regs(current); pfm_flush_regs(current);
/*
* make sure that switch_to() will not save context again /* free debug register resources */
*/ if ((current->thread.flags & IA64_THREAD_DBG_VALID) != 0) {
current->thread.flags &= ~IA64_THREAD_PM_VALID; pfm_release_debug_registers(current);
} }
#endif #endif
} }
...@@ -571,3 +644,29 @@ machine_power_off (void) ...@@ -571,3 +644,29 @@ machine_power_off (void)
pm_power_off(); pm_power_off();
machine_halt(); machine_halt();
} }
void __init
init_task_struct_cache (void)
{
}
struct task_struct *
dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
tsk = __get_free_pages(GFP_KERNEL, KERNEL_STACK_SIZE_ORDER);
if (!tsk)
return NULL;
memcpy(tsk, orig, sizeof(struct task_struct) + sizeof(struct thread_info));
tsk->thread_info = (struct thread_info *) ((char *) tsk + IA64_TASK_SIZE);
atomic_set(&tsk->usage, 1);
return tsk;
}
void
__put_task_struct (struct task_struct *tsk)
{
free_pages((unsigned long) tsk, KERNEL_STACK_SIZE_ORDER);
}
This diff is collapsed.
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
#include <asm/sal.h> #include <asm/sal.h>
#include <asm/pal.h> #include <asm/pal.h>
spinlock_t sal_lock = SPIN_LOCK_UNLOCKED; spinlock_t sal_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
unsigned long sal_platform_features;
static struct { static struct {
void *addr; /* function entry point */ void *addr; /* function entry point */
...@@ -76,7 +77,7 @@ ia64_sal_strerror (long status) ...@@ -76,7 +77,7 @@ ia64_sal_strerror (long status)
return str; return str;
} }
static void __init static void __init
ia64_sal_handler_init (void *entry_point, void *gpval) ia64_sal_handler_init (void *entry_point, void *gpval)
{ {
/* fill in the SAL procedure descriptor and point ia64_sal to it: */ /* fill in the SAL procedure descriptor and point ia64_sal to it: */
...@@ -102,7 +103,7 @@ ia64_sal_init (struct ia64_sal_systab *systab) ...@@ -102,7 +103,7 @@ ia64_sal_init (struct ia64_sal_systab *systab)
if (strncmp(systab->signature, "SST_", 4) != 0) if (strncmp(systab->signature, "SST_", 4) != 0)
printk("bad signature in system table!"); printk("bad signature in system table!");
/* /*
* revisions are coded in BCD, so %x does the job for us * revisions are coded in BCD, so %x does the job for us
*/ */
printk("SAL v%x.%02x: oem=%.32s, product=%.32s\n", printk("SAL v%x.%02x: oem=%.32s, product=%.32s\n",
...@@ -152,12 +153,12 @@ ia64_sal_init (struct ia64_sal_systab *systab) ...@@ -152,12 +153,12 @@ ia64_sal_init (struct ia64_sal_systab *systab)
case SAL_DESC_PLATFORM_FEATURE: case SAL_DESC_PLATFORM_FEATURE:
{ {
struct ia64_sal_desc_platform_feature *pf = (void *) p; struct ia64_sal_desc_platform_feature *pf = (void *) p;
sal_platform_features = pf->feature_mask;
printk("SAL: Platform features "); printk("SAL: Platform features ");
if (pf->feature_mask & (1 << 0)) if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_BUS_LOCK)
printk("BusLock "); printk("BusLock ");
if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT) {
if (pf->feature_mask & (1 << 1)) {
printk("IRQ_Redirection "); printk("IRQ_Redirection ");
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (no_int_routing) if (no_int_routing)
...@@ -166,15 +167,17 @@ ia64_sal_init (struct ia64_sal_systab *systab) ...@@ -166,15 +167,17 @@ ia64_sal_init (struct ia64_sal_systab *systab)
smp_int_redirect |= SMP_IRQ_REDIRECTION; smp_int_redirect |= SMP_IRQ_REDIRECTION;
#endif #endif
} }
if (pf->feature_mask & (1 << 2)) { if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT) {
printk("IPI_Redirection "); printk("IPI_Redirection ");
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
if (no_int_routing) if (no_int_routing)
smp_int_redirect &= ~SMP_IPI_REDIRECTION; smp_int_redirect &= ~SMP_IPI_REDIRECTION;
else else
smp_int_redirect |= SMP_IPI_REDIRECTION; smp_int_redirect |= SMP_IPI_REDIRECTION;
#endif #endif
} }
if (pf->feature_mask & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)
printk("ITC_Drift ");
printk("\n"); printk("\n");
break; break;
} }
......
/*
* salinfo.c
*
* Creates entries in /proc/sal for various system features.
*
* Copyright (c) 2001 Silicon Graphics, Inc. All rights reserved.
*
* 10/30/2001 jbarnes@sgi.com copied much of Stephane's palinfo
* code to create this file
*/
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <asm/sal.h>
MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>");
MODULE_DESCRIPTION("/proc interface to IA-64 SAL features");
MODULE_LICENSE("GPL");
static int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data);
typedef struct {
const char *name; /* name of the proc entry */
unsigned long feature; /* feature bit */
struct proc_dir_entry *entry; /* registered entry (removal) */
} salinfo_entry_t;
/*
* List {name,feature} pairs for every entry in /proc/sal/<feature>
* that this module exports
*/
static salinfo_entry_t salinfo_entries[]={
{ "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, },
{ "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, },
{ "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, },
{ "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, },
};
#define NR_SALINFO_ENTRIES (sizeof(salinfo_entries)/sizeof(salinfo_entry_t))
/*
* One for each feature and one more for the directory entry...
*/
static struct proc_dir_entry *salinfo_proc_entries[NR_SALINFO_ENTRIES + 1];
static int __init
salinfo_init(void)
{
struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */
struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */
int i;
salinfo_dir = proc_mkdir("sal", NULL);
for (i=0; i < NR_SALINFO_ENTRIES; i++) {
/* pass the feature bit in question as misc data */
*sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir,
salinfo_read, (void *)salinfo_entries[i].feature);
}
*sdir++ = salinfo_dir;
return 0;
}
static void __exit
salinfo_exit(void)
{
int i = 0;
for (i = 0; i < NR_SALINFO_ENTRIES ; i++) {
if (salinfo_proc_entries[i])
remove_proc_entry (salinfo_proc_entries[i]->name, NULL);
}
}
/*
* 'data' contains an integer that corresponds to the feature we're
* testing
*/
static int
salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
MOD_INC_USE_COUNT;
len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n");
if (len <= off+count) *eof = 1;
*start = page + off;
len -= off;
if (len>count) len = count;
if (len<0) len = 0;
MOD_DEC_USE_COUNT;
return len;
}
module_init(salinfo_init);
module_exit(salinfo_exit);
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2001 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* Copyright (C) 1998, 1999, 2001 Stephane Eranian <eranian@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com> * Copyright (C) 2000, Rohit Seth <rohit.seth@intel.com>
* Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 VA Linux Systems
* Copyright (C) 1999 Walt Drummond <drummond@valinux.com> * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/console.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/reboot.h> #include <linux/reboot.h>
...@@ -27,7 +28,7 @@ ...@@ -27,7 +28,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/threads.h> #include <linux/threads.h>
#include <linux/console.h> #include <linux/tty.h>
#include <asm/acpi-ext.h> #include <asm/acpi-ext.h>
#include <asm/ia32.h> #include <asm/ia32.h>
...@@ -147,6 +148,10 @@ free_available_memory (unsigned long start, unsigned long end, void *arg) ...@@ -147,6 +148,10 @@ free_available_memory (unsigned long start, unsigned long end, void *arg)
} }
/*
* Find a place to put the bootmap and return its starting address in bootmap_start.
* This address must be page-aligned.
*/
static int static int
find_bootmap_location (unsigned long start, unsigned long end, void *arg) find_bootmap_location (unsigned long start, unsigned long end, void *arg)
{ {
...@@ -165,7 +170,7 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg) ...@@ -165,7 +170,7 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg)
for (i = 0; i < num_rsvd_regions; i++) { for (i = 0; i < num_rsvd_regions; i++) {
range_start = MAX(start, free_start); range_start = MAX(start, free_start);
range_end = MIN(end, rsvd_region[i].start); range_end = MIN(end, rsvd_region[i].start & PAGE_MASK);
if (range_end <= range_start) continue; /* skip over empty range */ if (range_end <= range_start) continue; /* skip over empty range */
...@@ -177,7 +182,7 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg) ...@@ -177,7 +182,7 @@ find_bootmap_location (unsigned long start, unsigned long end, void *arg)
/* nothing more available in this segment */ /* nothing more available in this segment */
if (range_end == end) return 0; if (range_end == end) return 0;
free_start = rsvd_region[i].end; free_start = PAGE_ALIGN(rsvd_region[i].end);
} }
return 0; return 0;
} }
...@@ -306,6 +311,10 @@ setup_arch (char **cmdline_p) ...@@ -306,6 +311,10 @@ setup_arch (char **cmdline_p)
/* process SAL system table: */ /* process SAL system table: */
ia64_sal_init(efi.sal_systab); ia64_sal_init(efi.sal_systab);
#ifdef CONFIG_IA64_GENERIC
machvec_init(acpi_get_sysname());
#endif
/* /*
* Set `iobase' to the appropriate address in region 6 * Set `iobase' to the appropriate address in region 6
* (uncached access range) * (uncached access range)
...@@ -332,10 +341,6 @@ setup_arch (char **cmdline_p) ...@@ -332,10 +341,6 @@ setup_arch (char **cmdline_p)
cpu_init(); /* initialize the bootstrap CPU */ cpu_init(); /* initialize the bootstrap CPU */
#ifdef CONFIG_IA64_GENERIC
machvec_init(acpi_get_sysname());
#endif
if (efi.acpi20) { if (efi.acpi20) {
/* Parse the ACPI 2.0 tables */ /* Parse the ACPI 2.0 tables */
acpi20_parse(efi.acpi20); acpi20_parse(efi.acpi20);
...@@ -371,17 +376,14 @@ show_cpuinfo (struct seq_file *m, void *v) ...@@ -371,17 +376,14 @@ show_cpuinfo (struct seq_file *m, void *v)
{ {
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
# define lpj c->loops_per_jiffy # define lpj c->loops_per_jiffy
# define cpunum c->cpu
#else #else
# define lpj loops_per_jiffy # define lpj loops_per_jiffy
# define cpunum 0
#endif #endif
char family[32], features[128], *cp; char family[32], features[128], *cp;
struct cpuinfo_ia64 *c = v; struct cpuinfo_ia64 *c = v;
unsigned long mask, cpu = c - cpu_data(0); unsigned long mask;
#ifdef CONFIG_SMP
if (!(cpu_online_map & (1 << cpu)))
return 0;
#endif
mask = c->features; mask = c->features;
...@@ -403,7 +405,7 @@ show_cpuinfo (struct seq_file *m, void *v) ...@@ -403,7 +405,7 @@ show_cpuinfo (struct seq_file *m, void *v)
sprintf(cp, " 0x%lx", mask); sprintf(cp, " 0x%lx", mask);
seq_printf(m, seq_printf(m,
"processor : %lu\n" "processor : %d\n"
"vendor : %s\n" "vendor : %s\n"
"arch : IA-64\n" "arch : IA-64\n"
"family : %s\n" "family : %s\n"
...@@ -416,7 +418,7 @@ show_cpuinfo (struct seq_file *m, void *v) ...@@ -416,7 +418,7 @@ show_cpuinfo (struct seq_file *m, void *v)
"cpu MHz : %lu.%06lu\n" "cpu MHz : %lu.%06lu\n"
"itc MHz : %lu.%06lu\n" "itc MHz : %lu.%06lu\n"
"BogoMIPS : %lu.%02lu\n\n", "BogoMIPS : %lu.%02lu\n\n",
cpu, c->vendor, family, c->model, c->revision, c->archrev, cpunum, c->vendor, family, c->model, c->revision, c->archrev,
features, c->ppn, c->number, features, c->ppn, c->number,
c->proc_freq / 1000000, c->proc_freq % 1000000, c->proc_freq / 1000000, c->proc_freq % 1000000,
c->itc_freq / 1000000, c->itc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000,
...@@ -427,6 +429,10 @@ show_cpuinfo (struct seq_file *m, void *v) ...@@ -427,6 +429,10 @@ show_cpuinfo (struct seq_file *m, void *v)
static void * static void *
c_start (struct seq_file *m, loff_t *pos) c_start (struct seq_file *m, loff_t *pos)
{ {
#ifdef CONFIG_SMP
while (*pos < NR_CPUS && !(cpu_online_map & (1 << *pos)))
++*pos;
#endif
return *pos < NR_CPUS ? cpu_data(*pos) : NULL; return *pos < NR_CPUS ? cpu_data(*pos) : NULL;
} }
...@@ -483,6 +489,9 @@ identify_cpu (struct cpuinfo_ia64 *c) ...@@ -483,6 +489,9 @@ identify_cpu (struct cpuinfo_ia64 *c)
cpuid.bits[i] = ia64_get_cpuid(i); cpuid.bits[i] = ia64_get_cpuid(i);
memcpy(c->vendor, cpuid.field.vendor, 16); memcpy(c->vendor, cpuid.field.vendor, 16);
#ifdef CONFIG_SMP
c->cpu = smp_processor_id();
#endif
c->ppn = cpuid.field.ppn; c->ppn = cpuid.field.ppn;
c->number = cpuid.field.number; c->number = cpuid.field.number;
c->revision = cpuid.field.revision; c->revision = cpuid.field.revision;
...@@ -534,7 +543,7 @@ cpu_init (void) ...@@ -534,7 +543,7 @@ cpu_init (void)
= alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()),
sizeof(struct cpuinfo_ia64)); sizeof(struct cpuinfo_ia64));
for (cpu = 1; cpu < NR_CPUS; ++cpu) for (cpu = 1; cpu < NR_CPUS; ++cpu)
memcpy(my_cpu_data->cpu_data[cpu]->cpu_data_ptrs, memcpy(my_cpu_data->cpu_data[cpu]->cpu_data,
my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data)); my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data));
} else { } else {
order = get_order(sizeof(struct cpuinfo_ia64)); order = get_order(sizeof(struct cpuinfo_ia64));
...@@ -577,6 +586,8 @@ cpu_init (void) ...@@ -577,6 +586,8 @@ cpu_init (void)
atomic_inc(&init_mm.mm_count); atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm; current->active_mm = &init_mm;
if (current->mm)
BUG();
ia64_mmu_init(my_cpu_data); ia64_mmu_init(my_cpu_data);
...@@ -616,4 +627,6 @@ cpu_init (void) ...@@ -616,4 +627,6 @@ cpu_init (void)
num_phys_stacked = 96; num_phys_stacked = 96;
} }
local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8; local_cpu_data->phys_stacked_size_p8 = num_phys_stacked*8 + 8;
platform_cpu_init();
} }
...@@ -21,3 +21,5 @@ struct sigframe { ...@@ -21,3 +21,5 @@ struct sigframe {
struct siginfo info; struct siginfo info;
struct sigcontext sc; struct sigcontext sc;
}; };
extern long ia64_do_signal (sigset_t *, struct sigscratch *, long);
/* /*
* Architecture-specific signal handling support. * Architecture-specific signal handling support.
* *
* Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* Derived from i386 and Alpha versions. * Derived from i386 and Alpha versions.
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/stddef.h> #include <linux/stddef.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/wait.h> #include <linux/wait.h>
...@@ -39,8 +41,6 @@ ...@@ -39,8 +41,6 @@
# define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0]) # define GET_SIGSET(k,u) __get_user((k)->sig[0], &(u)->sig[0])
#endif #endif
extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */
long long
ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr) ia64_rt_sigsuspend (sigset_t *uset, size_t sigsetsize, struct sigscratch *scr)
{ {
...@@ -160,6 +160,7 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) ...@@ -160,6 +160,7 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from)
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user((short)from->si_code, &to->si_code);
switch (from->si_code >> 16) { switch (from->si_code >> 16) {
case __SI_FAULT >> 16: case __SI_FAULT >> 16:
err |= __put_user(from->si_flags, &to->si_flags);
err |= __put_user(from->si_isr, &to->si_isr); err |= __put_user(from->si_isr, &to->si_isr);
case __SI_POLL >> 16: case __SI_POLL >> 16:
err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_addr, &to->si_addr);
...@@ -172,7 +173,12 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from) ...@@ -172,7 +173,12 @@ copy_siginfo_to_user (siginfo_t *to, siginfo_t *from)
case __SI_PROF >> 16: case __SI_PROF >> 16:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_pfm_ovfl, &to->si_pfm_ovfl); if (from->si_code == PROF_OVFL) {
err |= __put_user(from->si_pfm_ovfl[0], &to->si_pfm_ovfl[0]);
err |= __put_user(from->si_pfm_ovfl[1], &to->si_pfm_ovfl[1]);
err |= __put_user(from->si_pfm_ovfl[2], &to->si_pfm_ovfl[2]);
err |= __put_user(from->si_pfm_ovfl[3], &to->si_pfm_ovfl[3]);
}
break; break;
default: default:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
...@@ -239,7 +245,7 @@ ia64_rt_sigreturn (struct sigscratch *scr) ...@@ -239,7 +245,7 @@ ia64_rt_sigreturn (struct sigscratch *scr)
* could be corrupted. * could be corrupted.
*/ */
retval = (long) &ia64_leave_kernel; retval = (long) &ia64_leave_kernel;
if (current->ptrace & PT_TRACESYS) if (test_thread_flag(TIF_SYSCALL_TRACE))
/* /*
* strace expects to be notified after sigreturn returns even though the * strace expects to be notified after sigreturn returns even though the
* context to which we return may not be in the middle of a syscall. * context to which we return may not be in the middle of a syscall.
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/cache.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/cache.h> #include <linux/cache.h>
...@@ -38,7 +39,6 @@ ...@@ -38,7 +39,6 @@
#include <asm/delay.h> #include <asm/delay.h>
#include <asm/efi.h> #include <asm/efi.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -51,14 +51,19 @@ ...@@ -51,14 +51,19 @@
#include <asm/unistd.h> #include <asm/unistd.h>
#include <asm/mca.h> #include <asm/mca.h>
/* The 'big kernel lock' */ /*
spinlock_t kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED; * The Big Kernel Lock. It's not supposed to be used for performance critical stuff
* anymore. But we still need to align it because certain workloads are still affected by
* it. For example, llseek() and various other filesystem related routines still use the
* BKL.
*/
spinlock_t kernel_flag __cacheline_aligned = SPIN_LOCK_UNLOCKED;
/* /*
* Structure and data for smp_call_function(). This is designed to minimise static memory * Structure and data for smp_call_function(). This is designed to minimise static memory
* requirements. It also looks cleaner. * requirements. It also looks cleaner.
*/ */
static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; static spinlock_t call_lock __cacheline_aligned = SPIN_LOCK_UNLOCKED;
struct call_data_struct { struct call_data_struct {
void (*func) (void *info); void (*func) (void *info);
...@@ -70,8 +75,12 @@ struct call_data_struct { ...@@ -70,8 +75,12 @@ struct call_data_struct {
static volatile struct call_data_struct *call_data; static volatile struct call_data_struct *call_data;
static spinlock_t migration_lock = SPIN_LOCK_UNLOCKED;
static task_t *migrating_task;
#define IPI_CALL_FUNC 0 #define IPI_CALL_FUNC 0
#define IPI_CPU_STOP 1 #define IPI_CPU_STOP 1
#define IPI_MIGRATE_TASK 2
static void static void
stop_this_cpu (void) stop_this_cpu (void)
...@@ -98,51 +107,60 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs) ...@@ -98,51 +107,60 @@ handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
mb(); /* Order interrupt and bit testing. */ mb(); /* Order interrupt and bit testing. */
while ((ops = xchg(pending_ipis, 0)) != 0) { while ((ops = xchg(pending_ipis, 0)) != 0) {
mb(); /* Order bit clearing and data access. */ mb(); /* Order bit clearing and data access. */
do { do {
unsigned long which; unsigned long which;
which = ffz(~ops); which = ffz(~ops);
ops &= ~(1 << which); ops &= ~(1 << which);
switch (which) { switch (which) {
case IPI_CALL_FUNC: case IPI_CALL_FUNC:
{ {
struct call_data_struct *data; struct call_data_struct *data;
void (*func)(void *info); void (*func)(void *info);
void *info; void *info;
int wait; int wait;
/* release the 'pointer lock' */ /* release the 'pointer lock' */
data = (struct call_data_struct *) call_data; data = (struct call_data_struct *) call_data;
func = data->func; func = data->func;
info = data->info; info = data->info;
wait = data->wait; wait = data->wait;
mb(); mb();
atomic_inc(&data->started); atomic_inc(&data->started);
/*
/* At this point the structure may be gone unless wait is true. */ * At this point the structure may be gone unless
(*func)(info); * wait is true.
*/
/* Notify the sending CPU that the task is done. */ (*func)(info);
mb();
if (wait) /* Notify the sending CPU that the task is done. */
atomic_inc(&data->finished); mb();
if (wait)
atomic_inc(&data->finished);
}
break;
case IPI_MIGRATE_TASK:
{
task_t *p = migrating_task;
spin_unlock(&migration_lock);
sched_task_migrated(p);
}
break;
case IPI_CPU_STOP:
stop_this_cpu();
break;
default:
printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
break;
} }
break; } while (ops);
mb(); /* Order data access and bit testing. */
case IPI_CPU_STOP:
stop_this_cpu();
break;
default:
printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
break;
} /* Switch */
} while (ops);
mb(); /* Order data access and bit testing. */
} }
} }
...@@ -185,10 +203,25 @@ smp_send_reschedule (int cpu) ...@@ -185,10 +203,25 @@ smp_send_reschedule (int cpu)
platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0);
} }
/*
* This function sends a reschedule IPI to all (other) CPUs. This should only be used if
* some 'global' task became runnable, such as a RT task, that must be handled now. The
* first CPU that manages to grab the task will run it.
*/
void
smp_send_reschedule_all (void)
{
int i;
for (i = 0; i < smp_num_cpus; i++)
if (i != smp_processor_id())
smp_send_reschedule(i);
}
void void
smp_flush_tlb_all (void) smp_flush_tlb_all (void)
{ {
smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1); smp_call_function((void (*)(void *))__flush_tlb_all, 0, 1, 1);
__flush_tlb_all(); __flush_tlb_all();
} }
...@@ -317,6 +350,15 @@ smp_send_stop (void) ...@@ -317,6 +350,15 @@ smp_send_stop (void)
smp_num_cpus = 1; smp_num_cpus = 1;
} }
void
smp_migrate_task (int cpu, task_t *p)
{
/* The target CPU will unlock the migration spinlock: */
spin_lock(&migration_lock);
migrating_task = p;
send_IPI_single(cpu, IPI_MIGRATE_TASK);
}
int __init int __init
setup_profiling_timer (unsigned int multiplier) setup_profiling_timer (unsigned int multiplier)
{ {
......
...@@ -70,6 +70,7 @@ extern void __init calibrate_delay(void); ...@@ -70,6 +70,7 @@ extern void __init calibrate_delay(void);
extern void start_ap(void); extern void start_ap(void);
int cpucount; int cpucount;
task_t *task_for_booting_cpu;
/* Setup configured maximum number of CPUs to activate */ /* Setup configured maximum number of CPUs to activate */
static int max_cpus = -1; static int max_cpus = -1;
...@@ -378,7 +379,7 @@ start_secondary (void *unused) ...@@ -378,7 +379,7 @@ start_secondary (void *unused)
smp_callin(); smp_callin();
Dprintk("CPU %d is set to go.\n", smp_processor_id()); Dprintk("CPU %d is set to go.\n", smp_processor_id());
while (!atomic_read(&smp_commenced)) while (!atomic_read(&smp_commenced))
; cpu_relax();
Dprintk("CPU %d is starting idle.\n", smp_processor_id()); Dprintk("CPU %d is starting idle.\n", smp_processor_id());
return cpu_idle(); return cpu_idle();
...@@ -416,13 +417,13 @@ do_boot_cpu (int sapicid) ...@@ -416,13 +417,13 @@ do_boot_cpu (int sapicid)
if (!idle) if (!idle)
panic("No idle process for CPU %d", cpu); panic("No idle process for CPU %d", cpu);
idle->processor = cpu; init_idle(idle, cpu);
ia64_cpu_to_sapicid[cpu] = sapicid; ia64_cpu_to_sapicid[cpu] = sapicid;
idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
del_from_runqueue(idle);
unhash_process(idle); unhash_process(idle);
init_tasks[cpu] = idle;
task_for_booting_cpu = idle;
Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid); Dprintk("Sending wakeup vector %u to AP 0x%x/0x%x.\n", ap_wakeup_vector, cpu, sapicid);
...@@ -451,6 +452,17 @@ do_boot_cpu (int sapicid) ...@@ -451,6 +452,17 @@ do_boot_cpu (int sapicid)
} }
} }
unsigned long cache_decay_ticks; /* # of ticks an idle task is considered cache-hot */
static void
smp_tune_scheduling (void)
{
cache_decay_ticks = 10; /* XXX base this on PAL info and cache-bandwidth estimate */
printk("task migration cache decay timeout: %ld msecs.\n",
(cache_decay_ticks + 1) * 1000 / HZ);
}
/* /*
* Cycle through the APs sending Wakeup IPIs to boot each. * Cycle through the APs sending Wakeup IPIs to boot each.
*/ */
...@@ -470,8 +482,8 @@ smp_boot_cpus (void) ...@@ -470,8 +482,8 @@ smp_boot_cpus (void)
smp_setup_percpu_timer(); smp_setup_percpu_timer();
/* /*
* We have the boot CPU online for sure. * We have the boot CPU online for sure.
*/ */
set_bit(0, &cpu_online_map); set_bit(0, &cpu_online_map);
set_bit(0, &cpu_callin_map); set_bit(0, &cpu_callin_map);
...@@ -480,9 +492,9 @@ smp_boot_cpus (void) ...@@ -480,9 +492,9 @@ smp_boot_cpus (void)
printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id); printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id);
global_irq_holder = 0; global_irq_holder = NO_PROC_ID;
current->processor = 0; current_thread_info()->cpu = 0;
init_idle(); smp_tune_scheduling();
/* /*
* If SMP should be disabled, then really disable it! * If SMP should be disabled, then really disable it!
...@@ -493,7 +505,7 @@ smp_boot_cpus (void) ...@@ -493,7 +505,7 @@ smp_boot_cpus (void)
smp_num_cpus = 1; smp_num_cpus = 1;
goto smp_done; goto smp_done;
} }
if (max_cpus != -1) if (max_cpus != -1)
printk (KERN_INFO "Limiting CPUs to %d\n", max_cpus); printk (KERN_INFO "Limiting CPUs to %d\n", max_cpus);
if (smp_boot_data.cpu_count > 1) { if (smp_boot_data.cpu_count > 1) {
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* This file contains various system calls that have different calling * This file contains various system calls that have different calling
* conventions on different platforms. * conventions on different platforms.
* *
* Copyright (C) 1999-2000 Hewlett-Packard Co * Copyright (C) 1999-2000, 2002 Hewlett-Packard Co
* Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
...@@ -201,15 +201,13 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un ...@@ -201,15 +201,13 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un
if (len == 0) if (len == 0)
goto out; goto out;
/* don't permit mappings into unmapped space or the virtual page table of a region: */ /*
* Don't permit mappings into unmapped space, the virtual page table of a region,
* or across a region boundary. Note: RGN_MAP_LIMIT is equal to 2^n-PAGE_SIZE
* (for some integer n <= 61) and len > 0.
*/
roff = rgn_offset(addr); roff = rgn_offset(addr);
if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT) { if ((len > RGN_MAP_LIMIT) || (roff > (RGN_MAP_LIMIT - len))) {
addr = -EINVAL;
goto out;
}
/* don't permit mappings that would cross a region boundary: */
if (rgn_index(addr) != rgn_index(addr + len)) {
addr = -EINVAL; addr = -EINVAL;
goto out; goto out;
} }
...@@ -276,74 +274,6 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3, ...@@ -276,74 +274,6 @@ ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
return addr; return addr;
} }
#if 1
/*
* This is here for a while to keep compatibillity with the old stat()
* call - it will be removed later once everybody migrates to the new
* kernel stat structure that matches the glibc one - Jes
*/
static int
cp_ia64_old_stat (struct kstat *stat, struct ia64_oldstat *statbuf)
{
struct ia64_oldstat tmp;
unsigned int blocks, indirect;
memset(&tmp, 0, sizeof(tmp));
tmp.st_dev = stat->dev;
tmp.st_ino = stat->ino;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
SET_STAT_UID(tmp, stat->uid);
SET_STAT_GID(tmp, stat->gid);
tmp.st_rdev = stat->rdev;
tmp.st_size = stat->size;
tmp.st_atime = stat->atime;
tmp.st_mtime = stat->mtime;
tmp.st_ctime = stat->ctime;
tmp.st_blocks = stat->i_blocks;
tmp.st_blksize = stat->i_blksize;
return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
}
asmlinkage long
ia64_oldstat (char *filename, struct ia64_oldstat *statbuf)
{
struct kstat stat;
int error = vfs_stat(filename, &stat);
if (!error)
error = cp_ia64_old_stat(&stat, statbuf);
return error;
}
asmlinkage long
ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf)
{
struct kstat stat;
int error = vfs_lstat(filename, &stat);
if (!error)
error = cp_ia64_old_stat(&stat, statbuf);
return error;
}
asmlinkage long
ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf)
{
struct kstat stat;
int error = vfs_fstat(fd, &stat);
if (!error)
error = cp_ia64_old_stat(&stat, statbuf);
return error;
}
#endif
#ifndef CONFIG_PCI #ifndef CONFIG_PCI
asmlinkage long asmlinkage long
......
/* /*
* Architecture-specific trap handling. * Architecture-specific trap handling.
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE
...@@ -32,6 +32,7 @@ register double f30 asm ("f30"); register double f31 asm ("f31"); ...@@ -32,6 +32,7 @@ register double f30 asm ("f30"); register double f31 asm ("f31");
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/tty.h>
#include <linux/vt_kern.h> /* For unblank_screen() */ #include <linux/vt_kern.h> /* For unblank_screen() */
#include <asm/hardirq.h> #include <asm/hardirq.h>
...@@ -133,6 +134,8 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) ...@@ -133,6 +134,8 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs)
/* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
siginfo.si_imm = break_num; siginfo.si_imm = break_num;
siginfo.si_flags = 0; /* clear __ISR_VALID */
siginfo.si_isr = 0;
switch (break_num) { switch (break_num) {
case 0: /* unknown error */ case 0: /* unknown error */
...@@ -352,6 +355,8 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -352,6 +355,8 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
siginfo.si_code = FPE_FLTDIV; siginfo.si_code = FPE_FLTDIV;
} }
siginfo.si_isr = isr; siginfo.si_isr = isr;
siginfo.si_flags = __ISR_VALID;
siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current); force_sig_info(SIGFPE, &siginfo, current);
} }
} else { } else {
...@@ -372,6 +377,8 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -372,6 +377,8 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
siginfo.si_code = FPE_FLTRES; siginfo.si_code = FPE_FLTRES;
} }
siginfo.si_isr = isr; siginfo.si_isr = isr;
siginfo.si_flags = __ISR_VALID;
siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current); force_sig_info(SIGFPE, &siginfo, current);
} }
} }
...@@ -490,6 +497,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ...@@ -490,6 +497,8 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
siginfo.si_imm = vector; siginfo.si_imm = vector;
siginfo.si_flags = __ISR_VALID;
siginfo.si_isr = isr;
force_sig_info(SIGILL, &siginfo, current); force_sig_info(SIGILL, &siginfo, current);
return; return;
} }
...@@ -517,6 +526,10 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ...@@ -517,6 +526,10 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
} }
siginfo.si_signo = SIGTRAP; siginfo.si_signo = SIGTRAP;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_addr = 0;
siginfo.si_imm = 0;
force_sig_info(SIGTRAP, &siginfo, current); force_sig_info(SIGTRAP, &siginfo, current);
return; return;
...@@ -528,6 +541,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ...@@ -528,6 +541,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_code = FPE_FLTINV; siginfo.si_code = FPE_FLTINV;
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
siginfo.si_flags = __ISR_VALID;
siginfo.si_isr = isr;
siginfo.si_imm = 0;
force_sig_info(SIGFPE, &siginfo, current); force_sig_info(SIGFPE, &siginfo, current);
} }
return; return;
...@@ -537,6 +553,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, ...@@ -537,6 +553,9 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa,
siginfo.si_signo = SIGILL; siginfo.si_signo = SIGILL;
siginfo.si_code = ILL_BADIADDR; siginfo.si_code = ILL_BADIADDR;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_flags = 0;
siginfo.si_isr = 0;
siginfo.si_imm = 0;
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
force_sig_info(SIGILL, &siginfo, current); force_sig_info(SIGILL, &siginfo, current);
return; return;
......
/* /*
* Architecture-specific unaligned trap handling. * Architecture-specific unaligned trap handling.
* *
* Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999-2002 Hewlett-Packard Co
* Copyright (C) 1999-2000 Stephane Eranian <eranian@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2001 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops. * 2001/10/11 Fix unaligned access to rotating registers in s/w pipelined loops.
* 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes. * 2001/08/13 Correct size of extended floats (float_fsz) from 16 to 10 bytes.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/tty.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/rse.h> #include <asm/rse.h>
...@@ -23,7 +24,7 @@ extern void die_if_kernel(char *str, struct pt_regs *regs, long err) __attribute ...@@ -23,7 +24,7 @@ extern void die_if_kernel(char *str, struct pt_regs *regs, long err) __attribute
#undef DEBUG_UNALIGNED_TRAP #undef DEBUG_UNALIGNED_TRAP
#ifdef DEBUG_UNALIGNED_TRAP #ifdef DEBUG_UNALIGNED_TRAP
# define DPRINT(a...) do { printk("%s.%u: ", __FUNCTION__, __LINE__); printk (a); } while (0) # define DPRINT(a...) do { printk("%s %u: ", __FUNCTION__, __LINE__); printk (a); } while (0)
# define DDUMP(str,vp,len) dump(str, vp, len) # define DDUMP(str,vp,len) dump(str, vp, len)
static void static void
...@@ -650,7 +651,7 @@ emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsi ...@@ -650,7 +651,7 @@ emulate_load_updates (update_t type, load_store_t ld, struct pt_regs *regs, unsi
* just in case. * just in case.
*/ */
if (ld.x6_op == 1 || ld.x6_op == 3) { if (ld.x6_op == 1 || ld.x6_op == 3) {
printk(KERN_ERR __FUNCTION__": register update on speculative load, error\n"); printk("%s %s: register update on speculative load, error\n", KERN_ERR, __FUNCTION__);
die_if_kernel("unaligned reference on specualtive load with register update\n", die_if_kernel("unaligned reference on specualtive load with register update\n",
regs, 30); regs, 30);
} }
...@@ -1080,8 +1081,8 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs ...@@ -1080,8 +1081,8 @@ emulate_load_floatpair (unsigned long ifa, load_store_t ld, struct pt_regs *regs
* For this reason we keep this sanity check * For this reason we keep this sanity check
*/ */
if (ld.x6_op == 1 || ld.x6_op == 3) if (ld.x6_op == 1 || ld.x6_op == 3)
printk(KERN_ERR __FUNCTION__": register update on speculative load pair, " printk("%s %s: register update on speculative load pair, "
"error\n"); "error\n",KERN_ERR, __FUNCTION__);
setreg(ld.r3, ifa, 0, regs); setreg(ld.r3, ifa, 0, regs);
} }
...@@ -1488,6 +1489,9 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) ...@@ -1488,6 +1489,9 @@ ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs)
si.si_errno = 0; si.si_errno = 0;
si.si_code = BUS_ADRALN; si.si_code = BUS_ADRALN;
si.si_addr = (void *) ifa; si.si_addr = (void *) ifa;
si.si_flags = 0;
si.si_isr = 0;
si.si_imm = 0;
force_sig_info(SIGBUS, &si, current); force_sig_info(SIGBUS, &si, current);
goto done; goto done;
} }
/* /*
* Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999-2002 Hewlett-Packard Co
* Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
/* /*
* This file implements call frame unwind support for the Linux * This file implements call frame unwind support for the Linux
...@@ -72,6 +72,8 @@ ...@@ -72,6 +72,8 @@
#define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC) #define alloc_reg_state() kmalloc(sizeof(struct unw_state_record), GFP_ATOMIC)
#define free_reg_state(usr) kfree(usr) #define free_reg_state(usr) kfree(usr)
#define alloc_labeled_state() kmalloc(sizeof(struct unw_labeled_state), GFP_ATOMIC)
#define free_labeled_state(usr) kfree(usr)
typedef unsigned long unw_word; typedef unsigned long unw_word;
typedef unsigned char unw_hash_index_t; typedef unsigned char unw_hash_index_t;
...@@ -521,7 +523,7 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write) ...@@ -521,7 +523,7 @@ unw_access_pr (struct unw_frame_info *info, unsigned long *val, int write)
} }
/* Unwind decoder routines */ /* Routines to manipulate the state stack. */
static inline void static inline void
push (struct unw_state_record *sr) push (struct unw_state_record *sr)
...@@ -534,24 +536,60 @@ push (struct unw_state_record *sr) ...@@ -534,24 +536,60 @@ push (struct unw_state_record *sr)
return; return;
} }
memcpy(rs, &sr->curr, sizeof(*rs)); memcpy(rs, &sr->curr, sizeof(*rs));
rs->next = sr->stack; sr->curr.next = rs;
sr->stack = rs;
} }
static void static void
pop (struct unw_state_record *sr) pop (struct unw_state_record *sr)
{ {
struct unw_reg_state *rs; struct unw_reg_state *rs = sr->curr.next;
if (!sr->stack) { if (!rs) {
printk ("unwind: stack underflow!\n"); printk("unwind: stack underflow!\n");
return; return;
} }
rs = sr->stack; memcpy(&sr->curr, rs, sizeof(*rs));
sr->stack = rs->next;
free_reg_state(rs); free_reg_state(rs);
} }
/* Make a copy of the state stack. Non-recursive to avoid stack overflows. */
static struct unw_reg_state *
dup_state_stack (struct unw_reg_state *rs)
{
struct unw_reg_state *copy, *prev = NULL, *first = NULL;
while (rs) {
copy = alloc_reg_state();
if (!copy) {
printk ("unwind.dup_state_stack: out of memory\n");
return NULL;
}
memcpy(copy, rs, sizeof(*copy));
if (first)
prev->next = copy;
else
first = copy;
rs = rs->next;
prev = copy;
}
return first;
}
/* Free all stacked register states (but not RS itself). */
static void
free_state_stack (struct unw_reg_state *rs)
{
struct unw_reg_state *p, *next;
for (p = rs->next; p != NULL; p = next) {
next = p->next;
free_reg_state(p);
}
rs->next = NULL;
}
/* Unwind decoder routines */
static enum unw_register_index __attribute__((const)) static enum unw_register_index __attribute__((const))
decode_abreg (unsigned char abreg, int memory) decode_abreg (unsigned char abreg, int memory)
{ {
...@@ -689,7 +727,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave ...@@ -689,7 +727,7 @@ desc_prologue (int body, unw_word rlen, unsigned char mask, unsigned char grsave
sr->first_region = 0; sr->first_region = 0;
/* check if we're done: */ /* check if we're done: */
if (body && sr->when_target < sr->region_start + sr->region_len) { if (sr->when_target < sr->region_start + sr->region_len) {
sr->done = 1; sr->done = 1;
return; return;
} }
...@@ -902,31 +940,36 @@ desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr) ...@@ -902,31 +940,36 @@ desc_epilogue (unw_word t, unw_word ecount, struct unw_state_record *sr)
static inline void static inline void
desc_copy_state (unw_word label, struct unw_state_record *sr) desc_copy_state (unw_word label, struct unw_state_record *sr)
{ {
struct unw_reg_state *rs; struct unw_labeled_state *ls;
for (rs = sr->reg_state_list; rs; rs = rs->next) { for (ls = sr->labeled_states; ls; ls = ls->next) {
if (rs->label == label) { if (ls->label == label) {
memcpy (&sr->curr, rs, sizeof(sr->curr)); free_state_stack(&sr->curr);
memcpy(&sr->curr, &ls->saved_state, sizeof(sr->curr));
sr->curr.next = dup_state_stack(ls->saved_state.next);
return; return;
} }
} }
printk("unwind: failed to find state labelled 0x%lx\n", label); printk("unwind: failed to find state labeled 0x%lx\n", label);
} }
static inline void static inline void
desc_label_state (unw_word label, struct unw_state_record *sr) desc_label_state (unw_word label, struct unw_state_record *sr)
{ {
struct unw_reg_state *rs; struct unw_labeled_state *ls;
rs = alloc_reg_state(); ls = alloc_labeled_state();
if (!rs) { if (!ls) {
printk("unwind: cannot stack!\n"); printk("unwind.desc_label_state(): out of memory\n");
return; return;
} }
memcpy(rs, &sr->curr, sizeof(*rs)); ls->label = label;
rs->label = label; memcpy(&ls->saved_state, &sr->curr, sizeof(ls->saved_state));
rs->next = sr->reg_state_list; ls->saved_state.next = dup_state_stack(sr->curr.next);
sr->reg_state_list = rs;
/* insert into list of labeled states: */
ls->next = sr->labeled_states;
sr->labeled_states = ls;
} }
/* /*
...@@ -1378,6 +1421,8 @@ lookup (struct unw_table *table, unsigned long rel_ip) ...@@ -1378,6 +1421,8 @@ lookup (struct unw_table *table, unsigned long rel_ip)
else else
break; break;
} }
if (rel_ip < e->start_offset || rel_ip >= e->end_offset)
return NULL;
return e; return e;
} }
...@@ -1388,9 +1433,9 @@ lookup (struct unw_table *table, unsigned long rel_ip) ...@@ -1388,9 +1433,9 @@ lookup (struct unw_table *table, unsigned long rel_ip)
static inline struct unw_script * static inline struct unw_script *
build_script (struct unw_frame_info *info) build_script (struct unw_frame_info *info)
{ {
struct unw_reg_state *rs, *next;
const struct unw_table_entry *e = 0; const struct unw_table_entry *e = 0;
struct unw_script *script = 0; struct unw_script *script = 0;
struct unw_labeled_state *ls, *next;
unsigned long ip = info->ip; unsigned long ip = info->ip;
struct unw_state_record sr; struct unw_state_record sr;
struct unw_table *table; struct unw_table *table;
...@@ -1535,15 +1580,15 @@ build_script (struct unw_frame_info *info) ...@@ -1535,15 +1580,15 @@ build_script (struct unw_frame_info *info)
for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i) for (i = UNW_REG_BSP; i < UNW_NUM_REGS; ++i)
compile_reg(&sr, i, script); compile_reg(&sr, i, script);
/* free labelled register states & stack: */ /* free labeled register states & stack: */
STAT(parse_start = ia64_get_itc()); STAT(parse_start = ia64_get_itc());
for (rs = sr.reg_state_list; rs; rs = next) { for (ls = sr.labeled_states; ls; ls = next) {
next = rs->next; next = ls->next;
free_reg_state(rs); free_state_stack(&ls->saved_state);
free_labeled_state(ls);
} }
while (sr.stack) free_state_stack(&sr.curr);
pop(&sr);
STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start); STAT(unw.stat.script.parse_time += ia64_get_itc() - parse_start);
script_finalize(script, &sr); script_finalize(script, &sr);
......
/* /*
* Copyright (C) 2000 Hewlett-Packard Co * Copyright (C) 2000, 2002 Hewlett-Packard Co
* Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
* Kernel unwind support. * Kernel unwind support.
*/ */
...@@ -85,6 +85,17 @@ struct unw_reg_info { ...@@ -85,6 +85,17 @@ struct unw_reg_info {
int when; /* when the register gets saved */ int when; /* when the register gets saved */
}; };
struct unw_reg_state {
struct unw_reg_state *next; /* next (outer) element on state stack */
struct unw_reg_info reg[UNW_NUM_REGS]; /* register save locations */
};
struct unw_labeled_state {
struct unw_labeled_state *next; /* next labeled state (or NULL) */
unsigned long label; /* label for this state */
struct unw_reg_state saved_state;
};
struct unw_state_record { struct unw_state_record {
unsigned int first_region : 1; /* is this the first region? */ unsigned int first_region : 1; /* is this the first region? */
unsigned int done : 1; /* are we done scanning descriptors? */ unsigned int done : 1; /* are we done scanning descriptors? */
...@@ -105,11 +116,8 @@ struct unw_state_record { ...@@ -105,11 +116,8 @@ struct unw_state_record {
u8 gr_save_loc; /* next general register to use for saving a register */ u8 gr_save_loc; /* next general register to use for saving a register */
u8 return_link_reg; /* branch register in which the return link is passed */ u8 return_link_reg; /* branch register in which the return link is passed */
struct unw_reg_state { struct unw_labeled_state *labeled_states; /* list of all labeled states */
struct unw_reg_state *next; struct unw_reg_state curr; /* current state */
unsigned long label; /* label of this state record */
struct unw_reg_info reg[UNW_NUM_REGS];
} curr, *stack, *reg_state_list;
}; };
enum unw_nat_type { enum unw_nat_type {
...@@ -139,7 +147,7 @@ struct unw_insn { ...@@ -139,7 +147,7 @@ struct unw_insn {
}; };
/* /*
* Preserved general static registers (r2-r5) give rise to two script * Preserved general static registers (r4-r7) give rise to two script
* instructions; everything else yields at most one instruction; at * instructions; everything else yields at most one instruction; at
* the end of the script, the psp gets popped, accounting for one more * the end of the script, the psp gets popped, accounting for one more
* instruction. * instruction.
......
/* /*
* * Copyright (C) 1999-2002 Hewlett-Packard Co
* Optimized function to clear a page of memory. * Stephane Eranian <eranian@hpl.hp.com>
* * David Mosberger-Tang <davidm@hpl.hp.com>
* Inputs: * Copyright (C) 2002 Ken Chen <kenneth.w.chen@intel.com>
* in0: address of page
*
* Output:
* none
*
* Copyright (C) 1999-2001 Hewlett-Packard Co
* Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 1999-2001 David Mosberger-Tang <davidm@hpl.hp.com>
* *
* 1/06/01 davidm Tuned for Itanium. * 1/06/01 davidm Tuned for Itanium.
* 2/12/02 kchen Tuned for both Itanium and McKinley
* 3/08/02 davidm Some more tweaking
*/ */
#include <linux/config.h>
#include <asm/asmmacro.h> #include <asm/asmmacro.h>
#include <asm/page.h> #include <asm/page.h>
#ifdef CONFIG_ITANIUM
# define L3_LINE_SIZE 64 // Itanium L3 line size
# define PREFETCH_LINES 9 // magic number
#else
# define L3_LINE_SIZE 128 // McKinley L3 line size
# define PREFETCH_LINES 7 // magic number
#endif
#define saved_lc r2 #define saved_lc r2
#define dst0 in0 #define dst_fetch r3
#define dst1 r8 #define dst1 r8
#define dst2 r9 #define dst2 r9
#define dst3 r10 #define dst3 r10
#define dst_fetch r11 #define dst4 r11
#define dst_last r31
GLOBAL_ENTRY(clear_page) GLOBAL_ENTRY(clear_page)
.prologue .prologue
.regstk 1,0,0,0 .regstk 1,0,0,0
mov r16 = PAGE_SIZE/64-1 // -1 = repeat/until mov r16 = PAGE_SIZE/L3_LINE_SIZE-1 // main loop count, -1=repeat/until
;;
.save ar.lc, saved_lc .save ar.lc, saved_lc
mov saved_lc = ar.lc mov saved_lc = ar.lc
.body .body
mov ar.lc = r16 mov ar.lc = (PREFETCH_LINES - 1)
adds dst1 = 16, dst0 mov dst_fetch = in0
adds dst2 = 32, dst0 adds dst1 = 16, in0
adds dst3 = 48, dst0 adds dst2 = 32, in0
adds dst_fetch = 512, dst0 ;;
.fetch: stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE
adds dst3 = 48, in0 // executing this multiple times is harmless
br.cloop.sptk.few .fetch
;;
addl dst_last = (PAGE_SIZE - PREFETCH_LINES*L3_LINE_SIZE), dst_fetch
mov ar.lc = r16 // one L3 line per iteration
adds dst4 = 64, in0
;;
#ifdef CONFIG_ITANIUM
// Optimized for Itanium
1: stf.spill.nta [dst1] = f0, 64
stf.spill.nta [dst2] = f0, 64
cmp.lt p8,p0=dst_fetch, dst_last
;;
#else
// Optimized for McKinley
1: stf.spill.nta [dst1] = f0, 64
stf.spill.nta [dst2] = f0, 64
stf.spill.nta [dst3] = f0, 64
stf.spill.nta [dst4] = f0, 128
cmp.lt p8,p0=dst_fetch, dst_last
;; ;;
1: stf.spill.nta [dst0] = f0, 64
stf.spill.nta [dst1] = f0, 64 stf.spill.nta [dst1] = f0, 64
stf.spill.nta [dst2] = f0, 64 stf.spill.nta [dst2] = f0, 64
#endif
stf.spill.nta [dst3] = f0, 64 stf.spill.nta [dst3] = f0, 64
(p8) stf.spill.nta [dst_fetch] = f0, L3_LINE_SIZE
lfetch [dst_fetch], 64 br.cloop.sptk.few 1b
br.cloop.dptk.few 1b
;; ;;
mov ar.lc = r2 // restore lc mov ar.lc = saved_lc // restore lc
br.ret.sptk.many rp br.ret.sptk.many rp
END(clear_page) END(clear_page)
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
* no return value * no return value
* *
* Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999, 2001 Hewlett-Packard Co
* Copyright (C) 1999 Stephane Eranian <eranian@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com>
* Copyright (C) 2001 David Mosberger <davidm@hpl.hp.com> * David Mosberger <davidm@hpl.hp.com>
* *
* 4/06/01 davidm Tuned to make it perform well both for cached and uncached copies. * 4/06/01 davidm Tuned to make it perform well both for cached and uncached copies.
*/ */
......
...@@ -27,10 +27,19 @@ ...@@ -27,10 +27,19 @@
#define ALIGN(val, align) ((unsigned long) \ #define ALIGN(val, align) ((unsigned long) \
(((unsigned long) (val) + ((align) - 1)) & ~((align) - 1))) (((unsigned long) (val) + ((align) - 1)) & ~((align) - 1)))
#define SG_ENT_VIRT_ADDRESS(sg) ((sg)->address ? (sg)->address \ #define OFFSET(val,align) ((unsigned long) \
: page_address((sg)->page) + (sg)->offset) ( (val) & ( (align) - 1)))
#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset)
#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG)) #define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
/*
* Maximum allowable number of contiguous slabs to map,
* must be a power of 2. What is the appropriate value ?
* The complexity of {map,unmap}_single is linearly dependent on this value.
*/
#define IO_TLB_SEGSIZE 128
/* /*
* log of the size of each IO TLB slab. The number of slabs is command line controllable. * log of the size of each IO TLB slab. The number of slabs is command line controllable.
*/ */
...@@ -69,10 +78,15 @@ static int __init ...@@ -69,10 +78,15 @@ static int __init
setup_io_tlb_npages (char *str) setup_io_tlb_npages (char *str)
{ {
io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT); io_tlb_nslabs = simple_strtoul(str, NULL, 0) << (PAGE_SHIFT - IO_TLB_SHIFT);
/* avoid tail segment of size < IO_TLB_SEGSIZE */
io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
return 1; return 1;
} }
__setup("swiotlb=", setup_io_tlb_npages); __setup("swiotlb=", setup_io_tlb_npages);
/* /*
* Statically reserve bounce buffer space and initialize bounce buffer data structures for * Statically reserve bounce buffer space and initialize bounce buffer data structures for
* the software IO TLB used to implement the PCI DMA API. * the software IO TLB used to implement the PCI DMA API.
...@@ -92,12 +106,12 @@ swiotlb_init (void) ...@@ -92,12 +106,12 @@ swiotlb_init (void)
/* /*
* Allocate and initialize the free list array. This array is used * Allocate and initialize the free list array. This array is used
* to find contiguous free memory regions of size 2^IO_TLB_SHIFT between * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
* io_tlb_start and io_tlb_end. * between io_tlb_start and io_tlb_end.
*/ */
io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int)); io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
for (i = 0; i < io_tlb_nslabs; i++) for (i = 0; i < io_tlb_nslabs; i++)
io_tlb_list[i] = io_tlb_nslabs - i; io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
io_tlb_index = 0; io_tlb_index = 0;
io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *)); io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
...@@ -124,7 +138,7 @@ map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction) ...@@ -124,7 +138,7 @@ map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction)
if (size > (1 << PAGE_SHIFT)) if (size > (1 << PAGE_SHIFT))
stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT)); stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
else else
stride = nslots; stride = 1;
if (!nslots) if (!nslots)
BUG(); BUG();
...@@ -151,7 +165,8 @@ map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction) ...@@ -151,7 +165,8 @@ map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction)
for (i = index; i < index + nslots; i++) for (i = index; i < index + nslots; i++)
io_tlb_list[i] = 0; io_tlb_list[i] = 0;
for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--) for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1)
&& io_tlb_list[i]; i--)
io_tlb_list[i] = ++count; io_tlb_list[i] = ++count;
dma_addr = io_tlb_start + (index << IO_TLB_SHIFT); dma_addr = io_tlb_start + (index << IO_TLB_SHIFT);
...@@ -217,7 +232,8 @@ unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) ...@@ -217,7 +232,8 @@ unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
*/ */
spin_lock_irqsave(&io_tlb_lock, flags); spin_lock_irqsave(&io_tlb_lock, flags);
{ {
int count = ((index + nslots) < io_tlb_nslabs ? io_tlb_list[index + nslots] : 0); int count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
io_tlb_list[index + nslots] : 0);
/* /*
* Step 1: return the slots to the free list, merging the slots with * Step 1: return the slots to the free list, merging the slots with
* superceeding slots * superceeding slots
...@@ -228,7 +244,8 @@ unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction) ...@@ -228,7 +244,8 @@ unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
* Step 2: merge the returned slots with the preceeding slots, if * Step 2: merge the returned slots with the preceeding slots, if
* available (non zero) * available (non zero)
*/ */
for (i = index - 1; (i >= 0) && io_tlb_list[i]; i--) for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) &&
io_tlb_list[i]; i--)
io_tlb_list[i] = ++count; io_tlb_list[i] = ++count;
} }
spin_unlock_irqrestore(&io_tlb_lock, flags); spin_unlock_irqrestore(&io_tlb_lock, flags);
...@@ -405,11 +422,9 @@ swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int d ...@@ -405,11 +422,9 @@ swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int d
for (i = 0; i < nelems; i++, sg++) { for (i = 0; i < nelems; i++, sg++) {
sg->orig_address = SG_ENT_VIRT_ADDRESS(sg); sg->orig_address = SG_ENT_VIRT_ADDRESS(sg);
if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) { if ((SG_ENT_PHYS_ADDRESS(sg) & ~hwdev->dma_mask) != 0) {
addr = map_single(hwdev, sg->address, sg->length, direction); addr = map_single(hwdev, sg->orig_address, sg->length, direction);
if (sg->address) sg->page = virt_to_page(addr);
sg->address = addr; sg->offset = (u64) addr & ~PAGE_MASK;
else
sg->page = virt_to_page(addr);
} }
} }
return nelems; return nelems;
...@@ -430,12 +445,10 @@ swiotlb_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int ...@@ -430,12 +445,10 @@ swiotlb_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int
for (i = 0; i < nelems; i++, sg++) for (i = 0; i < nelems; i++, sg++)
if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) { if (sg->orig_address != SG_ENT_VIRT_ADDRESS(sg)) {
unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction); unmap_single(hwdev, SG_ENT_VIRT_ADDRESS(sg), sg->length, direction);
if (sg->address) sg->page = virt_to_page(sg->orig_address);
sg->address = sg->orig_address; sg->offset = (u64) sg->orig_address & ~PAGE_MASK;
else
sg->page = virt_to_page(sg->orig_address);
} else if (direction == PCI_DMA_FROMDEVICE) } else if (direction == PCI_DMA_FROMDEVICE)
mark_clean(sg->address, sg->length); mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->length);
} }
/* /*
......
/* /*
* Kernel exception handling table support. Derived from arch/alpha/mm/extable.c. * Kernel exception handling table support. Derived from arch/alpha/mm/extable.c.
* *
* Copyright (C) 1998, 1999, 2001 Hewlett-Packard Co * Copyright (C) 1998, 1999, 2001-2002 Hewlett-Packard Co
* Copyright (C) 1998, 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -55,10 +55,12 @@ search_exception_table (unsigned long addr) ...@@ -55,10 +55,12 @@ search_exception_table (unsigned long addr)
struct module *mp; struct module *mp;
/* The kernel is the last "module" -- no need to treat it special. */ /* The kernel is the last "module" -- no need to treat it special. */
for (mp = module_list; mp ; mp = mp->next) { for (mp = module_list; mp; mp = mp->next) {
if (!mp->ex_table_start) if (!mp->ex_table_start)
continue; continue;
archdata = (struct archdata *) mp->archdata_start; archdata = (struct archdata *) mp->archdata_start;
if (!archdata)
continue;
entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1,
addr, (unsigned long) archdata->gp); addr, (unsigned long) archdata->gp);
if (entry) { if (entry) {
......
/* /*
* MMU fault handling support. * MMU fault handling support.
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2002 Hewlett-Packard Co
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/sched.h> #include <linux/sched.h>
...@@ -96,7 +96,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re ...@@ -96,7 +96,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
* sure we exit gracefully rather than endlessly redo the * sure we exit gracefully rather than endlessly redo the
* fault. * fault.
*/ */
switch (handle_mm_fault(mm, vma, address, mask)) { switch (handle_mm_fault(mm, vma, address, (mask & VM_WRITE) != 0)) {
case 1: case 1:
++current->min_flt; ++current->min_flt;
break; break;
...@@ -151,6 +151,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re ...@@ -151,6 +151,8 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
si.si_errno = 0; si.si_errno = 0;
si.si_code = code; si.si_code = code;
si.si_addr = (void *) address; si.si_addr = (void *) address;
si.si_isr = isr;
si.si_flags = __ISR_VALID;
force_sig_info(signal, &si, current); force_sig_info(signal, &si, current);
return; return;
} }
...@@ -194,9 +196,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re ...@@ -194,9 +196,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
out_of_memory: out_of_memory:
up_read(&mm->mmap_sem); up_read(&mm->mmap_sem);
if (current->pid == 1) { if (current->pid == 1) {
current->policy |= SCHED_YIELD; yield();
schedule();
down_read(&mm->mmap_sem);
goto survive; goto survive;
} }
printk("VM: killing process %s\n", current->comm); printk("VM: killing process %s\n", current->comm);
......
/* /*
* Initialize MMU support. * Initialize MMU support.
* *
* Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2002 Hewlett-Packard Co
* Copyright (C) 1998-2001 David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <asm/a.out.h>
#include <asm/bitops.h> #include <asm/bitops.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/efi.h> #include <asm/efi.h>
...@@ -37,10 +38,15 @@ unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL; ...@@ -37,10 +38,15 @@ unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
static unsigned long totalram_pages; static unsigned long totalram_pages;
static int pgt_cache_water[2] = { 25, 50 };
int int
do_check_pgt_cache (int low, int high) check_pgt_cache (void)
{ {
int freed = 0; int low, high, freed = 0;
low = pgt_cache_water[0];
high = pgt_cache_water[1];
if (pgtable_cache_size > high) { if (pgtable_cache_size > high) {
do { do {
...@@ -48,8 +54,6 @@ do_check_pgt_cache (int low, int high) ...@@ -48,8 +54,6 @@ do_check_pgt_cache (int low, int high)
free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed; free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed;
if (pmd_quicklist) if (pmd_quicklist)
free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed;
if (pte_quicklist)
free_page((unsigned long)pte_alloc_one_fast(0, 0)), ++freed;
} while (pgtable_cache_size > low); } while (pgtable_cache_size > low);
} }
return freed; return freed;
...@@ -243,15 +247,16 @@ put_gate_page (struct page *page, unsigned long address) ...@@ -243,15 +247,16 @@ put_gate_page (struct page *page, unsigned long address)
pmd = pmd_alloc(&init_mm, pgd, address); pmd = pmd_alloc(&init_mm, pgd, address);
if (!pmd) if (!pmd)
goto out; goto out;
pte = pte_alloc(&init_mm, pmd, address); pte = pte_alloc_map(&init_mm, pmd, address);
if (!pte) if (!pte)
goto out; goto out;
if (!pte_none(*pte)) { if (!pte_none(*pte)) {
pte_ERROR(*pte); pte_unmap(pte);
goto out; goto out;
} }
flush_page_to_ram(page); flush_page_to_ram(page);
set_pte(pte, mk_pte(page, PAGE_GATE)); set_pte(pte, mk_pte(page, PAGE_GATE));
pte_unmap(pte);
} }
out: spin_unlock(&init_mm.page_table_lock); out: spin_unlock(&init_mm.page_table_lock);
/* no need for flush_tlb */ /* no need for flush_tlb */
......
#
# ia64/sn/Makefile
#
# Copyright (C) 1999 Silicon Graphics, Inc.
# Copyright (C) Srinivasa Thirumalachar (sprasad@engr.sgi.com)
#
EXTRA_CFLAGS := -DSN -DLANGUAGE_C=1 -D_LANGUAGE_C=1 -I. -DBRINGUP \
-DDIRECT_L1_CONSOLE -DNUMA_BASE -DSIMULATED_KLGRAPH \
-DNUMA_MIGR_CONTROL -DLITTLE_ENDIAN -DREAL_HARDWARE \
-DNEW_INTERRUPTS
all: sn.a
O_TARGET = sn.a
obj-y = sn1/sn1.a
clean::
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#
# Automatically generated make config: don't edit
#
#
# Code maturity level options
#
# CONFIG_EXPERIMENTAL is not set
#
# Loadable module support
#
# CONFIG_MODULES is not set
#
# General setup
#
CONFIG_IA64=y
# CONFIG_ISA is not set
# CONFIG_EISA is not set
# CONFIG_MCA is not set
# CONFIG_SBUS is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
CONFIG_ITANIUM=y
# CONFIG_MCKINLEY is not set
# CONFIG_IA64_GENERIC is not set
# CONFIG_IA64_DIG is not set
CONFIG_IA64_HP_SIM=y
# CONFIG_IA64_SGI_SN1 is not set
# CONFIG_IA64_SGI_SN2 is not set
# CONFIG_IA64_PAGE_SIZE_4KB is not set
# CONFIG_IA64_PAGE_SIZE_8KB is not set
CONFIG_IA64_PAGE_SIZE_16KB=y
# CONFIG_IA64_PAGE_SIZE_64KB is not set
CONFIG_IA64_BRL_EMU=y
CONFIG_ITANIUM_BSTEP_SPECIFIC=y
CONFIG_IA64_L1_CACHE_SHIFT=6
CONFIG_KCORE_ELF=y
# CONFIG_SMP is not set
# CONFIG_IA32_SUPPORT is not set
# CONFIG_PERFMON is not set
# CONFIG_IA64_PALINFO is not set
# CONFIG_EFI_VARS is not set
CONFIG_NET=y
CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
# Networking options
#
# CONFIG_PACKET is not set
# CONFIG_NETLINK is not set
# CONFIG_NETFILTER is not set
# CONFIG_FILTER is not set
CONFIG_UNIX=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
#
#
#
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
#
# QoS and/or fair queueing
#
# CONFIG_NET_SCHED is not set
#
# Alternate 1394 support
#
# CONFIG_X1394 is not set
#
# Alternate SCSI support
#
# CONFIG_XSCSI is not set
#
# SCSI support
#
CONFIG_SCSI=y
#
# SCSI support type (disk, tape, CD-ROM)
#
CONFIG_BLK_DEV_SD=y
CONFIG_SD_EXTRA_DEVS=40
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
#
# CONFIG_SCSI_DEBUG_QUEUES is not set
# CONFIG_SCSI_MULTI_LUN is not set
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
# SCSI low-level drivers
#
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_SCSI_ADVANSYS is not set
# CONFIG_SCSI_IN2000 is not set
# CONFIG_SCSI_AM53C974 is not set
# CONFIG_SCSI_MEGARAID is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_DTC3280 is not set
# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_EATA_DMA is not set
# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_GENERIC_NCR5380 is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_PPA is not set
# CONFIG_SCSI_IMM is not set
# CONFIG_SCSI_NCR53C406A is not set
# CONFIG_SCSI_NCR53C7xx is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PCI2000 is not set
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
#
# Input core support
#
# CONFIG_INPUT is not set
# CONFIG_INPUT_KEYBDEV is not set
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_EVDEV is not set
#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
# CONFIG_SERIAL is not set
# CONFIG_SERIAL_EXTENDED is not set
# CONFIG_SERIAL_NONSTANDARD is not set
CONFIG_UNIX98_PTYS=y
CONFIG_UNIX98_PTY_COUNT=256
# CONFIG_PRINTER is not set
# CONFIG_PPDEV is not set
#
# I2C support
#
# CONFIG_I2C is not set
#
# Mice
#
# CONFIG_BUSMOUSE is not set
# CONFIG_MOUSE is not set
#
# Joysticks
#
# CONFIG_INPUT_GAMEPORT is not set
#
# Input core support is needed for gameports
#
#
# Input core support is needed for joysticks
#
# CONFIG_QIC02_TAPE is not set
#
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
# CONFIG_INTEL_RNG is not set
# CONFIG_NVRAM is not set
# CONFIG_RTC is not set
CONFIG_EFI_RTC=y
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
# CONFIG_FTAPE is not set
# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_MWAVE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
#
# File systems
#
# CONFIG_QUOTA is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_REISERFS_CHECK is not set
# CONFIG_ADFS_FS is not set
# CONFIG_ADFS_FS_RW is not set
# CONFIG_AFFS_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_FAT_FS is not set
# CONFIG_MSDOS_FS is not set
# CONFIG_UMSDOS_FS is not set
# CONFIG_VFAT_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
CONFIG_TMPFS=y
# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
# CONFIG_DEVFS_FS is not set
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
CONFIG_DEVPTS_FS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_QNX4FS_RW is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_XFS_SUPPORT is not set
#
# Network File Systems
#
# CONFIG_CODA_FS is not set
# CONFIG_NFS_FS is not set
# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
# CONFIG_NFSD_V3 is not set
# CONFIG_SUNRPC is not set
# CONFIG_LOCKD is not set
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
# CONFIG_NCPFS_IOCTL_LOCKING is not set
# CONFIG_NCPFS_STRONG is not set
# CONFIG_NCPFS_NFS_NS is not set
# CONFIG_NCPFS_OS2_NS is not set
# CONFIG_NCPFS_SMALLDOS is not set
# CONFIG_NCPFS_NLS is not set
# CONFIG_NCPFS_EXTRAS is not set
#
# Partition Types
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
# CONFIG_SMB_NLS is not set
# CONFIG_NLS is not set
#
# Console drivers
#
CONFIG_VGA_CONSOLE=y
#
# Frame-buffer support
#
# CONFIG_FB is not set
#
# Simulated drivers
#
CONFIG_SIMETH=y
CONFIG_SIM_SERIAL=y
CONFIG_SCSI_SIM=y
#
# Kernel hacking
#
CONFIG_DEBUG_KERNEL=y
CONFIG_IA64_PRINT_HAZARDS=y
# CONFIG_DISABLE_VHPT is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_IA64_EARLY_PRINTK=y
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_IA64_DEBUG_CMPXCHG is not set
# CONFIG_IA64_DEBUG_IRQ is not set
# CONFIG_KDB is not set
# CONFIG_KDB_MODULES is not set
# CONFIG_KALLSYMS is not set
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
# License. See the file "COPYING" in the main directory of this archive # License. See the file "COPYING" in the main directory of this archive
# for more details. # for more details.
# #
# Copyright (C) 2000 Silicon Graphics, Inc. # Copyright (c) 2000-2001 Silicon Graphics, Inc. All rights reserved.
# Copyright (C) Jack Steiner (steiner@sgi.com)
# #
TOPDIR=../../../.. TOPDIR=../../../..
...@@ -12,18 +11,16 @@ HPATH = $(TOPDIR)/include ...@@ -12,18 +11,16 @@ HPATH = $(TOPDIR)/include
LIB = ../../lib/lib.a LIB = ../../lib/lib.a
OBJ=fpromasm.o main.o fw-emu.o fpmem.o OBJ=fpromasm.o main.o fw-emu.o fpmem.o klgraph_init.o
obj-y=fprom obj-y=fprom
fprom: $(OBJ) fprom: $(OBJ)
$(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB) $(LD) -static -Tfprom.lds -o fprom $(OBJ) $(LIB)
comma := ,
.S.o: .S.o:
$(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $< $(CC) -D__ASSEMBLY__ $(AFLAGS) $(AFLAGS_KERNEL) -c -o $*.o $<
.c.o: .c.o:
$(CC) $(CFLAGS) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_KERNEL) -c -o $*.o $< $(CC) $(CFLAGS) $(CFLAGS_KERNEL) -c -o $*.o $<
clean: clean:
rm -f *.o fprom rm -f *.o fprom
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
* Copyright (C) 2000 by Colin Ngam
*/ */
#include <linux/types.h> #include <linux/types.h>
...@@ -14,6 +13,7 @@ ...@@ -14,6 +13,7 @@
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <asm/sn/sgi.h> #include <asm/sn/sgi.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/sn/io.h>
#include <asm/sn/iograph.h> #include <asm/sn/iograph.h>
#include <asm/sn/invent.h> #include <asm/sn/invent.h>
#include <asm/sn/hcl.h> #include <asm/sn/hcl.h>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -4,8 +4,7 @@ ...@@ -4,8 +4,7 @@
* License. See the file "COPYING" in the main directory of this archive * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
* *
* Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc. * Copyright (C) 1992 - 1997, 2000-2001 Silicon Graphics, Inc. All rights reserved.
* Copyright (C) 2000 by Colin Ngam
*/ */
/* /*
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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