fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / ia64 / kernel / perfmon.c
index 9f72dc5..c0a4d8f 100644 (file)
@@ -19,7 +19,6 @@
  *     http://www.hpl.hp.com/research/linux/perfmon
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/file.h>
 #include <linux/poll.h>
 #include <linux/vfs.h>
+#include <linux/smp.h>
 #include <linux/pagemap.h>
 #include <linux/mount.h>
-#include <linux/version.h>
 #include <linux/bitops.h>
+#include <linux/capability.h>
+#include <linux/rcupdate.h>
+#include <linux/completion.h>
 #include <linux/vs_memory.h>
-#include <linux/vs_cvirt.h>
 
 #include <asm/errno.h>
 #include <asm/intrinsics.h>
@@ -63,6 +64,9 @@
 
 #define PFM_INVALID_ACTIVATION (~0UL)
 
+#define PFM_NUM_PMC_REGS       64      /* PMC save area for ctxsw */
+#define PFM_NUM_PMD_REGS       64      /* PMD save area for ctxsw */
+
 /*
  * depth of message queue
  */
@@ -287,7 +291,7 @@ typedef struct pfm_context {
 
        unsigned long           ctx_ovfl_regs[4];       /* which registers overflowed (notification) */
 
-       struct semaphore        ctx_restart_sem;        /* use for blocking notification mode */
+       struct completion       ctx_restart_done;       /* use for blocking notification mode */
 
        unsigned long           ctx_used_pmds[4];       /* bitmask of PMD used            */
        unsigned long           ctx_all_pmds[4];        /* bitmask of all accessible PMDs */
@@ -297,14 +301,17 @@ typedef struct pfm_context {
        unsigned long           ctx_reload_pmcs[4];     /* bitmask of force reload PMC on ctxsw in */
        unsigned long           ctx_used_monitors[4];   /* bitmask of monitor PMC being used */
 
-       unsigned long           ctx_pmcs[IA64_NUM_PMC_REGS];    /*  saved copies of PMC values */
+       unsigned long           ctx_pmcs[PFM_NUM_PMC_REGS];     /*  saved copies of PMC values */
 
        unsigned int            ctx_used_ibrs[1];               /* bitmask of used IBR (speedup ctxsw in) */
        unsigned int            ctx_used_dbrs[1];               /* bitmask of used DBR (speedup ctxsw in) */
        unsigned long           ctx_dbrs[IA64_NUM_DBG_REGS];    /* DBR values (cache) when not loaded */
        unsigned long           ctx_ibrs[IA64_NUM_DBG_REGS];    /* IBR values (cache) when not loaded */
 
-       pfm_counter_t           ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */
+       pfm_counter_t           ctx_pmds[PFM_NUM_PMD_REGS]; /* software state for PMDS */
+
+       unsigned long           th_pmcs[PFM_NUM_PMC_REGS];      /* PMC thread save state */
+       unsigned long           th_pmds[PFM_NUM_PMD_REGS];      /* PMD thread save state */
 
        u64                     ctx_saved_psr_up;       /* only contains psr.up value */
 
@@ -499,7 +506,7 @@ typedef struct {
 static pfm_stats_t             pfm_stats[NR_CPUS];
 static pfm_session_t           pfm_sessions;   /* global sessions information */
 
-static spinlock_t pfm_alt_install_check = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pfm_alt_install_check);
 static pfm_intr_handler_desc_t  *pfm_alt_intr_handler;
 
 static struct proc_dir_entry   *perfmon_dir;
@@ -532,7 +539,6 @@ static ctl_table pfm_sysctl_root[] = {
 static struct ctl_table_header *pfm_sysctl_header;
 
 static int pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs);
-static int pfm_flush(struct file *filp);
 
 #define pfm_get_cpu_var(v)             __ia64_per_cpu_var(v)
 #define pfm_get_cpu_data(a,b)          per_cpu(a, b)
@@ -576,7 +582,7 @@ pfm_protect_ctx_ctxsw(pfm_context_t *x)
        return 0UL;
 }
 
-static inline unsigned long
+static inline void
 pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f)
 {
        spin_unlock(&(x)->ctx_lock);
@@ -595,10 +601,11 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
 }
 
 
