Annotation of sys/dev/sbus/qec.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: qec.c,v 1.10 2006/06/02 20:00:56 miod Exp $ */
! 2: /* $NetBSD: qec.c,v 1.12 2000/12/04 20:12:55 fvdl Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Paul Kranenburg.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: #include <sys/types.h>
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/kernel.h>
! 44: #include <sys/errno.h>
! 45: #include <sys/device.h>
! 46: #include <sys/malloc.h>
! 47:
! 48: #include <machine/bus.h>
! 49: #include <machine/intr.h>
! 50: #include <machine/autoconf.h>
! 51:
! 52: #include <dev/sbus/sbusvar.h>
! 53: #include <dev/sbus/qecreg.h>
! 54: #include <dev/sbus/qecvar.h>
! 55:
! 56: int qecprint(void *, const char *);
! 57: int qecmatch(struct device *, void *, void *);
! 58: void qecattach(struct device *, struct device *, void *);
! 59: void qec_init(struct qec_softc *);
! 60:
! 61: int qec_bus_map(
! 62: bus_space_tag_t,
! 63: bus_space_tag_t,
! 64: bus_addr_t, /*offset*/
! 65: bus_size_t, /*size*/
! 66: int, /*flags*/
! 67: bus_space_handle_t *);
! 68: void * qec_intr_establish(
! 69: bus_space_tag_t,
! 70: bus_space_tag_t,
! 71: int, /*bus interrupt priority*/
! 72: int, /*`device class' interrupt level*/
! 73: int, /*flags*/
! 74: int (*)(void *), /*handler*/
! 75: void *, /*arg*/
! 76: const char *); /*what*/
! 77:
! 78: struct cfattach qec_ca = {
! 79: sizeof(struct qec_softc), qecmatch, qecattach
! 80: };
! 81:
! 82: struct cfdriver qec_cd = {
! 83: NULL, "qec", DV_DULL
! 84: };
! 85:
! 86: int
! 87: qecprint(aux, busname)
! 88: void *aux;
! 89: const char *busname;
! 90: {
! 91: struct sbus_attach_args *sa = aux;
! 92: bus_space_tag_t t = sa->sa_bustag;
! 93: struct qec_softc *sc = t->cookie;
! 94:
! 95: sa->sa_bustag = sc->sc_bustag; /* XXX */
! 96: sbus_print(aux, busname); /* XXX */
! 97: sa->sa_bustag = t; /* XXX */
! 98: return (UNCONF);
! 99: }
! 100:
! 101: int
! 102: qecmatch(parent, vcf, aux)
! 103: struct device *parent;
! 104: void *vcf;
! 105: void *aux;
! 106: {
! 107: struct cfdata *cf = vcf;
! 108: struct sbus_attach_args *sa = aux;
! 109:
! 110: return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
! 111: }
! 112:
! 113: /*
! 114: * Attach all the sub-devices we can find
! 115: */
! 116: void
! 117: qecattach(parent, self, aux)
! 118: struct device *parent, *self;
! 119: void *aux;
! 120: {
! 121: struct sbus_attach_args *sa = aux;
! 122: struct qec_softc *sc = (void *)self;
! 123: int node;
! 124: int sbusburst;
! 125: struct sparc_bus_space_tag *sbt;
! 126: bus_space_handle_t bh;
! 127: int error;
! 128:
! 129: sc->sc_bustag = sa->sa_bustag;
! 130: sc->sc_dmatag = sa->sa_dmatag;
! 131: node = sa->sa_node;
! 132:
! 133: if (sa->sa_nreg < 2) {
! 134: printf("%s: only %d register sets\n",
! 135: self->dv_xname, sa->sa_nreg);
! 136: return;
! 137: }
! 138:
! 139: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
! 140: sa->sa_reg[0].sbr_offset, sa->sa_reg[0].sbr_size,
! 141: 0, 0, &sc->sc_regs) != 0) {
! 142: printf("%s: attach: cannot map registers\n", self->dv_xname);
! 143: return;
! 144: }
! 145:
! 146: /*
! 147: * This device's "register space 1" is just a buffer where the
! 148: * Lance ring-buffers can be stored. Note the buffer's location
! 149: * and size, so the child driver can pick them up.
! 150: */
! 151: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
! 152: sa->sa_reg[1].sbr_offset, sa->sa_reg[1].sbr_size, 0, 0, &bh) != 0) {
! 153: printf("%s: attach: cannot map registers\n", self->dv_xname);
! 154: return;
! 155: }
! 156: sc->sc_buffer = (caddr_t)bus_space_vaddr(sc->sc_bustag, bh);
! 157: sc->sc_bufsiz = (bus_size_t)sa->sa_reg[1].sbr_size;
! 158:
! 159: /* Get number of on-board channels */
! 160: sc->sc_nchannels = getpropint(node, "#channels", -1);
! 161: if (sc->sc_nchannels == -1) {
! 162: printf(": no channels\n");
! 163: return;
! 164: }
! 165:
! 166: /*
! 167: * Get transfer burst size from PROM
! 168: */
! 169: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
! 170: if (sbusburst == 0)
! 171: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
! 172:
! 173: sc->sc_burst = getpropint(node, "burst-sizes", -1);
! 174: if (sc->sc_burst == -1)
! 175: /* take SBus burst sizes */
! 176: sc->sc_burst = sbusburst;
! 177:
! 178: /* Clamp at parent's burst sizes */
! 179: sc->sc_burst &= sbusburst;
! 180:
! 181: /*
! 182: * Collect address translations from the OBP.
! 183: */
! 184: error = getprop(node, "ranges", sizeof(struct sbus_range),
! 185: &sc->sc_nrange, (void **)&sc->sc_range);
! 186: switch (error) {
! 187: case 0:
! 188: break;
! 189: case ENOENT:
! 190: default:
! 191: panic("%s: error getting ranges property", self->dv_xname);
! 192: }
! 193:
! 194: /* Allocate a bus tag */
! 195: sbt = malloc(sizeof(*sbt), M_DEVBUF, M_NOWAIT);
! 196: if (sbt == NULL) {
! 197: printf("%s: attach: out of memory\n", self->dv_xname);
! 198: return;
! 199: }
! 200:
! 201: bzero(sbt, sizeof *sbt);
! 202: strlcpy(sbt->name, sc->sc_dev.dv_xname, sizeof(sbt->name));
! 203: sbt->cookie = sc;
! 204: sbt->parent = sc->sc_bustag;
! 205: sbt->asi = sbt->parent->asi;
! 206: sbt->sasi = sbt->parent->sasi;
! 207: sbt->sparc_bus_map = qec_bus_map;
! 208: sbt->sparc_intr_establish = qec_intr_establish;
! 209:
! 210: /*
! 211: * Save interrupt information for use in our qec_intr_establish()
! 212: * function below. Apparently, the intr level for the quad
! 213: * ethernet board (qe) is stored in the QEC node rather than
! 214: * separately in each of the QE nodes.
! 215: *
! 216: * XXX - qe.c should call bus_intr_establish() with `level = 0'..
! 217: * XXX - maybe we should have our own attach args for all that.
! 218: */
! 219: sc->sc_intr = sa->sa_intr;
! 220:
! 221: printf(": %dK memory\n", sc->sc_bufsiz / 1024);
! 222:
! 223: qec_init(sc);
! 224:
! 225: /* search through children */
! 226: for (node = firstchild(node); node; node = nextsibling(node)) {
! 227: struct sbus_attach_args sa;
! 228:
! 229: sbus_setup_attach_args((struct sbus_softc *)parent,
! 230: sbt, sc->sc_dmatag, node, &sa);
! 231: (void)config_found(&sc->sc_dev, (void *)&sa, qecprint);
! 232: sbus_destroy_attach_args(&sa);
! 233: }
! 234: }
! 235:
! 236: int
! 237: qec_bus_map(t, t0, addr, size, flags, hp)
! 238: bus_space_tag_t t;
! 239: bus_space_tag_t t0;
! 240: bus_addr_t addr;
! 241: bus_size_t size;
! 242: int flags;
! 243: bus_space_handle_t *hp;
! 244: {
! 245: struct qec_softc *sc = t->cookie;
! 246: int slot = BUS_ADDR_IOSPACE(addr);
! 247: bus_addr_t offset = BUS_ADDR_PADDR(addr);
! 248: int i;
! 249:
! 250: for (t = t->parent; t; t = t->parent) {
! 251: if (t->sparc_bus_map != NULL)
! 252: break;
! 253: }
! 254:
! 255: if (t == NULL) {
! 256: printf("\nqec_bus_map: invalid parent");
! 257: return (EINVAL);
! 258: }
! 259:
! 260: if (flags & BUS_SPACE_MAP_PROMADDRESS) {
! 261: return ((*t->sparc_bus_map)
! 262: (t, t0, offset, size, flags, hp));
! 263: }
! 264:
! 265: for (i = 0; i < sc->sc_nrange; i++) {
! 266: bus_addr_t paddr;
! 267: int iospace;
! 268:
! 269: if (sc->sc_range[i].cspace != slot)
! 270: continue;
! 271:
! 272: /* We've found the connection to the parent bus */
! 273: paddr = sc->sc_range[i].poffset + offset;
! 274: iospace = sc->sc_range[i].pspace;
! 275: return ((*t->sparc_bus_map)
! 276: (t, t0, BUS_ADDR(iospace, paddr), size, flags, hp));
! 277: }
! 278:
! 279: return (EINVAL);
! 280: }
! 281:
! 282: void *
! 283: qec_intr_establish(t, t0, pri, level, flags, handler, arg, what)
! 284: bus_space_tag_t t;
! 285: bus_space_tag_t t0;
! 286: int pri;
! 287: int level;
! 288: int flags;
! 289: int (*handler)(void *);
! 290: void *arg;
! 291: const char *what;
! 292: {
! 293: struct qec_softc *sc = t->cookie;
! 294:
! 295: if (pri == 0) {
! 296: /*
! 297: * qe.c calls bus_intr_establish() with `pri == 0'
! 298: * XXX - see also comment in qec_attach().
! 299: */
! 300: if (sc->sc_intr == NULL) {
! 301: printf("%s: warning: no interrupts\n",
! 302: sc->sc_dev.dv_xname);
! 303: return (NULL);
! 304: }
! 305: pri = sc->sc_intr->sbi_pri;
! 306: }
! 307:
! 308: for (t = t->parent; t; t = t->parent) {
! 309: if (t->sparc_intr_establish != NULL)
! 310: return ((*t->sparc_intr_establish)
! 311: (t, t0, pri, level, flags, handler, arg, what));
! 312: }
! 313:
! 314: panic("qec_intr_extablish): no handler found");
! 315:
! 316: return (NULL);
! 317: }
! 318:
! 319: void
! 320: qec_init(sc)
! 321: struct qec_softc *sc;
! 322: {
! 323: bus_space_tag_t t = sc->sc_bustag;
! 324: bus_space_handle_t qr = sc->sc_regs;
! 325: u_int32_t v, burst = 0, psize;
! 326: int i;
! 327:
! 328: /* First, reset the controller */
! 329: bus_space_write_4(t, qr, QEC_QRI_CTRL, QEC_CTRL_RESET);
! 330: for (i = 0; i < 1000; i++) {
! 331: DELAY(100);
! 332: v = bus_space_read_4(t, qr, QEC_QRI_CTRL);
! 333: if ((v & QEC_CTRL_RESET) == 0)
! 334: break;
! 335: }
! 336:
! 337: /*
! 338: * Cut available buffer size into receive and transmit buffers.
! 339: * XXX - should probably be done in be & qe driver...
! 340: */
! 341: v = sc->sc_msize = sc->sc_bufsiz / sc->sc_nchannels;
! 342: bus_space_write_4(t, qr, QEC_QRI_MSIZE, v);
! 343:
! 344: v = sc->sc_rsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
! 345: bus_space_write_4(t, qr, QEC_QRI_RSIZE, v);
! 346: bus_space_write_4(t, qr, QEC_QRI_TSIZE, v);
! 347:
! 348: psize = sc->sc_nchannels == 1 ? QEC_PSIZE_2048 : 0;
! 349: bus_space_write_4(t, qr, QEC_QRI_PSIZE, psize);
! 350:
! 351: if (sc->sc_burst & SBUS_BURST_64)
! 352: burst = QEC_CTRL_B64;
! 353: else if (sc->sc_burst & SBUS_BURST_32)
! 354: burst = QEC_CTRL_B32;
! 355: else
! 356: burst = QEC_CTRL_B16;
! 357:
! 358: v = bus_space_read_4(t, qr, QEC_QRI_CTRL);
! 359: v = (v & QEC_CTRL_MODEMASK) | burst;
! 360: bus_space_write_4(t, qr, QEC_QRI_CTRL, v);
! 361: }
! 362:
! 363: /*
! 364: * Common routine to initialize the QEC packet ring buffer.
! 365: * Called from be & qe drivers.
! 366: */
! 367: void
! 368: qec_meminit(qr, pktbufsz)
! 369: struct qec_ring *qr;
! 370: unsigned int pktbufsz;
! 371: {
! 372: bus_addr_t txbufdma, rxbufdma;
! 373: bus_addr_t dma;
! 374: caddr_t p;
! 375: unsigned int ntbuf, nrbuf, i;
! 376:
! 377: p = qr->rb_membase;
! 378: dma = qr->rb_dmabase;
! 379:
! 380: ntbuf = qr->rb_ntbuf;
! 381: nrbuf = qr->rb_nrbuf;
! 382:
! 383: /*
! 384: * Allocate transmit descriptors
! 385: */
! 386: qr->rb_txd = (struct qec_xd *)p;
! 387: qr->rb_txddma = dma;
! 388: p += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
! 389: dma += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
! 390:
! 391: /*
! 392: * Allocate receive descriptors
! 393: */
! 394: qr->rb_rxd = (struct qec_xd *)p;
! 395: qr->rb_rxddma = dma;
! 396: p += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
! 397: dma += QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd);
! 398:
! 399:
! 400: /*
! 401: * Allocate transmit buffers
! 402: */
! 403: qr->rb_txbuf = p;
! 404: txbufdma = dma;
! 405: p += ntbuf * pktbufsz;
! 406: dma += ntbuf * pktbufsz;
! 407:
! 408: /*
! 409: * Allocate receive buffers
! 410: */
! 411: qr->rb_rxbuf = p;
! 412: rxbufdma = dma;
! 413: p += nrbuf * pktbufsz;
! 414: dma += nrbuf * pktbufsz;
! 415:
! 416: /*
! 417: * Initialize transmit buffer descriptors
! 418: */
! 419: for (i = 0; i < QEC_XD_RING_MAXSIZE; i++) {
! 420: qr->rb_txd[i].xd_addr = (u_int32_t)
! 421: (txbufdma + (i % ntbuf) * pktbufsz);
! 422: qr->rb_txd[i].xd_flags = 0;
! 423: }
! 424:
! 425: /*
! 426: * Initialize receive buffer descriptors
! 427: */
! 428: for (i = 0; i < QEC_XD_RING_MAXSIZE; i++) {
! 429: qr->rb_rxd[i].xd_addr = (u_int32_t)
! 430: (rxbufdma + (i % nrbuf) * pktbufsz);
! 431: qr->rb_rxd[i].xd_flags = (i < nrbuf)
! 432: ? QEC_XD_OWN | (pktbufsz & QEC_XD_LENGTH)
! 433: : 0;
! 434: }
! 435:
! 436: qr->rb_tdhead = qr->rb_tdtail = 0;
! 437: qr->rb_td_nbusy = 0;
! 438: qr->rb_rdtail = 0;
! 439: }
CVSweb