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