-static struct super_block *
-pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
+static int
+pfmfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data,
+            struct vfsmount *mnt)
 {
-       return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC);
+       return get_sb_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC, mnt);
 }
 
 static struct file_system_type pfm_fs_type = {
@@ -629,9 +636,11 @@ static int pfm_write_ibr_dbr(int mode, pfm_context_t *ctx, void *arg, int count,
 
 #include "perfmon_itanium.h"
 #include "perfmon_mckinley.h"
+#include "perfmon_montecito.h"
 #include "perfmon_generic.h"
 
 static pmu_config_t *pmu_confs[]={
+       &pmu_conf_mont,
        &pmu_conf_mck,
        &pmu_conf_ita,
        &pmu_conf_gen, /* must be last */
@@ -845,9 +854,8 @@ pfm_context_alloc(void)
         * allocate context descriptor 
         * must be able to free with interrupts disabled
         */
-       ctx = kmalloc(sizeof(pfm_context_t), GFP_KERNEL);
+       ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
        if (ctx) {
-               memset(ctx, 0, sizeof(pfm_context_t));
                DPRINT(("alloc ctx @%p\n", ctx));
        }
        return ctx;
@@ -866,7 +874,6 @@ static void
 pfm_mask_monitoring(struct task_struct *task)
 {
        pfm_context_t *ctx = PFM_GET_CTX(task);
-       struct thread_struct *th = &task->thread;
        unsigned long mask, val, ovfl_mask;
        int i;
 
@@ -887,7 +894,7 @@ pfm_mask_monitoring(struct task_struct *task)
         * So in both cases, the live register contains the owner's
         * state. We can ONLY touch the PMU registers and NOT the PSR.
         *
-        * As a consequence to this call, the thread->pmds[] array
+        * As a consequence to this call, the ctx->th_pmds[] array
         * contains stale information which must be ignored
         * when context is reloaded AND monitoring is active (see
         * pfm_restart).
@@ -922,9 +929,9 @@ pfm_mask_monitoring(struct task_struct *task)
        mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
        for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
                if ((mask & 0x1) == 0UL) continue;
-               ia64_set_pmc(i, th->pmcs[i] & ~0xfUL);
-               th->pmcs[i] &= ~0xfUL;
-               DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i]));
+               ia64_set_pmc(i, ctx->th_pmcs[i] & ~0xfUL);
+               ctx->th_pmcs[i] &= ~0xfUL;
+               DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
        }
        /*
         * make all of this visible
@@ -941,7 +948,6 @@ static void
 pfm_restore_monitoring(struct task_struct *task)
 {
        pfm_context_t *ctx = PFM_GET_CTX(task);
-       struct thread_struct *th = &task->thread;
        unsigned long mask, ovfl_mask;
        unsigned long psr, val;
        int i, is_system;
@@ -1007,9 +1013,9 @@ pfm_restore_monitoring(struct task_struct *task)
        mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
        for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
                if ((mask & 0x1) == 0UL) continue;
-               th->pmcs[i] = ctx->ctx_pmcs[i];
-               ia64_set_pmc(i, th->pmcs[i]);
-               DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i]));
+               ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
+               ia64_set_pmc(i, ctx->th_pmcs[i]);
+               DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, ctx->th_pmcs[i]));
        }
        ia64_srlz_d();
 
@@ -1068,7 +1074,6 @@ pfm_restore_pmds(unsigned long *pmds, unsigned long mask)
 static inline void
 pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
 {
-       struct thread_struct *thread = &task->thread;
        unsigned long ovfl_val = pmu_conf->ovfl_val;
        unsigned long mask = ctx->ctx_all_pmds[0];
        unsigned long val;
@@ -1090,11 +1095,11 @@ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
                        ctx->ctx_pmds[i].val = val & ~ovfl_val;
                         val &= ovfl_val;
                }
-               thread->pmds[i] = val;
+               ctx->th_pmds[i] = val;
 
                DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n",
                        i,
-                       thread->pmds[i],
+                       ctx->th_pmds[i],
                        ctx->ctx_pmds[i].val));
        }
 }
@@ -1105,7 +1110,6 @@ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
 static inline void
 pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
 {
-       struct thread_struct *thread = &task->thread;
        unsigned long mask = ctx->ctx_all_pmcs[0];
        int i;
 
@@ -1113,8 +1117,8 @@ pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
 
        for (i=0; mask; i++, mask>>=1) {
                /* masking 0 with ovfl_val yields 0 */
