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