hwpmc_powerpc.c revision 261173
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 261173 2014-01-25 22:50:42Z jhibbits $");
31147191Sjkoshy
32147191Sjkoshy#include <sys/param.h>
33147191Sjkoshy#include <sys/pmc.h>
34228869Sjhibbits#include <sys/pmckern.h>
35228869Sjhibbits#include <sys/systm.h>
36147191Sjkoshy
37147191Sjkoshy#include <machine/pmc_mdep.h>
38228869Sjhibbits#include <machine/spr.h>
39255199Sjhibbits#include <machine/pte.h>
40255199Sjhibbits#include <machine/sr.h>
41228869Sjhibbits#include <machine/cpu.h>
42255164Sjhibbits#include <machine/vmparam.h> /* For VM_MIN_KERNEL_ADDRESS/VM_MAX_KERNEL_ADDRESS */
43147191Sjkoshy
44255164Sjhibbits#include "hwpmc_powerpc.h"
45174410Sjkoshy
46255164Sjhibbits#define INKERNEL(x)	(((vm_offset_t)(x)) <= VM_MAX_KERNEL_ADDRESS && \
47255164Sjhibbits		((vm_offset_t)(x)) >= VM_MIN_KERNEL_ADDRESS)
48259395Sjhibbits#define INUSER(x)	(((vm_offset_t)(x)) <= VM_MAXUSER_ADDRESS && \
49259395Sjhibbits		((vm_offset_t)(x)) >= VM_MIN_ADDRESS)
50185168Sjkoshy
51255228Sjhibbitsstruct powerpc_cpu **powerpc_pcpu;
52255228Sjhibbits
53174410Sjkoshyint
54174410Sjkoshypmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
55174410Sjkoshy    struct trapframe *tf)
56174410Sjkoshy{
57255164Sjhibbits	int frames = 0;
58255164Sjhibbits	uintptr_t *sp;
59174410Sjkoshy
60259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
61259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
62228869Sjhibbits
63255164Sjhibbits	for (frames = 1; frames < maxsamples; frames++) {
64255164Sjhibbits		if (!INKERNEL(sp))
65228869Sjhibbits			break;
66259395Sjhibbits		cc[frames++] = sp[1];
67255164Sjhibbits		sp = (uintptr_t *)*sp;
68228869Sjhibbits	}
69255164Sjhibbits	return (frames);
70228869Sjhibbits}
71228869Sjhibbits
72228869Sjhibbitsstatic int
73228869Sjhibbitspowerpc_switch_in(struct pmc_cpu *pc, struct pmc_process *pp)
74228869Sjhibbits{
75255164Sjhibbits	return (0);
76228869Sjhibbits}
77228869Sjhibbits
78228869Sjhibbitsstatic int
79228869Sjhibbitspowerpc_switch_out(struct pmc_cpu *pc, struct pmc_process *pp)
80228869Sjhibbits{
81255164Sjhibbits	return (0);
82228869Sjhibbits}
83228869Sjhibbits
84255164Sjhibbitsint
85228869Sjhibbitspowerpc_describe(int cpu, int ri, struct pmc_info *pi, struct pmc **ppmc)
86228869Sjhibbits{
87228869Sjhibbits	int error;
88228869Sjhibbits	struct pmc_hw *phw;
89228869Sjhibbits	char powerpc_name[PMC_NAME_MAX];
90228869Sjhibbits
91228869Sjhibbits	KASSERT(cpu >= 0 && cpu < pmc_cpu_max(),
92228869Sjhibbits	    ("[powerpc,%d], illegal CPU %d", __LINE__, cpu));
93228869Sjhibbits
94228869Sjhibbits	phw = &powerpc_pcpu[cpu]->pc_ppcpmcs[ri];
95228869Sjhibbits	snprintf(powerpc_name, sizeof(powerpc_name), "POWERPC-%d", ri);
96228869Sjhibbits	if ((error = copystr(powerpc_name, pi->pm_name, PMC_NAME_MAX,
97228869Sjhibbits	    NULL)) != 0)
98228869Sjhibbits		return error;
99228869Sjhibbits	pi->pm_class = PMC_CLASS_PPC7450;
100228869Sjhibbits	if (phw->phw_state & PMC_PHW_FLAG_IS_ENABLED) {
101228869Sjhibbits		pi->pm_enabled = TRUE;
102228869Sjhibbits		*ppmc          = phw->phw_pmc;
103228869Sjhibbits	} else {
104228869Sjhibbits		pi->pm_enabled = FALSE;
105228869Sjhibbits		*ppmc	       = NULL;
106228869Sjhibbits	}
107228869Sjhibbits
108228869Sjhibbits	return (0);
109228869Sjhibbits}
110228869Sjhibbits
111255164Sjhibbitsint
112228869Sjhibbitspowerpc_get_config(int cpu, int ri, struct pmc **ppm)
113228869Sjhibbits{
114228869Sjhibbits	*ppm = powerpc_pcpu[cpu]->pc_ppcpmcs[ri].phw_pmc;
115228869Sjhibbits
116255164Sjhibbits	return (0);
117228869Sjhibbits}
118228869Sjhibbits
119228869Sjhibbitsstruct pmc_mdep *
120228869Sjhibbitspmc_md_initialize()
121228869Sjhibbits{
122228869Sjhibbits	struct pmc_mdep *pmc_mdep;
123255164Sjhibbits	int error;
124255164Sjhibbits	uint16_t vers;
125228869Sjhibbits
126228869Sjhibbits	/*
127228869Sjhibbits	 * Allocate space for pointers to PMC HW descriptors and for
128228869Sjhibbits	 * the MDEP structure used by MI code.
129228869Sjhibbits	 */
130228869Sjhibbits	powerpc_pcpu = malloc(sizeof(struct powerpc_cpu *) * pmc_cpu_max(), M_PMC,
131228869Sjhibbits			   M_WAITOK|M_ZERO);
132228869Sjhibbits
133228869Sjhibbits	/* Just one class */
134234598Sfabient	pmc_mdep = pmc_mdep_alloc(1);
135228869Sjhibbits
136228869Sjhibbits	pmc_mdep->pmd_cputype = PMC_CPU_PPC_7450;
137228869Sjhibbits
138255164Sjhibbits	vers = mfpvr() >> 16;
139228869Sjhibbits
140228869Sjhibbits	pmc_mdep->pmd_switch_in  = powerpc_switch_in;
141228869Sjhibbits	pmc_mdep->pmd_switch_out = powerpc_switch_out;
142228869Sjhibbits
143255164Sjhibbits	switch (vers) {
144255164Sjhibbits	case MPC7447A:
145255164Sjhibbits	case MPC7448:
146255164Sjhibbits	case MPC7450:
147255164Sjhibbits	case MPC7455:
148255164Sjhibbits	case MPC7457:
149255164Sjhibbits		error = pmc_mpc7xxx_initialize(pmc_mdep);
150261173Sjhibbits		break;
151255164Sjhibbits	case IBM970:
152255164Sjhibbits	case IBM970FX:
153255164Sjhibbits	case IBM970MP:
154255164Sjhibbits	default:
155255164Sjhibbits		error = -1;
156255164Sjhibbits		break;
157255164Sjhibbits	}
158228869Sjhibbits
159255164Sjhibbits	if (error != 0) {
160255164Sjhibbits		pmc_mdep_free(pmc_mdep);
161255164Sjhibbits		pmc_mdep = NULL;
162255164Sjhibbits		return NULL;
163255164Sjhibbits	}
164255164Sjhibbits
165228869Sjhibbits	return (pmc_mdep);
166228869Sjhibbits}
167228869Sjhibbits
168228869Sjhibbitsvoid
169228869Sjhibbitspmc_md_finalize(struct pmc_mdep *md)
170228869Sjhibbits{
171228869Sjhibbits	free(md, M_PMC);
172228869Sjhibbits}
173228869Sjhibbits
174174410Sjkoshyint
175174410Sjkoshypmc_save_user_callchain(uintptr_t *cc, int maxsamples,
176174410Sjkoshy    struct trapframe *tf)
177174410Sjkoshy{
178259395Sjhibbits	uintptr_t *sp;
179259395Sjhibbits	int frames = 0;
180259395Sjhibbits
181259395Sjhibbits	cc[frames++] = PMC_TRAPFRAME_TO_PC(tf);
182259395Sjhibbits	sp = (uintptr_t *)PMC_TRAPFRAME_TO_FP(tf);
183259395Sjhibbits
184259395Sjhibbits	for (frames = 1; frames < maxsamples; frames++) {
185259395Sjhibbits		if (!INUSER(sp))
186259395Sjhibbits			break;
187259395Sjhibbits		cc[frames++] = fuword(sp + 1);
188259395Sjhibbits		sp = (uintptr_t *)fuword(sp);
189259395Sjhibbits	}
190259395Sjhibbits	return (frames);
191174410Sjkoshy}
192