1/*-
2 * Copyright (c) 2011 Justin Hibbits
3 * Copyright (c) 2005, Joseph Koshy
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <sys/param.h>
33#include <sys/pmc.h>
34#include <sys/pmckern.h>
35#include <sys/systm.h>
36
37#include <machine/pmc_mdep.h>
38#include <machine/spr.h>
39#include <machine/cpu.h>
40
41#include "hwpmc_powerpc.h"
42
43#define	POWERPC_PMC_CAPS	(PMC_CAP_INTERRUPT | PMC_CAP_USER |     \
44				 PMC_CAP_SYSTEM | PMC_CAP_EDGE |	\
45				 PMC_CAP_THRESHOLD | PMC_CAP_READ |	\
46				 PMC_CAP_WRITE | PMC_CAP_INVERT |	\
47				 PMC_CAP_QUALIFIER)
48
49#define PPC_SET_PMC1SEL(r, x)	((r & ~(SPR_MMCR0_PMC1SEL(0x3f))) | SPR_MMCR0_PMC1SEL(x))
50#define PPC_SET_PMC2SEL(r, x)	((r & ~(SPR_MMCR0_PMC2SEL(0x3f))) | SPR_MMCR0_PMC2SEL(x))
51#define PPC_SET_PMC3SEL(r, x)	((r & ~(SPR_MMCR1_PMC3SEL(0x1f))) | SPR_MMCR1_PMC3SEL(x))
52#define PPC_SET_PMC4SEL(r, x)	((r & ~(SPR_MMCR1_PMC4SEL(0x1f))) | SPR_MMCR1_PMC4SEL(x))
53#define PPC_SET_PMC5SEL(r, x)	((r & ~(SPR_MMCR1_PMC5SEL(0x1f))) | SPR_MMCR1_PMC5SEL(x))
54#define PPC_SET_PMC6SEL(r, x)	((r & ~(SPR_MMCR1_PMC6SEL(0x3f))) | SPR_MMCR1_PMC6SEL(x))
55
56/* Change this when we support more than just the 7450. */
57#define MPC7XXX_MAX_PMCS	6
58
59#define MPC7XXX_PMC_HAS_OVERFLOWED(x) (mpc7xxx_pmcn_read(x) & (0x1 << 31))
60
61/*
62 * Things to improve on this:
63 * - It stops (clears to 0) the PMC and resets it at every context switch
64 *   currently.
65 */
66
67/*
68 * This should work for every 32-bit PowerPC implementation I know of (G3 and G4
69 * specifically).
70 */
71
72struct mpc7xxx_event_code_map {
73	enum pmc_event	pe_ev;       /* enum value */
74	uint8_t         pe_counter_mask;  /* Which counter this can be counted in. */
75	uint8_t		pe_code;     /* numeric code */
76};
77
78#define PPC_PMC_MASK1	0
79#define PPC_PMC_MASK2	1
80#define PPC_PMC_MASK3	2
81#define PPC_PMC_MASK4	3
82#define PPC_PMC_MASK5	4
83#define PPC_PMC_MASK6	5
84#define PPC_PMC_MASK_ALL	0x3f
85#define PMC_POWERPC_EVENT(id, mask, number) \
86	{ .pe_ev = PMC_EV_PPC7450_##id, .pe_counter_mask = mask, .pe_code = number }
87
88static struct mpc7xxx_event_code_map mpc7xxx_event_codes[] = {
89	PMC_POWERPC_EVENT(CYCLE,PPC_PMC_MASK_ALL, 1),
90	PMC_POWERPC_EVENT(INSTR_COMPLETED, 0x0f, 2),
91	PMC_POWERPC_EVENT(TLB_BIT_TRANSITIONS, 0x0f, 3),
92	PMC_POWERPC_EVENT(INSTR_DISPATCHED, 0x0f, 4),
93	PMC_POWERPC_EVENT(PMON_EXCEPT, 0x0f, 5),
94	PMC_POWERPC_EVENT(PMON_SIG, 0x0f, 7),
95	PMC_POWERPC_EVENT(VPU_INSTR_COMPLETED, 0x03, 8),
96	PMC_POWERPC_EVENT(VFPU_INSTR_COMPLETED, 0x03, 9),
97	PMC_POWERPC_EVENT(VIU1_INSTR_COMPLETED, 0x03, 10),
98	PMC_POWERPC_EVENT(VIU2_INSTR_COMPLETED, 0x03, 11),
99	PMC_POWERPC_EVENT(MTVSCR_INSTR_COMPLETED, 0x03, 12),
100	PMC_POWERPC_EVENT(MTVRSAVE_INSTR_COMPLETED, 0x03, 13),
101	PMC_POWERPC_EVENT(VPU_INSTR_WAIT_CYCLES, 0x03, 14),
102	PMC_POWERPC_EVENT(VFPU_INSTR_WAIT_CYCLES, 0x03, 15),
103	PMC_POWERPC_EVENT(VIU1_INSTR_WAIT_CYCLES, 0x03, 16),
104	PMC_POWERPC_EVENT(VIU2_INSTR_WAIT_CYCLES, 0x03, 17),
105	PMC_POWERPC_EVENT(MFVSCR_SYNC_CYCLES, 0x03, 18),
106	PMC_POWERPC_EVENT(VSCR_SAT_SET, 0x03, 19),
107	PMC_POWERPC_EVENT(STORE_INSTR_COMPLETED, 0x03, 20),
108	PMC_POWERPC_EVENT(L1_INSTR_CACHE_MISSES, 0x03, 21),
109	PMC_POWERPC_EVENT(L1_DATA_SNOOPS, 0x03, 22),
110	PMC_POWERPC_EVENT(UNRESOLVED_BRANCHES, 0x01, 23),
111	PMC_POWERPC_EVENT(SPEC_BUFFER_CYCLES, 0x01, 24),
112	PMC_POWERPC_EVENT(BRANCH_UNIT_STALL_CYCLES, 0x01, 25),
113	PMC_POWERPC_EVENT(TRUE_BRANCH_TARGET_HITS, 0x01, 26),
114	PMC_POWERPC_EVENT(BRANCH_LINK_STAC_PREDICTED, 0x01, 27),
115	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_DISPATCHES, 0x01, 28),
116	PMC_POWERPC_EVENT(CYCLES_THREE_INSTR_DISPATCHED, 0x01, 29),
117	PMC_POWERPC_EVENT(THRESHOLD_INSTR_QUEUE_ENTRIES_CYCLES, 0x01, 30),
118	PMC_POWERPC_EVENT(THRESHOLD_VEC_INSTR_QUEUE_ENTRIES_CYCLES, 0x01, 31),
119	PMC_POWERPC_EVENT(CYCLES_NO_COMPLETED_INSTRS, 0x01, 32),
120	PMC_POWERPC_EVENT(IU2_INSTR_COMPLETED, 0x01, 33),
121	PMC_POWERPC_EVENT(BRANCHES_COMPLETED, 0x01, 34),
122	PMC_POWERPC_EVENT(EIEIO_INSTR_COMPLETED, 0x01, 35),
123	PMC_POWERPC_EVENT(MTSPR_INSTR_COMPLETED, 0x01, 36),
124	PMC_POWERPC_EVENT(SC_INSTR_COMPLETED, 0x01, 37),
125	PMC_POWERPC_EVENT(LS_LM_COMPLETED, 0x01, 38),
126	PMC_POWERPC_EVENT(ITLB_HW_TABLE_SEARCH_CYCLES, 0x01, 39),
127	PMC_POWERPC_EVENT(DTLB_HW_SEARCH_CYCLES_OVER_THRESHOLD, 0x01, 40),
128	PMC_POWERPC_EVENT(L1_INSTR_CACHE_ACCESSES, 0x01, 41),
129	PMC_POWERPC_EVENT(INSTR_BKPT_MATCHES, 0x01, 42),
130	PMC_POWERPC_EVENT(L1_DATA_CACHE_LOAD_MISS_CYCLES_OVER_THRESHOLD, 0x01, 43),
131	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_ON_MODIFIED, 0x01, 44),
132	PMC_POWERPC_EVENT(LOAD_MISS_ALIAS, 0x01, 45),
133	PMC_POWERPC_EVENT(LOAD_MISS_ALIAS_ON_TOUCH, 0x01, 46),
134	PMC_POWERPC_EVENT(TOUCH_ALIAS, 0x01, 47),
135	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_CASTOUT_QUEUE, 0x01, 48),
136	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HIT_CASTOUT, 0x01, 49),
137	PMC_POWERPC_EVENT(L1_DATA_SNOOP_HITS, 0x01, 50),
138	PMC_POWERPC_EVENT(WRITE_THROUGH_STORES, 0x01, 51),
139	PMC_POWERPC_EVENT(CACHE_INHIBITED_STORES, 0x01, 52),
140	PMC_POWERPC_EVENT(L1_DATA_LOAD_HIT, 0x01, 53),
141	PMC_POWERPC_EVENT(L1_DATA_TOUCH_HIT, 0x01, 54),
142	PMC_POWERPC_EVENT(L1_DATA_STORE_HIT, 0x01, 55),
143	PMC_POWERPC_EVENT(L1_DATA_TOTAL_HITS, 0x01, 56),
144	PMC_POWERPC_EVENT(DST_INSTR_DISPATCHED, 0x01, 57),
145	PMC_POWERPC_EVENT(REFRESHED_DSTS, 0x01, 58),
146	PMC_POWERPC_EVENT(SUCCESSFUL_DST_TABLE_SEARCHES, 0x01, 59),
147	PMC_POWERPC_EVENT(DSS_INSTR_COMPLETED, 0x01, 60),
148	PMC_POWERPC_EVENT(DST_STREAM_0_CACHE_LINE_FETCHES, 0x01, 61),
149	PMC_POWERPC_EVENT(VTQ_SUSPENDS_DUE_TO_CTX_CHANGE, 0x01, 62),
150	PMC_POWERPC_EVENT(VTQ_LINE_FETCH_HIT, 0x01, 63),
151	PMC_POWERPC_EVENT(VEC_LOAD_INSTR_COMPLETED, 0x01, 64),
152	PMC_POWERPC_EVENT(FP_STORE_INSTR_COMPLETED_IN_LSU, 0x01, 65),
153	PMC_POWERPC_EVENT(FPU_RENORMALIZATION, 0x01, 66),
154	PMC_POWERPC_EVENT(FPU_DENORMALIZATION, 0x01, 67),
155	PMC_POWERPC_EVENT(FP_STORE_CAUSES_STALL_IN_LSU, 0x01, 68),
156	PMC_POWERPC_EVENT(LD_ST_TRUE_ALIAS_STALL, 0x01, 70),
157	PMC_POWERPC_EVENT(LSU_INDEXED_ALIAS_STALL, 0x01, 71),
158	PMC_POWERPC_EVENT(LSU_ALIAS_VS_FSQ_WB0_WB1, 0x01, 72),
159	PMC_POWERPC_EVENT(LSU_ALIAS_VS_CSQ, 0x01, 73),
160	PMC_POWERPC_EVENT(LSU_LOAD_HIT_LINE_ALIAS_VS_CSQ0, 0x01, 74),
161	PMC_POWERPC_EVENT(LSU_LOAD_MISS_LINE_ALIAS_VS_CSQ0, 0x01, 75),
162	PMC_POWERPC_EVENT(LSU_TOUCH_LINE_ALIAS_VS_FSQ_WB0_WB1, 0x01, 76),
163	PMC_POWERPC_EVENT(LSU_TOUCH_ALIAS_VS_CSQ, 0x01, 77),
164	PMC_POWERPC_EVENT(LSU_LMQ_FULL_STALL, 0x01, 78),
165	PMC_POWERPC_EVENT(FP_LOAD_INSTR_COMPLETED_IN_LSU, 0x01, 79),
166	PMC_POWERPC_EVENT(FP_LOAD_SINGLE_INSTR_COMPLETED_IN_LSU, 0x01, 80),
167	PMC_POWERPC_EVENT(FP_LOAD_DOUBLE_COMPLETED_IN_LSU, 0x01, 81),
168	PMC_POWERPC_EVENT(LSU_RA_LATCH_STALL, 0x01, 82),
169	PMC_POWERPC_EVENT(LSU_LOAD_VS_STORE_QUEUE_ALIAS_STALL, 0x01, 83),
170	PMC_POWERPC_EVENT(LSU_LMQ_INDEX_ALIAS, 0x01, 84),
171	PMC_POWERPC_EVENT(LSU_STORE_QUEUE_INDEX_ALIAS, 0x01, 85),
172	PMC_POWERPC_EVENT(LSU_CSQ_FORWARDING, 0x01, 86),
173	PMC_POWERPC_EVENT(LSU_MISALIGNED_LOAD_FINISH, 0x01, 87),
174	PMC_POWERPC_EVENT(LSU_MISALIGN_STORE_COMPLETED, 0x01, 88),
175	PMC_POWERPC_EVENT(LSU_MISALIGN_STALL, 0x01, 89),
176	PMC_POWERPC_EVENT(FP_ONE_QUARTER_FPSCR_RENAMES_BUSY, 0x01, 90),
177	PMC_POWERPC_EVENT(FP_ONE_HALF_FPSCR_RENAMES_BUSY, 0x01, 91),
178	PMC_POWERPC_EVENT(FP_THREE_QUARTERS_FPSCR_RENAMES_BUSY, 0x01, 92),
179	PMC_POWERPC_EVENT(FP_ALL_FPSCR_RENAMES_BUSY, 0x01, 93),
180	PMC_POWERPC_EVENT(FP_DENORMALIZED_RESULT, 0x01, 94),
181	PMC_POWERPC_EVENT(L1_DATA_TOTAL_MISSES, 0x02, 23),
182	PMC_POWERPC_EVENT(DISPATCHES_TO_FPR_ISSUE_QUEUE, 0x02, 24),
183	PMC_POWERPC_EVENT(LSU_INSTR_COMPLETED, 0x02, 25),
184	PMC_POWERPC_EVENT(LOAD_INSTR_COMPLETED, 0x02, 26),
185	PMC_POWERPC_EVENT(SS_SM_INSTR_COMPLETED, 0x02, 27),
186	PMC_POWERPC_EVENT(TLBIE_INSTR_COMPLETED, 0x02, 28),
187	PMC_POWERPC_EVENT(LWARX_INSTR_COMPLETED, 0x02, 29),
188	PMC_POWERPC_EVENT(MFSPR_INSTR_COMPLETED, 0x02, 30),
189	PMC_POWERPC_EVENT(REFETCH_SERIALIZATION, 0x02, 31),
190	PMC_POWERPC_EVENT(COMPLETION_QUEUE_ENTRIES_OVER_THRESHOLD, 0x02, 32),
191	PMC_POWERPC_EVENT(CYCLES_ONE_INSTR_DISPATCHED, 0x02, 33),
192	PMC_POWERPC_EVENT(CYCLES_TWO_INSTR_COMPLETED, 0x02, 34),
193	PMC_POWERPC_EVENT(ITLB_NON_SPECULATIVE_MISSES, 0x02, 35),
194	PMC_POWERPC_EVENT(CYCLES_WAITING_FROM_L1_INSTR_CACHE_MISS, 0x02, 36),
195	PMC_POWERPC_EVENT(L1_DATA_LOAD_ACCESS_MISS, 0x02, 37),
196	PMC_POWERPC_EVENT(L1_DATA_TOUCH_MISS, 0x02, 38),
197	PMC_POWERPC_EVENT(L1_DATA_STORE_MISS, 0x02, 39),
198	PMC_POWERPC_EVENT(L1_DATA_TOUCH_MISS_CYCLES, 0x02, 40),
199	PMC_POWERPC_EVENT(L1_DATA_CYCLES_USED, 0x02, 41),
200	PMC_POWERPC_EVENT(DST_STREAM_1_CACHE_LINE_FETCHES, 0x02, 42),
201	PMC_POWERPC_EVENT(VTQ_STREAM_CANCELED_PREMATURELY, 0x02, 43),
202	PMC_POWERPC_EVENT(VTQ_RESUMES_DUE_TO_CTX_CHANGE, 0x02, 44),
203	PMC_POWERPC_EVENT(VTQ_LINE_FETCH_MISS, 0x02, 45),
204	PMC_POWERPC_EVENT(VTQ_LINE_FETCH, 0x02, 46),
205	PMC_POWERPC_EVENT(TLBIE_SNOOPS, 0x02, 47),
206	PMC_POWERPC_EVENT(L1_INSTR_CACHE_RELOADS, 0x02, 48),
207	PMC_POWERPC_EVENT(L1_DATA_CACHE_RELOADS, 0x02, 49),
208	PMC_POWERPC_EVENT(L1_DATA_CACHE_CASTOUTS_TO_L2, 0x02, 50),
209	PMC_POWERPC_EVENT(STORE_MERGE_GATHER, 0x02, 51),
210	PMC_POWERPC_EVENT(CACHEABLE_STORE_MERGE_TO_32_BYTES, 0x02, 52),
211	PMC_POWERPC_EVENT(DATA_BKPT_MATCHES, 0x02, 53),
212	PMC_POWERPC_EVENT(FALL_THROUGH_BRANCHES_PROCESSED, 0x02, 54),
213	PMC_POWERPC_EVENT(FIRST_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x02, 55),
214	PMC_POWERPC_EVENT(SECOND_SPECULATION_BUFFER_ACTIVE, 0x02, 56),
215	PMC_POWERPC_EVENT(BPU_STALL_ON_LR_DEPENDENCY, 0x02, 57),
216	PMC_POWERPC_EVENT(BTIC_MISS, 0x02, 58),
217	PMC_POWERPC_EVENT(BRANCH_LINK_STACK_CORRECTLY_RESOLVED, 0x02, 59),
218	PMC_POWERPC_EVENT(FPR_ISSUE_STALLED, 0x02, 60),
219	PMC_POWERPC_EVENT(SWITCHES_BETWEEN_PRIV_USER, 0x02, 61),
220	PMC_POWERPC_EVENT(LSU_COMPLETES_FP_STORE_SINGLE, 0x02, 62),
221	PMC_POWERPC_EVENT(CYCLES_TWO_INSTR_COMPLETED, 0x04, 8),
222	PMC_POWERPC_EVENT(CYCLES_ONE_INSTR_DISPATCHED, 0x04, 9),
223	PMC_POWERPC_EVENT(VR_ISSUE_QUEUE_DISPATCHES, 0x04, 10),
224	PMC_POWERPC_EVENT(VR_STALLS, 0x04, 11),
225	PMC_POWERPC_EVENT(GPR_RENAME_BUFFER_ENTRIES_OVER_THRESHOLD, 0x04, 12),
226	PMC_POWERPC_EVENT(FPR_ISSUE_QUEUE_ENTRIES, 0x04, 13),
227	PMC_POWERPC_EVENT(FPU_INSTR_COMPLETED, 0x04, 14),
228	PMC_POWERPC_EVENT(STWCX_INSTR_COMPLETED, 0x04, 15),
229	PMC_POWERPC_EVENT(LS_LM_INSTR_PIECES, 0x04, 16),
230	PMC_POWERPC_EVENT(ITLB_HW_SEARCH_CYCLES_OVER_THRESHOLD, 0x04, 17),
231	PMC_POWERPC_EVENT(DTLB_MISSES, 0x04, 18),
232	PMC_POWERPC_EVENT(CANCELLED_L1_INSTR_CACHE_MISSES, 0x04, 19),
233	PMC_POWERPC_EVENT(L1_DATA_CACHE_OP_HIT, 0x04, 20),
234	PMC_POWERPC_EVENT(L1_DATA_LOAD_MISS_CYCLES, 0x04, 21),
235	PMC_POWERPC_EVENT(L1_DATA_PUSHES, 0x04, 22),
236	PMC_POWERPC_EVENT(L1_DATA_TOTAL_MISS, 0x04, 23),
237	PMC_POWERPC_EVENT(VT2_FETCHES, 0x04, 24),
238	PMC_POWERPC_EVENT(TAKEN_BRANCHES_PROCESSED, 0x04, 25),
239	PMC_POWERPC_EVENT(BRANCH_FLUSHES, 0x04, 26),
240	PMC_POWERPC_EVENT(SECOND_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x04, 27),
241	PMC_POWERPC_EVENT(THIRD_SPECULATION_BUFFER_ACTIVE, 0x04, 28),
242	PMC_POWERPC_EVENT(BRANCH_UNIT_STALL_ON_CTR_DEPENDENCY, 0x04, 29),
243	PMC_POWERPC_EVENT(FAST_BTIC_HIT, 0x04, 30),
244	PMC_POWERPC_EVENT(BRANCH_LINK_STACK_MISPREDICTED, 0x04, 31),
245	PMC_POWERPC_EVENT(CYCLES_THREE_INSTR_COMPLETED, 0x08, 14),
246	PMC_POWERPC_EVENT(CYCLES_NO_INSTR_DISPATCHED, 0x08, 15),
247	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_ENTRIES_OVER_THRESHOLD, 0x08, 16),
248	PMC_POWERPC_EVENT(GPR_ISSUE_QUEUE_STALLED, 0x08, 17),
249	PMC_POWERPC_EVENT(IU1_INSTR_COMPLETED, 0x08, 18),
250	PMC_POWERPC_EVENT(DSSALL_INSTR_COMPLETED, 0x08, 19),
251	PMC_POWERPC_EVENT(TLBSYNC_INSTR_COMPLETED, 0x08, 20),
252	PMC_POWERPC_EVENT(SYNC_INSTR_COMPLETED, 0x08, 21),
253	PMC_POWERPC_EVENT(SS_SM_INSTR_PIECES, 0x08, 22),
254	PMC_POWERPC_EVENT(DTLB_HW_SEARCH_CYCLES, 0x08, 23),
255	PMC_POWERPC_EVENT(SNOOP_RETRIES, 0x08, 24),
256	PMC_POWERPC_EVENT(SUCCESSFUL_STWCX, 0x08, 25),
257	PMC_POWERPC_EVENT(DST_STREAM_3_CACHE_LINE_FETCHES, 0x08, 26),
258	PMC_POWERPC_EVENT(THIRD_SPECULATIVE_BRANCH_BUFFER_RESOLVED_CORRECTLY, 0x08, 27),
259	PMC_POWERPC_EVENT(MISPREDICTED_BRANCHES, 0x08, 28),
260	PMC_POWERPC_EVENT(FOLDED_BRANCHES, 0x08, 29),
261	PMC_POWERPC_EVENT(FP_STORE_DOUBLE_COMPLETES_IN_LSU, 0x08, 30),
262	PMC_POWERPC_EVENT(L2_CACHE_HITS, 0x30, 2),
263	PMC_POWERPC_EVENT(L3_CACHE_HITS, 0x30, 3),
264	PMC_POWERPC_EVENT(L2_INSTR_CACHE_MISSES, 0x30, 4),
265	PMC_POWERPC_EVENT(L3_INSTR_CACHE_MISSES, 0x30, 5),
266	PMC_POWERPC_EVENT(L2_DATA_CACHE_MISSES, 0x30, 6),
267	PMC_POWERPC_EVENT(L3_DATA_CACHE_MISSES, 0x30, 7),
268	PMC_POWERPC_EVENT(L2_LOAD_HITS, 0x10, 8),
269	PMC_POWERPC_EVENT(L2_STORE_HITS, 0x10, 9),
270	PMC_POWERPC_EVENT(L3_LOAD_HITS, 0x10, 10),
271	PMC_POWERPC_EVENT(L3_STORE_HITS, 0x10, 11),
272	PMC_POWERPC_EVENT(L2_TOUCH_HITS, 0x30, 13),
273	PMC_POWERPC_EVENT(L3_TOUCH_HITS, 0x30, 14),
274	PMC_POWERPC_EVENT(SNOOP_RETRIES, 0x30, 15),
275	PMC_POWERPC_EVENT(SNOOP_MODIFIED, 0x10, 16),
276	PMC_POWERPC_EVENT(SNOOP_VALID, 0x10, 17),
277	PMC_POWERPC_EVENT(INTERVENTION, 0x30, 18),
278	PMC_POWERPC_EVENT(L2_CACHE_MISSES, 0x10, 19),
279	PMC_POWERPC_EVENT(L3_CACHE_MISSES, 0x10, 20),
280	PMC_POWERPC_EVENT(L2_CACHE_CASTOUTS, 0x20, 8),
281	PMC_POWERPC_EVENT(L3_CACHE_CASTOUTS, 0x20, 9),
282	PMC_POWERPC_EVENT(L2SQ_FULL_CYCLES, 0x20, 10),
283	PMC_POWERPC_EVENT(L3SQ_FULL_CYCLES, 0x20, 11),
284	PMC_POWERPC_EVENT(RAQ_FULL_CYCLES, 0x20, 16),
285	PMC_POWERPC_EVENT(WAQ_FULL_CYCLES, 0x20, 17),
286	PMC_POWERPC_EVENT(L1_EXTERNAL_INTERVENTIONS, 0x20, 19),
287	PMC_POWERPC_EVENT(L2_EXTERNAL_INTERVENTIONS, 0x20, 20),
288	PMC_POWERPC_EVENT(L3_EXTERNAL_INTERVENTIONS, 0x20, 21),
289	PMC_POWERPC_EVENT(EXTERNAL_INTERVENTIONS, 0x20, 22),
290	PMC_POWERPC_EVENT(EXTERNAL_PUSHES, 0x20, 23),
291	PMC_POWERPC_EVENT(EXTERNAL_SNOOP_RETRY, 0x20, 24),
292	PMC_POWERPC_EVENT(DTQ_FULL_CYCLES, 0x20, 25),
293	PMC_POWERPC_EVENT(BUS_RETRY, 0x20, 26),
294	PMC_POWERPC_EVENT(L2_VALID_REQUEST, 0x20, 27),
295	PMC_POWERPC_EVENT(BORDQ_FULL, 0x20, 28),
296	PMC_POWERPC_EVENT(BUS_TAS_FOR_READS, 0x20, 42),
297	PMC_POWERPC_EVENT(BUS_TAS_FOR_WRITES, 0x20, 43),
298	PMC_POWERPC_EVENT(BUS_READS_NOT_RETRIED, 0x20, 44),
299	PMC_POWERPC_EVENT(BUS_WRITES_NOT_RETRIED, 0x20, 45),
300	PMC_POWERPC_EVENT(BUS_READS_WRITES_NOT_RETRIED, 0x20, 46),
301	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_L1_RETRY, 0x20, 47),
302	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_PREVIOUS_ADJACENT, 0x20, 48),
303	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_COLLISION, 0x20, 49),
304	PMC_POWERPC_EVENT(BUS_RETRY_DUE_TO_INTERVENTION_ORDERING, 0x20, 50),
305	PMC_POWERPC_EVENT(SNOOP_REQUESTS, 0x20, 51),
306	PMC_POWERPC_EVENT(PREFETCH_ENGINE_REQUEST, 0x20, 52),
307	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_LOAD, 0x20, 53),
308	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_STORE, 0x20, 54),
309	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_INSTR_FETCH, 0x20, 55),
310	PMC_POWERPC_EVENT(PREFETCH_ENGINE_COLLISION_VS_LOAD_STORE_INSTR_FETCH, 0x20, 56),
311	PMC_POWERPC_EVENT(PREFETCH_ENGINE_FULL, 0x20, 57)
312};
313
314static pmc_value_t
315mpc7xxx_pmcn_read(unsigned int pmc)
316{
317	switch (pmc) {
318		case 0:
319			return mfspr(SPR_PMC1);
320			break;
321		case 1:
322			return mfspr(SPR_PMC2);
323			break;
324		case 2:
325			return mfspr(SPR_PMC3);
326			break;
327		case 3:
328			return mfspr(SPR_PMC4);
329			break;
330		case 4:
331			return mfspr(SPR_PMC5);
332			break;
333		case 5:
334			return mfspr(SPR_PMC6);
335		default:
336			panic("Invalid PMC number: %d\n", pmc);
337	}
338}
339
340static void
341mpc7xxx_pmcn_write(unsigned int pmc, uint32_t val)
342{
343	switch (pmc) {
344		case 0:
345			mtspr(SPR_PMC1, val);
346			break;
347		case 1:
348			mtspr(SPR_PMC2, val);
349			break;
350		case 2:
351			mtspr(SPR_PMC3, val);
352			break;
353		case 3:
354			mtspr(SPR_PMC4, val);
355			break;
356		case 4:
357			mtspr(SPR_PMC5, val);
358			break;
359		case 5:
360			mtspr(SPR_PMC6, val);
361			break;
362		default:
363			panic("Invalid PMC number: %d\n", pmc);
364	}
365}
366
367static int
368mpc7xxx_read_pmc(int cpu, int ri, pmc_value_t *v)
369{
370	struct pmc *pm;
371	pmc_value_t tmp;
372
373	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
374	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
375	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
376	    ("[powerpc,%d] illegal row index %d", __LINE__, ri));
377
378	pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
379	KASSERT(pm,
380	    ("[core,%d] cpu %d ri %d pmc not configured", __LINE__, cpu,
381		ri));
382
383	tmp = mpc7xxx_pmcn_read(ri);
384	PMCDBG2(MDP,REA,2,"ppc-read id=%d -> %jd", ri, tmp);
385	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
386		*v = POWERPC_PERFCTR_VALUE_TO_RELOAD_COUNT(tmp);
387	else
388		*v = tmp;
389
390	return 0;
391}
392
393static int
394mpc7xxx_write_pmc(int cpu, int ri, pmc_value_t v)
395{
396	struct pmc *pm;
397
398	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
399	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
400	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
401	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
402
403	pm  = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
404
405	if (PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm)))
406		v = POWERPC_RELOAD_COUNT_TO_PERFCTR_VALUE(v);
407
408	PMCDBG3(MDP,WRI,1,"powerpc-write cpu=%d ri=%d v=%jx", cpu, ri, v);
409
410	mpc7xxx_pmcn_write(ri, v);
411
412	return 0;
413}
414
415static int
416mpc7xxx_config_pmc(int cpu, int ri, struct pmc *pm)
417{
418	struct pmc_hw *phw;
419
420	PMCDBG3(MDP,CFG,1, "cpu=%d ri=%d pm=%p", cpu, ri, pm);
421
422	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
423	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
424	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
425	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
426
427	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
428
429	KASSERT(pm == NULL || phw->phw_pmc == NULL,
430	    ("[powerpc,%d] pm=%p phw->pm=%p hwpmc not unconfigured",
431	    __LINE__, pm, phw->phw_pmc));
432
433	phw->phw_pmc = pm;
434
435	return 0;
436}
437
438static int
439mpc7xxx_start_pmc(int cpu, int ri)
440{
441	uint32_t config;
442        struct pmc *pm;
443        struct pmc_hw *phw;
444	register_t pmc_mmcr;
445
446	phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
447	pm     = phw->phw_pmc;
448	config = pm->pm_md.pm_powerpc.pm_powerpc_evsel & ~POWERPC_PMC_ENABLE;
449
450	/* Enable the PMC. */
451	switch (ri) {
452	case 0:
453		pmc_mmcr = mfspr(SPR_MMCR0);
454		pmc_mmcr = PPC_SET_PMC1SEL(pmc_mmcr, config);
455		mtspr(SPR_MMCR0, pmc_mmcr);
456		break;
457	case 1:
458		pmc_mmcr = mfspr(SPR_MMCR0);
459		pmc_mmcr = PPC_SET_PMC2SEL(pmc_mmcr, config);
460		mtspr(SPR_MMCR0, pmc_mmcr);
461		break;
462	case 2:
463		pmc_mmcr = mfspr(SPR_MMCR1);
464		pmc_mmcr = PPC_SET_PMC3SEL(pmc_mmcr, config);
465		mtspr(SPR_MMCR1, pmc_mmcr);
466		break;
467	case 3:
468		pmc_mmcr = mfspr(SPR_MMCR0);
469		pmc_mmcr = PPC_SET_PMC4SEL(pmc_mmcr, config);
470		mtspr(SPR_MMCR0, pmc_mmcr);
471		break;
472	case 4:
473		pmc_mmcr = mfspr(SPR_MMCR1);
474		pmc_mmcr = PPC_SET_PMC5SEL(pmc_mmcr, config);
475		mtspr(SPR_MMCR1, pmc_mmcr);
476		break;
477	case 5:
478		pmc_mmcr = mfspr(SPR_MMCR1);
479		pmc_mmcr = PPC_SET_PMC6SEL(pmc_mmcr, config);
480		mtspr(SPR_MMCR1, pmc_mmcr);
481		break;
482	default:
483		break;
484	}
485
486	/* The mask is inverted (enable is 1) compared to the flags in MMCR0, which
487	 * are Freeze flags.
488	 */
489	config = ~pm->pm_md.pm_powerpc.pm_powerpc_evsel & POWERPC_PMC_ENABLE;
490
491	pmc_mmcr = mfspr(SPR_MMCR0);
492	pmc_mmcr &= ~SPR_MMCR0_FC;
493	pmc_mmcr |= config;
494	mtspr(SPR_MMCR0, pmc_mmcr);
495
496	return 0;
497}
498
499static int
500mpc7xxx_stop_pmc(int cpu, int ri)
501{
502        struct pmc *pm;
503        struct pmc_hw *phw;
504        register_t pmc_mmcr;
505
506	phw    = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
507	pm     = phw->phw_pmc;
508
509	/*
510	 * Disable the PMCs.
511	 */
512	switch (ri) {
513	case 0:
514		pmc_mmcr = mfspr(SPR_MMCR0);
515		pmc_mmcr = PPC_SET_PMC1SEL(pmc_mmcr, 0);
516		mtspr(SPR_MMCR0, pmc_mmcr);
517		break;
518	case 1:
519		pmc_mmcr = mfspr(SPR_MMCR0);
520		pmc_mmcr = PPC_SET_PMC2SEL(pmc_mmcr, 0);
521		mtspr(SPR_MMCR0, pmc_mmcr);
522		break;
523	case 2:
524		pmc_mmcr = mfspr(SPR_MMCR1);
525		pmc_mmcr = PPC_SET_PMC3SEL(pmc_mmcr, 0);
526		mtspr(SPR_MMCR1, pmc_mmcr);
527		break;
528	case 3:
529		pmc_mmcr = mfspr(SPR_MMCR0);
530		pmc_mmcr = PPC_SET_PMC4SEL(pmc_mmcr, 0);
531		mtspr(SPR_MMCR0, pmc_mmcr);
532		break;
533	case 4:
534		pmc_mmcr = mfspr(SPR_MMCR1);
535		pmc_mmcr = PPC_SET_PMC5SEL(pmc_mmcr, 0);
536		mtspr(SPR_MMCR1, pmc_mmcr);
537		break;
538	case 5:
539		pmc_mmcr = mfspr(SPR_MMCR1);
540		pmc_mmcr = PPC_SET_PMC6SEL(pmc_mmcr, 0);
541		mtspr(SPR_MMCR1, pmc_mmcr);
542		break;
543	default:
544		break;
545	}
546	return 0;
547}
548
549static int
550mpc7xxx_pcpu_init(struct pmc_mdep *md, int cpu)
551{
552	int first_ri, i;
553	struct pmc_cpu *pc;
554	struct powerpc_cpu *pac;
555	struct pmc_hw  *phw;
556
557	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
558	    ("[powerpc,%d] wrong cpu number %d", __LINE__, cpu));
559	PMCDBG1(MDP,INI,1,"powerpc-init cpu=%d", cpu);
560
561	powerpc_pcpu[cpu] = pac = malloc(sizeof(struct powerpc_cpu), M_PMC,
562	    M_WAITOK|M_ZERO);
563	pac->pc_ppcpmcs = malloc(sizeof(struct pmc_hw) * MPC7XXX_MAX_PMCS,
564	    M_PMC, M_WAITOK|M_ZERO);
565	pac->pc_class = PMC_CLASS_PPC7450;
566	pc = pmc_pcpu[cpu];
567	first_ri = md->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC].pcd_ri;
568	KASSERT(pc != NULL, ("[powerpc,%d] NULL per-cpu pointer", __LINE__));
569
570	for (i = 0, phw = pac->pc_ppcpmcs; i < MPC7XXX_MAX_PMCS; i++, phw++) {
571		phw->phw_state    = PMC_PHW_FLAG_IS_ENABLED |
572		    PMC_PHW_CPU_TO_STATE(cpu) | PMC_PHW_INDEX_TO_STATE(i);
573		phw->phw_pmc      = NULL;
574		pc->pc_hwpmcs[i + first_ri] = phw;
575	}
576
577	/* Clear the MMCRs, and set FC, to disable all PMCs. */
578	mtspr(SPR_MMCR0, SPR_MMCR0_FC | SPR_MMCR0_PMXE |
579	    SPR_MMCR0_FCECE | SPR_MMCR0_PMC1CE | SPR_MMCR0_PMCNCE);
580	mtspr(SPR_MMCR1, 0);
581
582	return 0;
583}
584
585static int
586mpc7xxx_pcpu_fini(struct pmc_mdep *md, int cpu)
587{
588	uint32_t mmcr0 = mfspr(SPR_MMCR0);
589
590	mtmsr(mfmsr() & ~PSL_PMM);
591	mmcr0 |= SPR_MMCR0_FC;
592	mtspr(SPR_MMCR0, mmcr0);
593
594	free(powerpc_pcpu[cpu]->pc_ppcpmcs, M_PMC);
595	free(powerpc_pcpu[cpu], M_PMC);
596
597	return 0;
598}
599
600static int
601mpc7xxx_allocate_pmc(int cpu, int ri, struct pmc *pm,
602  const struct pmc_op_pmcallocate *a)
603{
604	enum pmc_event pe;
605	uint32_t caps, config, counter;
606	int i;
607
608	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
609	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
610	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
611	    ("[powerpc,%d] illegal row index %d", __LINE__, ri));
612
613	caps = a->pm_caps;
614
615	pe = a->pm_ev;
616	for (i = 0; i < nitems(mpc7xxx_event_codes); i++) {
617		if (mpc7xxx_event_codes[i].pe_ev == pe) {
618			config = mpc7xxx_event_codes[i].pe_code;
619			counter =  mpc7xxx_event_codes[i].pe_counter_mask;
620			break;
621		}
622	}
623	if (i == nitems(mpc7xxx_event_codes))
624		return (EINVAL);
625
626	if ((counter & (1 << ri)) == 0)
627		return (EINVAL);
628
629	if (caps & PMC_CAP_SYSTEM)
630		config |= POWERPC_PMC_KERNEL_ENABLE;
631	if (caps & PMC_CAP_USER)
632		config |= POWERPC_PMC_USER_ENABLE;
633	if ((caps & (PMC_CAP_USER | PMC_CAP_SYSTEM)) == 0)
634		config |= POWERPC_PMC_ENABLE;
635
636	pm->pm_md.pm_powerpc.pm_powerpc_evsel = config;
637
638	PMCDBG2(MDP,ALL,2,"powerpc-allocate ri=%d -> config=0x%x", ri, config);
639
640	return 0;
641}
642
643static int
644mpc7xxx_release_pmc(int cpu, int ri, struct pmc *pmc)
645{
646	struct pmc_hw *phw;
647
648	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
649	    ("[powerpc,%d] illegal CPU value %d", __LINE__, cpu));
650	KASSERT(ri >= 0 && ri < MPC7XXX_MAX_PMCS,
651	    ("[powerpc,%d] illegal row-index %d", __LINE__, ri));
652
653	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
654	KASSERT(phw->phw_pmc == NULL,
655	    ("[powerpc,%d] PHW pmc %p non-NULL", __LINE__, phw->phw_pmc));
656
657	return 0;
658}
659
660static int
661mpc7xxx_intr(int cpu, struct trapframe *tf)
662{
663	int i, error, retval;
664	uint32_t config;
665	struct pmc *pm;
666	struct powerpc_cpu *pac;
667
668	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
669	    ("[powerpc,%d] out of range CPU %d", __LINE__, cpu));
670
671	PMCDBG3(MDP,INT,1, "cpu=%d tf=%p um=%d", cpu, (void *) tf,
672	    TRAPF_USERMODE(tf));
673
674	retval = 0;
675
676	pac = powerpc_pcpu[cpu];
677
678	config  = mfspr(SPR_MMCR0) & ~SPR_MMCR0_FC;
679
680	/*
681	 * look for all PMCs that have interrupted:
682	 * - look for a running, sampling PMC which has overflowed
683	 *   and which has a valid 'struct pmc' association
684	 *
685	 * If found, we call a helper to process the interrupt.
686	 */
687
688	for (i = 0; i < MPC7XXX_MAX_PMCS; i++) {
689		if ((pm = pac->pc_ppcpmcs[i].phw_pmc) == NULL ||
690		    !PMC_IS_SAMPLING_MODE(PMC_TO_MODE(pm))) {
691			continue;
692		}
693
694		if (!MPC7XXX_PMC_HAS_OVERFLOWED(i))
695			continue;
696
697		retval = 1;	/* Found an interrupting PMC. */
698
699		if (pm->pm_state != PMC_STATE_RUNNING)
700			continue;
701
702		/* Stop the counter if logging fails. */
703		error = pmc_process_interrupt(cpu, PMC_HR, pm, tf,
704		    TRAPF_USERMODE(tf));
705		if (error != 0)
706			mpc7xxx_stop_pmc(cpu, i);
707
708		/* reload count. */
709		mpc7xxx_write_pmc(cpu, i, pm->pm_sc.pm_reloadcount);
710	}
711
712	atomic_add_int(retval ? &pmc_stats.pm_intr_processed :
713	    &pmc_stats.pm_intr_ignored, 1);
714
715	/* Re-enable PERF exceptions. */
716	if (retval)
717		mtspr(SPR_MMCR0, config | SPR_MMCR0_PMXE);
718
719	return (retval);
720}
721
722int
723pmc_mpc7xxx_initialize(struct pmc_mdep *pmc_mdep)
724{
725	struct pmc_classdep *pcd;
726
727	pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
728
729	pcd = &pmc_mdep->pmd_classdep[PMC_MDEP_CLASS_INDEX_POWERPC];
730	pcd->pcd_caps  = POWERPC_PMC_CAPS;
731	pcd->pcd_class = PMC_CLASS_PPC7450;
732	pcd->pcd_num   = MPC7XXX_MAX_PMCS;
733	pcd->pcd_ri    = pmc_mdep->pmd_npmc;
734	pcd->pcd_width = 32;	/* All PMCs, even in ppc970, are 32-bit */
735
736	pcd->pcd_allocate_pmc   = mpc7xxx_allocate_pmc;
737	pcd->pcd_config_pmc     = mpc7xxx_config_pmc;
738	pcd->pcd_pcpu_fini      = mpc7xxx_pcpu_fini;
739	pcd->pcd_pcpu_init      = mpc7xxx_pcpu_init;
740	pcd->pcd_describe       = powerpc_describe;
741	pcd->pcd_get_config     = powerpc_get_config;
742	pcd->pcd_read_pmc       = mpc7xxx_read_pmc;
743	pcd->pcd_release_pmc    = mpc7xxx_release_pmc;
744	pcd->pcd_start_pmc      = mpc7xxx_start_pmc;
745	pcd->pcd_stop_pmc       = mpc7xxx_stop_pmc;
746 	pcd->pcd_write_pmc      = mpc7xxx_write_pmc;
747
748	pmc_mdep->pmd_npmc   += MPC7XXX_MAX_PMCS;
749	pmc_mdep->pmd_intr   =  mpc7xxx_intr;
750
751	return (0);
752}
753