-               thread->pmcs[i] = ctx->ctx_pmcs[i];
-               DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i]));
+               ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
+               DPRINT(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
        }
 }
 
@@ -1711,7 +1715,7 @@ static void
 pfm_syswide_force_stop(void *info)
 {
        pfm_context_t   *ctx = (pfm_context_t *)info;
-       struct pt_regs *regs = ia64_task_regs(current);
+       struct pt_regs *regs = task_pt_regs(current);
        struct task_struct *owner;
        unsigned long flags;
        int ret;
@@ -1771,7 +1775,7 @@ pfm_syswide_cleanup_other_cpu(pfm_context_t *ctx)
  * When caller is self-monitoring, the context is unloaded.
  */
 static int
-pfm_flush(struct file *filp)
+pfm_flush(struct file *filp, fl_owner_t id)
 {
        pfm_context_t *ctx;
        struct task_struct *task;
@@ -1816,7 +1820,7 @@ pfm_flush(struct file *filp)
        is_system = ctx->ctx_fl_system;
 
        task = PFM_CTX_TASK(ctx);
-       regs = ia64_task_regs(task);
+       regs = task_pt_regs(task);
 
        DPRINT(("ctx_state=%d is_current=%d\n",
                state,
@@ -1946,7 +1950,7 @@ pfm_close(struct inode *inode, struct file *filp)
        is_system = ctx->ctx_fl_system;
 
        task = PFM_CTX_TASK(ctx);
-       regs = ia64_task_regs(task);
+       regs = task_pt_regs(task);
 
        DPRINT(("ctx_state=%d is_current=%d\n", 
                state,
@@ -1990,7 +1994,7 @@ pfm_close(struct inode *inode, struct file *filp)
                /*
                 * force task to wake up from MASKED state
                 */
-               up(&ctx->ctx_restart_sem);
+               complete(&ctx->ctx_restart_done);
 
                DPRINT(("waking up ctx_state=%d\n", state));
 
@@ -2185,13 +2189,13 @@ pfm_alloc_fd(struct file **cfile)
        /*
         * allocate a new dcache entry
         */
-       file->f_dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
-       if (!file->f_dentry) goto out;
+       file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+       if (!file->f_path.dentry) goto out;
 
-       file->f_dentry->d_op = &pfmfs_dentry_operations;
+       file->f_path.dentry->d_op = &pfmfs_dentry_operations;
 
-       d_add(file->f_dentry, inode);
-       file->f_vfsmnt = mntget(pfmfs_mnt);
+       d_add(file->f_path.dentry, inode);
+       file->f_path.mnt = mntget(pfmfs_mnt);
        file->f_mapping = inode->i_mapping;
 
        file->f_op    = &pfm_file_ops;
@@ -2220,15 +2224,18 @@ static void
 pfm_free_fd(int fd, struct file *file)
 {
        struct files_struct *files = current->files;
+       struct fdtable *fdt;
 
        /* 
         * there ie no fd_uninstall(), so we do it here
         */
        spin_lock(&files->file_lock);
-        files->fd[fd] = NULL;
+       fdt = files_fdtable(files);
+       rcu_assign_pointer(fdt->fd[fd], NULL);
        spin_unlock(&files->file_lock);
 
-       if (file) put_filp(file);
+       if (file)
+               put_filp(file);
        put_unused_fd(fd);
 }
 
@@ -2295,7 +2302,7 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon
        DPRINT(("smpl_buf @%p\n", smpl_buf));
 
        /* allocate vma */
-       vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
+       vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
        if (!vma) {
                DPRINT(("Cannot allocate vma\n"));
                goto error_kmem;
@@ -2351,7 +2358,8 @@ pfm_smpl_buffer_alloc(struct task_struct *task, pfm_context_t *ctx, unsigned lon
        insert_vm_struct(mm, vma);
 
        vx_vmpages_add(mm, size >> PAGE_SHIFT);
-       vm_stat_account(vma);
+       vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file,
+                                                       vma_pages(vma));
        up_write(&task->mm->mmap_sem);
 
        /*
@@ -2701,7 +2709,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
        /*
         * init restart semaphore to locked
         */
-       sema_init(&ctx->ctx_restart_sem, 0);
+       init_completion(&ctx->ctx_restart_done);
 
        /*
         * activation is used in SMP only
@@ -2854,7 +2862,6 @@ pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
 static int
 pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-       struct thread_struct *thread = NULL;
        struct task_struct *task;
        pfarg_reg_t *req = (pfarg_reg_t *)arg;
        unsigned long value, pmc_pm;
@@ -2875,7 +2882,6 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
        if (state == PFM_CTX_ZOMBIE) return -EINVAL;
 
        if (is_loaded) {
-               thread = &task->thread;
                /*
                 * In system wide and when the context is loaded, access can only happen
                 * when the caller is running on the CPU being monitored by the session.
@@ -3030,7 +3036,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                 *
                 * The value in ctx_pmcs[] can only be changed in pfm_write_pmcs().
                 *
-                * The value in thread->pmcs[] may be modified on overflow, i.e.,  when
+                * The value in th_pmcs[] may be modified on overflow, i.e.,  when
                 * monitoring needs to be stopped.
                 */
                if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum);
@@ -3044,7 +3050,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                        /*
                         * write thread state
                         */
-                       if (is_system == 0) thread->pmcs[cnum] = value;
+                       if (is_system == 0) ctx->th_pmcs[cnum] = value;
 
                        /*
                         * write hardware register if we can
@@ -3096,7 +3102,6 @@ error:
 static int
 pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-       struct thread_struct *thread = NULL;
        struct task_struct *task;
        pfarg_reg_t *req = (pfarg_reg_t *)arg;
        unsigned long value, hw_value, ovfl_mask;
@@ -3120,7 +3125,6 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
         * the owner of the local PMU.
         */
        if (likely(is_loaded)) {
-               thread = &task->thread;
                /*
                 * In system wide and when the context is loaded, access can only happen
                 * when the caller is running on the CPU being monitored by the session.
@@ -3228,7 +3232,7 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                        /*
                         * write thread state
                         */
-                       if (is_system == 0) thread->pmds[cnum] = hw_value;
+                       if (is_system == 0) ctx->th_pmds[cnum] = hw_value;
 
                        /*
                         * write hardware register if we can
@@ -3294,7 +3298,6 @@ abort_mission:
 static int
 pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
 {
-       struct thread_struct *thread = NULL;
        struct task_struct *task;
        unsigned long val = 0UL, lval, ovfl_mask, sval;
        pfarg_reg_t *req = (pfarg_reg_t *)arg;
@@ -3318,7 +3321,6 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
        if (state == PFM_CTX_ZOMBIE) return -EINVAL;
 
        if (likely(is_loaded)) {
-               thread = &task->thread;
                /*
                 * In system wide and when the context is loaded, access can only happen
                 * when the caller is running on the CPU being monitored by the session.
@@ -3380,7 +3382,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                         * if context is zombie, then task does not exist anymore.
                         * In this case, we use the full value saved in the context (pfm_flush_regs()).
                         */
-                       val = is_loaded ? thread->pmds[cnum] : 0UL;
+                       val = is_loaded ? ctx->th_pmds[cnum] : 0UL;
                }
                rd_func = pmu_conf->pmd_desc[cnum].read_check;
 
@@ -3682,7 +3684,7 @@ pfm_restart(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
         */
        if (CTX_OVFL_NOBLOCK(ctx) == 0 && state == PFM_CTX_MASKED) {
                DPRINT(("unblocking [%d] \n", task->pid));
-               up(&ctx->ctx_restart_sem);
+               complete(&ctx->ctx_restart_done);
        } else {
                DPRINT(("[%d] armed exit trap\n", task->pid));
 
@@ -4049,7 +4051,7 @@ pfm_stop(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                 */
                ia64_psr(regs)->up = 0;
        } else {
-               tregs = ia64_task_regs(task);
+               tregs = task_pt_regs(task);
 
                /*
                 * stop monitoring at the user level
@@ -4131,7 +4133,7 @@ pfm_start(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                ia64_psr(regs)->up = 1;
 
        } else {
-               tregs = ia64_task_regs(ctx->ctx_task);
+               tregs = task_pt_regs(ctx->ctx_task);
 
                /*
                 * start monitoring at the kernel level the next
@@ -4315,6 +4317,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
        DPRINT(("before cmpxchg() old_ctx=%p new_ctx=%p\n",
                thread->pfm_context, ctx));
 
+       ret = -EBUSY;
        old = ia64_cmpxchg(acq, &thread->pfm_context, NULL, ctx, sizeof(pfm_context_t *));
        if (old != NULL) {
                DPRINT(("load_pid [%d] already has a context\n", req->load_pid));
@@ -4348,8 +4351,8 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
        pfm_copy_pmds(task, ctx);
        pfm_copy_pmcs(task, ctx);
 
-       pmcs_source = thread->pmcs;
-       pmds_source = thread->pmds;
+       pmcs_source = ctx->th_pmcs;
+       pmds_source = ctx->th_pmds;
 
        /*
         * always the case for system-wide
@@ -4400,7 +4403,7 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
                /*
                 * when not current, task MUST be stopped, so this is safe
                 */
-               regs = ia64_task_regs(task);
+               regs = task_pt_regs(task);
 
                /* force a full reload */
                ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
@@ -4526,7 +4529,7 @@ pfm_context_unload(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
        /*
         * per-task mode
         */
-       tregs = task == current ? regs : ia64_task_regs(task);
+       tregs = task == current ? regs : task_pt_regs(task);
 
        if (task == current) {
                /*
@@ -4589,7 +4592,7 @@ pfm_exit_thread(struct task_struct *task)
 {
        pfm_context_t *ctx;
        unsigned long flags;
-       struct pt_regs *regs = ia64_task_regs(task);
+       struct pt_regs *regs = task_pt_regs(task);
        int ret, state;
        int free_ok = 0;
 
@@ -4922,7 +4925,7 @@ restart_args:
        if (unlikely(ret)) goto abort_locked;
 
 skip_fd:
-       ret = (*func)(ctx, args_k, count, ia64_task_regs(current));
+       ret = (*func)(ctx, args_k, count, task_pt_regs(current));
 
        call_made = 1;
 
@@ -4930,14 +4933,16 @@ abort_locked:
        if (likely(ctx)) {
                DPRINT(("context unlocked\n"));
                UNPROTECT_CTX(ctx, flags);
-               fput(file);
        }
 
        /* copy argument back to user, if needed */
        if (call_made && PFM_CMD_RW_ARG(cmd) && copy_to_user(arg, args_k, base_sz*count)) ret = -EFAULT;
 
 error_args:
-       if (args_k) kfree(args_k);
+       if (file)
+               fput(file);
+
+       kfree(args_k);
 
        DPRINT(("cmd=%s ret=%ld\n", PFM_CMD_NAME(cmd), ret));
 
@@ -5046,7 +5051,7 @@ pfm_handle_work(void)
 
        pfm_clear_task_notify();
 
-       regs = ia64_task_regs(current);
+       regs = task_pt_regs(current);
 
        /*
         * extract reason for being here and clear
@@ -5083,7 +5088,7 @@ pfm_handle_work(void)
         * may go through without blocking on SMP systems
         * if restart has been received already by the time we call down()
         */
-       ret = down_interruptible(&ctx->ctx_restart_sem);
+       ret = wait_for_completion_interruptible(&ctx->ctx_restart_done);
 
        DPRINT(("after block sleeping ret=%d\n", ret));
 
@@ -5553,12 +5558,13 @@ report_spurious2:
 }
 
 static irqreturn_t
-pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg)
 {
        unsigned long start_cycles, total_cycles;
        unsigned long min, max;
        int this_cpu;
        int ret;
+       struct pt_regs *regs = get_irq_regs();
 
        this_cpu = get_cpu();
        if (likely(!pfm_alt_intr_handler)) {
@@ -5790,7 +5796,7 @@ pfm_syst_wide_update_task(struct task_struct *task, unsigned long info, int is_c
         * on every CPU, so we can rely on the pid to identify the idle task.
         */
        if ((info & PFM_CPUINFO_EXCL_IDLE) == 0 || task->pid) {
-               regs = ia64_task_regs(task);
+               regs = task_pt_regs(task);
                ia64_psr(regs)->pp = is_ctxswin ? dcr_pp : 0;
                return;
        }
@@ -5856,14 +5862,12 @@ void
 pfm_save_regs(struct task_struct *task)
 {
        pfm_context_t *ctx;
-       struct thread_struct *t;
        unsigned long flags;
        u64 psr;
 
 
        ctx = PFM_GET_CTX(task);
        if (ctx == NULL) return;
-       t = &task->thread;
 
        /*
         * we always come here with interrupts ALREADY disabled by
@@ -5873,7 +5877,7 @@ pfm_save_regs(struct task_struct *task)
        flags = pfm_protect_ctx_ctxsw(ctx);
 
        if (ctx->ctx_state == PFM_CTX_ZOMBIE) {
-               struct pt_regs *regs = ia64_task_regs(task);
+               struct pt_regs *regs = task_pt_regs(task);
 
                pfm_clear_psr_up();
 
@@ -5921,19 +5925,19 @@ pfm_save_regs(struct task_struct *task)
         * guarantee we will be schedule at that same
         * CPU again.
         */
-       pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
+       pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
 
        /*
         * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
         * we will need it on the restore path to check
         * for pending overflow.
         */
-       t->pmcs[0] = ia64_get_pmc(0);
+       ctx->th_pmcs[0] = ia64_get_pmc(0);
 
        /*
         * unfreeze PMU if had pending overflows
         */
-       if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+       if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
 
        /*
         * finally, allow context access.
@@ -5978,7 +5982,6 @@ static void
 pfm_lazy_save_regs (struct task_struct *task)
 {
        pfm_context_t *ctx;
-       struct thread_struct *t;
        unsigned long flags;
 
        { u64 psr  = pfm_get_psr();
@@ -5986,7 +5989,6 @@ pfm_lazy_save_regs (struct task_struct *task)
        }
 
        ctx = PFM_GET_CTX(task);
-       t   = &task->thread;
 
        /*
         * we need to mask PMU overflow here to
@@ -6011,19 +6013,19 @@ pfm_lazy_save_regs (struct task_struct *task)
        /*
         * save all the pmds we use
         */
-       pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
+       pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
 
        /*
         * save pmc0 ia64_srlz_d() done in pfm_save_pmds()
         * it is needed to check for pended overflow
         * on the restore path
         */
-       t->pmcs[0] = ia64_get_pmc(0);
+       ctx->th_pmcs[0] = ia64_get_pmc(0);
 
        /*
         * unfreeze PMU if had pending overflows
         */
-       if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+       if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
 
        /*
         * now get can unmask PMU interrupts, they will
@@ -6042,7 +6044,6 @@ void
 pfm_load_regs (struct task_struct *task)
 {
        pfm_context_t *ctx;
-       struct thread_struct *t;
        unsigned long pmc_mask = 0UL, pmd_mask = 0UL;
        unsigned long flags;
        u64 psr, psr_up;
@@ -6053,11 +6054,10 @@ pfm_load_regs (struct task_struct *task)
 
        BUG_ON(GET_PMU_OWNER());
 
-       t     = &task->thread;
        /*
         * possible on unload
         */
-       if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) return;
+       if (unlikely((task->thread.flags & IA64_THREAD_PM_VALID) == 0)) return;
 
        /*
         * we always come here with interrupts ALREADY disabled by
@@ -6073,7 +6073,7 @@ pfm_load_regs (struct task_struct *task)
        BUG_ON(psr & IA64_PSR_I);
 
        if (unlikely(ctx->ctx_state == PFM_CTX_ZOMBIE)) {
-               struct pt_regs *regs = ia64_task_regs(task);
+               struct pt_regs *regs = task_pt_regs(task);
 
                BUG_ON(ctx->ctx_smpl_hdr);
 
@@ -6139,26 +6139,26 @@ pfm_load_regs (struct task_struct *task)
         *
         * XXX: optimize here
         */
-       if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask);
-       if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask);
+       if (pmd_mask) pfm_restore_pmds(ctx->th_pmds, pmd_mask);
+       if (pmc_mask) pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
 
        /*
         * check for pending overflow at the time the state
         * was saved.
         */
-       if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
+       if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
                /*
                 * reload pmc0 with the overflow information
                 * On McKinley PMU, this will trigger a PMU interrupt
                 */
-               ia64_set_pmc(0, t->pmcs[0]);
+               ia64_set_pmc(0, ctx->th_pmcs[0]);
                ia64_srlz_d();
-               t->pmcs[0] = 0UL;
+               ctx->th_pmcs[0] = 0UL;
 
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
@@ -6206,7 +6206,6 @@ pfm_load_regs (struct task_struct *task)
 void
 pfm_load_regs (struct task_struct *task)
 {
-       struct thread_struct *t;
        pfm_context_t *ctx;
        struct task_struct *owner;
        unsigned long pmd_mask, pmc_mask;
@@ -6215,7 +6214,6 @@ pfm_load_regs (struct task_struct *task)
 
        owner = GET_PMU_OWNER();
        ctx   = PFM_GET_CTX(task);
-       t     = &task->thread;
        psr   = pfm_get_psr();
 
        BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
@@ -6278,27 +6276,27 @@ pfm_load_regs (struct task_struct *task)
         */
        pmc_mask = ctx->ctx_all_pmcs[0];
 
-       pfm_restore_pmds(t->pmds, pmd_mask);
-       pfm_restore_pmcs(t->pmcs, pmc_mask);
+       pfm_restore_pmds(ctx->th_pmds, pmd_mask);
+       pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
 
        /*
         * check for pending overflow at the time the state
         * was saved.
         */
-       if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
+       if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
                /*
                 * reload pmc0 with the overflow information
                 * On McKinley PMU, this will trigger a PMU interrupt
                 */
-               ia64_set_pmc(0, t->pmcs[0]);
+               ia64_set_pmc(0, ctx->th_pmcs[0]);
                ia64_srlz_d();
 
-               t->pmcs[0] = 0UL;
+               ctx->th_pmcs[0] = 0UL;
 
                /*
                 * will replay the PMU interrupt
                 */
-               if (need_irq_resend) hw_resend_irq(NULL, IA64_PERFMON_VECTOR);
+               if (need_irq_resend) ia64_resend_irq(IA64_PERFMON_VECTOR);
 
                pfm_stats[smp_processor_id()].pfm_replay_ovfl_intr_count++;
        }
@@ -6368,11 +6366,11 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
                 */
                pfm_unfreeze_pmu();
        } else {
-               pmc0 = task->thread.pmcs[0];
+               pmc0 = ctx->th_pmcs[0];
                /*
                 * clear whatever overflow status bits there were
                 */
-               task->thread.pmcs[0] = 0;
+               ctx->th_pmcs[0] = 0;
        }
        ovfl_val = pmu_conf->ovfl_val;
        /*
@@ -6393,7 +6391,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
                /*
                 * can access PMU always true in system wide mode
                 */
-               val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i];
+               val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : ctx->th_pmds[i];
 
                if (PMD_IS_COUNTING(i)) {
                        DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n",
@@ -6425,7 +6423,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
 
                DPRINT(("[%d] ctx_pmd[%d]=0x%lx  pmd_val=0x%lx\n", task->pid, i, val, pmd_val));
 
-               if (is_self) task->thread.pmds[i] = pmd_val;
+               if (is_self) ctx->th_pmds[i] = pmd_val;
 
                ctx->ctx_pmds[i].val = val;
        }
@@ -6433,7 +6431,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
 
 static struct irqaction perfmon_irqaction = {
        .handler = pfm_interrupt_handler,
-       .flags   = SA_INTERRUPT,
+       .flags   = IRQF_DISABLED,
        .name    = "perfmon"
 };
 
@@ -6442,7 +6440,7 @@ pfm_alt_save_pmu_state(void *data)
 {
        struct pt_regs *regs;
 
-       regs = ia64_task_regs(current);
+       regs = task_pt_regs(current);
 
        DPRINT(("called\n"));
 
@@ -6468,7 +6466,7 @@ pfm_alt_restore_pmu_state(void *data)
 {
        struct pt_regs *regs;
 
-       regs = ia64_task_regs(current);
+       regs = task_pt_regs(current);
 
        DPRINT(("called\n"));
 
@@ -6669,7 +6667,7 @@ pfm_init(void)
               ffz(pmu_conf->ovfl_val));
 
        /* sanity check */
-       if (pmu_conf->num_pmds >= IA64_NUM_PMD_REGS || pmu_conf->num_pmcs >= IA64_NUM_PMC_REGS) {
+       if (pmu_conf->num_pmds >= PFM_NUM_PMD_REGS || pmu_conf->num_pmcs >= PFM_NUM_PMC_REGS) {
                printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
                pmu_conf = NULL;
                return -1;
@@ -6715,6 +6713,7 @@ __initcall(pfm_init);
 void
 pfm_init_percpu (void)
 {
+       static int first_time=1;
        /*
         * make sure no measurement is active
         * (may inherit programmed PMCs from EFI).
@@ -6727,8 +6726,10 @@ pfm_init_percpu (void)
         */
        pfm_unfreeze_pmu();
 
-       if (smp_processor_id() == 0)
+       if (first_time) {
                register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
+               first_time=0;
+       }
 
        ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR);
        ia64_srlz_d();
@@ -6741,7 +6742,6 @@ void
 dump_pmu_state(const char *from)
 {
        struct task_struct *task;
-       struct thread_struct *t;
        struct pt_regs *regs;
        pfm_context_t *ctx;
        unsigned long psr, dcr, info, flags;
@@ -6750,7 +6750,7 @@ dump_pmu_state(const char *from)
        local_irq_save(flags);
 
        this_cpu = smp_processor_id();
-       regs     = ia64_task_regs(current);
+       regs     = task_pt_regs(current);
        info     = PFM_CPUINFO_GET();
        dcr      = ia64_getreg(_IA64_REG_CR_DCR);
 
@@ -6786,16 +6786,14 @@ dump_pmu_state(const char *from)
        ia64_psr(regs)->up = 0;
        ia64_psr(regs)->pp = 0;
 
-       t = &current->thread;
-
        for (i=1; PMC_IS_LAST(i) == 0; i++) {
                if (PMC_IS_IMPL(i) == 0) continue;
-               printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, t->pmcs[i]);
+               printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, ctx->th_pmcs[i]);
        }
 
        for (i=1; PMD_IS_LAST(i) == 0; i++) {
                if (PMD_IS_IMPL(i) == 0) continue;
-               printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, t->pmds[i]);
+               printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, ctx->th_pmds[i]);
        }
 
        if (ctx) {