1255164Sjhibbits/*-
2255164Sjhibbits * Copyright (c) 2011 Justin Hibbits
3255164Sjhibbits * Copyright (c) 2005, Joseph Koshy
4255164Sjhibbits * All rights reserved.
5255164Sjhibbits *
6255164Sjhibbits * Redistribution and use in source and binary forms, with or without
7255164Sjhibbits * modification, are permitted provided that the following conditions
8255164Sjhibbits * are met:
9255164Sjhibbits * 1. Redistributions of source code must retain the above copyright
10255164Sjhibbits *    notice, this list of conditions and the following disclaimer.
11255164Sjhibbits * 2. Redistributions in binary form must reproduce the above copyright
12255164Sjhibbits *    notice, this list of conditions and the following disclaimer in the
13255164Sjhibbits *    documentation and/or other materials provided with the distribution.
14255164Sjhibbits *
15255164Sjhibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16255164Sjhibbits * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17255164Sjhibbits * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18255164Sjhibbits * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19255164Sjhibbits * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20255164Sjhibbits * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21255164Sjhibbits * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22255164Sjhibbits * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23255164Sjhibbits * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24255164Sjhibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25255164Sjhibbits * SUCH DAMAGE.
26255164Sjhibbits *
27255164Sjhibbits */
28255164Sjhibbits
29255164Sjhibbits#include <sys/cdefs.h>
30255164Sjhibbits__FBSDID("$FreeBSD$");
31255164Sjhibbits
32255164Sjhibbits#include <sys/param.h>
33255164Sjhibbits#include <sys/pmc.h>
34255164Sjhibbits#include <sys/pmckern.h>
35255164Sjhibbits#include <sys/systm.h>
36255164Sjhibbits
37255164Sjhibbits#include <machine/pmc_mdep.h>
38255164Sjhibbits#include <machine/spr.h>
39255164Sjhibbits#include <machine/cpu.h>
40255164Sjhibbits
41255164Sjhibbits#include "hwpmc_powerpc.h"
42255164Sjhibbits
43255164Sjhibbits#define	POWERPC_PMC_CAPS	(PMC_CAP_INTERRUPT | PMC_CAP_USER |     \
44255164Sjhibbits				 PMC_CAP_SYSTEM | PMC_CAP_EDGE |	\
45255164Sjhibbits				 PMC_CAP_THRESHOLD | PMC_CAP_READ |	\
46255164Sjhibbits				 PMC_CAP_WRITE | PMC_CAP_INVERT |	\
47255164Sjhibbits				 PMC_CAP_QUALIFIER)
48255164Sjhibbits
49255164Sjhibbits#define PPC_SET_PMC1SEL(r, x)	((r & ~(SPR_MMCR0_PMC1SEL(0x3f))) | SPR_MMCR0_PMC1SEL(x))
50255164Sjhibbits#define PPC_SET_PMC2SEL(r, x)	((r & ~(SPR_MMCR0_PMC2SEL(0x3f))) | SPR_MMCR0_PMC2SEL(x))
51255164Sjhibbits#define PPC_SET_PMC3SEL(r, x)	((r & ~(SPR_MMCR1_PMC3SEL(0x1f))) | SPR_MMCR1_PMC3SEL(x))
52255164Sjhibbits#define PPC_SET_PMC4SEL(r, x)	((r & ~(SPR_MMCR1_PMC4SEL(0x1f))) | SPR_MMCR1_PMC4SEL(x))
53255164Sjhibbits#define PPC_SET_PMC5SEL(r, x)	((r & ~(SPR_MMCR1_PMC5SEL(0x1f))) | SPR_MMCR1_PMC5SEL(x))
54255164Sjhibbits#define PPC_SET_PMC6SEL(r, x)	((r & ~(SPR_MMCR1_PMC6SEL(0x3f))) | SPR_MMCR1_PMC6SEL(x))
55255164Sjhibbits
56255164Sjhibbits/* Change this when we support more than just the 7450. */
57255164Sjhibbits#define MPC7XXX_MAX_PMCS	6
58255164Sjhibbits
59255164Sjhibbits#define MPC7XXX_PMC_HAS_OVERFLOWED(x) (mpc7xxx_pmcn_read(x) & (0x1 << 31))
60255164Sjhibbits
61255164Sjhibbits/*
62255164Sjhibbits * Things to improve on this:
63255164Sjhibbits * - It stops (clears to 0) the PMC and resets it at every context switch
64255164Sjhibbits *   currently.
65255164Sjhibbits */
66255164Sjhibbits
67255164Sjhibbits/*
68255164Sjhibbits * This should work for every 32-bit PowerPC implementation I know of (G3 and G4
69255164Sjhibbits * specifically).
70255164Sjhibbits */
71255164Sjhibbits
72263122Sjhibbitsstruct mpc7xxx_event_code_map {
73255164Sjhibbits	enum pmc_event	pe_ev;       /* enum value */
74255164Sjhibbits	uint8_t         pe_counter_mask;  /* Which counter this can be counted in. */
75263122Sjhibbits	uint8_t		pe_code;     /* numeric code */
76255164Sjhibbits};
77255164Sjhibbits
78255164Sjhibbits#define PPC_PMC_MASK1	0
79255164Sjhibbits#define PPC_PMC_MASK2	1
80255164Sjhibbits#define PPC_PMC_MASK3	2
81255164Sjhibbits#define PPC_PMC_MASK4	3
82255164Sjhibbits#define PPC_PMC_MASK5	4
83255164Sjhibbits#define PPC_PMC_MASK6	5
84255164Sjhibbits#define PPC_PMC_MASK_ALL	0x3f
85255164Sjhibbits#define PMC_POWERPC_EVENT(id, mask, number) \
86255164Sjhibbits	{ .pe_ev = PMC_EV_PPC7450_##id, .pe_counter_mask = mask, .pe_code = number }
87255164Sjhibbits
88263122Sjhibbitsstatic struct mpc7xxx_event_code_map mpc7xxx_event_codes[] = {
89255164Sjhibbits	PMC_POWERPC_EVENT(CYCLE,PPC_PMC_MASK_ALL, 1),
90255164Sjhibbits	PMC_POWERPC_EVENT(INSTR_COMPLETED, 0x0f, 2),
91255164Sjhibbits	PMC_POWERPC_EVENT(TLB_BIT_TRANSITIONS, 0x0f, 3),
92255164Sjhibbits	PMC_POWERPC_EVENT(INSTR_DISPATCHED, 0x0f, 4),
93255164Sjhibbits	PMC_POWERPC_EVENT(PMON_EXCEPT, 0x0f, 5),
94255164Sjhibbits	PMC_POWERPC_EVENT(PMON_SIG, 0x0f, 7),
95255164Sjhibbits	PMC_POWERPC_EVENT(VPU_INSTR_COMPLETED, 0x03, 8),
96255164Sjhibbits	PMC_POWERPC_EVENT(VFPU_INSTR_COMPLETED, 0x03, 9),
97255164Sjhibbits	PMC_POWERPC_EVENT(VIU1_INSTR_COMPLETED, 0x03, 10),
98255164Sjhibbits	PMC_POWERPC_EVENT(VIU2_INSTR_COMPLETED, 0x03, 11),
99255164Sjhibbits	PMC_POWERPC_EVENT(MTVSCR_INSTR_COMPLETED, 0x03, 12),
100255164Sjhibbits	PMC_POWERPC_EVENT(MTVRSAVE_INSTR_COMPLETED, 0x03, 13),
101255164Sjhibbits	PMC_POWERPC_EVENT(VPU_INSTR_WAIT_CYCLES, 0x03, 14),
102255164Sjhibbits	PMC_POWERPC_EVENT(VFPU_INSTR_WAIT_CYCLES, 0x03, 15),
103255164Sjhibbits	PMC_POWERPC_EVENT(VIU1_INSTR_WAIT_CYCLES, 0x03, 16),
104255164Sjhibbits	PMC_POWERPC_EVENT(VIU2_INSTR_WAIT_CYCLES, 0x03, 17),
105255164Sjhibbits	PMC_POWERPC_EVENT(MFVSCR_SYNC_CYCLES, 0x03, 18),
106255164Sjhibbits	PMC_POWERPC_EVENT(VSCR_SAT_SET, 0x03, 19),
107255164Sjhibbits	PMC_POWERPC_EVENT(STORE_INSTR_COMPLETED, 0x03, 20),
108255164Sjhibbits	PMC_POWERPC_EVENT(L1_INSTR_CACHE_MISSES, 0x03, 21),
109255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_SNOOPS, 0x03, 22),
110255164Sjhibbits	PMC_POWERPC_EVENT(UNRESOLVED_BRANCHES, 0x01, 23),
111255164Sjhibbits	PMC_POWERPC_EVENT(SPEC_BUFFER_CYCLES, 0x01, 24),
112255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_UNIT_STALL_CYCLES, 0x01, 25),
113255164Sjhibbits	PMC_POWERPC_EVENT(TRUE_BRANCH_TARGET_HITS, 0x01, 26),
114255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_LINK_STAC_PREDICTED, 0x01, 27),
115255164Sjhibbits	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_DISPATCHES, 0x01, 28),
116255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_THREE_INSTR_DISPATCHED, 0x01, 29),
117255164Sjhibbits	PMC_POWERPC_EVENT(THRESHOLD_INSTR_QUEUE_ENTRIES_CYCLES, 0x01, 30),
118255164Sjhibbits	PMC_POWERPC_EVENT(THRESHOLD_VEC_INSTR_QUEUE_ENTRIES_CYCLES, 0x01, 31),
119255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_NO_COMPLETED_INSTRS, 0x01, 32),
120255164Sjhibbits	PMC_POWERPC_EVENT(IU2_INSTR_COMPLETED, 0x01, 33),
121255164Sjhibbits	PMC_POWERPC_EVENT(BRANCHES_COMPLETED, 0x01, 34),
122255164Sjhibbits	PMC_POWERPC_EVENT(EIEIO_INSTR_COMPLETED, 0x01, 35),
123255164Sjhibbits	PMC_POWERPC_EVENT(MTSPR_INSTR_COMPLETED, 0x01, 36),
124255164Sjhibbits	PMC_POWERPC_EVENT(SC_INSTR_COMPLETED, 0x01, 37),
125255164Sjhibbits	PMC_POWERPC_EVENT(LS_LM_COMPLETED, 0x01, 38),
126255164Sjhibbits	PMC_POWERPC_EVENT(ITLB_HW_TABLE_SEARCH_CYCLES, 0x01, 39),
127255164Sjhibbits	PMC_POWERPC_EVENT(DTLB_HW_SEARCH_CYCLES_OVER_THRESHOLD, 0x01, 40),
128255164Sjhibbits	PMC_POWERPC_EVENT(L1_INSTR_CACHE_ACCESSES, 0x01, 41),
129255164Sjhibbits	PMC_POWERPC_EVENT(INSTR_BKPT_MATCHES, 0x01, 42),
130255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_CACHE_LOAD_MISS_CYCLES_OVER_THRESHOLD, 0x01, 43),
131255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_ON_MODIFIED, 0x01, 44),
132255164Sjhibbits	PMC_POWERPC_EVENT(LOAD_MISS_ALIAS, 0x01, 45),
133255164Sjhibbits	PMC_POWERPC_EVENT(LOAD_MISS_ALIAS_ON_TOUCH, 0x01, 46),
134255164Sjhibbits	PMC_POWERPC_EVENT(TOUCH_ALIAS, 0x01, 47),
135255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_CASTOUT_QUEUE, 0x01, 48),
136255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_CASTOUT, 0x01, 49),
137255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HITS, 0x01, 50),
138255164Sjhibbits	PMC_POWERPC_EVENT(WRITE_THROUGH_STORES, 0x01, 51),
139255164Sjhibbits	PMC_POWERPC_EVENT(CACHE_INHIBITED_STORES, 0x01, 52),
140255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_LOAD_HIT, 0x01, 53),
141255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOUCH_HIT, 0x01, 54),
142255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_STORE_HIT, 0x01, 55),
143255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOTAL_HITS, 0x01, 56),
144255164Sjhibbits	PMC_POWERPC_EVENT(DST_INSTR_DISPATCHED, 0x01, 57),
145255164Sjhibbits	PMC_POWERPC_EVENT(REFRESHED_DSTS, 0x01, 58),
146255164Sjhibbits	PMC_POWERPC_EVENT(SUCCESSFUL_DST_TABLE_SEARCHES, 0x01, 59),
147255164Sjhibbits	PMC_POWERPC_EVENT(DSS_INSTR_COMPLETED, 0x01, 60),
148255164Sjhibbits	PMC_POWERPC_EVENT(DST_STREAM_0_CACHE_LINE_FETCHES, 0x01, 61),
149255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_SUSPENDS_DUE_TO_CTX_CHANGE, 0x01, 62),
150255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_LINE_FETCH_HIT, 0x01, 63),
151255164Sjhibbits	PMC_POWERPC_EVENT(VEC_LOAD_INSTR_COMPLETED, 0x01, 64),
152255164Sjhibbits	PMC_POWERPC_EVENT(FP_STORE_INSTR_COMPLETED_IN_LSU, 0x01, 65),
153255164Sjhibbits	PMC_POWERPC_EVENT(FPU_RENORMALIZATION, 0x01, 66),
154255164Sjhibbits	PMC_POWERPC_EVENT(FPU_DENORMALIZATION, 0x01, 67),
155255164Sjhibbits	PMC_POWERPC_EVENT(FP_STORE_CAUSES_STALL_IN_LSU, 0x01, 68),
156255164Sjhibbits	PMC_POWERPC_EVENT(LD_ST_TRUE_ALIAS_STALL, 0x01, 70),
157255164Sjhibbits	PMC_POWERPC_EVENT(LSU_INDEXED_ALIAS_STALL, 0x01, 71),
158255164Sjhibbits	PMC_POWERPC_EVENT(LSU_ALIAS_VS_FSQ_WB0_WB1, 0x01, 72),
159255164Sjhibbits	PMC_POWERPC_EVENT(LSU_ALIAS_VS_CSQ, 0x01, 73),
160255164Sjhibbits	PMC_POWERPC_EVENT(LSU_LOAD_HIT_LINE_ALIAS_VS_CSQ0, 0x01, 74),
161255164Sjhibbits	PMC_POWERPC_EVENT(LSU_LOAD_MISS_LINE_ALIAS_VS_CSQ0, 0x01, 75),
162255164Sjhibbits	PMC_POWERPC_EVENT(LSU_TOUCH_LINE_ALIAS_VS_FSQ_WB0_WB1, 0x01, 76),
163255164Sjhibbits	PMC_POWERPC_EVENT(LSU_TOUCH_ALIAS_VS_CSQ, 0x01, 77),
164255164Sjhibbits	PMC_POWERPC_EVENT(LSU_LMQ_FULL_STALL, 0x01, 78),
165255164Sjhibbits	PMC_POWERPC_EVENT(FP_LOAD_INSTR_COMPLETED_IN_LSU, 0x01, 79),
166255164Sjhibbits	PMC_POWERPC_EVENT(FP_LOAD_SINGLE_INSTR_COMPLETED_IN_LSU, 0x01, 80),
167255164Sjhibbits	PMC_POWERPC_EVENT(FP_LOAD_DOUBLE_COMPLETED_IN_LSU, 0x01, 81),
168255164Sjhibbits	PMC_POWERPC_EVENT(LSU_RA_LATCH_STALL, 0x01, 82),
169255164Sjhibbits	PMC_POWERPC_EVENT(LSU_LOAD_VS_STORE_QUEUE_ALIAS_STALL, 0x01, 83),
170255164Sjhibbits	PMC_POWERPC_EVENT(LSU_LMQ_INDEX_ALIAS, 0x01, 84),
171255164Sjhibbits	PMC_POWERPC_EVENT(LSU_STORE_QUEUE_INDEX_ALIAS, 0x01, 85),
172255164Sjhibbits	PMC_POWERPC_EVENT(LSU_CSQ_FORWARDING, 0x01, 86),
173255164Sjhibbits	PMC_POWERPC_EVENT(LSU_MISALIGNED_LOAD_FINISH, 0x01, 87),
174255164Sjhibbits	PMC_POWERPC_EVENT(LSU_MISALIGN_STORE_COMPLETED, 0x01, 88),
175255164Sjhibbits	PMC_POWERPC_EVENT(LSU_MISALIGN_STALL, 0x01, 89),
176255164Sjhibbits	PMC_POWERPC_EVENT(FP_ONE_QUARTER_FPSCR_RENAMES_BUSY, 0x01, 90),
177255164Sjhibbits	PMC_POWERPC_EVENT(FP_ONE_HALF_FPSCR_RENAMES_BUSY, 0x01, 91),
178255164Sjhibbits	PMC_POWERPC_EVENT(FP_THREE_QUARTERS_FPSCR_RENAMES_BUSY, 0x01, 92),
179255164Sjhibbits	PMC_POWERPC_EVENT(FP_ALL_FPSCR_RENAMES_BUSY, 0x01, 93),
180255164Sjhibbits	PMC_POWERPC_EVENT(FP_DENORMALIZED_RESULT, 0x01, 94),
181255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOTAL_MISSES, 0x02, 23),
182255164Sjhibbits	PMC_POWERPC_EVENT(DISPATCHES_TO_FPR_ISSUE_QUEUE, 0x02, 24),
183255164Sjhibbits	PMC_POWERPC_EVENT(LSU_INSTR_COMPLETED, 0x02, 25),
184255164Sjhibbits	PMC_POWERPC_EVENT(LOAD_INSTR_COMPLETED, 0x02, 26),
185255164Sjhibbits	PMC_POWERPC_EVENT(SS_SM_INSTR_COMPLETED, 0x02, 27),
186255164Sjhibbits	PMC_POWERPC_EVENT(TLBIE_INSTR_COMPLETED, 0x02, 28),
187255164Sjhibbits	PMC_POWERPC_EVENT(LWARX_INSTR_COMPLETED, 0x02, 29),
188255164Sjhibbits	PMC_POWERPC_EVENT(MFSPR_INSTR_COMPLETED, 0x02, 30),
189255164Sjhibbits	PMC_POWERPC_EVENT(REFETCH_SERIALIZATION, 0x02, 31),
190255164Sjhibbits	PMC_POWERPC_EVENT(COMPLETION_QUEUE_ENTRIES_OVER_THRESHOLD, 0x02, 32),
191255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_ONE_INSTR_DISPATCHED, 0x02, 33),
192255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_TWO_INSTR_COMPLETED, 0x02, 34),
193255164Sjhibbits	PMC_POWERPC_EVENT(ITLB_NON_SPECULATIVE_MISSES, 0x02, 35),
194255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_WAITING_FROM_L1_INSTR_CACHE_MISS, 0x02, 36),
195255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_LOAD_ACCESS_MISS, 0x02, 37),
196255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOUCH_MISS, 0x02, 38),
197255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_STORE_MISS, 0x02, 39),
198255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOUCH_MISS_CYCLES, 0x02, 40),
199255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_CYCLES_USED, 0x02, 41),
200255164Sjhibbits	PMC_POWERPC_EVENT(DST_STREAM_1_CACHE_LINE_FETCHES, 0x02, 42),
201255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_STREAM_CANCELED_PREMATURELY, 0x02, 43),
202255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_RESUMES_DUE_TO_CTX_CHANGE, 0x02, 44),
203255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_LINE_FETCH_MISS, 0x02, 45),
204255164Sjhibbits	PMC_POWERPC_EVENT(VTQ_LINE_FETCH, 0x02, 46),
205255164Sjhibbits	PMC_POWERPC_EVENT(TLBIE_SNOOPS, 0x02, 47),
206255164Sjhibbits	PMC_POWERPC_EVENT(L1_INSTR_CACHE_RELOADS, 0x02, 48),
207255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_CACHE_RELOADS, 0x02, 49),
208255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_CACHE_CASTOUTS_TO_L2, 0x02, 50),
209255164Sjhibbits	PMC_POWERPC_EVENT(STORE_MERGE_GATHER, 0x02, 51),
210255164Sjhibbits	PMC_POWERPC_EVENT(CACHEABLE_STORE_MERGE_TO_32_BYTES, 0x02, 52),
211255164Sjhibbits	PMC_POWERPC_EVENT(DATA_BKPT_MATCHES, 0x02, 53),
212255164Sjhibbits	PMC_POWERPC_EVENT(FALL_THROUGH_BRANCHES_PROCESSED, 0x02, 54),
213255164Sjhibbits	PMC_POWERPC_EVENT(FIRST_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x02, 55),
214255164Sjhibbits	PMC_POWERPC_EVENT(SECOND_SPECULATION_BUFFER_ACTIVE, 0x02, 56),
215255164Sjhibbits	PMC_POWERPC_EVENT(BPU_STALL_ON_LR_DEPENDENCY, 0x02, 57),
216255164Sjhibbits	PMC_POWERPC_EVENT(BTIC_MISS, 0x02, 58),
217255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_LINK_STACK_CORRECTLY_RESOLVED, 0x02, 59),
218255164Sjhibbits	PMC_POWERPC_EVENT(FPR_ISSUE_STALLED, 0x02, 60),
219255164Sjhibbits	PMC_POWERPC_EVENT(SWITCHES_BETWEEN_PRIV_USER, 0x02, 61),
220255164Sjhibbits	PMC_POWERPC_EVENT(LSU_COMPLETES_FP_STORE_SINGLE, 0x02, 62),
221255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_TWO_INSTR_COMPLETED, 0x04, 8),
222255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_ONE_INSTR_DISPATCHED, 0x04, 9),
223255164Sjhibbits	PMC_POWERPC_EVENT(VR_ISSUE_QUEUE_DISPATCHES, 0x04, 10),
224255164Sjhibbits	PMC_POWERPC_EVENT(VR_STALLS, 0x04, 11),
225255164Sjhibbits	PMC_POWERPC_EVENT(GPR_RENAME_BUFFER_ENTRIES_OVER_THRESHOLD, 0x04, 12),
226255164Sjhibbits	PMC_POWERPC_EVENT(FPR_ISSUE_QUEUE_ENTRIES, 0x04, 13),
227255164Sjhibbits	PMC_POWERPC_EVENT(FPU_INSTR_COMPLETED, 0x04, 14),
228255164Sjhibbits	PMC_POWERPC_EVENT(STWCX_INSTR_COMPLETED, 0x04, 15),
229255164Sjhibbits	PMC_POWERPC_EVENT(LS_LM_INSTR_PIECES, 0x04, 16),
230255164Sjhibbits	PMC_POWERPC_EVENT(ITLB_HW_SEARCH_CYCLES_OVER_THRESHOLD, 0x04, 17),
231255164Sjhibbits	PMC_POWERPC_EVENT(DTLB_MISSES, 0x04, 18),
232255164Sjhibbits	PMC_POWERPC_EVENT(CANCELLED_L1_INSTR_CACHE_MISSES, 0x04, 19),
233255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_CACHE_OP_HIT, 0x04, 20),
234255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_LOAD_MISS_CYCLES, 0x04, 21),
235255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_PUSHES, 0x04, 22),
236255164Sjhibbits	PMC_POWERPC_EVENT(L1_DATA_TOTAL_MISS, 0x04, 23),
237255164Sjhibbits	PMC_POWERPC_EVENT(VT2_FETCHES, 0x04, 24),
238255164Sjhibbits	PMC_POWERPC_EVENT(TAKEN_BRANCHES_PROCESSED, 0x04, 25),
239255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_FLUSHES, 0x04, 26),
240255164Sjhibbits	PMC_POWERPC_EVENT(SECOND_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x04, 27),
241255164Sjhibbits	PMC_POWERPC_EVENT(THIRD_SPECULATION_BUFFER_ACTIVE, 0x04, 28),
242255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_UNIT_STALL_ON_CTR_DEPENDENCY, 0x04, 29),
243255164Sjhibbits	PMC_POWERPC_EVENT(FAST_BTIC_HIT, 0x04, 30),
244255164Sjhibbits	PMC_POWERPC_EVENT(BRANCH_LINK_STACK_MISPREDICTED, 0x04, 31),
245255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_THREE_INSTR_COMPLETED, 0x08, 14),
246255164Sjhibbits	PMC_POWERPC_EVENT(CYCLES_NO_INSTR_DISPATCHED, 0x08, 15),
247255164Sjhibbits	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_ENTRIES_OVER_THRESHOLD, 0x08, 16),
248255164Sjhibbits	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_STALLED, 0x08, 17),
249255164Sjhibbits	PMC_POWERPC_EVENT(IU1_INSTR_COMPLETED, 0x08, 18),
250255164Sjhibbits	PMC_POWERPC_EVENT(DSSALL_INSTR_COMPLETED, 0x08, 19),
251255164Sjhibbits	PMC_POWERPC_EVENT(TLBSYNC_INSTR_COMPLETED, 0x08, 20),
252255164Sjhibbits	PMC_POWERPC_EVENT(SYNC_INSTR_COMPLETED, 0x08, 21),
253255164Sjhibbits	PMC_POWERPC_EVENT(SS_SM_INSTR_PIECES, 0x08, 22),
254255164Sjhibbits	PMC_POWERPC_EVENT(DTLB_HW_SEARCH_CYCLES, 0x08, 23),
255255164Sjhibbits	PMC_POWERPC_EVENT(SNOOP_RETRIES, 0x08, 24),
256255164Sjhibbits	PMC_POWERPC_EVENT(SUCCESSFUL_STWCX, 0x08, 25),
257255164Sjhibbits	PMC_POWERPC_EVENT(DST_STREAM_3_CACHE_LINE_FETCHES, 0x08, 26),
258255164Sjhibbits	PMC_POWERPC_EVENT(THIRD_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x08, 27),
259255164Sjhibbits	PMC_POWERPC_EVENT(MISPREDICTED_BRANCHES, 0x08, 28),
260255164Sjhibbits	PMC_POWERPC_EVENT(FOLDED_BRANCHES, 0x08, 29),
261255164Sjhibbits	PMC_POWERPC_EVENT(FP_STORE_DOUBLE_COMPLETES_IN_LSU, 0x08, 30),
262255164Sjhibbits	PMC_POWERPC_EVENT(L2_CACHE_HITS, 0x30, 2),
263255164Sjhibbits	PMC_POWERPC_EVENT(L3_CACHE_HITS, 0x30, 3),
264255164Sjhibbits	PMC_POWERPC_EVENT(L2_INSTR_CACHE_MISSES, 0x30, 4),
265255164Sjhibbits	PMC_POWERPC_EVENT(L3_INSTR_CACHE_MISSES, 0x30, 5),
266255164Sjhibbits	PMC_POWERPC_EVENT(L2_DATA_CACHE_MISSES, 0x30, 6),
267255164Sjhibbits	PMC_POWERPC_EVENT(L3_DATA_CACHE_MISSES, 0x30, 7),
268255164Sjhibbits	PMC_POWERPC_EVENT(L2_LOAD_HITS, 0x10, 8),
269255164Sjhibbits	PMC_POWERPC_EVENT(L2_STORE_HITS, 0x10, 9),
270255164Sjhibbits	PMC_POWERPC_EVENT(L3_LOAD_HITS, 0x10, 10),
271255164Sjhibbits	PMC_POWERPC_EVENT(L3_STORE_HITS, 0x10, 11),
272255164Sjhibbits	PMC_POWERPC_EVENT(L2_TOUCH_HITS, 0x30, 13),
273255164Sjhibbits	PMC_POWERPC_EVENT(L3_TOUCH_HITS, 0x30, 14),
274255164Sjhibbits	PMC_POWERPC_EVENT(SNOOP_RETRIES, 0x30, 15),
275255164Sjhibbits	PMC_POWERPC_EVENT(SNOOP_MODIFIED, 0x10, 16),
276255164Sjhibbits	PMC_POWERPC_EVENT(SNOOP_VALID, 0x10, 17),
277255164Sjhibbits	PMC_POWERPC_EVENT(INTERVENTION, 0x30, 18),
278255164Sjhibbits	PMC_POWERPC_EVENT(L2_CACHE_MISSES, 0x10, 19),
279255164Sjhibbits	PMC_POWERPC_EVENT(L3_CACHE_MISSES, 0x10, 20),
280255164Sjhibbits	PMC_POWERPC_EVENT(L2_CACHE_CASTOUTS, 0x20, 8),
281255164Sjhibbits	PMC_POWERPC_EVENT(L3_CACHE_CASTOUTS, 0x20, 9),
282255164Sjhibbits	PMC_POWERPC_EVENT(L2SQ_FULL_CYCLES, 0x20, 10),
283255164Sjhibbits	PMC_POWERPC_EVENT(L3SQ_FULL_CYCLES, 0x20, 11),
284255164Sjhibbits	PMC_POWERPC_EVENT(RAQ_FULL_CYCLES, 0x20, 16),
285255164Sjhibbits	PMC_POWERPC_EVENT(WAQ_FULL_CYCLES, 0x20, 17),
286255164Sjhibbits	PMC_POWERPC_EVENT(L1_EXTERNAL_INTERVENTIONS, 0x20, 19),
287255164Sjhibbits	PMC_POWERPC_EVENT(L2_EXTERNAL_INTERVENTIONS, 0x20, 20),
288255164Sjhibbits	PMC_POWERPC_EVENT(L3_EXTERNAL_INTERVENTIONS, 0x20, 21),
289255164Sjhibbits	PMC_POWERPC_EVENT(EXTERNAL_INTERVENTIONS, 0x20, 22),
290255164Sjhibbits	PMC_POWERPC_EVENT(EXTERNAL_PUSHES, 0x20, 23),
291255164Sjhibbits	PMC_POWERPC_EVENT(EXTERNAL_SNOOP_RETRY, 0x20, 24),
292255164Sjhibbits	PMC_POWERPC_EVENT(DTQ_FULL_CYCLES, 0x20, 25),
293255164Sjhibbits	PMC_POWERPC_EVENT(BUS_RETRY, 0x20, 26),
294255164Sjhibbits	PMC_POWERPC_EVENT(L2_VALID_REQUEST, 0x20, 27),
295255164Sjhibbits	PMC_POWERPC_EVENT(BORDQ_FULL, 0x20, 28),
296255164Sjhibbits	PMC_POWERPC_EVENT(BUS_TAS_FOR_READS, 0x20, 42),
297255164Sjhibbits	PMC_POWERPC_EVENT(BUS_TAS_FOR_WRITES, 0x20, 43),
298255164Sjhibbits	PMC_POWERPC_EVENT(BUS_READS_NOT_RETRIED, 0x20, 44),
299255164Sjhibbits	PMC_POWERPC_EVENT(BUS_WRITES_NOT_RETRIED, 0x20, 45),
300255164Sjhibbits	PMC_POWERPC_EVENT(BUS_READS_WRITES_NOT_RETRIED, 0x20, 46),
301255164Sjhibbits	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_L1_RETRY, 0x20, 47),
302255164Sjhibbits	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_PREVIOUS_ADJACENT, 0x20, 48),
303255164Sjhibbits	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_COLLISION, 0x20, 49),
304255164Sjhibbits	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_INTERVENTION_ORDERING, 0x20, 50),
305255164Sjhibbits	PMC_POWERPC_EVENT(SNOOP_REQUESTS, 0x20, 51),
306255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_REQUEST, 0x20, 52),
307255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_LOAD, 0x20, 53),
308255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_STORE, 0x20, 54),
309255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_INSTR_FETCH, 0x20, 55),
310255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_LOAD_STORE_INSTR_FETCH, 0x20, 56),
311255164Sjhibbits	PMC_POWERPC_EVENT(PREFETCH_ENGINE_FULL, 0x20, 57)
312255164Sjhibbits};
313255164Sjhibbits
314263122Sjhibbitsconst size_t mpc7xxx_event_codes_size =
315263122Sjhibbits	sizeof(mpc7xxx_event_codes) / sizeof(mpc7xxx_event_codes[0]);
316255164Sjhibbits
317255164Sjhibbitsstatic pmc_value_t
318255164Sjhibbitsmpc7xxx_pmcn_read(unsigned int pmc)
319255164Sjhibbits{
320255164Sjhibbits	switch (pmc) {
321255164Sjhibbits		case 0:
322255164Sjhibbits			return mfspr(SPR_PMC1);
323255164Sjhibbits			break;
324255164Sjhibbits		case 1:
325255164Sjhibbits			return mfspr(SPR_PMC2);
326255164Sjhibbits			break;
327255164Sjhibbits		case 2:
328255164Sjhibbits			return mfspr(SPR_PMC3);
329255164Sjhibbits			break;
330255164Sjhibbits		case 3:
331255164Sjhibbits			return mfspr(SPR_PMC4);
332255164Sjhibbits			break;
333255164Sjhibbits		case 4:
334255164Sjhibbits			return mfspr(SPR_PMC5);
335255164Sjhibbits			break;
336255164Sjhibbits		case 5:
337255164Sjhibbits			return mfspr(SPR_PMC6);
338255164Sjhibbits		default:
339255164Sjhibbits			panic("Invalid PMC number: %d\n", pmc);
340255164Sjhibbits	}
341255164Sjhibbits}
342255164Sjhibbits
343255164Sjhibbitsstatic void
344255164Sjhibbitsmpc7xxx_pmcn_write(unsigned int pmc, uint32_t val)
345255164Sjhibbits{
346255164Sjhibbits	switch (pmc) {
347255164Sjhibbits		case 0:
348255164Sjhibbits			mtspr(SPR_PMC1, val);
349255164Sjhibbits			break;
350255164Sjhibbits		case 1:
351255164Sjhibbits			mtspr(SPR_PMC2, val);
352255164Sjhibbits			break;
353255164Sjhibbits		case 2:
354255164Sjhibbits			mtspr(SPR_PMC3, val);
355255164Sjhibbits			break;
356255164Sjhibbits		case 3:
357255164Sjhibbits			mtspr(SPR_PMC4, val);
358255164Sjhibbits			break;
359255164Sjhibbits		case 4:
360255164Sjhibbits			mtspr(SPR_PMC5, val);
361255164Sjhibbits			break;
362255164Sjhibbits		case 5:
363255164Sjhibbits			mtspr(SPR_PMC6, val);
364255164Sjhibbits			break;
365255164Sjhibbits		default:
366255164Sjhibbits			panic("Invalid PMC number: %d\n", pmc);
367255164Sjhibbits	}
368255164Sjhibbits}
369255164Sjhibbits
370255164Sjhibbitsstatic int
371255164Sjhibbitsmpc7xxx_read_pmc(int cpu, int ri, pmc_value_t *v)
372255164Sjhibbits{
373255164Sjhibbits	struct pmc *pm;
374255164Sjhibbits	pmc_value_t tmp;
375255164Sjhibbits
376255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
377255164Sjhibbits	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
378255164Sjhibbits	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
379255164Sjhibbits	    ("[powerpc,%d] illegal row index %d", __LINE__, ri));
380255164Sjhibbits
381255164Sjhibbits	pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
382255164Sjhibbits	KASSERT(pm,
383255164Sjhibbits	    ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
384255164Sjhibbits		ri));
385255164Sjhibbits
386255164Sjhibbits	tmp = mpc7xxx_pmcn_read(ri);
387283884Sjhb	PMCDBG2(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp);
388255164Sjhibbits	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
389255164Sjhibbits		*v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
390255164Sjhibbits	else
391255164Sjhibbits		*v = tmp;
392255164Sjhibbits
393255164Sjhibbits	return 0;
394255164Sjhibbits}
395255164Sjhibbits
396255164Sjhibbitsstatic int
397255164Sjhibbitsmpc7xxx_write_pmc(int cpu, int ri, pmc_value_t v)
398255164Sjhibbits{
399255164Sjhibbits	struct pmc *pm;
400255164Sjhibbits
401255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
402255164Sjhibbits	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
403255164Sjhibbits	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
404255164Sjhibbits	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
405255164Sjhibbits
406255164Sjhibbits	pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
407255164Sjhibbits
408255164Sjhibbits	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
409255164Sjhibbits		v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
410255164Sjhibbits
411283884Sjhb	PMCDBG3(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v);
412255164Sjhibbits
413255164Sjhibbits	mpc7xxx_pmcn_write(ri, v);
414255164Sjhibbits
415255164Sjhibbits	return 0;
416255164Sjhibbits}
417255164Sjhibbits
418255164Sjhibbitsstatic int
419255164Sjhibbitsmpc7xxx_config_pmc(int cpu, int ri, struct pmc *pm)
420255164Sjhibbits{
421255164Sjhibbits	struct pmc_hw *phw;
422255164Sjhibbits
423283884Sjhb	PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
424255164Sjhibbits
425255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
426255164Sjhibbits	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
427255164Sjhibbits	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
428255164Sjhibbits	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
429255164Sjhibbits
430255164Sjhibbits	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
431255164Sjhibbits
432255164Sjhibbits	KASSERT(pm == NULL || phw->phw_pmc == NULL,
433255164Sjhibbits	    ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
434255164Sjhibbits	    __LINE__, pm, phw->phw_pmc));
435255164Sjhibbits
436255164Sjhibbits	phw->phw_pmc = pm;
437255164Sjhibbits
438255164Sjhibbits	return 0;
439255164Sjhibbits}
440255164Sjhibbits
441255164Sjhibbitsstatic int
442255164Sjhibbitsmpc7xxx_start_pmc(int cpu, int ri)
443255164Sjhibbits{
444255164Sjhibbits	uint32_t config;
445255164Sjhibbits        struct pmc *pm;
446255164Sjhibbits        struct pmc_hw *phw;
447255164Sjhibbits	register_t pmc_mmcr;
448255164Sjhibbits
449255164Sjhibbits	phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
450255164Sjhibbits	pm     = phw->phw_pmc;
451255164Sjhibbits	config = pm->pm_md.pm_powerpc.pm_powerpc_evsel & ~POWERPC_PMC_ENABLE;
452255164Sjhibbits
453255164Sjhibbits	/* Enable the PMC. */
454255164Sjhibbits	switch (ri) {
455255164Sjhibbits	case 0:
456255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
457255164Sjhibbits		pmc_mmcr = PPC_SET_PMC1SEL(pmc_mmcr, config);
458255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
459255164Sjhibbits		break;
460255164Sjhibbits	case 1:
461255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
462255164Sjhibbits		pmc_mmcr = PPC_SET_PMC2SEL(pmc_mmcr, config);
463255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
464255164Sjhibbits		break;
465255164Sjhibbits	case 2:
466255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
467255164Sjhibbits		pmc_mmcr = PPC_SET_PMC3SEL(pmc_mmcr, config);
468255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
469255164Sjhibbits		break;
470255164Sjhibbits	case 3:
471255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
472255164Sjhibbits		pmc_mmcr = PPC_SET_PMC4SEL(pmc_mmcr, config);
473255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
474255164Sjhibbits		break;
475255164Sjhibbits	case 4:
476255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
477255164Sjhibbits		pmc_mmcr = PPC_SET_PMC5SEL(pmc_mmcr, config);
478255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
479255164Sjhibbits		break;
480255164Sjhibbits	case 5:
481255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
482255164Sjhibbits		pmc_mmcr = PPC_SET_PMC6SEL(pmc_mmcr, config);
483255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
484255164Sjhibbits		break;
485255164Sjhibbits	default:
486255164Sjhibbits		break;
487255164Sjhibbits	}
488255164Sjhibbits
489255164Sjhibbits	/* The mask is inverted (enable is 1) compared to the flags in MMCR0, which
490255164Sjhibbits	 * are Freeze flags.
491255164Sjhibbits	 */
492255164Sjhibbits	config = ~pm->pm_md.pm_powerpc.pm_powerpc_evsel & POWERPC_PMC_ENABLE;
493255164Sjhibbits
494255164Sjhibbits	pmc_mmcr = mfspr(SPR_MMCR0);
495255164Sjhibbits	pmc_mmcr &= ~SPR_MMCR0_FC;
496255164Sjhibbits	pmc_mmcr |= config;
497255164Sjhibbits	mtspr(SPR_MMCR0, pmc_mmcr);
498255164Sjhibbits
499255164Sjhibbits	return 0;
500255164Sjhibbits}
501255164Sjhibbits
502255164Sjhibbitsstatic int
503255164Sjhibbitsmpc7xxx_stop_pmc(int cpu, int ri)
504255164Sjhibbits{
505255164Sjhibbits        struct pmc *pm;
506255164Sjhibbits        struct pmc_hw *phw;
507255164Sjhibbits        register_t pmc_mmcr;
508255164Sjhibbits
509255164Sjhibbits	phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
510255164Sjhibbits	pm     = phw->phw_pmc;
511255164Sjhibbits
512255164Sjhibbits	/*
513255164Sjhibbits	 * Disable the PMCs.
514255164Sjhibbits	 */
515255164Sjhibbits	switch (ri) {
516255164Sjhibbits	case 0:
517255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
518255164Sjhibbits		pmc_mmcr = PPC_SET_PMC1SEL(pmc_mmcr, 0);
519255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
520255164Sjhibbits		break;
521255164Sjhibbits	case 1:
522255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
523255164Sjhibbits		pmc_mmcr = PPC_SET_PMC2SEL(pmc_mmcr, 0);
524255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
525255164Sjhibbits		break;
526255164Sjhibbits	case 2:
527255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
528255164Sjhibbits		pmc_mmcr = PPC_SET_PMC3SEL(pmc_mmcr, 0);
529255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
530255164Sjhibbits		break;
531255164Sjhibbits	case 3:
532255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR0);
533255164Sjhibbits		pmc_mmcr = PPC_SET_PMC4SEL(pmc_mmcr, 0);
534255164Sjhibbits		mtspr(SPR_MMCR0, pmc_mmcr);
535255164Sjhibbits		break;
536255164Sjhibbits	case 4:
537255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
538255164Sjhibbits		pmc_mmcr = PPC_SET_PMC5SEL(pmc_mmcr, 0);
539255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
540255164Sjhibbits		break;
541255164Sjhibbits	case 5:
542255164Sjhibbits		pmc_mmcr = mfspr(SPR_MMCR1);
543255164Sjhibbits		pmc_mmcr = PPC_SET_PMC6SEL(pmc_mmcr, 0);
544255164Sjhibbits		mtspr(SPR_MMCR1, pmc_mmcr);
545255164Sjhibbits		break;
546255164Sjhibbits	default:
547255164Sjhibbits		break;
548255164Sjhibbits	}
549255164Sjhibbits	return 0;
550255164Sjhibbits}
551255164Sjhibbits
552255164Sjhibbitsstatic int
553255164Sjhibbitsmpc7xxx_pcpu_init(struct pmc_mdep *md, int cpu)
554255164Sjhibbits{
555255164Sjhibbits	int first_ri, i;
556255164Sjhibbits	struct pmc_cpu *pc;
557255164Sjhibbits	struct powerpc_cpu *pac;
558255164Sjhibbits	struct pmc_hw  *phw;
559255164Sjhibbits
560255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
561255164Sjhibbits	    ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
562283884Sjhb	PMCDBG1(MDP,INI,1,"powerpc-init cpu=%d", cpu);
563255164Sjhibbits
564255164Sjhibbits	powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
565255164Sjhibbits	    M_WAITOK|M_ZERO);
566255164Sjhibbits	pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * MPC7XXX_MAX_PMCS,
567255164Sjhibbits	    M_PMC, M_WAITOK|M_ZERO);
568263122Sjhibbits	pac->pc_class = PMC_CLASS_PPC7450;
569255164Sjhibbits	pc = pmc_pcpu[cpu];
570255164Sjhibbits	first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450].pcd_ri;
571255164Sjhibbits	KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
572255164Sjhibbits
573255164Sjhibbits	for (i = 0, phw = pac->pc_ppcpmcs; i < MPC7XXX_MAX_PMCS; i++, phw++) {
574255164Sjhibbits		phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
575255164Sjhibbits		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
576255164Sjhibbits		phw->phw_pmc      = NULL;
577255164Sjhibbits		pc->pc_hwpmcs[i + first_ri] = phw;
578255164Sjhibbits	}
579255164Sjhibbits
580255164Sjhibbits	/* Clear the MMCRs, and set FC, to disable all PMCs. */
581255164Sjhibbits	mtspr(SPR_MMCR0, SPR_MMCR0_FC | SPR_MMCR0_PMXE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE);
582255164Sjhibbits	mtspr(SPR_MMCR1, 0);
583255164Sjhibbits
584255164Sjhibbits	return 0;
585255164Sjhibbits}
586255164Sjhibbits
587255164Sjhibbitsstatic int
588255164Sjhibbitsmpc7xxx_pcpu_fini(struct pmc_mdep *md, int cpu)
589255164Sjhibbits{
590255164Sjhibbits	uint32_t mmcr0 = mfspr(SPR_MMCR0);
591255164Sjhibbits
592255164Sjhibbits	mmcr0 |= SPR_MMCR0_FC;
593255164Sjhibbits	mtspr(SPR_MMCR0, mmcr0);
594255164Sjhibbits	free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
595255164Sjhibbits	free(powerpc_pcpu[cpu], M_PMC);
596255164Sjhibbits	return 0;
597255164Sjhibbits}
598255164Sjhibbits
599255164Sjhibbitsstatic int
600255164Sjhibbitsmpc7xxx_allocate_pmc(int cpu, int ri, struct pmc *pm,
601255164Sjhibbits  const struct pmc_op_pmcallocate *a)
602255164Sjhibbits{
603255164Sjhibbits	enum pmc_event pe;
604255164Sjhibbits	uint32_t caps, config, counter;
605255164Sjhibbits	int i;
606255164Sjhibbits
607255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
608255164Sjhibbits	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
609255164Sjhibbits	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
610255164Sjhibbits	    ("[powerpc,%d] illegal row index %d", __LINE__, ri));
611255164Sjhibbits
612255164Sjhibbits	caps = a->pm_caps;
613255164Sjhibbits
614255164Sjhibbits	pe = a->pm_ev;
615263122Sjhibbits	for (i = 0; i < mpc7xxx_event_codes_size; i++) {
616263122Sjhibbits		if (mpc7xxx_event_codes[i].pe_ev == pe) {
617263122Sjhibbits			config = mpc7xxx_event_codes[i].pe_code;
618263122Sjhibbits			counter =  mpc7xxx_event_codes[i].pe_counter_mask;
619255164Sjhibbits			break;
620255164Sjhibbits		}
621255164Sjhibbits	}
622263122Sjhibbits	if (i == mpc7xxx_event_codes_size)
623255164Sjhibbits		return (EINVAL);
624255164Sjhibbits
625255164Sjhibbits	if ((counter & (1 << ri)) == 0)
626255164Sjhibbits		return (EINVAL);
627255164Sjhibbits
628255164Sjhibbits	if (caps & PMC_CAP_SYSTEM)
629255164Sjhibbits		config |= POWERPC_PMC_KERNEL_ENABLE;
630255164Sjhibbits	if (caps & PMC_CAP_USER)
631255164Sjhibbits		config |= POWERPC_PMC_USER_ENABLE;
632255164Sjhibbits	if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
633255164Sjhibbits		config |= POWERPC_PMC_ENABLE;
634255164Sjhibbits
635255164Sjhibbits	pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
636255164Sjhibbits
637283884Sjhb	PMCDBG2(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config);
638255164Sjhibbits
639255164Sjhibbits	return 0;
640255164Sjhibbits}
641255164Sjhibbits
642255164Sjhibbitsstatic int
643255164Sjhibbitsmpc7xxx_release_pmc(int cpu, int ri, struct pmc *pmc)
644255164Sjhibbits{
645255164Sjhibbits	struct pmc_hw *phw;
646255164Sjhibbits
647255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
648255164Sjhibbits	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
649255164Sjhibbits	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
650255164Sjhibbits	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
651255164Sjhibbits
652255164Sjhibbits	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
653255164Sjhibbits	KASSERT(phw->phw_pmc == NULL,
654255164Sjhibbits	    ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
655255164Sjhibbits
656255164Sjhibbits	return 0;
657255164Sjhibbits}
658255164Sjhibbits
659255164Sjhibbitsstatic int
660255164Sjhibbitsmpc7xxx_intr(int cpu, struct trapframe *tf)
661255164Sjhibbits{
662255164Sjhibbits	int i, error, retval;
663255164Sjhibbits	uint32_t config;
664255164Sjhibbits	struct pmc *pm;
665255164Sjhibbits	struct powerpc_cpu *pac;
666255164Sjhibbits	pmc_value_t v;
667255164Sjhibbits
668255164Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
669255164Sjhibbits	    ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
670255164Sjhibbits
671283884Sjhb	PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
672255164Sjhibbits	    TRAPF_USERMODE(tf));
673255164Sjhibbits
674255164Sjhibbits	retval = 0;
675255164Sjhibbits
676255164Sjhibbits	pac = powerpc_pcpu[cpu];
677255164Sjhibbits
678255164Sjhibbits	config  = mfspr(SPR_MMCR0);
679255164Sjhibbits	mtspr(SPR_MMCR0, config | SPR_MMCR0_FC);
680255164Sjhibbits
681255164Sjhibbits	/*
682255164Sjhibbits	 * look for all PMCs that have interrupted:
683255164Sjhibbits	 * - look for a running, sampling PMC which has overflowed
684255164Sjhibbits	 *   and which has a valid 'struct pmc' association
685255164Sjhibbits	 *
686255164Sjhibbits	 * If found, we call a helper to process the interrupt.
687255164Sjhibbits	 */
688255164Sjhibbits
689255164Sjhibbits	for (i = 0; i < MPC7XXX_MAX_PMCS; i++) {
690255164Sjhibbits		if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
691255164Sjhibbits		    !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
692255164Sjhibbits			continue;
693255164Sjhibbits		}
694255164Sjhibbits
695255164Sjhibbits		if (!MPC7XXX_PMC_HAS_OVERFLOWED(i))
696255164Sjhibbits			continue;
697255164Sjhibbits
698255164Sjhibbits		retval = 1;	/* Found an interrupting PMC. */
699255164Sjhibbits
700255164Sjhibbits		if (pm->pm_state != PMC_STATE_RUNNING)
701255164Sjhibbits			continue;
702255164Sjhibbits
703255164Sjhibbits		/* Stop the PMC, reload count. */
704255164Sjhibbits		v       = pm->pm_sc.pm_reloadcount;
705255164Sjhibbits		mpc7xxx_pmcn_write(i, v);
706255164Sjhibbits
707255164Sjhibbits		/* Restart the counter if logging succeeded. */
708255164Sjhibbits		error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
709255164Sjhibbits		    TRAPF_USERMODE(tf));
710255164Sjhibbits		if (error != 0)
711255164Sjhibbits			mpc7xxx_stop_pmc(cpu, i);
712255164Sjhibbits		atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
713255164Sjhibbits				&pmc_stats.pm_intr_ignored, 1);
714255164Sjhibbits
715255164Sjhibbits	}
716255164Sjhibbits
717255164Sjhibbits	/* Re-enable PERF exceptions. */
718255164Sjhibbits	mtspr(SPR_MMCR0, config | SPR_MMCR0_PMXE);
719255164Sjhibbits
720255164Sjhibbits	return (retval);
721255164Sjhibbits}
722255164Sjhibbits
723255164Sjhibbitsint
724255164Sjhibbitspmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
725255164Sjhibbits{
726255164Sjhibbits	struct pmc_classdep *pcd;
727255164Sjhibbits
728263122Sjhibbits	pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
729263122Sjhibbits
730255164Sjhibbits	pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_PPC7450];
731255164Sjhibbits	pcd->pcd_caps  = POWERPC_PMC_CAPS;
732255164Sjhibbits	pcd->pcd_class = PMC_CLASS_PPC7450;
733255164Sjhibbits	pcd->pcd_num   = MPC7XXX_MAX_PMCS;
734255164Sjhibbits	pcd->pcd_ri    = pmc_mdep->pmd_npmc;
735255164Sjhibbits	pcd->pcd_width = 32;	/* All PMCs, even in ppc970, are 32-bit */
736255164Sjhibbits
737255164Sjhibbits	pcd->pcd_allocate_pmc   = mpc7xxx_allocate_pmc;
738255164Sjhibbits	pcd->pcd_config_pmc     = mpc7xxx_config_pmc;
739255164Sjhibbits	pcd->pcd_pcpu_fini      = mpc7xxx_pcpu_fini;
740255164Sjhibbits	pcd->pcd_pcpu_init      = mpc7xxx_pcpu_init;
741263122Sjhibbits	pcd->pcd_describe       = powerpc_describe;
742263122Sjhibbits	pcd->pcd_get_config     = powerpc_get_config;
743255164Sjhibbits	pcd->pcd_read_pmc       = mpc7xxx_read_pmc;
744255164Sjhibbits	pcd->pcd_release_pmc    = mpc7xxx_release_pmc;
745255164Sjhibbits	pcd->pcd_start_pmc      = mpc7xxx_start_pmc;
746255164Sjhibbits	pcd->pcd_stop_pmc       = mpc7xxx_stop_pmc;
747255164Sjhibbits 	pcd->pcd_write_pmc      = mpc7xxx_write_pmc;
748255164Sjhibbits
749255164Sjhibbits	pmc_mdep->pmd_npmc   += MPC7XXX_MAX_PMCS;
750263122Sjhibbits	pmc_mdep->pmd_intr   =  mpc7xxx_intr;
751255164Sjhibbits
752263122Sjhibbits	return (0);
753255164Sjhibbits}
754