xref: /openbsd-src/sys/dev/sbus/uperf_sbus.c (revision 22e452df2392a375fd2998343a374f72c327cac3)
1*22e452dfSmpi /*	$OpenBSD: uperf_sbus.c,v 1.11 2022/03/13 13:34:54 mpi Exp $	*/
2c79026dfSjason 
3c79026dfSjason /*
4c79026dfSjason  * Copyright (c) 2002 Jason L. Wright (jason@thought.net)
5c79026dfSjason  * All rights reserved.
6c79026dfSjason  *
7c79026dfSjason  * Redistribution and use in source and binary forms, with or without
8c79026dfSjason  * modification, are permitted provided that the following conditions
9c79026dfSjason  * are met:
10c79026dfSjason  * 1. Redistributions of source code must retain the above copyright
11c79026dfSjason  *    notice, this list of conditions and the following disclaimer.
12c79026dfSjason  * 2. Redistributions in binary form must reproduce the above copyright
13c79026dfSjason  *    notice, this list of conditions and the following disclaimer in the
14c79026dfSjason  *    documentation and/or other materials provided with the distribution.
15c79026dfSjason  *
16c79026dfSjason  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17c79026dfSjason  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18c79026dfSjason  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19c79026dfSjason  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20c79026dfSjason  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21c79026dfSjason  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22c79026dfSjason  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c79026dfSjason  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24c79026dfSjason  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25c79026dfSjason  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26c79026dfSjason  * POSSIBILITY OF SUCH DAMAGE.
275248d82bSjason  *
285248d82bSjason  * Effort sponsored in part by the Defense Advanced Research Projects
295248d82bSjason  * Agency (DARPA) and Air Force Research Laboratory, Air Force
305248d82bSjason  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
315248d82bSjason  *
32c79026dfSjason  */
33c79026dfSjason 
34c79026dfSjason #include <sys/param.h>
35c79026dfSjason #include <sys/systm.h>
36c79026dfSjason #include <sys/kernel.h>
37c79026dfSjason #include <sys/errno.h>
38c79026dfSjason #include <sys/device.h>
39c79026dfSjason #include <sys/malloc.h>
40c79026dfSjason 
41c79026dfSjason #include <machine/bus.h>
42c79026dfSjason #include <machine/intr.h>
43c79026dfSjason #include <machine/autoconf.h>
44c79026dfSjason 
45dfd0dbb2Skettenis #ifdef DDB
46dfd0dbb2Skettenis #include <machine/db_machdep.h>
47dfd0dbb2Skettenis #endif
48dfd0dbb2Skettenis 
49c79026dfSjason #include <arch/sparc64/dev/uperfvar.h>
502631fa9aSjason #include <dev/sun/uperfio.h>
51c79026dfSjason #include <dev/sbus/sbusvar.h>
52c79026dfSjason #include <dev/sbus/uperf_sbusreg.h>
53c79026dfSjason 
54c4071fd1Smillert int uperf_sbus_match(struct device *, void *, void *);
55c4071fd1Smillert void uperf_sbus_attach(struct device *, struct device *, void *);
56c79026dfSjason 
57c79026dfSjason struct uperf_sbus_softc {
58c79026dfSjason 	struct uperf_softc	sc_usc;
59c79026dfSjason 	bus_space_tag_t		sc_bus_t;	/* direct register tag */
60c79026dfSjason 	bus_space_handle_t	sc_bus_h;	/* direct register handle */
61c79026dfSjason };
62c79026dfSjason 
63*22e452dfSmpi const struct cfattach uperf_sbus_ca = {
64c79026dfSjason 	sizeof(struct uperf_sbus_softc), uperf_sbus_match, uperf_sbus_attach
65c79026dfSjason };
66c79026dfSjason 
67c4071fd1Smillert u_int32_t uperf_sbus_read_reg(struct uperf_sbus_softc *, bus_size_t);
68c4071fd1Smillert void uperf_sbus_write_reg(struct uperf_sbus_softc *,
69c4071fd1Smillert     bus_size_t, u_int32_t);
70c79026dfSjason 
71c4071fd1Smillert int uperf_sbus_getcnt(void *, int, u_int32_t *, u_int32_t *);
72c4071fd1Smillert int uperf_sbus_clrcnt(void *, int);
73c4071fd1Smillert int uperf_sbus_getcntsrc(void *, int, u_int *, u_int *);
74c4071fd1Smillert int uperf_sbus_setcntsrc(void *, int, u_int, u_int);
75c79026dfSjason 
76dfd0dbb2Skettenis #ifdef DDB
77dfd0dbb2Skettenis void uperf_sbus_xir(void *, int);
78dfd0dbb2Skettenis #endif
79dfd0dbb2Skettenis 
80c79026dfSjason struct uperf_src uperf_sbus_srcs[] = {
81c79026dfSjason 	{ UPERFSRC_SYSCK, UPERF_CNT0|UPERF_CNT1, SEL0_SYSCK },
82c79026dfSjason 	{ UPERFSRC_PRALL, UPERF_CNT0|UPERF_CNT1, SEL0_PRALL },
83c79026dfSjason 	{ UPERFSRC_PRP0, UPERF_CNT0|UPERF_CNT1, SEL0_PRP0 },
84c79026dfSjason 	{ UPERFSRC_PRU2S, UPERF_CNT0|UPERF_CNT1, SEL0_PRUS },
85c79026dfSjason 	{ UPERFSRC_UPA128, UPERF_CNT0, SEL0_128BUSY },
86c79026dfSjason 	{ UPERFSRC_RP0, UPERF_CNT1, SEL1_RDP0 },
87c79026dfSjason 	{ UPERFSRC_UPA64, UPERF_CNT0, SEL0_64BUSY },
88c79026dfSjason 	{ UPERFSRC_P0CRMR, UPERF_CNT1, SEL1_CRMP0 },
89c79026dfSjason 	{ UPERFSRC_PIOS, UPERF_CNT0, SEL0_PIOSTALL },
90c79026dfSjason 	{ UPERFSRC_P0PIO, UPERF_CNT1, SEL1_PIOP0 },
91c79026dfSjason 	{ UPERFSRC_MEMRI, UPERF_CNT0|UPERF_CNT0, SEL0_MEMREQ },
92c79026dfSjason 	{ UPERFSRC_MCBUSY, UPERF_CNT0, SEL0_MCBUSY },
93c79026dfSjason 	{ UPERFSRC_MEMRC, UPERF_CNT1, SEL1_MRC},
94c79026dfSjason 	{ UPERFSRC_PXSH, UPERF_CNT0, SEL0_PENDSTALL },
95c79026dfSjason 	{ UPERFSRC_RDP0, UPERF_CNT0, SEL1_RDP1 },
96c79026dfSjason 	{ UPERFSRC_P0CWMR, UPERF_CNT0, SEL0_CWMRP0 },
97c79026dfSjason 	{ UPERFSRC_CRMP1, UPERF_CNT1, SEL1_CRMP1 },
98c79026dfSjason 	{ UPERFSRC_P1CWMR, UPERF_CNT0, SEL0_CWMRP1 },
99c79026dfSjason 	{ UPERFSRC_PIOP1, UPERF_CNT1, SEL1_PIOP1 },
100c79026dfSjason 	{ UPERFSRC_CIT, UPERF_CNT0, SEL0_CIT },
101c79026dfSjason 	{ UPERFSRC_CWXI, UPERF_CNT1, SEL1_CWXI },
102c79026dfSjason 	{ UPERFSRC_U2SDAT, UPERF_CNT0|UPERF_CNT1, SEL0_DACT },
103c79026dfSjason 	{ UPERFSRC_CRXI, UPERF_CNT0, SEL0_CRXI },
104c79026dfSjason 	{ -1, -1, 0 }
105c79026dfSjason };
106c79026dfSjason 
107c79026dfSjason int
uperf_sbus_match(struct device * parent,void * vcf,void * aux)1081e9a77deSjason uperf_sbus_match(struct device *parent, void *vcf, void *aux)
109c79026dfSjason {
110c79026dfSjason 	struct sbus_attach_args *sa = aux;
111c79026dfSjason 
112c79026dfSjason 	return (strcmp(sa->sa_name, "sc") == 0);
113c79026dfSjason }
114c79026dfSjason 
115c79026dfSjason void
uperf_sbus_attach(struct device * parent,struct device * self,void * aux)1161e9a77deSjason uperf_sbus_attach(struct device *parent, struct device *self, void *aux)
117c79026dfSjason {
118c79026dfSjason 	struct sbus_attach_args *sa = aux;
119c79026dfSjason 	struct uperf_sbus_softc *sc = (struct uperf_sbus_softc *)self;
120c79026dfSjason 	char *model;
121c79026dfSjason 	u_int32_t id;
122c79026dfSjason 
123c79026dfSjason 	sc->sc_bus_t = sa->sa_bustag;
124c79026dfSjason 	sc->sc_usc.usc_cookie = sc;
125c79026dfSjason 	sc->sc_usc.usc_getcntsrc = uperf_sbus_getcntsrc;
126c79026dfSjason 	sc->sc_usc.usc_setcntsrc = uperf_sbus_setcntsrc;
127c79026dfSjason 	sc->sc_usc.usc_clrcnt = uperf_sbus_clrcnt;
128c79026dfSjason 	sc->sc_usc.usc_getcnt = uperf_sbus_getcnt;
129c79026dfSjason 	sc->sc_usc.usc_srcs = uperf_sbus_srcs;
130c79026dfSjason 
131c79026dfSjason 	if (sa->sa_nreg != 1) {
132c79026dfSjason 		printf(": expected 1 register, got %d\n", sa->sa_nreg);
133c79026dfSjason 		return;
134c79026dfSjason 	}
135c79026dfSjason 
136c79026dfSjason 	if (sbus_bus_map(sc->sc_bus_t, sa->sa_reg[0].sbr_slot,
137a1eb5ed8Sjason 	    sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size, 0, 0,
138a1eb5ed8Sjason 	    &sc->sc_bus_h) != 0) {
139c79026dfSjason 		printf(": couldn't map registers\n");
140c79026dfSjason 		return;
141c79026dfSjason 	}
142c79026dfSjason 
143c79026dfSjason 	id = uperf_sbus_read_reg(sc, USC_ID);
144c79026dfSjason 	model = getpropstring(sa->sa_node, "model");
145c79026dfSjason 	if (model == NULL || strlen(model) == 0)
146c79026dfSjason 		model = "unknown";
147c79026dfSjason 
148c79026dfSjason 	printf(": model %s (%x/%x) ports %d\n", model,
149c79026dfSjason 	    (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S,
150c79026dfSjason 	    (id & USC_ID_VERS_M) >> USC_ID_VERS_S,
151c79026dfSjason 	    (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S);
152dfd0dbb2Skettenis 
153dfd0dbb2Skettenis #ifdef DDB
154dfd0dbb2Skettenis 	db_register_xir(uperf_sbus_xir, sc);
155dfd0dbb2Skettenis #endif
156c79026dfSjason }
157c79026dfSjason 
158c79026dfSjason /*
159c79026dfSjason  * Read from an indirect register
160c79026dfSjason  */
161c79026dfSjason u_int32_t
uperf_sbus_read_reg(struct uperf_sbus_softc * sc,bus_size_t r)1621e9a77deSjason uperf_sbus_read_reg(struct uperf_sbus_softc *sc, bus_size_t r)
163c79026dfSjason {
164c79026dfSjason 	u_int32_t v;
165c79026dfSjason 	int s;
166c79026dfSjason 
167c79026dfSjason 	s = splhigh();
168c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
169c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
170c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
171c79026dfSjason 
1724b1a56afSjsg 	/* Can't use multi reads because we have to guarantee order */
173c79026dfSjason 
174c79026dfSjason 	v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0);
175c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
176c79026dfSjason 	    BUS_SPACE_BARRIER_READ);
177c79026dfSjason 
178c79026dfSjason 	v <<= 8;
179c79026dfSjason 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1);
180c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
181c79026dfSjason 	    BUS_SPACE_BARRIER_READ);
182c79026dfSjason 
183c79026dfSjason 	v <<= 8;
184c79026dfSjason 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2);
185c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
186c79026dfSjason 	    BUS_SPACE_BARRIER_READ);
187c79026dfSjason 
188c79026dfSjason 	v <<= 8;
189c79026dfSjason 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3);
190c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
191c79026dfSjason 	    BUS_SPACE_BARRIER_READ);
192c79026dfSjason 
193c79026dfSjason 	splx(s);
194c79026dfSjason 	return (v);
195c79026dfSjason }
196c79026dfSjason 
197c79026dfSjason /*
198c79026dfSjason  * Write to an indirect register
199c79026dfSjason  */
200c79026dfSjason void
uperf_sbus_write_reg(struct uperf_sbus_softc * sc,bus_size_t r,u_int32_t v)2011e9a77deSjason uperf_sbus_write_reg(struct uperf_sbus_softc *sc, bus_size_t r, u_int32_t v)
202c79026dfSjason {
203c79026dfSjason 	int s;
204c79026dfSjason 
205c79026dfSjason 	s = splhigh();
206c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
207c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
208c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
209c79026dfSjason 
2104b1a56afSjsg 	/* Can't use multi writes because we have to guarantee order */
211c79026dfSjason 
212c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0,
213c79026dfSjason 	    (v >> 24) & 0xff);
214c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
215c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
216c79026dfSjason 
217c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1,
218c79026dfSjason 	    (v >> 16) & 0xff);
219c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
220c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
221c79026dfSjason 
222c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2,
223c79026dfSjason 	    (v >> 8) & 0xff);
224c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
225c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
226c79026dfSjason 
227c79026dfSjason 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3,
228c79026dfSjason 	    (v >> 0) & 0xff);
229c79026dfSjason 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
230c79026dfSjason 	    BUS_SPACE_BARRIER_WRITE);
231c79026dfSjason 	splx(s);
232c79026dfSjason }
233c79026dfSjason 
234c79026dfSjason int
uperf_sbus_clrcnt(void * vsc,int flags)2351e9a77deSjason uperf_sbus_clrcnt(void *vsc, int flags)
236c79026dfSjason {
237c79026dfSjason 	struct uperf_sbus_softc *sc = vsc;
238c79026dfSjason 	u_int32_t clr = 0, oldsrc;
239c79026dfSjason 
240c79026dfSjason 	if (flags & UPERF_CNT0)
241c79026dfSjason 		clr |= USC_PCTRL_CLR0;
242c79026dfSjason 	if (flags & UPERF_CNT1)
243c79026dfSjason 		clr |= USC_PCTRL_CLR1;
244c79026dfSjason 	if (clr) {
245c79026dfSjason 		oldsrc = uperf_sbus_read_reg(sc, USC_PERFCTRL);
246c79026dfSjason 		uperf_sbus_write_reg(sc, USC_PERFCTRL, clr | oldsrc);
247c79026dfSjason 	}
248c79026dfSjason 	return (0);
249c79026dfSjason }
250c79026dfSjason 
251c79026dfSjason int
uperf_sbus_setcntsrc(void * vsc,int flags,u_int src0,u_int src1)2521e9a77deSjason uperf_sbus_setcntsrc(void *vsc, int flags, u_int src0, u_int src1)
253c79026dfSjason {
254c79026dfSjason 	struct uperf_sbus_softc *sc = vsc;
255c79026dfSjason 	u_int32_t src;
256c79026dfSjason 
257c79026dfSjason 	src = uperf_sbus_read_reg(sc, USC_PERFCTRL);
258c79026dfSjason 	if (flags & UPERF_CNT0) {
259c79026dfSjason 		src &= ~USC_PCTRL_SEL0;
260c79026dfSjason 		src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0;
261c79026dfSjason 	}
262c79026dfSjason 	if (flags & UPERF_CNT1) {
263c79026dfSjason 		src &= ~USC_PCTRL_SEL1;
264c79026dfSjason 		src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1;
265c79026dfSjason 	}
266c79026dfSjason 	uperf_sbus_write_reg(sc, USC_PERFCTRL, src);
267c79026dfSjason 	return (0);
268c79026dfSjason }
269c79026dfSjason 
270c79026dfSjason int
uperf_sbus_getcntsrc(void * vsc,int flags,u_int * srcp0,u_int * srcp1)2711e9a77deSjason uperf_sbus_getcntsrc(void *vsc, int flags, u_int *srcp0, u_int *srcp1)
272c79026dfSjason {
273c79026dfSjason 	struct uperf_sbus_softc *sc = vsc;
274c79026dfSjason 	u_int32_t src;
275c79026dfSjason 
276c79026dfSjason 	src = uperf_sbus_read_reg(sc, USC_PERFCTRL);
277c79026dfSjason 	if (flags & UPERF_CNT0)
278c79026dfSjason 		*srcp0 = (src & USC_PCTRL_SEL0) >> 0;
279c79026dfSjason 	if (flags & UPERF_CNT1)
280c79026dfSjason 		*srcp1 = (src & USC_PCTRL_SEL1) >> 8;
281c79026dfSjason 	return (0);
282c79026dfSjason }
283c79026dfSjason 
284c79026dfSjason int
uperf_sbus_getcnt(void * vsc,int flags,u_int32_t * cntp0,u_int32_t * cntp1)2851e9a77deSjason uperf_sbus_getcnt(void *vsc, int flags, u_int32_t *cntp0, u_int32_t *cntp1)
286c79026dfSjason {
287c79026dfSjason 	struct uperf_sbus_softc *sc = vsc;
288c79026dfSjason 	u_int32_t c0, c1;
289c79026dfSjason 
290c79026dfSjason 	c0 = uperf_sbus_read_reg(sc, USC_PERF0);
291c79026dfSjason 	c1 = uperf_sbus_read_reg(sc, USC_PERFSHAD);
292c79026dfSjason 	if (flags & UPERF_CNT0)
293c79026dfSjason 		*cntp0 = c0;
294c79026dfSjason 	if (flags & UPERF_CNT1)
295c79026dfSjason 		*cntp1 = c1;
296c79026dfSjason 	return (0);
297c79026dfSjason }
298dfd0dbb2Skettenis 
299dfd0dbb2Skettenis #ifdef DDB
300dfd0dbb2Skettenis void
uperf_sbus_xir(void * arg,int cpu)301dfd0dbb2Skettenis uperf_sbus_xir(void *arg, int cpu)
302dfd0dbb2Skettenis {
303dfd0dbb2Skettenis 	struct uperf_sbus_softc *sc = arg;
304dfd0dbb2Skettenis 
305dfd0dbb2Skettenis 	uperf_sbus_write_reg(sc, USC_CTRL, USC_CTRL_XIR);
306dfd0dbb2Skettenis }
307dfd0dbb2Skettenis #endif
308