Commit 506e70d1 authored by Michael Neuling's avatar Michael Neuling Committed by Benjamin Herrenschmidt

powerpc/pmu: Fix order of interpreting BHRB target entries

The current Branch History Rolling Buffer (BHRB) code misinterprets the order
of entries in the hardware buffer.  It assumes that a branch target address
will be read _after_ its corresponding branch.  In reality the branch target
comes before (lower mfbhrb entry) it's corresponding branch.

This is a rewrite of the code to take this into account.
Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent d52f2dc4
...@@ -363,72 +363,75 @@ void power_pmu_flush_branch_stack(void) ...@@ -363,72 +363,75 @@ void power_pmu_flush_branch_stack(void)
power_pmu_bhrb_reset(); power_pmu_bhrb_reset();
} }
/* Processing BHRB entries */ /* Processing BHRB entries */
static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
{ {
u64 val; u64 val;
u64 addr; u64 addr;
int r_index, u_index, target, pred; int r_index, u_index, pred;
r_index = 0; r_index = 0;
u_index = 0; u_index = 0;
while (r_index < ppmu->bhrb_nr) { while (r_index < ppmu->bhrb_nr) {
/* Assembly read function */ /* Assembly read function */
val = read_bhrb(r_index); val = read_bhrb(r_index++);
if (!val)
/* Terminal marker: End of valid BHRB entries */ /* Terminal marker: End of valid BHRB entries */
if (val == 0) {
break; break;
} else { else {
/* BHRB field break up */
addr = val & BHRB_EA; addr = val & BHRB_EA;
pred = val & BHRB_PREDICTION; pred = val & BHRB_PREDICTION;
target = val & BHRB_TARGET;
/* Probable Missed entry: Not applicable for POWER8 */ if (!addr)
if ((addr == 0) && (target == 0) && (pred == 1)) { /* invalid entry */
r_index++;
continue; continue;
}
/* Real Missed entry: Power8 based missed entry */ /* Branches are read most recent first (ie. mfbhrb 0 is
if ((addr == 0) && (target == 1) && (pred == 1)) { * the most recent branch).
r_index++; * There are two types of valid entries:
continue; * 1) a target entry which is the to address of a
} * computed goto like a blr,bctr,btar. The next
* entry read from the bhrb will be branch
* corresponding to this target (ie. the actual
* blr/bctr/btar instruction).
* 2) a from address which is an actual branch. If a
* target entry proceeds this, then this is the
* matching branch for that target. If this is not
* following a target entry, then this is a branch
* where the target is given as an immediate field
* in the instruction (ie. an i or b form branch).
* In this case we need to read the instruction from
* memory to determine the target/to address.
*/
/* Reserved condition: Not a valid entry */ if (val & BHRB_TARGET) {
if ((addr == 0) && (target == 1) && (pred == 0)) { /* Target branches use two entries
r_index++; * (ie. computed gotos/XL form)
continue; */
} cpuhw->bhrb_entries[u_index].to = addr;
cpuhw->bhrb_entries[u_index].mispred = pred;
cpuhw->bhrb_entries[u_index].predicted = ~pred;
/* Is a target address */ /* Get from address in next entry */
val = read_bhrb(r_index++);
addr = val & BHRB_EA;
if (val & BHRB_TARGET) { if (val & BHRB_TARGET) {
/* First address cannot be a target address */ /* Shouldn't have two targets in a
if (r_index == 0) { row.. Reset index and try again */
r_index++; r_index--;
continue; addr = 0;
} }
cpuhw->bhrb_entries[u_index].from = addr;
/* Update target address for the previous entry */
cpuhw->bhrb_entries[u_index - 1].to = addr;
cpuhw->bhrb_entries[u_index - 1].mispred = pred;
cpuhw->bhrb_entries[u_index - 1].predicted = ~pred;
/* Dont increment u_index */
r_index++;
} else { } else {
/* Update address, flags for current entry */ /* Branches to immediate field
(ie I or B form) */
cpuhw->bhrb_entries[u_index].from = addr; cpuhw->bhrb_entries[u_index].from = addr;
cpuhw->bhrb_entries[u_index].to = 0;
cpuhw->bhrb_entries[u_index].mispred = pred; cpuhw->bhrb_entries[u_index].mispred = pred;
cpuhw->bhrb_entries[u_index].predicted = ~pred; cpuhw->bhrb_entries[u_index].predicted = ~pred;
/* Successfully popullated one entry */
u_index++;
r_index++;
} }
u_index++;
} }
} }
cpuhw->bhrb_stack.nr = u_index; cpuhw->bhrb_stack.nr = u_index;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment