1147191Sjkoshy/*-
2255164Sjhibbits * Copyright (c) 2011,2013 Justin Hibbits
3147191Sjkoshy * Copyright (c) 2005, Joseph Koshy
4147191Sjkoshy * All rights reserved.
5147191Sjkoshy *
6147191Sjkoshy * Redistribution and use in source and binary forms, with or without
7147191Sjkoshy * modification, are permitted provided that the following conditions
8147191Sjkoshy * are met:
9147191Sjkoshy * 1. Redistributions of source code must retain the above copyright
10147191Sjkoshy *    notice, this list of conditions and the following disclaimer.
11147191Sjkoshy * 2. Redistributions in binary form must reproduce the above copyright
12147191Sjkoshy *    notice, this list of conditions and the following disclaimer in the
13147191Sjkoshy *    documentation and/or other materials provided with the distribution.
14147191Sjkoshy *
15147191Sjkoshy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16147191Sjkoshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17147191Sjkoshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18147191Sjkoshy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19147191Sjkoshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20147191Sjkoshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21147191Sjkoshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22147191Sjkoshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23147191Sjkoshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24147191Sjkoshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25147191Sjkoshy * SUCH DAMAGE.
26147191Sjkoshy *
27147191Sjkoshy */
28147191Sjkoshy
29147191Sjkoshy#include <sys/cdefs.h>
30147191Sjkoshy__FBSDID("$FreeBSD$");
31147191Sjkoshy
32147191Sjkoshy#include <sys/param.h>
33147191Sjkoshy#include <sys/pmc.h>
34228869Sjhibbits#include <sys/pmckern.h>
35262547Sjhibbits#include <sys/sysent.h>
36228869Sjhibbits#include <sys/systm.h>
37147191Sjkoshy
38147191Sjkoshy#include <machine/pmc_mdep.h>
39228869Sjhibbits#include <machine/spr.h>
40255199Sjhibbits#include <machine/pte.h>
41255199Sjhibbits#include <machine/sr.h>
42228869Sjhibbits#include <machine/cpu.h>
43271602Sjhibbits#include <machine/stack.h>
44147191Sjkoshy
45255164Sjhibbits#include "hwpmc_powerpc.h"
46174410Sjkoshy
47271602Sjhibbits#ifdef __powerpc64__
48271602Sjhibbits#define OFFSET 4 /* Account for the TOC reload slot */
49271602Sjhibbits#else
50271602Sjhibbits#define OFFSET 0
51271602Sjhibbits#endif
52185168Sjkoshy
53255228Sjhibbitsstruct powerpc_cpu **powerpc_pcpu;
54255228Sjhibbits
55174410Sjkoshyint
56174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
57174410Sjkoshy    struct trapframe *tf)
58174410Sjkoshy{
59268207Sjhibbits	uintptr_t *osp, *sp;
60271602Sjhibbits	uintptr_t pc;
61255164Sjhibbits	int frames = 0;
62174410Sjkoshy
63259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
64259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
65271602Sjhibbits	osp = (uintptr_t *)PAGE_SIZE;
66228869Sjhibbits
67262547Sjhibbits	for (; frames < maxsamples; frames++) {
68271602Sjhibbits		if (sp <= osp)
69228869Sjhibbits			break;
70271602Sjhibbits	    #ifdef __powerpc64__
71271602Sjhibbits		pc = sp[2];
72271602Sjhibbits	    #else
73271602Sjhibbits		pc = sp[1];
74271602Sjhibbits	    #endif
75271602Sjhibbits		if ((pc & 3) || (pc < 0x100))
76271602Sjhibbits			break;
77271602Sjhibbits
78271602Sjhibbits		/*
79271602Sjhibbits		 * trapexit() and asttrapexit() are sentinels
80271602Sjhibbits		 * for kernel stack tracing.
81271602Sjhibbits		 * */
82271602Sjhibbits		if (pc + OFFSET == (uintptr_t) &trapexit ||
83271602Sjhibbits		    pc + OFFSET == (uintptr_t) &asttrapexit)
84271602Sjhibbits			break;
85271602Sjhibbits
86271602Sjhibbits		cc[frames] = pc;
87268207Sjhibbits		osp = sp;
88255164Sjhibbits		sp = (uintptr_t *)*sp;
89228869Sjhibbits	}
90255164Sjhibbits	return (frames);
91228869Sjhibbits}
92228869Sjhibbits
93228869Sjhibbitsstatic int
94228869Sjhibbitspowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
95228869Sjhibbits{
96262547Sjhibbits
97255164Sjhibbits	return (0);
98228869Sjhibbits}
99228869Sjhibbits
100228869Sjhibbitsstatic int
101228869Sjhibbitspowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
102228869Sjhibbits{
103262547Sjhibbits
104255164Sjhibbits	return (0);
105228869Sjhibbits}
106228869Sjhibbits
107255164Sjhibbitsint
108228869Sjhibbitspowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
109228869Sjhibbits{
110228869Sjhibbits	int error;
111228869Sjhibbits	struct pmc_hw *phw;
112228869Sjhibbits	char powerpc_name[PMC_NAME_MAX];
113228869Sjhibbits
114228869Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
115228869Sjhibbits	    ("[powerpc,%d], illegal CPU %d", __LINE__, cpu));
116228869Sjhibbits
117228869Sjhibbits	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
118228869Sjhibbits	snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri);
119228869Sjhibbits	if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX,
120228869Sjhibbits	    NULL)) != 0)
121228869Sjhibbits		return error;
122261342Sjhibbits	pi->pm_class = powerpc_pcpu[cpu]->pc_class;
123228869Sjhibbits	if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
124228869Sjhibbits		pi->pm_enabled = TRUE;
125228869Sjhibbits		*ppmc          = phw->phw_pmc;
126228869Sjhibbits	} else {
127228869Sjhibbits		pi->pm_enabled = FALSE;
128228869Sjhibbits		*ppmc	       = NULL;
129228869Sjhibbits	}
130228869Sjhibbits
131228869Sjhibbits	return (0);
132228869Sjhibbits}
133228869Sjhibbits
134255164Sjhibbitsint
135228869Sjhibbitspowerpc_get_config(int cpu, int ri, struct pmc **ppm)
136228869Sjhibbits{
137262547Sjhibbits
138228869Sjhibbits	*ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
139228869Sjhibbits
140255164Sjhibbits	return (0);
141228869Sjhibbits}
142228869Sjhibbits
143228869Sjhibbitsstruct pmc_mdep *
144228869Sjhibbitspmc_md_initialize()
145228869Sjhibbits{
146228869Sjhibbits	struct pmc_mdep *pmc_mdep;
147255164Sjhibbits	int error;
148255164Sjhibbits	uint16_t vers;
149228869Sjhibbits
150228869Sjhibbits	/*
151228869Sjhibbits	 * Allocate space for pointers to PMC HW descriptors and for
152228869Sjhibbits	 * the MDEP structure used by MI code.
153228869Sjhibbits	 */
154228869Sjhibbits	powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC,
155228869Sjhibbits			   M_WAITOK|M_ZERO);
156228869Sjhibbits
157228869Sjhibbits	/* Just one class */
158234598Sfabient	pmc_mdep = pmc_mdep_alloc(1);
159228869Sjhibbits
160255164Sjhibbits	vers = mfpvr() >> 16;
161228869Sjhibbits
162228869Sjhibbits	pmc_mdep->pmd_switch_in  = powerpc_switch_in;
163228869Sjhibbits	pmc_mdep->pmd_switch_out = powerpc_switch_out;
164228869Sjhibbits
165255164Sjhibbits	switch (vers) {
166255164Sjhibbits	case MPC7447A:
167255164Sjhibbits	case MPC7448:
168255164Sjhibbits	case MPC7450:
169255164Sjhibbits	case MPC7455:
170255164Sjhibbits	case MPC7457:
171255164Sjhibbits		error = pmc_mpc7xxx_initialize(pmc_mdep);
172261173Sjhibbits		break;
173255164Sjhibbits	case IBM970:
174255164Sjhibbits	case IBM970FX:
175255164Sjhibbits	case IBM970MP:
176261342Sjhibbits		error = pmc_ppc970_initialize(pmc_mdep);
177261342Sjhibbits		break;
178281713Sjhibbits	case FSL_E500v1:
179281713Sjhibbits	case FSL_E500v2:
180281713Sjhibbits	case FSL_E500mc:
181294197Sjhibbits	case FSL_E5500:
182281713Sjhibbits		error = pmc_e500_initialize(pmc_mdep);
183281713Sjhibbits		break;
184255164Sjhibbits	default:
185255164Sjhibbits		error = -1;
186255164Sjhibbits		break;
187255164Sjhibbits	}
188228869Sjhibbits
189255164Sjhibbits	if (error != 0) {
190255164Sjhibbits		pmc_mdep_free(pmc_mdep);
191255164Sjhibbits		pmc_mdep = NULL;
192255164Sjhibbits	}
193255164Sjhibbits
194228869Sjhibbits	return (pmc_mdep);
195228869Sjhibbits}
196228869Sjhibbits
197228869Sjhibbitsvoid
198228869Sjhibbitspmc_md_finalize(struct pmc_mdep *md)
199228869Sjhibbits{
200261342Sjhibbits
201261342Sjhibbits	free(powerpc_pcpu, M_PMC);
202261342Sjhibbits	powerpc_pcpu = NULL;
203228869Sjhibbits}
204228869Sjhibbits
205174410Sjkoshyint
206174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples,
207174410Sjkoshy    struct trapframe *tf)
208174410Sjkoshy{
209268207Sjhibbits	uintptr_t *osp, *sp;
210259395Sjhibbits	int frames = 0;
211259395Sjhibbits
212259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
213259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
214268207Sjhibbits	osp = NULL;
215259395Sjhibbits
216262547Sjhibbits	for (; frames < maxsamples; frames++) {
217271602Sjhibbits		if (sp <= osp)
218259395Sjhibbits			break;
219268207Sjhibbits		osp = sp;
220262547Sjhibbits#ifdef __powerpc64__
221262547Sjhibbits		/* Check if 32-bit mode. */
222262547Sjhibbits		if (!(tf->srr1 & PSL_SF)) {
223268207Sjhibbits			cc[frames] = fuword32((uint32_t *)sp + 1);
224262547Sjhibbits			sp = (uintptr_t *)(uintptr_t)fuword32(sp);
225262547Sjhibbits		} else {
226268207Sjhibbits			cc[frames] = fuword(sp + 2);
227262547Sjhibbits			sp = (uintptr_t *)fuword(sp);
228262547Sjhibbits		}
229262547Sjhibbits#else
230268207Sjhibbits		cc[frames] = fuword32((uint32_t *)sp + 1);
231262547Sjhibbits		sp = (uintptr_t *)fuword32(sp);
232262547Sjhibbits#endif
233259395Sjhibbits	}
234262547Sjhibbits
235259395Sjhibbits	return (frames);
236174410Sjkoshy}
237