Commit 2e3e80c2 authored by Linus Torvalds's avatar Linus Torvalds
parents 4e7c6816 fffcc150
...@@ -1023,8 +1023,8 @@ W: http://www.ia64-linux.org/ ...@@ -1023,8 +1023,8 @@ W: http://www.ia64-linux.org/
S: Maintained S: Maintained
SN-IA64 (Itanium) SUB-PLATFORM SN-IA64 (Itanium) SUB-PLATFORM
P: Jesse Barnes P: Greg Edwards
M: jbarnes@sgi.com M: edwardsg@sgi.com
L: linux-altix@sgi.com L: linux-altix@sgi.com
L: linux-ia64@vger.kernel.org L: linux-ia64@vger.kernel.org
W: http://www.sgi.com/altix W: http://www.sgi.com/altix
......
...@@ -1182,7 +1182,7 @@ ENTRY(notify_resume_user) ...@@ -1182,7 +1182,7 @@ ENTRY(notify_resume_user)
;; ;;
(pNonSys) mov out2=0 // out2==0 => not a syscall (pNonSys) mov out2=0 // out2==0 => not a syscall
.fframe 16 .fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) .spillsp ar.unat, 16
st8 [sp]=r9,-16 // allocate space for ar.unat and save it st8 [sp]=r9,-16 // allocate space for ar.unat and save it
st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch
.body .body
...@@ -1208,7 +1208,7 @@ GLOBAL_ENTRY(sys_rt_sigsuspend) ...@@ -1208,7 +1208,7 @@ GLOBAL_ENTRY(sys_rt_sigsuspend)
adds out2=8,sp // out2=&sigscratch->ar_pfs adds out2=8,sp // out2=&sigscratch->ar_pfs
;; ;;
.fframe 16 .fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) .spillsp ar.unat, 16
st8 [sp]=r9,-16 // allocate space for ar.unat and save it st8 [sp]=r9,-16 // allocate space for ar.unat and save it
st8 [out2]=loc1,-8 // save ar.pfs, out2=&sigscratch st8 [out2]=loc1,-8 // save ar.pfs, out2=&sigscratch
.body .body
......
...@@ -1390,8 +1390,7 @@ ia64_mca_init(void) ...@@ -1390,8 +1390,7 @@ ia64_mca_init(void)
register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* Setup the CPEI/P vector and handler */ /* Setup the CPEI/P handler */
cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
#endif #endif
...@@ -1436,6 +1435,7 @@ ia64_mca_late_init(void) ...@@ -1436,6 +1435,7 @@ ia64_mca_late_init(void)
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* Setup the CPEI/P vector and handler */ /* Setup the CPEI/P vector and handler */
cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI);
init_timer(&cpe_poll_timer); init_timer(&cpe_poll_timer);
cpe_poll_timer.function = ia64_mca_cpe_poll; cpe_poll_timer.function = ia64_mca_cpe_poll;
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
(pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \ (pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \
(pKStk) ld8 r3 = [r3];; \ (pKStk) ld8 r3 = [r3];; \
(pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \ (pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \
(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ (pKStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \
(pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ (pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \
(pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ (pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \
;; \ ;; \
...@@ -50,7 +50,6 @@ ...@@ -50,7 +50,6 @@
(pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ (pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \
(pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ (pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \
;; \ ;; \
(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \
(pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ (pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \
;; \ ;; \
(pUStk) mov r18=ar.bsp; \ (pUStk) mov r18=ar.bsp; \
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Version Perfmon-2.x is a rewrite of perfmon-1.x * Version Perfmon-2.x is a rewrite of perfmon-1.x
* by Stephane Eranian, Hewlett Packard Co. * by Stephane Eranian, Hewlett Packard Co.
* *
* Copyright (C) 1999-2003, 2005 Hewlett Packard Co * Copyright (C) 1999-2005 Hewlett Packard Co
* Stephane Eranian <eranian@hpl.hp.com> * Stephane Eranian <eranian@hpl.hp.com>
* David Mosberger-Tang <davidm@hpl.hp.com> * David Mosberger-Tang <davidm@hpl.hp.com>
* *
...@@ -497,6 +497,9 @@ typedef struct { ...@@ -497,6 +497,9 @@ typedef struct {
static pfm_stats_t pfm_stats[NR_CPUS]; static pfm_stats_t pfm_stats[NR_CPUS];
static pfm_session_t pfm_sessions; /* global sessions information */ static pfm_session_t pfm_sessions; /* global sessions information */
static spinlock_t pfm_alt_install_check = SPIN_LOCK_UNLOCKED;
static pfm_intr_handler_desc_t *pfm_alt_intr_handler;
static struct proc_dir_entry *perfmon_dir; static struct proc_dir_entry *perfmon_dir;
static pfm_uuid_t pfm_null_uuid = {0,}; static pfm_uuid_t pfm_null_uuid = {0,};
...@@ -606,6 +609,7 @@ DEFINE_PER_CPU(unsigned long, pfm_syst_info); ...@@ -606,6 +609,7 @@ DEFINE_PER_CPU(unsigned long, pfm_syst_info);
DEFINE_PER_CPU(struct task_struct *, pmu_owner); DEFINE_PER_CPU(struct task_struct *, pmu_owner);
DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); DEFINE_PER_CPU(pfm_context_t *, pmu_ctx);
DEFINE_PER_CPU(unsigned long, pmu_activation_number); DEFINE_PER_CPU(unsigned long, pmu_activation_number);
EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info);
/* forward declaration */ /* forward declaration */
...@@ -1325,7 +1329,7 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) ...@@ -1325,7 +1329,7 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu)
error_conflict: error_conflict:
DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n",
pfm_sessions.pfs_sys_session[cpu]->pid, pfm_sessions.pfs_sys_session[cpu]->pid,
smp_processor_id())); cpu));
abort: abort:
UNLOCK_PFS(flags); UNLOCK_PFS(flags);
...@@ -5555,26 +5559,32 @@ pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) ...@@ -5555,26 +5559,32 @@ pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
int ret; int ret;
this_cpu = get_cpu(); this_cpu = get_cpu();
min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; if (likely(!pfm_alt_intr_handler)) {
max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min;
max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max;
start_cycles = ia64_get_itc(); start_cycles = ia64_get_itc();
ret = pfm_do_interrupt_handler(irq, arg, regs); ret = pfm_do_interrupt_handler(irq, arg, regs);
total_cycles = ia64_get_itc(); total_cycles = ia64_get_itc();
/* /*
* don't measure spurious interrupts * don't measure spurious interrupts
*/ */
if (likely(ret == 0)) { if (likely(ret == 0)) {
total_cycles -= start_cycles; total_cycles -= start_cycles;
if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles; if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles;
if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles; if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles;
pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles; pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles;
}
}
else {
(*pfm_alt_intr_handler->handler)(irq, arg, regs);
} }
put_cpu_no_resched(); put_cpu_no_resched();
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -6425,6 +6435,141 @@ static struct irqaction perfmon_irqaction = { ...@@ -6425,6 +6435,141 @@ static struct irqaction perfmon_irqaction = {
.name = "perfmon" .name = "perfmon"
}; };
static void
pfm_alt_save_pmu_state(void *data)
{
struct pt_regs *regs;
regs = ia64_task_regs(current);
DPRINT(("called\n"));
/*
* should not be necessary but
* let's take not risk
*/
pfm_clear_psr_up();
pfm_clear_psr_pp();
ia64_psr(regs)->pp = 0;
/*
* This call is required
* May cause a spurious interrupt on some processors
*/
pfm_freeze_pmu();
ia64_srlz_d();
}
void
pfm_alt_restore_pmu_state(void *data)
{
struct pt_regs *regs;
regs = ia64_task_regs(current);
DPRINT(("called\n"));
/*
* put PMU back in state expected
* by perfmon
*/
pfm_clear_psr_up();
pfm_clear_psr_pp();
ia64_psr(regs)->pp = 0;
/*
* perfmon runs with PMU unfrozen at all times
*/
pfm_unfreeze_pmu();
ia64_srlz_d();
}
int
pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
{
int ret, i;
int reserve_cpu;
/* some sanity checks */
if (hdl == NULL || hdl->handler == NULL) return -EINVAL;
/* do the easy test first */
if (pfm_alt_intr_handler) return -EBUSY;
/* one at a time in the install or remove, just fail the others */
if (!spin_trylock(&pfm_alt_install_check)) {
return -EBUSY;
}
/* reserve our session */
for_each_online_cpu(reserve_cpu) {
ret = pfm_reserve_session(NULL, 1, reserve_cpu);
if (ret) goto cleanup_reserve;
}
/* save the current system wide pmu states */
ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1);
if (ret) {
DPRINT(("on_each_cpu() failed: %d\n", ret));
goto cleanup_reserve;
}
/* officially change to the alternate interrupt handler */
pfm_alt_intr_handler = hdl;
spin_unlock(&pfm_alt_install_check);
return 0;
cleanup_reserve:
for_each_online_cpu(i) {
/* don't unreserve more than we reserved */
if (i >= reserve_cpu) break;
pfm_unreserve_session(NULL, 1, i);
}
spin_unlock(&pfm_alt_install_check);
return ret;
}
EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt);
int
pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl)
{
int i;
int ret;
if (hdl == NULL) return -EINVAL;
/* cannot remove someone else's handler! */
if (pfm_alt_intr_handler != hdl) return -EINVAL;
/* one at a time in the install or remove, just fail the others */
if (!spin_trylock(&pfm_alt_install_check)) {
return -EBUSY;
}
pfm_alt_intr_handler = NULL;
ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1);
if (ret) {
DPRINT(("on_each_cpu() failed: %d\n", ret));
}
for_each_online_cpu(i) {
pfm_unreserve_session(NULL, 1, i);
}
spin_unlock(&pfm_alt_install_check);
return 0;
}
EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt);
/* /*
* perfmon initialization routine, called from the initcall() table * perfmon initialization routine, called from the initcall() table
*/ */
......
...@@ -692,16 +692,30 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs *pt, ...@@ -692,16 +692,30 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs *pt,
unsigned long cfm) unsigned long cfm)
{ {
struct unw_frame_info info, prev_info; struct unw_frame_info info, prev_info;
unsigned long ip, pr; unsigned long ip, sp, pr;
unw_init_from_blocked_task(&info, child); unw_init_from_blocked_task(&info, child);
while (1) { while (1) {
prev_info = info; prev_info = info;
if (unw_unwind(&info) < 0) if (unw_unwind(&info) < 0)
return; return;
if (unw_get_rp(&info, &ip) < 0)
unw_get_sp(&info, &sp);
if ((long)((unsigned long)child + IA64_STK_OFFSET - sp)
< IA64_PT_REGS_SIZE) {
dprintk("ptrace.%s: ran off the top of the kernel "
"stack\n", __FUNCTION__);
return;
}
if (unw_get_pr (&prev_info, &pr) < 0) {
unw_get_rp(&prev_info, &ip);
dprintk("ptrace.%s: failed to read "
"predicate register (ip=0x%lx)\n",
__FUNCTION__, ip);
return; return;
if (ip < FIXADDR_USER_END) }
if (unw_is_intr_frame(&info)
&& (pr & (1UL << PRED_USER_STACK)))
break; break;
} }
......
...@@ -624,7 +624,7 @@ static struct { ...@@ -624,7 +624,7 @@ static struct {
__u16 thread_id; __u16 thread_id;
__u16 proc_fixed_addr; __u16 proc_fixed_addr;
__u8 valid; __u8 valid;
}mt_info[NR_CPUS] __devinit; } mt_info[NR_CPUS] __devinitdata;
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static inline void static inline void
......
...@@ -182,13 +182,6 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un ...@@ -182,13 +182,6 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un
} }
} }
/*
* A zero mmap always succeeds in Linux, independent of whether or not the
* remaining arguments are valid.
*/
if (len == 0)
goto out;
/* Careful about overflows.. */ /* Careful about overflows.. */
len = PAGE_ALIGN(len); len = PAGE_ALIGN(len);
if (!len || len > TASK_SIZE) { if (!len || len > TASK_SIZE) {
......
...@@ -271,6 +271,8 @@ void __init sn_setup(char **cmdline_p) ...@@ -271,6 +271,8 @@ void __init sn_setup(char **cmdline_p)
int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
extern void sn_cpu_init(void); extern void sn_cpu_init(void);
ia64_sn_plat_set_error_handling_features();
/* /*
* If the generic code has enabled vga console support - lets * If the generic code has enabled vga console support - lets
* get rid of it again. This is a kludge for the fact that ACPI * get rid of it again. This is a kludge for the fact that ACPI
......
...@@ -177,6 +177,10 @@ typedef union { ...@@ -177,6 +177,10 @@ typedef union {
extern long perfmonctl(int fd, int cmd, void *arg, int narg); extern long perfmonctl(int fd, int cmd, void *arg, int narg);
typedef struct {
void (*handler)(int irq, void *arg, struct pt_regs *regs);
} pfm_intr_handler_desc_t;
extern void pfm_save_regs (struct task_struct *); extern void pfm_save_regs (struct task_struct *);
extern void pfm_load_regs (struct task_struct *); extern void pfm_load_regs (struct task_struct *);
...@@ -187,6 +191,10 @@ extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, ...@@ -187,6 +191,10 @@ extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info,
extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs);
extern void pfm_init_percpu(void); extern void pfm_init_percpu(void);
extern void pfm_handle_work(void); extern void pfm_handle_work(void);
extern int pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
extern int pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h);
/* /*
* Reset PMD register flags * Reset PMD register flags
......
...@@ -115,6 +115,13 @@ ...@@ -115,6 +115,13 @@
#define SAL_IROUTER_INTR_XMIT SAL_CONSOLE_INTR_XMIT #define SAL_IROUTER_INTR_XMIT SAL_CONSOLE_INTR_XMIT
#define SAL_IROUTER_INTR_RECV SAL_CONSOLE_INTR_RECV #define SAL_IROUTER_INTR_RECV SAL_CONSOLE_INTR_RECV
/*
* Error Handling Features
*/
#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV 0x1
#define SAL_ERR_FEAT_LOG_SBES 0x2
#define SAL_ERR_FEAT_MFR_OVERRIDE 0x4
#define SAL_ERR_FEAT_SBE_THRESHOLD 0xffff0000
/* /*
* SAL Error Codes * SAL Error Codes
...@@ -341,6 +348,25 @@ ia64_sn_plat_cpei_handler(void) ...@@ -341,6 +348,25 @@ ia64_sn_plat_cpei_handler(void)
return ret_stuff.status; return ret_stuff.status;
} }
/*
* Set Error Handling Features
*/
static inline u64
ia64_sn_plat_set_error_handling_features(void)
{
struct ia64_sal_retval ret_stuff;
ret_stuff.status = 0;
ret_stuff.v0 = 0;
ret_stuff.v1 = 0;
ret_stuff.v2 = 0;
SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES,
(SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV | SAL_ERR_FEAT_LOG_SBES),
0, 0, 0, 0, 0, 0);
return ret_stuff.status;
}
/* /*
* Checks for console input. * Checks for console input.
*/ */
...@@ -472,7 +498,7 @@ static inline u64 ...@@ -472,7 +498,7 @@ static inline u64
ia64_sn_pod_mode(void) ia64_sn_pod_mode(void)
{ {
struct ia64_sal_retval isrv; struct ia64_sal_retval isrv;
SAL_CALL(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0); SAL_CALL_REENTRANT(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0);
if (isrv.status) if (isrv.status)
return 0; return 0;
return isrv.v0; return isrv.v0;
......
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