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