--- /dev/null
+diff --git a/Documentation/ABI/testing/sysfs-perfmon b/Documentation/ABI/testing/sysfs-perfmon
+new file mode 100644
+index 0000000..bde434c
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-perfmon
+@@ -0,0 +1,87 @@
++What: /sys/kernel/perfmon
++Date: Nov 2007
++KernelVersion: 2.6.24
++Contact: eranian@gmail.com
++
++Description: provide the configuration interface for the perfmon2 subsystems.
++ The tree contains information about the detected hardware, current
++ state of the subsystem as well as some configuration parameters.
++
++ The tree consists of the following entries:
++
++ /sys/kernel/perfmon/debug (read-write):
++
++ Enable perfmon2 debugging output via klogd. Debug messages produced during
++ PMU interrupt handling are not controlled by this entry. The traces a rate-limited
++ to avoid flooding of the console. It is possible to change the throttling
++ via /proc/sys/kernel/printk_ratelimit. The value is interpreted as a bitmask.
++ Each bit enables a particular type of debug messages. Refer to the file
++ include/linux/perfmon_kern.h for more information
++
++ /sys/kernel/perfmon/pmc_max_fast_arg (read-only):
++
++ Number of perfmon2 syscall arguments copied directly onto the
++ stack (copy_from_user) for pfm_write_pmcs(). Copying to the stack avoids
++ having to allocate a buffer. The unit is the number of pfarg_pmc_t
++ structures.
++
++ /sys/kernel/perfmon/pmd_max_fast_arg (read-only):
++
++ Number of perfmon2 syscall arguments copied directly onto the
++ stack (copy_from_user) for pfm_write_pmds()/pfm_read_pmds(). Copying
++ to the stack avoids having to allocate a buffer. The unit is the number
++ of pfarg_pmd_t structures.
++
++
++ /sys/kernel/perfmon/reset_stats (write-only):
++
++ Reset the statistics collected by perfmon2. Stats are available
++ per-cpu via debugfs.
++
++ /sys/kernel/perfmon/smpl_buffer_mem_cur (read-only):
++
++ Reports the amount of memory currently dedicated to sampling
++ buffers by the kernel. The unit is byte.
++
++ /sys/kernel/perfmon/smpl_buffer_mem_max (read-write):
++
++ Maximum amount of kernel memory usable for sampling buffers. -1 means
++ everything that is available. Unit is byte.
++
++ /sys/kernel/perfmon/smpl_buffer_mem_cur (read-only):
++
++ Current utilization of kernel memory in bytes.
++
++ /sys/kernel/perfmon/sys_group (read-write):
++
++ Users group allowed to create a system-wide perfmon2 context (session).
++ -1 means any group. This control will be kept until we find a package
++ able to control capabilities via PAM.
++
++ /sys/kernel/perfmon/task_group (read-write):
++
++ Users group allowed to create a per-thread context (session).
++ -1 means any group. This control will be kept until we find a
++ package able to control capabilities via PAM.
++
++ /sys/kernel/perfmon/sys_sessions_count (read-only):
++
++ Number of system-wide contexts currently attached to CPUs.
++
++ /sys/kernel/perfmon/task_sessions_count (read-only):
++
++ Number of per-thread contexts currently attached to threads.
++
++ /sys/kernel/perfmon/version (read-only):
++
++ Perfmon2 interface revision number.
++
++ /sys/kernel/perfmon/arg_mem_max(read-write):
++
++ Maximum size of vector arguments expressed in bytes. Can be modified
++
++ /sys/kernel/perfmon/mode(read-write):
++
++ Bitmask to enable/disable certain perfmon2 features.
++ Currently defined:
++ - bit 0: if set, then reserved bitfield are ignored on PMC writes
+diff --git a/Documentation/ABI/testing/sysfs-perfmon-fmt b/Documentation/ABI/testing/sysfs-perfmon-fmt
+new file mode 100644
+index 0000000..1b45270
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-perfmon-fmt
+@@ -0,0 +1,18 @@
++What: /sys/kernel/perfmon/formats
++Date: 2007
++KernelVersion: 2.6.24
++Contact: eranian@gmail.com
++
++Description: provide description of available perfmon2 custom sampling buffer formats
++ which are implemented as independent kernel modules. Each formats gets
++ a subdir which a few entries.
++
++ The name of the subdir is the name of the sampling format. The same name
++ must be passed to pfm_create_context() to use the format.
++
++ Each subdir XX contains the following entries:
++
++ /sys/kernel/perfmon/formats/XX/version (read-only):
++
++ Version number of the format in clear text and null terminated.
++
+diff --git a/Documentation/ABI/testing/sysfs-perfmon-pmu b/Documentation/ABI/testing/sysfs-perfmon-pmu
+new file mode 100644
+index 0000000..a1afc7e
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-perfmon-pmu
+@@ -0,0 +1,46 @@
++What: /sys/kernel/perfmon/pmu
++Date: Nov 2007
++KernelVersion: 2.6.24
++Contact: eranian@gmail.com
++
++Description: provide information about the currently loaded PMU description module.
++ The module contains the mapping of the actual performance counter registers
++ onto the logical PMU exposed by perfmon. There is at most one PMU description
++ module loaded at any time.
++
++ The sysfs PMU tree provides a description of the mapping for each register.
++ There is one subdir per config and data registers along an entry for the
++ name of the PMU model.
++
++ The model entry is as follows:
++
++ /sys/kernel/perfmon/pmu_desc/model (read-only):
++
++ Name of the PMU model is clear text and zero terminated.
++
++ Then for each logical PMU register, XX, gets a subtree with the following entries:
++
++ /sys/kernel/perfmon/pmu_desc/pm*XX/addr (read-only):
++
++ The physical address or index of the actual underlying hardware register.
++ On Itanium, it corresponds to the index. But on X86 processor, this is
++ the actual MSR address.
++
++ /sys/kernel/perfmon/pmu_desc/pm*XX/dfl_val (read-only):
++
++ The default value of the register in hexadecimal.
++
++ /sys/kernel/perfmon/pmu_desc/pm*XX/name (read-only):
++
++ The name of the hardware register.
++
++ /sys/kernel/perfmon/pmu_desc/pm*XX/rsvd_msk (read-only):
++
++ The bitmask of reserved bits, i.e., bits which cannot be changed by
++ applications. When a bit is set, it means the corresponding bit in the
++ actual register is reserved.
++
++ /sys/kernel/perfmon/pmu_desc/pm*XX/width (read-only):
++
++ the width in bits of the registers. This field is only relevant for counter
++ registers.
+diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
+index 1150444..2652b6c 100644
+--- a/Documentation/kernel-parameters.txt
++++ b/Documentation/kernel-parameters.txt
+@@ -1643,6 +1643,9 @@ and is between 256 and 4096 characters. It is defined in the file
+ Format: { 0 | 1 }
+ See arch/parisc/kernel/pdc_chassis.c
+
++ perfmon_debug [PERFMON] Enables Perfmon debug messages. Needed
++ to see traces of the early startup startup phase.
++
+ pf. [PARIDE]
+ See Documentation/paride.txt.
+
+diff --git a/Documentation/perfmon2-debugfs.txt b/Documentation/perfmon2-debugfs.txt
+new file mode 100644
+index 0000000..b30cae8
+--- /dev/null
++++ b/Documentation/perfmon2-debugfs.txt
+@@ -0,0 +1,126 @@
++ The perfmon2 debug and statistics interface
++ ------------------------------------------
++ Stephane Eranian
++ <eranian@gmail.com>
++
++The perfmon2 interfaces exports a set of statistics which are used to tune and
++debug the implementation. The data is composed of a set of very simple metrics
++mostly aggregated counts and durations. They instruments key points in the
++perfmon2 code, such as context switch and interrupt handling.
++
++The data is accessible via the debug filesystem (debugfs). Thus you need to
++have the filesystem support enabled in your kernel. Furthermore since, 2.6.25,
++the perfmon2 statistics interface is an optional component. It needs to be
++explicitely enabled in the kernel config file (CONFIG_PERFMON_DEBUG_FS).
++
++To access the data, the debugs filesystem must be mounted. Supposing the mount
++point is /debugfs, you would need to do:
++ $ mount -t debugs none /debugfs
++
++The data is located under the perfmon subdirectory and is organized per CPU.
++For each CPU, the same set of metrics is available, one metric per file in
++clear ASCII text.
++
++The metrics are as follows:
++
++ ctxswin_count (read-only):
++
++ Number of PMU context switch in.
++
++ ctxswin_ns (read-only):
++
++ Number of nanoseconds spent in the PMU context switch in
++ routine. Dividing this number by the value of ctxswin_count,
++ yields average cost of the PMU context switch in.
++
++ ctxswout_count (read-only):
++
++ Number of PMU context switch out.
++
++ ctxswout_ns (read-only):
++
++ Number of nanoseconds spent in the PMU context switch in
++ routine. Dividing this number by the value of ctxswout_count,
++ yields average cost of the PMU context switch out.
++
++ fmt_handler_calls (read-only):
++
++ Number of calls to the sampling format routine that handles
++ PMU interrupts, i.e., typically the routine that records a
++ sample.
++
++ fmt_handler_ns (read-only):
++
++ Number of nanoseconds spent in the routine that handle PMU
++ interrupt in the sampling format. Dividing this number by
++ the number of calls provided by fmt_handler_calls, yields
++ average time spent in this routine.
++
++ ovfl_intr_all_count (read-only):
++
++ Number of PMU interrupts received by the kernel.
++
++
++ ovfl_intr_nmi_count (read-only):
++
++ Number of Non Maskeable Interrupts (NMI) received by the kernel
++ for perfmon. This is relevant only on X86 hardware.
++
++ ovfl_intr_ns (read-only):
++
++ Number of nanoseconds spent in the perfmon2 PMU interrupt
++ handler routine. Dividing this number of ovfl_intr_all_count
++ yields the average time to handle one PMU interrupt.
++
++ ovfl_intr_regular_count (read-only):
++
++ Number of PMU interrupts which are actually processed by
++ the perfmon interrupt handler. There may be spurious or replay
++ interrupts.
++
++ ovfl_intr_replay_count (read-only):
++
++ Number of PMU interrupts which were replayed on context switch
++ in or on event set switching. Interrupts get replayed when they
++ were in flight at the time monitoring had to be stopped.
++
++ perfmon/ovfl_intr_spurious_count (read-only):
++
++ Number of PMU interrupts which were dropped because there was
++ no active context (session).
++
++ ovfl_notify_count (read-only):
++
++ Number of user level notifications sent. Notifications are
++ appended as messages to the context queue. Notifications may
++ be sent on PMU interrupts.
++
++ pfm_restart_count (read-only):
++
++ Number of times pfm_restart() is called.
++
++ reset_pmds_count (read-only):
++
++ Number of times pfm_reset_pmds() is called.
++
++ set_switch_count (read-only):
++
++ Number of event set switches.
++
++ set_switch_ns (read-only):
++
++ Number of nanoseconds spent in the set switching routine.
++ Dividing this number by set_switch_count yields the average
++ cost of switching sets.
++
++ handle_timeout_count (read-only):
++
++ Number of times the pfm_handle_timeout() routine is called.
++ It is used for timeout-based set switching.
++
++ handle_work_count (read-only):
++
++ Number of times pfm_handle_work() is called. The routine
++ handles asynchronous perfmon2 work for per-thread contexts
++ (sessions).
++
+diff --git a/Documentation/perfmon2.txt b/Documentation/perfmon2.txt
+new file mode 100644
+index 0000000..4a8fada
+--- /dev/null
++++ b/Documentation/perfmon2.txt
+@@ -0,0 +1,213 @@
++ The perfmon2 hardware monitoring interface
++ ------------------------------------------
++ Stephane Eranian
++ <eranian@gmail.com>
++
++I/ Introduction
++
++ The perfmon2 interface provides access to the hardware performance counters of
++ major processors. Nowadays, all processors implement some flavors of performance
++ counters which capture micro-architectural level information such as the number
++ of elapsed cycles, number of cache misses, and so on.
++
++ The interface is implemented as a set of new system calls and a set of config files
++ in /sys.
++
++ It is possible to monitoring a single thread or a CPU. In either mode, applications
++ can count or collect samples. System-wide monitoring is supported by running a
++ monitoring session on each CPU. The interface support event-based sampling where the
++ sampling period is expressed as the number of occurrences of event, instead of just a
++ timeout. This approach provides a much better granularity and flexibility.
++
++ For performance reason, it is possible to use a kernel-level sampling buffer to minimize
++ the overhead incurred by sampling. The format of the buffer, i.e., what is recorded, how
++ it is recorded, and how it is exported to user-land is controlled by a kernel module called
++ a custom sampling format. The current implementation comes with a default format but
++ it is possible to create additional formats. There is an in-kernel registration
++ interface for formats. Each format is identified by a simple string which a tool
++ can pass when a monitoring session is created.
++
++ The interface also provides support for event set and multiplexing to work around
++ hardware limitations in the number of available counters or in how events can be
++ combined. Each set defines as many counters as the hardware can support. The kernel
++ then multiplexes the sets. The interface supports time-base switching but also
++ overflow based switching, i.e., after n overflows of designated counters.
++
++ Applications never manipulates the actual performance counter registers. Instead they see
++ a logical Performance Monitoring Unit (PMU) composed of a set of config register (PMC)
++ and a set of data registers (PMD). Note that PMD are not necessarily counters, they
++ can be buffers. The logical PMU is then mapped onto the actual PMU using a mapping
++ table which is implemented as a kernel module. The mapping is chosen once for each
++ new processor. It is visible in /sys/kernel/perfmon/pmu_desc. The kernel module
++ is automatically loaded on first use.
++
++ A monitoring session, or context, is uniquely identified by a file descriptor
++ obtained when the context is created. File sharing semantics apply to access
++ the context inside a process. A context is never inherited across fork. The file
++ descriptor can be used to received counter overflow notifications or when the
++ sampling buffer is full. It is possible to use poll/select on the descriptor
++ to wait for notifications from multiplex contexts. Similarly, the descriptor
++ supports asynchronous notification via SIGIO.
++
++ Counters are always exported as being 64-bit wide regardless of what the underlying
++ hardware implements.
++
++II/ Kernel compilation
++
++ To enable perfmon2, you need to enable CONFIG_PERFMON
++
++III/ OProfile interactions
++
++ The set of features offered by perfmon2 is rich enough to support migrating
++ Oprofile on top of it. That means that PMU programming and low-level interrupt
++ handling could be done by perfmon2. The Oprofile sampling buffer management code
++ in the kernel as well as how samples are exported to users could remain through
++ the use of a custom sampling buffer format. This is how Oprofile work on Itanium.
++
++ The current interactions with Oprofile are:
++ - on X86: Both subsystems can be compiled into the same kernel. There is enforced
++ mutual exclusion between the two subsystems. When there is an Oprofile
++ session, no perfmon2 session can exist and vice-versa. Perfmon2 session
++ encapsulates both per-thread and system-wide sessions here.
++
++ - On IA-64: Oprofile works on top of perfmon2. Oprofile being a system-wide monitoring
++ tool, the regular per-thread vs. system-wide session restrictions apply.
++
++ - on PPC: no integration yet. You need to enable/disble one of the two subsystems
++ - on MIPS: no integration yet. You need to enable/disble one of the two subsystems
++
++IV/ User tools
++
++ We have released a simple monitoring tool to demonstrate the feature of the
++ interface. The tool is called pfmon and it comes with a simple helper library
++ called libpfm. The library comes with a set of examples to show how to use the
++ kernel perfmon2 interface. Visit http://perfmon2.sf.net for details.
++
++ There maybe other tools available for perfmon2.
++
++V/ How to program?
++
++ The best way to learn how to program perfmon2, is to take a look at the source
++ code for the examples in libpfm. The source code is available from:
++ http://perfmon2.sf.net
++
++VI/ System calls overview
++
++ The interface is implemented by the following system calls:
++
++ * int pfm_create_context(pfarg_ctx_t *ctx, char *fmt, void *arg, size_t arg_size)
++
++ This function create a perfmon2 context. The type of context is per-thread by
++ default unless PFM_FL_SYSTEM_WIDE is passed in ctx. The sampling format name
++ is passed in fmt. Arguments to the format are passed in arg which is of size
++ arg_size. Upon successful return, the file descriptor identifying the context
++ is returned.
++
++ * int pfm_write_pmds(int fd, pfarg_pmd_t *pmds, int n)
++
++ This function is used to program the PMD registers. It is possible to pass
++ vectors of PMDs.
++
++ * int pfm_write_pmcs(int fd, pfarg_pmc_t *pmds, int n)
++
++ This function is used to program the PMC registers. It is possible to pass
++ vectors of PMDs.
++
++ * int pfm_read_pmds(int fd, pfarg_pmd_t *pmds, int n)
++
++ This function is used to read the PMD registers. It is possible to pass
++ vectors of PMDs.
++
++ * int pfm_load_context(int fd, pfarg_load_t *load)
++
++ This function is used to attach the context to a thread or CPU.
++ Thread means kernel-visible thread (NPTL). The thread identification
++ as obtained by gettid must be passed to load->load_target.
++
++ To operate on another thread (not self), it is mandatory that the thread
++ be stopped via ptrace().
++
++ To attach to a CPU, the CPU number must be specified in load->load_target
++ AND the call must be issued on that CPU. To monitor a CPU, a thread MUST
++ be pinned on that CPU.
++
++ Until the context is attached, the actual counters are not accessed.
++
++ * int pfm_unload_context(int fd)
++
++ The context is detached for the thread or CPU is was attached to.
++ As a consequence monitoring is stopped.
++
++ When monitoring another thread, the thread MUST be stopped via ptrace()
++ for this function to succeed.
++
++ * int pfm_start(int fd, pfarg_start_t *st)
++
++ Start monitoring. The context must be attached for this function to succeed.
++ Optionally, it is possible to specify the event set on which to start using the
++ st argument, otherwise just pass NULL.
++
++ When monitoring another thread, the thread MUST be stopped via ptrace()
++ for this function to succeed.
++
++ * int pfm_stop(int fd)
++
++ Stop monitoring. The context must be attached for this function to succeed.
++
++ When monitoring another thread, the thread MUST be stopped via ptrace()
++ for this function to succeed.
++
++
++ * int pfm_create_evtsets(int fd, pfarg_setdesc_t *sets, int n)
++
++ This function is used to create or change event sets. By default set 0 exists.
++ It is possible to create/change multiple sets in one call.
++
++ The context must be detached for this call to succeed.
++
++ Sets are identified by a 16-bit integer. They are sorted based on this
++ set and switching occurs in a round-robin fashion.
++
++ * int pfm_delete_evtsets(int fd, pfarg_setdesc_t *sets, int n)
++
++ Delete event sets. The context must be detached for this call to succeed.
++
++
++ * int pfm_getinfo_evtsets(int fd, pfarg_setinfo_t *sets, int n)
++
++ Retrieve information about event sets. In particular it is possible
++ to get the number of activation of a set. It is possible to retrieve
++ information about multiple sets in one call.
++
++
++ * int pfm_restart(int fd)
++
++ Indicate to the kernel that the application is done processing an overflow
++ notification. A consequence of this call could be that monitoring resumes.
++
++ * int read(fd, pfm_msg_t *msg, sizeof(pfm_msg_t))
++
++ the regular read() system call can be used with the context file descriptor to
++ receive overflow notification messages. Non-blocking read() is supported.
++
++ Each message carry information about the overflow such as which counter overflowed
++ and where the program was (interrupted instruction pointer).
++
++ * int close(int fd)
++
++ To destroy a context, the regular close() system call is used.
++
++
++VII/ /sys interface overview
++
++ Refer to Documentation/ABI/testing/sysfs-perfmon-* for a detailed description
++ of the sysfs interface of perfmon2.
++
++VIII/ debugfs interface overview
++
++ Refer to Documentation/perfmon2-debugfs.txt for a detailed description of the
++ debug and statistics interface of perfmon2.
++
++IX/ Documentation
++
++ Visit http://perfmon2.sf.net
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 8dae455..fb38c2a 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -3239,6 +3239,14 @@ M: balbir@linux.vnet.ibm.com
+ L: linux-kernel@vger.kernel.org
+ S: Maintained
+
++PERFMON SUBSYSTEM
++P: Stephane Eranian
++M: eranian@gmail.com
++L: perfmon2-devel@lists.sf.net
++W: http://perfmon2.sf.net
++T: git kernel.org:/pub/scm/linux/kernel/git/eranian/linux-2.6
++S: Maintained
++
+ PERSONALITY HANDLING
+ P: Christoph Hellwig
+ M: hch@infradead.org
+diff --git a/Makefile b/Makefile
+index 16e3fbb..7bb1320 100644
+--- a/Makefile
++++ b/Makefile
+@@ -620,6 +620,7 @@ export mod_strip_cmd
+
+ ifeq ($(KBUILD_EXTMOD),)
+ core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
++core-$(CONFIG_PERFMON) += perfmon/
+
+ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \
+ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \
+diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
+index 48e496f..1d79b01 100644
+--- a/arch/ia64/Kconfig
++++ b/arch/ia64/Kconfig
+@@ -470,14 +470,6 @@ config COMPAT_FOR_U64_ALIGNMENT
+ config IA64_MCA_RECOVERY
+ tristate "MCA recovery from errors other than TLB."
+
+-config PERFMON
+- bool "Performance monitor support"
+- help
+- Selects whether support for the IA-64 performance monitor hardware
+- is included in the kernel. This makes some kernel data-structures a
+- little bigger and slows down execution a bit, but it is generally
+- a good idea to turn this on. If you're unsure, say Y.
+-
+ config IA64_PALINFO
+ tristate "/proc/pal support"
+ help
+@@ -549,6 +541,8 @@ source "drivers/firmware/Kconfig"
+
+ source "fs/Kconfig.binfmt"
+
++source "arch/ia64/perfmon/Kconfig"
++
+ endmenu
+
+ menu "Power management and ACPI"
+diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile
+index 905d25b..9aa622d 100644
+--- a/arch/ia64/Makefile
++++ b/arch/ia64/Makefile
+@@ -57,6 +57,7 @@ core-$(CONFIG_IA64_GENERIC) += arch/ia64/dig/
+ core-$(CONFIG_IA64_HP_ZX1) += arch/ia64/dig/
+ core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
+ core-$(CONFIG_IA64_SGI_SN2) += arch/ia64/sn/
++core-$(CONFIG_PERFMON) += arch/ia64/perfmon/
+ core-$(CONFIG_IA64_SGI_UV) += arch/ia64/uv/
+ core-$(CONFIG_KVM) += arch/ia64/kvm/
+
+diff --git a/arch/ia64/configs/generic_defconfig b/arch/ia64/configs/generic_defconfig
+index 9f48397..ff9572a 100644
+--- a/arch/ia64/configs/generic_defconfig
++++ b/arch/ia64/configs/generic_defconfig
+@@ -209,7 +209,6 @@ CONFIG_IA32_SUPPORT=y
+ CONFIG_COMPAT=y
+ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
+ CONFIG_IA64_MCA_RECOVERY=y
+-CONFIG_PERFMON=y
+ CONFIG_IA64_PALINFO=y
+ # CONFIG_IA64_MC_ERR_INJECT is not set
+ CONFIG_SGI_SN=y
+@@ -234,6 +233,16 @@ CONFIG_BINFMT_ELF=y
+ CONFIG_BINFMT_MISC=m
+
+ #
++# Hardware Performance Monitoring support
++#
++CONFIG_PERFMON=y
++CONFIG_IA64_PERFMON_COMPAT=y
++CONFIG_IA64_PERFMON_GENERIC=m
++CONFIG_IA64_PERFMON_ITANIUM=y
++CONFIG_IA64_PERFMON_MCKINLEY=y
++CONFIG_IA64_PERFMON_MONTECITO=y
++
++#
+ # Power management and ACPI
+ #
+ CONFIG_PM=y
+diff --git a/arch/ia64/include/asm/Kbuild b/arch/ia64/include/asm/Kbuild
+index ccbe8ae..cf64b3b 100644
+--- a/arch/ia64/include/asm/Kbuild
++++ b/arch/ia64/include/asm/Kbuild
+@@ -5,10 +5,12 @@ header-y += fpu.h
+ header-y += fpswa.h
+ header-y += ia64regs.h
+ header-y += intel_intrin.h
+-header-y += perfmon_default_smpl.h
+ header-y += ptrace_offsets.h
+ header-y += rse.h
+ header-y += ucontext.h
++header-y += perfmon.h
++header-y += perfmon_compat.h
++header-y += perfmon_default_smpl.h
+
+ unifdef-y += gcc_intrin.h
+ unifdef-y += intrinsics.h
+diff --git a/arch/ia64/include/asm/hw_irq.h b/arch/ia64/include/asm/hw_irq.h
+index 5c99cbc..4a45cb0 100644
+--- a/arch/ia64/include/asm/hw_irq.h
++++ b/arch/ia64/include/asm/hw_irq.h
+@@ -67,9 +67,9 @@ extern int ia64_last_device_vector;
+ #define IA64_NUM_DEVICE_VECTORS (IA64_LAST_DEVICE_VECTOR - IA64_FIRST_DEVICE_VECTOR + 1)
+
+ #define IA64_MCA_RENDEZ_VECTOR 0xe8 /* MCA rendez interrupt */
+-#define IA64_PERFMON_VECTOR 0xee /* performance monitor interrupt vector */
+ #define IA64_TIMER_VECTOR 0xef /* use highest-prio group 15 interrupt for timer */
+ #define IA64_MCA_WAKEUP_VECTOR 0xf0 /* MCA wakeup (must be >MCA_RENDEZ_VECTOR) */
++#define IA64_PERFMON_VECTOR 0xf1 /* performance monitor interrupt vector */
+ #define IA64_IPI_LOCAL_TLB_FLUSH 0xfc /* SMP flush local TLB */
+ #define IA64_IPI_RESCHEDULE 0xfd /* SMP reschedule */
+ #define IA64_IPI_VECTOR 0xfe /* inter-processor interrupt vector */
+diff --git a/arch/ia64/include/asm/perfmon.h b/arch/ia64/include/asm/perfmon.h
+index 7f3333d..150c4b4 100644
+--- a/arch/ia64/include/asm/perfmon.h
++++ b/arch/ia64/include/asm/perfmon.h
+@@ -1,279 +1,59 @@
+ /*
+- * Copyright (C) 2001-2003 Hewlett-Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
+- */
+-
+-#ifndef _ASM_IA64_PERFMON_H
+-#define _ASM_IA64_PERFMON_H
+-
+-/*
+- * perfmon comamnds supported on all CPU models
+- */
+-#define PFM_WRITE_PMCS 0x01
+-#define PFM_WRITE_PMDS 0x02
+-#define PFM_READ_PMDS 0x03
+-#define PFM_STOP 0x04
+-#define PFM_START 0x05
+-#define PFM_ENABLE 0x06 /* obsolete */
+-#define PFM_DISABLE 0x07 /* obsolete */
+-#define PFM_CREATE_CONTEXT 0x08
+-#define PFM_DESTROY_CONTEXT 0x09 /* obsolete use close() */
+-#define PFM_RESTART 0x0a
+-#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */
+-#define PFM_GET_FEATURES 0x0c
+-#define PFM_DEBUG 0x0d
+-#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */
+-#define PFM_GET_PMC_RESET_VAL 0x0f
+-#define PFM_LOAD_CONTEXT 0x10
+-#define PFM_UNLOAD_CONTEXT 0x11
+-
+-/*
+- * PMU model specific commands (may not be supported on all PMU models)
+- */
+-#define PFM_WRITE_IBRS 0x20
+-#define PFM_WRITE_DBRS 0x21
+-
+-/*
+- * context flags
+- */
+-#define PFM_FL_NOTIFY_BLOCK 0x01 /* block task on user level notifications */
+-#define PFM_FL_SYSTEM_WIDE 0x02 /* create a system wide context */
+-#define PFM_FL_OVFL_NO_MSG 0x80 /* do not post overflow/end messages for notification */
+-
+-/*
+- * event set flags
+- */
+-#define PFM_SETFL_EXCL_IDLE 0x01 /* exclude idle task (syswide only) XXX: DO NOT USE YET */
+-
+-/*
+- * PMC flags
+- */
+-#define PFM_REGFL_OVFL_NOTIFY 0x1 /* send notification on overflow */
+-#define PFM_REGFL_RANDOM 0x2 /* randomize sampling interval */
+-
+-/*
+- * PMD/PMC/IBR/DBR return flags (ignored on input)
++ * Copyright (c) 2001-2007 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+- * Those flags are used on output and must be checked in case EAGAIN is returned
+- * by any of the calls using a pfarg_reg_t or pfarg_dbreg_t structure.
+- */
+-#define PFM_REG_RETFL_NOTAVAIL (1UL<<31) /* set if register is implemented but not available */
+-#define PFM_REG_RETFL_EINVAL (1UL<<30) /* set if register entry is invalid */
+-#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|PFM_REG_RETFL_EINVAL)
+-
+-#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0)
+-
+-typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */
+-
+-/*
+- * Request structure used to define a context
+- */
+-typedef struct {
+- pfm_uuid_t ctx_smpl_buf_id; /* which buffer format to use (if needed) */
+- unsigned long ctx_flags; /* noblock/block */
+- unsigned short ctx_nextra_sets; /* number of extra event sets (you always get 1) */
+- unsigned short ctx_reserved1; /* for future use */
+- int ctx_fd; /* return arg: unique identification for context */
+- void *ctx_smpl_vaddr; /* return arg: virtual address of sampling buffer, is used */
+- unsigned long ctx_reserved2[11];/* for future use */
+-} pfarg_context_t;
+-
+-/*
+- * Request structure used to write/read a PMC or PMD
+- */
+-typedef struct {
+- unsigned int reg_num; /* which register */
+- unsigned short reg_set; /* event set for this register */
+- unsigned short reg_reserved1; /* for future use */
+-
+- unsigned long reg_value; /* initial pmc/pmd value */
+- unsigned long reg_flags; /* input: pmc/pmd flags, return: reg error */
+-
+- unsigned long reg_long_reset; /* reset after buffer overflow notification */
+- unsigned long reg_short_reset; /* reset after counter overflow */
+-
+- unsigned long reg_reset_pmds[4]; /* which other counters to reset on overflow */
+- unsigned long reg_random_seed; /* seed value when randomization is used */
+- unsigned long reg_random_mask; /* bitmask used to limit random value */
+- unsigned long reg_last_reset_val;/* return: PMD last reset value */
+-
+- unsigned long reg_smpl_pmds[4]; /* which pmds are accessed when PMC overflows */
+- unsigned long reg_smpl_eventid; /* opaque sampling event identifier */
+-
+- unsigned long reg_reserved2[3]; /* for future use */
+-} pfarg_reg_t;
+-
+-typedef struct {
+- unsigned int dbreg_num; /* which debug register */
+- unsigned short dbreg_set; /* event set for this register */
+- unsigned short dbreg_reserved1; /* for future use */
+- unsigned long dbreg_value; /* value for debug register */
+- unsigned long dbreg_flags; /* return: dbreg error */
+- unsigned long dbreg_reserved2[1]; /* for future use */
+-} pfarg_dbreg_t;
+-
+-typedef struct {
+- unsigned int ft_version; /* perfmon: major [16-31], minor [0-15] */
+- unsigned int ft_reserved; /* reserved for future use */
+- unsigned long reserved[4]; /* for future use */
+-} pfarg_features_t;
+-
+-typedef struct {
+- pid_t load_pid; /* process to load the context into */
+- unsigned short load_set; /* first event set to load */
+- unsigned short load_reserved1; /* for future use */
+- unsigned long load_reserved2[3]; /* for future use */
+-} pfarg_load_t;
+-
+-typedef struct {
+- int msg_type; /* generic message header */
+- int msg_ctx_fd; /* generic message header */
+- unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */
+- unsigned short msg_active_set; /* active set at the time of overflow */
+- unsigned short msg_reserved1; /* for future use */
+- unsigned int msg_reserved2; /* for future use */
+- unsigned long msg_tstamp; /* for perf tuning/debug */
+-} pfm_ovfl_msg_t;
+-
+-typedef struct {
+- int msg_type; /* generic message header */
+- int msg_ctx_fd; /* generic message header */
+- unsigned long msg_tstamp; /* for perf tuning */
+-} pfm_end_msg_t;
+-
+-typedef struct {
+- int msg_type; /* type of the message */
+- int msg_ctx_fd; /* unique identifier for the context */
+- unsigned long msg_tstamp; /* for perf tuning */
+-} pfm_gen_msg_t;
+-
+-#define PFM_MSG_OVFL 1 /* an overflow happened */
+-#define PFM_MSG_END 2 /* task to which context was attached ended */
+-
+-typedef union {
+- pfm_ovfl_msg_t pfm_ovfl_msg;
+- pfm_end_msg_t pfm_end_msg;
+- pfm_gen_msg_t pfm_gen_msg;
+-} pfm_msg_t;
+-
+-/*
+- * Define the version numbers for both perfmon as a whole and the sampling buffer format.
++ * This file contains Itanium Processor Family specific definitions
++ * for the perfmon interface.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
+ */
+-#define PFM_VERSION_MAJ 2U
+-#define PFM_VERSION_MIN 0U
+-#define PFM_VERSION (((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
+-#define PFM_VERSION_MAJOR(x) (((x)>>16) & 0xffff)
+-#define PFM_VERSION_MINOR(x) ((x) & 0xffff)
+-
++#ifndef _ASM_IA64_PERFMON_H_
++#define _ASM_IA64_PERFMON_H_
+
+ /*
+- * miscellaneous architected definitions
++ * arch-specific user visible interface definitions
+ */
+-#define PMU_FIRST_COUNTER 4 /* first counting monitor (PMC/PMD) */
+-#define PMU_MAX_PMCS 256 /* maximum architected number of PMC registers */
+-#define PMU_MAX_PMDS 256 /* maximum architected number of PMD registers */
+-
+-#ifdef __KERNEL__
+-
+-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_load_regs (struct task_struct *);
+
+-extern void pfm_exit_thread(struct task_struct *);
+-extern int pfm_use_debug_registers(struct task_struct *);
+-extern int pfm_release_debug_registers(struct task_struct *);
+-extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, int is_ctxswin);
+-extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs);
+-extern void pfm_init_percpu(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);
++#define PFM_ARCH_MAX_PMCS (256+64)
++#define PFM_ARCH_MAX_PMDS (256+64)
+
+-
+-
+-/*
+- * Reset PMD register flags
+- */
+-#define PFM_PMD_SHORT_RESET 0
+-#define PFM_PMD_LONG_RESET 1
+-
+-typedef union {
+- unsigned int val;
+- struct {
+- unsigned int notify_user:1; /* notify user program of overflow */
+- unsigned int reset_ovfl_pmds:1; /* reset overflowed PMDs */
+- unsigned int block_task:1; /* block monitored task on kernel exit */
+- unsigned int mask_monitoring:1; /* mask monitors via PMCx.plm */
+- unsigned int reserved:28; /* for future use */
+- } bits;
+-} pfm_ovfl_ctrl_t;
+-
+-typedef struct {
+- unsigned char ovfl_pmd; /* index of overflowed PMD */
+- unsigned char ovfl_notify; /* =1 if monitor requested overflow notification */
+- unsigned short active_set; /* event set active at the time of the overflow */
+- pfm_ovfl_ctrl_t ovfl_ctrl; /* return: perfmon controls to set by handler */
+-
+- unsigned long pmd_last_reset; /* last reset value of of the PMD */
+- unsigned long smpl_pmds[4]; /* bitmask of other PMD of interest on overflow */
+- unsigned long smpl_pmds_values[PMU_MAX_PMDS]; /* values for the other PMDs of interest */
+- unsigned long pmd_value; /* current 64-bit value of the PMD */
+- unsigned long pmd_eventid; /* eventid associated with PMD */
+-} pfm_ovfl_arg_t;
+-
+-
+-typedef struct {
+- char *fmt_name;
+- pfm_uuid_t fmt_uuid;
+- size_t fmt_arg_size;
+- unsigned long fmt_flags;
+-
+- int (*fmt_validate)(struct task_struct *task, unsigned int flags, int cpu, void *arg);
+- int (*fmt_getsize)(struct task_struct *task, unsigned int flags, int cpu, void *arg, unsigned long *size);
+- int (*fmt_init)(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *arg);
+- int (*fmt_handler)(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp);
+- int (*fmt_restart)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
+- int (*fmt_restart_active)(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs);
+- int (*fmt_exit)(struct task_struct *task, void *buf, struct pt_regs *regs);
+-
+- struct list_head fmt_list;
+-} pfm_buffer_fmt_t;
+-
+-extern int pfm_register_buffer_fmt(pfm_buffer_fmt_t *fmt);
+-extern int pfm_unregister_buffer_fmt(pfm_uuid_t uuid);
++#define PFM_ARCH_PMD_STK_ARG 8
++#define PFM_ARCH_PMC_STK_ARG 8
+
+ /*
+- * perfmon interface exported to modules
++ * Itanium specific context flags
++ *
++ * bits[00-15]: generic flags (see asm/perfmon.h)
++ * bits[16-31]: arch-specific flags
+ */
+-extern int pfm_mod_read_pmds(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs);
+-extern int pfm_mod_write_pmcs(struct task_struct *, void *req, unsigned int nreq, struct pt_regs *regs);
+-extern int pfm_mod_write_ibrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs);
+-extern int pfm_mod_write_dbrs(struct task_struct *task, void *req, unsigned int nreq, struct pt_regs *regs);
++#define PFM_ITA_FL_INSECURE 0x10000 /* clear psr.sp on non system, non self */
+
+ /*
+- * describe the content of the local_cpu_date->pfm_syst_info field
++ * Itanium specific public event set flags (set_flags)
++ *
++ * event set flags layout:
++ * bits[00-15] : generic flags
++ * bits[16-31] : arch-specific flags
+ */
+-#define PFM_CPUINFO_SYST_WIDE 0x1 /* if set a system wide session exists */
+-#define PFM_CPUINFO_DCR_PP 0x2 /* if set the system wide session has started */
+-#define PFM_CPUINFO_EXCL_IDLE 0x4 /* the system wide session excludes the idle task */
++#define PFM_ITA_SETFL_EXCL_INTR 0x10000 /* exclude interrupt execution */
++#define PFM_ITA_SETFL_INTR_ONLY 0x20000 /* include only interrupt execution */
++#define PFM_ITA_SETFL_IDLE_EXCL 0x40000 /* stop monitoring in idle loop */
+
+ /*
+- * sysctl control structure. visible to sampling formats
++ * compatibility for version v2.0 of the interface
+ */
+-typedef struct {
+- int debug; /* turn on/off debugging via syslog */
+- int debug_ovfl; /* turn on/off debug printk in overflow handler */
+- int fastctxsw; /* turn on/off fast (unsecure) ctxsw */
+- int expert_mode; /* turn on/off value checking */
+-} pfm_sysctl_t;
+-extern pfm_sysctl_t pfm_sysctl;
+-
+-
+-#endif /* __KERNEL__ */
++#include <asm/perfmon_compat.h>
+
+-#endif /* _ASM_IA64_PERFMON_H */
++#endif /* _ASM_IA64_PERFMON_H_ */
+diff --git a/arch/ia64/include/asm/perfmon_compat.h b/arch/ia64/include/asm/perfmon_compat.h
+new file mode 100644
+index 0000000..5c14514
+--- /dev/null
++++ b/arch/ia64/include/asm/perfmon_compat.h
+@@ -0,0 +1,167 @@
++/*
++ * Copyright (c) 2001-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This header file contains perfmon interface definition
++ * that are now obsolete and should be dropped in favor
++ * of their equivalent functions as explained below.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++
++#ifndef _ASM_IA64_PERFMON_COMPAT_H_
++#define _ASM_IA64_PERFMON_COMPAT_H_
++
++/*
++ * custom sampling buffer identifier type
++ */
++typedef __u8 pfm_uuid_t[16];
++
++/*
++ * obsolete perfmon commands. Supported only on IA-64 for
++ * backward compatiblity reasons with perfmon v2.0.
++ */
++#define PFM_WRITE_PMCS 0x01 /* use pfm_write_pmcs */
++#define PFM_WRITE_PMDS 0x02 /* use pfm_write_pmds */
++#define PFM_READ_PMDS 0x03 /* use pfm_read_pmds */
++#define PFM_STOP 0x04 /* use pfm_stop */
++#define PFM_START 0x05 /* use pfm_start */
++#define PFM_ENABLE 0x06 /* obsolete */
++#define PFM_DISABLE 0x07 /* obsolete */
++#define PFM_CREATE_CONTEXT 0x08 /* use pfm_create_context */
++#define PFM_DESTROY_CONTEXT 0x09 /* use close() */
++#define PFM_RESTART 0x0a /* use pfm_restart */
++#define PFM_PROTECT_CONTEXT 0x0b /* obsolete */
++#define PFM_GET_FEATURES 0x0c /* use /proc/sys/perfmon */
++#define PFM_DEBUG 0x0d /* /proc/sys/kernel/perfmon/debug */
++#define PFM_UNPROTECT_CONTEXT 0x0e /* obsolete */
++#define PFM_GET_PMC_RESET_VAL 0x0f /* use /proc/perfmon_map */
++#define PFM_LOAD_CONTEXT 0x10 /* use pfm_load_context */
++#define PFM_UNLOAD_CONTEXT 0x11 /* use pfm_unload_context */
++
++/*
++ * PMU model specific commands (may not be supported on all PMU models)
++ */
++#define PFM_WRITE_IBRS 0x20 /* obsolete: use PFM_WRITE_PMCS[256-263]*/
++#define PFM_WRITE_DBRS 0x21 /* obsolete: use PFM_WRITE_PMCS[264-271]*/
++
++/*
++ * argument to PFM_CREATE_CONTEXT
++ */
++struct pfarg_context {
++ pfm_uuid_t ctx_smpl_buf_id; /* buffer format to use */
++ unsigned long ctx_flags; /* noblock/block */
++ unsigned int ctx_reserved1; /* for future use */
++ int ctx_fd; /* return: fildesc */
++ void *ctx_smpl_vaddr; /* return: vaddr of buffer */
++ unsigned long ctx_reserved3[11];/* for future use */
++};
++
++/*
++ * argument structure for PFM_WRITE_PMCS/PFM_WRITE_PMDS/PFM_WRITE_PMDS
++ */
++struct pfarg_reg {
++ unsigned int reg_num; /* which register */
++ unsigned short reg_set; /* event set for this register */
++ unsigned short reg_reserved1; /* for future use */
++
++ unsigned long reg_value; /* initial pmc/pmd value */
++ unsigned long reg_flags; /* input: flags, ret: error */
++
++ unsigned long reg_long_reset; /* reset value after notification */
++ unsigned long reg_short_reset; /* reset after counter overflow */
++
++ unsigned long reg_reset_pmds[4]; /* registers to reset on overflow */
++ unsigned long reg_random_seed; /* seed for randomization */
++ unsigned long reg_random_mask; /* random range limit */
++ unsigned long reg_last_reset_val;/* return: PMD last reset value */
++
++ unsigned long reg_smpl_pmds[4]; /* pmds to be saved on overflow */
++ unsigned long reg_smpl_eventid; /* opaque sampling event id */
++ unsigned long reg_ovfl_switch_cnt;/* #overflows to switch */
++
++ unsigned long reg_reserved2[2]; /* for future use */
++};
++
++/*
++ * argument to PFM_WRITE_IBRS/PFM_WRITE_DBRS
++ */
++struct pfarg_dbreg {
++ unsigned int dbreg_num; /* which debug register */
++ unsigned short dbreg_set; /* event set */
++ unsigned short dbreg_reserved1; /* for future use */
++ unsigned long dbreg_value; /* value for debug register */
++ unsigned long dbreg_flags; /* return: dbreg error */
++ unsigned long dbreg_reserved2[1]; /* for future use */
++};
++
++/*
++ * argument to PFM_GET_FEATURES
++ */
++struct pfarg_features {
++ unsigned int ft_version; /* major [16-31], minor [0-15] */
++ unsigned int ft_reserved; /* reserved for future use */
++ unsigned long reserved[4]; /* for future use */
++};
++
++typedef struct {
++ int msg_type; /* generic message header */
++ int msg_ctx_fd; /* generic message header */
++ unsigned long msg_ovfl_pmds[4]; /* which PMDs overflowed */
++ unsigned short msg_active_set; /* active set on overflow */
++ unsigned short msg_reserved1; /* for future use */
++ unsigned int msg_reserved2; /* for future use */
++ unsigned long msg_tstamp; /* for perf tuning/debug */
++} pfm_ovfl_msg_t;
++
++typedef struct {
++ int msg_type; /* generic message header */
++ int msg_ctx_fd; /* generic message header */
++ unsigned long msg_tstamp; /* for perf tuning */
++} pfm_end_msg_t;
++
++typedef struct {
++ int msg_type; /* type of the message */
++ int msg_ctx_fd; /* context file descriptor */
++ unsigned long msg_tstamp; /* for perf tuning */
++} pfm_gen_msg_t;
++
++typedef union {
++ int type;
++ pfm_ovfl_msg_t pfm_ovfl_msg;
++ pfm_end_msg_t pfm_end_msg;
++ pfm_gen_msg_t pfm_gen_msg;
++} pfm_msg_t;
++
++/*
++ * PMD/PMC return flags in case of error (ignored on input)
++ *
++ * reg_flags layout:
++ * bit 00-15 : generic flags
++ * bits[16-23] : arch-specific flags (see asm/perfmon.h)
++ * bit 24-31 : error codes
++ *
++ * Those flags are used on output and must be checked in case EINVAL is
++ * returned by a command accepting a vector of values and each has a flag
++ * field, such as pfarg_reg or pfarg_reg
++ */
++#define PFM_REG_RETFL_NOTAVAIL (1<<31) /* not implemented or unaccessible */
++#define PFM_REG_RETFL_EINVAL (1<<30) /* entry is invalid */
++#define PFM_REG_RETFL_MASK (PFM_REG_RETFL_NOTAVAIL|\
++ PFM_REG_RETFL_EINVAL)
++
++#define PFM_REG_HAS_ERROR(flag) (((flag) & PFM_REG_RETFL_MASK) != 0)
++
++#endif /* _ASM_IA64_PERFMON_COMPAT_H_ */
+diff --git a/arch/ia64/include/asm/perfmon_default_smpl.h b/arch/ia64/include/asm/perfmon_default_smpl.h
+index 48822c0..8234f32 100644
+--- a/arch/ia64/include/asm/perfmon_default_smpl.h
++++ b/arch/ia64/include/asm/perfmon_default_smpl.h
+@@ -1,83 +1,106 @@
+ /*
+- * Copyright (C) 2002-2003 Hewlett-Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+- * This file implements the default sampling buffer format
+- * for Linux/ia64 perfmon subsystem.
++ * This file implements the old default sampling buffer format
++ * for the perfmon2 subsystem. For IA-64 only.
++ *
++ * It requires the use of the perfmon_compat.h header. It is recommended
++ * that applications be ported to the new format instead.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
+ */
+-#ifndef __PERFMON_DEFAULT_SMPL_H__
+-#define __PERFMON_DEFAULT_SMPL_H__ 1
++#ifndef __ASM_IA64_PERFMON_DEFAULT_SMPL_H__
++#define __ASM_IA64_PERFMON_DEFAULT_SMPL_H__ 1
++
++#ifndef __ia64__
++#error "this file must be used for compatibility reasons only on IA-64"
++#endif
+
+ #define PFM_DEFAULT_SMPL_UUID { \
+- 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82, 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97}
++ 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82,\
++ 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97}
+
+ /*
+ * format specific parameters (passed at context creation)
+ */
+-typedef struct {
++struct pfm_default_smpl_arg {
+ unsigned long buf_size; /* size of the buffer in bytes */
+ unsigned int flags; /* buffer specific flags */
+ unsigned int res1; /* for future use */
+ unsigned long reserved[2]; /* for future use */
+-} pfm_default_smpl_arg_t;
++};
+
+ /*
+ * combined context+format specific structure. Can be passed
+- * to PFM_CONTEXT_CREATE
++ * to PFM_CONTEXT_CREATE (not PFM_CONTEXT_CREATE2)
+ */
+-typedef struct {
+- pfarg_context_t ctx_arg;
+- pfm_default_smpl_arg_t buf_arg;
+-} pfm_default_smpl_ctx_arg_t;
++struct pfm_default_smpl_ctx_arg {
++ struct pfarg_context ctx_arg;
++ struct pfm_default_smpl_arg buf_arg;
++};
+
+ /*
+ * This header is at the beginning of the sampling buffer returned to the user.
+ * It is directly followed by the first record.
+ */
+-typedef struct {
+- unsigned long hdr_count; /* how many valid entries */
+- unsigned long hdr_cur_offs; /* current offset from top of buffer */
+- unsigned long hdr_reserved2; /* reserved for future use */
++struct pfm_default_smpl_hdr {
++ u64 hdr_count; /* how many valid entries */
++ u64 hdr_cur_offs; /* current offset from top of buffer */
++ u64 dr_reserved2; /* reserved for future use */
+
+- unsigned long hdr_overflows; /* how many times the buffer overflowed */
+- unsigned long hdr_buf_size; /* how many bytes in the buffer */
++ u64 hdr_overflows; /* how many times the buffer overflowed */
++ u64 hdr_buf_size; /* how many bytes in the buffer */
+
+- unsigned int hdr_version; /* contains perfmon version (smpl format diffs) */
+- unsigned int hdr_reserved1; /* for future use */
+- unsigned long hdr_reserved[10]; /* for future use */
+-} pfm_default_smpl_hdr_t;
++ u32 hdr_version; /* smpl format version*/
++ u32 hdr_reserved1; /* for future use */
++ u64 hdr_reserved[10]; /* for future use */
++};
+
+ /*
+ * Entry header in the sampling buffer. The header is directly followed
+- * with the values of the PMD registers of interest saved in increasing
+- * index order: PMD4, PMD5, and so on. How many PMDs are present depends
++ * with the values of the PMD registers of interest saved in increasing
++ * index order: PMD4, PMD5, and so on. How many PMDs are present depends
+ * on how the session was programmed.
+ *
+ * In the case where multiple counters overflow at the same time, multiple
+ * entries are written consecutively.
+ *
+- * last_reset_value member indicates the initial value of the overflowed PMD.
++ * last_reset_value member indicates the initial value of the overflowed PMD.
+ */
+-typedef struct {
+- int pid; /* thread id (for NPTL, this is gettid()) */
+- unsigned char reserved1[3]; /* reserved for future use */
+- unsigned char ovfl_pmd; /* index of overflowed PMD */
+-
+- unsigned long last_reset_val; /* initial value of overflowed PMD */
+- unsigned long ip; /* where did the overflow interrupt happened */
+- unsigned long tstamp; /* ar.itc when entering perfmon intr. handler */
+-
+- unsigned short cpu; /* cpu on which the overfow occured */
+- unsigned short set; /* event set active when overflow ocurred */
+- int tgid; /* thread group id (for NPTL, this is getpid()) */
+-} pfm_default_smpl_entry_t;
++struct pfm_default_smpl_entry {
++ pid_t pid; /* thread id (for NPTL, this is gettid()) */
++ uint8_t reserved1[3]; /* for future use */
++ uint8_t ovfl_pmd; /* overflow pmd for this sample */
++ u64 last_reset_val; /* initial value of overflowed PMD */
++ unsigned long ip; /* where did the overflow interrupt happened */
++ u64 tstamp; /* overflow timetamp */
++ u16 cpu; /* cpu on which the overfow occured */
++ u16 set; /* event set active when overflow ocurred */
++ pid_t tgid; /* thread group id (for NPTL, this is getpid()) */
++};
+
+-#define PFM_DEFAULT_MAX_PMDS 64 /* how many pmds supported by data structures (sizeof(unsigned long) */
+-#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(pfm_default_smpl_entry_t)+(sizeof(unsigned long)*PFM_DEFAULT_MAX_PMDS))
+-#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(pfm_default_smpl_hdr_t)+PFM_DEFAULT_MAX_ENTRY_SIZE)
++#define PFM_DEFAULT_MAX_PMDS 64 /* #pmds supported */
++#define PFM_DEFAULT_MAX_ENTRY_SIZE (sizeof(struct pfm_default_smpl_entry)+\
++ (sizeof(u64)*PFM_DEFAULT_MAX_PMDS))
++#define PFM_DEFAULT_SMPL_MIN_BUF_SIZE (sizeof(struct pfm_default_smpl_hdr)+\
++ PFM_DEFAULT_MAX_ENTRY_SIZE)
+
+ #define PFM_DEFAULT_SMPL_VERSION_MAJ 2U
+-#define PFM_DEFAULT_SMPL_VERSION_MIN 0U
+-#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|(PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff))
++#define PFM_DEFAULT_SMPL_VERSION_MIN 1U
++#define PFM_DEFAULT_SMPL_VERSION (((PFM_DEFAULT_SMPL_VERSION_MAJ&0xffff)<<16)|\
++ (PFM_DEFAULT_SMPL_VERSION_MIN & 0xffff))
+
+-#endif /* __PERFMON_DEFAULT_SMPL_H__ */
++#endif /* __ASM_IA64_PERFMON_DEFAULT_SMPL_H__ */
+diff --git a/arch/ia64/include/asm/perfmon_kern.h b/arch/ia64/include/asm/perfmon_kern.h
+new file mode 100644
+index 0000000..fb40459
+--- /dev/null
++++ b/arch/ia64/include/asm/perfmon_kern.h
+@@ -0,0 +1,356 @@
++/*
++ * Copyright (c) 2001-2007 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This file contains Itanium Processor Family specific definitions
++ * for the perfmon interface.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#ifndef _ASM_IA64_PERFMON_KERN_H_
++#define _ASM_IA64_PERFMON_KERN_H_
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_PERFMON
++#include <asm/unistd.h>
++#include <asm/hw_irq.h>
++
++/*
++ * describe the content of the pfm_syst_info field
++ * layout:
++ * bits[00-15] : generic flags
++ * bits[16-31] : arch-specific flags
++ */
++#define PFM_ITA_CPUINFO_IDLE_EXCL 0x10000 /* stop monitoring in idle loop */
++
++/*
++ * For some CPUs, the upper bits of a counter must be set in order for the
++ * overflow interrupt to happen. On overflow, the counter has wrapped around,
++ * and the upper bits are cleared. This function may be used to set them back.
++ */
++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx,
++ unsigned int cnum)
++{}
++
++/*
++ * called from __pfm_interrupt_handler(). ctx is not NULL.
++ * ctx is locked. PMU interrupt is masked.
++ *
++ * must stop all monitoring to ensure handler has consistent view.
++ * must collect overflowed PMDs bitmask into povfls_pmds and
++ * npend_ovfls. If no interrupt detected then npend_ovfls
++ * must be set to zero.
++ */
++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ u64 tmp;
++
++ /*
++ * do not overwrite existing value, must
++ * process those first (coming from context switch replay)
++ */
++ if (set->npend_ovfls)
++ return;
++
++ ia64_srlz_d();
++
++ tmp = ia64_get_pmc(0) & ~0xf;
++
++ set->povfl_pmds[0] = tmp;
++
++ set->npend_ovfls = ia64_popcnt(tmp);
++}
++
++static inline int pfm_arch_init_pmu_config(void)
++{
++ return 0;
++}
++
++static inline void pfm_arch_resend_irq(struct pfm_context *ctx)
++{
++ ia64_resend_irq(IA64_PERFMON_VECTOR);
++}
++
++static inline void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{}
++
++static inline void pfm_arch_serialize(void)
++{
++ ia64_srlz_d();
++}
++
++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx)
++{
++ PFM_DBG_ovfl("state=%d", ctx->state);
++ ia64_set_pmc(0, 0);
++ /* no serialization */
++}
++
++static inline void pfm_arch_write_pmc(struct pfm_context *ctx,
++ unsigned int cnum, u64 value)
++{
++ if (cnum < 256) {
++ ia64_set_pmc(pfm_pmu_conf->pmc_desc[cnum].hw_addr, value);
++ } else if (cnum < 264) {
++ ia64_set_ibr(cnum-256, value);
++ ia64_dv_serialize_instruction();
++ } else {
++ ia64_set_dbr(cnum-264, value);
++ ia64_dv_serialize_instruction();
++ }
++}
++
++/*
++ * On IA-64, for per-thread context which have the ITA_FL_INSECURE
++ * flag, it is possible to start/stop monitoring directly from user evel
++ * without calling pfm_start()/pfm_stop. This allows very lightweight
++ * control yet the kernel sometimes needs to know if monitoring is actually
++ * on or off.
++ *
++ * Tracking of this information is normally done by pfm_start/pfm_stop
++ * in flags.started. Here we need to compensate by checking actual
++ * psr bit.
++ */
++static inline int pfm_arch_is_active(struct pfm_context *ctx)
++{
++ return ctx->flags.started
++ || ia64_getreg(_IA64_REG_PSR) & (IA64_PSR_UP|IA64_PSR_PP);
++}
++
++static inline void pfm_arch_write_pmd(struct pfm_context *ctx,
++ unsigned int cnum, u64 value)
++{
++ /*
++ * for a counting PMD, overflow bit must be cleared
++ */
++ if (pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64)
++ value &= pfm_pmu_conf->ovfl_mask;
++
++ /*
++ * for counters, write to upper bits are ignored, no need to mask
++ */
++ ia64_set_pmd(pfm_pmu_conf->pmd_desc[cnum].hw_addr, value);
++}
++
++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum)
++{
++ return ia64_get_pmd(pfm_pmu_conf->pmd_desc[cnum].hw_addr);
++}
++
++static inline u64 pfm_arch_read_pmc(struct pfm_context *ctx, unsigned int cnum)
++{
++ return ia64_get_pmc(pfm_pmu_conf->pmc_desc[cnum].hw_addr);
++}
++
++static inline void pfm_arch_ctxswout_sys(struct task_struct *task,
++ struct pfm_context *ctx)
++{
++ struct pt_regs *regs;
++
++ regs = task_pt_regs(task);
++ ia64_psr(regs)->pp = 0;
++}
++
++static inline void pfm_arch_ctxswin_sys(struct task_struct *task,
++ struct pfm_context *ctx)
++{
++ struct pt_regs *regs;
++
++ if (!(ctx->active_set->flags & PFM_ITA_SETFL_INTR_ONLY)) {
++ regs = task_pt_regs(task);
++ ia64_psr(regs)->pp = 1;
++ }
++}
++
++/*
++ * On IA-64, the PMDs are NOT saved by pfm_arch_freeze_pmu()
++ * when entering the PMU interrupt handler, thus, we need
++ * to save them in pfm_switch_sets_from_intr()
++ */
++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ pfm_save_pmds(ctx, set);
++}
++
++int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags);
++
++static inline void pfm_arch_context_free(struct pfm_context *ctx)
++{}
++
++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_ctxswin_thread(struct task_struct *task,
++ struct pfm_context *ctx);
++
++void pfm_arch_unload_context(struct pfm_context *ctx);
++int pfm_arch_load_context(struct pfm_context *ctx);
++int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags);
++
++void pfm_arch_mask_monitoring(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++void pfm_arch_unmask_monitoring(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++
++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set);
++
++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx);
++
++int pfm_arch_init(void);
++void pfm_arch_init_percpu(void);
++char *pfm_arch_get_pmu_module_name(void);
++
++int __pfm_use_dbregs(struct task_struct *task);
++int __pfm_release_dbregs(struct task_struct *task);
++int pfm_ia64_mark_dbregs_used(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++
++void pfm_arch_show_session(struct seq_file *m);
++
++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds)
++{
++ return 0;
++}
++
++static inline void pfm_arch_pmu_release(void)
++{}
++
++/* not necessary on IA-64 */
++static inline void pfm_cacheflush(void *addr, unsigned int len)
++{}
++
++/*
++ * miscellaneous architected definitions
++ */
++#define PFM_ITA_FCNTR 4 /* first counting monitor (PMC/PMD) */
++
++/*
++ * private event set flags (set_priv_flags)
++ */
++#define PFM_ITA_SETFL_USE_DBR 0x1000000 /* set uses debug registers */
++
++
++/*
++ * Itanium-specific data structures
++ */
++struct pfm_ia64_context_flags {
++ unsigned int use_dbr:1; /* use range restrictions (debug registers) */
++ unsigned int insecure:1; /* insecure monitoring for non-self session */
++ unsigned int reserved:30;/* for future use */
++};
++
++struct pfm_arch_context {
++ struct pfm_ia64_context_flags flags; /* arch specific ctx flags */
++ u64 ctx_saved_psr_up;/* storage for psr_up */
++#ifdef CONFIG_IA64_PERFMON_COMPAT
++ void *ctx_smpl_vaddr; /* vaddr of user mapping */
++#endif
++};
++
++#ifdef CONFIG_IA64_PERFMON_COMPAT
++ssize_t pfm_arch_compat_read(struct pfm_context *ctx,
++ char __user *buf,
++ int non_block,
++ size_t size);
++int pfm_ia64_compat_init(void);
++int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx,
++ size_t rsize, struct file *filp);
++#else
++static inline ssize_t pfm_arch_compat_read(struct pfm_context *ctx,
++ char __user *buf,
++ int non_block,
++ size_t size)
++{
++ return -EINVAL;
++}
++
++static inline int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx,
++ size_t rsize, struct file *filp)
++{
++ return -EINVAL;
++}
++#endif
++
++static inline void pfm_arch_arm_handle_work(struct task_struct *task)
++{
++ /*
++ * On IA-64, we ran out of bits in the bottom 7 bits of the
++ * threadinfo bitmask.Thus we used a 2-stage approach by piggybacking
++ * on NOTIFY_RESUME and then in do_notify_resume() we demultiplex and
++ * call pfm_handle_work() if needed
++ */
++ set_tsk_thread_flag(task, TIF_NOTIFY_RESUME);
++}
++
++static inline void pfm_arch_disarm_handle_work(struct task_struct *task)
++{
++ /*
++ * we cannot just clear TIF_NOTIFY_RESUME because other TIF flags are
++ * piggybackedonto it: TIF_PERFMON_WORK, TIF_RESTORE_RSE
++ *
++ * The tsk_clear_notify_resume() checks if any of those are set before
++ * clearing the * bit
++ */
++ tsk_clear_notify_resume(task);
++}
++
++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg)
++{
++ return 0;
++}
++
++extern struct pfm_ia64_pmu_info *pfm_ia64_pmu_info;
++
++#define PFM_ARCH_CTX_SIZE (sizeof(struct pfm_arch_context))
++
++/*
++ * IA-64 does not need extra alignment requirements for the sampling buffer
++ */
++#define PFM_ARCH_SMPL_ALIGN_SIZE 0
++
++
++static inline void pfm_release_dbregs(struct task_struct *task)
++{
++ if (task->thread.flags & IA64_THREAD_DBG_VALID)
++ __pfm_release_dbregs(task);
++}
++
++#define pfm_use_dbregs(_t) __pfm_use_dbregs(_t)
++
++static inline int pfm_arch_get_base_syscall(void)
++{
++ return __NR_pfm_create_context;
++}
++
++struct pfm_arch_pmu_info {
++ unsigned long mask_pmcs[PFM_PMC_BV]; /* modify on when masking */
++};
++
++DECLARE_PER_CPU(u32, pfm_syst_info);
++#else /* !CONFIG_PERFMON */
++/*
++ * perfmon ia64-specific hooks
++ */
++#define pfm_release_dbregs(_t) do { } while (0)
++#define pfm_use_dbregs(_t) (0)
++
++#endif /* CONFIG_PERFMON */
++
++#endif /* __KERNEL__ */
++#endif /* _ASM_IA64_PERFMON_KERN_H_ */
+diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
+index f88fa05..9d6af9c 100644
+--- a/arch/ia64/include/asm/processor.h
++++ b/arch/ia64/include/asm/processor.h
+@@ -42,7 +42,6 @@
+
+ #define IA64_THREAD_FPH_VALID (__IA64_UL(1) << 0) /* floating-point high state valid? */
+ #define IA64_THREAD_DBG_VALID (__IA64_UL(1) << 1) /* debug registers valid? */
+-#define IA64_THREAD_PM_VALID (__IA64_UL(1) << 2) /* performance registers valid? */
+ #define IA64_THREAD_UAC_NOPRINT (__IA64_UL(1) << 3) /* don't log unaligned accesses */
+ #define IA64_THREAD_UAC_SIGBUS (__IA64_UL(1) << 4) /* generate SIGBUS on unaligned acc. */
+ #define IA64_THREAD_MIGRATION (__IA64_UL(1) << 5) /* require migration
+@@ -321,14 +320,6 @@ struct thread_struct {
+ #else
+ # define INIT_THREAD_IA32
+ #endif /* CONFIG_IA32_SUPPORT */
+-#ifdef CONFIG_PERFMON
+- void *pfm_context; /* pointer to detailed PMU context */
+- unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */
+-# define INIT_THREAD_PM .pfm_context = NULL, \
+- .pfm_needs_checking = 0UL,
+-#else
+-# define INIT_THREAD_PM
+-#endif
+ __u64 dbr[IA64_NUM_DBG_REGS];
+ __u64 ibr[IA64_NUM_DBG_REGS];
+ struct ia64_fpreg fph[96]; /* saved/loaded on demand */
+@@ -343,7 +334,6 @@ struct thread_struct {
+ .task_size = DEFAULT_TASK_SIZE, \
+ .last_fph_cpu = -1, \
+ INIT_THREAD_IA32 \
+- INIT_THREAD_PM \
+ .dbr = {0, }, \
+ .ibr = {0, }, \
+ .fph = {{{{0}}}, } \
+diff --git a/arch/ia64/include/asm/system.h b/arch/ia64/include/asm/system.h
+index 927a381..ab5aeea 100644
+--- a/arch/ia64/include/asm/system.h
++++ b/arch/ia64/include/asm/system.h
+@@ -217,6 +217,7 @@ struct task_struct;
+ extern void ia64_save_extra (struct task_struct *task);
+ extern void ia64_load_extra (struct task_struct *task);
+
++
+ #ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct *next);
+ # define IA64_ACCOUNT_ON_SWITCH(p,n) ia64_account_on_switch(p,n)
+@@ -224,16 +225,9 @@ extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct
+ # define IA64_ACCOUNT_ON_SWITCH(p,n)
+ #endif
+
+-#ifdef CONFIG_PERFMON
+- DECLARE_PER_CPU(unsigned long, pfm_syst_info);
+-# define PERFMON_IS_SYSWIDE() (__get_cpu_var(pfm_syst_info) & 0x1)
+-#else
+-# define PERFMON_IS_SYSWIDE() (0)
+-#endif
+-
+-#define IA64_HAS_EXTRA_STATE(t) \
+- ((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID) \
+- || IS_IA32_PROCESS(task_pt_regs(t)) || PERFMON_IS_SYSWIDE())
++#define IA64_HAS_EXTRA_STATE(t) \
++ (((t)->thread.flags & IA64_THREAD_DBG_VALID) \
++ || IS_IA32_PROCESS(task_pt_regs(t)))
+
+ #define __switch_to(prev,next,last) do { \
+ IA64_ACCOUNT_ON_SWITCH(prev, next); \
+@@ -241,6 +235,10 @@ extern void ia64_account_on_switch (struct task_struct *prev, struct task_struct
+ ia64_save_extra(prev); \
+ if (IA64_HAS_EXTRA_STATE(next)) \
+ ia64_load_extra(next); \
++ if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW)) \
++ pfm_ctxsw_out(prev, next); \
++ if (test_tsk_thread_flag(next, TIF_PERFMON_CTXSW)) \
++ pfm_ctxsw_in(prev, next); \
+ ia64_psr(task_pt_regs(next))->dfh = !ia64_is_local_fpu_owner(next); \
+ (last) = ia64_switch_to((next)); \
+ } while (0)
+diff --git a/arch/ia64/include/asm/thread_info.h b/arch/ia64/include/asm/thread_info.h
+index 7c60fcd..3355332 100644
+--- a/arch/ia64/include/asm/thread_info.h
++++ b/arch/ia64/include/asm/thread_info.h
+@@ -110,6 +110,8 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
+ #define TIF_DB_DISABLED 19 /* debug trap disabled for fsyscall */
+ #define TIF_FREEZE 20 /* is freezing for suspend */
+ #define TIF_RESTORE_RSE 21 /* user RBS is newer than kernel RBS */
++#define TIF_PERFMON_CTXSW 22 /* perfmon needs ctxsw calls */
++#define TIF_PERFMON_WORK 23 /* work for pfm_handle_work() */
+
+ #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+ #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+@@ -123,6 +125,8 @@ extern void tsk_clear_notify_resume(struct task_struct *tsk);
+ #define _TIF_DB_DISABLED (1 << TIF_DB_DISABLED)
+ #define _TIF_FREEZE (1 << TIF_FREEZE)
+ #define _TIF_RESTORE_RSE (1 << TIF_RESTORE_RSE)
++#define _TIF_PERFMON_CTXSW (1 << TIF_PERFMON_CTXSW)
++#define _TIF_PERFMON_WORK (1 << TIF_PERFMON_WORK)
+
+ /* "work to do on user-return" bits */
+ #define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\
+diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
+index d535833..29a43bc 100644
+--- a/arch/ia64/include/asm/unistd.h
++++ b/arch/ia64/include/asm/unistd.h
+@@ -308,11 +308,23 @@
+ #define __NR_dup3 1316
+ #define __NR_pipe2 1317
+ #define __NR_inotify_init1 1318
++#define __NR_pfm_create_context 1319
++#define __NR_pfm_write_pmcs (__NR_pfm_create_context+1)
++#define __NR_pfm_write_pmds (__NR_pfm_create_context+2)
++#define __NR_pfm_read_pmds (__NR_pfm_create_context+3)
++#define __NR_pfm_load_context (__NR_pfm_create_context+4)
++#define __NR_pfm_start (__NR_pfm_create_context+5)
++#define __NR_pfm_stop (__NR_pfm_create_context+6)
++#define __NR_pfm_restart (__NR_pfm_create_context+7)
++#define __NR_pfm_create_evtsets (__NR_pfm_create_context+8)
++#define __NR_pfm_getinfo_evtsets (__NR_pfm_create_context+9)
++#define __NR_pfm_delete_evtsets (__NR_pfm_create_context+10)
++#define __NR_pfm_unload_context (__NR_pfm_create_context+11)
+
+ #ifdef __KERNEL__
+
+
+-#define NR_syscalls 295 /* length of syscall table */
++#define NR_syscalls 307 /* length of syscall table */
+
+ /*
+ * The following defines stop scripts/checksyscalls.sh from complaining about
+diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
+index 87fea11..b5ac54c 100644
+--- a/arch/ia64/kernel/Makefile
++++ b/arch/ia64/kernel/Makefile
+@@ -5,7 +5,7 @@
+ extra-y := head.o init_task.o vmlinux.lds
+
+ obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \
+- irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \
++ irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o ptrace.o sal.o \
+ salinfo.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
+ unwind.o mca.o mca_asm.o topology.o
+
+@@ -23,7 +23,6 @@ obj-$(CONFIG_IOSAPIC) += iosapic.o
+ obj-$(CONFIG_MODULES) += module.o
+ obj-$(CONFIG_SMP) += smp.o smpboot.o
+ obj-$(CONFIG_NUMA) += numa.o
+-obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
+ obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
+ obj-$(CONFIG_CPU_FREQ) += cpufreq/
+ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
+diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
+index 0dd6c14..f1c3e41 100644
+--- a/arch/ia64/kernel/entry.S
++++ b/arch/ia64/kernel/entry.S
+@@ -1697,6 +1697,18 @@ sys_call_table:
+ data8 sys_dup3
+ data8 sys_pipe2
+ data8 sys_inotify_init1
++ data8 sys_pfm_create_context
++ data8 sys_pfm_write_pmcs // 1320
++ data8 sys_pfm_write_pmds
++ data8 sys_pfm_read_pmds
++ data8 sys_pfm_load_context
++ data8 sys_pfm_start
++ data8 sys_pfm_stop // 1325
++ data8 sys_pfm_restart
++ data8 sys_pfm_create_evtsets
++ data8 sys_pfm_getinfo_evtsets
++ data8 sys_pfm_delete_evtsets
++ data8 sys_pfm_unload_context // 1330
+
+ .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
+ #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
+diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
+index 28d3d48..ede8024 100644
+--- a/arch/ia64/kernel/irq_ia64.c
++++ b/arch/ia64/kernel/irq_ia64.c
+@@ -40,10 +40,6 @@
+ #include <asm/system.h>
+ #include <asm/tlbflush.h>
+
+-#ifdef CONFIG_PERFMON
+-# include <asm/perfmon.h>
+-#endif
+-
+ #define IRQ_DEBUG 0
+
+ #define IRQ_VECTOR_UNASSIGNED (0)
+@@ -660,9 +656,6 @@ init_IRQ (void)
+ }
+ #endif
+ #endif
+-#ifdef CONFIG_PERFMON
+- pfm_init_percpu();
+-#endif
+ platform_irq_init();
+ }
+
+diff --git a/arch/ia64/kernel/perfmon_default_smpl.c b/arch/ia64/kernel/perfmon_default_smpl.c
+deleted file mode 100644
+index 5f637bb..0000000
+--- a/arch/ia64/kernel/perfmon_default_smpl.c
++++ /dev/null
+@@ -1,296 +0,0 @@
+-/*
+- * Copyright (C) 2002-2003 Hewlett-Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
+- *
+- * This file implements the default sampling buffer format
+- * for the Linux/ia64 perfmon-2 subsystem.
+- */
+-#include <linux/kernel.h>
+-#include <linux/types.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <asm/delay.h>
+-#include <linux/smp.h>
+-
+-#include <asm/perfmon.h>
+-#include <asm/perfmon_default_smpl.h>
+-
+-MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
+-MODULE_DESCRIPTION("perfmon default sampling format");
+-MODULE_LICENSE("GPL");
+-
+-#define DEFAULT_DEBUG 1
+-
+-#ifdef DEFAULT_DEBUG
+-#define DPRINT(a) \
+- do { \
+- if (unlikely(pfm_sysctl.debug >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
+- } while (0)
+-
+-#define DPRINT_ovfl(a) \
+- do { \
+- if (unlikely(pfm_sysctl.debug > 0 && pfm_sysctl.debug_ovfl >0)) { printk("%s.%d: CPU%d ", __func__, __LINE__, smp_processor_id()); printk a; } \
+- } while (0)
+-
+-#else
+-#define DPRINT(a)
+-#define DPRINT_ovfl(a)
+-#endif
+-
+-static int
+-default_validate(struct task_struct *task, unsigned int flags, int cpu, void *data)
+-{
+- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t*)data;
+- int ret = 0;
+-
+- if (data == NULL) {
+- DPRINT(("[%d] no argument passed\n", task_pid_nr(task)));
+- return -EINVAL;
+- }
+-
+- DPRINT(("[%d] validate flags=0x%x CPU%d\n", task_pid_nr(task), flags, cpu));
+-
+- /*
+- * must hold at least the buffer header + one minimally sized entry
+- */
+- if (arg->buf_size < PFM_DEFAULT_SMPL_MIN_BUF_SIZE) return -EINVAL;
+-
+- DPRINT(("buf_size=%lu\n", arg->buf_size));
+-
+- return ret;
+-}
+-
+-static int
+-default_get_size(struct task_struct *task, unsigned int flags, int cpu, void *data, unsigned long *size)
+-{
+- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
+-
+- /*
+- * size has been validated in default_validate
+- */
+- *size = arg->buf_size;
+-
+- return 0;
+-}
+-
+-static int
+-default_init(struct task_struct *task, void *buf, unsigned int flags, int cpu, void *data)
+-{
+- pfm_default_smpl_hdr_t *hdr;
+- pfm_default_smpl_arg_t *arg = (pfm_default_smpl_arg_t *)data;
+-
+- hdr = (pfm_default_smpl_hdr_t *)buf;
+-
+- hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION;
+- hdr->hdr_buf_size = arg->buf_size;
+- hdr->hdr_cur_offs = sizeof(*hdr);
+- hdr->hdr_overflows = 0UL;
+- hdr->hdr_count = 0UL;
+-
+- DPRINT(("[%d] buffer=%p buf_size=%lu hdr_size=%lu hdr_version=%u cur_offs=%lu\n",
+- task_pid_nr(task),
+- buf,
+- hdr->hdr_buf_size,
+- sizeof(*hdr),
+- hdr->hdr_version,
+- hdr->hdr_cur_offs));
+-
+- return 0;
+-}
+-
+-static int
+-default_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg, struct pt_regs *regs, unsigned long stamp)
+-{
+- pfm_default_smpl_hdr_t *hdr;
+- pfm_default_smpl_entry_t *ent;
+- void *cur, *last;
+- unsigned long *e, entry_size;
+- unsigned int npmds, i;
+- unsigned char ovfl_pmd;
+- unsigned char ovfl_notify;
+-
+- if (unlikely(buf == NULL || arg == NULL|| regs == NULL || task == NULL)) {
+- DPRINT(("[%d] invalid arguments buf=%p arg=%p\n", task->pid, buf, arg));
+- return -EINVAL;
+- }
+-
+- hdr = (pfm_default_smpl_hdr_t *)buf;
+- cur = buf+hdr->hdr_cur_offs;
+- last = buf+hdr->hdr_buf_size;
+- ovfl_pmd = arg->ovfl_pmd;
+- ovfl_notify = arg->ovfl_notify;
+-
+- /*
+- * precheck for sanity
+- */
+- if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
+-
+- npmds = hweight64(arg->smpl_pmds[0]);
+-
+- ent = (pfm_default_smpl_entry_t *)cur;
+-
+- prefetch(arg->smpl_pmds_values);
+-
+- entry_size = sizeof(*ent) + (npmds << 3);
+-
+- /* position for first pmd */
+- e = (unsigned long *)(ent+1);
+-
+- hdr->hdr_count++;
+-
+- DPRINT_ovfl(("[%d] count=%lu cur=%p last=%p free_bytes=%lu ovfl_pmd=%d ovfl_notify=%d npmds=%u\n",
+- task->pid,
+- hdr->hdr_count,
+- cur, last,
+- last-cur,
+- ovfl_pmd,
+- ovfl_notify, npmds));
+-
+- /*
+- * current = task running at the time of the overflow.
+- *
+- * per-task mode:
+- * - this is ususally the task being monitored.
+- * Under certain conditions, it might be a different task
+- *
+- * system-wide:
+- * - this is not necessarily the task controlling the session
+- */
+- ent->pid = current->pid;
+- ent->ovfl_pmd = ovfl_pmd;
+- ent->last_reset_val = arg->pmd_last_reset; //pmd[0].reg_last_reset_val;
+-
+- /*
+- * where did the fault happen (includes slot number)
+- */
+- ent->ip = regs->cr_iip | ((regs->cr_ipsr >> 41) & 0x3);
+-
+- ent->tstamp = stamp;
+- ent->cpu = smp_processor_id();
+- ent->set = arg->active_set;
+- ent->tgid = current->tgid;
+-
+- /*
+- * selectively store PMDs in increasing index number
+- */
+- if (npmds) {
+- unsigned long *val = arg->smpl_pmds_values;
+- for(i=0; i < npmds; i++) {
+- *e++ = *val++;
+- }
+- }
+-
+- /*
+- * update position for next entry
+- */
+- hdr->hdr_cur_offs += entry_size;
+- cur += entry_size;
+-
+- /*
+- * post check to avoid losing the last sample
+- */
+- if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE) goto full;
+-
+- /*
+- * keep same ovfl_pmds, ovfl_notify
+- */
+- arg->ovfl_ctrl.bits.notify_user = 0;
+- arg->ovfl_ctrl.bits.block_task = 0;
+- arg->ovfl_ctrl.bits.mask_monitoring = 0;
+- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1; /* reset before returning from interrupt handler */
+-
+- return 0;
+-full:
+- DPRINT_ovfl(("sampling buffer full free=%lu, count=%lu, ovfl_notify=%d\n", last-cur, hdr->hdr_count, ovfl_notify));
+-
+- /*
+- * increment number of buffer overflow.
+- * important to detect duplicate set of samples.
+- */
+- hdr->hdr_overflows++;
+-
+- /*
+- * if no notification requested, then we saturate the buffer
+- */
+- if (ovfl_notify == 0) {
+- arg->ovfl_ctrl.bits.notify_user = 0;
+- arg->ovfl_ctrl.bits.block_task = 0;
+- arg->ovfl_ctrl.bits.mask_monitoring = 1;
+- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0;
+- } else {
+- arg->ovfl_ctrl.bits.notify_user = 1;
+- arg->ovfl_ctrl.bits.block_task = 1; /* ignored for non-blocking context */
+- arg->ovfl_ctrl.bits.mask_monitoring = 1;
+- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 0; /* no reset now */
+- }
+- return -1; /* we are full, sorry */
+-}
+-
+-static int
+-default_restart(struct task_struct *task, pfm_ovfl_ctrl_t *ctrl, void *buf, struct pt_regs *regs)
+-{
+- pfm_default_smpl_hdr_t *hdr;
+-
+- hdr = (pfm_default_smpl_hdr_t *)buf;
+-
+- hdr->hdr_count = 0UL;
+- hdr->hdr_cur_offs = sizeof(*hdr);
+-
+- ctrl->bits.mask_monitoring = 0;
+- ctrl->bits.reset_ovfl_pmds = 1; /* uses long-reset values */
+-
+- return 0;
+-}
+-
+-static int
+-default_exit(struct task_struct *task, void *buf, struct pt_regs *regs)
+-{
+- DPRINT(("[%d] exit(%p)\n", task_pid_nr(task), buf));
+- return 0;
+-}
+-
+-static pfm_buffer_fmt_t default_fmt={
+- .fmt_name = "default_format",
+- .fmt_uuid = PFM_DEFAULT_SMPL_UUID,
+- .fmt_arg_size = sizeof(pfm_default_smpl_arg_t),
+- .fmt_validate = default_validate,
+- .fmt_getsize = default_get_size,
+- .fmt_init = default_init,
+- .fmt_handler = default_handler,
+- .fmt_restart = default_restart,
+- .fmt_restart_active = default_restart,
+- .fmt_exit = default_exit,
+-};
+-
+-static int __init
+-pfm_default_smpl_init_module(void)
+-{
+- int ret;
+-
+- ret = pfm_register_buffer_fmt(&default_fmt);
+- if (ret == 0) {
+- printk("perfmon_default_smpl: %s v%u.%u registered\n",
+- default_fmt.fmt_name,
+- PFM_DEFAULT_SMPL_VERSION_MAJ,
+- PFM_DEFAULT_SMPL_VERSION_MIN);
+- } else {
+- printk("perfmon_default_smpl: %s cannot register ret=%d\n",
+- default_fmt.fmt_name,
+- ret);
+- }
+-
+- return ret;
+-}
+-
+-static void __exit
+-pfm_default_smpl_cleanup_module(void)
+-{
+- int ret;
+- ret = pfm_unregister_buffer_fmt(default_fmt.fmt_uuid);
+-
+- printk("perfmon_default_smpl: unregister %s=%d\n", default_fmt.fmt_name, ret);
+-}
+-
+-module_init(pfm_default_smpl_init_module);
+-module_exit(pfm_default_smpl_cleanup_module);
+-
+diff --git a/arch/ia64/kernel/perfmon_generic.h b/arch/ia64/kernel/perfmon_generic.h
+deleted file mode 100644
+index 6748947..0000000
+--- a/arch/ia64/kernel/perfmon_generic.h
++++ /dev/null
+@@ -1,45 +0,0 @@
+-/*
+- * This file contains the generic PMU register description tables
+- * and pmc checker used by perfmon.c.
+- *
+- * Copyright (C) 2002-2003 Hewlett Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
+- */
+-
+-static pfm_reg_desc_t pfm_gen_pmc_desc[PMU_MAX_PMCS]={
+-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-static pfm_reg_desc_t pfm_gen_pmd_desc[PMU_MAX_PMDS]={
+-/* pmd0 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+-/* pmd1 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+-/* pmd2 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+-/* pmd3 */ { PFM_REG_NOTIMPL , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}},
+-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-/*
+- * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+- */
+-static pmu_config_t pmu_conf_gen={
+- .pmu_name = "Generic",
+- .pmu_family = 0xff, /* any */
+- .ovfl_val = (1UL << 32) - 1,
+- .num_ibrs = 0, /* does not use */
+- .num_dbrs = 0, /* does not use */
+- .pmd_desc = pfm_gen_pmd_desc,
+- .pmc_desc = pfm_gen_pmc_desc
+-};
+-
+diff --git a/arch/ia64/kernel/perfmon_itanium.h b/arch/ia64/kernel/perfmon_itanium.h
+deleted file mode 100644
+index d1d508a..0000000
+--- a/arch/ia64/kernel/perfmon_itanium.h
++++ /dev/null
+@@ -1,115 +0,0 @@
+-/*
+- * This file contains the Itanium PMU register description tables
+- * and pmc checker used by perfmon.c.
+- *
+- * Copyright (C) 2002-2003 Hewlett Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
+- */
+-static int pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+-
+-static pfm_reg_desc_t pfm_ita_pmc_desc[PMU_MAX_PMCS]={
+-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, -1UL, NULL, NULL, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc8 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc9 */ { PFM_REG_CONFIG , 0, 0xf00000003ffffff8UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc10 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0000000010000000UL, -1UL, NULL, pfm_ita_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc13 */ { PFM_REG_CONFIG , 0, 0x0003ffff00000001UL, -1UL, NULL, pfm_ita_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-static pfm_reg_desc_t pfm_ita_pmd_desc[PMU_MAX_PMDS]={
+-/* pmd0 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+-/* pmd1 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+-/* pmd2 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+-/* pmd3 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+-/* pmd4 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+-/* pmd5 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+-/* pmd6 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+-/* pmd7 */ { PFM_REG_COUNTING, 0, 0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+-/* pmd8 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd9 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd10 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd11 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd12 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd13 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd14 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd15 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd16 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd17 */ { PFM_REG_BUFFER , 0, 0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-static int
+-pfm_ita_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+-{
+- int ret;
+- int is_loaded;
+-
+- /* sanitfy check */
+- if (ctx == NULL) return -EINVAL;
+-
+- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED;
+-
+- /*
+- * we must clear the (instruction) debug registers if pmc13.ta bit is cleared
+- * before they are written (fl_using_dbreg==0) to avoid picking up stale information.
+- */
+- if (cnum == 13 && is_loaded && ((*val & 0x1) == 0UL) && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc[%d]=0x%lx has active pmc13.ta cleared, clearing ibr\n", cnum, *val));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers as in use and also
+- * ensure that they are properly cleared.
+- */
+- ret = pfm_write_ibr_dbr(1, ctx, NULL, 0, regs);
+- if (ret) return ret;
+- }
+-
+- /*
+- * we must clear the (data) debug registers if pmc11.pt bit is cleared
+- * before they are written (fl_using_dbreg==0) to avoid picking up stale information.
+- */
+- if (cnum == 11 && is_loaded && ((*val >> 28)& 0x1) == 0 && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc[%d]=0x%lx has active pmc11.pt cleared, clearing dbr\n", cnum, *val));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers as in use and also
+- * ensure that they are properly cleared.
+- */
+- ret = pfm_write_ibr_dbr(0, ctx, NULL, 0, regs);
+- if (ret) return ret;
+- }
+- return 0;
+-}
+-
+-/*
+- * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+- */
+-static pmu_config_t pmu_conf_ita={
+- .pmu_name = "Itanium",
+- .pmu_family = 0x7,
+- .ovfl_val = (1UL << 32) - 1,
+- .pmd_desc = pfm_ita_pmd_desc,
+- .pmc_desc = pfm_ita_pmc_desc,
+- .num_ibrs = 8,
+- .num_dbrs = 8,
+- .use_rr_dbregs = 1, /* debug register are use for range retrictions */
+-};
+-
+-
+diff --git a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h
+deleted file mode 100644
+index c4bec7a..0000000
+--- a/arch/ia64/kernel/perfmon_mckinley.h
++++ /dev/null
+@@ -1,187 +0,0 @@
+-/*
+- * This file contains the McKinley PMU register description tables
+- * and pmc checker used by perfmon.c.
+- *
+- * Copyright (C) 2002-2003 Hewlett Packard Co
+- * Stephane Eranian <eranian@hpl.hp.com>
+- */
+-static int pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+-
+-static pfm_reg_desc_t pfm_mck_pmc_desc[PMU_MAX_PMCS]={
+-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x1UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x0000000000800000UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(4),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL, pfm_mck_pmc_check, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc8 */ { PFM_REG_CONFIG , 0, 0xffffffff3fffffffUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc9 */ { PFM_REG_CONFIG , 0, 0xffffffff3ffffffcUL, 0xffffffff3ffffffbUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL, pfm_mck_pmc_check, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL, pfm_mck_pmc_check, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc13 */ { PFM_REG_CONFIG , 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc14 */ { PFM_REG_CONFIG , 0, 0x0db60db60db60db6UL, 0x2492UL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+-/* pmc15 */ { PFM_REG_CONFIG , 0, 0x00000000fffffff0UL, 0xfUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-static pfm_reg_desc_t pfm_mck_pmd_desc[PMU_MAX_PMDS]={
+-/* pmd0 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(1),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+-/* pmd1 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(0),0UL, 0UL, 0UL}, {RDEP(10),0UL, 0UL, 0UL}},
+-/* pmd2 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+-/* pmd3 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(17),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(4),0UL, 0UL, 0UL}},
+-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(5),0UL, 0UL, 0UL}},
+-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(6),0UL, 0UL, 0UL}},
+-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0UL, -1UL, NULL, NULL, {0UL,0UL, 0UL, 0UL}, {RDEP(7),0UL, 0UL, 0UL}},
+-/* pmd8 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd9 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd10 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd11 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd12 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd13 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd14 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd15 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(16),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd16 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15),0UL, 0UL, 0UL}, {RDEP(12),0UL, 0UL, 0UL}},
+-/* pmd17 */ { PFM_REG_BUFFER , 0, 0x0UL, -1UL, NULL, NULL, {RDEP(2)|RDEP(3),0UL, 0UL, 0UL}, {RDEP(11),0UL, 0UL, 0UL}},
+- { PFM_REG_END , 0, 0x0UL, -1UL, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-/*
+- * PMC reserved fields must have their power-up values preserved
+- */
+-static int
+-pfm_mck_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+-{
+- unsigned long tmp1, tmp2, ival = *val;
+-
+- /* remove reserved areas from user value */
+- tmp1 = ival & PMC_RSVD_MASK(cnum);
+-
+- /* get reserved fields values */
+- tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+-
+- *val = tmp1 | tmp2;
+-
+- DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n",
+- cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val));
+- return 0;
+-}
+-
+-/*
+- * task can be NULL if the context is unloaded
+- */
+-static int
+-pfm_mck_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+-{
+- int ret = 0, check_case1 = 0;
+- unsigned long val8 = 0, val14 = 0, val13 = 0;
+- int is_loaded;
+-
+- /* first preserve the reserved fields */
+- pfm_mck_reserved(cnum, val, regs);
+-
+- /* sanitfy check */
+- if (ctx == NULL) return -EINVAL;
+-
+- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED;
+-
+- /*
+- * we must clear the debug registers if pmc13 has a value which enable
+- * memory pipeline event constraints. In this case we need to clear the
+- * the debug registers if they have not yet been accessed. This is required
+- * to avoid picking stale state.
+- * PMC13 is "active" if:
+- * one of the pmc13.cfg_dbrpXX field is different from 0x3
+- * AND
+- * at the corresponding pmc13.ena_dbrpXX is set.
+- */
+- DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, *val, ctx->ctx_fl_using_dbreg, is_loaded));
+-
+- if (cnum == 13 && is_loaded
+- && (*val & 0x1e00000000000UL) && (*val & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc[%d]=0x%lx has active pmc13 settings, clearing dbr\n", cnum, *val));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers as in use and also
+- * ensure that they are properly cleared.
+- */
+- ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs);
+- if (ret) return ret;
+- }
+- /*
+- * we must clear the (instruction) debug registers if any pmc14.ibrpX bit is enabled
+- * before they are (fl_using_dbreg==0) to avoid picking up stale information.
+- */
+- if (cnum == 14 && is_loaded && ((*val & 0x2222UL) != 0x2222UL) && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc[%d]=0x%lx has active pmc14 settings, clearing ibr\n", cnum, *val));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers as in use and also
+- * ensure that they are properly cleared.
+- */
+- ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs);
+- if (ret) return ret;
+-
+- }
+-
+- switch(cnum) {
+- case 4: *val |= 1UL << 23; /* force power enable bit */
+- break;
+- case 8: val8 = *val;
+- val13 = ctx->ctx_pmcs[13];
+- val14 = ctx->ctx_pmcs[14];
+- check_case1 = 1;
+- break;
+- case 13: val8 = ctx->ctx_pmcs[8];
+- val13 = *val;
+- val14 = ctx->ctx_pmcs[14];
+- check_case1 = 1;
+- break;
+- case 14: val8 = ctx->ctx_pmcs[8];
+- val13 = ctx->ctx_pmcs[13];
+- val14 = *val;
+- check_case1 = 1;
+- break;
+- }
+- /* check illegal configuration which can produce inconsistencies in tagging
+- * i-side events in L1D and L2 caches
+- */
+- if (check_case1) {
+- ret = ((val13 >> 45) & 0xf) == 0
+- && ((val8 & 0x1) == 0)
+- && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
+- ||(((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
+-
+- if (ret) DPRINT((KERN_DEBUG "perfmon: failure check_case1\n"));
+- }
+-
+- return ret ? -EINVAL : 0;
+-}
+-
+-/*
+- * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+- */
+-static pmu_config_t pmu_conf_mck={
+- .pmu_name = "Itanium 2",
+- .pmu_family = 0x1f,
+- .flags = PFM_PMU_IRQ_RESEND,
+- .ovfl_val = (1UL << 47) - 1,
+- .pmd_desc = pfm_mck_pmd_desc,
+- .pmc_desc = pfm_mck_pmc_desc,
+- .num_ibrs = 8,
+- .num_dbrs = 8,
+- .use_rr_dbregs = 1 /* debug register are use for range restrictions */
+-};
+-
+-
+diff --git a/arch/ia64/kernel/perfmon_montecito.h b/arch/ia64/kernel/perfmon_montecito.h
+deleted file mode 100644
+index 7f8da4c..0000000
+--- a/arch/ia64/kernel/perfmon_montecito.h
++++ /dev/null
+@@ -1,269 +0,0 @@
+-/*
+- * This file contains the Montecito PMU register description tables
+- * and pmc checker used by perfmon.c.
+- *
+- * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
+- * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+- */
+-static int pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs);
+-
+-#define RDEP_MONT_ETB (RDEP(38)|RDEP(39)|RDEP(48)|RDEP(49)|RDEP(50)|RDEP(51)|RDEP(52)|RDEP(53)|RDEP(54)|\
+- RDEP(55)|RDEP(56)|RDEP(57)|RDEP(58)|RDEP(59)|RDEP(60)|RDEP(61)|RDEP(62)|RDEP(63))
+-#define RDEP_MONT_DEAR (RDEP(32)|RDEP(33)|RDEP(36))
+-#define RDEP_MONT_IEAR (RDEP(34)|RDEP(35))
+-
+-static pfm_reg_desc_t pfm_mont_pmc_desc[PMU_MAX_PMCS]={
+-/* pmc0 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc1 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc2 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc3 */ { PFM_REG_CONTROL , 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc4 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(4),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc5 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(5),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc6 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(6),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc7 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(7),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc8 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(8),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc9 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(9),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc10 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(10),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc11 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(11),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc12 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(12),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc13 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(13),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc14 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(14),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc15 */ { PFM_REG_COUNTING, 6, 0x2000000, 0x7c7fff7f, NULL, pfm_mont_pmc_check, {RDEP(15),0, 0, 0}, {0,0, 0, 0}},
+-/* pmc16 */ { PFM_REG_NOTIMPL, },
+-/* pmc17 */ { PFM_REG_NOTIMPL, },
+-/* pmc18 */ { PFM_REG_NOTIMPL, },
+-/* pmc19 */ { PFM_REG_NOTIMPL, },
+-/* pmc20 */ { PFM_REG_NOTIMPL, },
+-/* pmc21 */ { PFM_REG_NOTIMPL, },
+-/* pmc22 */ { PFM_REG_NOTIMPL, },
+-/* pmc23 */ { PFM_REG_NOTIMPL, },
+-/* pmc24 */ { PFM_REG_NOTIMPL, },
+-/* pmc25 */ { PFM_REG_NOTIMPL, },
+-/* pmc26 */ { PFM_REG_NOTIMPL, },
+-/* pmc27 */ { PFM_REG_NOTIMPL, },
+-/* pmc28 */ { PFM_REG_NOTIMPL, },
+-/* pmc29 */ { PFM_REG_NOTIMPL, },
+-/* pmc30 */ { PFM_REG_NOTIMPL, },
+-/* pmc31 */ { PFM_REG_NOTIMPL, },
+-/* pmc32 */ { PFM_REG_CONFIG, 0, 0x30f01ffffffffffUL, 0x30f01ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc33 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc34 */ { PFM_REG_CONFIG, 0, 0xf01ffffffffffUL, 0xf01ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc35 */ { PFM_REG_CONFIG, 0, 0x0, 0x1ffffffffffUL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc36 */ { PFM_REG_CONFIG, 0, 0xfffffff0, 0xf, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc37 */ { PFM_REG_MONITOR, 4, 0x0, 0x3fff, NULL, pfm_mont_pmc_check, {RDEP_MONT_IEAR, 0, 0, 0}, {0, 0, 0, 0}},
+-/* pmc38 */ { PFM_REG_CONFIG, 0, 0xdb6, 0x2492, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc39 */ { PFM_REG_MONITOR, 6, 0x0, 0xffcf, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc40 */ { PFM_REG_MONITOR, 6, 0x2000000, 0xf01cf, NULL, pfm_mont_pmc_check, {RDEP_MONT_DEAR,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc41 */ { PFM_REG_CONFIG, 0, 0x00002078fefefefeUL, 0x1e00018181818UL, NULL, pfm_mont_pmc_check, {0,0, 0, 0}, {0,0, 0, 0}},
+-/* pmc42 */ { PFM_REG_MONITOR, 6, 0x0, 0x7ff4f, NULL, pfm_mont_pmc_check, {RDEP_MONT_ETB,0, 0, 0}, {0,0, 0, 0}},
+- { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-static pfm_reg_desc_t pfm_mont_pmd_desc[PMU_MAX_PMDS]={
+-/* pmd0 */ { PFM_REG_NOTIMPL, },
+-/* pmd1 */ { PFM_REG_NOTIMPL, },
+-/* pmd2 */ { PFM_REG_NOTIMPL, },
+-/* pmd3 */ { PFM_REG_NOTIMPL, },
+-/* pmd4 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(4),0, 0, 0}},
+-/* pmd5 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(5),0, 0, 0}},
+-/* pmd6 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(6),0, 0, 0}},
+-/* pmd7 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(7),0, 0, 0}},
+-/* pmd8 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(8),0, 0, 0}},
+-/* pmd9 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(9),0, 0, 0}},
+-/* pmd10 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(10),0, 0, 0}},
+-/* pmd11 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(11),0, 0, 0}},
+-/* pmd12 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(12),0, 0, 0}},
+-/* pmd13 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(13),0, 0, 0}},
+-/* pmd14 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(14),0, 0, 0}},
+-/* pmd15 */ { PFM_REG_COUNTING, 0, 0x0, -1, NULL, NULL, {0,0, 0, 0}, {RDEP(15),0, 0, 0}},
+-/* pmd16 */ { PFM_REG_NOTIMPL, },
+-/* pmd17 */ { PFM_REG_NOTIMPL, },
+-/* pmd18 */ { PFM_REG_NOTIMPL, },
+-/* pmd19 */ { PFM_REG_NOTIMPL, },
+-/* pmd20 */ { PFM_REG_NOTIMPL, },
+-/* pmd21 */ { PFM_REG_NOTIMPL, },
+-/* pmd22 */ { PFM_REG_NOTIMPL, },
+-/* pmd23 */ { PFM_REG_NOTIMPL, },
+-/* pmd24 */ { PFM_REG_NOTIMPL, },
+-/* pmd25 */ { PFM_REG_NOTIMPL, },
+-/* pmd26 */ { PFM_REG_NOTIMPL, },
+-/* pmd27 */ { PFM_REG_NOTIMPL, },
+-/* pmd28 */ { PFM_REG_NOTIMPL, },
+-/* pmd29 */ { PFM_REG_NOTIMPL, },
+-/* pmd30 */ { PFM_REG_NOTIMPL, },
+-/* pmd31 */ { PFM_REG_NOTIMPL, },
+-/* pmd32 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(33)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}},
+-/* pmd33 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(36),0, 0, 0}, {RDEP(40),0, 0, 0}},
+-/* pmd34 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(35),0, 0, 0}, {RDEP(37),0, 0, 0}},
+-/* pmd35 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(34),0, 0, 0}, {RDEP(37),0, 0, 0}},
+-/* pmd36 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP(32)|RDEP(33),0, 0, 0}, {RDEP(40),0, 0, 0}},
+-/* pmd37 */ { PFM_REG_NOTIMPL, },
+-/* pmd38 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd39 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd40 */ { PFM_REG_NOTIMPL, },
+-/* pmd41 */ { PFM_REG_NOTIMPL, },
+-/* pmd42 */ { PFM_REG_NOTIMPL, },
+-/* pmd43 */ { PFM_REG_NOTIMPL, },
+-/* pmd44 */ { PFM_REG_NOTIMPL, },
+-/* pmd45 */ { PFM_REG_NOTIMPL, },
+-/* pmd46 */ { PFM_REG_NOTIMPL, },
+-/* pmd47 */ { PFM_REG_NOTIMPL, },
+-/* pmd48 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd49 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd50 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd51 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd52 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd53 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd54 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd55 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd56 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd57 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd58 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd59 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd60 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd61 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd62 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+-/* pmd63 */ { PFM_REG_BUFFER, 0, 0x0, -1, NULL, NULL, {RDEP_MONT_ETB,0, 0, 0}, {RDEP(39),0, 0, 0}},
+- { PFM_REG_END , 0, 0x0, -1, NULL, NULL, {0,}, {0,}}, /* end marker */
+-};
+-
+-/*
+- * PMC reserved fields must have their power-up values preserved
+- */
+-static int
+-pfm_mont_reserved(unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+-{
+- unsigned long tmp1, tmp2, ival = *val;
+-
+- /* remove reserved areas from user value */
+- tmp1 = ival & PMC_RSVD_MASK(cnum);
+-
+- /* get reserved fields values */
+- tmp2 = PMC_DFL_VAL(cnum) & ~PMC_RSVD_MASK(cnum);
+-
+- *val = tmp1 | tmp2;
+-
+- DPRINT(("pmc[%d]=0x%lx, mask=0x%lx, reset=0x%lx, val=0x%lx\n",
+- cnum, ival, PMC_RSVD_MASK(cnum), PMC_DFL_VAL(cnum), *val));
+- return 0;
+-}
+-
+-/*
+- * task can be NULL if the context is unloaded
+- */
+-static int
+-pfm_mont_pmc_check(struct task_struct *task, pfm_context_t *ctx, unsigned int cnum, unsigned long *val, struct pt_regs *regs)
+-{
+- int ret = 0;
+- unsigned long val32 = 0, val38 = 0, val41 = 0;
+- unsigned long tmpval;
+- int check_case1 = 0;
+- int is_loaded;
+-
+- /* first preserve the reserved fields */
+- pfm_mont_reserved(cnum, val, regs);
+-
+- tmpval = *val;
+-
+- /* sanity check */
+- if (ctx == NULL) return -EINVAL;
+-
+- is_loaded = ctx->ctx_state == PFM_CTX_LOADED || ctx->ctx_state == PFM_CTX_MASKED;
+-
+- /*
+- * we must clear the debug registers if pmc41 has a value which enable
+- * memory pipeline event constraints. In this case we need to clear the
+- * the debug registers if they have not yet been accessed. This is required
+- * to avoid picking stale state.
+- * PMC41 is "active" if:
+- * one of the pmc41.cfg_dtagXX field is different from 0x3
+- * AND
+- * at the corresponding pmc41.en_dbrpXX is set.
+- * AND
+- * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used)
+- */
+- DPRINT(("cnum=%u val=0x%lx, using_dbreg=%d loaded=%d\n", cnum, tmpval, ctx->ctx_fl_using_dbreg, is_loaded));
+-
+- if (cnum == 41 && is_loaded
+- && (tmpval & 0x1e00000000000UL) && (tmpval & 0x18181818UL) != 0x18181818UL && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc[%d]=0x%lx has active pmc41 settings, clearing dbr\n", cnum, tmpval));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers if:
+- * AND
+- */
+- ret = pfm_write_ibr_dbr(PFM_DATA_RR, ctx, NULL, 0, regs);
+- if (ret) return ret;
+- }
+- /*
+- * we must clear the (instruction) debug registers if:
+- * pmc38.ig_ibrpX is 0 (enabled)
+- * AND
+- * ctx_fl_using_dbreg == 0 (i.e., dbr not yet used)
+- */
+- if (cnum == 38 && is_loaded && ((tmpval & 0x492UL) != 0x492UL) && ctx->ctx_fl_using_dbreg == 0) {
+-
+- DPRINT(("pmc38=0x%lx has active pmc38 settings, clearing ibr\n", tmpval));
+-
+- /* don't mix debug with perfmon */
+- if (task && (task->thread.flags & IA64_THREAD_DBG_VALID) != 0) return -EINVAL;
+-
+- /*
+- * a count of 0 will mark the debug registers as in use and also
+- * ensure that they are properly cleared.
+- */
+- ret = pfm_write_ibr_dbr(PFM_CODE_RR, ctx, NULL, 0, regs);
+- if (ret) return ret;
+-
+- }
+- switch(cnum) {
+- case 32: val32 = *val;
+- val38 = ctx->ctx_pmcs[38];
+- val41 = ctx->ctx_pmcs[41];
+- check_case1 = 1;
+- break;
+- case 38: val38 = *val;
+- val32 = ctx->ctx_pmcs[32];
+- val41 = ctx->ctx_pmcs[41];
+- check_case1 = 1;
+- break;
+- case 41: val41 = *val;
+- val32 = ctx->ctx_pmcs[32];
+- val38 = ctx->ctx_pmcs[38];
+- check_case1 = 1;
+- break;
+- }
+- /* check illegal configuration which can produce inconsistencies in tagging
+- * i-side events in L1D and L2 caches
+- */
+- if (check_case1) {
+- ret = (((val41 >> 45) & 0xf) == 0 && ((val32>>57) & 0x1) == 0)
+- && ((((val38>>1) & 0x3) == 0x2 || ((val38>>1) & 0x3) == 0)
+- || (((val38>>4) & 0x3) == 0x2 || ((val38>>4) & 0x3) == 0));
+- if (ret) {
+- DPRINT(("invalid config pmc38=0x%lx pmc41=0x%lx pmc32=0x%lx\n", val38, val41, val32));
+- return -EINVAL;
+- }
+- }
+- *val = tmpval;
+- return 0;
+-}
+-
+-/*
+- * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
+- */
+-static pmu_config_t pmu_conf_mont={
+- .pmu_name = "Montecito",
+- .pmu_family = 0x20,
+- .flags = PFM_PMU_IRQ_RESEND,
+- .ovfl_val = (1UL << 47) - 1,
+- .pmd_desc = pfm_mont_pmd_desc,
+- .pmc_desc = pfm_mont_pmc_desc,
+- .num_ibrs = 8,
+- .num_dbrs = 8,
+- .use_rr_dbregs = 1 /* debug register are use for range retrictions */
+-};
+diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
+index 3ab8373..a7dfb39 100644
+--- a/arch/ia64/kernel/process.c
++++ b/arch/ia64/kernel/process.c
+@@ -28,6 +28,7 @@
+ #include <linux/delay.h>
+ #include <linux/kdebug.h>
+ #include <linux/utsname.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/cpu.h>
+ #include <asm/delay.h>
+@@ -45,10 +46,6 @@
+
+ #include "entry.h"
+
+-#ifdef CONFIG_PERFMON
+-# include <asm/perfmon.h>
+-#endif
+-
+ #include "sigframe.h"
+
+ void (*ia64_mark_idle)(int);
+@@ -162,10 +159,8 @@ show_regs (struct pt_regs *regs)
+
+ void tsk_clear_notify_resume(struct task_struct *tsk)
+ {
+-#ifdef CONFIG_PERFMON
+- if (tsk->thread.pfm_needs_checking)
++ if (test_ti_thread_flag(task_thread_info(tsk), TIF_PERFMON_WORK))
+ return;
+-#endif
+ if (test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_RSE))
+ return;
+ clear_ti_thread_flag(task_thread_info(tsk), TIF_NOTIFY_RESUME);
+@@ -188,14 +183,9 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
+ return;
+ }
+
+-#ifdef CONFIG_PERFMON
+- if (current->thread.pfm_needs_checking)
+- /*
+- * Note: pfm_handle_work() allow us to call it with interrupts
+- * disabled, and may enable interrupts within the function.
+- */
+- pfm_handle_work();
+-#endif
++ /* process perfmon asynchronous work (e.g. block thread or reset) */
++ if (test_thread_flag(TIF_PERFMON_WORK))
++ pfm_handle_work(task_pt_regs(current));
+
+ /* deal with pending signal delivery */
+ if (test_thread_flag(TIF_SIGPENDING)) {
+@@ -212,22 +202,15 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall)
+ local_irq_disable(); /* force interrupt disable */
+ }
+
+-static int pal_halt = 1;
+ static int can_do_pal_halt = 1;
+
+ static int __init nohalt_setup(char * str)
+ {
+- pal_halt = can_do_pal_halt = 0;
++ can_do_pal_halt = 0;
+ return 1;
+ }
+ __setup("nohalt", nohalt_setup);
+
+-void
+-update_pal_halt_status(int status)
+-{
+- can_do_pal_halt = pal_halt && status;
+-}
+-
+ /*
+ * We use this if we don't have any better idle routine..
+ */
+@@ -236,6 +219,22 @@ default_idle (void)
+ {
+ local_irq_enable();
+ while (!need_resched()) {
++#ifdef CONFIG_PERFMON
++ u64 psr = 0;
++ /*
++ * If requested, we stop the PMU to avoid
++ * measuring across the core idle loop.
++ *
++ * dcr.pp is not modified on purpose
++ * it is used when coming out of
++ * safe_halt() via interrupt
++ */
++ if ((__get_cpu_var(pfm_syst_info) & PFM_ITA_CPUINFO_IDLE_EXCL)) {
++ psr = ia64_getreg(_IA64_REG_PSR);
++ if (psr & IA64_PSR_PP)
++ ia64_rsm(IA64_PSR_PP);
++ }
++#endif
+ if (can_do_pal_halt) {
+ local_irq_disable();
+ if (!need_resched()) {
+@@ -244,6 +243,12 @@ default_idle (void)
+ local_irq_enable();
+ } else
+ cpu_relax();
++#ifdef CONFIG_PERFMON
++ if ((__get_cpu_var(pfm_syst_info) & PFM_ITA_CPUINFO_IDLE_EXCL)) {
++ if (psr & IA64_PSR_PP)
++ ia64_ssm(IA64_PSR_PP);
++ }
++#endif
+ }
+ }
+
+@@ -344,22 +349,9 @@ cpu_idle (void)
+ void
+ ia64_save_extra (struct task_struct *task)
+ {
+-#ifdef CONFIG_PERFMON
+- unsigned long info;
+-#endif
+-
+ if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
+ ia64_save_debug_regs(&task->thread.dbr[0]);
+
+-#ifdef CONFIG_PERFMON
+- if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
+- pfm_save_regs(task);
+-
+- info = __get_cpu_var(pfm_syst_info);
+- if (info & PFM_CPUINFO_SYST_WIDE)
+- pfm_syst_wide_update_task(task, info, 0);
+-#endif
+-
+ #ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(task_pt_regs(task)))
+ ia32_save_state(task);
+@@ -369,22 +361,9 @@ ia64_save_extra (struct task_struct *task)
+ void
+ ia64_load_extra (struct task_struct *task)
+ {
+-#ifdef CONFIG_PERFMON
+- unsigned long info;
+-#endif
+-
+ if ((task->thread.flags & IA64_THREAD_DBG_VALID) != 0)
+ ia64_load_debug_regs(&task->thread.dbr[0]);
+
+-#ifdef CONFIG_PERFMON
+- if ((task->thread.flags & IA64_THREAD_PM_VALID) != 0)
+- pfm_load_regs(task);
+-
+- info = __get_cpu_var(pfm_syst_info);
+- if (info & PFM_CPUINFO_SYST_WIDE)
+- pfm_syst_wide_update_task(task, info, 1);
+-#endif
+-
+ #ifdef CONFIG_IA32_SUPPORT
+ if (IS_IA32_PROCESS(task_pt_regs(task)))
+ ia32_load_state(task);
+@@ -510,8 +489,7 @@ copy_thread (int nr, unsigned long clone_flags,
+ * call behavior where scratch registers are preserved across
+ * system calls (unless used by the system call itself).
+ */
+-# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID \
+- | IA64_THREAD_PM_VALID)
++# define THREAD_FLAGS_TO_CLEAR (IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID)
+ # define THREAD_FLAGS_TO_SET 0
+ p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
+ | THREAD_FLAGS_TO_SET);
+@@ -533,10 +511,8 @@ copy_thread (int nr, unsigned long clone_flags,
+ }
+ #endif
+
+-#ifdef CONFIG_PERFMON
+- if (current->thread.pfm_context)
+- pfm_inherit(p, child_ptregs);
+-#endif
++ pfm_copy_thread(p);
++
+ return retval;
+ }
+
+@@ -745,15 +721,13 @@ exit_thread (void)
+ {
+
+ ia64_drop_fpu(current);
+-#ifdef CONFIG_PERFMON
+- /* if needed, stop monitoring and flush state to perfmon context */
+- if (current->thread.pfm_context)
+- pfm_exit_thread(current);
++
++ /* if needed, stop monitoring and flush state to perfmon context */
++ pfm_exit_thread();
+
+ /* free debug register resources */
+- if (current->thread.flags & IA64_THREAD_DBG_VALID)
+- pfm_release_debug_registers(current);
+-#endif
++ pfm_release_dbregs(current);
++
+ if (IS_IA32_PROCESS(task_pt_regs(current)))
+ ia32_drop_ia64_partial_page_list(current);
+ }
+diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
+index 2a9943b..bb1ca1e 100644
+--- a/arch/ia64/kernel/ptrace.c
++++ b/arch/ia64/kernel/ptrace.c
+@@ -20,6 +20,7 @@
+ #include <linux/security.h>
+ #include <linux/audit.h>
+ #include <linux/signal.h>
++#include <linux/perfmon_kern.h>
+ #include <linux/regset.h>
+ #include <linux/elf.h>
+
+@@ -30,9 +31,6 @@
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
+ #include <asm/unwind.h>
+-#ifdef CONFIG_PERFMON
+-#include <asm/perfmon.h>
+-#endif
+
+ #include "entry.h"
+
+@@ -2124,7 +2122,6 @@ access_uarea(struct task_struct *child, unsigned long addr,
+ "address 0x%lx\n", addr);
+ return -1;
+ }
+-#ifdef CONFIG_PERFMON
+ /*
+ * Check if debug registers are used by perfmon. This
+ * test must be done once we know that we can do the
+@@ -2142,9 +2139,8 @@ access_uarea(struct task_struct *child, unsigned long addr,
+ * IA64_THREAD_DBG_VALID. The registers are restored
+ * by the PMU context switch code.
+ */
+- if (pfm_use_debug_registers(child))
++ if (pfm_use_dbregs(child))
+ return -1;
+-#endif
+
+ if (!(child->thread.flags & IA64_THREAD_DBG_VALID)) {
+ child->thread.flags |= IA64_THREAD_DBG_VALID;
+diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
+index de636b2..677fa68 100644
+--- a/arch/ia64/kernel/setup.c
++++ b/arch/ia64/kernel/setup.c
+@@ -45,6 +45,7 @@
+ #include <linux/cpufreq.h>
+ #include <linux/kexec.h>
+ #include <linux/crash_dump.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/ia32.h>
+ #include <asm/machvec.h>
+@@ -1051,6 +1052,8 @@ cpu_init (void)
+ }
+ platform_cpu_init();
+ pm_idle = default_idle;
++
++ pfm_init_percpu();
+ }
+
+ void __init
+diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
+index d8f05e5..3d7a739 100644
+--- a/arch/ia64/kernel/smpboot.c
++++ b/arch/ia64/kernel/smpboot.c
+@@ -39,6 +39,7 @@
+ #include <linux/efi.h>
+ #include <linux/percpu.h>
+ #include <linux/bitops.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/atomic.h>
+ #include <asm/cache.h>
+@@ -381,10 +382,6 @@ smp_callin (void)
+ extern void ia64_init_itm(void);
+ extern volatile int time_keeper_id;
+
+-#ifdef CONFIG_PERFMON
+- extern void pfm_init_percpu(void);
+-#endif
+-
+ cpuid = smp_processor_id();
+ phys_id = hard_smp_processor_id();
+ itc_master = time_keeper_id;
+@@ -410,10 +407,6 @@ smp_callin (void)
+
+ ia64_mca_cmc_vector_setup(); /* Setup vector on AP */
+
+-#ifdef CONFIG_PERFMON
+- pfm_init_percpu();
+-#endif
+-
+ local_irq_enable();
+
+ if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
+@@ -751,6 +744,7 @@ int __cpu_disable(void)
+ cpu_clear(cpu, cpu_online_map);
+ local_flush_tlb_all();
+ cpu_clear(cpu, cpu_callin_map);
++ pfm_cpu_disable();
+ return 0;
+ }
+
+diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c
+index bcbb6d8..a0ed33a 100644
+--- a/arch/ia64/kernel/sys_ia64.c
++++ b/arch/ia64/kernel/sys_ia64.c
+@@ -284,3 +284,11 @@ sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, un
+ }
+
+ #endif /* CONFIG_PCI */
++
++#ifndef CONFIG_IA64_PERFMON_COMPAT
++asmlinkage long
++sys_perfmonctl (int fd, int cmd, void __user *arg, int count)
++{
++ return -ENOSYS;
++}
++#endif
+diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile
+index 98771e2..077fd09 100644
+--- a/arch/ia64/lib/Makefile
++++ b/arch/ia64/lib/Makefile
+@@ -13,7 +13,6 @@ lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \
+
+ obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o
+ obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o
+-lib-$(CONFIG_PERFMON) += carta_random.o
+
+ AFLAGS___divdi3.o =
+ AFLAGS___udivdi3.o = -DUNSIGNED
+diff --git a/arch/ia64/oprofile/init.c b/arch/ia64/oprofile/init.c
+index 125a602..892de6a 100644
+--- a/arch/ia64/oprofile/init.c
++++ b/arch/ia64/oprofile/init.c
+@@ -12,8 +12,8 @@
+ #include <linux/init.h>
+ #include <linux/errno.h>
+
+-extern int perfmon_init(struct oprofile_operations * ops);
+-extern void perfmon_exit(void);
++extern int op_perfmon_init(struct oprofile_operations * ops);
++extern void op_perfmon_exit(void);
+ extern void ia64_backtrace(struct pt_regs * const regs, unsigned int depth);
+
+ int __init oprofile_arch_init(struct oprofile_operations * ops)
+@@ -22,7 +22,7 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
+
+ #ifdef CONFIG_PERFMON
+ /* perfmon_init() can fail, but we have no way to report it */
+- ret = perfmon_init(ops);
++ ret = op_perfmon_init(ops);
+ #endif
+ ops->backtrace = ia64_backtrace;
+
+@@ -33,6 +33,6 @@ int __init oprofile_arch_init(struct oprofile_operations * ops)
+ void oprofile_arch_exit(void)
+ {
+ #ifdef CONFIG_PERFMON
+- perfmon_exit();
++ op_perfmon_exit();
+ #endif
+ }
+diff --git a/arch/ia64/oprofile/perfmon.c b/arch/ia64/oprofile/perfmon.c
+index bc41dd3..6fa9d17 100644
+--- a/arch/ia64/oprofile/perfmon.c
++++ b/arch/ia64/oprofile/perfmon.c
+@@ -10,25 +10,30 @@
+ #include <linux/kernel.h>
+ #include <linux/oprofile.h>
+ #include <linux/sched.h>
+-#include <asm/perfmon.h>
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
+ #include <asm/ptrace.h>
+ #include <asm/errno.h>
+
+ static int allow_ints;
+
+ static int
+-perfmon_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
+- struct pt_regs *regs, unsigned long stamp)
++perfmon_handler(struct pfm_context *ctx,
++ unsigned long ip, u64 stamp, void *data)
+ {
+- int event = arg->pmd_eventid;
++ struct pt_regs *regs;
++ struct pfm_ovfl_arg *arg;
++
++ regs = data;
++ arg = &ctx->ovfl_arg;
+
+- arg->ovfl_ctrl.bits.reset_ovfl_pmds = 1;
++ arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET;
+
+ /* the owner of the oprofile event buffer may have exited
+ * without perfmon being shutdown (e.g. SIGSEGV)
+ */
+ if (allow_ints)
+- oprofile_add_sample(regs, event);
++ oprofile_add_sample(regs, arg->pmd_eventid);
+ return 0;
+ }
+
+@@ -45,17 +50,13 @@ static void perfmon_stop(void)
+ allow_ints = 0;
+ }
+
+-
+-#define OPROFILE_FMT_UUID { \
+- 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69, 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c }
+-
+-static pfm_buffer_fmt_t oprofile_fmt = {
+- .fmt_name = "oprofile_format",
+- .fmt_uuid = OPROFILE_FMT_UUID,
+- .fmt_handler = perfmon_handler,
++static struct pfm_smpl_fmt oprofile_fmt = {
++ .fmt_name = "OProfile",
++ .fmt_handler = perfmon_handler,
++ .fmt_flags = PFM_FMT_BUILTIN_FLAG,
++ .owner = THIS_MODULE
+ };
+
+-
+ static char * get_cpu_type(void)
+ {
+ __u8 family = local_cpu_data->family;
+@@ -75,9 +76,9 @@ static char * get_cpu_type(void)
+
+ static int using_perfmon;
+
+-int perfmon_init(struct oprofile_operations * ops)
++int __init op_perfmon_init(struct oprofile_operations * ops)
+ {
+- int ret = pfm_register_buffer_fmt(&oprofile_fmt);
++ int ret = pfm_fmt_register(&oprofile_fmt);
+ if (ret)
+ return -ENODEV;
+
+@@ -90,10 +91,10 @@ int perfmon_init(struct oprofile_operations * ops)
+ }
+
+
+-void perfmon_exit(void)
++void __exit op_perfmon_exit(void)
+ {
+ if (!using_perfmon)
+ return;
+
+- pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid);
++ pfm_fmt_unregister(&oprofile_fmt);
+ }
+diff --git a/arch/ia64/perfmon/Kconfig b/arch/ia64/perfmon/Kconfig
+new file mode 100644
+index 0000000..99c68bd
+--- /dev/null
++++ b/arch/ia64/perfmon/Kconfig
+@@ -0,0 +1,67 @@
++menu "Hardware Performance Monitoring support"
++config PERFMON
++ bool "Perfmon2 performance monitoring interface"
++ default n
++ help
++ Enables the perfmon2 interface to access the hardware
++ performance counters. See <http://perfmon2.sf.net/> for
++ more details.
++
++config PERFMON_DEBUG
++ bool "Perfmon debugging"
++ default n
++ depends on PERFMON
++ help
++ Enables perfmon debugging support
++
++config PERFMON_DEBUG_FS
++ bool "Enable perfmon statistics reporting via debugfs"
++ default y
++ depends on PERFMON && DEBUG_FS
++ help
++ Enable collection and reporting of perfmon timing statistics under
++ debugfs. This is used for debugging and performance analysis of the
++ subsystem. The debugfs filesystem must be mounted.
++
++config IA64_PERFMON_COMPAT
++ bool "Enable old perfmon-2 compatbility mode"
++ default n
++ depends on PERFMON
++ help
++ Enable this option to allow performance tools which used the old
++ perfmon-2 interface to continue to work. Old tools are those using
++ the obsolete commands and arguments. Check your programs and look
++ in include/asm-ia64/perfmon_compat.h for more information.
++
++config IA64_PERFMON_GENERIC
++ tristate "Generic IA-64 PMU support"
++ depends on PERFMON
++ default n
++ help
++ Enables generic IA-64 PMU support.
++ The generic PMU is defined by the IA-64 architecture document.
++ This option should only be necessary when running with a PMU that
++ is not yet explicitely supported. Even then, there is no guarantee
++ that this support will work.
++
++config IA64_PERFMON_ITANIUM
++ tristate "Itanium (Merced) Performance Monitoring support"
++ depends on PERFMON
++ default n
++ help
++ Enables Itanium (Merced) PMU support.
++
++config IA64_PERFMON_MCKINLEY
++ tristate "Itanium 2 (McKinley) Performance Monitoring support"
++ depends on PERFMON
++ default n
++ help
++ Enables Itanium 2 (McKinley, Madison, Deerfield) PMU support.
++
++config IA64_PERFMON_MONTECITO
++ tristate "Itanium 2 9000 (Montecito) Performance Monitoring support"
++ depends on PERFMON
++ default n
++ help
++ Enables support for Itanium 2 9000 (Montecito) PMU.
++endmenu
+diff --git a/arch/ia64/perfmon/Makefile b/arch/ia64/perfmon/Makefile
+new file mode 100644
+index 0000000..c9cdf9f
+--- /dev/null
++++ b/arch/ia64/perfmon/Makefile
+@@ -0,0 +1,11 @@
++#
++# Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
++# Contributed by Stephane Eranian <eranian@hpl.hp.com>
++#
++obj-$(CONFIG_PERFMON) += perfmon.o
++obj-$(CONFIG_IA64_PERFMON_COMPAT) += perfmon_default_smpl.o \
++ perfmon_compat.o
++obj-$(CONFIG_IA64_PERFMON_GENERIC) += perfmon_generic.o
++obj-$(CONFIG_IA64_PERFMON_ITANIUM) += perfmon_itanium.o
++obj-$(CONFIG_IA64_PERFMON_MCKINLEY) += perfmon_mckinley.o
++obj-$(CONFIG_IA64_PERFMON_MONTECITO) += perfmon_montecito.o
+diff --git a/arch/ia64/perfmon/perfmon.c b/arch/ia64/perfmon/perfmon.c
+new file mode 100644
+index 0000000..3f59410
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon.c
+@@ -0,0 +1,946 @@
++/*
++ * This file implements the IA-64 specific
++ * support for the perfmon2 interface
++ *
++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++
++struct pfm_arch_session {
++ u32 pfs_sys_use_dbr; /* syswide session uses dbr */
++ u32 pfs_ptrace_use_dbr; /* a thread uses dbr via ptrace()*/
++};
++
++DEFINE_PER_CPU(u32, pfm_syst_info);
++
++static struct pfm_arch_session pfm_arch_sessions;
++static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pfm_arch_sessions_lock);
++
++static inline void pfm_clear_psr_pp(void)
++{
++ ia64_rsm(IA64_PSR_PP);
++}
++
++static inline void pfm_set_psr_pp(void)
++{
++ ia64_ssm(IA64_PSR_PP);
++}
++
++static inline void pfm_clear_psr_up(void)
++{
++ ia64_rsm(IA64_PSR_UP);
++}
++
++static inline void pfm_set_psr_up(void)
++{
++ ia64_ssm(IA64_PSR_UP);
++}
++
++static inline void pfm_set_psr_l(u64 val)
++{
++ ia64_setreg(_IA64_REG_PSR_L, val);
++}
++
++static inline void pfm_restore_ibrs(u64 *ibrs, unsigned int nibrs)
++{
++ unsigned int i;
++
++ for (i = 0; i < nibrs; i++) {
++ ia64_set_ibr(i, ibrs[i]);
++ ia64_dv_serialize_instruction();
++ }
++ ia64_srlz_i();
++}
++
++static inline void pfm_restore_dbrs(u64 *dbrs, unsigned int ndbrs)
++{
++ unsigned int i;
++
++ for (i = 0; i < ndbrs; i++) {
++ ia64_set_dbr(i, dbrs[i]);
++ ia64_dv_serialize_data();
++ }
++ ia64_srlz_d();
++}
++
++irqreturn_t pmu_interrupt_handler(int irq, void *arg)
++{
++ struct pt_regs *regs;
++ regs = get_irq_regs();
++ irq_enter();
++ pfm_interrupt_handler(instruction_pointer(regs), regs);
++ irq_exit();
++ return IRQ_HANDLED;
++}
++static struct irqaction perfmon_irqaction = {
++ .handler = pmu_interrupt_handler,
++ .flags = IRQF_DISABLED, /* means keep interrupts masked */
++ .name = "perfmon"
++};
++
++void pfm_arch_quiesce_pmu_percpu(void)
++{
++ u64 dcr;
++ /*
++ * make sure no measurement is active
++ * (may inherit programmed PMCs from EFI).
++ */
++ pfm_clear_psr_pp();
++ pfm_clear_psr_up();
++
++ /*
++ * ensure dcr.pp is cleared
++ */
++ dcr = ia64_getreg(_IA64_REG_CR_DCR);
++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP);
++
++ /*
++ * we run with the PMU not frozen at all times
++ */
++ ia64_set_pmc(0, 0);
++ ia64_srlz_d();
++}
++
++void pfm_arch_init_percpu(void)
++{
++ pfm_arch_quiesce_pmu_percpu();
++ /*
++ * program PMU interrupt vector
++ */
++ ia64_setreg(_IA64_REG_CR_PMV, IA64_PERFMON_VECTOR);
++ ia64_srlz_d();
++}
++
++int pfm_arch_context_create(struct pfm_context *ctx, u32 ctx_flags)
++{
++ struct pfm_arch_context *ctx_arch;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ ctx_arch->flags.use_dbr = 0;
++ ctx_arch->flags.insecure = (ctx_flags & PFM_ITA_FL_INSECURE) ? 1: 0;
++
++ PFM_DBG("insecure=%d", ctx_arch->flags.insecure);
++
++ return 0;
++}
++
++/*
++ * Called from pfm_ctxsw(). Task is guaranteed to be current.
++ * Context is locked. Interrupts are masked. Monitoring may be active.
++ * PMU access is guaranteed. PMC and PMD registers are live in PMU.
++ *
++ * Return:
++ * non-zero : did not save PMDs (as part of stopping the PMU)
++ * 0 : saved PMDs (no need to save them in caller)
++ */
++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pfm_event_set *set;
++ u64 psr, tmp;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ set = ctx->active_set;
++
++ /*
++ * save current PSR: needed because we modify it
++ */
++ ia64_srlz_d();
++ psr = ia64_getreg(_IA64_REG_PSR);
++
++ /*
++ * stop monitoring:
++ * This is the last instruction which may generate an overflow
++ *
++ * we do not clear ipsr.up
++ */
++ pfm_clear_psr_up();
++ ia64_srlz_d();
++
++ /*
++ * extract overflow status bits
++ */
++ tmp = ia64_get_pmc(0) & ~0xf;
++
++ /*
++ * keep a copy of psr.up (for reload)
++ */
++ ctx_arch->ctx_saved_psr_up = psr & IA64_PSR_UP;
++
++ /*
++ * save overflow status bits
++ */
++ set->povfl_pmds[0] = tmp;
++
++ /*
++ * record how many pending overflows
++ * XXX: assume identity mapping for counters
++ */
++ set->npend_ovfls = ia64_popcnt(tmp);
++
++ /*
++ * make sure the PMU is unfrozen for the next task
++ */
++ if (set->npend_ovfls) {
++ ia64_set_pmc(0, 0);
++ ia64_srlz_d();
++ }
++ return 1;
++}
++
++/*
++ * Called from pfm_ctxsw(). Task is guaranteed to be current.
++ * set cannot be NULL. Context is locked. Interrupts are masked.
++ * Caller has already restored all PMD and PMC registers.
++ *
++ * must reactivate monitoring
++ */
++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ /*
++ * when monitoring is not explicitly started
++ * then psr_up = 0, in which case we do not
++ * need to restore
++ */
++ if (likely(ctx_arch->ctx_saved_psr_up)) {
++ pfm_set_psr_up();
++ ia64_srlz_d();
++ }
++}
++
++int pfm_arch_reserve_session(struct pfm_context *ctx, u32 cpu)
++{
++ struct pfm_arch_context *ctx_arch;
++ int is_system;
++ int ret = 0;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ is_system = ctx->flags.system;
++
++ spin_lock(&pfm_arch_sessions_lock);
++
++ if (is_system && ctx_arch->flags.use_dbr) {
++ PFM_DBG("syswide context uses dbregs");
++
++ if (pfm_arch_sessions.pfs_ptrace_use_dbr) {
++ PFM_DBG("cannot reserve syswide context: "
++ "dbregs in use by ptrace");
++ ret = -EBUSY;
++ } else {
++ pfm_arch_sessions.pfs_sys_use_dbr++;
++ }
++ }
++ spin_unlock(&pfm_arch_sessions_lock);
++
++ return ret;
++}
++
++void pfm_arch_release_session(struct pfm_context *ctx, u32 cpu)
++{
++ struct pfm_arch_context *ctx_arch;
++ int is_system;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ is_system = ctx->flags.system;
++
++ spin_lock(&pfm_arch_sessions_lock);
++
++ if (is_system && ctx_arch->flags.use_dbr)
++ pfm_arch_sessions.pfs_sys_use_dbr--;
++ spin_unlock(&pfm_arch_sessions_lock);
++}
++
++/*
++ * function called from pfm_load_context_*(). Task is not guaranteed to be
++ * current task. If not then other task is guaranteed stopped and off any CPU.
++ * context is locked and interrupts are masked.
++ *
++ * On PFM_LOAD_CONTEXT, the interface guarantees monitoring is stopped.
++ *
++ * For system-wide task is NULL
++ */
++int pfm_arch_load_context(struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pt_regs *regs;
++ int ret = 0;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ /*
++ * cannot load a context which is using range restrictions,
++ * into a thread that is being debugged.
++ *
++ * if one set out of several is using the debug registers, then
++ * we assume the context as whole is using them.
++ */
++ if (ctx_arch->flags.use_dbr) {
++ if (ctx->flags.system) {
++ spin_lock(&pfm_arch_sessions_lock);
++
++ if (pfm_arch_sessions.pfs_ptrace_use_dbr) {
++ PFM_DBG("cannot reserve syswide context: "
++ "dbregs in use by ptrace");
++ ret = -EBUSY;
++ } else {
++ pfm_arch_sessions.pfs_sys_use_dbr++;
++ PFM_DBG("pfs_sys_use_dbr=%u",
++ pfm_arch_sessions.pfs_sys_use_dbr);
++ }
++ spin_unlock(&pfm_arch_sessions_lock);
++
++ } else if (ctx->task->thread.flags & IA64_THREAD_DBG_VALID) {
++ PFM_DBG("load_pid [%d] thread is debugged, cannot "
++ "use range restrictions", ctx->task->pid);
++ ret = -EBUSY;
++ }
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * We need to intervene on context switch to toggle the
++ * psr.pp bit in system-wide. As such, we set the TIF
++ * flag so that pfm_arch_ctxswout_sys() and the
++ * pfm_arch_ctxswin_sys() functions get called
++ * from pfm_ctxsw_sys();
++ */
++ if (ctx->flags.system) {
++ set_thread_flag(TIF_PERFMON_CTXSW);
++ PFM_DBG("[%d] set TIF", current->pid);
++ return 0;
++ }
++
++ regs = task_pt_regs(ctx->task);
++
++ /*
++ * self-monitoring systematically allows user level control
++ */
++ if (ctx->task != current) {
++ /*
++ * when not current, task is stopped, so this is safe
++ */
++ ctx_arch->ctx_saved_psr_up = 0;
++ ia64_psr(regs)->up = ia64_psr(regs)->pp = 0;
++ } else
++ ctx_arch->flags.insecure = 1;
++
++ /*
++ * allow user level control (start/stop/read pmd) if:
++ * - self-monitoring
++ * - requested at context creation (PFM_IA64_FL_INSECURE)
++ *
++ * There is not security hole with PFM_IA64_FL_INSECURE because
++ * when not self-monitored, the caller must have permissions to
++ * attached to the task.
++ */
++ if (ctx_arch->flags.insecure) {
++ ia64_psr(regs)->sp = 0;
++ PFM_DBG("clearing psr.sp for [%d]", ctx->task->pid);
++ }
++ return 0;
++}
++
++int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags)
++{
++#define PFM_SETFL_BOTH_SWITCH (PFM_SETFL_OVFL_SWITCH|PFM_SETFL_TIME_SWITCH)
++#define PFM_ITA_SETFL_BOTH_INTR (PFM_ITA_SETFL_INTR_ONLY|\
++ PFM_ITA_SETFL_EXCL_INTR)
++
++/* exclude return value field */
++#define PFM_SETFL_ALL_MASK (PFM_ITA_SETFL_BOTH_INTR \
++ | PFM_SETFL_BOTH_SWITCH \
++ | PFM_ITA_SETFL_IDLE_EXCL)
++
++ if ((flags & ~PFM_SETFL_ALL_MASK)) {
++ PFM_DBG("invalid flags=0x%x", flags);
++ return -EINVAL;
++ }
++
++ if ((flags & PFM_ITA_SETFL_BOTH_INTR) == PFM_ITA_SETFL_BOTH_INTR) {
++ PFM_DBG("both excl intr and ontr only are set");
++ return -EINVAL;
++ }
++
++ if ((flags & PFM_ITA_SETFL_IDLE_EXCL) && !ctx->flags.system) {
++ PFM_DBG("idle exclude flag only for system-wide context");
++ return -EINVAL;
++ }
++ return 0;
++}
++
++/*
++ * function called from pfm_unload_context_*(). Context is locked.
++ * interrupts are masked. task is not guaranteed to be current task.
++ * Access to PMU is not guaranteed.
++ *
++ * function must do whatever arch-specific action is required on unload
++ * of a context.
++ *
++ * called for both system-wide and per-thread. task is NULL for ssytem-wide
++ */
++void pfm_arch_unload_context(struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pt_regs *regs;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ if (ctx->flags.system) {
++ /*
++ * disable context switch hook
++ */
++ clear_thread_flag(TIF_PERFMON_CTXSW);
++
++ if (ctx_arch->flags.use_dbr) {
++ spin_lock(&pfm_arch_sessions_lock);
++ pfm_arch_sessions.pfs_sys_use_dbr--;
++ PFM_DBG("sys_use_dbr=%u", pfm_arch_sessions.pfs_sys_use_dbr);
++ spin_unlock(&pfm_arch_sessions_lock);
++ }
++ } else {
++ regs = task_pt_regs(ctx->task);
++
++ /*
++ * cancel user level control for per-task context
++ */
++ ia64_psr(regs)->sp = 1;
++ PFM_DBG("setting psr.sp for [%d]", ctx->task->pid);
++ }
++}
++
++/*
++ * mask monitoring by setting the privilege level to 0
++ * we cannot use psr.pp/psr.up for this, it is controlled by
++ * the user
++ */
++void pfm_arch_mask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ unsigned long mask;
++ unsigned int i;
++
++ arch_info = pfm_pmu_info();
++ /*
++ * as an optimization we look at the first 64 PMC
++ * registers only starting at PMC4.
++ */
++ mask = arch_info->mask_pmcs[0] >> PFM_ITA_FCNTR;
++ for (i = PFM_ITA_FCNTR; mask; i++, mask >>= 1) {
++ if (likely(mask & 0x1))
++ ia64_set_pmc(i, set->pmcs[i] & ~0xfUL);
++ }
++ /*
++ * make changes visisble
++ */
++ ia64_srlz_d();
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets()
++ * context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMD registers from set.
++ */
++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_context *ctx_arch;
++ unsigned long *mask;
++ u16 i, num;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ if (ctx_arch->flags.insecure) {
++ num = ctx->regs.num_rw_pmd;
++ mask = ctx->regs.rw_pmds;
++ } else {
++ num = set->nused_pmds;
++ mask = set->used_pmds;
++ }
++ /*
++ * must restore all implemented read-write PMDS to avoid leaking
++ * information especially when PFM_IA64_FL_INSECURE is set.
++ *
++ * XXX: should check PFM_IA64_FL_INSECURE==0 and use used_pmd instead
++ */
++ for (i = 0; num; i++) {
++ if (likely(test_bit(i, mask))) {
++ pfm_arch_write_pmd(ctx, i, set->pmds[i].value);
++ num--;
++ }
++ }
++ ia64_srlz_d();
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets()
++ * context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMC registers from set if needed
++ */
++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ u64 mask2 = 0, val, plm;
++ unsigned long impl_mask, mask_pmcs;
++ unsigned int i;
++
++ arch_info = pfm_pmu_info();
++ /*
++ * as an optimization we only look at the first 64
++ * PMC registers. In fact, we should never scan the
++ * entire impl_pmcs because ibr/dbr are implemented
++ * separately.
++ *
++ * always skip PMC0-PMC3. PMC0 taken care of when saving
++ * state. PMC1-PMC3 not used until we get counters in
++ * the 60 and above index range.
++ */
++ impl_mask = ctx->regs.pmcs[0] >> PFM_ITA_FCNTR;
++ mask_pmcs = arch_info->mask_pmcs[0] >> PFM_ITA_FCNTR;
++ plm = ctx->state == PFM_CTX_MASKED ? ~0xf : ~0x0;
++
++ for (i = PFM_ITA_FCNTR;
++ impl_mask;
++ i++, impl_mask >>= 1, mask_pmcs >>= 1) {
++ if (likely(impl_mask & 0x1)) {
++ mask2 = mask_pmcs & 0x1 ? plm : ~0;
++ val = set->pmcs[i] & mask2;
++ ia64_set_pmc(i, val);
++ PFM_DBG_ovfl("pmc%u=0x%lx", i, val);
++ }
++ }
++ /*
++ * restore DBR/IBR
++ */
++ if (set->priv_flags & PFM_ITA_SETFL_USE_DBR) {
++ pfm_restore_ibrs(set->pmcs+256, 8);
++ pfm_restore_dbrs(set->pmcs+264, 8);
++ }
++ ia64_srlz_d();
++}
++
++void pfm_arch_unmask_monitoring(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ u64 psr;
++ int is_system;
++
++ is_system = ctx->flags.system;
++
++ psr = ia64_getreg(_IA64_REG_PSR);
++
++ /*
++ * monitoring is masked via the PMC.plm
++ *
++ * As we restore their value, we do not want each counter to
++ * restart right away. We stop monitoring using the PSR,
++ * restore the PMC (and PMD) and then re-establish the psr
++ * as it was. Note that there can be no pending overflow at
++ * this point, because monitoring is still MASKED.
++ *
++ * Because interrupts are masked we can avoid changing
++ * DCR.pp.
++ */
++ if (is_system)
++ pfm_clear_psr_pp();
++ else
++ pfm_clear_psr_up();
++
++ ia64_srlz_d();
++
++ pfm_arch_restore_pmcs(ctx, set);
++
++ /*
++ * restore psr
++ *
++ * monitoring may start right now but interrupts
++ * are still masked
++ */
++ pfm_set_psr_l(psr);
++ ia64_srlz_d();
++}
++
++/*
++ * Called from pfm_stop()
++ *
++ * For per-thread:
++ * task is not necessarily current. If not current task, then
++ * task is guaranteed stopped and off any cpu. Access to PMU
++ * is not guaranteed. Interrupts are masked. Context is locked.
++ * Set is the active set.
++ *
++ * must disable active monitoring. ctx cannot be NULL
++ */
++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pt_regs *regs;
++ u64 dcr, psr;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ regs = task_pt_regs(task);
++
++ if (!ctx->flags.system) {
++ /*
++ * in ZOMBIE state we always have task == current due to
++ * pfm_exit_thread()
++ */
++ ia64_psr(regs)->up = 0;
++ ctx_arch->ctx_saved_psr_up = 0;
++
++ /*
++ * in case of ZOMBIE state, there is no unload to clear
++ * insecure monitoring, so we do it in stop instead.
++ */
++ if (ctx->state == PFM_CTX_ZOMBIE)
++ ia64_psr(regs)->sp = 1;
++
++ if (task == current) {
++ pfm_clear_psr_up();
++ ia64_srlz_d();
++ }
++ } else if (ctx->flags.started) { /* do not stop twice */
++ dcr = ia64_getreg(_IA64_REG_CR_DCR);
++ psr = ia64_getreg(_IA64_REG_PSR);
++
++ ia64_psr(regs)->pp = 0;
++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP);
++ pfm_clear_psr_pp();
++ ia64_srlz_d();
++
++ if (ctx->active_set->flags & PFM_ITA_SETFL_IDLE_EXCL) {
++ PFM_DBG("disabling idle exclude");
++ __get_cpu_var(pfm_syst_info) &= ~PFM_ITA_CPUINFO_IDLE_EXCL;
++ }
++ }
++}
++
++/*
++ * called from pfm_start()
++ *
++ * Interrupts are masked. Context is locked. Set is the active set.
++ *
++ * For per-thread:
++ * Task is not necessarily current. If not current task, then task
++ * is guaranteed stopped and off any cpu. No access to PMU is task
++ * is not current.
++ *
++ * For system-wide:
++ * task is always current
++ *
++ * must enable active monitoring.
++ */
++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pt_regs *regs;
++ u64 dcr, dcr_pp, psr_pp;
++ u32 flags;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ regs = task_pt_regs(task);
++ flags = ctx->active_set->flags;
++
++ /*
++ * per-thread mode
++ */
++ if (!ctx->flags.system) {
++
++ ia64_psr(regs)->up = 1;
++
++ if (task == current) {
++ pfm_set_psr_up();
++ ia64_srlz_d();
++ } else {
++ /*
++ * activate monitoring at next ctxswin
++ */
++ ctx_arch->ctx_saved_psr_up = IA64_PSR_UP;
++ }
++ return;
++ }
++
++ /*
++ * system-wide mode
++ */
++ dcr = ia64_getreg(_IA64_REG_CR_DCR);
++ if (flags & PFM_ITA_SETFL_INTR_ONLY) {
++ dcr_pp = 1;
++ psr_pp = 0;
++ } else if (flags & PFM_ITA_SETFL_EXCL_INTR) {
++ dcr_pp = 0;
++ psr_pp = 1;
++ } else {
++ dcr_pp = psr_pp = 1;
++ }
++ PFM_DBG("dcr_pp=%lu psr_pp=%lu", dcr_pp, psr_pp);
++
++ /*
++ * update dcr_pp and psr_pp
++ */
++ if (dcr_pp)
++ ia64_setreg(_IA64_REG_CR_DCR, dcr | IA64_DCR_PP);
++ else
++ ia64_setreg(_IA64_REG_CR_DCR, dcr & ~IA64_DCR_PP);
++
++ if (psr_pp) {
++ pfm_set_psr_pp();
++ ia64_psr(regs)->pp = 1;
++ } else {
++ pfm_clear_psr_pp();
++ ia64_psr(regs)->pp = 0;
++ }
++ ia64_srlz_d();
++
++ if (ctx->active_set->flags & PFM_ITA_SETFL_IDLE_EXCL) {
++ PFM_DBG("enable idle exclude");
++ __get_cpu_var(pfm_syst_info) |= PFM_ITA_CPUINFO_IDLE_EXCL;
++ }
++}
++
++/*
++ * Only call this function when a process is trying to
++ * write the debug registers (reading is always allowed)
++ * called from arch/ia64/kernel/ptrace.c:access_uarea()
++ */
++int __pfm_use_dbregs(struct task_struct *task)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct pfm_context *ctx;
++ unsigned long flags;
++ int ret = 0;
++
++ PFM_DBG("called for [%d]", task->pid);
++
++ ctx = task->pfm_context;
++
++ /*
++ * do it only once
++ */
++ if (task->thread.flags & IA64_THREAD_DBG_VALID) {
++ PFM_DBG("IA64_THREAD_DBG_VALID already set");
++ return 0;
++ }
++ if (ctx) {
++ spin_lock_irqsave(&ctx->lock, flags);
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ if (ctx_arch->flags.use_dbr == 1) {
++ PFM_DBG("PMU using dbregs already, no ptrace access");
++ ret = -1;
++ }
++ spin_unlock_irqrestore(&ctx->lock, flags);
++ if (ret)
++ return ret;
++ }
++
++ spin_lock(&pfm_arch_sessions_lock);
++
++ /*
++ * We cannot allow setting breakpoints when system wide monitoring
++ * sessions are using the debug registers.
++ */
++ if (!pfm_arch_sessions.pfs_sys_use_dbr)
++ pfm_arch_sessions.pfs_ptrace_use_dbr++;
++ else
++ ret = -1;
++
++ PFM_DBG("ptrace_use_dbr=%u sys_use_dbr=%u by [%d] ret = %d",
++ pfm_arch_sessions.pfs_ptrace_use_dbr,
++ pfm_arch_sessions.pfs_sys_use_dbr,
++ task->pid, ret);
++
++ spin_unlock(&pfm_arch_sessions_lock);
++ if (ret)
++ return ret;
++#ifndef CONFIG_SMP
++ /*
++ * in UP, we need to check whether the current
++ * owner of the PMU is not using the debug registers
++ * for monitoring. Because we are using a lazy
++ * save on ctxswout, we must force a save in this
++ * case because the debug registers are being
++ * modified by another task. We save the current
++ * PMD registers, and clear ownership. In ctxswin,
++ * full state will be reloaded.
++ *
++ * Note: we overwrite task.
++ */
++ task = __get_cpu_var(pmu_owner);
++ ctx = __get_cpu_var(pmu_ctx);
++
++ if (task == NULL)
++ return 0;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ if (ctx_arch->flags.use_dbr)
++ pfm_save_pmds_release(ctx);
++#endif
++ return 0;
++}
++
++/*
++ * This function is called for every task that exits with the
++ * IA64_THREAD_DBG_VALID set. This indicates a task which was
++ * able to use the debug registers for debugging purposes via
++ * ptrace(). Therefore we know it was not using them for
++ * perfmormance monitoring, so we only decrement the number
++ * of "ptraced" debug register users to keep the count up to date
++ */
++int __pfm_release_dbregs(struct task_struct *task)
++{
++ int ret;
++
++ spin_lock(&pfm_arch_sessions_lock);
++
++ if (pfm_arch_sessions.pfs_ptrace_use_dbr == 0) {
++ PFM_ERR("invalid release for [%d] ptrace_use_dbr=0", task->pid);
++ ret = -1;
++ } else {
++ pfm_arch_sessions.pfs_ptrace_use_dbr--;
++ ret = 0;
++ }
++ spin_unlock(&pfm_arch_sessions_lock);
++
++ return ret;
++}
++
++int pfm_ia64_mark_dbregs_used(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ struct pfm_arch_context *ctx_arch;
++ struct task_struct *task;
++ struct thread_struct *thread;
++ int ret = 0, state;
++ int i, can_access_pmu = 0;
++ int is_loaded, is_system;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++ state = ctx->state;
++ task = ctx->task;
++ is_loaded = state == PFM_CTX_LOADED || state == PFM_CTX_MASKED;
++ is_system = ctx->flags.system;
++ can_access_pmu = __get_cpu_var(pmu_owner) == task || is_system;
++
++ if (is_loaded == 0)
++ goto done;
++
++ if (is_system == 0) {
++ thread = &(task->thread);
++
++ /*
++ * cannot use debug registers for montioring if they are
++ * already used for debugging
++ */
++ if (thread->flags & IA64_THREAD_DBG_VALID) {
++ PFM_DBG("debug registers already in use for [%d]",
++ task->pid);
++ return -EBUSY;
++ }
++ }
++
++ /*
++ * check for debug registers in system wide mode
++ */
++ spin_lock(&pfm_arch_sessions_lock);
++
++ if (is_system) {
++ if (pfm_arch_sessions.pfs_ptrace_use_dbr)
++ ret = -EBUSY;
++ else
++ pfm_arch_sessions.pfs_sys_use_dbr++;
++ }
++
++ spin_unlock(&pfm_arch_sessions_lock);
++
++ if (ret != 0)
++ return ret;
++
++ /*
++ * clear hardware registers to make sure we don't
++ * pick up stale state.
++ */
++ if (can_access_pmu) {
++ PFM_DBG("clearing ibrs, dbrs");
++ for (i = 0; i < 8; i++) {
++ ia64_set_ibr(i, 0);
++ ia64_dv_serialize_instruction();
++ }
++ ia64_srlz_i();
++ for (i = 0; i < 8; i++) {
++ ia64_set_dbr(i, 0);
++ ia64_dv_serialize_data();
++ }
++ ia64_srlz_d();
++ }
++done:
++ /*
++ * debug registers are now in use
++ */
++ ctx_arch->flags.use_dbr = 1;
++ set->priv_flags |= PFM_ITA_SETFL_USE_DBR;
++ PFM_DBG("set%u use_dbr=1", set->id);
++ return 0;
++}
++EXPORT_SYMBOL(pfm_ia64_mark_dbregs_used);
++
++char *pfm_arch_get_pmu_module_name(void)
++{
++ switch (local_cpu_data->family) {
++ case 0x07:
++ return "perfmon_itanium";
++ case 0x1f:
++ return "perfmon_mckinley";
++ case 0x20:
++ return "perfmon_montecito";
++ default:
++ return "perfmon_generic";
++ }
++ return NULL;
++}
++
++/*
++ * global arch-specific intialization, called only once
++ */
++int __init pfm_arch_init(void)
++{
++ int ret;
++
++ spin_lock_init(&pfm_arch_sessions_lock);
++
++#ifdef CONFIG_IA64_PERFMON_COMPAT
++ ret = pfm_ia64_compat_init();
++ if (ret)
++ return ret;
++#endif
++ register_percpu_irq(IA64_PERFMON_VECTOR, &perfmon_irqaction);
++
++
++ return 0;
++}
+diff --git a/arch/ia64/perfmon/perfmon_compat.c b/arch/ia64/perfmon/perfmon_compat.c
+new file mode 100644
+index 0000000..2fd3d3c
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_compat.c
+@@ -0,0 +1,1210 @@
++/*
++ * This file implements the IA-64 specific
++ * support for the perfmon2 interface
++ *
++ * Copyright (c) 1999-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/file.h>
++#include <linux/fdtable.h>
++#include <linux/seq_file.h>
++#include <linux/vmalloc.h>
++#include <linux/proc_fs.h>
++#include <linux/perfmon_kern.h>
++#include <linux/uaccess.h>
++
++asmlinkage long sys_pfm_stop(int fd);
++asmlinkage long sys_pfm_start(int fd, struct pfarg_start __user *st);
++asmlinkage long sys_pfm_unload_context(int fd);
++asmlinkage long sys_pfm_restart(int fd);
++asmlinkage long sys_pfm_load_context(int fd, struct pfarg_load __user *ld);
++
++ssize_t pfm_sysfs_res_show(char *buf, size_t sz, int what);
++
++extern ssize_t __pfm_read(struct pfm_context *ctx,
++ union pfarg_msg *msg_buf,
++ int non_block);
++/*
++ * function providing some help for backward compatiblity with old IA-64
++ * applications. In the old model, certain attributes of a counter were
++ * passed via the PMC, now they are passed via the PMD.
++ */
++static int pfm_compat_update_pmd(struct pfm_context *ctx, u16 set_id, u16 cnum,
++ u32 rflags,
++ unsigned long *smpl_pmds,
++ unsigned long *reset_pmds,
++ u64 eventid)
++{
++ struct pfm_event_set *set;
++ int is_counting;
++ unsigned long *impl_pmds;
++ u32 flags = 0;
++ u16 max_pmd;
++
++ impl_pmds = ctx->regs.pmds;
++ max_pmd = ctx->regs.max_pmd;
++
++ /*
++ * given that we do not maintain PMC ->PMD dependencies
++ * we cannot figure out what to do in case PMCxx != PMDxx
++ */
++ if (cnum > max_pmd)
++ return 0;
++
++ /*
++ * assumes PMCxx controls PMDxx which is always true for counters
++ * on Itanium PMUs.
++ */
++ is_counting = pfm_pmu_conf->pmd_desc[cnum].type & PFM_REG_C64;
++ set = pfm_find_set(ctx, set_id, 0);
++
++ /*
++ * for v2.0, we only allowed counting PMD to generate
++ * user-level notifications. Same thing with randomization.
++ */
++ if (is_counting) {
++ if (rflags & PFM_REGFL_OVFL_NOTIFY)
++ flags |= PFM_REGFL_OVFL_NOTIFY;
++ if (rflags & PFM_REGFL_RANDOM)
++ flags |= PFM_REGFL_RANDOM;
++ /*
++ * verify validity of smpl_pmds
++ */
++ if (unlikely(bitmap_subset(smpl_pmds,
++ impl_pmds, max_pmd) == 0)) {
++ PFM_DBG("invalid smpl_pmds=0x%llx for pmd%u",
++ (unsigned long long)smpl_pmds[0], cnum);
++ return -EINVAL;
++ }
++ /*
++ * verify validity of reset_pmds
++ */
++ if (unlikely(bitmap_subset(reset_pmds,
++ impl_pmds, max_pmd) == 0)) {
++ PFM_DBG("invalid reset_pmds=0x%lx for pmd%u",
++ reset_pmds[0], cnum);
++ return -EINVAL;
++ }
++ /*
++ * ensures that a PFM_READ_PMDS succeeds with a
++ * corresponding PFM_WRITE_PMDS
++ */
++ __set_bit(cnum, set->used_pmds);
++
++ } else if (rflags & (PFM_REGFL_OVFL_NOTIFY|PFM_REGFL_RANDOM)) {
++ PFM_DBG("cannot set ovfl_notify or random on pmd%u", cnum);
++ return -EINVAL;
++ }
++
++ set->pmds[cnum].flags = flags;
++
++ if (is_counting) {
++ bitmap_copy(set->pmds[cnum].reset_pmds,
++ reset_pmds,
++ max_pmd);
++
++ bitmap_copy(set->pmds[cnum].smpl_pmds,
++ smpl_pmds,
++ max_pmd);
++
++ set->pmds[cnum].eventid = eventid;
++
++ /*
++ * update ovfl_notify
++ */
++ if (rflags & PFM_REGFL_OVFL_NOTIFY)
++ __set_bit(cnum, set->ovfl_notify);
++ else
++ __clear_bit(cnum, set->ovfl_notify);
++
++ }
++ PFM_DBG("pmd%u flags=0x%x eventid=0x%lx r_pmds=0x%lx s_pmds=0x%lx",
++ cnum, flags,
++ eventid,
++ reset_pmds[0],
++ smpl_pmds[0]);
++
++ return 0;
++}
++
++
++int __pfm_write_ibrs_old(struct pfm_context *ctx, void *arg, int count)
++{
++ struct pfarg_dbreg *req = arg;
++ struct pfarg_pmc pmc;
++ int i, ret = 0;
++
++ memset(&pmc, 0, sizeof(pmc));
++
++ for (i = 0; i < count; i++, req++) {
++ pmc.reg_num = 256+req->dbreg_num;
++ pmc.reg_value = req->dbreg_value;
++ pmc.reg_flags = 0;
++ pmc.reg_set = req->dbreg_set;
++
++ ret = __pfm_write_pmcs(ctx, &pmc, 1);
++
++ req->dbreg_flags &= ~PFM_REG_RETFL_MASK;
++ req->dbreg_flags |= pmc.reg_flags;
++
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static long pfm_write_ibrs_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *ctx;
++ struct task_struct *task;
++ struct file *filp;
++ struct pfarg_dbreg *req = NULL;
++ void *fptr, *resume;
++ unsigned long flags;
++ size_t sz;
++ int ret, fput_needed;
++
++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req))
++ return -EINVAL;
++
++ sz = count*sizeof(*req);
++
++ filp = fget_light(fd, &fput_needed);
++ if (unlikely(filp == NULL)) {
++ PFM_DBG("invalid fd %d", fd);
++ return -EBADF;
++ }
++
++ ctx = filp->private_data;
++ ret = -EBADF;
++
++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) {
++ PFM_DBG("fd %d not related to perfmon", fd);
++ goto error;
++ }
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++ spin_lock_irqsave(&ctx->lock, flags);
++
++ task = ctx->task;
++
++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume);
++ if (ret == 0)
++ ret = __pfm_write_ibrs_old(ctx, req, count);
++
++ spin_unlock_irqrestore(&ctx->lock, flags);
++
++ if (resume)
++ pfm_resume_task(task, resume);
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ kfree(fptr);
++error:
++ fput_light(filp, fput_needed);
++ return ret;
++}
++
++int __pfm_write_dbrs_old(struct pfm_context *ctx, void *arg, int count)
++{
++ struct pfarg_dbreg *req = arg;
++ struct pfarg_pmc pmc;
++ int i, ret = 0;
++
++ memset(&pmc, 0, sizeof(pmc));
++
++ for (i = 0; i < count; i++, req++) {
++ pmc.reg_num = 264+req->dbreg_num;
++ pmc.reg_value = req->dbreg_value;
++ pmc.reg_flags = 0;
++ pmc.reg_set = req->dbreg_set;
++
++ ret = __pfm_write_pmcs(ctx, &pmc, 1);
++
++ req->dbreg_flags &= ~PFM_REG_RETFL_MASK;
++ req->dbreg_flags |= pmc.reg_flags;
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static long pfm_write_dbrs_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *ctx;
++ struct task_struct *task;
++ struct file *filp;
++ struct pfarg_dbreg *req = NULL;
++ void *fptr, *resume;
++ unsigned long flags;
++ size_t sz;
++ int ret, fput_needed;
++
++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req))
++ return -EINVAL;
++
++ sz = count*sizeof(*req);
++
++ filp = fget_light(fd, &fput_needed);
++ if (unlikely(filp == NULL)) {
++ PFM_DBG("invalid fd %d", fd);
++ return -EBADF;
++ }
++
++ ctx = filp->private_data;
++ ret = -EBADF;
++
++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) {
++ PFM_DBG("fd %d not related to perfmon", fd);
++ goto error;
++ }
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++ spin_lock_irqsave(&ctx->lock, flags);
++
++ task = ctx->task;
++
++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume);
++ if (ret == 0)
++ ret = __pfm_write_dbrs_old(ctx, req, count);
++
++ spin_unlock_irqrestore(&ctx->lock, flags);
++
++ if (resume)
++ pfm_resume_task(task, resume);
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ kfree(fptr);
++error:
++ fput_light(filp, fput_needed);
++ return ret;
++}
++
++int __pfm_write_pmcs_old(struct pfm_context *ctx, struct pfarg_reg *req_old,
++ int count)
++{
++ struct pfarg_pmc req;
++ unsigned int i;
++ int ret, error_code;
++
++ memset(&req, 0, sizeof(req));
++
++ for (i = 0; i < count; i++, req_old++) {
++ req.reg_num = req_old->reg_num;
++ req.reg_set = req_old->reg_set;
++ req.reg_flags = 0;
++ req.reg_value = req_old->reg_value;
++
++ ret = __pfm_write_pmcs(ctx, (void *)&req, 1);
++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK;
++ req_old->reg_flags |= req.reg_flags;
++
++ if (ret)
++ return ret;
++
++ ret = pfm_compat_update_pmd(ctx, req_old->reg_set,
++ req_old->reg_num,
++ (u32)req_old->reg_flags,
++ req_old->reg_smpl_pmds,
++ req_old->reg_reset_pmds,
++ req_old->reg_smpl_eventid);
++
++ error_code = ret ? PFM_REG_RETFL_EINVAL : 0;
++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK;
++ req_old->reg_flags |= error_code;
++
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static long pfm_write_pmcs_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *ctx;
++ struct task_struct *task;
++ struct file *filp;
++ struct pfarg_reg *req = NULL;
++ void *fptr, *resume;
++ unsigned long flags;
++ size_t sz;
++ int ret, fput_needed;
++
++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req))
++ return -EINVAL;
++
++ sz = count*sizeof(*req);
++
++ filp = fget_light(fd, &fput_needed);
++ if (unlikely(filp == NULL)) {
++ PFM_DBG("invalid fd %d", fd);
++ return -EBADF;
++ }
++
++ ctx = filp->private_data;
++ ret = -EBADF;
++
++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) {
++ PFM_DBG("fd %d not related to perfmon", fd);
++ goto error;
++ }
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++ spin_lock_irqsave(&ctx->lock, flags);
++
++ task = ctx->task;
++
++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume);
++ if (ret == 0)
++ ret = __pfm_write_pmcs_old(ctx, req, count);
++
++ spin_unlock_irqrestore(&ctx->lock, flags);
++
++ if (resume)
++ pfm_resume_task(task, resume);
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ kfree(fptr);
++
++error:
++ fput_light(filp, fput_needed);
++ return ret;
++}
++
++int __pfm_write_pmds_old(struct pfm_context *ctx, struct pfarg_reg *req_old,
++ int count)
++{
++ struct pfarg_pmd req;
++ int i, ret;
++
++ memset(&req, 0, sizeof(req));
++
++ for (i = 0; i < count; i++, req_old++) {
++ req.reg_num = req_old->reg_num;
++ req.reg_set = req_old->reg_set;
++ req.reg_value = req_old->reg_value;
++ /* flags passed with pmcs in v2.0 */
++
++ req.reg_long_reset = req_old->reg_long_reset;
++ req.reg_short_reset = req_old->reg_short_reset;
++ req.reg_random_mask = req_old->reg_random_mask;
++ /*
++ * reg_random_seed is ignored since v2.3
++ */
++
++ /*
++ * skip last_reset_val not used for writing
++ * skip smpl_pmds, reset_pmds, eventid, ovfl_swtch_cnt
++ * as set in pfm_write_pmcs_old.
++ *
++ * ovfl_switch_cnt ignored, not implemented in v2.0
++ */
++ ret = __pfm_write_pmds(ctx, (void *)&req, 1, 1);
++
++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK;
++ req_old->reg_flags |= req.reg_flags;
++
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static long pfm_write_pmds_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *ctx;
++ struct task_struct *task;
++ struct file *filp;
++ struct pfarg_reg *req = NULL;
++ void *fptr, *resume;
++ unsigned long flags;
++ size_t sz;
++ int ret, fput_needed;
++
++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req))
++ return -EINVAL;
++
++ sz = count*sizeof(*req);
++
++ filp = fget_light(fd, &fput_needed);
++ if (unlikely(filp == NULL)) {
++ PFM_DBG("invalid fd %d", fd);
++ return -EBADF;
++ }
++
++ ctx = filp->private_data;
++ ret = -EBADF;
++
++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) {
++ PFM_DBG("fd %d not related to perfmon", fd);
++ goto error;
++ }
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++ spin_lock_irqsave(&ctx->lock, flags);
++
++ task = ctx->task;
++
++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume);
++ if (ret == 0)
++ ret = __pfm_write_pmds_old(ctx, req, count);
++
++ spin_unlock_irqrestore(&ctx->lock, flags);
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ if (resume)
++ pfm_resume_task(task, resume);
++
++ kfree(fptr);
++error:
++ fput_light(filp, fput_needed);
++ return ret;
++}
++
++int __pfm_read_pmds_old(struct pfm_context *ctx, struct pfarg_reg *req_old,
++ int count)
++{
++ struct pfarg_pmd req;
++ int i, ret;
++
++ memset(&req, 0, sizeof(req));
++
++ for (i = 0; i < count; i++, req_old++) {
++ req.reg_num = req_old->reg_num;
++ req.reg_set = req_old->reg_set;
++
++ /* skip value not used for reading */
++ req.reg_flags = req_old->reg_flags;
++
++ /* skip short/long_reset not used for reading */
++ /* skip last_reset_val not used for reading */
++ /* skip ovfl_switch_cnt not used for reading */
++
++ ret = __pfm_read_pmds(ctx, (void *)&req, 1);
++
++ req_old->reg_flags &= ~PFM_REG_RETFL_MASK;
++ req_old->reg_flags |= req.reg_flags;
++ if (ret)
++ return ret;
++
++ /* update fields */
++ req_old->reg_value = req.reg_value;
++
++ req_old->reg_last_reset_val = req.reg_last_reset_val;
++ req_old->reg_ovfl_switch_cnt = req.reg_ovfl_switch_cnt;
++ }
++ return 0;
++}
++
++static long pfm_read_pmds_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *ctx;
++ struct task_struct *task;
++ struct file *filp;
++ struct pfarg_reg *req = NULL;
++ void *fptr, *resume;
++ unsigned long flags;
++ size_t sz;
++ int ret, fput_needed;
++
++ if (count < 1 || count >= PFM_MAX_ARG_COUNT(req))
++ return -EINVAL;
++
++ sz = count*sizeof(*req);
++
++ filp = fget_light(fd, &fput_needed);
++ if (unlikely(filp == NULL)) {
++ PFM_DBG("invalid fd %d", fd);
++ return -EBADF;
++ }
++
++ ctx = filp->private_data;
++ ret = -EBADF;
++
++ if (unlikely(!ctx || filp->f_op != &pfm_file_ops)) {
++ PFM_DBG("fd %d not related to perfmon", fd);
++ goto error;
++ }
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++ spin_lock_irqsave(&ctx->lock, flags);
++
++ task = ctx->task;
++
++ ret = pfm_check_task_state(ctx, PFM_CMD_STOPPED, &flags, &resume);
++ if (ret == 0)
++ ret = __pfm_read_pmds_old(ctx, req, count);
++
++ spin_unlock_irqrestore(&ctx->lock, flags);
++
++ if (resume)
++ pfm_resume_task(task, resume);
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ kfree(fptr);
++error:
++ fput_light(filp, fput_needed);
++ return ret;
++}
++
++/*
++ * OBSOLETE: use /proc/perfmon_map instead
++ */
++static long pfm_get_default_pmcs_old(int fd, void __user *ureq, int count)
++{
++ struct pfarg_reg *req = NULL;
++ void *fptr;
++ size_t sz;
++ int ret, i;
++ unsigned int cnum;
++
++ if (count < 1)
++ return -EINVAL;
++
++ /*
++ * ensure the pfm_pmu_conf does not disappear while
++ * we use it
++ */
++ ret = pfm_pmu_conf_get(1);
++ if (ret)
++ return ret;
++
++ sz = count*sizeof(*ureq);
++
++ ret = pfm_get_args(ureq, sz, 0, NULL, (void **)&req, &fptr);
++ if (ret)
++ goto error;
++
++
++ for (i = 0; i < count; i++, req++) {
++ cnum = req->reg_num;
++
++ if (i >= PFM_MAX_PMCS ||
++ (pfm_pmu_conf->pmc_desc[cnum].type & PFM_REG_I) == 0) {
++ req->reg_flags = PFM_REG_RETFL_EINVAL;
++ break;
++ }
++ req->reg_value = pfm_pmu_conf->pmc_desc[cnum].dfl_val;
++ req->reg_flags = 0;
++
++ PFM_DBG("pmc[%u]=0x%lx", cnum, req->reg_value);
++ }
++
++ if (copy_to_user(ureq, req, sz))
++ ret = -EFAULT;
++
++ kfree(fptr);
++error:
++ pfm_pmu_conf_put();
++
++ return ret;
++}
++
++/*
++ * allocate a sampling buffer and remaps it into the user address space of
++ * the task. This is only in compatibility mode
++ *
++ * function called ONLY on current task
++ */
++int pfm_smpl_buf_alloc_compat(struct pfm_context *ctx, size_t rsize,
++ struct file *filp)
++{
++ struct mm_struct *mm = current->mm;
++ struct vm_area_struct *vma = NULL;
++ struct pfm_arch_context *ctx_arch;
++ size_t size;
++ int ret;
++ extern struct vm_operations_struct pfm_buf_map_vm_ops;
++
++ ctx_arch = pfm_ctx_arch(ctx);
++
++ /*
++ * allocate buffer + map desc
++ */
++ ret = pfm_smpl_buf_alloc(ctx, rsize);
++ if (ret)
++ return ret;
++
++ size = ctx->smpl_size;
++
++
++ /* allocate vma */
++ vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL);
++ if (!vma) {
++ PFM_DBG("Cannot allocate vma");
++ goto error_kmem;
++ }
++ memset(vma, 0, sizeof(*vma));
++
++ /*
++ * partially initialize the vma for the sampling buffer
++ */
++ vma->vm_mm = mm;
++ vma->vm_flags = VM_READ | VM_MAYREAD | VM_RESERVED;
++ vma->vm_page_prot = PAGE_READONLY;
++ vma->vm_ops = &pfm_buf_map_vm_ops;
++ vma->vm_file = filp;
++ vma->vm_private_data = ctx;
++ vma->vm_pgoff = 0;
++
++ /*
++ * simulate effect of mmap()
++ */
++ get_file(filp);
++
++ /*
++ * Let's do the difficult operations next.
++ *
++ * now we atomically find some area in the address space and
++ * remap the buffer into it.
++ */
++ down_write(¤t->mm->mmap_sem);
++
++ /* find some free area in address space, must have mmap sem held */
++ vma->vm_start = get_unmapped_area(NULL, 0, size, 0,
++ MAP_PRIVATE|MAP_ANONYMOUS);
++ if (vma->vm_start == 0) {
++ PFM_DBG("cannot find unmapped area of size %zu", size);
++ up_write(¤t->mm->mmap_sem);
++ goto error;
++ }
++ vma->vm_end = vma->vm_start + size;
++
++ PFM_DBG("aligned_size=%zu mapped @0x%lx", size, vma->vm_start);
++ /*
++ * now insert the vma in the vm list for the process, must be
++ * done with mmap lock held
++ */
++ insert_vm_struct(mm, vma);
++
++ mm->total_vm += size >> PAGE_SHIFT;
++
++ up_write(¤t->mm->mmap_sem);
++
++ /*
++ * IMPORTANT: we do not issue the fput()
++ * because we want to increase the ref count
++ * on the descriptor to simulate what mmap()
++ * would do
++ */
++
++ /*
++ * used to propagate vaddr to syscall stub
++ */
++ ctx_arch->ctx_smpl_vaddr = (void *)vma->vm_start;
++
++ return 0;
++error:
++ kmem_cache_free(vm_area_cachep, vma);
++error_kmem:
++ pfm_smpl_buf_space_release(ctx, ctx->smpl_size);
++ vfree(ctx->smpl_addr);
++ return -ENOMEM;
++}
++
++#define PFM_DEFAULT_SMPL_UUID { \
++ 0x4d, 0x72, 0xbe, 0xc0, 0x06, 0x64, 0x41, 0x43, 0x82,\
++ 0xb4, 0xd3, 0xfd, 0x27, 0x24, 0x3c, 0x97}
++
++static pfm_uuid_t old_default_uuid = PFM_DEFAULT_SMPL_UUID;
++static pfm_uuid_t null_uuid;
++
++/*
++ * function invoked in case, pfm_context_create fails
++ * at the last operation, copy_to_user. It needs to
++ * undo memory allocations and free the file descriptor
++ */
++static void pfm_undo_create_context_fd(int fd, struct pfm_context *ctx)
++{
++ struct files_struct *files = current->files;
++ struct file *file;
++ int fput_needed;
++
++ file = fget_light(fd, &fput_needed);
++ /*
++ * there is no fd_uninstall(), so we do it
++ * here. put_unused_fd() does not remove the
++ * effect of fd_install().
++ */
++
++ spin_lock(&files->file_lock);
++ files->fd_array[fd] = NULL;
++ spin_unlock(&files->file_lock);
++
++ fput_light(file, fput_needed);
++
++ /*
++ * decrement ref count and kill file
++ */
++ put_filp(file);
++
++ put_unused_fd(fd);
++
++ pfm_free_context(ctx);
++}
++
++static int pfm_get_smpl_arg_old(pfm_uuid_t uuid, void __user *fmt_uarg,
++ size_t usize, void **arg,
++ struct pfm_smpl_fmt **fmt)
++{
++ struct pfm_smpl_fmt *f;
++ void *addr = NULL;
++ size_t sz;
++ int ret;
++
++ if (!memcmp(uuid, null_uuid, sizeof(pfm_uuid_t)))
++ return 0;
++
++ if (memcmp(uuid, old_default_uuid, sizeof(pfm_uuid_t))) {
++ PFM_DBG("compatibility mode supports only default sampling format");
++ return -EINVAL;
++ }
++ /*
++ * find fmt and increase refcount
++ */
++ f = pfm_smpl_fmt_get("default-old");
++ if (f == NULL) {
++ PFM_DBG("default-old buffer format not found");
++ return -EINVAL;
++ }
++
++ /*
++ * expected format argument size
++ */
++ sz = f->fmt_arg_size;
++
++ /*
++ * check user size matches expected size
++ * usize = -1 is for IA-64 backward compatibility
++ */
++ ret = -EINVAL;
++ if (sz != usize && usize != -1) {
++ PFM_DBG("invalid arg size %zu, format expects %zu",
++ usize, sz);
++ goto error;
++ }
++
++ ret = -ENOMEM;
++ addr = kmalloc(sz, GFP_KERNEL);
++ if (addr == NULL)
++ goto error;
++
++ ret = -EFAULT;
++ if (copy_from_user(addr, fmt_uarg, sz))
++ goto error;
++
++ *arg = addr;
++ *fmt = f;
++ return 0;
++
++error:
++ kfree(addr);
++ pfm_smpl_fmt_put(f);
++ return ret;
++}
++
++static long pfm_create_context_old(int fd, void __user *ureq, int count)
++{
++ struct pfm_context *new_ctx;
++ struct pfm_arch_context *ctx_arch;
++ struct pfm_smpl_fmt *fmt = NULL;
++ struct pfarg_context req_old;
++ void __user *usmpl_arg;
++ void *smpl_arg = NULL;
++ struct pfarg_ctx req;
++ int ret;
++
++ if (count != 1)
++ return -EINVAL;
++
++ if (copy_from_user(&req_old, ureq, sizeof(req_old)))
++ return -EFAULT;
++
++ memset(&req, 0, sizeof(req));
++
++ /*
++ * sampling format args are following pfarg_context
++ */
++ usmpl_arg = ureq+sizeof(req_old);
++
++ ret = pfm_get_smpl_arg_old(req_old.ctx_smpl_buf_id, usmpl_arg, -1,
++ &smpl_arg, &fmt);
++ if (ret)
++ return ret;
++
++ req.ctx_flags = req_old.ctx_flags;
++
++ /*
++ * returns file descriptor if >=0, or error code */
++ ret = __pfm_create_context(&req, fmt, smpl_arg, PFM_COMPAT, &new_ctx);
++ if (ret >= 0) {
++ ctx_arch = pfm_ctx_arch(new_ctx);
++ req_old.ctx_fd = ret;
++ req_old.ctx_smpl_vaddr = ctx_arch->ctx_smpl_vaddr;
++ }
++
++ if (copy_to_user(ureq, &req_old, sizeof(req_old))) {
++ pfm_undo_create_context_fd(req_old.ctx_fd, new_ctx);
++ ret = -EFAULT;
++ }
++
++ kfree(smpl_arg);
++
++ return ret;
++}
++
++/*
++ * obsolete call: use /proc/perfmon
++ */
++static long pfm_get_features_old(int fd, void __user *arg, int count)
++{
++ struct pfarg_features req;
++ int ret = 0;
++
++ if (count != 1)
++ return -EINVAL;
++
++ memset(&req, 0, sizeof(req));
++
++ req.ft_version = PFM_VERSION;
++
++ if (copy_to_user(arg, &req, sizeof(req)))
++ ret = -EFAULT;
++
++ return ret;
++}
++
++static long pfm_debug_old(int fd, void __user *arg, int count)
++{
++ int m;
++
++ if (count != 1)
++ return -EINVAL;
++
++ if (get_user(m, (int __user *)arg))
++ return -EFAULT;
++
++
++ pfm_controls.debug = m == 0 ? 0 : 1;
++
++ PFM_INFO("debugging %s (timing reset)",
++ pfm_controls.debug ? "on" : "off");
++
++ if (m == 0)
++ for_each_online_cpu(m) {
++ memset(&per_cpu(pfm_stats, m), 0,
++ sizeof(struct pfm_stats));
++ }
++ return 0;
++}
++
++static long pfm_unload_context_old(int fd, void __user *arg, int count)
++{
++ if (count)
++ return -EINVAL;
++
++ return sys_pfm_unload_context(fd);
++}
++
++static long pfm_restart_old(int fd, void __user *arg, int count)
++{
++ if (count)
++ return -EINVAL;
++
++ return sys_pfm_restart(fd);
++}
++
++static long pfm_stop_old(int fd, void __user *arg, int count)
++{
++ if (count)
++ return -EINVAL;
++
++ return sys_pfm_stop(fd);
++}
++
++static long pfm_start_old(int fd, void __user *arg, int count)
++{
++ if (count > 1)
++ return -EINVAL;
++
++ return sys_pfm_start(fd, arg);
++}
++
++static long pfm_load_context_old(int fd, void __user *ureq, int count)
++{
++ if (count != 1)
++ return -EINVAL;
++
++ return sys_pfm_load_context(fd, ureq);
++}
++
++/*
++ * perfmon command descriptions
++ */
++struct pfm_cmd_desc {
++ long (*cmd_func)(int fd, void __user *arg, int count);
++};
++
++/*
++ * functions MUST be listed in the increasing order of
++ * their index (see permfon.h)
++ */
++#define PFM_CMD(name) \
++ { .cmd_func = name, \
++ }
++#define PFM_CMD_NONE \
++ { .cmd_func = NULL \
++ }
++
++static struct pfm_cmd_desc pfm_cmd_tab[] = {
++/* 0 */PFM_CMD_NONE,
++/* 1 */PFM_CMD(pfm_write_pmcs_old),
++/* 2 */PFM_CMD(pfm_write_pmds_old),
++/* 3 */PFM_CMD(pfm_read_pmds_old),
++/* 4 */PFM_CMD(pfm_stop_old),
++/* 5 */PFM_CMD(pfm_start_old),
++/* 6 */PFM_CMD_NONE,
++/* 7 */PFM_CMD_NONE,
++/* 8 */PFM_CMD(pfm_create_context_old),
++/* 9 */PFM_CMD_NONE,
++/* 10 */PFM_CMD(pfm_restart_old),
++/* 11 */PFM_CMD_NONE,
++/* 12 */PFM_CMD(pfm_get_features_old),
++/* 13 */PFM_CMD(pfm_debug_old),
++/* 14 */PFM_CMD_NONE,
++/* 15 */PFM_CMD(pfm_get_default_pmcs_old),
++/* 16 */PFM_CMD(pfm_load_context_old),
++/* 17 */PFM_CMD(pfm_unload_context_old),
++/* 18 */PFM_CMD_NONE,
++/* 19 */PFM_CMD_NONE,
++/* 20 */PFM_CMD_NONE,
++/* 21 */PFM_CMD_NONE,
++/* 22 */PFM_CMD_NONE,
++/* 23 */PFM_CMD_NONE,
++/* 24 */PFM_CMD_NONE,
++/* 25 */PFM_CMD_NONE,
++/* 26 */PFM_CMD_NONE,
++/* 27 */PFM_CMD_NONE,
++/* 28 */PFM_CMD_NONE,
++/* 29 */PFM_CMD_NONE,
++/* 30 */PFM_CMD_NONE,
++/* 31 */PFM_CMD_NONE,
++/* 32 */PFM_CMD(pfm_write_ibrs_old),
++/* 33 */PFM_CMD(pfm_write_dbrs_old),
++};
++#define PFM_CMD_COUNT ARRAY_SIZE(pfm_cmd_tab)
++
++/*
++ * system-call entry point (must return long)
++ */
++asmlinkage long sys_perfmonctl(int fd, int cmd, void __user *arg, int count)
++{
++ if (perfmon_disabled)
++ return -ENOSYS;
++
++ if (unlikely(cmd < 0 || cmd >= PFM_CMD_COUNT
++ || pfm_cmd_tab[cmd].cmd_func == NULL)) {
++ PFM_DBG("invalid cmd=%d", cmd);
++ return -EINVAL;
++ }
++ return (long)pfm_cmd_tab[cmd].cmd_func(fd, arg, count);
++}
++
++/*
++ * Called from pfm_read() for a perfmon v2.0 context.
++ *
++ * compatibility mode pfm_read() routine. We need a separate
++ * routine because the definition of the message has changed.
++ * The pfm_msg and pfarg_msg structures are different.
++ *
++ * return: sizeof(pfm_msg_t) on success, -errno otherwise
++ */
++ssize_t pfm_arch_compat_read(struct pfm_context *ctx,
++ char __user *buf,
++ int non_block,
++ size_t size)
++{
++ union pfarg_msg msg_buf;
++ pfm_msg_t old_msg_buf;
++ pfm_ovfl_msg_t *o_msg;
++ struct pfarg_ovfl_msg *n_msg;
++ int ret;
++
++ PFM_DBG("msg=%p size=%zu", buf, size);
++
++ /*
++ * cannot extract partial messages.
++ * check even when there is no message
++ *
++ * cannot extract more than one message per call. Bytes
++ * above sizeof(msg) are ignored.
++ */
++ if (size < sizeof(old_msg_buf)) {
++ PFM_DBG("message is too small size=%zu must be >=%zu)",
++ size,
++ sizeof(old_msg_buf));
++ return -EINVAL;
++ }
++
++ ret = __pfm_read(ctx, &msg_buf, non_block);
++ if (ret < 1)
++ return ret;
++
++ /*
++ * force return value to old message size
++ */
++ ret = sizeof(old_msg_buf);
++
++ o_msg = &old_msg_buf.pfm_ovfl_msg;
++ n_msg = &msg_buf.pfm_ovfl_msg;
++
++ switch (msg_buf.type) {
++ case PFM_MSG_OVFL:
++ o_msg->msg_type = PFM_MSG_OVFL;
++ o_msg->msg_ctx_fd = 0;
++ o_msg->msg_active_set = n_msg->msg_active_set;
++ o_msg->msg_tstamp = 0;
++
++ o_msg->msg_ovfl_pmds[0] = n_msg->msg_ovfl_pmds[0];
++ o_msg->msg_ovfl_pmds[1] = n_msg->msg_ovfl_pmds[1];
++ o_msg->msg_ovfl_pmds[2] = n_msg->msg_ovfl_pmds[2];
++ o_msg->msg_ovfl_pmds[3] = n_msg->msg_ovfl_pmds[3];
++ break;
++ case PFM_MSG_END:
++ o_msg->msg_type = PFM_MSG_END;
++ o_msg->msg_ctx_fd = 0;
++ o_msg->msg_tstamp = 0;
++ break;
++ default:
++ PFM_DBG("unknown msg type=%d", msg_buf.type);
++ }
++ if (copy_to_user(buf, &old_msg_buf, sizeof(old_msg_buf)))
++ ret = -EFAULT;
++ PFM_DBG_ovfl("ret=%d", ret);
++ return ret;
++}
++
++/*
++ * legacy /proc/perfmon simplified interface (we only maintain the
++ * global information (no more per-cpu stats, use
++ * /sys/devices/system/cpu/cpuXX/perfmon
++ */
++static struct proc_dir_entry *perfmon_proc;
++
++static void *pfm_proc_start(struct seq_file *m, loff_t *pos)
++{
++ if (*pos == 0)
++ return (void *)1;
++
++ return NULL;
++}
++
++static void *pfm_proc_next(struct seq_file *m, void *v, loff_t *pos)
++{
++ ++*pos;
++ return pfm_proc_start(m, pos);
++}
++
++static void pfm_proc_stop(struct seq_file *m, void *v)
++{
++}
++
++/*
++ * this is a simplified version of the legacy /proc/perfmon.
++ * We have retained ONLY the key information that tools are actually
++ * using
++ */
++static void pfm_proc_show_header(struct seq_file *m)
++{
++ char buf[128];
++
++ pfm_sysfs_res_show(buf, sizeof(buf), 3);
++
++ seq_printf(m, "perfmon version : %u.%u\n",
++ PFM_VERSION_MAJ, PFM_VERSION_MIN);
++
++ seq_printf(m, "model : %s", buf);
++}
++
++static int pfm_proc_show(struct seq_file *m, void *v)
++{
++ pfm_proc_show_header(m);
++ return 0;
++}
++
++struct seq_operations pfm_proc_seq_ops = {
++ .start = pfm_proc_start,
++ .next = pfm_proc_next,
++ .stop = pfm_proc_stop,
++ .show = pfm_proc_show
++};
++
++static int pfm_proc_open(struct inode *inode, struct file *file)
++{
++ return seq_open(file, &pfm_proc_seq_ops);
++}
++
++
++static struct file_operations pfm_proc_fops = {
++ .open = pfm_proc_open,
++ .read = seq_read,
++ .llseek = seq_lseek,
++ .release = seq_release,
++};
++
++/*
++ * called from pfm_arch_init(), global initialization, called once
++ */
++int __init pfm_ia64_compat_init(void)
++{
++ /*
++ * create /proc/perfmon
++ */
++ perfmon_proc = create_proc_entry("perfmon", S_IRUGO, NULL);
++ if (perfmon_proc == NULL) {
++ PFM_ERR("cannot create /proc entry, perfmon disabled");
++ return -1;
++ }
++ perfmon_proc->proc_fops = &pfm_proc_fops;
++ return 0;
++}
+diff --git a/arch/ia64/perfmon/perfmon_default_smpl.c b/arch/ia64/perfmon/perfmon_default_smpl.c
+new file mode 100644
+index 0000000..b408a13
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_default_smpl.c
+@@ -0,0 +1,273 @@
++/*
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This file implements the old default sampling buffer format
++ * for the Linux/ia64 perfmon-2 subsystem. This is for backward
++ * compatibility only. use the new default format in perfmon/
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/smp.h>
++#include <linux/sysctl.h>
++
++#ifdef MODULE
++#define FMT_FLAGS 0
++#else
++#define FMT_FLAGS PFM_FMTFL_IS_BUILTIN
++#endif
++
++#include <linux/perfmon_kern.h>
++#include <asm/perfmon_default_smpl.h>
++
++MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
++MODULE_DESCRIPTION("perfmon old default sampling format");
++MODULE_LICENSE("GPL");
++
++static int pfm_default_fmt_validate(u32 flags, u16 npmds, void *data)
++{
++ struct pfm_default_smpl_arg *arg = data;
++ size_t min_buf_size;
++
++ if (data == NULL) {
++ PFM_DBG("no argument passed");
++ return -EINVAL;
++ }
++
++ /*
++ * compute min buf size. All PMD are manipulated as 64bit entities
++ */
++ min_buf_size = sizeof(struct pfm_default_smpl_hdr)
++ + (sizeof(struct pfm_default_smpl_entry) + (npmds*sizeof(u64)));
++
++ PFM_DBG("validate flags=0x%x npmds=%u min_buf_size=%lu "
++ "buf_size=%lu CPU%d", flags, npmds, min_buf_size,
++ arg->buf_size, smp_processor_id());
++
++ /*
++ * must hold at least the buffer header + one minimally sized entry
++ */
++ if (arg->buf_size < min_buf_size)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int pfm_default_fmt_get_size(unsigned int flags, void *data,
++ size_t *size)
++{
++ struct pfm_default_smpl_arg *arg = data;
++
++ /*
++ * size has been validated in default_validate
++ */
++ *size = arg->buf_size;
++
++ return 0;
++}
++
++static int pfm_default_fmt_init(struct pfm_context *ctx, void *buf,
++ u32 flags, u16 npmds, void *data)
++{
++ struct pfm_default_smpl_hdr *hdr;
++ struct pfm_default_smpl_arg *arg = data;
++
++ hdr = buf;
++
++ hdr->hdr_version = PFM_DEFAULT_SMPL_VERSION;
++ hdr->hdr_buf_size = arg->buf_size;
++ hdr->hdr_cur_offs = sizeof(*hdr);
++ hdr->hdr_overflows = 0;
++ hdr->hdr_count = 0;
++
++ PFM_DBG("buffer=%p buf_size=%lu hdr_size=%lu "
++ "hdr_version=%u cur_offs=%lu",
++ buf,
++ hdr->hdr_buf_size,
++ sizeof(*hdr),
++ hdr->hdr_version,
++ hdr->hdr_cur_offs);
++
++ return 0;
++}
++
++static int pfm_default_fmt_handler(struct pfm_context *ctx,
++ unsigned long ip, u64 tstamp, void *data)
++{
++ struct pfm_default_smpl_hdr *hdr;
++ struct pfm_default_smpl_entry *ent;
++ void *cur, *last, *buf;
++ u64 *e;
++ size_t entry_size;
++ u16 npmds, i, ovfl_pmd;
++ struct pfm_ovfl_arg *arg;
++
++ hdr = ctx->smpl_addr;
++ arg = &ctx->ovfl_arg;
++
++ buf = hdr;
++ cur = buf+hdr->hdr_cur_offs;
++ last = buf+hdr->hdr_buf_size;
++ ovfl_pmd = arg->ovfl_pmd;
++
++ /*
++ * precheck for sanity
++ */
++ if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE)
++ goto full;
++
++ npmds = arg->num_smpl_pmds;
++
++ ent = cur;
++
++ prefetch(arg->smpl_pmds_values);
++
++ entry_size = sizeof(*ent) + (npmds << 3);
++
++ /* position for first pmd */
++ e = (unsigned long *)(ent+1);
++
++ hdr->hdr_count++;
++
++ PFM_DBG_ovfl("count=%lu cur=%p last=%p free_bytes=%lu "
++ "ovfl_pmd=%d npmds=%u",
++ hdr->hdr_count,
++ cur, last,
++ last-cur,
++ ovfl_pmd,
++ npmds);
++
++ /*
++ * current = task running at the time of the overflow.
++ *
++ * per-task mode:
++ * - this is ususally the task being monitored.
++ * Under certain conditions, it might be a different task
++ *
++ * system-wide:
++ * - this is not necessarily the task controlling the session
++ */
++ ent->pid = current->pid;
++ ent->ovfl_pmd = ovfl_pmd;
++ ent->last_reset_val = arg->pmd_last_reset;
++
++ /*
++ * where did the fault happen (includes slot number)
++ */
++ ent->ip = ip;
++
++ ent->tstamp = tstamp;
++ ent->cpu = smp_processor_id();
++ ent->set = arg->active_set;
++ ent->tgid = current->tgid;
++
++ /*
++ * selectively store PMDs in increasing index number
++ */
++ if (npmds) {
++ u64 *val = arg->smpl_pmds_values;
++ for (i = 0; i < npmds; i++)
++ *e++ = *val++;
++ }
++
++ /*
++ * update position for next entry
++ */
++ hdr->hdr_cur_offs += entry_size;
++ cur += entry_size;
++
++ /*
++ * post check to avoid losing the last sample
++ */
++ if ((last - cur) < PFM_DEFAULT_MAX_ENTRY_SIZE)
++ goto full;
++
++ /*
++ * reset before returning from interrupt handler
++ */
++ arg->ovfl_ctrl = PFM_OVFL_CTRL_RESET;
++ return 0;
++full:
++ PFM_DBG_ovfl("smpl buffer full free=%lu, count=%lu",
++ last-cur, hdr->hdr_count);
++
++ /*
++ * increment number of buffer overflow.
++ * important to detect duplicate set of samples.
++ */
++ hdr->hdr_overflows++;
++
++ /*
++ * request notification and masking of monitoring.
++ * Notification is still subject to the overflowed
++ */
++ arg->ovfl_ctrl = PFM_OVFL_CTRL_NOTIFY | PFM_OVFL_CTRL_MASK;
++
++ return -ENOBUFS; /* we are full, sorry */
++}
++
++static int pfm_default_fmt_restart(int is_active, u32 *ovfl_ctrl, void *buf)
++{
++ struct pfm_default_smpl_hdr *hdr;
++
++ hdr = buf;
++
++ hdr->hdr_count = 0;
++ hdr->hdr_cur_offs = sizeof(*hdr);
++
++ *ovfl_ctrl = PFM_OVFL_CTRL_RESET;
++
++ return 0;
++}
++
++static int pfm_default_fmt_exit(void *buf)
++{
++ return 0;
++}
++
++static struct pfm_smpl_fmt default_fmt = {
++ .fmt_name = "default-old",
++ .fmt_version = 0x10000,
++ .fmt_arg_size = sizeof(struct pfm_default_smpl_arg),
++ .fmt_validate = pfm_default_fmt_validate,
++ .fmt_getsize = pfm_default_fmt_get_size,
++ .fmt_init = pfm_default_fmt_init,
++ .fmt_handler = pfm_default_fmt_handler,
++ .fmt_restart = pfm_default_fmt_restart,
++ .fmt_exit = pfm_default_fmt_exit,
++ .fmt_flags = FMT_FLAGS,
++ .owner = THIS_MODULE
++};
++
++static int pfm_default_fmt_init_module(void)
++{
++ int ret;
++
++ return pfm_fmt_register(&default_fmt);
++ return ret;
++}
++
++static void pfm_default_fmt_cleanup_module(void)
++{
++ pfm_fmt_unregister(&default_fmt);
++}
++
++module_init(pfm_default_fmt_init_module);
++module_exit(pfm_default_fmt_cleanup_module);
+diff --git a/arch/ia64/perfmon/perfmon_generic.c b/arch/ia64/perfmon/perfmon_generic.c
+new file mode 100644
+index 0000000..47b1870
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_generic.c
+@@ -0,0 +1,148 @@
++/*
++ * This file contains the generic PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++#include <asm/pal.h>
++
++MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
++MODULE_DESCRIPTION("Generic IA-64 PMU description tables");
++MODULE_LICENSE("GPL");
++
++#define RDEP(x) (1UL << (x))
++
++#define PFM_IA64GEN_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7))
++#define PFM_IA64GEN_RSVD (0xffffffffffff0080UL)
++#define PFM_IA64GEN_NO64 (1UL<<5)
++
++/* forward declaration */
++static struct pfm_pmu_config pfm_ia64gen_pmu_conf;
++
++static struct pfm_arch_pmu_info pfm_ia64gen_pmu_info = {
++ .mask_pmcs = {PFM_IA64GEN_MASK_PMCS,},
++};
++
++static struct pfm_regmap_desc pfm_ia64gen_pmc_desc[] = {
++/* pmc0 */ PMX_NA,
++/* pmc1 */ PMX_NA,
++/* pmc2 */ PMX_NA,
++/* pmc3 */ PMX_NA,
++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 4),
++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 5),
++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 6),
++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7", 0x0, PFM_IA64GEN_RSVD, PFM_IA64GEN_NO64, 7)
++};
++#define PFM_IA64GEN_NUM_PMCS ARRAY_SIZE(pfm_ia64gen_pmc_desc)
++
++static struct pfm_regmap_desc pfm_ia64gen_pmd_desc[] = {
++/* pmd0 */ PMX_NA,
++/* pmd1 */ PMX_NA,
++/* pmd2 */ PMX_NA,
++/* pmd3 */ PMX_NA,
++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4),
++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5),
++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6),
++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7)
++};
++#define PFM_IA64GEN_NUM_PMDS ARRAY_SIZE(pfm_ia64gen_pmd_desc)
++
++static int pfm_ia64gen_pmc_check(struct pfm_context *ctx,
++ struct pfm_event_set *set,
++ struct pfarg_pmc *req)
++{
++#define PFM_IA64GEN_PMC_PM_POS6 (1UL<<6)
++ u64 tmpval;
++ int is_system;
++
++ is_system = ctx->flags.system;
++ tmpval = req->reg_value;
++
++ switch (req->reg_num) {
++ case 4:
++ case 5:
++ case 6:
++ case 7:
++ /* set pmc.oi for 64-bit emulation */
++ tmpval |= 1UL << 5;
++
++ if (is_system)
++ tmpval |= PFM_IA64GEN_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_IA64GEN_PMC_PM_POS6;
++ break;
++
++ }
++ req->reg_value = tmpval;
++
++ return 0;
++}
++
++/*
++ * matches anything
++ */
++static int pfm_ia64gen_probe_pmu(void)
++{
++ u64 pm_buffer[16];
++ pal_perf_mon_info_u_t pm_info;
++
++ /*
++ * call PAL_PERFMON_INFO to retrieve counter width which
++ * is implementation specific
++ */
++ if (ia64_pal_perf_mon_info(pm_buffer, &pm_info))
++ return -1;
++
++ pfm_ia64gen_pmu_conf.counter_width = pm_info.pal_perf_mon_info_s.width;
++
++ return 0;
++}
++
++/*
++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
++ */
++static struct pfm_pmu_config pfm_ia64gen_pmu_conf = {
++ .pmu_name = "Generic IA-64",
++ .counter_width = 0, /* computed from PAL_PERFMON_INFO */
++ .pmd_desc = pfm_ia64gen_pmd_desc,
++ .pmc_desc = pfm_ia64gen_pmc_desc,
++ .probe_pmu = pfm_ia64gen_probe_pmu,
++ .num_pmc_entries = PFM_IA64GEN_NUM_PMCS,
++ .num_pmd_entries = PFM_IA64GEN_NUM_PMDS,
++ .pmc_write_check = pfm_ia64gen_pmc_check,
++ .version = "1.0",
++ .flags = PFM_PMU_BUILTIN_FLAG,
++ .owner = THIS_MODULE,
++ .pmu_info = &pfm_ia64gen_pmu_info
++ /* no read/write checkers */
++};
++
++static int __init pfm_gen_pmu_init_module(void)
++{
++ return pfm_pmu_register(&pfm_ia64gen_pmu_conf);
++}
++
++static void __exit pfm_gen_pmu_cleanup_module(void)
++{
++ pfm_pmu_unregister(&pfm_ia64gen_pmu_conf);
++}
++
++module_init(pfm_gen_pmu_init_module);
++module_exit(pfm_gen_pmu_cleanup_module);
+diff --git a/arch/ia64/perfmon/perfmon_itanium.c b/arch/ia64/perfmon/perfmon_itanium.c
+new file mode 100644
+index 0000000..094b31b
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_itanium.c
+@@ -0,0 +1,232 @@
++/*
++ * This file contains the Itanium PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++
++MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
++MODULE_DESCRIPTION("Itanium (Merced) PMU description tables");
++MODULE_LICENSE("GPL");
++
++#define RDEP(x) (1ULL << (x))
++
++#define PFM_ITA_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|RDEP(10)|RDEP(11)|\
++ RDEP(12))
++
++#define PFM_ITA_NO64 (1ULL<<5)
++
++static struct pfm_arch_pmu_info pfm_ita_pmu_info = {
++ .mask_pmcs = {PFM_ITA_MASK_PMCS,},
++};
++/* reserved bits are 1 in the mask */
++#define PFM_ITA_RSVD 0xfffffffffc8000a0UL
++/*
++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using
++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information
++ * but this is fine because they are handled separately in the IA-64 specific
++ * code.
++ */
++static struct pfm_regmap_desc pfm_ita_pmc_desc[] = {
++/* pmc0 */ PMX_NA,
++/* pmc1 */ PMX_NA,
++/* pmc2 */ PMX_NA,
++/* pmc3 */ PMX_NA,
++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 4),
++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 5),
++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 6),
++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x20, PFM_ITA_RSVD, PFM_ITA_NO64, 7),
++/* pmc8 */ PMC_D(PFM_REG_W , "PMC8" , 0xfffffffe3ffffff8UL, 0xfff00000001c0000UL, 0, 8),
++/* pmc9 */ PMC_D(PFM_REG_W , "PMC9" , 0xfffffffe3ffffff8UL, 0xfff00000001c0000UL, 0, 9),
++/* pmc10 */ PMC_D(PFM_REG_W , "PMC10", 0x0, 0xfffffffff3f0ff30UL, 0, 10),
++/* pmc11 */ PMC_D(PFM_REG_W , "PMC11", 0x10000000UL, 0xffffffffecf0ff30UL, 0, 11),
++/* pmc12 */ PMC_D(PFM_REG_W , "PMC12", 0x0, 0xffffffffffff0030UL, 0, 12),
++/* pmc13 */ PMC_D(PFM_REG_W , "PMC13", 0x3ffff00000001UL, 0xfffffffffffffffeUL, 0, 13),
++/* pmc14 */ PMX_NA,
++/* pmc15 */ PMX_NA,
++/* pmc16 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc24 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc32 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc40 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc256 */ PMC_D(PFM_REG_W , "IBR0", 0x0, 0, 0, 0),
++/* pmc257 */ PMC_D(PFM_REG_W , "IBR1", 0x0, 0x8000000000000000UL, 0, 1),
++/* pmc258 */ PMC_D(PFM_REG_W , "IBR2", 0x0, 0, 0, 2),
++/* pmc259 */ PMC_D(PFM_REG_W , "IBR3", 0x0, 0x8000000000000000UL, 0, 3),
++/* pmc260 */ PMC_D(PFM_REG_W , "IBR4", 0x0, 0, 0, 4),
++/* pmc261 */ PMC_D(PFM_REG_W , "IBR5", 0x0, 0x8000000000000000UL, 0, 5),
++/* pmc262 */ PMC_D(PFM_REG_W , "IBR6", 0x0, 0, 0, 6),
++/* pmc263 */ PMC_D(PFM_REG_W , "IBR7", 0x0, 0x8000000000000000UL, 0, 7),
++/* pmc264 */ PMC_D(PFM_REG_W , "DBR0", 0x0, 0, 0, 0),
++/* pmc265 */ PMC_D(PFM_REG_W , "DBR1", 0x0, 0xc000000000000000UL, 0, 1),
++/* pmc266 */ PMC_D(PFM_REG_W , "DBR2", 0x0, 0, 0, 2),
++/* pmc267 */ PMC_D(PFM_REG_W , "DBR3", 0x0, 0xc000000000000000UL, 0, 3),
++/* pmc268 */ PMC_D(PFM_REG_W , "DBR4", 0x0, 0, 0, 4),
++/* pmc269 */ PMC_D(PFM_REG_W , "DBR5", 0x0, 0xc000000000000000UL, 0, 5),
++/* pmc270 */ PMC_D(PFM_REG_W , "DBR6", 0x0, 0, 0, 6),
++/* pmc271 */ PMC_D(PFM_REG_W , "DBR7", 0x0, 0xc000000000000000UL, 0, 7)
++};
++#define PFM_ITA_NUM_PMCS ARRAY_SIZE(pfm_ita_pmc_desc)
++
++static struct pfm_regmap_desc pfm_ita_pmd_desc[] = {
++/* pmd0 */ PMD_DP(PFM_REG_I , "PMD0", 0, 1ull << 10),
++/* pmd1 */ PMD_DP(PFM_REG_I , "PMD1", 1, 1ull << 10),
++/* pmd2 */ PMD_DP(PFM_REG_I , "PMD2", 2, 1ull << 11),
++/* pmd3 */ PMD_DP(PFM_REG_I , "PMD3", 3, 1ull << 11),
++/* pmd4 */ PMD_DP(PFM_REG_C , "PMD4", 4, 1ull << 4),
++/* pmd5 */ PMD_DP(PFM_REG_C , "PMD5", 5, 1ull << 5),
++/* pmd6 */ PMD_DP(PFM_REG_C , "PMD6", 6, 1ull << 6),
++/* pmd7 */ PMD_DP(PFM_REG_C , "PMD7", 7, 1ull << 7),
++/* pmd8 */ PMD_DP(PFM_REG_I , "PMD8", 8, 1ull << 12),
++/* pmd9 */ PMD_DP(PFM_REG_I , "PMD9", 9, 1ull << 12),
++/* pmd10 */ PMD_DP(PFM_REG_I , "PMD10", 10, 1ull << 12),
++/* pmd11 */ PMD_DP(PFM_REG_I , "PMD11", 11, 1ull << 12),
++/* pmd12 */ PMD_DP(PFM_REG_I , "PMD12", 12, 1ull << 12),
++/* pmd13 */ PMD_DP(PFM_REG_I , "PMD13", 13, 1ull << 12),
++/* pmd14 */ PMD_DP(PFM_REG_I , "PMD14", 14, 1ull << 12),
++/* pmd15 */ PMD_DP(PFM_REG_I , "PMD15", 15, 1ull << 12),
++/* pmd16 */ PMD_DP(PFM_REG_I , "PMD16", 16, 1ull << 12),
++/* pmd17 */ PMD_DP(PFM_REG_I , "PMD17", 17, 1ull << 11)
++};
++#define PFM_ITA_NUM_PMDS ARRAY_SIZE(pfm_ita_pmd_desc)
++
++static int pfm_ita_pmc_check(struct pfm_context *ctx,
++ struct pfm_event_set *set,
++ struct pfarg_pmc *req)
++{
++#define PFM_ITA_PMC_PM_POS6 (1UL<<6)
++ struct pfm_arch_context *ctx_arch;
++ u64 tmpval;
++ u16 cnum;
++ int ret = 0, is_system;
++
++ tmpval = req->reg_value;
++ cnum = req->reg_num;
++ ctx_arch = pfm_ctx_arch(ctx);
++ is_system = ctx->flags.system;
++
++ switch (cnum) {
++ case 4:
++ case 5:
++ case 6:
++ case 7:
++ case 10:
++ case 11:
++ case 12:
++ if (is_system)
++ tmpval |= PFM_ITA_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_ITA_PMC_PM_POS6;
++ break;
++ }
++
++ /*
++ * we must clear the (instruction) debug registers if pmc13.ta bit is
++ * cleared before they are written (fl_using_dbreg==0) to avoid
++ * picking up stale information.
++ */
++ if (cnum == 13 && ((tmpval & 0x1) == 0)
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc13 has pmc13.ta cleared, clearing ibr");
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * we must clear the (data) debug registers if pmc11.pt bit is cleared
++ * before they are written (fl_using_dbreg==0) to avoid picking up
++ * stale information.
++ */
++ if (cnum == 11 && ((tmpval >> 28) & 0x1) == 0
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc11 has pmc11.pt cleared, clearing dbr");
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++ }
++
++ req->reg_value = tmpval;
++
++ return 0;
++}
++
++static int pfm_ita_probe_pmu(void)
++{
++ return local_cpu_data->family == 0x7 && !ia64_platform_is("hpsim")
++ ? 0 : -1;
++}
++
++/*
++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
++ */
++static struct pfm_pmu_config pfm_ita_pmu_conf = {
++ .pmu_name = "Itanium",
++ .counter_width = 32,
++ .pmd_desc = pfm_ita_pmd_desc,
++ .pmc_desc = pfm_ita_pmc_desc,
++ .pmc_write_check = pfm_ita_pmc_check,
++ .num_pmc_entries = PFM_ITA_NUM_PMCS,
++ .num_pmd_entries = PFM_ITA_NUM_PMDS,
++ .probe_pmu = pfm_ita_probe_pmu,
++ .version = "1.0",
++ .flags = PFM_PMU_BUILTIN_FLAG,
++ .owner = THIS_MODULE,
++ .pmu_info = &pfm_ita_pmu_info
++};
++
++static int __init pfm_ita_pmu_init_module(void)
++{
++ return pfm_pmu_register(&pfm_ita_pmu_conf);
++}
++
++static void __exit pfm_ita_pmu_cleanup_module(void)
++{
++ pfm_pmu_unregister(&pfm_ita_pmu_conf);
++}
++
++module_init(pfm_ita_pmu_init_module);
++module_exit(pfm_ita_pmu_cleanup_module);
++
+diff --git a/arch/ia64/perfmon/perfmon_mckinley.c b/arch/ia64/perfmon/perfmon_mckinley.c
+new file mode 100644
+index 0000000..dc59092
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_mckinley.c
+@@ -0,0 +1,290 @@
++/*
++ * This file contains the McKinley PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++
++MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
++MODULE_DESCRIPTION("Itanium 2 (McKinley) PMU description tables");
++MODULE_LICENSE("GPL");
++
++#define RDEP(x) (1UL << (x))
++
++#define PFM_MCK_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|RDEP(10)|RDEP(11)|\
++ RDEP(12))
++
++#define PFM_MCK_NO64 (1UL<<5)
++
++static struct pfm_arch_pmu_info pfm_mck_pmu_info = {
++ .mask_pmcs = {PFM_MCK_MASK_PMCS,},
++};
++
++/* reserved bits are 1 in the mask */
++#define PFM_ITA2_RSVD 0xfffffffffc8000a0UL
++
++/*
++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using
++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information
++ * but this is fine because they are handled separately in the IA-64 specific
++ * code.
++ */
++static struct pfm_regmap_desc pfm_mck_pmc_desc[] = {
++/* pmc0 */ PMX_NA,
++/* pmc1 */ PMX_NA,
++/* pmc2 */ PMX_NA,
++/* pmc3 */ PMX_NA,
++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x800020UL, 0xfffffffffc8000a0, PFM_MCK_NO64, 4),
++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 5),
++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 6),
++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x20UL, PFM_ITA2_RSVD, PFM_MCK_NO64, 7),
++/* pmc8 */ PMC_D(PFM_REG_W , "PMC8" , 0xffffffff3fffffffUL, 0xc0000004UL, 0, 8),
++/* pmc9 */ PMC_D(PFM_REG_W , "PMC9" , 0xffffffff3ffffffcUL, 0xc0000004UL, 0, 9),
++/* pmc10 */ PMC_D(PFM_REG_W , "PMC10", 0x0, 0xffffffffffff0000UL, 0, 10),
++/* pmc11 */ PMC_D(PFM_REG_W , "PMC11", 0x0, 0xfffffffffcf0fe30UL, 0, 11),
++/* pmc12 */ PMC_D(PFM_REG_W , "PMC12", 0x0, 0xffffffffffff0000UL, 0, 12),
++/* pmc13 */ PMC_D(PFM_REG_W , "PMC13", 0x2078fefefefeUL, 0xfffe1fffe7e7e7e7UL, 0, 13),
++/* pmc14 */ PMC_D(PFM_REG_W , "PMC14", 0x0db60db60db60db6UL, 0xffffffffffffdb6dUL, 0, 14),
++/* pmc15 */ PMC_D(PFM_REG_W , "PMC15", 0xfffffff0UL, 0xfffffffffffffff0UL, 0, 15),
++/* pmc16 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc24 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc32 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc40 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc256 */ PMC_D(PFM_REG_W , "IBR0", 0x0, 0, 0, 0),
++/* pmc257 */ PMC_D(PFM_REG_W , "IBR1", 0x0, 0x8000000000000000UL, 0, 1),
++/* pmc258 */ PMC_D(PFM_REG_W , "IBR2", 0x0, 0, 0, 2),
++/* pmc259 */ PMC_D(PFM_REG_W , "IBR3", 0x0, 0x8000000000000000UL, 0, 3),
++/* pmc260 */ PMC_D(PFM_REG_W , "IBR4", 0x0, 0, 0, 4),
++/* pmc261 */ PMC_D(PFM_REG_W , "IBR5", 0x0, 0x8000000000000000UL, 0, 5),
++/* pmc262 */ PMC_D(PFM_REG_W , "IBR6", 0x0, 0, 0, 6),
++/* pmc263 */ PMC_D(PFM_REG_W , "IBR7", 0x0, 0x8000000000000000UL, 0, 7),
++/* pmc264 */ PMC_D(PFM_REG_W , "DBR0", 0x0, 0, 0, 0),
++/* pmc265 */ PMC_D(PFM_REG_W , "DBR1", 0x0, 0xc000000000000000UL, 0, 1),
++/* pmc266 */ PMC_D(PFM_REG_W , "DBR2", 0x0, 0, 0, 2),
++/* pmc267 */ PMC_D(PFM_REG_W , "DBR3", 0x0, 0xc000000000000000UL, 0, 3),
++/* pmc268 */ PMC_D(PFM_REG_W , "DBR4", 0x0, 0, 0, 4),
++/* pmc269 */ PMC_D(PFM_REG_W , "DBR5", 0x0, 0xc000000000000000UL, 0, 5),
++/* pmc270 */ PMC_D(PFM_REG_W , "DBR6", 0x0, 0, 0, 6),
++/* pmc271 */ PMC_D(PFM_REG_W , "DBR7", 0x0, 0xc000000000000000UL, 0, 7)
++};
++#define PFM_MCK_NUM_PMCS ARRAY_SIZE(pfm_mck_pmc_desc)
++
++static struct pfm_regmap_desc pfm_mck_pmd_desc[] = {
++/* pmd0 */ PMD_DP(PFM_REG_I, "PMD0", 0, 1ull << 10),
++/* pmd1 */ PMD_DP(PFM_REG_I, "PMD1", 1, 1ull << 10),
++/* pmd2 */ PMD_DP(PFM_REG_I, "PMD2", 2, 1ull << 11),
++/* pmd3 */ PMD_DP(PFM_REG_I, "PMD3", 3, 1ull << 11),
++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4),
++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5),
++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6),
++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7),
++/* pmd8 */ PMD_DP(PFM_REG_I, "PMD8", 8, 1ull << 12),
++/* pmd9 */ PMD_DP(PFM_REG_I, "PMD9", 9, 1ull << 12),
++/* pmd10 */ PMD_DP(PFM_REG_I, "PMD10", 10, 1ull << 12),
++/* pmd11 */ PMD_DP(PFM_REG_I, "PMD11", 11, 1ull << 12),
++/* pmd12 */ PMD_DP(PFM_REG_I, "PMD12", 12, 1ull << 12),
++/* pmd13 */ PMD_DP(PFM_REG_I, "PMD13", 13, 1ull << 12),
++/* pmd14 */ PMD_DP(PFM_REG_I, "PMD14", 14, 1ull << 12),
++/* pmd15 */ PMD_DP(PFM_REG_I, "PMD15", 15, 1ull << 12),
++/* pmd16 */ PMD_DP(PFM_REG_I, "PMD16", 16, 1ull << 12),
++/* pmd17 */ PMD_DP(PFM_REG_I, "PMD17", 17, 1ull << 11)
++};
++#define PFM_MCK_NUM_PMDS ARRAY_SIZE(pfm_mck_pmd_desc)
++
++static int pfm_mck_pmc_check(struct pfm_context *ctx,
++ struct pfm_event_set *set,
++ struct pfarg_pmc *req)
++{
++ struct pfm_arch_context *ctx_arch;
++ u64 val8 = 0, val14 = 0, val13 = 0;
++ u64 tmpval;
++ u16 cnum;
++ int ret = 0, check_case1 = 0;
++ int is_system;
++
++ tmpval = req->reg_value;
++ cnum = req->reg_num;
++ ctx_arch = pfm_ctx_arch(ctx);
++ is_system = ctx->flags.system;
++
++#define PFM_MCK_PMC_PM_POS6 (1UL<<6)
++#define PFM_MCK_PMC_PM_POS4 (1UL<<4)
++
++ switch (cnum) {
++ case 4:
++ case 5:
++ case 6:
++ case 7:
++ case 11:
++ case 12:
++ if (is_system)
++ tmpval |= PFM_MCK_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_MCK_PMC_PM_POS6;
++ break;
++
++ case 8:
++ val8 = tmpval;
++ val13 = set->pmcs[13];
++ val14 = set->pmcs[14];
++ check_case1 = 1;
++ break;
++
++ case 10:
++ if (is_system)
++ tmpval |= PFM_MCK_PMC_PM_POS4;
++ else
++ tmpval &= ~PFM_MCK_PMC_PM_POS4;
++ break;
++
++ case 13:
++ val8 = set->pmcs[8];
++ val13 = tmpval;
++ val14 = set->pmcs[14];
++ check_case1 = 1;
++ break;
++
++ case 14:
++ val8 = set->pmcs[8];
++ val13 = set->pmcs[13];
++ val14 = tmpval;
++ check_case1 = 1;
++ break;
++ }
++
++ /*
++ * check illegal configuration which can produce inconsistencies
++ * in tagging i-side events in L1D and L2 caches
++ */
++ if (check_case1) {
++ ret = (((val13 >> 45) & 0xf) == 0 && ((val8 & 0x1) == 0))
++ && ((((val14>>1) & 0x3) == 0x2 || ((val14>>1) & 0x3) == 0x0)
++ || (((val14>>4) & 0x3) == 0x2 || ((val14>>4) & 0x3) == 0x0));
++
++ if (ret) {
++ PFM_DBG("perfmon: invalid config pmc8=0x%lx "
++ "pmc13=0x%lx pmc14=0x%lx",
++ val8, val13, val14);
++ return -EINVAL;
++ }
++ }
++
++ /*
++ * check if configuration implicitely activates the use of
++ * the debug registers. If true, then we ensure that this is
++ * possible and that we do not pick up stale value in the HW
++ * registers.
++ *
++ * We postpone the checks of pmc13 and pmc14 to avoid side effects
++ * in case of errors
++ */
++
++ /*
++ * pmc13 is "active" if:
++ * one of the pmc13.cfg_dbrpXX field is different from 0x3
++ * AND
++ * at the corresponding pmc13.ena_dbrpXX is set.
++ */
++ if (cnum == 13 && (tmpval & 0x1e00000000000UL)
++ && (tmpval & 0x18181818UL) != 0x18181818UL
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc13=0x%lx active", tmpval);
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++ }
++
++ /*
++ * if any pmc14.ibrpX bit is enabled we must clear the ibrs
++ */
++ if (cnum == 14 && ((tmpval & 0x2222UL) != 0x2222UL)
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc14=0x%lx active", tmpval);
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++ }
++
++ req->reg_value = tmpval;
++
++ return 0;
++}
++
++static int pfm_mck_probe_pmu(void)
++{
++ return local_cpu_data->family == 0x1f ? 0 : -1;
++}
++
++/*
++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
++ */
++static struct pfm_pmu_config pfm_mck_pmu_conf = {
++ .pmu_name = "Itanium 2",
++ .counter_width = 47,
++ .pmd_desc = pfm_mck_pmd_desc,
++ .pmc_desc = pfm_mck_pmc_desc,
++ .pmc_write_check = pfm_mck_pmc_check,
++ .num_pmc_entries = PFM_MCK_NUM_PMCS,
++ .num_pmd_entries = PFM_MCK_NUM_PMDS,
++ .probe_pmu = pfm_mck_probe_pmu,
++ .version = "1.0",
++ .flags = PFM_PMU_BUILTIN_FLAG,
++ .owner = THIS_MODULE,
++ .pmu_info = &pfm_mck_pmu_info,
++};
++
++static int __init pfm_mck_pmu_init_module(void)
++{
++ return pfm_pmu_register(&pfm_mck_pmu_conf);
++}
++
++static void __exit pfm_mck_pmu_cleanup_module(void)
++{
++ pfm_pmu_unregister(&pfm_mck_pmu_conf);
++}
++
++module_init(pfm_mck_pmu_init_module);
++module_exit(pfm_mck_pmu_cleanup_module);
+diff --git a/arch/ia64/perfmon/perfmon_montecito.c b/arch/ia64/perfmon/perfmon_montecito.c
+new file mode 100644
+index 0000000..3f76f73
+--- /dev/null
++++ b/arch/ia64/perfmon/perfmon_montecito.c
+@@ -0,0 +1,412 @@
++/*
++ * This file contains the McKinley PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <linux/perfmon_kern.h>
++
++MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
++MODULE_DESCRIPTION("Dual-Core Itanium 2 (Montecito) PMU description table");
++MODULE_LICENSE("GPL");
++
++#define RDEP(x) (1UL << (x))
++
++#define PFM_MONT_MASK_PMCS (RDEP(4)|RDEP(5)|RDEP(6)|RDEP(7)|\
++ RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|\
++ RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|\
++ RDEP(37)|RDEP(39)|RDEP(40)|RDEP(42))
++
++#define PFM_MONT_NO64 (1UL<<5)
++
++static struct pfm_arch_pmu_info pfm_mont_pmu_info = {
++ .mask_pmcs = {PFM_MONT_MASK_PMCS,},
++};
++
++#define PFM_MONT_RSVD 0xffffffff838000a0UL
++/*
++ *
++ * For debug registers, writing xBR(y) means we use also xBR(y+1). Hence using
++ * PMC256+y means we use PMC256+y+1. Yet, we do not have dependency information
++ * but this is fine because they are handled separately in the IA-64 specific
++ * code.
++ *
++ * For PMC4-PMC15, PMC40: we force pmc.ism=2 (IA-64 mode only)
++ */
++static struct pfm_regmap_desc pfm_mont_pmc_desc[] = {
++/* pmc0 */ PMX_NA,
++/* pmc1 */ PMX_NA,
++/* pmc2 */ PMX_NA,
++/* pmc3 */ PMX_NA,
++/* pmc4 */ PMC_D(PFM_REG_W64, "PMC4" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 4),
++/* pmc5 */ PMC_D(PFM_REG_W64, "PMC5" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 5),
++/* pmc6 */ PMC_D(PFM_REG_W64, "PMC6" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 6),
++/* pmc7 */ PMC_D(PFM_REG_W64, "PMC7" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 7),
++/* pmc8 */ PMC_D(PFM_REG_W64, "PMC8" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 8),
++/* pmc9 */ PMC_D(PFM_REG_W64, "PMC9" , 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 9),
++/* pmc10 */ PMC_D(PFM_REG_W64, "PMC10", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 10),
++/* pmc11 */ PMC_D(PFM_REG_W64, "PMC11", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 11),
++/* pmc12 */ PMC_D(PFM_REG_W64, "PMC12", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 12),
++/* pmc13 */ PMC_D(PFM_REG_W64, "PMC13", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 13),
++/* pmc14 */ PMC_D(PFM_REG_W64, "PMC14", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 14),
++/* pmc15 */ PMC_D(PFM_REG_W64, "PMC15", 0x2000020UL, PFM_MONT_RSVD, PFM_MONT_NO64, 15),
++/* pmc16 */ PMX_NA,
++/* pmc17 */ PMX_NA,
++/* pmc18 */ PMX_NA,
++/* pmc19 */ PMX_NA,
++/* pmc20 */ PMX_NA,
++/* pmc21 */ PMX_NA,
++/* pmc22 */ PMX_NA,
++/* pmc23 */ PMX_NA,
++/* pmc24 */ PMX_NA,
++/* pmc25 */ PMX_NA,
++/* pmc26 */ PMX_NA,
++/* pmc27 */ PMX_NA,
++/* pmc28 */ PMX_NA,
++/* pmc29 */ PMX_NA,
++/* pmc30 */ PMX_NA,
++/* pmc31 */ PMX_NA,
++/* pmc32 */ PMC_D(PFM_REG_W , "PMC32", 0x30f01ffffffffffUL, 0xfcf0fe0000000000UL, 0, 32),
++/* pmc33 */ PMC_D(PFM_REG_W , "PMC33", 0x0, 0xfffffe0000000000UL, 0, 33),
++/* pmc34 */ PMC_D(PFM_REG_W , "PMC34", 0xf01ffffffffffUL, 0xfff0fe0000000000UL, 0, 34),
++/* pmc35 */ PMC_D(PFM_REG_W , "PMC35", 0x0, 0x1ffffffffffUL, 0, 35),
++/* pmc36 */ PMC_D(PFM_REG_W , "PMC36", 0xfffffff0UL, 0xfffffffffffffff0UL, 0, 36),
++/* pmc37 */ PMC_D(PFM_REG_W , "PMC37", 0x0, 0xffffffffffffc000UL, 0, 37),
++/* pmc38 */ PMC_D(PFM_REG_W , "PMC38", 0xdb6UL, 0xffffffffffffdb6dUL, 0, 38),
++/* pmc39 */ PMC_D(PFM_REG_W , "PMC39", 0x0, 0xffffffffffff0030UL, 0, 39),
++/* pmc40 */ PMC_D(PFM_REG_W , "PMC40", 0x2000000UL, 0xfffffffffff0fe30UL, 0, 40),
++/* pmc41 */ PMC_D(PFM_REG_W , "PMC41", 0x00002078fefefefeUL, 0xfffe1fffe7e7e7e7UL, 0, 41),
++/* pmc42 */ PMC_D(PFM_REG_W , "PMC42", 0x0, 0xfff800b0UL, 0, 42),
++/* pmc43 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc48 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc56 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc64 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc72 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc80 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc88 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc96 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc104 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc112 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc120 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc128 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc136 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc144 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc152 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc160 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc168 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc176 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc184 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc192 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc200 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc208 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc216 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc224 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc232 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc240 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc248 */ PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA, PMX_NA,
++/* pmc256 */ PMC_D(PFM_REG_W, "IBR0", 0x0, 0, 0, 0),
++/* pmc257 */ PMC_D(PFM_REG_W, "IBR1", 0x0, 0x8000000000000000UL, 0, 1),
++/* pmc258 */ PMC_D(PFM_REG_W, "IBR2", 0x0, 0, 0, 2),
++/* pmc259 */ PMC_D(PFM_REG_W, "IBR3", 0x0, 0x8000000000000000UL, 0, 3),
++/* pmc260 */ PMC_D(PFM_REG_W, "IBR4", 0x0, 0, 0, 4),
++/* pmc261 */ PMC_D(PFM_REG_W, "IBR5", 0x0, 0x8000000000000000UL, 0, 5),
++/* pmc262 */ PMC_D(PFM_REG_W, "IBR6", 0x0, 0, 0, 6),
++/* pmc263 */ PMC_D(PFM_REG_W, "IBR7", 0x0, 0x8000000000000000UL, 0, 7),
++/* pmc264 */ PMC_D(PFM_REG_W, "DBR0", 0x0, 0, 0, 0),
++/* pmc265 */ PMC_D(PFM_REG_W, "DBR1", 0x0, 0xc000000000000000UL, 0, 1),
++/* pmc266 */ PMC_D(PFM_REG_W, "DBR2", 0x0, 0, 0, 2),
++/* pmc267 */ PMC_D(PFM_REG_W, "DBR3", 0x0, 0xc000000000000000UL, 0, 3),
++/* pmc268 */ PMC_D(PFM_REG_W, "DBR4", 0x0, 0, 0, 4),
++/* pmc269 */ PMC_D(PFM_REG_W, "DBR5", 0x0, 0xc000000000000000UL, 0, 5),
++/* pmc270 */ PMC_D(PFM_REG_W, "DBR6", 0x0, 0, 0, 6),
++/* pmc271 */ PMC_D(PFM_REG_W, "DBR7", 0x0, 0xc000000000000000UL, 0, 7)
++};
++#define PFM_MONT_NUM_PMCS ARRAY_SIZE(pfm_mont_pmc_desc)
++
++static struct pfm_regmap_desc pfm_mont_pmd_desc[] = {
++/* pmd0 */ PMX_NA,
++/* pmd1 */ PMX_NA,
++/* pmd2 */ PMX_NA,
++/* pmd3 */ PMX_NA,
++/* pmd4 */ PMD_DP(PFM_REG_C, "PMD4", 4, 1ull << 4),
++/* pmd5 */ PMD_DP(PFM_REG_C, "PMD5", 5, 1ull << 5),
++/* pmd6 */ PMD_DP(PFM_REG_C, "PMD6", 6, 1ull << 6),
++/* pmd7 */ PMD_DP(PFM_REG_C, "PMD7", 7, 1ull << 7),
++/* pmd8 */ PMD_DP(PFM_REG_C, "PMD8", 8, 1ull << 8),
++/* pmd9 */ PMD_DP(PFM_REG_C, "PMD9", 9, 1ull << 9),
++/* pmd10 */ PMD_DP(PFM_REG_C, "PMD10", 10, 1ull << 10),
++/* pmd11 */ PMD_DP(PFM_REG_C, "PMD11", 11, 1ull << 11),
++/* pmd12 */ PMD_DP(PFM_REG_C, "PMD12", 12, 1ull << 12),
++/* pmd13 */ PMD_DP(PFM_REG_C, "PMD13", 13, 1ull << 13),
++/* pmd14 */ PMD_DP(PFM_REG_C, "PMD14", 14, 1ull << 14),
++/* pmd15 */ PMD_DP(PFM_REG_C, "PMD15", 15, 1ull << 15),
++/* pmd16 */ PMX_NA,
++/* pmd17 */ PMX_NA,
++/* pmd18 */ PMX_NA,
++/* pmd19 */ PMX_NA,
++/* pmd20 */ PMX_NA,
++/* pmd21 */ PMX_NA,
++/* pmd22 */ PMX_NA,
++/* pmd23 */ PMX_NA,
++/* pmd24 */ PMX_NA,
++/* pmd25 */ PMX_NA,
++/* pmd26 */ PMX_NA,
++/* pmd27 */ PMX_NA,
++/* pmd28 */ PMX_NA,
++/* pmd29 */ PMX_NA,
++/* pmd30 */ PMX_NA,
++/* pmd31 */ PMX_NA,
++/* pmd32 */ PMD_DP(PFM_REG_I, "PMD32", 32, 1ull << 40),
++/* pmd33 */ PMD_DP(PFM_REG_I, "PMD33", 33, 1ull << 40),
++/* pmd34 */ PMD_DP(PFM_REG_I, "PMD34", 34, 1ull << 37),
++/* pmd35 */ PMD_DP(PFM_REG_I, "PMD35", 35, 1ull << 37),
++/* pmd36 */ PMD_DP(PFM_REG_I, "PMD36", 36, 1ull << 40),
++/* pmd37 */ PMX_NA,
++/* pmd38 */ PMD_DP(PFM_REG_I, "PMD38", 38, (1ull<<39)|(1ull<<42)),
++/* pmd39 */ PMD_DP(PFM_REG_I, "PMD39", 39, (1ull<<39)|(1ull<<42)),
++/* pmd40 */ PMX_NA,
++/* pmd41 */ PMX_NA,
++/* pmd42 */ PMX_NA,
++/* pmd43 */ PMX_NA,
++/* pmd44 */ PMX_NA,
++/* pmd45 */ PMX_NA,
++/* pmd46 */ PMX_NA,
++/* pmd47 */ PMX_NA,
++/* pmd48 */ PMD_DP(PFM_REG_I, "PMD48", 48, (1ull<<39)|(1ull<<42)),
++/* pmd49 */ PMD_DP(PFM_REG_I, "PMD49", 49, (1ull<<39)|(1ull<<42)),
++/* pmd50 */ PMD_DP(PFM_REG_I, "PMD50", 50, (1ull<<39)|(1ull<<42)),
++/* pmd51 */ PMD_DP(PFM_REG_I, "PMD51", 51, (1ull<<39)|(1ull<<42)),
++/* pmd52 */ PMD_DP(PFM_REG_I, "PMD52", 52, (1ull<<39)|(1ull<<42)),
++/* pmd53 */ PMD_DP(PFM_REG_I, "PMD53", 53, (1ull<<39)|(1ull<<42)),
++/* pmd54 */ PMD_DP(PFM_REG_I, "PMD54", 54, (1ull<<39)|(1ull<<42)),
++/* pmd55 */ PMD_DP(PFM_REG_I, "PMD55", 55, (1ull<<39)|(1ull<<42)),
++/* pmd56 */ PMD_DP(PFM_REG_I, "PMD56", 56, (1ull<<39)|(1ull<<42)),
++/* pmd57 */ PMD_DP(PFM_REG_I, "PMD57", 57, (1ull<<39)|(1ull<<42)),
++/* pmd58 */ PMD_DP(PFM_REG_I, "PMD58", 58, (1ull<<39)|(1ull<<42)),
++/* pmd59 */ PMD_DP(PFM_REG_I, "PMD59", 59, (1ull<<39)|(1ull<<42)),
++/* pmd60 */ PMD_DP(PFM_REG_I, "PMD60", 60, (1ull<<39)|(1ull<<42)),
++/* pmd61 */ PMD_DP(PFM_REG_I, "PMD61", 61, (1ull<<39)|(1ull<<42)),
++/* pmd62 */ PMD_DP(PFM_REG_I, "PMD62", 62, (1ull<<39)|(1ull<<42)),
++/* pmd63 */ PMD_DP(PFM_REG_I, "PMD63", 63, (1ull<<39)|(1ull<<42))
++};
++#define PFM_MONT_NUM_PMDS ARRAY_SIZE(pfm_mont_pmd_desc)
++
++static int pfm_mont_has_ht;
++
++static int pfm_mont_pmc_check(struct pfm_context *ctx,
++ struct pfm_event_set *set,
++ struct pfarg_pmc *req)
++{
++ struct pfm_arch_context *ctx_arch;
++ u64 val32 = 0, val38 = 0, val41 = 0;
++ u64 tmpval;
++ u16 cnum;
++ int ret = 0, check_case1 = 0;
++ int is_system;
++
++ tmpval = req->reg_value;
++ cnum = req->reg_num;
++ ctx_arch = pfm_ctx_arch(ctx);
++ is_system = ctx->flags.system;
++
++#define PFM_MONT_PMC_PM_POS6 (1UL<<6)
++#define PFM_MONT_PMC_PM_POS4 (1UL<<4)
++
++ switch (cnum) {
++ case 4:
++ case 5:
++ case 6:
++ case 7:
++ case 8:
++ case 9:
++ if (is_system)
++ tmpval |= PFM_MONT_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_MONT_PMC_PM_POS6;
++ break;
++ case 10:
++ case 11:
++ case 12:
++ case 13:
++ case 14:
++ case 15:
++ if ((req->reg_flags & PFM_REGFL_NO_EMUL64) == 0) {
++ if (pfm_mont_has_ht) {
++ PFM_INFO("perfmon: Errata 121 PMD10/PMD15 cannot be used to overflow"
++ "when threads on on");
++ return -EINVAL;
++ }
++ }
++ if (is_system)
++ tmpval |= PFM_MONT_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_MONT_PMC_PM_POS6;
++ break;
++ case 39:
++ case 40:
++ case 42:
++ if (pfm_mont_has_ht && ((req->reg_value >> 8) & 0x7) == 4) {
++ PFM_INFO("perfmon: Errata 120: IP-EAR not available when threads are on");
++ return -EINVAL;
++ }
++ if (is_system)
++ tmpval |= PFM_MONT_PMC_PM_POS6;
++ else
++ tmpval &= ~PFM_MONT_PMC_PM_POS6;
++ break;
++
++ case 32:
++ val32 = tmpval;
++ val38 = set->pmcs[38];
++ val41 = set->pmcs[41];
++ check_case1 = 1;
++ break;
++
++ case 37:
++ if (is_system)
++ tmpval |= PFM_MONT_PMC_PM_POS4;
++ else
++ tmpval &= ~PFM_MONT_PMC_PM_POS4;
++ break;
++
++ case 38:
++ val38 = tmpval;
++ val32 = set->pmcs[32];
++ val41 = set->pmcs[41];
++ check_case1 = 1;
++ break;
++ case 41:
++ val41 = tmpval;
++ val32 = set->pmcs[32];
++ val38 = set->pmcs[38];
++ check_case1 = 1;
++ break;
++ }
++
++ if (check_case1) {
++ ret = (((val41 >> 45) & 0xf) == 0 && ((val32>>57) & 0x1) == 0)
++ && ((((val38>>1) & 0x3) == 0x2 || ((val38>>1) & 0x3) == 0)
++ || (((val38>>4) & 0x3) == 0x2 || ((val38>>4) & 0x3) == 0));
++ if (ret) {
++ PFM_DBG("perfmon: invalid config pmc38=0x%lx "
++ "pmc41=0x%lx pmc32=0x%lx",
++ val38, val41, val32);
++ return -EINVAL;
++ }
++ }
++
++ /*
++ * check if configuration implicitely activates the use of the
++ * debug registers. If true, then we ensure that this is possible
++ * and that we do not pick up stale value in the HW registers.
++ */
++
++ /*
++ *
++ * pmc41 is "active" if:
++ * one of the pmc41.cfgdtagXX field is different from 0x3
++ * AND
++ * the corsesponding pmc41.en_dbrpXX is set.
++ * AND
++ * ctx_fl_use_dbr (dbr not yet used)
++ */
++ if (cnum == 41
++ && (tmpval & 0x1e00000000000)
++ && (tmpval & 0x18181818) != 0x18181818
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc41=0x%lx active, clearing dbr", tmpval);
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++ }
++ /*
++ * we must clear the (instruction) debug registers if:
++ * pmc38.ig_ibrpX is 0 (enabled)
++ * and
++ * fl_use_dbr == 0 (dbr not yet used)
++ */
++ if (cnum == 38 && ((tmpval & 0x492) != 0x492)
++ && ctx_arch->flags.use_dbr == 0) {
++ PFM_DBG("pmc38=0x%lx active pmc38, clearing ibr", tmpval);
++ ret = pfm_ia64_mark_dbregs_used(ctx, set);
++ if (ret)
++ return ret;
++
++ }
++ req->reg_value = tmpval;
++ return 0;
++}
++
++static void pfm_handle_errata(void)
++{
++ pfm_mont_has_ht = 1;
++
++ PFM_INFO("activating workaround for errata 120 "
++ "(Disable IP-EAR when threads are on)");
++
++ PFM_INFO("activating workaround for Errata 121 "
++ "(PMC10-PMC15 cannot be used to overflow"
++ " when threads are on");
++}
++static int pfm_mont_probe_pmu(void)
++{
++ if (local_cpu_data->family != 0x20)
++ return -1;
++
++ /*
++ * the 2 errata must be activated when
++ * threads are/can be enabled
++ */
++ if (is_multithreading_enabled())
++ pfm_handle_errata();
++
++ return 0;
++}
++
++/*
++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
++ */
++static struct pfm_pmu_config pfm_mont_pmu_conf = {
++ .pmu_name = "Montecito",
++ .counter_width = 47,
++ .pmd_desc = pfm_mont_pmd_desc,
++ .pmc_desc = pfm_mont_pmc_desc,
++ .num_pmc_entries = PFM_MONT_NUM_PMCS,
++ .num_pmd_entries = PFM_MONT_NUM_PMDS,
++ .pmc_write_check = pfm_mont_pmc_check,
++ .probe_pmu = pfm_mont_probe_pmu,
++ .version = "1.0",
++ .pmu_info = &pfm_mont_pmu_info,
++ .flags = PFM_PMU_BUILTIN_FLAG,
++ .owner = THIS_MODULE
++};
++
++static int __init pfm_mont_pmu_init_module(void)
++{
++ return pfm_pmu_register(&pfm_mont_pmu_conf);
++}
++
++static void __exit pfm_mont_pmu_cleanup_module(void)
++{
++ pfm_pmu_unregister(&pfm_mont_pmu_conf);
++}
++
++module_init(pfm_mont_pmu_init_module);
++module_exit(pfm_mont_pmu_cleanup_module);
+diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
+index 1e06d23..b87f445 100644
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -1857,6 +1857,8 @@ config SECCOMP
+
+ If unsure, say Y. Only embedded should say N here.
+
++source "arch/mips/perfmon/Kconfig"
++
+ endmenu
+
+ config RWSEM_GENERIC_SPINLOCK
+diff --git a/arch/mips/Makefile b/arch/mips/Makefile
+index 9aab51c..712acf7 100644
+--- a/arch/mips/Makefile
++++ b/arch/mips/Makefile
+@@ -154,6 +154,12 @@ endif
+ endif
+
+ #
++# Perfmon support
++#
++
++core-$(CONFIG_PERFMON) += arch/mips/perfmon/
++
++#
+ # Firmware support
+ #
+ libs-$(CONFIG_ARC) += arch/mips/fw/arc/
+diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
+index 22fc19b..4467361 100644
+--- a/arch/mips/kernel/process.c
++++ b/arch/mips/kernel/process.c
+@@ -27,6 +27,7 @@
+ #include <linux/completion.h>
+ #include <linux/kallsyms.h>
+ #include <linux/random.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/asm.h>
+ #include <asm/bootinfo.h>
+@@ -94,6 +95,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
+
+ void exit_thread(void)
+ {
++ pfm_exit_thread();
+ }
+
+ void flush_thread(void)
+@@ -162,6 +164,8 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ if (clone_flags & CLONE_SETTLS)
+ ti->tp_value = regs->regs[7];
+
++ pfm_copy_thread(p);
++
+ return 0;
+ }
+
+diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
+index 5e75a31..e96ddd6 100644
+--- a/arch/mips/kernel/scall32-o32.S
++++ b/arch/mips/kernel/scall32-o32.S
+@@ -653,6 +653,18 @@ einval: li v0, -EINVAL
+ sys sys_dup3 3
+ sys sys_pipe2 2
+ sys sys_inotify_init1 1
++ sys sys_pfm_create_context 4 /* 4330 */
++ sys sys_pfm_write_pmcs 3
++ sys sys_pfm_write_pmds 4
++ sys sys_pfm_read_pmds 3
++ sys sys_pfm_load_context 2
++ sys sys_pfm_start 2 /* 4335 */
++ sys sys_pfm_stop 1
++ sys sys_pfm_restart 1
++ sys sys_pfm_create_evtsets 3
++ sys sys_pfm_getinfo_evtsets 3
++ sys sys_pfm_delete_evtsets 3 /* 4340 */
++ sys sys_pfm_unload_context 1
+ .endm
+
+ /* We pre-compute the number of _instruction_ bytes needed to
+diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
+index 3d58204..adb2ba9 100644
+--- a/arch/mips/kernel/scall64-64.S
++++ b/arch/mips/kernel/scall64-64.S
+@@ -487,4 +487,16 @@ sys_call_table:
+ PTR sys_dup3
+ PTR sys_pipe2
+ PTR sys_inotify_init1
++ PTR sys_pfm_create_context
++ PTR sys_pfm_write_pmcs /* 5290 */
++ PTR sys_pfm_write_pmds
++ PTR sys_pfm_read_pmds
++ PTR sys_pfm_load_context
++ PTR sys_pfm_start
++ PTR sys_pfm_stop /* 5295 */
++ PTR sys_pfm_restart
++ PTR sys_pfm_create_evtsets
++ PTR sys_pfm_getinfo_evtsets
++ PTR sys_pfm_delete_evtsets
++ PTR sys_pfm_unload_context /* 5300 */
+ .size sys_call_table,.-sys_call_table
+diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
+index da7f1b6..6d12095 100644
+--- a/arch/mips/kernel/scall64-n32.S
++++ b/arch/mips/kernel/scall64-n32.S
+@@ -400,12 +400,12 @@ EXPORT(sysn32_call_table)
+ PTR sys_ioprio_set
+ PTR sys_ioprio_get
+ PTR compat_sys_utimensat
+- PTR compat_sys_signalfd /* 5280 */
++ PTR compat_sys_signalfd /* 6280 */
+ PTR sys_ni_syscall
+ PTR sys_eventfd
+ PTR sys_fallocate
+ PTR sys_timerfd_create
+- PTR sys_timerfd_gettime /* 5285 */
++ PTR sys_timerfd_gettime /* 6285 */
+ PTR sys_timerfd_settime
+ PTR sys_signalfd4
+ PTR sys_eventfd2
+@@ -413,4 +413,16 @@ EXPORT(sysn32_call_table)
+ PTR sys_dup3 /* 5290 */
+ PTR sys_pipe2
+ PTR sys_inotify_init1
++ PTR sys_pfm_create_context
++ PTR sys_pfm_write_pmcs
++ PTR sys_pfm_write_pmds /* 6295 */
++ PTR sys_pfm_read_pmds
++ PTR sys_pfm_load_context
++ PTR sys_pfm_start
++ PTR sys_pfm_stop
++ PTR sys_pfm_restart /* 6300 */
++ PTR sys_pfm_create_evtsets
++ PTR sys_pfm_getinfo_evtsets
++ PTR sys_pfm_delete_evtsets
++ PTR sys_pfm_unload_context
+ .size sysn32_call_table,.-sysn32_call_table
+diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
+index d7cd1aa..e77f55a 100644
+--- a/arch/mips/kernel/scall64-o32.S
++++ b/arch/mips/kernel/scall64-o32.S
+@@ -535,4 +535,16 @@ sys_call_table:
+ PTR sys_dup3
+ PTR sys_pipe2
+ PTR sys_inotify_init1
++ PTR sys_pfm_create_context /* 4330 */
++ PTR sys_pfm_write_pmcs
++ PTR sys_pfm_write_pmds
++ PTR sys_pfm_read_pmds
++ PTR sys_pfm_load_context
++ PTR sys_pfm_start /* 4335 */
++ PTR sys_pfm_stop
++ PTR sys_pfm_restart
++ PTR sys_pfm_create_evtsets
++ PTR sys_pfm_getinfo_evtsets
++ PTR sys_pfm_delete_evtsets /* 4340 */
++ PTR sys_pfm_unload_context
+ .size sys_call_table,.-sys_call_table
+diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
+index a4e106c..6a7e60c 100644
+--- a/arch/mips/kernel/signal.c
++++ b/arch/mips/kernel/signal.c
+@@ -20,6 +20,7 @@
+ #include <linux/unistd.h>
+ #include <linux/compiler.h>
+ #include <linux/uaccess.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/abi.h>
+ #include <asm/asm.h>
+@@ -694,8 +695,11 @@ static void do_signal(struct pt_regs *regs)
+ * - triggered by the TIF_WORK_MASK flags
+ */
+ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
+- __u32 thread_info_flags)
++ __u32 thread_info_flags)
+ {
++ if (thread_info_flags & _TIF_PERFMON_WORK)
++ pfm_handle_work(regs);
++
+ /* deal with pending signal delivery */
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ do_signal(regs);
+diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
+index 1f467d5..163dfe4 100644
+--- a/arch/mips/kernel/time.c
++++ b/arch/mips/kernel/time.c
+@@ -49,10 +49,11 @@ int update_persistent_clock(struct timespec now)
+ return rtc_mips_set_mmss(now.tv_sec);
+ }
+
+-static int null_perf_irq(void)
++int null_perf_irq(void)
+ {
+ return 0;
+ }
++EXPORT_SYMBOL(null_perf_irq);
+
+ int (*perf_irq)(void) = null_perf_irq;
+
+diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
+index b602ac6..9cbd75f 100644
+--- a/arch/mips/kernel/traps.c
++++ b/arch/mips/kernel/traps.c
+@@ -92,17 +92,15 @@ static void show_raw_backtrace(unsigned long reg29)
+ #ifdef CONFIG_KALLSYMS
+ printk("\n");
+ #endif
+- while (!kstack_end(sp)) {
+- unsigned long __user *p =
+- (unsigned long __user *)(unsigned long)sp++;
+- if (__get_user(addr, p)) {
+- printk(" (Bad stack address)");
+- break;
++#define IS_KVA01(a) ((((unsigned long)a) & 0xc0000000) == 0x80000000)
++ if (IS_KVA01(sp)) {
++ while (!kstack_end(sp)) {
++ addr = *sp++;
++ if (__kernel_text_address(addr))
++ print_ip_sym(addr);
+ }
+- if (__kernel_text_address(addr))
+- print_ip_sym(addr);
++ printk("\n");
+ }
+- printk("\n");
+ }
+
+ #ifdef CONFIG_KALLSYMS
+diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
+index 0b97d47..d8f36b5 100644
+--- a/arch/mips/mti-malta/malta-time.c
++++ b/arch/mips/mti-malta/malta-time.c
+@@ -27,6 +27,7 @@
+ #include <linux/time.h>
+ #include <linux/timex.h>
+ #include <linux/mc146818rtc.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/mipsregs.h>
+ #include <asm/mipsmtregs.h>
+diff --git a/arch/mips/perfmon/Kconfig b/arch/mips/perfmon/Kconfig
+new file mode 100644
+index 0000000..b426eea
+--- /dev/null
++++ b/arch/mips/perfmon/Kconfig
+@@ -0,0 +1,61 @@
++menu "Hardware Performance Monitoring support"
++config PERFMON
++ bool "Perfmon2 performance monitoring interface"
++ default n
++ help
++ Enables the perfmon2 interface to access the hardware
++ performance counters. See <http://perfmon2.sf.net/> for
++ more details.
++
++config PERFMON_DEBUG
++ bool "Perfmon debugging"
++ default n
++ depends on PERFMON
++ help
++ Enables perfmon debugging support
++
++config PERFMON_DEBUG_FS
++ bool "Enable perfmon statistics reporting via debugfs"
++ default y
++ depends on PERFMON && DEBUG_FS
++ help
++ Enable collection and reporting of perfmon timing statistics under
++ debugfs. This is used for debugging and performance analysis of the
++ subsystem. The debugfs filesystem must be mounted.
++
++config PERFMON_FLUSH
++ bool "Flush sampling buffer when modified"
++ depends on PERFMON
++ default n
++ help
++ On some MIPS models, cache aliasing may cause invalid
++ data to be read from the perfmon sampling buffer. Use this option
++ to flush the buffer when it is modified to ensure valid data is
++ visible at the user level.
++
++config PERFMON_ALIGN
++ bool "Align sampling buffer to avoid cache aliasing"
++ depends on PERFMON
++ default n
++ help
++ On some MIPS models, cache aliasing may cause invalid
++ data to be read from the perfmon sampling buffer. By forcing a bigger
++ page alignment (4-page), one can guarantee the buffer virtual address
++ will conflict in the cache with the user level mapping of the buffer
++ thereby ensuring a consistent view by user programs.
++
++config PERFMON_DEBUG
++ bool "Perfmon debugging"
++ depends on PERFMON
++ default n
++ depends on PERFMON
++ help
++ Enables perfmon debugging support
++
++config PERFMON_MIPS64
++ tristate "Support for MIPS64 hardware performance counters"
++ depends on PERFMON
++ default n
++ help
++ Enables support for the MIPS64 hardware performance counters"
++endmenu
+diff --git a/arch/mips/perfmon/Makefile b/arch/mips/perfmon/Makefile
+new file mode 100644
+index 0000000..153b83f
+--- /dev/null
++++ b/arch/mips/perfmon/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_PERFMON) += perfmon.o
++obj-$(CONFIG_PERFMON_MIPS64) += perfmon_mips64.o
+diff --git a/arch/mips/perfmon/perfmon.c b/arch/mips/perfmon/perfmon.c
+new file mode 100644
+index 0000000..6615a77
+--- /dev/null
++++ b/arch/mips/perfmon/perfmon.c
+@@ -0,0 +1,313 @@
++/*
++ * This file implements the MIPS64 specific
++ * support for the perfmon2 interface
++ *
++ * Copyright (c) 2005 Philip J. Mucci
++ *
++ * based on versions for other architectures:
++ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@htrpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++
++/*
++ * collect pending overflowed PMDs. Called from pfm_ctxsw()
++ * and from PMU interrupt handler. Must fill in set->povfl_pmds[]
++ * and set->npend_ovfls. Interrupts are masked
++ */
++static void __pfm_get_ovfl_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ u64 new_val, wmask;
++ u64 *used_mask, *intr_pmds;
++ u64 mask[PFM_PMD_BV];
++ unsigned int i, max;
++
++ max = ctx->regs.max_intr_pmd;
++ intr_pmds = ctx->regs.intr_pmds;
++ used_mask = set->used_pmds;
++
++ wmask = 1ULL << pfm_pmu_conf->counter_width;
++
++ bitmap_and(cast_ulp(mask),
++ cast_ulp(intr_pmds),
++ cast_ulp(used_mask),
++ max);
++
++ /*
++ * check all PMD that can generate interrupts
++ * (that includes counters)
++ */
++ for (i = 0; i < max; i++) {
++ if (test_bit(i, mask)) {
++ new_val = pfm_arch_read_pmd(ctx, i);
++
++ PFM_DBG_ovfl("pmd%u new_val=0x%llx bit=%d\n",
++ i, (unsigned long long)new_val,
++ (new_val&wmask) ? 1 : 0);
++
++ if (new_val & wmask) {
++ __set_bit(i, set->povfl_pmds);
++ set->npend_ovfls++;
++ }
++ }
++ }
++}
++
++static void pfm_stop_active(struct task_struct *task, struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ unsigned int i, max;
++
++ max = ctx->regs.max_pmc;
++
++ /*
++ * clear enable bits, assume all pmcs are enable pmcs
++ */
++ for (i = 0; i < max; i++) {
++ if (test_bit(i, set->used_pmcs))
++ pfm_arch_write_pmc(ctx, i, 0);
++ }
++
++ if (set->npend_ovfls)
++ return;
++
++ __pfm_get_ovfl_pmds(ctx, set);
++}
++
++/*
++ * Called from pfm_ctxsw(). Task is guaranteed to be current.
++ * Context is locked. Interrupts are masked. Monitoring is active.
++ * PMU access is guaranteed. PMC and PMD registers are live in PMU.
++ *
++ * for per-thread:
++ * must stop monitoring for the task
++ *
++ * Return:
++ * non-zero : did not save PMDs (as part of stopping the PMU)
++ * 0 : saved PMDs (no need to save them in caller)
++ */
++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx)
++{
++ /*
++ * disable lazy restore of PMC registers.
++ */
++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_PMCS;
++
++ /*
++ * if masked, monitoring is stopped, thus there is no
++ * need to stop the PMU again and there is no need to
++ * check for pending overflows. This is not just an
++ * optimization, this is also for correctness as you
++ * may end up detecting overflows twice.
++ */
++ if (ctx->state == PFM_CTX_MASKED)
++ return 1;
++
++ pfm_stop_active(task, ctx, ctx->active_set);
++
++ return 1;
++}
++
++/*
++ * Called from pfm_stop() and pfm_ctxsw()
++ * Interrupts are masked. Context is locked. Set is the active set.
++ *
++ * For per-thread:
++ * task is not necessarily current. If not current task, then
++ * task is guaranteed stopped and off any cpu. Access to PMU
++ * is not guaranteed. Interrupts are masked. Context is locked.
++ * Set is the active set.
++ *
++ * For system-wide:
++ * task is current
++ *
++ * must disable active monitoring. ctx cannot be NULL
++ */
++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx)
++{
++ /*
++ * no need to go through stop_save()
++ * if we are already stopped
++ */
++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED)
++ return;
++
++ /*
++ * stop live registers and collect pending overflow
++ */
++ if (task == current)
++ pfm_stop_active(task, ctx, ctx->active_set);
++}
++
++/*
++ * called from pfm_start() or pfm_ctxsw() when idle task and
++ * EXCL_IDLE is on.
++ *
++ * Interrupts are masked. Context is locked. Set is the active set.
++ *
++ * For per-trhead:
++ * Task is not necessarily current. If not current task, then task
++ * is guaranteed stopped and off any cpu. Access to PMU is not guaranteed.
++ *
++ * For system-wide:
++ * task is always current
++ *
++ * must enable active monitoring.
++ */
++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_event_set *set;
++ unsigned int i, max_pmc;
++
++ if (task != current)
++ return;
++
++ set = ctx->active_set;
++ max_pmc = ctx->regs.max_pmc;
++
++ for (i = 0; i < max_pmc; i++) {
++ if (test_bit(i, set->used_pmcs))
++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]);
++ }
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets()
++ * context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMD registers from set.
++ */
++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ u64 ovfl_mask, val;
++ u64 *impl_pmds;
++ unsigned int i;
++ unsigned int max_pmd;
++
++ max_pmd = ctx->regs.max_pmd;
++ ovfl_mask = pfm_pmu_conf->ovfl_mask;
++ impl_pmds = ctx->regs.pmds;
++
++ /*
++ * must restore all pmds to avoid leaking
++ * information to user.
++ */
++ for (i = 0; i < max_pmd; i++) {
++
++ if (test_bit(i, impl_pmds) == 0)
++ continue;
++
++ val = set->pmds[i].value;
++
++ /*
++ * set upper bits for counter to ensure
++ * overflow will trigger
++ */
++ val &= ovfl_mask;
++
++ pfm_arch_write_pmd(ctx, i, val);
++ }
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw().
++ * Context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMC registers from set, if needed.
++ */
++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ u64 *impl_pmcs;
++ unsigned int i, max_pmc;
++
++ max_pmc = ctx->regs.max_pmc;
++ impl_pmcs = ctx->regs.pmcs;
++
++ /*
++ * - by default no PMCS measures anything
++ * - on ctxswout, all used PMCs are disabled (cccr enable bit cleared)
++ * hence when masked we do not need to restore anything
++ */
++ if (ctx->state == PFM_CTX_MASKED || ctx->flags.started == 0)
++ return;
++
++ /*
++ * restore all pmcs
++ */
++ for (i = 0; i < max_pmc; i++)
++ if (test_bit(i, impl_pmcs))
++ pfm_arch_write_pmc(ctx, i, set->pmcs[i]);
++}
++
++char *pfm_arch_get_pmu_module_name(void)
++{
++ switch (cpu_data->cputype) {
++#ifndef CONFIG_SMP
++ case CPU_34K:
++#if defined(CPU_74K)
++ case CPU_74K:
++#endif
++#endif
++ case CPU_SB1:
++ case CPU_SB1A:
++ case CPU_R12000:
++ case CPU_25KF:
++ case CPU_24K:
++ case CPU_20KC:
++ case CPU_5KC:
++ return "perfmon_mips64";
++ default:
++ return NULL;
++ }
++ return NULL;
++}
++
++int perfmon_perf_irq(void)
++{
++ /* BLATANTLY STOLEN FROM OPROFILE, then modified */
++ struct pt_regs *regs;
++ unsigned int counters = pfm_pmu_conf->regs_all.max_pmc;
++ unsigned int control;
++ unsigned int counter;
++
++ regs = get_irq_regs();
++ switch (counters) {
++#define HANDLE_COUNTER(n) \
++ case n + 1: \
++ control = read_c0_perfctrl ## n(); \
++ counter = read_c0_perfcntr ## n(); \
++ if ((control & MIPS64_PMC_INT_ENABLE_MASK) && \
++ (counter & MIPS64_PMD_INTERRUPT)) { \
++ pfm_interrupt_handler(instruction_pointer(regs),\
++ regs); \
++ return(1); \
++ }
++ HANDLE_COUNTER(3)
++ HANDLE_COUNTER(2)
++ HANDLE_COUNTER(1)
++ HANDLE_COUNTER(0)
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(perfmon_perf_irq);
+diff --git a/arch/mips/perfmon/perfmon_mips64.c b/arch/mips/perfmon/perfmon_mips64.c
+new file mode 100644
+index 0000000..78cb43d
+--- /dev/null
++++ b/arch/mips/perfmon/perfmon_mips64.c
+@@ -0,0 +1,218 @@
++/*
++ * This file contains the MIPS64 and decendent PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright (c) 2005 Philip Mucci
++ *
++ * Based on perfmon_p6.c:
++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++
++MODULE_AUTHOR("Philip Mucci <mucci@cs.utk.edu>");
++MODULE_DESCRIPTION("MIPS64 PMU description tables");
++MODULE_LICENSE("GPL");
++
++/*
++ * reserved:
++ * - bit 63-9
++ * RSVD: reserved bits must be 1
++ */
++#define PFM_MIPS64_PMC_RSVD 0xfffffffffffff810ULL
++#define PFM_MIPS64_PMC_VAL (1ULL<<4)
++
++extern int null_perf_irq(struct pt_regs *regs);
++extern int (*perf_irq)(struct pt_regs *regs);
++extern int perfmon_perf_irq(struct pt_regs *regs);
++
++static struct pfm_arch_pmu_info pfm_mips64_pmu_info;
++
++static struct pfm_regmap_desc pfm_mips64_pmc_desc[] = {
++/* pmc0 */ PMC_D(PFM_REG_I64, "CP0_25_0", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 0),
++/* pmc1 */ PMC_D(PFM_REG_I64, "CP0_25_1", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 1),
++/* pmc2 */ PMC_D(PFM_REG_I64, "CP0_25_2", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 2),
++/* pmc3 */ PMC_D(PFM_REG_I64, "CP0_25_3", PFM_MIPS64_PMC_VAL, PFM_MIPS64_PMC_RSVD, 0, 3)
++};
++#define PFM_MIPS64_NUM_PMCS ARRAY_SIZE(pfm_mips64_pmc_desc)
++
++static struct pfm_regmap_desc pfm_mips64_pmd_desc[] = {
++/* pmd0 */ PMD_D(PFM_REG_C, "CP0_25_0", 0),
++/* pmd1 */ PMD_D(PFM_REG_C, "CP0_25_1", 1),
++/* pmd2 */ PMD_D(PFM_REG_C, "CP0_25_2", 2),
++/* pmd3 */ PMD_D(PFM_REG_C, "CP0_25_3", 3)
++};
++#define PFM_MIPS64_NUM_PMDS ARRAY_SIZE(pfm_mips64_pmd_desc)
++
++static int pfm_mips64_probe_pmu(void)
++{
++ struct cpuinfo_mips *c = ¤t_cpu_data;
++
++ switch (c->cputype) {
++#ifndef CONFIG_SMP
++ case CPU_34K:
++#if defined(CPU_74K)
++ case CPU_74K:
++#endif
++#endif
++ case CPU_SB1:
++ case CPU_SB1A:
++ case CPU_R12000:
++ case CPU_25KF:
++ case CPU_24K:
++ case CPU_20KC:
++ case CPU_5KC:
++ return 0;
++ break;
++ default:
++ PFM_INFO("Unknown cputype 0x%x", c->cputype);
++ }
++ return -1;
++}
++
++/*
++ * impl_pmcs, impl_pmds are computed at runtime to minimize errors!
++ */
++static struct pfm_pmu_config pfm_mips64_pmu_conf = {
++ .pmu_name = "MIPS", /* placeholder */
++ .counter_width = 31,
++ .pmd_desc = pfm_mips64_pmd_desc,
++ .pmc_desc = pfm_mips64_pmc_desc,
++ .num_pmc_entries = PFM_MIPS64_NUM_PMCS,
++ .num_pmd_entries = PFM_MIPS64_NUM_PMDS,
++ .probe_pmu = pfm_mips64_probe_pmu,
++ .flags = PFM_PMU_BUILTIN_FLAG,
++ .owner = THIS_MODULE,
++ .pmu_info = &pfm_mips64_pmu_info
++};
++
++static inline int n_counters(void)
++{
++ if (!(read_c0_config1() & MIPS64_CONFIG_PMC_MASK))
++ return 0;
++ if (!(read_c0_perfctrl0() & MIPS64_PMC_CTR_MASK))
++ return 1;
++ if (!(read_c0_perfctrl1() & MIPS64_PMC_CTR_MASK))
++ return 2;
++ if (!(read_c0_perfctrl2() & MIPS64_PMC_CTR_MASK))
++ return 3;
++ return 4;
++}
++
++static int __init pfm_mips64_pmu_init_module(void)
++{
++ struct cpuinfo_mips *c = ¤t_cpu_data;
++ int i, ret, num;
++ u64 temp_mask;
++
++ switch (c->cputype) {
++ case CPU_5KC:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS5KC";
++ break;
++ case CPU_R12000:
++ pfm_mips64_pmu_conf.pmu_name = "MIPSR12000";
++ break;
++ case CPU_20KC:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS20KC";
++ break;
++ case CPU_24K:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS24K";
++ break;
++ case CPU_25KF:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS25KF";
++ break;
++ case CPU_SB1:
++ pfm_mips64_pmu_conf.pmu_name = "SB1";
++ break;
++ case CPU_SB1A:
++ pfm_mips64_pmu_conf.pmu_name = "SB1A";
++ break;
++#ifndef CONFIG_SMP
++ case CPU_34K:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS34K";
++ break;
++#if defined(CPU_74K)
++ case CPU_74K:
++ pfm_mips64_pmu_conf.pmu_name = "MIPS74K";
++ break;
++#endif
++#endif
++ default:
++ PFM_INFO("Unknown cputype 0x%x", c->cputype);
++ return -1;
++ }
++
++ /* The R14k and older performance counters have to */
++ /* be hard-coded, as there is no support for auto-detection */
++ if ((c->cputype == CPU_R12000) || (c->cputype == CPU_R14000))
++ num = 4;
++ else if (c->cputype == CPU_R10000)
++ num = 2;
++ else
++ num = n_counters();
++
++ if (num == 0) {
++ PFM_INFO("cputype 0x%x has no counters", c->cputype);
++ return -1;
++ }
++ /* mark remaining counters unavailable */
++ for (i = num; i < PFM_MIPS64_NUM_PMCS; i++)
++ pfm_mips64_pmc_desc[i].type = PFM_REG_NA;
++
++ for (i = num; i < PFM_MIPS64_NUM_PMDS; i++)
++ pfm_mips64_pmd_desc[i].type = PFM_REG_NA;
++
++ /* set the PMC_RSVD mask */
++ switch (c->cputype) {
++ case CPU_5KC:
++ case CPU_R10000:
++ case CPU_20KC:
++ /* 4-bits for event */
++ temp_mask = 0xfffffffffffffe10ULL;
++ break;
++ case CPU_R12000:
++ case CPU_R14000:
++ /* 5-bits for event */
++ temp_mask = 0xfffffffffffffc10ULL;
++ break;
++ default:
++ /* 6-bits for event */
++ temp_mask = 0xfffffffffffff810ULL;
++ }
++ for (i = 0; i < PFM_MIPS64_NUM_PMCS; i++)
++ pfm_mips64_pmc_desc[i].rsvd_msk = temp_mask;
++
++ pfm_mips64_pmu_conf.num_pmc_entries = num;
++ pfm_mips64_pmu_conf.num_pmd_entries = num;
++
++ pfm_mips64_pmu_info.pmu_style = c->cputype;
++
++ ret = pfm_pmu_register(&pfm_mips64_pmu_conf);
++ if (ret == 0)
++ perf_irq = perfmon_perf_irq;
++ return ret;
++}
++
++static void __exit pfm_mips64_pmu_cleanup_module(void)
++{
++ pfm_pmu_unregister(&pfm_mips64_pmu_conf);
++ perf_irq = null_perf_irq;
++}
++
++module_init(pfm_mips64_pmu_init_module);
++module_exit(pfm_mips64_pmu_cleanup_module);
+diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
+index 587da5e..a411389 100644
+--- a/arch/powerpc/Kconfig
++++ b/arch/powerpc/Kconfig
+@@ -230,6 +230,8 @@ source "init/Kconfig"
+ source "arch/powerpc/sysdev/Kconfig"
+ source "arch/powerpc/platforms/Kconfig"
+
++source "arch/powerpc/perfmon/Kconfig"
++
+ menu "Kernel options"
+
+ config HIGHMEM
+diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
+index c6be19e..7ea20cb 100644
+--- a/arch/powerpc/Makefile
++++ b/arch/powerpc/Makefile
+@@ -146,6 +146,7 @@ core-y += arch/powerpc/kernel/ \
+ arch/powerpc/platforms/
+ core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/
+ core-$(CONFIG_XMON) += arch/powerpc/xmon/
++core-$(CONFIG_PERFMON) += arch/powerpc/perfmon/
+ core-$(CONFIG_KVM) += arch/powerpc/kvm/
+
+ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
+diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild
+index 5ab7d7f..88cb533 100644
+--- a/arch/powerpc/include/asm/Kbuild
++++ b/arch/powerpc/include/asm/Kbuild
+@@ -21,6 +21,7 @@ header-y += resource.h
+ header-y += sigcontext.h
+ header-y += statfs.h
+ header-y += ps3fb.h
++header-y += perfmon.h
+
+ unifdef-y += bootx.h
+ unifdef-y += byteorder.h
+diff --git a/arch/powerpc/include/asm/cell-pmu.h b/arch/powerpc/include/asm/cell-pmu.h
+index 8066eed..981db26 100644
+--- a/arch/powerpc/include/asm/cell-pmu.h
++++ b/arch/powerpc/include/asm/cell-pmu.h
+@@ -61,6 +61,11 @@
+
+ /* Macros for the pm_status register. */
+ #define CBE_PM_CTR_OVERFLOW_INTR(ctr) (1 << (31 - ((ctr) & 7)))
++#define CBE_PM_OVERFLOW_CTRS(pm_status) (((pm_status) >> 24) & 0xff)
++#define CBE_PM_ALL_OVERFLOW_INTR 0xff000000
++#define CBE_PM_INTERVAL_INTR 0x00800000
++#define CBE_PM_TRACE_BUFFER_FULL_INTR 0x00400000
++#define CBE_PM_TRACE_BUFFER_UNDERFLOW_INTR 0x00200000
+
+ enum pm_reg_name {
+ group_control,
+diff --git a/arch/powerpc/include/asm/cell-regs.h b/arch/powerpc/include/asm/cell-regs.h
+index fd6fd00..580786d 100644
+--- a/arch/powerpc/include/asm/cell-regs.h
++++ b/arch/powerpc/include/asm/cell-regs.h
+@@ -117,8 +117,9 @@ struct cbe_pmd_regs {
+ u8 pad_0x0c1c_0x0c20 [4]; /* 0x0c1c */
+ #define CBE_PMD_FIR_MODE_M8 0x00800
+ u64 fir_enable_mask; /* 0x0c20 */
+-
+- u8 pad_0x0c28_0x0ca8 [0x0ca8 - 0x0c28]; /* 0x0c28 */
++ u8 pad_0x0c28_0x0c98 [0x0c98 - 0x0c28]; /* 0x0c28 */
++ u64 on_ramp_trace; /* 0x0c98 */
++ u64 pad_0x0ca0; /* 0x0ca0 */
+ u64 ras_esc_0; /* 0x0ca8 */
+ u8 pad_0x0cb0_0x1000 [0x1000 - 0x0cb0]; /* 0x0cb0 */
+ };
+@@ -218,7 +219,11 @@ extern struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu);
+
+
+ struct cbe_mic_tm_regs {
+- u8 pad_0x0000_0x0040[0x0040 - 0x0000]; /* 0x0000 */
++ u8 pad_0x0000_0x0010[0x0010 - 0x0000]; /* 0x0000 */
++
++ u64 MBL_debug; /* 0x0010 */
++
++ u8 pad_0x0018_0x0040[0x0040 - 0x0018]; /* 0x0018 */
+
+ u64 mic_ctl_cnfg2; /* 0x0040 */
+ #define CBE_MIC_ENABLE_AUX_TRC 0x8000000000000000LL
+@@ -303,6 +308,25 @@ struct cbe_mic_tm_regs {
+ extern struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np);
+ extern struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu);
+
++/*
++ *
++ * PPE Privileged MMIO Registers definition. (offset 0x500000 - 0x500fff)
++ *
++ */
++struct cbe_ppe_priv_regs {
++ u8 pad_0x0000_0x0858[0x0858 - 0x0000]; /* 0x0000 */
++
++ u64 L2_debug1; /* 0x0858 */
++
++ u8 pad_0x0860_0x0958[0x0958 - 0x0860]; /* 0x0860 */
++
++ u64 ciu_dr1; /* 0x0958 */
++
++ u8 pad_0x0960_0x1000[0x1000 - 0x0960]; /* 0x0960 */
++};
++
++extern struct cbe_ppe_priv_regs __iomem *cbe_get_cpu_ppe_priv_regs(int cpu);
++
+ /* some utility functions to deal with SMT */
+ extern u32 cbe_get_hw_thread_id(int cpu);
+ extern u32 cbe_cpu_to_node(int cpu);
+diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
+index 6493a39..ba9ead4 100644
+--- a/arch/powerpc/include/asm/paca.h
++++ b/arch/powerpc/include/asm/paca.h
+@@ -97,6 +97,10 @@ struct paca_struct {
+ u8 soft_enabled; /* irq soft-enable flag */
+ u8 hard_enabled; /* set if irqs are enabled in MSR */
+ u8 io_sync; /* writel() needs spin_unlock sync */
++#ifdef CONFIG_PERFMON
++ u8 pmu_except_pending; /* PMU exception occurred while soft
++ * disabled */
++#endif
+
+ /* Stuff for accurate time accounting */
+ u64 user_time; /* accumulated usermode TB ticks */
+diff --git a/arch/powerpc/include/asm/perfmon.h b/arch/powerpc/include/asm/perfmon.h
+new file mode 100644
+index 0000000..da0ae3b
+--- /dev/null
++++ b/arch/powerpc/include/asm/perfmon.h
+@@ -0,0 +1,33 @@
++/*
++ * Copyright (c) 2007 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This file contains powerpc specific definitions for the perfmon
++ * interface.
++ *
++ * This file MUST never be included directly. Use linux/perfmon.h.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#ifndef _ASM_POWERPC_PERFMON_H_
++#define _ASM_POWERPC_PERFMON_H_
++
++/*
++ * arch-specific user visible interface definitions
++ */
++#define PFM_ARCH_MAX_PMCS (256+64) /* 256 HW 64 SW */
++#define PFM_ARCH_MAX_PMDS (256+64) /* 256 HW 64 SW */
++
++#endif /* _ASM_POWERPC_PERFMON_H_ */
+diff --git a/arch/powerpc/include/asm/perfmon_kern.h b/arch/powerpc/include/asm/perfmon_kern.h
+new file mode 100644
+index 0000000..65ec984
+--- /dev/null
++++ b/arch/powerpc/include/asm/perfmon_kern.h
+@@ -0,0 +1,390 @@
++/*
++ * Copyright (c) 2005 David Gibson, IBM Corporation.
++ *
++ * Based on other versions:
++ * Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This file contains powerpc specific definitions for the perfmon
++ * interface.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#ifndef _ASM_POWERPC_PERFMON_KERN_H_
++#define _ASM_POWERPC_PERFMON_KERN_H_
++
++#ifdef __KERNEL__
++
++#ifdef CONFIG_PERFMON
++
++#include <asm/pmc.h>
++#include <asm/unistd.h>
++
++#define HID0_PMC5_6_GR_MODE (1UL << (63 - 40))
++
++enum powerpc_pmu_type {
++ PFM_POWERPC_PMU_NONE,
++ PFM_POWERPC_PMU_604,
++ PFM_POWERPC_PMU_604e,
++ PFM_POWERPC_PMU_750, /* XXX: Minor event set diffs between IBM and Moto. */
++ PFM_POWERPC_PMU_7400,
++ PFM_POWERPC_PMU_7450,
++ PFM_POWERPC_PMU_POWER4,
++ PFM_POWERPC_PMU_POWER5,
++ PFM_POWERPC_PMU_POWER5p,
++ PFM_POWERPC_PMU_POWER6,
++ PFM_POWERPC_PMU_CELL,
++};
++
++struct pfm_arch_pmu_info {
++ enum powerpc_pmu_type pmu_style;
++
++ void (*write_pmc)(unsigned int cnum, u64 value);
++ void (*write_pmd)(unsigned int cnum, u64 value);
++
++ u64 (*read_pmd)(unsigned int cnum);
++
++ void (*enable_counters)(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++ void (*disable_counters)(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++
++ void (*irq_handler)(struct pt_regs *regs, struct pfm_context *ctx);
++ void (*get_ovfl_pmds)(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++
++ /* The following routines are optional. */
++ void (*restore_pmcs)(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++ void (*restore_pmds)(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++
++ int (*ctxswout_thread)(struct task_struct *task,
++ struct pfm_context *ctx,
++ struct pfm_event_set *set);
++ void (*ctxswin_thread)(struct task_struct *task,
++ struct pfm_context *ctx,
++ struct pfm_event_set *set);
++ int (*load_context)(struct pfm_context *ctx);
++ void (*unload_context)(struct pfm_context *ctx);
++ int (*acquire_pmu)(u64 *unavail_pmcs, u64 *unavail_pmds);
++ void (*release_pmu)(void);
++ void *platform_info;
++ void (*resend_irq)(struct pfm_context *ctx);
++};
++
++#ifdef CONFIG_PPC32
++#define PFM_ARCH_PMD_STK_ARG 6 /* conservative value */
++#define PFM_ARCH_PMC_STK_ARG 6 /* conservative value */
++#else
++#define PFM_ARCH_PMD_STK_ARG 8 /* conservative value */
++#define PFM_ARCH_PMC_STK_ARG 8 /* conservative value */
++#endif
++
++static inline void pfm_arch_resend_irq(struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ arch_info->resend_irq(ctx);
++}
++
++static inline void pfm_arch_serialize(void)
++{}
++
++static inline void pfm_arch_write_pmc(struct pfm_context *ctx,
++ unsigned int cnum,
++ u64 value)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++
++ /*
++ * we only write to the actual register when monitoring is
++ * active (pfm_start was issued)
++ */
++ if (ctx && ctx->flags.started == 0)
++ return;
++
++ BUG_ON(!arch_info->write_pmc);
++
++ arch_info->write_pmc(cnum, value);
++}
++
++static inline void pfm_arch_write_pmd(struct pfm_context *ctx,
++ unsigned int cnum, u64 value)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++
++ value &= pfm_pmu_conf->ovfl_mask;
++
++ BUG_ON(!arch_info->write_pmd);
++
++ arch_info->write_pmd(cnum, value);
++}
++
++static inline u64 pfm_arch_read_pmd(struct pfm_context *ctx, unsigned int cnum)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++
++ BUG_ON(!arch_info->read_pmd);
++
++ return arch_info->read_pmd(cnum);
++}
++
++/*
++ * For some CPUs, the upper bits of a counter must be set in order for the
++ * overflow interrupt to happen. On overflow, the counter has wrapped around,
++ * and the upper bits are cleared. This function may be used to set them back.
++ */
++static inline void pfm_arch_ovfl_reset_pmd(struct pfm_context *ctx,
++ unsigned int cnum)
++{
++ u64 val = pfm_arch_read_pmd(ctx, cnum);
++
++ /* This masks out overflow bit 31 */
++ pfm_arch_write_pmd(ctx, cnum, val);
++}
++
++/*
++ * At certain points, perfmon needs to know if monitoring has been
++ * explicitely started/stopped by user via pfm_start/pfm_stop. The
++ * information is tracked in flags.started. However on certain
++ * architectures, it may be possible to start/stop directly from
++ * user level with a single assembly instruction bypassing
++ * the kernel. This function must be used to determine by
++ * an arch-specific mean if monitoring is actually started/stopped.
++ */
++static inline int pfm_arch_is_active(struct pfm_context *ctx)
++{
++ return ctx->flags.started;
++}
++
++static inline void pfm_arch_ctxswout_sys(struct task_struct *task,
++ struct pfm_context *ctx)
++{}
++
++static inline void pfm_arch_ctxswin_sys(struct task_struct *task,
++ struct pfm_context *ctx)
++{}
++
++void pfm_arch_init_percpu(void);
++int pfm_arch_is_monitoring_active(struct pfm_context *ctx);
++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx);
++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set);
++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set);
++void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx, struct pfm_event_set *set);
++int pfm_arch_get_ovfl_pmds(struct pfm_context *ctx,
++ struct pfm_event_set *set);
++char *pfm_arch_get_pmu_module_name(void);
++/*
++ * called from __pfm_interrupt_handler(). ctx is not NULL.
++ * ctx is locked. PMU interrupt is masked.
++ *
++ * must stop all monitoring to ensure handler has consistent view.
++ * must collect overflowed PMDs bitmask into povfls_pmds and
++ * npend_ovfls. If no interrupt detected then npend_ovfls
++ * must be set to zero.
++ */
++static inline void pfm_arch_intr_freeze_pmu(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ pfm_arch_stop(current, ctx);
++}
++
++void powerpc_irq_handler(struct pt_regs *regs);
++
++/*
++ * unfreeze PMU from pfm_do_interrupt_handler()
++ * ctx may be NULL for spurious
++ */
++static inline void pfm_arch_intr_unfreeze_pmu(struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ if (!ctx)
++ return;
++
++ PFM_DBG_ovfl("state=%d", ctx->state);
++
++ ctx->flags.started = 1;
++
++ if (ctx->state == PFM_CTX_MASKED)
++ return;
++
++ arch_info = pfm_pmu_info();
++ BUG_ON(!arch_info->enable_counters);
++ arch_info->enable_counters(ctx, ctx->active_set);
++}
++
++/*
++ * PowerPC does not save the PMDs during pfm_arch_intr_freeze_pmu(), thus
++ * this routine needs to do it when switching sets on overflow
++ */
++static inline void pfm_arch_save_pmds_from_intr(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ pfm_save_pmds(ctx, set);
++}
++
++/*
++ * this function is called from the PMU interrupt handler ONLY.
++ * On PPC, the PMU is frozen via arch_stop, masking would be implemented
++ * via arch-stop as well. Given that the PMU is already stopped when
++ * entering the interrupt handler, we do not need to stop it again, so
++ * this function is a nop.
++ */
++static inline void pfm_arch_mask_monitoring(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{}
++
++/*
++ * Simply need to start the context in order to unmask.
++ */
++static inline void pfm_arch_unmask_monitoring(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ pfm_arch_start(current, ctx);
++}
++
++
++static inline int pfm_arch_pmu_config_init(struct pfm_pmu_config *cfg)
++{
++ return 0;
++}
++
++static inline int pfm_arch_context_create(struct pfm_context *ctx,
++ u32 ctx_flags)
++{
++ return 0;
++}
++
++static inline void pfm_arch_context_free(struct pfm_context *ctx)
++{}
++
++/* not necessary on PowerPC */
++static inline void pfm_cacheflush(void *addr, unsigned int len)
++{}
++
++/*
++ * function called from pfm_setfl_sane(). Context is locked
++ * and interrupts are masked.
++ * The value of flags is the value of ctx_flags as passed by
++ * user.
++ *
++ * function must check arch-specific set flags.
++ * Return:
++ * 1 when flags are valid
++ * 0 on error
++ */
++static inline int pfm_arch_setfl_sane(struct pfm_context *ctx, u32 flags)
++{
++ return 0;
++}
++
++static inline int pfm_arch_init(void)
++{
++ return 0;
++}
++
++static inline int pfm_arch_load_context(struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ int rc = 0;
++
++ arch_info = pfm_pmu_info();
++ if (arch_info->load_context)
++ rc = arch_info->load_context(ctx);
++
++ return rc;
++}
++
++static inline void pfm_arch_unload_context(struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ if (arch_info->unload_context)
++ arch_info->unload_context(ctx);
++}
++
++static inline int pfm_arch_pmu_acquire(u64 *unavail_pmcs, u64 *unavail_pmds)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ int rc = 0;
++
++ arch_info = pfm_pmu_info();
++ if (arch_info->acquire_pmu) {
++ rc = arch_info->acquire_pmu(unavail_pmcs, unavail_pmds);
++ if (rc)
++ return rc;
++ }
++
++ return reserve_pmc_hardware(powerpc_irq_handler);
++}
++
++static inline void pfm_arch_pmu_release(void)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ if (arch_info->release_pmu)
++ arch_info->release_pmu();
++
++ release_pmc_hardware();
++}
++
++static inline void pfm_arch_arm_handle_work(struct task_struct *task)
++{}
++
++static inline void pfm_arch_disarm_handle_work(struct task_struct *task)
++{}
++
++static inline int pfm_arch_get_base_syscall(void)
++{
++ return __NR_pfm_create_context;
++}
++
++struct pfm_arch_context {
++ /* Cell: Most recent value of the pm_status
++ * register read by the interrupt handler.
++ *
++ * Interrupt handler sets last_read_updated if it
++ * just read and updated last_read_pm_status
++ */
++ u32 last_read_pm_status;
++ u32 last_read_updated;
++ u64 powergs_pmc5, powergs_pmc6;
++ u64 delta_tb, delta_tb_start;
++ u64 delta_purr, delta_purr_start;
++};
++
++#define PFM_ARCH_CTX_SIZE sizeof(struct pfm_arch_context)
++/*
++ * PowerPC does not need extra alignment requirements for the sampling buffer
++ */
++#define PFM_ARCH_SMPL_ALIGN_SIZE 0
++
++#endif /* CONFIG_PERFMON */
++
++#endif /* __KERNEL__ */
++#endif /* _ASM_POWERPC_PERFMON_KERN_H_ */
+diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
+index c6d1ab6..a9f3ad0 100644
+--- a/arch/powerpc/include/asm/reg.h
++++ b/arch/powerpc/include/asm/reg.h
+@@ -698,6 +698,7 @@
+ #define PV_POWER5 0x003A
+ #define PV_POWER5p 0x003B
+ #define PV_970FX 0x003C
++#define PV_POWER6 0x003E
+ #define PV_630 0x0040
+ #define PV_630p 0x0041
+ #define PV_970MP 0x0044
+diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
+index f6cc7a4..0164841 100644
+--- a/arch/powerpc/include/asm/systbl.h
++++ b/arch/powerpc/include/asm/systbl.h
+@@ -322,3 +322,15 @@ SYSCALL_SPU(epoll_create1)
+ SYSCALL_SPU(dup3)
+ SYSCALL_SPU(pipe2)
+ SYSCALL(inotify_init1)
++SYSCALL(pfm_create_context)
++SYSCALL(pfm_write_pmcs)
++SYSCALL(pfm_write_pmds)
++SYSCALL(pfm_read_pmds)
++SYSCALL(pfm_load_context)
++SYSCALL(pfm_start)
++SYSCALL(pfm_stop)
++SYSCALL(pfm_restart)
++SYSCALL(pfm_create_evtsets)
++SYSCALL(pfm_getinfo_evtsets)
++SYSCALL(pfm_delete_evtsets)
++SYSCALL(pfm_unload_context)
+diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
+index 9665a26..6cda9f9 100644
+--- a/arch/powerpc/include/asm/thread_info.h
++++ b/arch/powerpc/include/asm/thread_info.h
+@@ -130,10 +130,12 @@ static inline struct thread_info *current_thread_info(void)
+ #define _TIF_FREEZE (1<<TIF_FREEZE)
+ #define _TIF_RUNLATCH (1<<TIF_RUNLATCH)
+ #define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
++#define _TIF_PERFMON_WORK (1<<TIF_PERFMON_WORK)
++#define _TIF_PERFMON_CTXSW (1<<TIF_PERFMON_CTXSW)
+ #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
+
+ #define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+- _TIF_NOTIFY_RESUME)
++ _TIF_NOTIFY_RESUME | _TIF_PERFMON_WORK)
+ #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR)
+
+ /* Bits in local_flags */
+diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
+index e07d0c7..6226cba 100644
+--- a/arch/powerpc/include/asm/unistd.h
++++ b/arch/powerpc/include/asm/unistd.h
+@@ -341,10 +341,22 @@
+ #define __NR_dup3 316
+ #define __NR_pipe2 317
+ #define __NR_inotify_init1 318
++#define __NR_pfm_create_context 319
++#define __NR_pfm_write_pmcs 320
++#define __NR_pfm_write_pmds 321
++#define __NR_pfm_read_pmds 322
++#define __NR_pfm_load_context 323
++#define __NR_pfm_start 324
++#define __NR_pfm_stop 325
++#define __NR_pfm_restart 326
++#define __NR_pfm_create_evtsets 327
++#define __NR_pfm_getinfo_evtsets 328
++#define __NR_pfm_delete_evtsets 329
++#define __NR_pfm_unload_context 330
+
+ #ifdef __KERNEL__
+
+-#define __NR_syscalls 319
++#define __NR_syscalls 331
+
+ #define __NR__exit __NR_exit
+ #define NR_syscalls __NR_syscalls
+diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
+index 1cbbf70..198645f 100644
+--- a/arch/powerpc/kernel/entry_32.S
++++ b/arch/powerpc/kernel/entry_32.S
+@@ -39,7 +39,7 @@
+ * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE.
+ */
+ #if MSR_KERNEL >= 0x10000
+-#define LOAD_MSR_KERNEL(r, x) lis r,(x)@h; ori r,r,(x)@l
++#define LOAD_MSR_KERNEL(r, x) lis r,(x)@ha; ori r,r,(x)@l
+ #else
+ #define LOAD_MSR_KERNEL(r, x) li r,(x)
+ #endif
+diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
+index 2d802e9..77a090d 100644
+--- a/arch/powerpc/kernel/entry_64.S
++++ b/arch/powerpc/kernel/entry_64.S
+@@ -643,6 +643,10 @@ user_work:
+ b .ret_from_except_lite
+
+ 1: bl .save_nvgprs
++#ifdef CONFIG_PERFMON
++ addi r3,r1,STACK_FRAME_OVERHEAD
++ bl .pfm_handle_work
++#endif /* CONFIG_PERFMON */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .do_signal
+ b .ret_from_except
+diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
+index d972dec..b255fba 100644
+--- a/arch/powerpc/kernel/irq.c
++++ b/arch/powerpc/kernel/irq.c
+@@ -104,6 +104,24 @@ static inline notrace void set_soft_enabled(unsigned long enable)
+ : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
+ }
+
++#ifdef CONFIG_PERFMON
++static inline unsigned long get_pmu_except_pending(void)
++{
++ unsigned long pending;
++
++ __asm__ __volatile__("lbz %0,%1(13)"
++ : "=r" (pending) : "i" (offsetof(struct paca_struct, pmu_except_pending)));
++
++ return pending;
++}
++
++static inline void set_pmu_except_pending(unsigned long pending)
++{
++ __asm__ __volatile__("stb %0,%1(13)"
++ : : "r" (pending), "i" (offsetof(struct paca_struct, pmu_except_pending)));
++}
++#endif /* CONFIG_PERFMON */
++
+ notrace void raw_local_irq_restore(unsigned long en)
+ {
+ /*
+@@ -162,6 +180,19 @@ notrace void raw_local_irq_restore(unsigned long en)
+ lv1_get_version_info(&tmp);
+ }
+
++#ifdef CONFIG_PERFMON
++ /*
++ * If a PMU exception occurred while interrupts were soft disabled,
++ * force a PMU exception.
++ */
++ if (get_pmu_except_pending()) {
++ set_pmu_except_pending(0);
++ /* Make sure we trigger the edge detection circuitry */
++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO);
++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_PMAO);
++ }
++#endif /* CONFIG_PERFMON */
++
+ __hard_irq_enable();
+ }
+ EXPORT_SYMBOL(raw_local_irq_restore);
+diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
+index 957bded..32dbc8e 100644
+--- a/arch/powerpc/kernel/process.c
++++ b/arch/powerpc/kernel/process.c
+@@ -33,6 +33,7 @@
+ #include <linux/mqueue.h>
+ #include <linux/hardirq.h>
+ #include <linux/utsname.h>
++#include <linux/perfmon_kern.h>
+
+ #include <asm/pgtable.h>
+ #include <asm/uaccess.h>
+@@ -393,9 +394,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
+ new_thread->start_tb = current_tb;
+ }
+ #endif
+-
+ local_irq_save(flags);
+
++ if (test_tsk_thread_flag(prev, TIF_PERFMON_CTXSW))
++ pfm_ctxsw_out(prev, new);
++
++ if (test_tsk_thread_flag(new, TIF_PERFMON_CTXSW))
++ pfm_ctxsw_in(prev, new);
++
+ account_system_vtime(current);
+ account_process_vtime(current);
+ calculate_steal_time();
+@@ -544,6 +550,7 @@ void show_regs(struct pt_regs * regs)
+ void exit_thread(void)
+ {
+ discard_lazy_cpu_state();
++ pfm_exit_thread();
+ }
+
+ void flush_thread(void)
+@@ -669,6 +676,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ #else
+ kregs->nip = (unsigned long)ret_from_fork;
+ #endif
++ pfm_copy_thread(p);
+
+ return 0;
+ }
+diff --git a/arch/powerpc/perfmon/Kconfig b/arch/powerpc/perfmon/Kconfig
+new file mode 100644
+index 0000000..3f4bbf2
+--- /dev/null
++++ b/arch/powerpc/perfmon/Kconfig
+@@ -0,0 +1,67 @@
++menu "Hardware Performance Monitoring support"
++config PERFMON
++ bool "Perfmon2 performance monitoring interface"
++ default n
++ help
++ Enables the perfmon2 interface to access the hardware
++ performance counters. See <http://perfmon2.sf.net/> for
++ more details.
++
++config PERFMON_DEBUG
++ bool "Perfmon debugging"
++ default n
++ depends on PERFMON
++ help
++ Enables perfmon debugging support
++
++config PERFMON_DEBUG_FS
++ bool "Enable perfmon statistics reporting via debugfs"
++ default y
++ depends on PERFMON && DEBUG_FS
++ help
++ Enable collection and reporting of perfmon timing statistics under
++ debugfs. This is used for debugging and performance analysis of the
++ subsystem. The debugfs filesystem must be mounted.
++
++config PERFMON_POWER4
++ tristate "Support for Power4 hardware performance counters"
++ depends on PERFMON && PPC64
++ default n
++ help
++ Enables support for the Power 4 hardware performance counters
++ If unsure, say M.
++
++config PERFMON_POWER5
++ tristate "Support for Power5 hardware performance counters"
++ depends on PERFMON && PPC64
++ default n
++ help
++ Enables support for the Power 5 hardware performance counters
++ If unsure, say M.
++
++config PERFMON_POWER6
++ tristate "Support for Power6 hardware performance counters"
++ depends on PERFMON && PPC64
++ default n
++ help
++ Enables support for the Power 6 hardware performance counters
++ If unsure, say M.
++
++config PERFMON_PPC32
++ tristate "Support for PPC32 hardware performance counters"
++ depends on PERFMON && PPC32
++ default n
++ help
++ Enables support for the PPC32 hardware performance counters
++ If unsure, say M.
++
++config PERFMON_CELL
++ tristate "Support for Cell hardware performance counters"
++ depends on PERFMON && PPC_CELL
++ select PS3_LPM if PPC_PS3
++ default n
++ help
++ Enables support for the Cell hardware performance counters.
++ If unsure, say M.
++
++endmenu
+diff --git a/arch/powerpc/perfmon/Makefile b/arch/powerpc/perfmon/Makefile
+new file mode 100644
+index 0000000..300661f
+--- /dev/null
++++ b/arch/powerpc/perfmon/Makefile
+@@ -0,0 +1,6 @@
++obj-$(CONFIG_PERFMON) += perfmon.o
++obj-$(CONFIG_PERFMON_POWER4) += perfmon_power4.o
++obj-$(CONFIG_PERFMON_POWER5) += perfmon_power5.o
++obj-$(CONFIG_PERFMON_POWER6) += perfmon_power6.o
++obj-$(CONFIG_PERFMON_PPC32) += perfmon_ppc32.o
++obj-$(CONFIG_PERFMON_CELL) += perfmon_cell.o
+diff --git a/arch/powerpc/perfmon/perfmon.c b/arch/powerpc/perfmon/perfmon.c
+new file mode 100644
+index 0000000..51a8b6a
+--- /dev/null
++++ b/arch/powerpc/perfmon/perfmon.c
+@@ -0,0 +1,334 @@
++/*
++ * This file implements the powerpc specific
++ * support for the perfmon2 interface
++ *
++ * Copyright (c) 2005 David Gibson, IBM Corporation.
++ *
++ * based on versions for other architectures:
++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++#include <linux/interrupt.h>
++#include <linux/perfmon_kern.h>
++
++static void pfm_stop_active(struct task_struct *task,
++ struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ BUG_ON(!arch_info->disable_counters || !arch_info->get_ovfl_pmds);
++
++ arch_info->disable_counters(ctx, set);
++
++ if (set->npend_ovfls)
++ return;
++
++ arch_info->get_ovfl_pmds(ctx, set);
++}
++
++/*
++ * Called from pfm_save_pmds(). Interrupts are masked. Registers are
++ * already saved away.
++ */
++void pfm_arch_clear_pmd_ovfl_cond(struct pfm_context *ctx,
++ struct pfm_event_set *set)
++{
++ int i, num;
++ u64 *used_pmds, *intr_pmds;
++
++ num = set->nused_pmds;
++ used_pmds = set->used_pmds;
++ intr_pmds = ctx->regs.intr_pmds;
++
++ for (i = 0; num; i++)
++ if (likely(test_bit(i, used_pmds))) {
++ if (likely(test_bit(i, intr_pmds)))
++ pfm_write_pmd(ctx, i, 0);
++ num--;
++ }
++}
++
++/*
++ * Called from pfm_ctxsw(). Task is guaranteed to be current.
++ * Context is locked. Interrupts are masked. Monitoring is active.
++ * PMU access is guaranteed. PMC and PMD registers are live in PMU.
++ *
++ * for per-thread:
++ * must stop monitoring for the task
++ * Return:
++ * non-zero : did not save PMDs (as part of stopping the PMU)
++ * 0 : saved PMDs (no need to save them in caller)
++ */
++int pfm_arch_ctxswout_thread(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ /*
++ * disable lazy restore of the PMC/PMD registers.
++ */
++ ctx->active_set->priv_flags |= PFM_SETFL_PRIV_MOD_BOTH;
++
++ if (ctx->state == PFM_CTX_MASKED)
++ return 1;
++
++ pfm_stop_active(task, ctx, ctx->active_set);
++
++ if (arch_info->ctxswout_thread)
++ arch_info->ctxswout_thread(task, ctx, ctx->active_set);
++
++ return pfm_arch_is_active(ctx);
++}
++
++/*
++ * Called from pfm_ctxsw
++ */
++void pfm_arch_ctxswin_thread(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ if (ctx->state != PFM_CTX_MASKED && ctx->flags.started == 1) {
++ BUG_ON(!arch_info->enable_counters);
++ arch_info->enable_counters(ctx, ctx->active_set);
++ }
++
++ if (arch_info->ctxswin_thread)
++ arch_info->ctxswin_thread(task, ctx, ctx->active_set);
++}
++
++/*
++ * Called from pfm_stop() and idle notifier
++ *
++ * Interrupts are masked. Context is locked. Set is the active set.
++ *
++ * For per-thread:
++ * task is not necessarily current. If not current task, then
++ * task is guaranteed stopped and off any cpu. Access to PMU
++ * is not guaranteed. Interrupts are masked. Context is locked.
++ * Set is the active set.
++ *
++ * For system-wide:
++ * task is current
++ *
++ * must disable active monitoring. ctx cannot be NULL
++ */
++void pfm_arch_stop(struct task_struct *task, struct pfm_context *ctx)
++{
++ /*
++ * no need to go through stop_save()
++ * if we are already stopped
++ */
++ if (!ctx->flags.started || ctx->state == PFM_CTX_MASKED)
++ return;
++
++ /*
++ * stop live registers and collect pending overflow
++ */
++ if (task == current)
++ pfm_stop_active(task, ctx, ctx->active_set);
++}
++
++/*
++ * Enable active monitoring. Called from pfm_start() and
++ * pfm_arch_unmask_monitoring().
++ *
++ * Interrupts are masked. Context is locked. Set is the active set.
++ *
++ * For per-thread:
++ * Task is not necessarily current. If not current task, then task
++ * is guaranteed stopped and off any cpu. No access to PMU if task
++ * is not current.
++ *
++ * For system-wide:
++ * Task is always current
++ */
++void pfm_arch_start(struct task_struct *task, struct pfm_context *ctx)
++{
++ struct pfm_arch_pmu_info *arch_info;
++
++ arch_info = pfm_pmu_info();
++ if (task != current)
++ return;
++
++ BUG_ON(!arch_info->enable_counters);
++
++ arch_info->enable_counters(ctx, ctx->active_set);
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets()
++ * context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMD registers from set.
++ */
++void pfm_arch_restore_pmds(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ u64 *used_pmds;
++ u16 i, num;
++
++ arch_info = pfm_pmu_info();
++
++ /* The model-specific module can override the default
++ * restore-PMD method.
++ */
++ if (arch_info->restore_pmds)
++ return arch_info->restore_pmds(ctx, set);
++
++ num = set->nused_pmds;
++ used_pmds = set->used_pmds;
++
++ for (i = 0; num; i++) {
++ if (likely(test_bit(i, used_pmds))) {
++ pfm_write_pmd(ctx, i, set->pmds[i].value);
++ num--;
++ }
++ }
++}
++
++/*
++ * function called from pfm_switch_sets(), pfm_context_load_thread(),
++ * pfm_context_load_sys(), pfm_ctxsw(), pfm_switch_sets()
++ * context is locked. Interrupts are masked. set cannot be NULL.
++ * Access to the PMU is guaranteed.
++ *
++ * function must restore all PMC registers from set, if needed.
++ */
++void pfm_arch_restore_pmcs(struct pfm_context *ctx, struct pfm_event_set *set)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ u64 *impl_pmcs;
++ unsigned int i, max_pmc, reg;
++
++ arch_info = pfm_pmu_info();
++ /* The model-specific module can override the default
++ * restore-PMC method.
++ */
++ if (arch_info->restore_pmcs)
++ return arch_info->restore_pmcs(ctx, set);
++
++ /* The "common" powerpc model's enable the counters simply by writing
++ * all the control registers. Therefore, if we're masked or stopped we
++ * don't need to bother restoring the PMCs now.
++ */
++ if (ctx->state == PFM_CTX_MASKED || ctx->flags.started == 0)
++ return;
++
++ max_pmc = ctx->regs.max_pmc;
++ impl_pmcs = ctx->regs.pmcs;
++
++ /*
++ * Restore all pmcs in reverse order to ensure the counters aren't
++ * enabled before their event selectors are set correctly.
++ */
++ reg = max_pmc - 1;
++ for (i = 0; i < max_pmc; i++) {
++ if (test_bit(reg, impl_pmcs))
++ pfm_arch_write_pmc(ctx, reg, set->pmcs[reg]);
++ reg--;
++ }
++}
++
++char *pfm_arch_get_pmu_module_name(void)
++{
++ unsigned int pvr = mfspr(SPRN_PVR);
++
++ switch (PVR_VER(pvr)) {
++ case 0x0004: /* 604 */
++ case 0x0009: /* 604e; */
++ case 0x000A: /* 604ev */
++ case 0x0008: /* 750/740 */
++ case 0x7000: /* 750FX */
++ case 0x7001:
++ case 0x7002: /* 750GX */
++ case 0x000C: /* 7400 */
++ case 0x800C: /* 7410 */
++ case 0x8000: /* 7451/7441 */
++ case 0x8001: /* 7455/7445 */
++ case 0x8002: /* 7457/7447 */
++ case 0x8003: /* 7447A */
++ case 0x8004: /* 7448 */
++ return("perfmon_ppc32");
++ case PV_POWER4:
++ case PV_POWER4p:
++ return "perfmon_power4";
++ case PV_POWER5:
++ return "perfmon_power5";
++ case PV_POWER5p:
++ if (PVR_REV(pvr) < 0x300)
++ /* PMU behaves like POWER5 */
++ return "perfmon_power5";
++ else
++ /* PMU behaves like POWER6 */
++ return "perfmon_power6";
++ case PV_POWER6:
++ return "perfmon_power6";
++ case PV_970:
++ case PV_970FX:
++ case PV_970MP:
++ return "perfmon_ppc970";
++ case PV_BE:
++ return "perfmon_cell";
++ }
++ return NULL;
++}
++
++void pfm_arch_init_percpu(void)
++{
++#ifdef CONFIG_PPC64
++ extern void ppc64_enable_pmcs(void);
++ ppc64_enable_pmcs();
++#endif
++}
++
++/**
++ * powerpc_irq_handler
++ *
++ * Get the perfmon context that belongs to the current CPU, and call the
++ * model-specific interrupt handler.
++ **/
++void powerpc_irq_handler(struct pt_regs *regs)
++{
++ struct pfm_arch_pmu_info *arch_info;
++ struct pfm_context *ctx;
++
++ if (! regs->softe) {
++ /*
++ * We got a PMU interrupt while interrupts were soft
++ * disabled. Disable hardware interrupts by clearing
++ * MSR_EE and also clear PMAO because we will need to set
++ * that again later when interrupts are re-enabled and
++ * raw_local_irq_restore() sees that the pmu_except_pending
++ * flag is set.
++ */
++ regs->msr &= ~MSR_EE;
++ get_paca()->pmu_except_pending = 1;
++ mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_PMAO);
++ return;
++ }
++
++ arch_info = pfm_pmu_info();
++ if (arch_info->irq_handler) {
++ ctx = __get_cpu_var(pmu_ctx);
++ if (likely(ctx))
++ arch_info->irq_handler(regs, ctx);
++ }
++}
+diff --git a/arch/powerpc/perfmon/perfmon_cell.c b/arch/powerpc/perfmon/perfmon_cell.c
+new file mode 100644
+index 0000000..e1ae12c
+--- /dev/null
++++ b/arch/powerpc/perfmon/perfmon_cell.c
+@@ -0,0 +1,1449 @@
++/*
++ * This file contains the Cell PMU register description tables
++ * and pmc checker used by perfmon.c.
++ *
++ * Copyright IBM Corporation 2007
++ * (C) Copyright 2007 TOSHIBA CORPORATION
++ *
++ * Based on other Perfmon2 PMU modules.
++ * Copyright (c) 2005-2006 Hewlett-Packard Development Company, L.P.
++ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of version 2 of the GNU General Public
++ * License as published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ * 02111-1307 USA
++ */
++
++#include <linux/module.h>
++#include <linux/perfmon_kern.h>
++#include <linux/io.h>
++#include <asm/cell-pmu.h>
++#include <asm/cell-regs.h>
++#include <asm/machdep.h>
++#include <asm/rtas.h>
++#include <asm/ps3.h>
++#include <asm/spu.h>
++
++MODULE_AUTHOR("Kevin Corry <kevcorry@us.ibm.com>, "
++ "Carl Love <carll@us.ibm.com>");
++MODULE_DESCRIPTION("Cell PMU description table");
++MODULE_LICENSE("GPL");
++
++struct pfm_cell_platform_pmu_info {
++ u32 (*read_ctr)(u32 cpu, u32 ctr);
++ void (*write_ctr)(u32 cpu, u32 ctr, u32 val);
++ void (*write_pm07_control)(u32 cpu, u32 ctr, u32 val);
++ void (*write_pm)(u32 cpu, enum pm_reg_name reg, u32 val);
++ void (*enable_pm)(u32 cpu);
++ void (*disable_pm)(u32 cpu);
++ void (*enable_pm_interrupts)(u32 cpu, u32 thread, u32 mask);
++ u32 (*get_and_clear_pm_interrupts)(u32 cpu);
++ u32 (*get_hw_thread_id)(int cpu);
++ struct cbe_ppe_priv_regs __iomem *(*get_cpu_ppe_priv_regs)(int cpu);
++ struct cbe_pmd_regs __iomem *(*get_cpu_pmd_regs)(int cpu);
++ struct cbe_mic_tm_regs __iomem *(*get_cpu_mic_tm_regs)(int cpu);
++ int (*rtas_token)(const char *service);
++ int (*rtas_call)(int token, int param1, int param2, int *param3, ...);
++};
++
++/*
++ * Mapping from Perfmon logical control registers to Cell hardware registers.
++ */
++static struct pfm_regmap_desc pfm_cell_pmc_desc[] = {
++ /* Per-counter control registers. */
++ PMC_D(PFM_REG_I, "pm0_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm1_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm2_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm3_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm4_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm5_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm6_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm7_control", 0, 0, 0, 0),
++
++ /* Per-counter RTAS arguments. Each of these registers has three fields.
++ * bits 63-48: debug-bus word
++ * bits 47-32: sub-unit
++ * bits 31-0 : full signal number
++ * (MSB = 63, LSB = 0)
++ */
++ PMC_D(PFM_REG_I, "pm0_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm1_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm2_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm3_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm4_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm5_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm6_event", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm7_event", 0, 0, 0, 0),
++
++ /* Global control registers. Same order as enum pm_reg_name. */
++ PMC_D(PFM_REG_I, "group_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "debug_bus_control", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "trace_address", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "ext_trace_timer", 0, 0, 0, 0),
++ PMC_D(PFM_REG_I, "pm_status", 0, 0, 0, 0),
++ /* set the interrupt overflow bit for the four 32 bit counters
++ * that is currently supported. Will need to fix when 32 and 16
++ * bit counters are supported.
++ */
++ PMC_D(PFM_REG_I, "pm_control", 0xF0000000, 0xF0000000, 0, 0),
++ PMC_D(PFM_REG_I, "pm_interval", 0, 0, 0, 0), /* FIX: Does user-space also need read access to this one? */
++ PMC_D(PFM_REG_I, "pm_start_stop", 0, 0, 0, 0),
++};
++#define PFM_PM_NUM_PMCS ARRAY_SIZE(pfm_cell_pmc_desc)
++
++#define CELL_PMC_GROUP_CONTROL 16
++#define CELL_PMC_PM_STATUS 20
++#define CELL_PMC_PM_CONTROL 21
++#define CELL_PMC_PM_CONTROL_CNTR_MASK 0x01E00000UL
++#define CELL_PMC_PM_CONTROL_CNTR_16 0x01E00000UL
++
++/*
++ * Mapping from Perfmon logical data counters to Cell hardware counters.
++ */
++static struct pfm_regmap_desc pfm_cell_pmd_desc[] = {
++ PMD_D(PFM_REG_C, "pm0", 0),
++ PMD_D(PFM_REG_C, "pm1", 0),
++ PMD_D(PFM_REG_C, "pm2", 0),
++ PMD_D(PFM_REG_C, "pm3", 0),
++ PMD_D(PFM_REG_C, "pm4", 0),
++ PMD_D(PFM_REG_C, "pm5", 0),
++ PMD_D(PFM_REG_C, "pm6", 0),
++ PMD_D(PFM_REG_C, "pm7", 0),
++};
++#define PFM_PM_NUM_PMDS ARRAY_SIZE(pfm_cell_pmd_desc)
++
++#define PFM_EVENT_PMC_BUS_WORD(x) (((x) >> 48) & 0x00ff)
++#define PFM_EVENT_PMC_FULL_SIGNAL_NUMBER(x) ((x) & 0xffffffff)
++#define PFM_EVENT_PMC_SIGNAL_GROUP(x) (((x) & 0xffffffff) / 100)
++#define PFM_PM_CTR_INPUT_MUX_BIT(pm07_control) (((pm07_control) >> 26) & 0x1f)
++#define PFM_PM_CTR_INPUT_MUX_GROUP_INDEX(pm07_control) ((pm07_control) >> 31)
++#define PFM_GROUP_CONTROL_GROUP0_WORD(grp_ctrl) ((grp_ctrl) >> 30)
++#define PFM_GROUP_CONTROL_GROUP1_WORD(grp_ctrl) (((grp_ctrl) >> 28) & 0x3)
++#define PFM_NUM_OF_GROUPS 2
++#define PFM_PPU_IU1_THREAD1_BASE_BIT 19
++#define PFM_PPU_XU_THREAD1_BASE_BIT 16
++#define PFM_COUNTER_CTRL_PMC_PPU_TH0 0x100000000ULL
++#define PFM_COUNTER_CTRL_PMC_PPU_TH1 0x200000000ULL
++
++/*
++ * Debug-bus signal handling.
++ *
++ * Some Cell systems have firmware that can handle the debug-bus signal
++ * routing. For systems without this firmware, we have a minimal in-kernel
++ * implementation as well.
++ */
++
++/* The firmware only sees physical CPUs, so divide by 2 if SMT is on. */
++#ifdef CONFIG_SCHED_SMT
++#define RTAS_CPU(cpu) ((cpu) / 2)
++#else
++#define RTAS_CPU(cpu) (cpu)
++#endif
++#define RTAS_BUS_WORD(x) (u16)(((x) >> 48) & 0x0000ffff)
++#define RTAS_SUB_UNIT(x) (u16)(((x) >> 32) & 0x0000ffff)
++#define RTAS_SIGNAL_NUMBER(x) (s32)( (x) & 0xffffffff)
++#define RTAS_SIGNAL_GROUP(x) (RTAS_SIGNAL_NUMBER(x) / 100)
++
++#define subfunc_RESET 1
++#define subfunc_ACTIVATE 2
++
++#define passthru_ENABLE 1
++#define passthru_DISABLE 2
++
++/**
++ * struct cell_rtas_arg
++ *
++ * @cpu: Processor to modify. Linux numbers CPUs based on SMT IDs, but the
++ * firmware only sees the physical CPUs. So this value should be the
++ * SMT ID (from smp_processor_id() or get_cpu()) divided by 2.
++ * @sub_unit: Hardware subunit this applies to (if applicable).
++ * @signal_group: Signal group to enable/disable on the trace bus.
++ * @bus_word: For signal groups that propagate via the trace bus, this trace
++ * bus word will be used. This is a mask of (1 << TraceBusWord).
++ * For other signal groups, this specifies the trigger or event bus.
++ * @bit: Trigger/Event bit, if applicable for the signal group.
++ *
++ * An array of these structures are passed to rtas_call() to set up the
++ * signals on the debug bus.
++ **/
++struct cell_rtas_arg {
++ u16 cpu;
++ u16 sub_unit;
++ s16 signal_group;
++ u8 bus_word;
++ u8 bit;
++};
++
++/**
++ * rtas_reset_signals
++ *
++ * Use the firmware RTAS call to disable signal pass-thru and to reset the
++ * debug-bus signals.
++ **/
++static int rtas_reset_signals(u32 cpu)
++{
++ struct cell_rtas_arg signal;
++ u64 real_addr = virt_to_phys(&signal);
++ int rc;
++ struct pfm_cell_platform_pmu_info *info =
++ ((struct pfm_arch_pmu_info *)
++ (pfm_pmu_conf->pmu_info))->platform_info;
++
++ memset(&signal, 0, sizeof(signal));
++ signal.cpu = RTAS_CPU(cpu);
++ rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"),
++ 5, 1, NULL,
++ subfunc_RESET,
++ passthru_DISABLE,
++ real_addr >> 32,
++ real_addr & 0xffffffff,
++ sizeof(signal));
++
++ return rc;
++}
++
++/**
++ * rtas_activate_signals
++ *
++ * Use the firmware RTAS call to enable signal pass-thru and to activate the
++ * desired signal groups on the debug-bus.
++ **/
++static int rtas_activate_signals(struct cell_rtas_arg *signals,
++ int num_signals)
++{
++ u64 real_addr = virt_to_phys(signals);
++ int rc;
++ struct pfm_cell_platform_pmu_info *info =
++ ((struct pfm_arch_pmu_info *)
++ (pfm_pmu_conf->pmu_info))->platform_info;
++
++ rc = info->rtas_call(info->rtas_token("ibm,cbe-perftools"),
++ 5, 1, NULL,
++ subfunc_ACTIVATE,
++ passthru_ENABLE,
++ real_addr >> 32,
++ real_addr & 0xffffffff,
++ num_signals * sizeof(*signals));
++
++ return rc;
++}
++
++#define HID1_RESET_MASK (~0x00000001ffffffffUL)
++#define PPU_IU1_WORD0_HID1_EN_MASK (~0x00000001f0c0802cUL)
++#define PPU_IU1_WORD0_HID1_EN_WORD ( 0x00000001f0400000UL)
++#define PPU_IU1_WORD1_HID1_EN_MASK (~0x000000010fc08023UL)
++#define PPU_IU1_WORD1_HID1_EN_WORD ( 0x000000010f400001UL)
++#define PPU_XU_WORD0_HID1_EN_MASK (~0x00000001f038402cUL)
++#define PPU_XU_WORD0_HID1_EN_WORD ( 0x00000001f0080008UL)
++#define PPU_XU_WORD1_HID1_EN_MASK (~0x000000010f074023UL)
++#define PPU_XU_WORD1_HID1_EN_WORD ( 0x000000010f030002UL)
++
++/* The bus_word field in the cell_rtas_arg structure is a bit-mask
++ * indicating which debug-bus word(s) to use.
++ */
++enum {
++ BUS_WORD_0 = 1,
++ BUS_WORD_1 = 2,
++ BUS_WORD_2 = 4,
++ BUS_WORD_3 = 8,
++};
++
++/* Definitions of the signal-groups that the built-in signal-activation
++ * code can handle.
++ */
++enum {
++ SIG_GROUP_NONE = 0,
++
++ /* 2.x PowerPC Processor Unit (PPU) Signal Groups */
++ SIG_GROUP_PPU_BASE = 20,
++ SIG_GROUP_PPU_IU1 = 21,
++ SIG_GROUP_PPU_XU = 22,
++
++ /* 3.x PowerPC Storage Subsystem (PPSS) Signal Groups */
++ SIG_GROUP_PPSS_BASE = 30,
++
++ /* 4.x Synergistic Processor Unit (SPU) Signal Groups */
++ SIG_GROUP_SPU_BASE = 40,
++
++ /* 5.x Memory Flow Controller (MFC) Signal Groups */
++ SIG_GROUP_MFC_BASE = 50,
++
++ /* 6.x Element )nterconnect Bus (EIB) Signal Groups */
++ SIG_GROUP_EIB_BASE = 60,
++
++ /* 7.x Memory Interface Controller (MIC) Signal Groups */
++ SIG_GROUP_MIC_BASE = 70,
++
++ /* 8.x Cell Broadband Engine Interface (BEI) Signal Groups */
++ SIG_GROUP_BEI_BASE = 80,
++};
++
++/**
++ * rmw_spr
++ *
++ * Read-modify-write for a special-purpose-register.
++ **/
++#define rmw_spr(spr_id, a_mask, o_mask) \
++ do { \
++ u64 value = mfspr(spr_id); \
++ value &= (u64)(a_mask); \
++ value |= (u64)(o_mask); \
++ mtspr((spr_id), value); \
++ } while (0)
++
++/**
++ * r