uperf_ebus.c revision 1.3
1/*	$OpenBSD: uperf_ebus.c,v 1.3 2003/02/17 01:29:20 henric Exp $	*/
2
3/*
4 * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by Jason L. Wright
18 * 4. The name of the author may not be used to endorse or promote products
19 *    derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Effort sponsored in part by the Defense Advanced Research Projects
34 * Agency (DARPA) and Air Force Research Laboratory, Air Force
35 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
36 *
37 */
38
39#include <sys/types.h>
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/device.h>
44#include <sys/conf.h>
45#include <sys/timeout.h>
46
47#include <machine/bus.h>
48#include <machine/autoconf.h>
49#include <machine/openfirm.h>
50
51#include <sparc64/dev/ebusreg.h>
52#include <sparc64/dev/ebusvar.h>
53#include <dev/sun/uperfio.h>
54#include <dev/sbus/uperf_sbusreg.h>
55#include <sparc64/dev/uperfvar.h>
56#include <sparc64/dev/iommureg.h>
57#include <sparc64/dev/psychoreg.h>
58
59struct uperf_ebus_softc {
60	struct uperf_softc	sc_usc;
61	bus_space_tag_t		sc_bus_t;
62	bus_space_handle_t	sc_bus_h;
63};
64
65int	uperf_ebus_match(struct device *, void *, void *);
66void	uperf_ebus_attach(struct device *, struct device *, void *);
67
68struct cfattach uperf_ebus_ca = {
69	sizeof(struct uperf_ebus_softc), uperf_ebus_match, uperf_ebus_attach
70};
71
72u_int32_t uperf_ebus_read_reg(struct uperf_ebus_softc *, bus_size_t);
73void uperf_ebus_write_reg(struct uperf_ebus_softc *,
74    bus_size_t, u_int32_t);
75
76int uperf_ebus_getcnt(void *, int, u_int32_t *, u_int32_t *);
77int uperf_ebus_clrcnt(void *, int);
78int uperf_ebus_getcntsrc(void *, int, u_int *, u_int *);
79int uperf_ebus_setcntsrc(void *, int, u_int, u_int);
80
81struct uperf_src uperf_ebus_srcs[] = {
82	{ UPERFSRC_SDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRA },
83	{ UPERFSRC_SDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWA },
84	{ UPERFSRC_CDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRA },
85	{ UPERFSRC_CDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWA },
86	{ UPERFSRC_SBMA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMA },
87	{ UPERFSRC_DVA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVA },
88	{ UPERFSRC_DVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWA },
89	{ UPERFSRC_PIOA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOA },
90	{ UPERFSRC_SDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRB },
91	{ UPERFSRC_SDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWB },
92	{ UPERFSRC_CDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRB },
93	{ UPERFSRC_CDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWB },
94	{ UPERFSRC_SBMB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMB },
95	{ UPERFSRC_DVB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVB },
96	{ UPERFSRC_DVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWB },
97	{ UPERFSRC_PIOB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOB },
98	{ UPERFSRC_TLBMISS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TLBMISS },
99	{ UPERFSRC_NINTRS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_NINTRS },
100	{ UPERFSRC_INACK, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_INACK },
101	{ UPERFSRC_PIOR, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOR },
102	{ UPERFSRC_PIOW, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOW },
103	{ UPERFSRC_MERGE, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_MERGE },
104	{ UPERFSRC_TBLA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLA },
105	{ UPERFSRC_STCA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCA },
106	{ UPERFSRC_TBLB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLB },
107	{ UPERFSRC_STCB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCB },
108	{ -1, -1, 0 }
109};
110int
111uperf_ebus_match(parent, match, aux)
112	struct device *parent;
113	void *match;
114	void *aux;
115{
116	struct ebus_attach_args *ea = aux;
117
118	return (strcmp(ea->ea_name, "sc") == 0);
119}
120
121void
122uperf_ebus_attach(parent, self, aux)
123	struct device *parent, *self;
124	void *aux;
125{
126	struct uperf_ebus_softc *sc = (void *)self;
127	struct ebus_attach_args *ea = aux;
128	char *model;
129	u_int32_t id;
130
131	sc->sc_bus_t = ea->ea_memtag;
132	sc->sc_usc.usc_cookie = sc;
133	sc->sc_usc.usc_getcntsrc = uperf_ebus_getcntsrc;
134	sc->sc_usc.usc_setcntsrc = uperf_ebus_setcntsrc;
135	sc->sc_usc.usc_clrcnt = uperf_ebus_clrcnt;
136	sc->sc_usc.usc_getcnt = uperf_ebus_getcnt;
137	sc->sc_usc.usc_srcs = uperf_ebus_srcs;
138
139	/* Use prom address if available, otherwise map it. */
140	if (ea->ea_nregs != 1) {
141		printf(": expected 1 register, got %d\n", ea->ea_nregs);
142		return;
143	}
144
145	if (ebus_bus_map(sc->sc_bus_t, 0,
146	    EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size,
147	    0, 0, &sc->sc_bus_h) != 0) {
148		printf(": can't map register space\n");
149		return;
150	}
151
152	id = uperf_ebus_read_reg(sc, USC_ID);
153	model = getpropstring(ea->ea_node, "model");
154	if (model == NULL || strlen(model) == 0)
155		model = "unknown";
156
157	printf(": model %s (%x/%x) ports %d\n", model,
158	    (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S,
159	    (id & USC_ID_VERS_M) >> USC_ID_VERS_S,
160	    (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S);
161}
162
163/*
164 * Read an indirect register.
165 */
166u_int32_t
167uperf_ebus_read_reg(sc, r)
168	struct uperf_ebus_softc *sc;
169	bus_size_t r;
170{
171	u_int32_t v;
172	int s;
173
174	s = splhigh();
175	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
176	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
177	    BUS_SPACE_BARRIER_WRITE);
178
179	/* Can't use multi reads because we have to gaurantee order */
180
181	v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0);
182	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
183	    BUS_SPACE_BARRIER_READ);
184
185	v <<= 8;
186	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1);
187	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
188	    BUS_SPACE_BARRIER_READ);
189
190	v <<= 8;
191	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2);
192	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
193	    BUS_SPACE_BARRIER_READ);
194
195	v <<= 8;
196	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3);
197	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
198	    BUS_SPACE_BARRIER_READ);
199
200	splx(s);
201	return (v);
202}
203
204/*
205 * Write an indirect register.
206 */
207void
208uperf_ebus_write_reg(sc, r, v)
209	struct uperf_ebus_softc *sc;
210	bus_size_t r;
211	u_int32_t v;
212{
213	int s;
214
215	s = splhigh();
216	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
217	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
218	    BUS_SPACE_BARRIER_WRITE);
219
220	/* Can't use multi writes because we have to gaurantee order */
221
222	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0,
223	    (v >> 24) & 0xff);
224	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
225	    BUS_SPACE_BARRIER_WRITE);
226
227	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1,
228	    (v >> 16) & 0xff);
229	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
230	    BUS_SPACE_BARRIER_WRITE);
231
232	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2,
233	    (v >> 8) & 0xff);
234	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
235	    BUS_SPACE_BARRIER_WRITE);
236
237	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3,
238	    (v >> 0) & 0xff);
239	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
240	    BUS_SPACE_BARRIER_WRITE);
241	splx(s);
242}
243
244int
245uperf_ebus_clrcnt(vsc, flags)
246	void *vsc;
247	int flags;
248{
249	struct uperf_ebus_softc *sc = vsc;
250	u_int32_t clr = 0, oldsrc;
251
252	if (flags & UPERF_CNT0)
253		clr |= USC_PCTRL_CLR0;
254	if (flags & UPERF_CNT1)
255		clr |= USC_PCTRL_CLR1;
256	if (clr) {
257		oldsrc = uperf_ebus_read_reg(sc, USC_PERFCTRL);
258		uperf_ebus_write_reg(sc, USC_PERFCTRL, clr | oldsrc);
259	}
260	return (0);
261}
262
263int
264uperf_ebus_setcntsrc(vsc, flags, src0, src1)
265	void *vsc;
266	int flags;
267	u_int src0, src1;
268{
269	struct uperf_ebus_softc *sc = vsc;
270	u_int32_t src;
271
272	src = uperf_ebus_read_reg(sc, USC_PERFCTRL);
273	if (flags & UPERF_CNT0) {
274		src &= ~USC_PCTRL_SEL0;
275		src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0;
276	}
277	if (flags & UPERF_CNT1) {
278		src &= ~USC_PCTRL_SEL1;
279		src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1;
280	}
281	uperf_ebus_write_reg(sc, USC_PERFCTRL, src);
282	return (0);
283}
284
285int
286uperf_ebus_getcntsrc(vsc, flags, srcp0, srcp1)
287	void *vsc;
288	int flags;
289	u_int *srcp0, *srcp1;
290{
291	struct uperf_ebus_softc *sc = vsc;
292	u_int32_t src;
293
294	src = uperf_ebus_read_reg(sc, USC_PERFCTRL);
295	if (flags & UPERF_CNT0)
296		*srcp0 = (src & USC_PCTRL_SEL0) >> 0;
297	if (flags & UPERF_CNT1)
298		*srcp1 = (src & USC_PCTRL_SEL1) >> 8;
299	return (0);
300}
301
302int
303uperf_ebus_getcnt(vsc, flags, cntp0, cntp1)
304	void *vsc;
305	int flags;
306	u_int32_t *cntp0, *cntp1;
307{
308	struct uperf_ebus_softc *sc = vsc;
309	u_int32_t c0, c1;
310
311	c0 = uperf_ebus_read_reg(sc, USC_PERF0);
312	c1 = uperf_ebus_read_reg(sc, USC_PERFSHAD);
313	if (flags & UPERF_CNT0)
314		*cntp0 = c0;
315	if (flags & UPERF_CNT1)
316		*cntp1 = c1;
317	return (0);
318}
319