Robert,
I have applied this patch to my tree.
Thanks.
On Mon, Jul 02, 2007 at 05:58:07PM +0200, Robert Richter wrote:
> Signed-off-by: Robert Richter <[EMAIL PROTECTED]>
>
> ---
> arch/i386/perfmon/Kconfig | 2
> arch/i386/perfmon/Makefile | 4
> arch/i386/perfmon/perfmon.c | 4
> arch/x86_64/perfmon/Kconfig | 2
> arch/x86_64/perfmon/Makefile | 2
> arch/x86_64/perfmon/perfmon_amd64.c | 341
> ++++++++++++++++++++++++++++++++++++
> arch/x86_64/perfmon/perfmon_k8.c | 341
> ------------------------------------
> 7 files changed, 348 insertions(+), 348 deletions(-)
>
> Index: linux-2.6.22-rc4/arch/i386/perfmon/Kconfig
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/i386/perfmon/Kconfig
> +++ linux-2.6.22-rc4/arch/i386/perfmon/Kconfig
> @@ -55,7 +55,7 @@ config I386_PERFMON_INTEL_ARCH
> Enables 32-bit support for Intel architectural performance counters.
> This
> architecture was introduced by Intel Core Solo/Core Duo processors.
>
> -config I386_PERFMON_K8
> +config I386_PERFMON_AMD64
> tristate "Support 32-bit mode AMD Athlon64/Opteron64 hardware
> performance counters"
> depends on PERFMON
> default n
> Index: linux-2.6.22-rc4/arch/i386/perfmon/Makefile
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/i386/perfmon/Makefile
> +++ linux-2.6.22-rc4/arch/i386/perfmon/Makefile
> @@ -8,7 +8,7 @@ obj-$(CONFIG_I386_PERFMON_P4) += perfmo
> obj-$(CONFIG_I386_PERFMON_CORE) += perfmon_core.o
> obj-$(CONFIG_I386_PERFMON_INTEL_ARCH) += perfmon_intel_arch.o
> obj-$(CONFIG_I386_PERFMON_PEBS) += perfmon_pebs_smpl.o
> -obj-$(CONFIG_I386_PERFMON_K8) += perfmon_k8.o
> +obj-$(CONFIG_I386_PERFMON_AMD64) += perfmon_amd64.o
>
> -perfmon_k8-$(subst m,y,$(CONFIG_I386_PERFMON_K8)) +=
> ../../x86_64/perfmon/perfmon_k8.o
> +perfmon_amd64-$(subst m,y,$(CONFIG_I386_PERFMON_AMD64)) +=
> ../../x86_64/perfmon/perfmon_amd64.o
> perfmon_core-$(subst m,y,$(CONFIG_I386_PERFMON_CORE)) +=
> ../../x86_64/perfmon/perfmon_core.o
> Index: linux-2.6.22-rc4/arch/i386/perfmon/perfmon.c
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/i386/perfmon/perfmon.c
> +++ linux-2.6.22-rc4/arch/i386/perfmon/perfmon.c
> @@ -810,7 +810,7 @@ fastcall void smp_pmu_interrupt(struct p
> * 0 : no overflow
> * 1 : at least one overflow
> *
> - * used by AMD K8 and Intel architectural PMU
> + * used by AMD64 and Intel architectural PMU
> */
> static int __kprobes pfm_has_ovfl_p6(struct pfm_context *ctx)
> {
> @@ -1117,7 +1117,7 @@ char *pfm_arch_get_pmu_module_name(void)
> case 16:
> /* All Opteron processors */
> if (cpu_data->x86_vendor == X86_VENDOR_AMD)
> - return "perfmon_k8";
> + return "perfmon_amd64";
>
> switch(cpu_data->x86_model) {
> case 0 ... 6:
> Index: linux-2.6.22-rc4/arch/x86_64/perfmon/Kconfig
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/x86_64/perfmon/Kconfig
> +++ linux-2.6.22-rc4/arch/x86_64/perfmon/Kconfig
> @@ -14,7 +14,7 @@ config PERFMON_DEBUG
> help
> Enables perfmon debugging support
>
> -config X86_64_PERFMON_K8
> +config X86_64_PERFMON_AMD64
> tristate "Support 64-bit mode AMD Athlon64 and Opteron64 hardware
> performance counters"
> depends on PERFMON
> default n
> Index: linux-2.6.22-rc4/arch/x86_64/perfmon/Makefile
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/x86_64/perfmon/Makefile
> +++ linux-2.6.22-rc4/arch/x86_64/perfmon/Makefile
> @@ -4,7 +4,7 @@
> #
>
> obj-$(CONFIG_PERFMON) += perfmon.o
> -obj-$(CONFIG_X86_64_PERFMON_K8) += perfmon_k8.o
> +obj-$(CONFIG_X86_64_PERFMON_AMD64) += perfmon_amd64.o
> obj-$(CONFIG_X86_64_PERFMON_P4) += perfmon_p4.o
> obj-$(CONFIG_X86_64_PERFMON_CORE) += perfmon_core.o
> obj-$(CONFIG_X86_64_PERFMON_INTEL_ARCH) += perfmon_intel_arch.o
> Index: linux-2.6.22-rc4/arch/x86_64/perfmon/perfmon_amd64.c
> ===================================================================
> --- /dev/null
> +++ linux-2.6.22-rc4/arch/x86_64/perfmon/perfmon_amd64.c
> @@ -0,0 +1,341 @@
> +/*
> + * This file contains the PMU description for the Athlon64 and Opteron64
> + * processors. It supports 32 and 64-bit modes.
> + *
> + * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
> + * Contributed by Stephane Eranian <[EMAIL PROTECTED]>
> + *
> + * 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.h>
> +#include <linux/vmalloc.h>
> +#include <asm/nmi.h>
> +
> +MODULE_AUTHOR("Stephane Eranian <[EMAIL PROTECTED]>");
> +MODULE_DESCRIPTION("AMD64 PMU description table");
> +MODULE_LICENSE("GPL");
> +
> +static int force_nmi;
> +MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt");
> +module_param(force_nmi, bool, 0600);
> +
> +static struct pfm_arch_pmu_info pfm_amd64_pmu_info = {
> + .pmc_addrs = {
> +/* pmc0 */ {{MSR_K7_EVNTSEL0, 0}, 0, PFM_REGT_EN},
> +/* pmc1 */ {{MSR_K7_EVNTSEL1, 0}, 1, PFM_REGT_EN},
> +/* pmc2 */ {{MSR_K7_EVNTSEL2, 0}, 2, PFM_REGT_EN},
> +/* pmc3 */ {{MSR_K7_EVNTSEL3, 0}, 3, PFM_REGT_EN},
> + },
> + .pmd_addrs = {
> +/* pmd0 */ {{MSR_K7_PERFCTR0, 0}, 0, PFM_REGT_CTR},
> +/* pmd1 */ {{MSR_K7_PERFCTR1, 0}, 0, PFM_REGT_CTR},
> +/* pmd2 */ {{MSR_K7_PERFCTR2, 0}, 0, PFM_REGT_CTR},
> +/* pmd3 */ {{MSR_K7_PERFCTR3, 0}, 0, PFM_REGT_CTR},
> + },
> + .pmu_style = PFM_X86_PMU_AMD64
> +};
> +
> +/*
> + * force Local APIC interrupt on overflow
> + */
> +#define PFM_K8_VAL (1ULL<<20)
> +#define PFM_K8_NO64 (1ULL<<20)
> +
> +/*
> + * reserved bits must be zero
> + *
> + * - upper 32 bits are reserved
> + * - APIC enable bit is reserved (forced to 1)
> + * - bit 21 is reserved
> + */
> +#define PFM_K8_RSVD ((~((1ULL<<32)-1)) \
> + | (1ULL<<20) \
> + | (1ULL<<21))
> +
> +static struct pfm_regmap_desc pfm_amd64_pmc_desc[] = {
> +/* pmc0 */ PMC_D(PFM_REG_I64, "PERFSEL0", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL0),
> +/* pmc1 */ PMC_D(PFM_REG_I64, "PERFSEL1", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL1),
> +/* pmc2 */ PMC_D(PFM_REG_I64, "PERFSEL2", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL2),
> +/* pmc3 */ PMC_D(PFM_REG_I64, "PERFSEL3", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL3),
> +};
> +#define PFM_AMD_NUM_PMCS ARRAY_SIZE(pfm_amd64_pmc_desc)
> +
> +static struct pfm_regmap_desc pfm_amd64_pmd_desc[] = {
> +/* pmd0 */ PMD_D(PFM_REG_C, "PERFCTR0", MSR_K7_PERFCTR0),
> +/* pmd1 */ PMD_D(PFM_REG_C, "PERFCTR1", MSR_K7_PERFCTR1),
> +/* pmd2 */ PMD_D(PFM_REG_C, "PERFCTR2", MSR_K7_PERFCTR2),
> +/* pmd3 */ PMD_D(PFM_REG_C, "PERFCTR3", MSR_K7_PERFCTR3)
> +};
> +#define PFM_AMD_NUM_PMDS ARRAY_SIZE(pfm_amd64_pmd_desc)
> +
> +static struct pfm_context **pfm_nb_sys_owners;
> +static struct pfm_context *pfm_nb_task_owner;
> +
> +static struct pfm_pmu_config pfm_amd64_pmu_conf;
> +
> +/*
> + * There can only be one user per socket for the Northbridge (NB) events,
> + * so we enforce mutual exclusion as follows:
> + * - per-thread : only one context machine-wide can use NB events
> + * - system-wide: only one context per processor socket
> + *
> + * Exclusion is enforced at:
> + * - pfm_load_context()
> + * - pfm_write_pmcs() for attached contexts
> + *
> + * Exclusion is released at:
> + * - pfm_unload_context() or any calls that implicitely uses it
> + *
> + * return:
> + * 0 : successfully acquire NB access
> + * < 0: errno, failed to acquire NB access
> + */
> +static int pfm_amd64_acquire_nb(struct pfm_context *ctx)
> +{
> + struct pfm_context **entry, *old;
> + int proc_id;
> +
> +#ifdef CONFIG_SMP
> + proc_id = topology_physical_package_id(smp_processor_id());
> +#else
> + proc_id = 0;
> +#endif
> +
> + if (ctx->flags.system)
> + entry = &pfm_nb_sys_owners[proc_id];
> + else
> + entry = &pfm_nb_task_owner;
> +
> + old = cmpxchg(entry, NULL, ctx);
> + if (!old) {
> + if (ctx->flags.system)
> + PFM_DBG("acquired Northbridge event access on socket
> %u", proc_id);
> + else
> + PFM_DBG("acquired Northbridge event access globally");
> + } else if (old != ctx) {
> + if (ctx->flags.system)
> + PFM_DBG("NorthBridge event conflict on socket %u",
> proc_id);
> + else
> + PFM_DBG("global NorthBridge event conflict");
> + return -EBUSY;
> + }
> + return 0;
> +}
> +
> +/*
> + * invoked from pfm_write_pmcs() when pfm_nb_sys_owners is not NULL,i.e.,
> + * when we have detected a multi-core processor.
> + *
> + * context is locked, interrupts are masked
> + */
> +static int pfm_amd64_pmc_write_check(struct pfm_context *ctx,
> + struct pfm_event_set *set,
> + struct pfarg_pmc *req)
> +{
> + unsigned int event;
> + /*
> + * delay checking NB event until we load the context
> + */
> + if (ctx->state == PFM_CTX_UNLOADED)
> + return 0;
> +
> + /*
> + * check event is NB event
> + */
> + event = (unsigned int)(req->reg_value & 0xff);
> + if (event < 0xee)
> + return 0;
> +
> + return pfm_amd64_acquire_nb(ctx);
> +}
> +
> +/*
> + * invoked on pfm_load_context().
> + * context is locked, interrupts are masked
> + */
> +static int pfm_amd64_load_context(struct pfm_context *ctx)
> +{
> + struct pfm_event_set *set;
> + unsigned int i, n;
> +
> + /*
> + * scan all sets for NB events
> + */
> + list_for_each_entry(set, &ctx->list, list) {
> + n = set->nused_pmcs;
> + for (i = 0; n; i++) {
> + if (!test_bit(i, cast_ulp(set->used_pmcs)))
> + continue;
> + if ((set->pmcs[i] & 0xff) >= 0xee)
> + goto found;
> + n--;
> + }
> + }
> + return 0;
> +found:
> + return pfm_amd64_acquire_nb(ctx);
> +}
> +
> +/*
> + * invoked on pfm_unload_context()
> + */
> +static int pfm_amd64_unload_context(struct pfm_context *ctx)
> +{
> + struct pfm_context **entry, *old;
> + int proc_id;
> +
> +#ifdef CONFIG_SMP
> + proc_id = topology_physical_package_id(smp_processor_id());
> +#else
> + proc_id = 0;
> +#endif
> +
> + /*
> + * unload always happens on the monitored CPU in system-wide
> + */
> + if (ctx->flags.system)
> + entry = &pfm_nb_sys_owners[proc_id];
> + else
> + entry = &pfm_nb_task_owner;
> +
> + old = cmpxchg(entry, ctx, NULL);
> + if (old == ctx) {
> + if (ctx->flags.system)
> + PFM_DBG("released NorthBridge on socket %u", proc_id);
> + else
> + PFM_DBG("released NorthBridge events globally");
> + }
> + return 0;
> +}
> +
> +/*
> + * detect if we need to active NorthBridge event access control
> + */
> +static int pfm_amd64_setup_nb_event_control(void)
> +{
> + unsigned int c, n = 0;
> + unsigned int max_phys = 0;
> +
> +#ifdef CONFIG_SMP
> + for_each_possible_cpu(c) {
> + if (cpu_data[c].phys_proc_id > max_phys)
> + max_phys = cpu_data[c].phys_proc_id;
> + }
> +#else
> + max_phys = 0;
> +#endif
> + if (max_phys > 255) {
> + PFM_INFO("socket id %d is too big to handle", max_phys);
> + return -ENOMEM;
> + }
> +
> + n = max_phys + 1;
> + if (n < 2)
> + return 0;
> +
> + pfm_nb_sys_owners = vmalloc(n * sizeof(*pfm_nb_sys_owners));
> + if (!pfm_nb_sys_owners)
> + return -ENOMEM;
> +
> + memset(pfm_nb_sys_owners, 0, n * sizeof(*pfm_nb_sys_owners));
> + pfm_nb_task_owner = NULL;
> +
> + /*
> + * activate write-checker for PMC registers
> + */
> + for (c = 0; c < PFM_AMD_NUM_PMCS; c++) {
> + pfm_amd64_pmc_desc[c].type |= PFM_REG_WC;
> + }
> +
> + pfm_amd64_pmu_info.load_context = pfm_amd64_load_context;
> + pfm_amd64_pmu_info.unload_context = pfm_amd64_unload_context;
> +
> + pfm_amd64_pmu_conf.pmc_write_check = pfm_amd64_pmc_write_check;
> +
> + PFM_INFO("NorthBridge event access control enabled");
> +
> + return 0;
> +}
> +
> +static int pfm_amd64_probe_pmu(void)
> +{
> + if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) {
> + PFM_INFO("not an AMD processor");
> + return -1;
> + }
> +
> + switch (current_cpu_data.x86) {
> + case 15:
> + case 16:
> + PFM_INFO("found family=%d", current_cpu_data.x86);
> + break;
> + default:
> + PFM_INFO("unsupported family=%d", current_cpu_data.x86);
> + return -1;
> + }
> +
> + /*
> + * check for local APIC (required)
> + */
> + if (!cpu_has_apic) {
> + PFM_INFO("no local APIC, unsupported");
> + return -1;
> + }
> +
> + if (current_cpu_data.x86_max_cores > 1)
> + return pfm_amd64_setup_nb_event_control();
> +
> + PFM_INFO("nmi_watchdog=%d nmi_active=%d force_nmi=%d",
> + nmi_watchdog, atomic_read(&nmi_active), force_nmi);
> + /*
> + * NMI using PMU?
> + * Actual removal of NMI counter is done by pfm_pmu_acquire()
> + */
> + if (nmi_watchdog == NMI_LOCAL_APIC || force_nmi)
> + pfm_amd64_pmu_info.flags |= PFM_X86_FL_USE_NMI;
> +
> + return 0;
> +}
> +
> +static struct pfm_pmu_config pfm_amd64_pmu_conf = {
> + .pmu_name = "AMD64",
> + .counter_width = 47,
> + .pmd_desc = pfm_amd64_pmd_desc,
> + .pmc_desc = pfm_amd64_pmc_desc,
> + .num_pmc_entries = PFM_AMD_NUM_PMCS,
> + .num_pmd_entries = PFM_AMD_NUM_PMDS,
> + .probe_pmu = pfm_amd64_probe_pmu,
> + .version = "1.1",
> + .arch_info = &pfm_amd64_pmu_info,
> + .flags = PFM_PMU_BUILTIN_FLAG,
> + .owner = THIS_MODULE
> +};
> +
> +static int __init pfm_amd64_pmu_init_module(void)
> +{
> + return pfm_pmu_register(&pfm_amd64_pmu_conf);
> +}
> +
> +static void __exit pfm_amd64_pmu_cleanup_module(void)
> +{
> + if (pfm_nb_sys_owners)
> + vfree(pfm_nb_sys_owners);
> +
> + pfm_pmu_unregister(&pfm_amd64_pmu_conf);
> +}
> +
> +module_init(pfm_amd64_pmu_init_module);
> +module_exit(pfm_amd64_pmu_cleanup_module);
> Index: linux-2.6.22-rc4/arch/x86_64/perfmon/perfmon_k8.c
> ===================================================================
> --- linux-2.6.22-rc4.orig/arch/x86_64/perfmon/perfmon_k8.c
> +++ /dev/null
> @@ -1,341 +0,0 @@
> -/*
> - * This file contains the PMU description for the Athlon64 and Opteron64
> - * processors. It supports 32 and 64-bit modes.
> - *
> - * Copyright (c) 2005-2007 Hewlett-Packard Development Company, L.P.
> - * Contributed by Stephane Eranian <[EMAIL PROTECTED]>
> - *
> - * 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.h>
> -#include <linux/vmalloc.h>
> -#include <asm/nmi.h>
> -
> -MODULE_AUTHOR("Stephane Eranian <[EMAIL PROTECTED]>");
> -MODULE_DESCRIPTION("AMD64 PMU description table");
> -MODULE_LICENSE("GPL");
> -
> -static int force_nmi;
> -MODULE_PARM_DESC(force_nmi, "bool: force use of NMI for PMU interrupt");
> -module_param(force_nmi, bool, 0600);
> -
> -static struct pfm_arch_pmu_info pfm_amd64_pmu_info = {
> - .pmc_addrs = {
> -/* pmc0 */ {{MSR_K7_EVNTSEL0, 0}, 0, PFM_REGT_EN},
> -/* pmc1 */ {{MSR_K7_EVNTSEL1, 0}, 1, PFM_REGT_EN},
> -/* pmc2 */ {{MSR_K7_EVNTSEL2, 0}, 2, PFM_REGT_EN},
> -/* pmc3 */ {{MSR_K7_EVNTSEL3, 0}, 3, PFM_REGT_EN},
> - },
> - .pmd_addrs = {
> -/* pmd0 */ {{MSR_K7_PERFCTR0, 0}, 0, PFM_REGT_CTR},
> -/* pmd1 */ {{MSR_K7_PERFCTR1, 0}, 0, PFM_REGT_CTR},
> -/* pmd2 */ {{MSR_K7_PERFCTR2, 0}, 0, PFM_REGT_CTR},
> -/* pmd3 */ {{MSR_K7_PERFCTR3, 0}, 0, PFM_REGT_CTR},
> - },
> - .pmu_style = PFM_X86_PMU_AMD64
> -};
> -
> -/*
> - * force Local APIC interrupt on overflow
> - */
> -#define PFM_K8_VAL (1ULL<<20)
> -#define PFM_K8_NO64 (1ULL<<20)
> -
> -/*
> - * reserved bits must be zero
> - *
> - * - upper 32 bits are reserved
> - * - APIC enable bit is reserved (forced to 1)
> - * - bit 21 is reserved
> - */
> -#define PFM_K8_RSVD ((~((1ULL<<32)-1)) \
> - | (1ULL<<20) \
> - | (1ULL<<21))
> -
> -static struct pfm_regmap_desc pfm_amd64_pmc_desc[] = {
> -/* pmc0 */ PMC_D(PFM_REG_I64, "PERFSEL0", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL0),
> -/* pmc1 */ PMC_D(PFM_REG_I64, "PERFSEL1", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL1),
> -/* pmc2 */ PMC_D(PFM_REG_I64, "PERFSEL2", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL2),
> -/* pmc3 */ PMC_D(PFM_REG_I64, "PERFSEL3", PFM_K8_VAL, PFM_K8_RSVD,
> PFM_K8_NO64, MSR_K7_EVNTSEL3),
> -};
> -#define PFM_AMD_NUM_PMCS ARRAY_SIZE(pfm_amd64_pmc_desc)
> -
> -static struct pfm_regmap_desc pfm_amd64_pmd_desc[] = {
> -/* pmd0 */ PMD_D(PFM_REG_C, "PERFCTR0", MSR_K7_PERFCTR0),
> -/* pmd1 */ PMD_D(PFM_REG_C, "PERFCTR1", MSR_K7_PERFCTR1),
> -/* pmd2 */ PMD_D(PFM_REG_C, "PERFCTR2", MSR_K7_PERFCTR2),
> -/* pmd3 */ PMD_D(PFM_REG_C, "PERFCTR3", MSR_K7_PERFCTR3)
> -};
> -#define PFM_AMD_NUM_PMDS ARRAY_SIZE(pfm_amd64_pmd_desc)
> -
> -static struct pfm_context **pfm_nb_sys_owners;
> -static struct pfm_context *pfm_nb_task_owner;
> -
> -static struct pfm_pmu_config pfm_amd64_pmu_conf;
> -
> -/*
> - * There can only be one user per socket for the Northbridge (NB) events,
> - * so we enforce mutual exclusion as follows:
> - * - per-thread : only one context machine-wide can use NB events
> - * - system-wide: only one context per processor socket
> - *
> - * Exclusion is enforced at:
> - * - pfm_load_context()
> - * - pfm_write_pmcs() for attached contexts
> - *
> - * Exclusion is released at:
> - * - pfm_unload_context() or any calls that implicitely uses it
> - *
> - * return:
> - * 0 : successfully acquire NB access
> - * < 0: errno, failed to acquire NB access
> - */
> -static int pfm_amd64_acquire_nb(struct pfm_context *ctx)
> -{
> - struct pfm_context **entry, *old;
> - int proc_id;
> -
> -#ifdef CONFIG_SMP
> - proc_id = topology_physical_package_id(smp_processor_id());
> -#else
> - proc_id = 0;
> -#endif
> -
> - if (ctx->flags.system)
> - entry = &pfm_nb_sys_owners[proc_id];
> - else
> - entry = &pfm_nb_task_owner;
> -
> - old = cmpxchg(entry, NULL, ctx);
> - if (!old) {
> - if (ctx->flags.system)
> - PFM_DBG("acquired Northbridge event access on socket
> %u", proc_id);
> - else
> - PFM_DBG("acquired Northbridge event access globally");
> - } else if (old != ctx) {
> - if (ctx->flags.system)
> - PFM_DBG("NorthBridge event conflict on socket %u",
> proc_id);
> - else
> - PFM_DBG("global NorthBridge event conflict");
> - return -EBUSY;
> - }
> - return 0;
> -}
> -
> -/*
> - * invoked from pfm_write_pmcs() when pfm_nb_sys_owners is not NULL,i.e.,
> - * when we have detected a multi-core processor.
> - *
> - * context is locked, interrupts are masked
> - */
> -static int pfm_amd64_pmc_write_check(struct pfm_context *ctx,
> - struct pfm_event_set *set,
> - struct pfarg_pmc *req)
> -{
> - unsigned int event;
> - /*
> - * delay checking NB event until we load the context
> - */
> - if (ctx->state == PFM_CTX_UNLOADED)
> - return 0;
> -
> - /*
> - * check event is NB event
> - */
> - event = (unsigned int)(req->reg_value & 0xff);
> - if (event < 0xee)
> - return 0;
> -
> - return pfm_amd64_acquire_nb(ctx);
> -}
> -
> -/*
> - * invoked on pfm_load_context().
> - * context is locked, interrupts are masked
> - */
> -static int pfm_amd64_load_context(struct pfm_context *ctx)
> -{
> - struct pfm_event_set *set;
> - unsigned int i, n;
> -
> - /*
> - * scan all sets for NB events
> - */
> - list_for_each_entry(set, &ctx->list, list) {
> - n = set->nused_pmcs;
> - for (i = 0; n; i++) {
> - if (!test_bit(i, cast_ulp(set->used_pmcs)))
> - continue;
> - if ((set->pmcs[i] & 0xff) >= 0xee)
> - goto found;
> - n--;
> - }
> - }
> - return 0;
> -found:
> - return pfm_amd64_acquire_nb(ctx);
> -}
> -
> -/*
> - * invoked on pfm_unload_context()
> - */
> -static int pfm_amd64_unload_context(struct pfm_context *ctx)
> -{
> - struct pfm_context **entry, *old;
> - int proc_id;
> -
> -#ifdef CONFIG_SMP
> - proc_id = topology_physical_package_id(smp_processor_id());
> -#else
> - proc_id = 0;
> -#endif
> -
> - /*
> - * unload always happens on the monitored CPU in system-wide
> - */
> - if (ctx->flags.system)
> - entry = &pfm_nb_sys_owners[proc_id];
> - else
> - entry = &pfm_nb_task_owner;
> -
> - old = cmpxchg(entry, ctx, NULL);
> - if (old == ctx) {
> - if (ctx->flags.system)
> - PFM_DBG("released NorthBridge on socket %u", proc_id);
> - else
> - PFM_DBG("released NorthBridge events globally");
> - }
> - return 0;
> -}
> -
> -/*
> - * detect if we need to active NorthBridge event access control
> - */
> -static int pfm_amd64_setup_nb_event_control(void)
> -{
> - unsigned int c, n = 0;
> - unsigned int max_phys = 0;
> -
> -#ifdef CONFIG_SMP
> - for_each_possible_cpu(c) {
> - if (cpu_data[c].phys_proc_id > max_phys)
> - max_phys = cpu_data[c].phys_proc_id;
> - }
> -#else
> - max_phys = 0;
> -#endif
> - if (max_phys > 255) {
> - PFM_INFO("socket id %d is too big to handle", max_phys);
> - return -ENOMEM;
> - }
> -
> - n = max_phys + 1;
> - if (n < 2)
> - return 0;
> -
> - pfm_nb_sys_owners = vmalloc(n * sizeof(*pfm_nb_sys_owners));
> - if (!pfm_nb_sys_owners)
> - return -ENOMEM;
> -
> - memset(pfm_nb_sys_owners, 0, n * sizeof(*pfm_nb_sys_owners));
> - pfm_nb_task_owner = NULL;
> -
> - /*
> - * activate write-checker for PMC registers
> - */
> - for (c = 0; c < PFM_AMD_NUM_PMCS; c++) {
> - pfm_amd64_pmc_desc[c].type |= PFM_REG_WC;
> - }
> -
> - pfm_amd64_pmu_info.load_context = pfm_amd64_load_context;
> - pfm_amd64_pmu_info.unload_context = pfm_amd64_unload_context;
> -
> - pfm_amd64_pmu_conf.pmc_write_check = pfm_amd64_pmc_write_check;
> -
> - PFM_INFO("NorthBridge event access control enabled");
> -
> - return 0;
> -}
> -
> -static int pfm_amd64_probe_pmu(void)
> -{
> - if (current_cpu_data.x86_vendor != X86_VENDOR_AMD) {
> - PFM_INFO("not an AMD processor");
> - return -1;
> - }
> -
> - switch (current_cpu_data.x86) {
> - case 15:
> - case 16:
> - PFM_INFO("found family=%d", current_cpu_data.x86);
> - break;
> - default:
> - PFM_INFO("unsupported family=%d", current_cpu_data.x86);
> - return -1;
> - }
> -
> - /*
> - * check for local APIC (required)
> - */
> - if (!cpu_has_apic) {
> - PFM_INFO("no local APIC, unsupported");
> - return -1;
> - }
> -
> - if (current_cpu_data.x86_max_cores > 1)
> - return pfm_amd64_setup_nb_event_control();
> -
> - PFM_INFO("nmi_watchdog=%d nmi_active=%d force_nmi=%d",
> - nmi_watchdog, atomic_read(&nmi_active), force_nmi);
> - /*
> - * NMI using PMU?
> - * Actual removal of NMI counter is done by pfm_pmu_acquire()
> - */
> - if (nmi_watchdog == NMI_LOCAL_APIC || force_nmi)
> - pfm_amd64_pmu_info.flags |= PFM_X86_FL_USE_NMI;
> -
> - return 0;
> -}
> -
> -static struct pfm_pmu_config pfm_amd64_pmu_conf = {
> - .pmu_name = "AMD64",
> - .counter_width = 47,
> - .pmd_desc = pfm_amd64_pmd_desc,
> - .pmc_desc = pfm_amd64_pmc_desc,
> - .num_pmc_entries = PFM_AMD_NUM_PMCS,
> - .num_pmd_entries = PFM_AMD_NUM_PMDS,
> - .probe_pmu = pfm_amd64_probe_pmu,
> - .version = "1.1",
> - .arch_info = &pfm_amd64_pmu_info,
> - .flags = PFM_PMU_BUILTIN_FLAG,
> - .owner = THIS_MODULE
> -};
> -
> -static int __init pfm_amd64_pmu_init_module(void)
> -{
> - return pfm_pmu_register(&pfm_amd64_pmu_conf);
> -}
> -
> -static void __exit pfm_amd64_pmu_cleanup_module(void)
> -{
> - if (pfm_nb_sys_owners)
> - vfree(pfm_nb_sys_owners);
> -
> - pfm_pmu_unregister(&pfm_amd64_pmu_conf);
> -}
> -
> -module_init(pfm_amd64_pmu_init_module);
> -module_exit(pfm_amd64_pmu_cleanup_module);
>
> --
> AMD Saxony, Dresden, Germany
> Operating System Research Center
> email: [EMAIL PROTECTED]
>
>
>
> _______________________________________________
> perfmon mailing list
> [email protected]
> http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/
--
-Stephane
_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/