hwpmc_powerpc.c revision 268207
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: head/sys/dev/hwpmc/hwpmc_powerpc.c 268207 2014-07-03 06:52:26Z jhibbits $");
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>
43255164Sjhibbits#include <machine/vmparam.h> /* For VM_MIN_KERNEL_ADDRESS/VM_MAX_KERNEL_ADDRESS */
44147191Sjkoshy
45255164Sjhibbits#include "hwpmc_powerpc.h"
46174410Sjkoshy
47255164Sjhibbits#define INKERNEL(x)	(((vm_offset_t)(x)) <= VM_MAX_KERNEL_ADDRESS && \
48255164Sjhibbits		((vm_offset_t)(x)) >= VM_MIN_KERNEL_ADDRESS)
49259395Sjhibbits#define INUSER(x)	(((vm_offset_t)(x)) <= VM_MAXUSER_ADDRESS && \
50259395Sjhibbits		((vm_offset_t)(x)) >= VM_MIN_ADDRESS)
51185168Sjkoshy
52255228Sjhibbitsstruct powerpc_cpu **powerpc_pcpu;
53255228Sjhibbits
54174410Sjkoshyint
55174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
56174410Sjkoshy    struct trapframe *tf)
57174410Sjkoshy{
58268207Sjhibbits	uintptr_t *osp, *sp;
59255164Sjhibbits	int frames = 0;
60174410Sjkoshy
61259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
62259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
63268207Sjhibbits	osp = NULL;
64228869Sjhibbits
65262547Sjhibbits	for (; frames < maxsamples; frames++) {
66268207Sjhibbits		if (!INKERNEL(sp) || sp <= osp)
67228869Sjhibbits			break;
68262547Sjhibbits#ifdef __powerpc64__
69268207Sjhibbits		cc[frames] = sp[2];
70262547Sjhibbits#else
71268207Sjhibbits		cc[frames] = sp[1];
72262547Sjhibbits#endif
73268207Sjhibbits		osp = sp;
74255164Sjhibbits		sp = (uintptr_t *)*sp;
75228869Sjhibbits	}
76255164Sjhibbits	return (frames);
77228869Sjhibbits}
78228869Sjhibbits
79228869Sjhibbitsstatic int
80228869Sjhibbitspowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
81228869Sjhibbits{
82262547Sjhibbits
83255164Sjhibbits	return (0);
84228869Sjhibbits}
85228869Sjhibbits
86228869Sjhibbitsstatic int
87228869Sjhibbitspowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
88228869Sjhibbits{
89262547Sjhibbits
90255164Sjhibbits	return (0);
91228869Sjhibbits}
92228869Sjhibbits
93255164Sjhibbitsint
94228869Sjhibbitspowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
95228869Sjhibbits{
96228869Sjhibbits	int error;
97228869Sjhibbits	struct pmc_hw *phw;
98228869Sjhibbits	char powerpc_name[PMC_NAME_MAX];
99228869Sjhibbits
100228869Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
101228869Sjhibbits	    ("[powerpc,%d], illegal CPU %d", __LINE__, cpu));
102228869Sjhibbits
103228869Sjhibbits	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
104228869Sjhibbits	snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri);
105228869Sjhibbits	if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX,
106228869Sjhibbits	    NULL)) != 0)
107228869Sjhibbits		return error;
108261342Sjhibbits	pi->pm_class = powerpc_pcpu[cpu]->pc_class;
109228869Sjhibbits	if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
110228869Sjhibbits		pi->pm_enabled = TRUE;
111228869Sjhibbits		*ppmc          = phw->phw_pmc;
112228869Sjhibbits	} else {
113228869Sjhibbits		pi->pm_enabled = FALSE;
114228869Sjhibbits		*ppmc	       = NULL;
115228869Sjhibbits	}
116228869Sjhibbits
117228869Sjhibbits	return (0);
118228869Sjhibbits}
119228869Sjhibbits
120255164Sjhibbitsint
121228869Sjhibbitspowerpc_get_config(int cpu, int ri, struct pmc **ppm)
122228869Sjhibbits{
123262547Sjhibbits
124228869Sjhibbits	*ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
125228869Sjhibbits
126255164Sjhibbits	return (0);
127228869Sjhibbits}
128228869Sjhibbits
129228869Sjhibbitsstruct pmc_mdep *
130228869Sjhibbitspmc_md_initialize()
131228869Sjhibbits{
132228869Sjhibbits	struct pmc_mdep *pmc_mdep;
133255164Sjhibbits	int error;
134255164Sjhibbits	uint16_t vers;
135228869Sjhibbits
136228869Sjhibbits	/*
137228869Sjhibbits	 * Allocate space for pointers to PMC HW descriptors and for
138228869Sjhibbits	 * the MDEP structure used by MI code.
139228869Sjhibbits	 */
140228869Sjhibbits	powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC,
141228869Sjhibbits			   M_WAITOK|M_ZERO);
142228869Sjhibbits
143228869Sjhibbits	/* Just one class */
144234598Sfabient	pmc_mdep = pmc_mdep_alloc(1);
145228869Sjhibbits
146255164Sjhibbits	vers = mfpvr() >> 16;
147228869Sjhibbits
148228869Sjhibbits	pmc_mdep->pmd_switch_in  = powerpc_switch_in;
149228869Sjhibbits	pmc_mdep->pmd_switch_out = powerpc_switch_out;
150228869Sjhibbits
151255164Sjhibbits	switch (vers) {
152255164Sjhibbits	case MPC7447A:
153255164Sjhibbits	case MPC7448:
154255164Sjhibbits	case MPC7450:
155255164Sjhibbits	case MPC7455:
156255164Sjhibbits	case MPC7457:
157255164Sjhibbits		error = pmc_mpc7xxx_initialize(pmc_mdep);
158261173Sjhibbits		break;
159255164Sjhibbits	case IBM970:
160255164Sjhibbits	case IBM970FX:
161255164Sjhibbits	case IBM970MP:
162261342Sjhibbits		error = pmc_ppc970_initialize(pmc_mdep);
163261342Sjhibbits		break;
164255164Sjhibbits	default:
165255164Sjhibbits		error = -1;
166255164Sjhibbits		break;
167255164Sjhibbits	}
168228869Sjhibbits
169255164Sjhibbits	if (error != 0) {
170255164Sjhibbits		pmc_mdep_free(pmc_mdep);
171255164Sjhibbits		pmc_mdep = NULL;
172255164Sjhibbits	}
173255164Sjhibbits
174228869Sjhibbits	return (pmc_mdep);
175228869Sjhibbits}
176228869Sjhibbits
177228869Sjhibbitsvoid
178228869Sjhibbitspmc_md_finalize(struct pmc_mdep *md)
179228869Sjhibbits{
180261342Sjhibbits
181261342Sjhibbits	free(powerpc_pcpu, M_PMC);
182261342Sjhibbits	powerpc_pcpu = NULL;
183228869Sjhibbits}
184228869Sjhibbits
185174410Sjkoshyint
186174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples,
187174410Sjkoshy    struct trapframe *tf)
188174410Sjkoshy{
189268207Sjhibbits	uintptr_t *osp, *sp;
190259395Sjhibbits	int frames = 0;
191259395Sjhibbits
192259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
193259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
194268207Sjhibbits	osp = NULL;
195259395Sjhibbits
196262547Sjhibbits	for (; frames < maxsamples; frames++) {
197268207Sjhibbits		if (!INUSER(sp) || sp <= osp)
198259395Sjhibbits			break;
199268207Sjhibbits		osp = sp;
200262547Sjhibbits#ifdef __powerpc64__
201262547Sjhibbits		/* Check if 32-bit mode. */
202262547Sjhibbits		if (!(tf->srr1 & PSL_SF)) {
203268207Sjhibbits			cc[frames] = fuword32((uint32_t *)sp + 1);
204262547Sjhibbits			sp = (uintptr_t *)(uintptr_t)fuword32(sp);
205262547Sjhibbits		} else {
206268207Sjhibbits			cc[frames] = fuword(sp + 2);
207262547Sjhibbits			sp = (uintptr_t *)fuword(sp);
208262547Sjhibbits		}
209262547Sjhibbits#else
210268207Sjhibbits		cc[frames] = fuword32((uint32_t *)sp + 1);
211262547Sjhibbits		sp = (uintptr_t *)fuword32(sp);
212262547Sjhibbits#endif
213259395Sjhibbits	}
214262547Sjhibbits
215259395Sjhibbits	return (frames);
216174410Sjkoshy}
217