1 /* $OpenBSD: uperf_ebus.c,v 1.9 2022/10/16 01:22:39 jsg 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(struct device *parent, void *match, void *aux) 114 { 115 struct ebus_attach_args *ea = aux; 116 117 return (strcmp(ea->ea_name, "sc") == 0); 118 } 119 120 void 121 uperf_ebus_attach(struct device *parent, struct device *self, void *aux) 122 { 123 struct uperf_ebus_softc *sc = (void *)self; 124 struct ebus_attach_args *ea = aux; 125 char *model; 126 u_int32_t id; 127 128 sc->sc_bus_t = ea->ea_memtag; 129 sc->sc_usc.usc_cookie = sc; 130 sc->sc_usc.usc_getcntsrc = uperf_ebus_getcntsrc; 131 sc->sc_usc.usc_setcntsrc = uperf_ebus_setcntsrc; 132 sc->sc_usc.usc_clrcnt = uperf_ebus_clrcnt; 133 sc->sc_usc.usc_getcnt = uperf_ebus_getcnt; 134 sc->sc_usc.usc_srcs = uperf_ebus_srcs; 135 136 /* Use prom address if available, otherwise map it. */ 137 if (ea->ea_nregs != 1) { 138 printf(": expected 1 register, got %d\n", ea->ea_nregs); 139 return; 140 } 141 142 if (ebus_bus_map(sc->sc_bus_t, 0, 143 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 144 0, 0, &sc->sc_bus_h) != 0) { 145 printf(": can't map register space\n"); 146 return; 147 } 148 149 id = uperf_ebus_read_reg(sc, USC_ID); 150 model = getpropstring(ea->ea_node, "model"); 151 if (model == NULL || strlen(model) == 0) 152 model = "unknown"; 153 154 printf(": model %s (%x/%x) ports %d\n", model, 155 (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S, 156 (id & USC_ID_VERS_M) >> USC_ID_VERS_S, 157 (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S); 158 159 #ifdef DDB 160 db_register_xir(uperf_ebus_xir, sc); 161 #endif 162 } 163 164 /* 165 * Read an indirect register. 166 */ 167 u_int32_t 168 uperf_ebus_read_reg(struct uperf_ebus_softc *sc, bus_size_t r) 169 { 170 u_int32_t v; 171 int s; 172 173 s = splhigh(); 174 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 175 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 176 BUS_SPACE_BARRIER_WRITE); 177 178 /* Can't use multi reads because we have to guarantee order */ 179 180 v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0); 181 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 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 + 1); 186 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 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 + 2); 191 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 192 BUS_SPACE_BARRIER_READ); 193 194 v <<= 8; 195 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3); 196 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 197 BUS_SPACE_BARRIER_READ); 198 199 splx(s); 200 return (v); 201 } 202 203 /* 204 * Write an indirect register. 205 */ 206 void 207 uperf_ebus_write_reg(struct uperf_ebus_softc *sc, bus_size_t r, u_int32_t v) 208 { 209 int s; 210 211 s = splhigh(); 212 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 213 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 214 BUS_SPACE_BARRIER_WRITE); 215 216 /* Can't use multi writes because we have to guarantee order */ 217 218 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 219 (v >> 24) & 0xff); 220 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 221 BUS_SPACE_BARRIER_WRITE); 222 223 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 224 (v >> 16) & 0xff); 225 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 226 BUS_SPACE_BARRIER_WRITE); 227 228 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 229 (v >> 8) & 0xff); 230 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 231 BUS_SPACE_BARRIER_WRITE); 232 233 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 234 (v >> 0) & 0xff); 235 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 236 BUS_SPACE_BARRIER_WRITE); 237 splx(s); 238 } 239 240 int 241 uperf_ebus_clrcnt(void *vsc, int flags) 242 { 243 struct uperf_ebus_softc *sc = vsc; 244 u_int32_t clr = 0, oldsrc; 245 246 if (flags & UPERF_CNT0) 247 clr |= USC_PCTRL_CLR0; 248 if (flags & UPERF_CNT1) 249 clr |= USC_PCTRL_CLR1; 250 if (clr) { 251 oldsrc = uperf_ebus_read_reg(sc, USC_PERFCTRL); 252 uperf_ebus_write_reg(sc, USC_PERFCTRL, clr | oldsrc); 253 } 254 return (0); 255 } 256 257 int 258 uperf_ebus_setcntsrc(void *vsc, int flags, u_int src0, u_int src1) 259 { 260 struct uperf_ebus_softc *sc = vsc; 261 u_int32_t src; 262 263 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 264 if (flags & UPERF_CNT0) { 265 src &= ~USC_PCTRL_SEL0; 266 src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0; 267 } 268 if (flags & UPERF_CNT1) { 269 src &= ~USC_PCTRL_SEL1; 270 src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1; 271 } 272 uperf_ebus_write_reg(sc, USC_PERFCTRL, src); 273 return (0); 274 } 275 276 int 277 uperf_ebus_getcntsrc(void *vsc, int flags, u_int *srcp0, u_int *srcp1) 278 { 279 struct uperf_ebus_softc *sc = vsc; 280 u_int32_t src; 281 282 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 283 if (flags & UPERF_CNT0) 284 *srcp0 = (src & USC_PCTRL_SEL0) >> 0; 285 if (flags & UPERF_CNT1) 286 *srcp1 = (src & USC_PCTRL_SEL1) >> 8; 287 return (0); 288 } 289 290 int 291 uperf_ebus_getcnt(void *vsc, int flags, u_int32_t *cntp0, u_int32_t *cntp1) 292 { 293 struct uperf_ebus_softc *sc = vsc; 294 u_int32_t c0, c1; 295 296 c0 = uperf_ebus_read_reg(sc, USC_PERF0); 297 c1 = uperf_ebus_read_reg(sc, USC_PERFSHAD); 298 if (flags & UPERF_CNT0) 299 *cntp0 = c0; 300 if (flags & UPERF_CNT1) 301 *cntp1 = c1; 302 return (0); 303 } 304 305 #ifdef DDB 306 void 307 uperf_ebus_xir(void *arg, int cpu) 308 { 309 struct uperf_ebus_softc *sc = arg; 310 311 uperf_ebus_write_reg(sc, USC_CTRL, USC_CTRL_XIR); 312 } 313 #endif 314