1/*
2 * File:         arch/blackfin/oprofile/common.c
3 * Based on:     arch/alpha/oprofile/common.c
4 * Author:       Anton Blanchard <anton@au.ibm.com>
5 *
6 * Created:
7 * Description:
8 *
9 * Modified:
10 *               Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
11 *               Copyright 2004-2006 Analog Devices Inc.
12 *
13 * Bugs:         Enter bugs at http://blackfin.uclinux.org/
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, see the file COPYING, or write
27 * to the Free Software Foundation, Inc.,
28 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
29 */
30
31#include <linux/oprofile.h>
32#include <linux/init.h>
33#include <linux/smp.h>
34#include <linux/errno.h>
35#include <linux/mutex.h>
36
37#include <asm/ptrace.h>
38#include <asm/system.h>
39#include <asm/blackfin.h>
40#include <asm/irq.h>
41#include <asm/io.h>
42
43#include "op_blackfin.h"
44
45#define BFIN_533_ID  0xE5040003
46#define BFIN_537_ID  0xE5040002
47
48static int pfmon_enabled;
49static struct mutex pfmon_lock;
50
51struct op_bfin533_model *model;
52
53struct op_counter_config ctr[OP_MAX_COUNTER];
54
55static int op_bfin_setup(void)
56{
57	int ret;
58
59	/* Pre-compute the values to stuff in the hardware registers.  */
60	spin_lock(&oprofilefs_lock);
61	ret = model->reg_setup(ctr);
62	spin_unlock(&oprofilefs_lock);
63
64	return ret;
65}
66
67static void op_bfin_shutdown(void)
68{
69}
70
71static int op_bfin_start(void)
72{
73	int ret = -EBUSY;
74
75	printk(KERN_INFO "KSDBG:in %s\n", __FUNCTION__);
76	mutex_lock(&pfmon_lock);
77	if (!pfmon_enabled) {
78		ret = model->start(ctr);
79		pfmon_enabled = !ret;
80	}
81	mutex_unlock(&pfmon_lock);
82
83	return ret;
84}
85
86static void op_bfin_stop(void)
87{
88	mutex_lock(&pfmon_lock);
89	if (pfmon_enabled) {
90		model->stop();
91		pfmon_enabled = 0;
92	}
93	mutex_unlock(&pfmon_lock);
94}
95
96static int op_bfin_create_files(struct super_block *sb, struct dentry *root)
97{
98	int i;
99
100	for (i = 0; i < model->num_counters; ++i) {
101		struct dentry *dir;
102		char buf[3];
103		printk(KERN_INFO "Oprofile: creating files... \n");
104
105		snprintf(buf, sizeof buf, "%d", i);
106		dir = oprofilefs_mkdir(sb, root, buf);
107
108		oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
109		oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
110		oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
111		/*
112		 * We dont support per counter user/kernel selection, but
113		 * we leave the entries because userspace expects them
114		 */
115		oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
116		oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
117		oprofilefs_create_ulong(sb, dir, "unit_mask",
118					&ctr[i].unit_mask);
119	}
120
121	return 0;
122}
123int __init oprofile_arch_init(struct oprofile_operations *ops)
124{
125#ifdef CONFIG_HARDWARE_PM
126	unsigned int dspid;
127
128	mutex_init(&pfmon_lock);
129
130	dspid = bfin_read_DSPID();
131
132	printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid);
133
134	switch (dspid) {
135	case BFIN_533_ID:
136		model = &op_model_bfin533;
137		model->num_counters = 2;
138		break;
139	case BFIN_537_ID:
140		model = &op_model_bfin533;
141		model->num_counters = 2;
142		break;
143	default:
144		return -ENODEV;
145	}
146
147	ops->cpu_type = model->name;
148	ops->create_files = op_bfin_create_files;
149	ops->setup = op_bfin_setup;
150	ops->shutdown = op_bfin_shutdown;
151	ops->start = op_bfin_start;
152	ops->stop = op_bfin_stop;
153
154	printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
155	       ops->cpu_type);
156
157	return 0;
158#else
159	return -1;
160#endif
161}
162
163void oprofile_arch_exit(void)
164{
165}
166