aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2014-02-07 16:01:23 -0500
committerWill Deacon <will.deacon@arm.com>2014-02-21 06:11:15 -0500
commitb7aafe9928beda2ed2c1a3035a1bed878f0cb2ab (patch)
tree9ed5e1472c7d55241eb99a6ce482045ccfa95b48
parenteab443ef391d18772710dc2c156f7ee05e51f754 (diff)
ARM: perf: fully support Krait CPU PMU events
Krait supports a set of performance monitor region event selection registers (PMRESR) sitting behind a cp15 based interface that extend the architected PMU events to include Krait CPU and Venum VFP specific events. To use these events the user is expected to program the region register (PMRESRn) with the event code shifted into the group they care about and then point the PMNx event at that region+group combo by writing a PMRESRn_GROUPx event. Add support for this hardware. Note: the raw event number is a pure software construct that allows us to map the multi-dimensional number space of regions, groups, and event codes into a flat event number space suitable for use by the perf framework. This is based on code originally written by Ashwin Chaugule and Neil Leeder [1]. [1] https://www.codeaurora.org/cgit/quic/la/kernel/msm/tree/arch/arm/kernel/perf_event_msm_krait.c?h=msm-3.4 Cc: Neil Leeder <nleeder@codeaurora.org> Cc: Ashwin Chaugule <ashwinc@codeaurora.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--arch/arm/kernel/perf_event_v7.c407
1 files changed, 401 insertions, 6 deletions
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 16386b1d27a8..2fce4751f4c0 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -18,6 +18,10 @@
18 18
19#ifdef CONFIG_CPU_V7 19#ifdef CONFIG_CPU_V7
20 20
21#include <asm/cp15.h>
22#include <asm/vfp.h>
23#include "../vfp/vfpinstr.h"
24
21/* 25/*
22 * Common ARMv7 event types 26 * Common ARMv7 event types
23 * 27 *
@@ -109,6 +113,20 @@ enum armv7_a15_perf_types {
109 ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76, 113 ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76,
110}; 114};
111 115
116/* ARMv7 Krait specific event types */
117enum krait_perf_types {
118 KRAIT_PMRESR0_GROUP0 = 0xcc,
119 KRAIT_PMRESR1_GROUP0 = 0xd0,
120 KRAIT_PMRESR2_GROUP0 = 0xd4,
121 KRAIT_VPMRESR0_GROUP0 = 0xd8,
122
123 KRAIT_PERFCTR_L1_ICACHE_ACCESS = 0x10011,
124 KRAIT_PERFCTR_L1_ICACHE_MISS = 0x10010,
125
126 KRAIT_PERFCTR_L1_ITLB_ACCESS = 0x12222,
127 KRAIT_PERFCTR_L1_DTLB_ACCESS = 0x12210,
128};
129
112/* 130/*
113 * Cortex-A8 HW events mapping 131 * Cortex-A8 HW events mapping
114 * 132 *
@@ -779,8 +797,8 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
779 }, 797 },
780 [C(L1I)] = { 798 [C(L1I)] = {
781 [C(OP_READ)] = { 799 [C(OP_READ)] = {
782 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 800 [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ICACHE_ACCESS,
783 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 801 [C(RESULT_MISS)] = KRAIT_PERFCTR_L1_ICACHE_MISS,
784 }, 802 },
785 [C(OP_WRITE)] = { 803 [C(OP_WRITE)] = {
786 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 804 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED,
@@ -807,11 +825,11 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
807 }, 825 },
808 [C(DTLB)] = { 826 [C(DTLB)] = {
809 [C(OP_READ)] = { 827 [C(OP_READ)] = {
810 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 828 [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS,
811 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 829 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
812 }, 830 },
813 [C(OP_WRITE)] = { 831 [C(OP_WRITE)] = {
814 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 832 [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_DTLB_ACCESS,
815 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 833 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
816 }, 834 },
817 [C(OP_PREFETCH)] = { 835 [C(OP_PREFETCH)] = {
@@ -821,11 +839,11 @@ static const unsigned krait_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
821 }, 839 },
822 [C(ITLB)] = { 840 [C(ITLB)] = {
823 [C(OP_READ)] = { 841 [C(OP_READ)] = {
824 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 842 [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS,
825 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 843 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
826 }, 844 },
827 [C(OP_WRITE)] = { 845 [C(OP_WRITE)] = {
828 [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, 846 [C(RESULT_ACCESS)] = KRAIT_PERFCTR_L1_ITLB_ACCESS,
829 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, 847 [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED,
830 }, 848 },
831 [C(OP_PREFETCH)] = { 849 [C(OP_PREFETCH)] = {
@@ -1428,6 +1446,378 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
1428 return 0; 1446 return 0;
1429} 1447}
1430 1448
1449/*
1450 * Krait Performance Monitor Region Event Selection Register (PMRESRn)
1451 *
1452 * 31 30 24 16 8 0
1453 * +--------------------------------+
1454 * PMRESR0 | EN | CC | CC | CC | CC | N = 1, R = 0
1455 * +--------------------------------+
1456 * PMRESR1 | EN | CC | CC | CC | CC | N = 1, R = 1
1457 * +--------------------------------+
1458 * PMRESR2 | EN | CC | CC | CC | CC | N = 1, R = 2
1459 * +--------------------------------+
1460 * VPMRESR0 | EN | CC | CC | CC | CC | N = 2, R = ?
1461 * +--------------------------------+
1462 * EN | G=3 | G=2 | G=1 | G=0
1463 *
1464 * Event Encoding:
1465 *
1466 * hwc->config_base = 0xNRCCG
1467 *
1468 * N = prefix, 1 for Krait CPU (PMRESRn), 2 for Venum VFP (VPMRESR)
1469 * R = region register
1470 * CC = class of events the group G is choosing from
1471 * G = group or particular event
1472 *
1473 * Example: 0x12021 is a Krait CPU event in PMRESR2's group 1 with code 2
1474 *
1475 * A region (R) corresponds to a piece of the CPU (execution unit, instruction
1476 * unit, etc.) while the event code (CC) corresponds to a particular class of
1477 * events (interrupts for example). An event code is broken down into
1478 * groups (G) that can be mapped into the PMU (irq, fiqs, and irq+fiqs for
1479 * example).
1480 */
1481
1482#define KRAIT_EVENT (1 << 16)
1483#define VENUM_EVENT (2 << 16)
1484#define KRAIT_EVENT_MASK (KRAIT_EVENT | VENUM_EVENT)
1485#define PMRESRn_EN BIT(31)
1486
1487static u32 krait_read_pmresrn(int n)
1488{
1489 u32 val;
1490
1491 switch (n) {
1492 case 0:
1493 asm volatile("mrc p15, 1, %0, c9, c15, 0" : "=r" (val));
1494 break;
1495 case 1:
1496 asm volatile("mrc p15, 1, %0, c9, c15, 1" : "=r" (val));
1497 break;
1498 case 2:
1499 asm volatile("mrc p15, 1, %0, c9, c15, 2" : "=r" (val));
1500 break;
1501 default:
1502 BUG(); /* Should be validated in krait_pmu_get_event_idx() */
1503 }
1504
1505 return val;
1506}
1507
1508static void krait_write_pmresrn(int n, u32 val)
1509{
1510 switch (n) {
1511 case 0:
1512 asm volatile("mcr p15, 1, %0, c9, c15, 0" : : "r" (val));
1513 break;
1514 case 1:
1515 asm volatile("mcr p15, 1, %0, c9, c15, 1" : : "r" (val));
1516 break;
1517 case 2:
1518 asm volatile("mcr p15, 1, %0, c9, c15, 2" : : "r" (val));
1519 break;
1520 default:
1521 BUG(); /* Should be validated in krait_pmu_get_event_idx() */
1522 }
1523}
1524
1525static u32 krait_read_vpmresr0(void)
1526{
1527 u32 val;
1528 asm volatile("mrc p10, 7, %0, c11, c0, 0" : "=r" (val));
1529 return val;
1530}
1531
1532static void krait_write_vpmresr0(u32 val)
1533{
1534 asm volatile("mcr p10, 7, %0, c11, c0, 0" : : "r" (val));
1535}
1536
1537static void krait_pre_vpmresr0(u32 *venum_orig_val, u32 *fp_orig_val)
1538{
1539 u32 venum_new_val;
1540 u32 fp_new_val;
1541
1542 BUG_ON(preemptible());
1543 /* CPACR Enable CP10 and CP11 access */
1544 *venum_orig_val = get_copro_access();
1545 venum_new_val = *venum_orig_val | CPACC_SVC(10) | CPACC_SVC(11);
1546 set_copro_access(venum_new_val);
1547
1548 /* Enable FPEXC */
1549 *fp_orig_val = fmrx(FPEXC);
1550 fp_new_val = *fp_orig_val | FPEXC_EN;
1551 fmxr(FPEXC, fp_new_val);
1552}
1553
1554static void krait_post_vpmresr0(u32 venum_orig_val, u32 fp_orig_val)
1555{
1556 BUG_ON(preemptible());
1557 /* Restore FPEXC */
1558 fmxr(FPEXC, fp_orig_val);
1559 isb();
1560 /* Restore CPACR */
1561 set_copro_access(venum_orig_val);
1562}
1563
1564static u32 krait_get_pmresrn_event(unsigned int region)
1565{
1566 static const u32 pmresrn_table[] = { KRAIT_PMRESR0_GROUP0,
1567 KRAIT_PMRESR1_GROUP0,
1568 KRAIT_PMRESR2_GROUP0 };
1569 return pmresrn_table[region];
1570}
1571
1572static void krait_evt_setup(int idx, u32 config_base)
1573{
1574 u32 val;
1575 u32 mask;
1576 u32 vval, fval;
1577 unsigned int region;
1578 unsigned int group;
1579 unsigned int code;
1580 unsigned int group_shift;
1581 bool venum_event;
1582
1583 venum_event = !!(config_base & VENUM_EVENT);
1584 region = (config_base >> 12) & 0xf;
1585 code = (config_base >> 4) & 0xff;
1586 group = (config_base >> 0) & 0xf;
1587
1588 group_shift = group * 8;
1589 mask = 0xff << group_shift;
1590
1591 /* Configure evtsel for the region and group */
1592 if (venum_event)
1593 val = KRAIT_VPMRESR0_GROUP0;
1594 else
1595 val = krait_get_pmresrn_event(region);
1596 val += group;
1597 /* Mix in mode-exclusion bits */
1598 val |= config_base & (ARMV7_EXCLUDE_USER | ARMV7_EXCLUDE_PL1);
1599 armv7_pmnc_write_evtsel(idx, val);
1600
1601 asm volatile("mcr p15, 0, %0, c9, c15, 0" : : "r" (0));
1602
1603 if (venum_event) {
1604 krait_pre_vpmresr0(&vval, &fval);
1605 val = krait_read_vpmresr0();
1606 val &= ~mask;
1607 val |= code << group_shift;
1608 val |= PMRESRn_EN;
1609 krait_write_vpmresr0(val);
1610 krait_post_vpmresr0(vval, fval);
1611 } else {
1612 val = krait_read_pmresrn(region);
1613 val &= ~mask;
1614 val |= code << group_shift;
1615 val |= PMRESRn_EN;
1616 krait_write_pmresrn(region, val);
1617 }
1618}
1619
1620static u32 krait_clear_pmresrn_group(u32 val, int group)
1621{
1622 u32 mask;
1623 int group_shift;
1624
1625 group_shift = group * 8;
1626 mask = 0xff << group_shift;
1627 val &= ~mask;
1628
1629 /* Don't clear enable bit if entire region isn't disabled */
1630 if (val & ~PMRESRn_EN)
1631 return val |= PMRESRn_EN;
1632
1633 return 0;
1634}
1635
1636static void krait_clearpmu(u32 config_base)
1637{
1638 u32 val;
1639 u32 vval, fval;
1640 unsigned int region;
1641 unsigned int group;
1642 bool venum_event;
1643
1644 venum_event = !!(config_base & VENUM_EVENT);
1645 region = (config_base >> 12) & 0xf;
1646 group = (config_base >> 0) & 0xf;
1647
1648 if (venum_event) {
1649 krait_pre_vpmresr0(&vval, &fval);
1650 val = krait_read_vpmresr0();
1651 val = krait_clear_pmresrn_group(val, group);
1652 krait_write_vpmresr0(val);
1653 krait_post_vpmresr0(vval, fval);
1654 } else {
1655 val = krait_read_pmresrn(region);
1656 val = krait_clear_pmresrn_group(val, group);
1657 krait_write_pmresrn(region, val);
1658 }
1659}
1660
1661static void krait_pmu_disable_event(struct perf_event *event)
1662{
1663 unsigned long flags;
1664 struct hw_perf_event *hwc = &event->hw;
1665 int idx = hwc->idx;
1666 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
1667
1668 /* Disable counter and interrupt */
1669 raw_spin_lock_irqsave(&events->pmu_lock, flags);
1670
1671 /* Disable counter */
1672 armv7_pmnc_disable_counter(idx);
1673
1674 /*
1675 * Clear pmresr code (if destined for PMNx counters)
1676 */
1677 if (hwc->config_base & KRAIT_EVENT_MASK)
1678 krait_clearpmu(hwc->config_base);
1679
1680 /* Disable interrupt for this counter */
1681 armv7_pmnc_disable_intens(idx);
1682
1683 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
1684}
1685
1686static void krait_pmu_enable_event(struct perf_event *event)
1687{
1688 unsigned long flags;
1689 struct hw_perf_event *hwc = &event->hw;
1690 int idx = hwc->idx;
1691 struct pmu_hw_events *events = cpu_pmu->get_hw_events();
1692
1693 /*
1694 * Enable counter and interrupt, and set the counter to count
1695 * the event that we're interested in.
1696 */
1697 raw_spin_lock_irqsave(&events->pmu_lock, flags);
1698
1699 /* Disable counter */
1700 armv7_pmnc_disable_counter(idx);
1701
1702 /*
1703 * Set event (if destined for PMNx counters)
1704 * We set the event for the cycle counter because we
1705 * have the ability to perform event filtering.
1706 */
1707 if (hwc->config_base & KRAIT_EVENT_MASK)
1708 krait_evt_setup(idx, hwc->config_base);
1709 else
1710 armv7_pmnc_write_evtsel(idx, hwc->config_base);
1711
1712 /* Enable interrupt for this counter */
1713 armv7_pmnc_enable_intens(idx);
1714
1715 /* Enable counter */
1716 armv7_pmnc_enable_counter(idx);
1717
1718 raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
1719}
1720
1721static void krait_pmu_reset(void *info)
1722{
1723 u32 vval, fval;
1724
1725 armv7pmu_reset(info);
1726
1727 /* Clear all pmresrs */
1728 krait_write_pmresrn(0, 0);
1729 krait_write_pmresrn(1, 0);
1730 krait_write_pmresrn(2, 0);
1731
1732 krait_pre_vpmresr0(&vval, &fval);
1733 krait_write_vpmresr0(0);
1734 krait_post_vpmresr0(vval, fval);
1735}
1736
1737static int krait_event_to_bit(struct perf_event *event, unsigned int region,
1738 unsigned int group)
1739{
1740 int bit;
1741 struct hw_perf_event *hwc = &event->hw;
1742 struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
1743
1744 if (hwc->config_base & VENUM_EVENT)
1745 bit = KRAIT_VPMRESR0_GROUP0;
1746 else
1747 bit = krait_get_pmresrn_event(region);
1748 bit -= krait_get_pmresrn_event(0);
1749 bit += group;
1750 /*
1751 * Lower bits are reserved for use by the counters (see
1752 * armv7pmu_get_event_idx() for more info)
1753 */
1754 bit += ARMV7_IDX_COUNTER_LAST(cpu_pmu) + 1;
1755
1756 return bit;
1757}
1758
1759/*
1760 * We check for column exclusion constraints here.
1761 * Two events cant use the same group within a pmresr register.
1762 */
1763static int krait_pmu_get_event_idx(struct pmu_hw_events *cpuc,
1764 struct perf_event *event)
1765{
1766 int idx;
1767 int bit;
1768 unsigned int prefix;
1769 unsigned int region;
1770 unsigned int code;
1771 unsigned int group;
1772 bool krait_event;
1773 struct hw_perf_event *hwc = &event->hw;
1774
1775 region = (hwc->config_base >> 12) & 0xf;
1776 code = (hwc->config_base >> 4) & 0xff;
1777 group = (hwc->config_base >> 0) & 0xf;
1778 krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
1779
1780 if (krait_event) {
1781 /* Ignore invalid events */
1782 if (group > 3 || region > 2)
1783 return -EINVAL;
1784 prefix = hwc->config_base & KRAIT_EVENT_MASK;
1785 if (prefix != KRAIT_EVENT && prefix != VENUM_EVENT)
1786 return -EINVAL;
1787 if (prefix == VENUM_EVENT && (code & 0xe0))
1788 return -EINVAL;
1789
1790 bit = krait_event_to_bit(event, region, group);
1791 if (test_and_set_bit(bit, cpuc->used_mask))
1792 return -EAGAIN;
1793 }
1794
1795 idx = armv7pmu_get_event_idx(cpuc, event);
1796 if (idx < 0 && krait_event)
1797 clear_bit(bit, cpuc->used_mask);
1798
1799 return idx;
1800}
1801
1802static void krait_pmu_clear_event_idx(struct pmu_hw_events *cpuc,
1803 struct perf_event *event)
1804{
1805 int bit;
1806 struct hw_perf_event *hwc = &event->hw;
1807 unsigned int region;
1808 unsigned int group;
1809 bool krait_event;
1810
1811 region = (hwc->config_base >> 12) & 0xf;
1812 group = (hwc->config_base >> 0) & 0xf;
1813 krait_event = !!(hwc->config_base & KRAIT_EVENT_MASK);
1814
1815 if (krait_event) {
1816 bit = krait_event_to_bit(event, region, group);
1817 clear_bit(bit, cpuc->used_mask);
1818 }
1819}
1820
1431static int krait_pmu_init(struct arm_pmu *cpu_pmu) 1821static int krait_pmu_init(struct arm_pmu *cpu_pmu)
1432{ 1822{
1433 armv7pmu_init(cpu_pmu); 1823 armv7pmu_init(cpu_pmu);
@@ -1440,6 +1830,11 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu)
1440 cpu_pmu->map_event = krait_map_event; 1830 cpu_pmu->map_event = krait_map_event;
1441 cpu_pmu->num_events = armv7_read_num_pmnc_events(); 1831 cpu_pmu->num_events = armv7_read_num_pmnc_events();
1442 cpu_pmu->set_event_filter = armv7pmu_set_event_filter; 1832 cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
1833 cpu_pmu->reset = krait_pmu_reset;
1834 cpu_pmu->enable = krait_pmu_enable_event;
1835 cpu_pmu->disable = krait_pmu_disable_event;
1836 cpu_pmu->get_event_idx = krait_pmu_get_event_idx;
1837 cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
1443 return 0; 1838 return 0;
1444} 1839}
1445#else 1840#else