xref: /openbsd/sys/dev/sbus/uperf_sbus.c (revision 5af055cd)
1 /*	$OpenBSD: uperf_sbus.c,v 1.8 2008/12/15 22:35:06 kettenis 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/types.h>
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/errno.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 
42 #include <machine/bus.h>
43 #include <machine/intr.h>
44 #include <machine/autoconf.h>
45 
46 #ifdef DDB
47 #include <machine/db_machdep.h>
48 #endif
49 
50 #include <arch/sparc64/dev/uperfvar.h>
51 #include <dev/sun/uperfio.h>
52 #include <dev/sbus/sbusvar.h>
53 #include <dev/sbus/uperf_sbusreg.h>
54 
55 int uperf_sbus_match(struct device *, void *, void *);
56 void uperf_sbus_attach(struct device *, struct device *, void *);
57 
58 struct uperf_sbus_softc {
59 	struct uperf_softc	sc_usc;
60 	bus_space_tag_t		sc_bus_t;	/* direct register tag */
61 	bus_space_handle_t	sc_bus_h;	/* direct register handle */
62 };
63 
64 struct cfattach uperf_sbus_ca = {
65 	sizeof(struct uperf_sbus_softc), uperf_sbus_match, uperf_sbus_attach
66 };
67 
68 u_int32_t uperf_sbus_read_reg(struct uperf_sbus_softc *, bus_size_t);
69 void uperf_sbus_write_reg(struct uperf_sbus_softc *,
70     bus_size_t, u_int32_t);
71 
72 int uperf_sbus_getcnt(void *, int, u_int32_t *, u_int32_t *);
73 int uperf_sbus_clrcnt(void *, int);
74 int uperf_sbus_getcntsrc(void *, int, u_int *, u_int *);
75 int uperf_sbus_setcntsrc(void *, int, u_int, u_int);
76 
77 #ifdef DDB
78 void uperf_sbus_xir(void *, int);
79 #endif
80 
81 struct uperf_src uperf_sbus_srcs[] = {
82 	{ UPERFSRC_SYSCK, UPERF_CNT0|UPERF_CNT1, SEL0_SYSCK },
83 	{ UPERFSRC_PRALL, UPERF_CNT0|UPERF_CNT1, SEL0_PRALL },
84 	{ UPERFSRC_PRP0, UPERF_CNT0|UPERF_CNT1, SEL0_PRP0 },
85 	{ UPERFSRC_PRU2S, UPERF_CNT0|UPERF_CNT1, SEL0_PRUS },
86 	{ UPERFSRC_UPA128, UPERF_CNT0, SEL0_128BUSY },
87 	{ UPERFSRC_RP0, UPERF_CNT1, SEL1_RDP0 },
88 	{ UPERFSRC_UPA64, UPERF_CNT0, SEL0_64BUSY },
89 	{ UPERFSRC_P0CRMR, UPERF_CNT1, SEL1_CRMP0 },
90 	{ UPERFSRC_PIOS, UPERF_CNT0, SEL0_PIOSTALL },
91 	{ UPERFSRC_P0PIO, UPERF_CNT1, SEL1_PIOP0 },
92 	{ UPERFSRC_MEMRI, UPERF_CNT0|UPERF_CNT0, SEL0_MEMREQ },
93 	{ UPERFSRC_MCBUSY, UPERF_CNT0, SEL0_MCBUSY },
94 	{ UPERFSRC_MEMRC, UPERF_CNT1, SEL1_MRC},
95 	{ UPERFSRC_PXSH, UPERF_CNT0, SEL0_PENDSTALL },
96 	{ UPERFSRC_RDP0, UPERF_CNT0, SEL1_RDP1 },
97 	{ UPERFSRC_P0CWMR, UPERF_CNT0, SEL0_CWMRP0 },
98 	{ UPERFSRC_CRMP1, UPERF_CNT1, SEL1_CRMP1 },
99 	{ UPERFSRC_P1CWMR, UPERF_CNT0, SEL0_CWMRP1 },
100 	{ UPERFSRC_PIOP1, UPERF_CNT1, SEL1_PIOP1 },
101 	{ UPERFSRC_CIT, UPERF_CNT0, SEL0_CIT },
102 	{ UPERFSRC_CWXI, UPERF_CNT1, SEL1_CWXI },
103 	{ UPERFSRC_U2SDAT, UPERF_CNT0|UPERF_CNT1, SEL0_DACT },
104 	{ UPERFSRC_CRXI, UPERF_CNT0, SEL0_CRXI },
105 	{ -1, -1, 0 }
106 };
107 
108 int
109 uperf_sbus_match(struct device *parent, void *vcf, void *aux)
110 {
111 	struct sbus_attach_args *sa = aux;
112 
113 	return (strcmp(sa->sa_name, "sc") == 0);
114 }
115 
116 void
117 uperf_sbus_attach(struct device *parent, struct device *self, void *aux)
118 {
119 	struct sbus_attach_args *sa = aux;
120 	struct uperf_sbus_softc *sc = (struct uperf_sbus_softc *)self;
121 	char *model;
122 	u_int32_t id;
123 
124 	sc->sc_bus_t = sa->sa_bustag;
125 	sc->sc_usc.usc_cookie = sc;
126 	sc->sc_usc.usc_getcntsrc = uperf_sbus_getcntsrc;
127 	sc->sc_usc.usc_setcntsrc = uperf_sbus_setcntsrc;
128 	sc->sc_usc.usc_clrcnt = uperf_sbus_clrcnt;
129 	sc->sc_usc.usc_getcnt = uperf_sbus_getcnt;
130 	sc->sc_usc.usc_srcs = uperf_sbus_srcs;
131 
132 	if (sa->sa_nreg != 1) {
133 		printf(": expected 1 register, got %d\n", sa->sa_nreg);
134 		return;
135 	}
136 
137 	if (sbus_bus_map(sc->sc_bus_t, sa->sa_reg[0].sbr_slot,
138 	    sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size, 0, 0,
139 	    &sc->sc_bus_h) != 0) {
140 		printf(": couldn't map registers\n");
141 		return;
142 	}
143 
144 	id = uperf_sbus_read_reg(sc, USC_ID);
145 	model = getpropstring(sa->sa_node, "model");
146 	if (model == NULL || strlen(model) == 0)
147 		model = "unknown";
148 
149 	printf(": model %s (%x/%x) ports %d\n", model,
150 	    (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S,
151 	    (id & USC_ID_VERS_M) >> USC_ID_VERS_S,
152 	    (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S);
153 
154 #ifdef DDB
155 	db_register_xir(uperf_sbus_xir, sc);
156 #endif
157 }
158 
159 /*
160  * Read from an indirect register
161  */
162 u_int32_t
163 uperf_sbus_read_reg(struct uperf_sbus_softc *sc, bus_size_t r)
164 {
165 	u_int32_t v;
166 	int s;
167 
168 	s = splhigh();
169 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
170 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
171 	    BUS_SPACE_BARRIER_WRITE);
172 
173 	/* Can't use multi reads because we have to gaurantee order */
174 
175 	v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0);
176 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
177 	    BUS_SPACE_BARRIER_READ);
178 
179 	v <<= 8;
180 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1);
181 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
182 	    BUS_SPACE_BARRIER_READ);
183 
184 	v <<= 8;
185 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2);
186 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
187 	    BUS_SPACE_BARRIER_READ);
188 
189 	v <<= 8;
190 	v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3);
191 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
192 	    BUS_SPACE_BARRIER_READ);
193 
194 	splx(s);
195 	return (v);
196 }
197 
198 /*
199  * Write to an indirect register
200  */
201 void
202 uperf_sbus_write_reg(struct uperf_sbus_softc *sc, bus_size_t r, u_int32_t v)
203 {
204 	int s;
205 
206 	s = splhigh();
207 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r);
208 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1,
209 	    BUS_SPACE_BARRIER_WRITE);
210 
211 	/* Can't use multi writes because we have to gaurantee order */
212 
213 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0,
214 	    (v >> 24) & 0xff);
215 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1,
216 	    BUS_SPACE_BARRIER_WRITE);
217 
218 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1,
219 	    (v >> 16) & 0xff);
220 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1,
221 	    BUS_SPACE_BARRIER_WRITE);
222 
223 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2,
224 	    (v >> 8) & 0xff);
225 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1,
226 	    BUS_SPACE_BARRIER_WRITE);
227 
228 	bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3,
229 	    (v >> 0) & 0xff);
230 	bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1,
231 	    BUS_SPACE_BARRIER_WRITE);
232 	splx(s);
233 }
234 
235 int
236 uperf_sbus_clrcnt(void *vsc, int flags)
237 {
238 	struct uperf_sbus_softc *sc = vsc;
239 	u_int32_t clr = 0, oldsrc;
240 
241 	if (flags & UPERF_CNT0)
242 		clr |= USC_PCTRL_CLR0;
243 	if (flags & UPERF_CNT1)
244 		clr |= USC_PCTRL_CLR1;
245 	if (clr) {
246 		oldsrc = uperf_sbus_read_reg(sc, USC_PERFCTRL);
247 		uperf_sbus_write_reg(sc, USC_PERFCTRL, clr | oldsrc);
248 	}
249 	return (0);
250 }
251 
252 int
253 uperf_sbus_setcntsrc(void *vsc, int flags, u_int src0, u_int src1)
254 {
255 	struct uperf_sbus_softc *sc = vsc;
256 	u_int32_t src;
257 
258 	src = uperf_sbus_read_reg(sc, USC_PERFCTRL);
259 	if (flags & UPERF_CNT0) {
260 		src &= ~USC_PCTRL_SEL0;
261 		src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0;
262 	}
263 	if (flags & UPERF_CNT1) {
264 		src &= ~USC_PCTRL_SEL1;
265 		src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1;
266 	}
267 	uperf_sbus_write_reg(sc, USC_PERFCTRL, src);
268 	return (0);
269 }
270 
271 int
272 uperf_sbus_getcntsrc(void *vsc, int flags, u_int *srcp0, u_int *srcp1)
273 {
274 	struct uperf_sbus_softc *sc = vsc;
275 	u_int32_t src;
276 
277 	src = uperf_sbus_read_reg(sc, USC_PERFCTRL);
278 	if (flags & UPERF_CNT0)
279 		*srcp0 = (src & USC_PCTRL_SEL0) >> 0;
280 	if (flags & UPERF_CNT1)
281 		*srcp1 = (src & USC_PCTRL_SEL1) >> 8;
282 	return (0);
283 }
284 
285 int
286 uperf_sbus_getcnt(void *vsc, int flags, u_int32_t *cntp0, u_int32_t *cntp1)
287 {
288 	struct uperf_sbus_softc *sc = vsc;
289 	u_int32_t c0, c1;
290 
291 	c0 = uperf_sbus_read_reg(sc, USC_PERF0);
292 	c1 = uperf_sbus_read_reg(sc, USC_PERFSHAD);
293 	if (flags & UPERF_CNT0)
294 		*cntp0 = c0;
295 	if (flags & UPERF_CNT1)
296 		*cntp1 = c1;
297 	return (0);
298 }
299 
300 #ifdef DDB
301 void
302 uperf_sbus_xir(void *arg, int cpu)
303 {
304 	struct uperf_sbus_softc *sc = arg;
305 
306 	uperf_sbus_write_reg(sc, USC_CTRL, USC_CTRL_XIR);
307 }
308 #endif
309