summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/local_apic.c86
-rw-r--r--sys/amd64/include/apicvar.h3
-rw-r--r--sys/amd64/include/pmc_mdep.h1
-rw-r--r--sys/dev/hwpmc/hwpmc_core.c7
-rw-r--r--sys/dev/hwpmc/hwpmc_piv.c5
-rw-r--r--sys/dev/hwpmc/hwpmc_ppro.c5
-rw-r--r--sys/dev/hwpmc/hwpmc_x86.c22
-rw-r--r--sys/i386/i386/local_apic.c86
-rw-r--r--sys/i386/include/apicvar.h3
-rw-r--r--sys/i386/include/pmc_mdep.h1
10 files changed, 191 insertions, 28 deletions
diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c
index cd3073c..13bd774 100644
--- a/sys/amd64/amd64/local_apic.c
+++ b/sys/amd64/amd64/local_apic.c
@@ -123,7 +123,7 @@ static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
- { 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
+ { 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
@@ -305,11 +305,9 @@ lapic_setup(int boot)
lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
-#ifdef HWPMC_HOOKS
/* Program the PMC LVT entry if present. */
if (maxlvt >= LVT_PMC)
lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
-#endif
/* Program timer LVT and setup handler. */
lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
@@ -332,6 +330,88 @@ lapic_setup(int boot)
intr_restore(eflags);
}
+void
+lapic_reenable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ uint32_t value;
+
+ value = lapic->lvt_pcint;
+ value &= ~APIC_LVT_M;
+ lapic->lvt_pcint = value;
+#endif
+}
+
+#ifdef HWPMC_HOOKS
+static void
+lapic_update_pmc(void *dummy)
+{
+ struct lapic *la;
+
+ la = &lapics[lapic_id()];
+ lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
+}
+#endif
+
+int
+lapic_enable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ u_int32_t maxlvt;
+
+ /* Fail if the local APIC is not present. */
+ if (lapic == NULL)
+ return (0);
+
+ /* Fail if the PMC LVT is not present. */
+ maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
+ if (maxlvt < LVT_PMC)
+ return (0);
+
+ lvts[LVT_PMC].lvt_masked = 0;
+
+#ifdef SMP
+ /*
+ * If hwpmc was loaded at boot time then the APs may not be
+ * started yet. In that case, don't forward the request to
+ * them as they will program the lvt when they start.
+ */
+ if (smp_started)
+ smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
+ else
+#endif
+ lapic_update_pmc(NULL);
+ return (1);
+#else
+ return (0);
+#endif
+}
+
+void
+lapic_disable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ u_int32_t maxlvt;
+
+ /* Fail if the local APIC is not present. */
+ if (lapic == NULL)
+ return;
+
+ /* Fail if the PMC LVT is not present. */
+ maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
+ if (maxlvt < LVT_PMC)
+ return;
+
+ lvts[LVT_PMC].lvt_masked = 1;
+
+#ifdef SMP
+ /* The APs should always be started when hwpmc is unloaded. */
+ KASSERT(mp_ncpus == 1 || smp_started, ("hwpmc unloaded too early"));
+#endif
+ smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
+#endif
+}
+
/*
* Called by cpu_initclocks() on the BSP to setup the local APIC timer so
* that it can drive hardclock, statclock, and profclock. This function
diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h
index 73fff6c..9d6d538 100644
--- a/sys/amd64/include/apicvar.h
+++ b/sys/amd64/include/apicvar.h
@@ -201,7 +201,9 @@ int ioapic_set_triggermode(void *cookie, u_int pin,
int ioapic_set_smi(void *cookie, u_int pin);
void lapic_create(u_int apic_id, int boot_cpu);
void lapic_disable(void);
+void lapic_disable_pmc(void);
void lapic_dump(const char *str);
+int lapic_enable_pmc(void);
void lapic_eoi(void);
u_int lapic_error(void);
int lapic_id(void);
@@ -212,6 +214,7 @@ void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
+void lapic_reenable_pmc(void);
void lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id);
int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked);
int lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode);
diff --git a/sys/amd64/include/pmc_mdep.h b/sys/amd64/include/pmc_mdep.h
index f8c26f2..f233a51 100644
--- a/sys/amd64/include/pmc_mdep.h
+++ b/sys/amd64/include/pmc_mdep.h
@@ -115,7 +115,6 @@ union pmc_md_pmc {
*/
void start_exceptions(void), end_exceptions(void);
-void pmc_x86_lapic_enable_pmc_interrupt(void);
struct pmc_mdep *pmc_amd_initialize(void);
void pmc_amd_finalize(struct pmc_mdep *_md);
diff --git a/sys/dev/hwpmc/hwpmc_core.c b/sys/dev/hwpmc/hwpmc_core.c
index 214e42c..f84e0f1 100644
--- a/sys/dev/hwpmc/hwpmc_core.c
+++ b/sys/dev/hwpmc/hwpmc_core.c
@@ -32,10 +32,13 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/bus.h>
#include <sys/pmc.h>
#include <sys/pmckern.h>
#include <sys/systm.h>
+#include <machine/intr_machdep.h>
+#include <machine/apicvar.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
@@ -1771,7 +1774,7 @@ core_intr(int cpu, struct trapframe *tf)
}
if (found_interrupt)
- pmc_x86_lapic_enable_pmc_interrupt();
+ lapic_reenable_pmc();
atomic_add_int(found_interrupt ? &pmc_stats.pm_intr_processed :
&pmc_stats.pm_intr_ignored, 1);
@@ -1895,7 +1898,7 @@ core2_intr(int cpu, struct trapframe *tf)
(uintmax_t) rdmsr(IA_GLOBAL_OVF_CTRL));
if (found_interrupt)
- pmc_x86_lapic_enable_pmc_interrupt();
+ lapic_reenable_pmc();
atomic_add_int(found_interrupt ? &pmc_stats.pm_intr_processed :
&pmc_stats.pm_intr_ignored, 1);
diff --git a/sys/dev/hwpmc/hwpmc_piv.c b/sys/dev/hwpmc/hwpmc_piv.c
index 565be88..8ee8518 100644
--- a/sys/dev/hwpmc/hwpmc_piv.c
+++ b/sys/dev/hwpmc/hwpmc_piv.c
@@ -32,6 +32,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/pmc.h>
@@ -39,6 +40,8 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <sys/systm.h>
+#include <machine/intr_machdep.h>
+#include <machine/apicvar.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/cputypes.h>
@@ -1537,7 +1540,7 @@ p4_intr(int cpu, struct trapframe *tf)
*/
if (did_interrupt)
- pmc_x86_lapic_enable_pmc_interrupt();
+ lapic_reenable_pmc();
atomic_add_int(did_interrupt ? &pmc_stats.pm_intr_processed :
&pmc_stats.pm_intr_ignored, 1);
diff --git a/sys/dev/hwpmc/hwpmc_ppro.c b/sys/dev/hwpmc/hwpmc_ppro.c
index 909bfe2..8da185b 100644
--- a/sys/dev/hwpmc/hwpmc_ppro.c
+++ b/sys/dev/hwpmc/hwpmc_ppro.c
@@ -32,6 +32,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/bus.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/pmc.h>
@@ -39,6 +40,8 @@ __FBSDID("$FreeBSD$");
#include <sys/smp.h>
#include <sys/systm.h>
+#include <machine/intr_machdep.h>
+#include <machine/apicvar.h>
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/cputypes.h>
@@ -718,7 +721,7 @@ p6_intr(int cpu, struct trapframe *tf)
* unmasked after a PMC interrupt.
*/
if (retval)
- pmc_x86_lapic_enable_pmc_interrupt();
+ lapic_reenable_pmc();
atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
&pmc_stats.pm_intr_ignored, 1);
diff --git a/sys/dev/hwpmc/hwpmc_x86.c b/sys/dev/hwpmc/hwpmc_x86.c
index b48a6b0..09d04bb 100644
--- a/sys/dev/hwpmc/hwpmc_x86.c
+++ b/sys/dev/hwpmc/hwpmc_x86.c
@@ -39,7 +39,8 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#include <machine/cputypes.h>
-#include <machine/apicreg.h>
+#include <machine/intr_machdep.h>
+#include <machine/apicvar.h>
#include <machine/pmc_mdep.h>
#include <machine/md_var.h>
@@ -47,18 +48,6 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_param.h>
#include <vm/pmap.h>
-extern volatile lapic_t *lapic;
-
-void
-pmc_x86_lapic_enable_pmc_interrupt(void)
-{
- uint32_t value;
-
- value = lapic->lvt_pcint;
- value &= ~APIC_LVT_M;
- lapic->lvt_pcint = value;
-}
-
/*
* Attempt to walk a user call stack using a too-simple algorithm.
* In the general case we need unwind information associated with
@@ -252,16 +241,15 @@ pmc_md_initialize()
struct pmc_mdep *md;
/* determine the CPU kind */
- md = NULL;
if (cpu_vendor_id == CPU_VENDOR_AMD)
md = pmc_amd_initialize();
else if (cpu_vendor_id == CPU_VENDOR_INTEL)
md = pmc_intel_initialize();
else
- KASSERT(0, ("[x86,%d] Unknown vendor", __LINE__));
+ return (NULL);
/* disallow sampling if we do not have an LAPIC */
- if (md != NULL && lapic == NULL)
+ if (!lapic_enable_pmc())
for (i = 1; i < md->pmd_nclass; i++)
md->pmd_classdep[i].pcd_caps &= ~PMC_CAP_INTERRUPT;
@@ -271,6 +259,8 @@ pmc_md_initialize()
void
pmc_md_finalize(struct pmc_mdep *md)
{
+
+ lapic_disable_pmc();
if (cpu_vendor_id == CPU_VENDOR_AMD)
pmc_amd_finalize(md);
else if (cpu_vendor_id == CPU_VENDOR_INTEL)
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 2cc6a45..5e79aa8 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -123,7 +123,7 @@ static struct lvt lvts[LVT_MAX + 1] = {
{ 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* LINT1: NMI */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_TIMER_INT }, /* Timer */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_ERROR_INT }, /* Error */
- { 1, 1, 0, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
+ { 1, 1, 1, 1, APIC_LVT_DM_NMI, 0 }, /* PMC */
{ 1, 1, 1, 1, APIC_LVT_DM_FIXED, APIC_THERMAL_INT }, /* Thermal */
};
@@ -307,11 +307,9 @@ lapic_setup(int boot)
lapic->lvt_lint0 = lvt_mode(la, LVT_LINT0, lapic->lvt_lint0);
lapic->lvt_lint1 = lvt_mode(la, LVT_LINT1, lapic->lvt_lint1);
-#ifdef HWPMC_HOOKS
/* Program the PMC LVT entry if present. */
if (maxlvt >= LVT_PMC)
lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
-#endif
/* Program timer LVT and setup handler. */
lapic->lvt_timer = lvt_mode(la, LVT_TIMER, lapic->lvt_timer);
@@ -334,6 +332,88 @@ lapic_setup(int boot)
intr_restore(eflags);
}
+void
+lapic_reenable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ uint32_t value;
+
+ value = lapic->lvt_pcint;
+ value &= ~APIC_LVT_M;
+ lapic->lvt_pcint = value;
+#endif
+}
+
+#ifdef HWPMC_HOOKS
+static void
+lapic_update_pmc(void *dummy)
+{
+ struct lapic *la;
+
+ la = &lapics[lapic_id()];
+ lapic->lvt_pcint = lvt_mode(la, LVT_PMC, lapic->lvt_pcint);
+}
+#endif
+
+int
+lapic_enable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ u_int32_t maxlvt;
+
+ /* Fail if the local APIC is not present. */
+ if (lapic == NULL)
+ return (0);
+
+ /* Fail if the PMC LVT is not present. */
+ maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
+ if (maxlvt < LVT_PMC)
+ return (0);
+
+ lvts[LVT_PMC].lvt_masked = 0;
+
+#ifdef SMP
+ /*
+ * If hwpmc was loaded at boot time then the APs may not be
+ * started yet. In that case, don't forward the request to
+ * them as they will program the lvt when they start.
+ */
+ if (smp_started)
+ smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
+ else
+#endif
+ lapic_update_pmc(NULL);
+ return (1);
+#else
+ return (0);
+#endif
+}
+
+void
+lapic_disable_pmc(void)
+{
+#ifdef HWPMC_HOOKS
+ u_int32_t maxlvt;
+
+ /* Fail if the local APIC is not present. */
+ if (lapic == NULL)
+ return;
+
+ /* Fail if the PMC LVT is not present. */
+ maxlvt = (lapic->version & APIC_VER_MAXLVT) >> MAXLVTSHIFT;
+ if (maxlvt < LVT_PMC)
+ return;
+
+ lvts[LVT_PMC].lvt_masked = 1;
+
+#ifdef SMP
+ /* The APs should always be started when hwpmc is unloaded. */
+ KASSERT(mp_ncpus == 1 || smp_started, ("hwpmc unloaded too early"));
+#endif
+ smp_rendezvous(NULL, lapic_update_pmc, NULL, NULL);
+#endif
+}
+
/*
* Called by cpu_initclocks() on the BSP to setup the local APIC timer so
* that it can drive hardclock, statclock, and profclock. This function
diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h
index a13766f..b15452b 100644
--- a/sys/i386/include/apicvar.h
+++ b/sys/i386/include/apicvar.h
@@ -230,7 +230,9 @@ int ioapic_set_triggermode(void *cookie, u_int pin,
int ioapic_set_smi(void *cookie, u_int pin);
void lapic_create(u_int apic_id, int boot_cpu);
void lapic_disable(void);
+void lapic_disable_pmc(void);
void lapic_dump(const char *str);
+int lapic_enable_pmc(void);
void lapic_eoi(void);
u_int lapic_error(void);
int lapic_id(void);
@@ -241,6 +243,7 @@ void lapic_ipi_vectored(u_int vector, int dest);
int lapic_ipi_wait(int delay);
void lapic_handle_intr(int vector, struct trapframe *frame);
void lapic_handle_timer(struct trapframe *frame);
+void lapic_reenable_pmc(void);
void lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id);
int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked);
int lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode);
diff --git a/sys/i386/include/pmc_mdep.h b/sys/i386/include/pmc_mdep.h
index 63d5f8b..4389a20 100644
--- a/sys/i386/include/pmc_mdep.h
+++ b/sys/i386/include/pmc_mdep.h
@@ -150,7 +150,6 @@ struct pmc_mdep;
*/
void start_exceptions(void), end_exceptions(void);
-void pmc_x86_lapic_enable_pmc_interrupt(void);
struct pmc_mdep *pmc_amd_initialize(void);
void pmc_amd_finalize(struct pmc_mdep *_md);
OpenPOWER on IntegriCloud