uperf_ebus.c revision 1.1
1/* $OpenBSD: uperf_ebus.c,v 1.1 2002/04/04 23:16:22 jason 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jason L. Wright 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34/* 35 */ 36 37#include <sys/types.h> 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/device.h> 42#include <sys/conf.h> 43#include <sys/timeout.h> 44 45#include <machine/bus.h> 46#include <machine/autoconf.h> 47#include <machine/openfirm.h> 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 57struct 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 63int uperf_ebus_match(struct device *, void *, void *); 64void uperf_ebus_attach(struct device *, struct device *, void *); 65 66struct cfattach uperf_ebus_ca = { 67 sizeof(struct uperf_ebus_softc), uperf_ebus_match, uperf_ebus_attach 68}; 69 70u_int32_t uperf_ebus_read_reg(struct uperf_ebus_softc *, bus_size_t); 71void uperf_ebus_write_reg(struct uperf_ebus_softc *, 72 bus_size_t, u_int32_t); 73 74int uperf_ebus_getcnt(void *, int, u_int32_t *, u_int32_t *); 75int uperf_ebus_clrcnt(void *, int); 76int uperf_ebus_getcntsrc(void *, int, u_int *, u_int *); 77int uperf_ebus_setcntsrc(void *, int, u_int, u_int); 78 79struct uperf_src uperf_ebus_srcs[] = { 80 { UPERFSRC_SDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRA }, 81 { UPERFSRC_SDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWA }, 82 { UPERFSRC_CDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRA }, 83 { UPERFSRC_CDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWA }, 84 { UPERFSRC_SBMA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMA }, 85 { UPERFSRC_DVA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVA }, 86 { UPERFSRC_DVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWA }, 87 { UPERFSRC_PIOA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOA }, 88 { UPERFSRC_SDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRB }, 89 { UPERFSRC_SDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWB }, 90 { UPERFSRC_CDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRB }, 91 { UPERFSRC_CDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWB }, 92 { UPERFSRC_SBMB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMB }, 93 { UPERFSRC_DVB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVB }, 94 { UPERFSRC_DVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWB }, 95 { UPERFSRC_PIOB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOB }, 96 { UPERFSRC_TLBMISS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TLBMISS }, 97 { UPERFSRC_NINTRS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_NINTRS }, 98 { UPERFSRC_INACK, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_INACK }, 99 { UPERFSRC_PIOR, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOR }, 100 { UPERFSRC_PIOW, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOW }, 101 { UPERFSRC_MERGE, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_MERGE }, 102 { UPERFSRC_TBLA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLA }, 103 { UPERFSRC_STCA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCA }, 104 { UPERFSRC_TBLB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLB }, 105 { UPERFSRC_STCB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCB }, 106 { -1, -1, 0 } 107}; 108int 109uperf_ebus_match(parent, match, aux) 110 struct device *parent; 111 void *match; 112 void *aux; 113{ 114 struct ebus_attach_args *ea = aux; 115 116 return (strcmp(ea->ea_name, "sc") == 0); 117} 118 119void 120uperf_ebus_attach(parent, self, aux) 121 struct device *parent, *self; 122 void *aux; 123{ 124 struct uperf_ebus_softc *sc = (void *)self; 125 struct ebus_attach_args *ea = aux; 126 char *model; 127 u_int32_t id; 128 129 sc->sc_bus_t = ea->ea_bustag; 130 sc->sc_usc.usc_cookie = sc; 131 sc->sc_usc.usc_getcntsrc = uperf_ebus_getcntsrc; 132 sc->sc_usc.usc_setcntsrc = uperf_ebus_setcntsrc; 133 sc->sc_usc.usc_clrcnt = uperf_ebus_clrcnt; 134 sc->sc_usc.usc_getcnt = uperf_ebus_getcnt; 135 sc->sc_usc.usc_srcs = uperf_ebus_srcs; 136 137 /* Use prom address if available, otherwise map it. */ 138 if (ea->ea_nregs != 1) { 139 printf(": expected 1 register, got %d\n", ea->ea_nregs); 140 return; 141 } 142 143 if (ebus_bus_map(sc->sc_bus_t, 0, 144 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 145 0, 0, &sc->sc_bus_h) != 0) { 146 printf(": can't map register space\n"); 147 return; 148 } 149 150 id = uperf_ebus_read_reg(sc, USC_ID); 151 model = getpropstring(ea->ea_node, "model"); 152 if (model == NULL || strlen(model) == 0) 153 model = "unknown"; 154 155 printf(": model %s (%x/%x) ports %d\n", model, 156 (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S, 157 (id & USC_ID_VERS_M) >> USC_ID_VERS_S, 158 (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S); 159} 160 161/* 162 * Read an indirect register. 163 */ 164u_int32_t 165uperf_ebus_read_reg(sc, r) 166 struct uperf_ebus_softc *sc; 167 bus_size_t r; 168{ 169 u_int32_t v; 170 int s; 171 172 s = splhigh(); 173 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 174 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 175 BUS_SPACE_BARRIER_WRITE); 176 177 /* Can't use multi reads because we have to gaurantee order */ 178 179 v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0); 180 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 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 + 1); 185 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 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 + 2); 190 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 191 BUS_SPACE_BARRIER_READ); 192 193 v <<= 8; 194 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3); 195 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 196 BUS_SPACE_BARRIER_READ); 197 198 splx(s); 199 return (v); 200} 201 202/* 203 * Write an indirect register. 204 */ 205void 206uperf_ebus_write_reg(sc, r, v) 207 struct uperf_ebus_softc *sc; 208 bus_size_t r; 209 u_int32_t v; 210{ 211 int s; 212 213 s = splhigh(); 214 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 215 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 216 BUS_SPACE_BARRIER_WRITE); 217 218 /* Can't use multi writes because we have to gaurantee order */ 219 220 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 221 (v >> 24) & 0xff); 222 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 223 BUS_SPACE_BARRIER_WRITE); 224 225 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 226 (v >> 16) & 0xff); 227 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 228 BUS_SPACE_BARRIER_WRITE); 229 230 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 231 (v >> 8) & 0xff); 232 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 233 BUS_SPACE_BARRIER_WRITE); 234 235 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 236 (v >> 0) & 0xff); 237 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 238 BUS_SPACE_BARRIER_WRITE); 239 splx(s); 240} 241 242int 243uperf_ebus_clrcnt(vsc, flags) 244 void *vsc; 245 int flags; 246{ 247 struct uperf_ebus_softc *sc = vsc; 248 u_int32_t clr = 0, oldsrc; 249 250 if (flags & UPERF_CNT0) 251 clr |= USC_PCTRL_CLR0; 252 if (flags & UPERF_CNT1) 253 clr |= USC_PCTRL_CLR1; 254 if (clr) { 255 oldsrc = uperf_ebus_read_reg(sc, USC_PERFCTRL); 256 uperf_ebus_write_reg(sc, USC_PERFCTRL, clr | oldsrc); 257 } 258 return (0); 259} 260 261int 262uperf_ebus_setcntsrc(vsc, flags, src0, src1) 263 void *vsc; 264 int flags; 265 u_int src0, src1; 266{ 267 struct uperf_ebus_softc *sc = vsc; 268 u_int32_t src; 269 270 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 271 if (flags & UPERF_CNT0) { 272 src &= ~USC_PCTRL_SEL0; 273 src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0; 274 } 275 if (flags & UPERF_CNT1) { 276 src &= ~USC_PCTRL_SEL1; 277 src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1; 278 } 279 uperf_ebus_write_reg(sc, USC_PERFCTRL, src); 280 return (0); 281} 282 283int 284uperf_ebus_getcntsrc(vsc, flags, srcp0, srcp1) 285 void *vsc; 286 int flags; 287 u_int *srcp0, *srcp1; 288{ 289 struct uperf_ebus_softc *sc = vsc; 290 u_int32_t src; 291 292 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 293 if (flags & UPERF_CNT0) 294 *srcp0 = (src & USC_PCTRL_SEL0) >> 0; 295 if (flags & UPERF_CNT1) 296 *srcp1 = (src & USC_PCTRL_SEL1) >> 8; 297 return (0); 298} 299 300int 301uperf_ebus_getcnt(vsc, flags, cntp0, cntp1) 302 void *vsc; 303 int flags; 304 u_int32_t *cntp0, *cntp1; 305{ 306 struct uperf_ebus_softc *sc = vsc; 307 u_int32_t c0, c1; 308 309 c0 = uperf_ebus_read_reg(sc, USC_PERF0); 310 c1 = uperf_ebus_read_reg(sc, USC_PERFSHAD); 311 if (flags & UPERF_CNT0) 312 *cntp0 = c0; 313 if (flags & UPERF_CNT1) 314 *cntp1 = c1; 315 return (0); 316} 317