aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/perf_event_server.h1
-rw-r--r--arch/powerpc/perf/core-book3s.c167
2 files changed, 165 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h
index 3f0c15c6f068..f265049dd7d6 100644
--- a/arch/powerpc/include/asm/perf_event_server.h
+++ b/arch/powerpc/include/asm/perf_event_server.h
@@ -73,6 +73,7 @@ extern int register_power_pmu(struct power_pmu *);
73struct pt_regs; 73struct pt_regs;
74extern unsigned long perf_misc_flags(struct pt_regs *regs); 74extern unsigned long perf_misc_flags(struct pt_regs *regs);
75extern unsigned long perf_instruction_pointer(struct pt_regs *regs); 75extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
76extern unsigned long int read_bhrb(int n);
76 77
77/* 78/*
78 * Only override the default definitions in include/linux/perf_event.h 79 * Only override the default definitions in include/linux/perf_event.h
diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c
index 4ac6e64a52ce..c627843c5b2e 100644
--- a/arch/powerpc/perf/core-book3s.c
+++ b/arch/powerpc/perf/core-book3s.c
@@ -19,6 +19,11 @@
19#include <asm/firmware.h> 19#include <asm/firmware.h>
20#include <asm/ptrace.h> 20#include <asm/ptrace.h>
21 21
22#define BHRB_MAX_ENTRIES 32
23#define BHRB_TARGET 0x0000000000000002
24#define BHRB_PREDICTION 0x0000000000000001
25#define BHRB_EA 0xFFFFFFFFFFFFFFFC
26
22struct cpu_hw_events { 27struct cpu_hw_events {
23 int n_events; 28 int n_events;
24 int n_percpu; 29 int n_percpu;
@@ -38,7 +43,15 @@ struct cpu_hw_events {
38 43
39 unsigned int group_flag; 44 unsigned int group_flag;
40 int n_txn_start; 45 int n_txn_start;
46
47 /* BHRB bits */
48 u64 bhrb_filter; /* BHRB HW branch filter */
49 int bhrb_users;
50 void *bhrb_context;
51 struct perf_branch_stack bhrb_stack;
52 struct perf_branch_entry bhrb_entries[BHRB_MAX_ENTRIES];
41}; 53};
54
42DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); 55DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
43 56
44struct power_pmu *ppmu; 57struct power_pmu *ppmu;
@@ -858,6 +871,9 @@ static void power_pmu_enable(struct pmu *pmu)
858 } 871 }
859 872
860 out: 873 out:
874 if (cpuhw->bhrb_users)
875 ppmu->config_bhrb(cpuhw->bhrb_filter);
876
861 local_irq_restore(flags); 877 local_irq_restore(flags);
862} 878}
863 879
@@ -888,6 +904,47 @@ static int collect_events(struct perf_event *group, int max_count,
888 return n; 904 return n;
889} 905}
890 906
907/* Reset all possible BHRB entries */
908static void power_pmu_bhrb_reset(void)
909{
910 asm volatile(PPC_CLRBHRB);
911}
912
913void power_pmu_bhrb_enable(struct perf_event *event)
914{
915 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
916
917 if (!ppmu->bhrb_nr)
918 return;
919
920 /* Clear BHRB if we changed task context to avoid data leaks */
921 if (event->ctx->task && cpuhw->bhrb_context != event->ctx) {
922 power_pmu_bhrb_reset();
923 cpuhw->bhrb_context = event->ctx;
924 }
925 cpuhw->bhrb_users++;
926}
927
928void power_pmu_bhrb_disable(struct perf_event *event)
929{
930 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
931
932 if (!ppmu->bhrb_nr)
933 return;
934
935 cpuhw->bhrb_users--;
936 WARN_ON_ONCE(cpuhw->bhrb_users < 0);
937
938 if (!cpuhw->disabled && !cpuhw->bhrb_users) {
939 /* BHRB cannot be turned off when other
940 * events are active on the PMU.
941 */
942
943 /* avoid stale pointer */
944 cpuhw->bhrb_context = NULL;
945 }
946}
947
891/* 948/*
892 * Add a event to the PMU. 949 * Add a event to the PMU.
893 * If all events are not already frozen, then we disable and 950 * If all events are not already frozen, then we disable and
@@ -947,6 +1004,9 @@ nocheck:
947 1004
948 ret = 0; 1005 ret = 0;
949 out: 1006 out:
1007 if (has_branch_stack(event))
1008 power_pmu_bhrb_enable(event);
1009
950 perf_pmu_enable(event->pmu); 1010 perf_pmu_enable(event->pmu);
951 local_irq_restore(flags); 1011 local_irq_restore(flags);
952 return ret; 1012 return ret;
@@ -999,6 +1059,9 @@ static void power_pmu_del(struct perf_event *event, int ef_flags)
999 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE); 1059 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
1000 } 1060 }
1001 1061
1062 if (has_branch_stack(event))
1063 power_pmu_bhrb_disable(event);
1064
1002 perf_pmu_enable(event->pmu); 1065 perf_pmu_enable(event->pmu);
1003 local_irq_restore(flags); 1066 local_irq_restore(flags);
1004} 1067}
@@ -1117,6 +1180,15 @@ int power_pmu_commit_txn(struct pmu *pmu)
1117 return 0; 1180 return 0;
1118} 1181}
1119 1182
1183/* Called from ctxsw to prevent one process's branch entries to
1184 * mingle with the other process's entries during context switch.
1185 */
1186void power_pmu_flush_branch_stack(void)
1187{
1188 if (ppmu->bhrb_nr)
1189 power_pmu_bhrb_reset();
1190}
1191
1120/* 1192/*
1121 * Return 1 if we might be able to put event on a limited PMC, 1193 * Return 1 if we might be able to put event on a limited PMC,
1122 * or 0 if not. 1194 * or 0 if not.
@@ -1231,9 +1303,11 @@ static int power_pmu_event_init(struct perf_event *event)
1231 if (!ppmu) 1303 if (!ppmu)
1232 return -ENOENT; 1304 return -ENOENT;
1233 1305
1234 /* does not support taken branch sampling */ 1306 if (has_branch_stack(event)) {
1235 if (has_branch_stack(event)) 1307 /* PMU has BHRB enabled */
1236 return -EOPNOTSUPP; 1308 if (!(ppmu->flags & PPMU_BHRB))
1309 return -EOPNOTSUPP;
1310 }
1237 1311
1238 switch (event->attr.type) { 1312 switch (event->attr.type) {
1239 case PERF_TYPE_HARDWARE: 1313 case PERF_TYPE_HARDWARE:
@@ -1314,6 +1388,15 @@ static int power_pmu_event_init(struct perf_event *event)
1314 1388
1315 cpuhw = &get_cpu_var(cpu_hw_events); 1389 cpuhw = &get_cpu_var(cpu_hw_events);
1316 err = power_check_constraints(cpuhw, events, cflags, n + 1); 1390 err = power_check_constraints(cpuhw, events, cflags, n + 1);
1391
1392 if (has_branch_stack(event)) {
1393 cpuhw->bhrb_filter = ppmu->bhrb_filter_map(
1394 event->attr.branch_sample_type);
1395
1396 if(cpuhw->bhrb_filter == -1)
1397 return -EOPNOTSUPP;
1398 }
1399
1317 put_cpu_var(cpu_hw_events); 1400 put_cpu_var(cpu_hw_events);
1318 if (err) 1401 if (err)
1319 return -EINVAL; 1402 return -EINVAL;
@@ -1372,8 +1455,79 @@ struct pmu power_pmu = {
1372 .cancel_txn = power_pmu_cancel_txn, 1455 .cancel_txn = power_pmu_cancel_txn,
1373 .commit_txn = power_pmu_commit_txn, 1456 .commit_txn = power_pmu_commit_txn,
1374 .event_idx = power_pmu_event_idx, 1457 .event_idx = power_pmu_event_idx,
1458 .flush_branch_stack = power_pmu_flush_branch_stack,
1375}; 1459};
1376 1460
1461/* Processing BHRB entries */
1462void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw)
1463{
1464 u64 val;
1465 u64 addr;
1466 int r_index, u_index, target, pred;
1467
1468 r_index = 0;
1469 u_index = 0;
1470 while (r_index < ppmu->bhrb_nr) {
1471 /* Assembly read function */
1472 val = read_bhrb(r_index);
1473
1474 /* Terminal marker: End of valid BHRB entries */
1475 if (val == 0) {
1476 break;
1477 } else {
1478 /* BHRB field break up */
1479 addr = val & BHRB_EA;
1480 pred = val & BHRB_PREDICTION;
1481 target = val & BHRB_TARGET;
1482
1483 /* Probable Missed entry: Not applicable for POWER8 */
1484 if ((addr == 0) && (target == 0) && (pred == 1)) {
1485 r_index++;
1486 continue;
1487 }
1488
1489 /* Real Missed entry: Power8 based missed entry */
1490 if ((addr == 0) && (target == 1) && (pred == 1)) {
1491 r_index++;
1492 continue;
1493 }
1494
1495 /* Reserved condition: Not a valid entry */
1496 if ((addr == 0) && (target == 1) && (pred == 0)) {
1497 r_index++;
1498 continue;
1499 }
1500
1501 /* Is a target address */
1502 if (val & BHRB_TARGET) {
1503 /* First address cannot be a target address */
1504 if (r_index == 0) {
1505 r_index++;
1506 continue;
1507 }
1508
1509 /* Update target address for the previous entry */
1510 cpuhw->bhrb_entries[u_index - 1].to = addr;
1511 cpuhw->bhrb_entries[u_index - 1].mispred = pred;
1512 cpuhw->bhrb_entries[u_index - 1].predicted = ~pred;
1513
1514 /* Dont increment u_index */
1515 r_index++;
1516 } else {
1517 /* Update address, flags for current entry */
1518 cpuhw->bhrb_entries[u_index].from = addr;
1519 cpuhw->bhrb_entries[u_index].mispred = pred;
1520 cpuhw->bhrb_entries[u_index].predicted = ~pred;
1521
1522 /* Successfully popullated one entry */
1523 u_index++;
1524 r_index++;
1525 }
1526 }
1527 }
1528 cpuhw->bhrb_stack.nr = u_index;
1529 return;
1530}
1377 1531
1378/* 1532/*
1379 * A counter has overflowed; update its count and record 1533 * A counter has overflowed; update its count and record
@@ -1433,6 +1587,13 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
1433 if (event->attr.sample_type & PERF_SAMPLE_ADDR) 1587 if (event->attr.sample_type & PERF_SAMPLE_ADDR)
1434 perf_get_data_addr(regs, &data.addr); 1588 perf_get_data_addr(regs, &data.addr);
1435 1589
1590 if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) {
1591 struct cpu_hw_events *cpuhw;
1592 cpuhw = &__get_cpu_var(cpu_hw_events);
1593 power_pmu_bhrb_read(cpuhw);
1594 data.br_stack = &cpuhw->bhrb_stack;
1595 }
1596
1436 if (perf_event_overflow(event, &data, regs)) 1597 if (perf_event_overflow(event, &data, regs))
1437 power_pmu_stop(event, 0); 1598 power_pmu_stop(event, 0);
1438 } 1599 }