uperf_ebus.c revision 1.3
1/* $OpenBSD: uperf_ebus.c,v 1.3 2003/02/17 01:29:20 henric 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 * Effort sponsored in part by the Defense Advanced Research Projects 34 * Agency (DARPA) and Air Force Research Laboratory, Air Force 35 * Materiel Command, USAF, under agreement number F30602-01-2-0537. 36 * 37 */ 38 39#include <sys/types.h> 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/device.h> 44#include <sys/conf.h> 45#include <sys/timeout.h> 46 47#include <machine/bus.h> 48#include <machine/autoconf.h> 49#include <machine/openfirm.h> 50 51#include <sparc64/dev/ebusreg.h> 52#include <sparc64/dev/ebusvar.h> 53#include <dev/sun/uperfio.h> 54#include <dev/sbus/uperf_sbusreg.h> 55#include <sparc64/dev/uperfvar.h> 56#include <sparc64/dev/iommureg.h> 57#include <sparc64/dev/psychoreg.h> 58 59struct uperf_ebus_softc { 60 struct uperf_softc sc_usc; 61 bus_space_tag_t sc_bus_t; 62 bus_space_handle_t sc_bus_h; 63}; 64 65int uperf_ebus_match(struct device *, void *, void *); 66void uperf_ebus_attach(struct device *, struct device *, void *); 67 68struct cfattach uperf_ebus_ca = { 69 sizeof(struct uperf_ebus_softc), uperf_ebus_match, uperf_ebus_attach 70}; 71 72u_int32_t uperf_ebus_read_reg(struct uperf_ebus_softc *, bus_size_t); 73void uperf_ebus_write_reg(struct uperf_ebus_softc *, 74 bus_size_t, u_int32_t); 75 76int uperf_ebus_getcnt(void *, int, u_int32_t *, u_int32_t *); 77int uperf_ebus_clrcnt(void *, int); 78int uperf_ebus_getcntsrc(void *, int, u_int *, u_int *); 79int uperf_ebus_setcntsrc(void *, int, u_int, u_int); 80 81struct uperf_src uperf_ebus_srcs[] = { 82 { UPERFSRC_SDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRA }, 83 { UPERFSRC_SDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWA }, 84 { UPERFSRC_CDVRA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRA }, 85 { UPERFSRC_CDVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWA }, 86 { UPERFSRC_SBMA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMA }, 87 { UPERFSRC_DVA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVA }, 88 { UPERFSRC_DVWA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWA }, 89 { UPERFSRC_PIOA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOA }, 90 { UPERFSRC_SDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVRB }, 91 { UPERFSRC_SDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SDVWB }, 92 { UPERFSRC_CDVRB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVRB }, 93 { UPERFSRC_CDVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_CDVWB }, 94 { UPERFSRC_SBMB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_SBMB }, 95 { UPERFSRC_DVB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVB }, 96 { UPERFSRC_DVWB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_DVWB }, 97 { UPERFSRC_PIOB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOB }, 98 { UPERFSRC_TLBMISS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TLBMISS }, 99 { UPERFSRC_NINTRS, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_NINTRS }, 100 { UPERFSRC_INACK, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_INACK }, 101 { UPERFSRC_PIOR, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOR }, 102 { UPERFSRC_PIOW, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_PIOW }, 103 { UPERFSRC_MERGE, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_MERGE }, 104 { UPERFSRC_TBLA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLA }, 105 { UPERFSRC_STCA, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCA }, 106 { UPERFSRC_TBLB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_TBLB }, 107 { UPERFSRC_STCB, UPERF_CNT0|UPERF_CNT1, PSY_PMCRSEL_STCB }, 108 { -1, -1, 0 } 109}; 110int 111uperf_ebus_match(parent, match, aux) 112 struct device *parent; 113 void *match; 114 void *aux; 115{ 116 struct ebus_attach_args *ea = aux; 117 118 return (strcmp(ea->ea_name, "sc") == 0); 119} 120 121void 122uperf_ebus_attach(parent, self, aux) 123 struct device *parent, *self; 124 void *aux; 125{ 126 struct uperf_ebus_softc *sc = (void *)self; 127 struct ebus_attach_args *ea = aux; 128 char *model; 129 u_int32_t id; 130 131 sc->sc_bus_t = ea->ea_memtag; 132 sc->sc_usc.usc_cookie = sc; 133 sc->sc_usc.usc_getcntsrc = uperf_ebus_getcntsrc; 134 sc->sc_usc.usc_setcntsrc = uperf_ebus_setcntsrc; 135 sc->sc_usc.usc_clrcnt = uperf_ebus_clrcnt; 136 sc->sc_usc.usc_getcnt = uperf_ebus_getcnt; 137 sc->sc_usc.usc_srcs = uperf_ebus_srcs; 138 139 /* Use prom address if available, otherwise map it. */ 140 if (ea->ea_nregs != 1) { 141 printf(": expected 1 register, got %d\n", ea->ea_nregs); 142 return; 143 } 144 145 if (ebus_bus_map(sc->sc_bus_t, 0, 146 EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), ea->ea_regs[0].size, 147 0, 0, &sc->sc_bus_h) != 0) { 148 printf(": can't map register space\n"); 149 return; 150 } 151 152 id = uperf_ebus_read_reg(sc, USC_ID); 153 model = getpropstring(ea->ea_node, "model"); 154 if (model == NULL || strlen(model) == 0) 155 model = "unknown"; 156 157 printf(": model %s (%x/%x) ports %d\n", model, 158 (id & USC_ID_IMPL_M) >> USC_ID_IMPL_S, 159 (id & USC_ID_VERS_M) >> USC_ID_VERS_S, 160 (id & USC_ID_UPANUM_M) >> USC_ID_UPANUM_S); 161} 162 163/* 164 * Read an indirect register. 165 */ 166u_int32_t 167uperf_ebus_read_reg(sc, r) 168 struct uperf_ebus_softc *sc; 169 bus_size_t r; 170{ 171 u_int32_t v; 172 int s; 173 174 s = splhigh(); 175 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 176 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 177 BUS_SPACE_BARRIER_WRITE); 178 179 /* Can't use multi reads because we have to gaurantee order */ 180 181 v = bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0); 182 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 183 BUS_SPACE_BARRIER_READ); 184 185 v <<= 8; 186 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1); 187 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 188 BUS_SPACE_BARRIER_READ); 189 190 v <<= 8; 191 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2); 192 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 193 BUS_SPACE_BARRIER_READ); 194 195 v <<= 8; 196 v |= bus_space_read_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3); 197 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 198 BUS_SPACE_BARRIER_READ); 199 200 splx(s); 201 return (v); 202} 203 204/* 205 * Write an indirect register. 206 */ 207void 208uperf_ebus_write_reg(sc, r, v) 209 struct uperf_ebus_softc *sc; 210 bus_size_t r; 211 u_int32_t v; 212{ 213 int s; 214 215 s = splhigh(); 216 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, r); 217 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_ADDR, 1, 218 BUS_SPACE_BARRIER_WRITE); 219 220 /* Can't use multi writes because we have to gaurantee order */ 221 222 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 223 (v >> 24) & 0xff); 224 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 0, 1, 225 BUS_SPACE_BARRIER_WRITE); 226 227 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 228 (v >> 16) & 0xff); 229 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 1, 1, 230 BUS_SPACE_BARRIER_WRITE); 231 232 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 233 (v >> 8) & 0xff); 234 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 2, 1, 235 BUS_SPACE_BARRIER_WRITE); 236 237 bus_space_write_1(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 238 (v >> 0) & 0xff); 239 bus_space_barrier(sc->sc_bus_t, sc->sc_bus_h, USC_DATA + 3, 1, 240 BUS_SPACE_BARRIER_WRITE); 241 splx(s); 242} 243 244int 245uperf_ebus_clrcnt(vsc, flags) 246 void *vsc; 247 int flags; 248{ 249 struct uperf_ebus_softc *sc = vsc; 250 u_int32_t clr = 0, oldsrc; 251 252 if (flags & UPERF_CNT0) 253 clr |= USC_PCTRL_CLR0; 254 if (flags & UPERF_CNT1) 255 clr |= USC_PCTRL_CLR1; 256 if (clr) { 257 oldsrc = uperf_ebus_read_reg(sc, USC_PERFCTRL); 258 uperf_ebus_write_reg(sc, USC_PERFCTRL, clr | oldsrc); 259 } 260 return (0); 261} 262 263int 264uperf_ebus_setcntsrc(vsc, flags, src0, src1) 265 void *vsc; 266 int flags; 267 u_int src0, src1; 268{ 269 struct uperf_ebus_softc *sc = vsc; 270 u_int32_t src; 271 272 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 273 if (flags & UPERF_CNT0) { 274 src &= ~USC_PCTRL_SEL0; 275 src |= ((src0 << 0) & USC_PCTRL_SEL0) | USC_PCTRL_CLR0; 276 } 277 if (flags & UPERF_CNT1) { 278 src &= ~USC_PCTRL_SEL1; 279 src |= ((src1 << 8) & USC_PCTRL_SEL1) | USC_PCTRL_CLR1; 280 } 281 uperf_ebus_write_reg(sc, USC_PERFCTRL, src); 282 return (0); 283} 284 285int 286uperf_ebus_getcntsrc(vsc, flags, srcp0, srcp1) 287 void *vsc; 288 int flags; 289 u_int *srcp0, *srcp1; 290{ 291 struct uperf_ebus_softc *sc = vsc; 292 u_int32_t src; 293 294 src = uperf_ebus_read_reg(sc, USC_PERFCTRL); 295 if (flags & UPERF_CNT0) 296 *srcp0 = (src & USC_PCTRL_SEL0) >> 0; 297 if (flags & UPERF_CNT1) 298 *srcp1 = (src & USC_PCTRL_SEL1) >> 8; 299 return (0); 300} 301 302int 303uperf_ebus_getcnt(vsc, flags, cntp0, cntp1) 304 void *vsc; 305 int flags; 306 u_int32_t *cntp0, *cntp1; 307{ 308 struct uperf_ebus_softc *sc = vsc; 309 u_int32_t c0, c1; 310 311 c0 = uperf_ebus_read_reg(sc, USC_PERF0); 312 c1 = uperf_ebus_read_reg(sc, USC_PERFSHAD); 313 if (flags & UPERF_CNT0) 314 *cntp0 = c0; 315 if (flags & UPERF_CNT1) 316 *cntp1 = c1; 317 return (0); 318} 319