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