Commit-ID: aabbaa6036fd847c583f585c6bae82b5a033e6c7 Gitweb: http://git.kernel.org/tip/aabbaa6036fd847c583f585c6bae82b5a033e6c7 Author: "Paul Mackerras" <paulus@xxxxxxxxx> AuthorDate: Fri, 6 Mar 2009 16:27:10 +1100 Commit: Paul Mackerras <paulus@xxxxxxxxx> CommitDate: Fri, 6 Mar 2009 16:28:37 +1100 perfcounters/powerpc: add support for POWER5+ processors Impact: more hardware support This adds the back-end for the PMU on the POWER5+ processors (i.e. GS, including GS DD3 aka POWER5++). This doesn't use the fixed-function PMC5 and PMC6 since they don't respect the freeze conditions and don't generate interrupts, as on POWER6. Signed-off-by: Paul Mackerras <paulus@xxxxxxxxx> --- arch/powerpc/kernel/Makefile | 4 +- arch/powerpc/kernel/perf_counter.c | 4 + .../powerpc/kernel/{power5-pmu.c => power5+-pmu.c} | 187 +++++++++----------- 3 files changed, 88 insertions(+), 107 deletions(-) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b4c6f46..49851e0 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -94,8 +94,8 @@ obj-$(CONFIG_AUDIT) += audit.o obj64-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o -obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o ppc970-pmu.o power5-pmu.o \ - power6-pmu.o +obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o ppc970-pmu.o \ + power5-pmu.o power5+-pmu.o power6-pmu.o obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o diff --git a/arch/powerpc/kernel/perf_counter.c b/arch/powerpc/kernel/perf_counter.c index 4fec112..162f398 100644 --- a/arch/powerpc/kernel/perf_counter.c +++ b/arch/powerpc/kernel/perf_counter.c @@ -826,6 +826,7 @@ void hw_perf_counter_setup(int cpu) extern struct power_pmu ppc970_pmu; extern struct power_pmu power5_pmu; +extern struct power_pmu power5p_pmu; extern struct power_pmu power6_pmu; static int init_perf_counters(void) @@ -848,6 +849,9 @@ static int init_perf_counters(void) case PV_POWER5: ppmu = &power5_pmu; break; + case PV_POWER5p: + ppmu = &power5p_pmu; + break; case 0x3e: ppmu = &power6_pmu; break; diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/kernel/power5+-pmu.c similarity index 72% copy from arch/powerpc/kernel/power5-pmu.c copy to arch/powerpc/kernel/power5+-pmu.c index 379ed10..cec21ea 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/kernel/power5+-pmu.c @@ -13,7 +13,7 @@ #include <asm/reg.h> /* - * Bits in event code for POWER5 (not POWER5++) + * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3) */ #define PM_PMC_SH 20 /* PMC number (1-based) for direct events */ #define PM_PMC_MSK 0xf @@ -40,7 +40,7 @@ #define PM_LASTUNIT 0xc /* - * Bits in MMCR1 for POWER5 + * Bits in MMCR1 for POWER5+ */ #define MMCR1_TTM0SEL_SH 62 #define MMCR1_TTM1SEL_SH 60 @@ -78,14 +78,8 @@ * Layout of constraint bits: * 6666555555555544444444443333333333222222222211111111110000000000 * 3210987654321098765432109876543210987654321098765432109876543210 - * <><>[ ><><>< ><> [ >[ >[ >< >< >< >< ><><><><><><> - * T0T1 NC G0G1G2 G3 UC PS1PS2 B0 B1 B2 B3 P6P5P4P3P2P1 - * - * T0 - TTM0 constraint - * 54-55: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0xc0_0000_0000_0000 - * - * T1 - TTM1 constraint - * 52-53: TTM1SEL value (0=IDU, 3=GRS) 0x30_0000_0000_0000 + * [ ><><>< ><> <><>[ > < >< >< >< ><><><><> + * NC G0G1G2 G3 T0T1 UC B0 B1 B2 B3 P4P3P2P1 * * NC - number of counters * 51: NC error 0x0008_0000_0000_0000 @@ -98,29 +92,31 @@ * 39-40: GRS_FABSEL value * Note that these match up with their bit positions in MMCR1 * - * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS - * 37: UC3 error 0x20_0000_0000 - * 36: FPU|IFU|ISU1 events needed 0x10_0000_0000 - * 35: ISU0 events needed 0x08_0000_0000 - * 34: IDU|GRS events needed 0x04_0000_0000 + * T0 - TTM0 constraint + * 36-37: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0x30_0000_0000 * - * PS1 - * 33: PS1 error 0x2_0000_0000 - * 31-32: count of events needing PMC1/2 0x1_8000_0000 + * T1 - TTM1 constraint + * 34-35: TTM1SEL value (0=IDU, 3=GRS) 0x0c_0000_0000 * - * PS2 - * 30: PS2 error 0x4000_0000 - * 28-29: count of events needing PMC3/4 0x3000_0000 + * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS + * 33: UC3 error 0x02_0000_0000 + * 32: FPU|IFU|ISU1 events needed 0x01_0000_0000 + * 31: ISU0 events needed 0x01_8000_0000 + * 30: IDU|GRS events needed 0x00_4000_0000 * * B0 - * 24-27: Byte 0 event source 0x0f00_0000 + * 20-23: Byte 0 event source 0x00f0_0000 * Encoding as for the event code * * B1, B2, B3 - * 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources + * 16-19, 12-15, 8-11: Byte 1, 2, 3 event sources * - * P1..P6 - * 0-11: Count of events needing PMC1..PMC6 + * P4 + * 7: P1 error 0x80 + * 6-7: Count of events needing PMC4 + * + * P1..P3 + * 0-6: Count of events needing PMC1..PMC3 */ static const int grsel_shift[8] = { @@ -131,32 +127,27 @@ static const int grsel_shift[8] = { /* Masks and values for using events from the various units */ static u64 unit_cons[PM_LASTUNIT+1][2] = { - [PM_FPU] = { 0xc0002000000000ull, 0x00001000000000ull }, - [PM_ISU0] = { 0x00002000000000ull, 0x00000800000000ull }, - [PM_ISU1] = { 0xc0002000000000ull, 0xc0001000000000ull }, - [PM_IFU] = { 0xc0002000000000ull, 0x80001000000000ull }, - [PM_IDU] = { 0x30002000000000ull, 0x00000400000000ull }, - [PM_GRS] = { 0x30002000000000ull, 0x30000400000000ull }, + [PM_FPU] = { 0x3200000000ull, 0x0100000000ull }, + [PM_ISU0] = { 0x0200000000ull, 0x0080000000ull }, + [PM_ISU1] = { 0x3200000000ull, 0x3100000000ull }, + [PM_IFU] = { 0x3200000000ull, 0x2100000000ull }, + [PM_IDU] = { 0x0e00000000ull, 0x0040000000ull }, + [PM_GRS] = { 0x0e00000000ull, 0x0c40000000ull }, }; -static int power5_get_constraint(unsigned int event, u64 *maskp, u64 *valp) +static int power5p_get_constraint(unsigned int event, u64 *maskp, u64 *valp) { int pmc, byte, unit, sh; int bit, fmask; u64 mask = 0, value = 0; - int grp = -1; pmc = (event >> PM_PMC_SH) & PM_PMC_MSK; if (pmc) { - if (pmc > 6) + if (pmc > 4) return -1; sh = (pmc - 1) * 2; mask |= 2 << sh; value |= 1 << sh; - if (pmc <= 4) - grp = (pmc - 1) >> 1; - else if (event != 0x500009 && event != 0x600005) - return -1; } if (event & PM_BUSEVENT_MSK) { unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK; @@ -181,30 +172,12 @@ static int power5_get_constraint(unsigned int event, u64 *maskp, u64 *valp) mask |= (u64)fmask << sh; value |= (u64)((event >> PM_GRS_SH) & fmask) << sh; } - /* - * Bus events on bytes 0 and 2 can be counted - * on PMC1/2; bytes 1 and 3 on PMC3/4. - */ - if (!pmc) - grp = byte & 1; /* Set byte lane select field */ - mask |= 0xfULL << (24 - 4 * byte); - value |= (u64)unit << (24 - 4 * byte); - } - if (grp == 0) { - /* increment PMC1/2 field */ - mask |= 0x200000000ull; - value |= 0x080000000ull; - } else if (grp == 1) { - /* increment PMC3/4 field */ - mask |= 0x40000000ull; - value |= 0x10000000ull; - } - if (pmc < 5) { - /* need a counter from PMC1-4 set */ - mask |= 0x8000000000000ull; - value |= 0x1000000000000ull; + mask |= 0xfULL << (20 - 4 * byte); + value |= (u64)unit << (20 - 4 * byte); } + mask |= 0x8000000000000ull; + value |= 0x1000000000000ull; *maskp = mask; *valp = value; return 0; @@ -213,10 +186,15 @@ static int power5_get_constraint(unsigned int event, u64 *maskp, u64 *valp) #define MAX_ALT 3 /* at most 3 alternatives for any event */ static const unsigned int event_alternatives[][MAX_ALT] = { + { 0x100c0, 0x40001f }, /* PM_GCT_FULL_CYC */ { 0x120e4, 0x400002 }, /* PM_GRP_DISP_REJECT */ + { 0x230e2, 0x323087 }, /* PM_BR_PRED_CR */ + { 0x230e3, 0x223087, 0x3230a0 }, /* PM_BR_PRED_TA */ { 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */ - { 0x100005, 0x600005 }, /* PM_RUN_CYC */ - { 0x100009, 0x200009, 0x500009 }, /* PM_INST_CMPL */ + { 0x800c4, 0xc20e0 }, /* PM_DTLB_MISS */ + { 0xc50c6, 0xc60e0 }, /* PM_MRK_DTLB_MISS */ + { 0x100009, 0x200009 }, /* PM_INST_CMPL */ + { 0x200015, 0x300015 }, /* PM_LSU_LMQ_SRQ_EMPTY_CYC */ { 0x300009, 0x400009 }, /* PM_INST_DISP */ }; @@ -248,7 +226,8 @@ static const unsigned char bytedecode_alternatives[4][4] = { /* * Some direct events for decodes of event bus byte 3 have alternative * PMCSEL values on other counters. This returns the alternative - * event code for those that do, or -1 otherwise. + * event code for those that do, or -1 otherwise. This also handles + * alternative PCMSEL values for add events. */ static int find_alternative_bdecode(unsigned int event) { @@ -266,10 +245,22 @@ static int find_alternative_bdecode(unsigned int event) bytedecode_alternatives[altpmc - 1][j]; } } + + /* new decode alternatives for power5+ */ + if (pmc == 1 && (pp == 0x0d || pp == 0x0e)) + return event + (2 << PM_PMC_SH) + (0x2e - 0x0d); + if (pmc == 3 && (pp == 0x2e || pp == 0x2f)) + return event - (2 << PM_PMC_SH) - (0x2e - 0x0d); + + /* alternative add event encodings */ + if (pp == 0x10 || pp == 0x28) + return ((event ^ (0x10 ^ 0x28)) & ~PM_PMC_MSKS) | + (altpmc << PM_PMC_SH); + return -1; } -static int power5_get_alternatives(unsigned int event, unsigned int alt[]) +static int power5p_get_alternatives(unsigned int event, unsigned int alt[]) { int i, j, ae, nalt = 1; @@ -290,37 +281,32 @@ static int power5_get_alternatives(unsigned int event, unsigned int alt[]) return nalt; } -static int power5_compute_mmcr(unsigned int event[], int n_ev, - unsigned int hwc[], u64 mmcr[]) +static int power5p_compute_mmcr(unsigned int event[], int n_ev, + unsigned int hwc[], u64 mmcr[]) { u64 mmcr1 = 0; unsigned int pmc, unit, byte, psel; - unsigned int ttm, grp; + unsigned int ttm; int i, isbus, bit, grsel; unsigned int pmc_inuse = 0; - unsigned int pmc_grp_use[2]; unsigned char busbyte[4]; unsigned char unituse[16]; int ttmuse; - if (n_ev > 6) + if (n_ev > 4) return -1; /* First pass to count resource use */ - pmc_grp_use[0] = pmc_grp_use[1] = 0; memset(busbyte, 0, sizeof(busbyte)); memset(unituse, 0, sizeof(unituse)); for (i = 0; i < n_ev; ++i) { pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK; if (pmc) { - if (pmc > 6) + if (pmc > 4) return -1; if (pmc_inuse & (1 << (pmc - 1))) return -1; pmc_inuse |= 1 << (pmc - 1); - /* count 1/2 vs 3/4 use */ - if (pmc <= 4) - ++pmc_grp_use[(pmc - 1) >> 1]; } if (event[i] & PM_BUSEVENT_MSK) { unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK; @@ -335,16 +321,12 @@ static int power5_compute_mmcr(unsigned int event[], int n_ev, ++unit; byte &= 3; } - if (!pmc) - ++pmc_grp_use[byte & 1]; if (busbyte[byte] && busbyte[byte] != unit) return -1; busbyte[byte] = unit; unituse[unit] = 1; } } - if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2) - return -1; /* * Assign resources and set multiplexer selects. @@ -403,33 +385,28 @@ static int power5_compute_mmcr(unsigned int event[], int n_ev, if (!pmc) { /* Bus event or any-PMC direct event */ for (pmc = 0; pmc < 4; ++pmc) { - if (pmc_inuse & (1 << pmc)) - continue; - grp = (pmc >> 1) & 1; - if (isbus) { - if (grp == (byte & 1)) - break; - } else if (pmc_grp_use[grp] < 2) { - ++pmc_grp_use[grp]; + if (!(pmc_inuse & (1 << pmc))) break; - } } + if (pmc >= 4) + return -1; pmc_inuse |= 1 << pmc; - } else if (pmc <= 4) { + } else { /* Direct event */ --pmc; - if ((psel == 8 || psel == 0x10) && isbus && (byte & 2)) + if (isbus && (byte & 2) && + (psel == 8 || psel == 0x10 || psel == 0x28)) /* add events on higher-numbered bus */ mmcr1 |= 1ull << (MMCR1_PMC1_ADDER_SEL_SH - pmc); - } else { - /* Instructions or run cycles on PMC5/6 */ - --pmc; } if (isbus && unit == PM_GRS) { bit = psel & 7; grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK; mmcr1 |= (u64)grsel << grsel_shift[bit]; } + if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1)) + /* select alternate byte lane */ + psel |= 0x10; if (pmc <= 3) mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc); hwc[i] = pmc; @@ -446,30 +423,30 @@ static int power5_compute_mmcr(unsigned int event[], int n_ev, return 0; } -static void power5_disable_pmc(unsigned int pmc, u64 mmcr[]) +static void power5p_disable_pmc(unsigned int pmc, u64 mmcr[]) { if (pmc <= 3) mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc)); } -static int power5_generic_events[] = { +static int power5p_generic_events[] = { [PERF_COUNT_CPU_CYCLES] = 0xf, [PERF_COUNT_INSTRUCTIONS] = 0x100009, - [PERF_COUNT_CACHE_REFERENCES] = 0x4c1090, /* LD_REF_L1 */ + [PERF_COUNT_CACHE_REFERENCES] = 0x1c10a8, /* LD_REF_L1 */ [PERF_COUNT_CACHE_MISSES] = 0x3c1088, /* LD_MISS_L1 */ [PERF_COUNT_BRANCH_INSTRUCTIONS] = 0x230e4, /* BR_ISSUED */ [PERF_COUNT_BRANCH_MISSES] = 0x230e5, /* BR_MPRED_CR */ }; -struct power_pmu power5_pmu = { - .n_counter = 6, +struct power_pmu power5p_pmu = { + .n_counter = 4, .max_alternatives = MAX_ALT, - .add_fields = 0x7000090000555ull, - .test_adder = 0x3000490000000ull, - .compute_mmcr = power5_compute_mmcr, - .get_constraint = power5_get_constraint, - .get_alternatives = power5_get_alternatives, - .disable_pmc = power5_disable_pmc, - .n_generic = ARRAY_SIZE(power5_generic_events), - .generic_events = power5_generic_events, + .add_fields = 0x7000000000055ull, + .test_adder = 0x3000040000000ull, + .compute_mmcr = power5p_compute_mmcr, + .get_constraint = power5p_get_constraint, + .get_alternatives = power5p_get_alternatives, + .disable_pmc = power5p_disable_pmc, + .n_generic = ARRAY_SIZE(power5p_generic_events), + .generic_events = power5p_generic_events, }; -- To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html