1 /* $OpenBSD: uperf_ebus.c,v 1.5 2008/12/15 22:33: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/device.h> 39 #include <sys/conf.h> 40 #include <sys/timeout.h> 41 42 #include <machine/bus.h> 43 #include <machine/autoconf.h> 44 #include <machine/openfirm.h> 45 46 #ifdef DDB 47 #include <machine/db_machdep.h> 48 #endif 49 50 #include <sparc64/dev/ebusreg.h> 51 #include <sparc64/dev/ebusvar.h> 52 #include <dev/sun/uperfio.h> 53 #include <dev/sbus/uperf_sbusreg.h> 54 #include <sparc64/dev/uperfvar.h> 55 #include <sparc64/dev/iommureg.h> 56 #include <sparc64/dev/psychoreg.h> 57 58 struct uperf_ebus_softc { 59 struct uperf_softc sc_usc; 60 bus_space_tag_t sc_bus_t; 61 bus_space_handle_t sc_bus_h; 62 }; 63 64 int uperf_ebus_match(struct device *, void *, void *); 65 void uperf_ebus_attach(struct device *, struct device *, void *); 66 67 struct cfattach uperf_ebus_ca = { 68 sizeof(struct uperf_ebus_softc), uperf_ebus_match, uperf_ebus_attach 69 }; 70 71 u_int32_t uperf_ebus_read_reg(struct uperf_ebus_softc *, bus_size_t); 72 void uperf_ebus_write_reg(struct uperf_ebus_softc *, 73 bus_size_t, u_int32_t); 74 75 int uperf_ebus_getcnt(void *, int, u_int32_t *, u_int32_t *); 76 int uperf_ebus_clrcnt(void *, int); 77 int uperf_ebus_getcntsrc(void *, int, u_int *, u_int *); 78 int uperf_ebus_setcntsrc(void *, int, u_int, u_int); 79 80 #ifdef DDB 81 void uperf_ebus_xir(void *, int); 82 #endif 83 84 struct uperf_src uperf_ebus_srcs[] = { 85 { UPERFSRC_SDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRA }, 86 { UPERFSRC_SDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWA }, 87 { UPERFSRC_CDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRA }, 88 { UPERFSRC_CDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWA }, 89 { UPERFSRC_SBMA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMA }, 90 { UPERFSRC_DVA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVA }, 91 { UPERFSRC_DVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWA }, 92 { UPERFSRC_PIOA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOA }, 93 { UPERFSRC_SDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRB }, 94 { UPERFSRC_SDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWB }, 95 { UPERFSRC_CDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRB }, 96 { UPERFSRC_CDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWB }, 97 { UPERFSRC_SBMB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMB }, 98 { UPERFSRC_DVB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVB }, 99 { UPERFSRC_DVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWB }, 100 { UPERFSRC_PIOB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOB }, 101 { UPERFSRC_TLBMISS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TLBMISS }, 102 { UPERFSRC_NINTRS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_NINTRS }, 103 { UPERFSRC_INACK, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_INACK }, 104 { UPERFSRC_PIOR, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOR }, 105 { UPERFSRC_PIOW, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOW }, 106 { UPERFSRC_MERGE, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_MERGE }, 107 { UPERFSRC_TBLA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLA }, 108 { UPERFSRC_STCA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCA }, 109 { UPERFSRC_TBLB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLB }, 110 { UPERFSRC_STCB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCB }, 111 { -1, -1, 0 } 112 }; 113 int 114 uperf_ebus_match(parent, match, aux) 115 struct device *parent; 116 void *match; 117 void *aux; 118 { 119 struct ebus_attach_args *ea = aux; 120 121 return (strcmp(ea->ea_name, "sc") == 0); 122 } 123 124 void 125 uperf_ebus_attach(parent, self, aux) 126 struct device *parent, *self; 127 void *aux; 128 { 129 struct uperf_ebus_softc *sc = (void *)self; 130 struct ebus_attach_args *ea = aux; 131 char *model; 132 u_int32_t id; 133 134 sc->sc_bus_t = ea->ea_memtag; 135 sc->sc_usc.usc_cookie = sc; 136 sc->sc_usc.usc_getcntsrc = uperf_ebus_getcntsrc; 137 sc->sc_usc.usc_setcntsrc = uperf_ebus_setcntsrc; 138 sc->sc_usc.usc_clrcnt = uperf_ebus_clrcnt; 139 sc->sc_usc.usc_getcnt = uperf_ebus_getcnt; 140 sc->sc_usc.usc_srcs = uperf_ebus_srcs; 141 142 /* Use prom address if available, otherwise map it. */ 143 if (ea->ea_nregs != 1) { 144 printf(": expected 1 register, got %d\n", ea->ea_nregs); 145 return; 146 } 147 148 if (ebus_bus_map(sc->sc_bus_t, 0, 149 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 150 0, 0, &sc->sc_bus_h) != 0) { 151 printf(": can't map register space\n"); 152 return; 153 } 154 155 id = uperf_ebus_read_reg(sc, USC_ID); 156 model = getpropstring(ea->ea_node, "model"); 157 if (model == NULL || strlen(model) == 0) 158 model = "unknown"; 159 160 printf(": model %s (%x/%x) ports %d\n", model, 161 (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S, 162 (id & USC_ID_VERS_M) >> USC_ID_VERS_S, 163 (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S); 164 165 #ifdef DDB 166 db_register_xir(uperf_ebus_xir, sc); 167 #endif 168 } 169 170 /* 171 * Read an indirect register. 172 */ 173 u_int32_t 174 uperf_ebus_read_reg(sc, r) 175 struct uperf_ebus_softc *sc; 176 bus_size_t r; 177 { 178 u_int32_t v; 179 int s; 180 181 s = splhigh(); 182 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 183 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 184 BUS_SPACE_BARRIER_WRITE); 185 186 /* Can't use multi reads because we have to gaurantee order */ 187 188 v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0); 189 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 190 BUS_SPACE_BARRIER_READ); 191 192 v <<= 8; 193 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1); 194 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 195 BUS_SPACE_BARRIER_READ); 196 197 v <<= 8; 198 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2); 199 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 200 BUS_SPACE_BARRIER_READ); 201 202 v <<= 8; 203 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3); 204 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 205 BUS_SPACE_BARRIER_READ); 206 207 splx(s); 208 return (v); 209 } 210 211 /* 212 * Write an indirect register. 213 */ 214 void 215 uperf_ebus_write_reg(sc, r, v) 216 struct uperf_ebus_softc *sc; 217 bus_size_t r; 218 u_int32_t v; 219 { 220 int s; 221 222 s = splhigh(); 223 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 224 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 225 BUS_SPACE_BARRIER_WRITE); 226 227 /* Can't use multi writes because we have to gaurantee order */ 228 229 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 230 (v >> 24) & 0xff); 231 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 232 BUS_SPACE_BARRIER_WRITE); 233 234 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 235 (v >> 16) & 0xff); 236 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 237 BUS_SPACE_BARRIER_WRITE); 238 239 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 240 (v >> 8) & 0xff); 241 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 242 BUS_SPACE_BARRIER_WRITE); 243 244 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 245 (v >> 0) & 0xff); 246 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 247 BUS_SPACE_BARRIER_WRITE); 248 splx(s); 249 } 250 251 int 252 uperf_ebus_clrcnt(vsc, flags) 253 void *vsc; 254 int flags; 255 { 256 struct uperf_ebus_softc *sc = vsc; 257 u_int32_t clr = 0, oldsrc; 258 259 if (flags & UPERF_CNT0) 260 clr |= USC_PCTRL_CLR0; 261 if (flags & UPERF_CNT1) 262 clr |= USC_PCTRL_CLR1; 263 if (clr) { 264 oldsrc = uperf_ebus_read_reg(sc, USC_PERFCTRL); 265 uperf_ebus_write_reg(sc, USC_PERFCTRL, clr | oldsrc); 266 } 267 return (0); 268 } 269 270 int 271 uperf_ebus_setcntsrc(vsc, flags, src0, src1) 272 void *vsc; 273 int flags; 274 u_int src0, src1; 275 { 276 struct uperf_ebus_softc *sc = vsc; 277 u_int32_t src; 278 279 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 280 if (flags & UPERF_CNT0) { 281 src &= ~USC_PCTRL_SEL0; 282 src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0; 283 } 284 if (flags & UPERF_CNT1) { 285 src &= ~USC_PCTRL_SEL1; 286 src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1; 287 } 288 uperf_ebus_write_reg(sc, USC_PERFCTRL, src); 289 return (0); 290 } 291 292 int 293 uperf_ebus_getcntsrc(vsc, flags, srcp0, srcp1) 294 void *vsc; 295 int flags; 296 u_int *srcp0, *srcp1; 297 { 298 struct uperf_ebus_softc *sc = vsc; 299 u_int32_t src; 300 301 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 302 if (flags & UPERF_CNT0) 303 *srcp0 = (src & USC_PCTRL_SEL0) >> 0; 304 if (flags & UPERF_CNT1) 305 *srcp1 = (src & USC_PCTRL_SEL1) >> 8; 306 return (0); 307 } 308 309 int 310 uperf_ebus_getcnt(vsc, flags, cntp0, cntp1) 311 void *vsc; 312 int flags; 313 u_int32_t *cntp0, *cntp1; 314 { 315 struct uperf_ebus_softc *sc = vsc; 316 u_int32_t c0, c1; 317 318 c0 = uperf_ebus_read_reg(sc, USC_PERF0); 319 c1 = uperf_ebus_read_reg(sc, USC_PERFSHAD); 320 if (flags & UPERF_CNT0) 321 *cntp0 = c0; 322 if (flags & UPERF_CNT1) 323 *cntp1 = c1; 324 return (0); 325 } 326 327 #ifdef DDB 328 void 329 uperf_ebus_xir(void *arg, int cpu) 330 { 331 struct uperf_ebus_softc *sc = arg; 332 333 uperf_ebus_write_reg(sc, USC_CTRL, USC_CTRL_XIR); 334 } 335 #endif 336