Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133546959
D21553.id64056.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
3 KB
Referenced Files
None
Subscribers
None
D21553.id64056.diff
View Options
Index: head/sys/dev/hwpmc/hwpmc_amd.h
===================================================================
--- head/sys/dev/hwpmc/hwpmc_amd.h
+++ head/sys/dev/hwpmc/hwpmc_amd.h
@@ -76,6 +76,7 @@
#define AMD_PMC_PERFCTR_EP_DF_3 0xC0010247
#define AMD_NPMCS 16
+#define AMD_CORE_NPMCS 6
#define AMD_PMC_COUNTERMASK 0xFF000000
Index: head/sys/dev/hwpmc/hwpmc_amd.c
===================================================================
--- head/sys/dev/hwpmc/hwpmc_amd.c
+++ head/sys/dev/hwpmc/hwpmc_amd.c
@@ -39,6 +39,7 @@
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
+#include <sys/pcpu.h>
#include <sys/pmc.h>
#include <sys/pmckern.h>
#include <sys/smp.h>
@@ -53,6 +54,10 @@
enum pmc_class amd_pmc_class;
#endif
+#define OVERFLOW_WAIT_COUNT 50
+
+DPCPU_DEFINE_STATIC(uint32_t, nmi_counter);
+
/* AMD K7 & K8 PMCs */
struct amd_descr {
struct pmc_descr pm_descr; /* "base class" */
@@ -739,6 +744,7 @@
struct pmc_hw *phw;
const struct amd_descr *pd;
uint64_t config;
+ int i;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
("[amd,%d] illegal CPU value %d", __LINE__, cpu));
@@ -761,6 +767,21 @@
/* turn off the PMC ENABLE bit */
config = pm->pm_md.pm_amd.pm_amd_evsel & ~AMD_PMC_ENABLE;
wrmsr(pd->pm_evsel, config);
+
+ /*
+ * Due to NMI latency on newer AMD processors
+ * NMI interrupts are ignored, which leads to
+ * panic or messages based on kernel configuraiton
+ */
+
+ /* Wait for the count to be reset */
+ for (i = 0; i < OVERFLOW_WAIT_COUNT; i++) {
+ if (rdmsr(pd->pm_perfctr) & (1 << (pd->pm_descr.pd_width - 1)))
+ break;
+
+ DELAY(1);
+ }
+
return 0;
}
@@ -779,6 +800,7 @@
struct pmc *pm;
struct amd_cpu *pac;
pmc_value_t v;
+ uint32_t active = 0, count = 0;
cpu = curcpu;
KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
@@ -798,19 +820,21 @@
*
* If found, we call a helper to process the interrupt.
*
- * If multiple PMCs interrupt at the same time, the AMD64
- * processor appears to deliver as many NMIs as there are
- * outstanding PMC interrupts. So we process only one NMI
- * interrupt at a time.
+ * PMCs interrupting at the same time are collapsed into
+ * a single interrupt. Check all the valid pmcs for
+ * overflow.
*/
- for (i = 0; retval == 0 && i < AMD_NPMCS; i++) {
+ for (i = 0; i < AMD_CORE_NPMCS; i++) {
if ((pm = pac->pc_amdpmcs[i].phw_pmc) == NULL ||
!PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
continue;
}
+ /* Consider pmc with valid handle as active */
+ active++;
+
if (!AMD_PMC_HAS_OVERFLOWED(i))
continue;
@@ -820,8 +844,8 @@
continue;
/* Stop the PMC, reload count. */
- evsel = AMD_PMC_EVSEL_0 + i;
- perfctr = AMD_PMC_PERFCTR_0 + i;
+ evsel = amd_pmcdesc[i].pm_evsel;
+ perfctr = amd_pmcdesc[i].pm_perfctr;
v = pm->pm_sc.pm_reloadcount;
config = rdmsr(evsel);
@@ -837,6 +861,26 @@
error = pmc_process_interrupt(PMC_HR, pm, tf);
if (error == 0)
wrmsr(evsel, config);
+ }
+
+ /*
+ * Due to NMI latency, there can be a scenario in which
+ * multiple pmcs gets serviced in an earlier NMI and we
+ * do not find an overflow in the subsequent NMI.
+ *
+ * For such cases we keep a per-cpu count of active NMIs
+ * and compare it with min(active pmcs, 2) to determine
+ * if this NMI was for a pmc overflow which was serviced
+ * in an earlier request or should be ignored.
+ */
+
+ if (retval) {
+ DPCPU_SET(nmi_counter, min(2, active));
+ } else {
+ if ((count = DPCPU_GET(nmi_counter))) {
+ retval = 1;
+ DPCPU_SET(nmi_counter, --count);
+ }
}
if (retval)
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Oct 27, 1:56 PM (20 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24297583
Default Alt Text
D21553.id64056.diff (3 KB)
Attached To
Mode
D21553: hwpmc : fix perf counter MSR access
Attached
Detach File
Event Timeline
Log In to Comment