Annotation of sys/arch/sparc/dev/qec.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: qec.c,v 1.17 2006/06/02 20:00:54 miod Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
! 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 AUTHORS ``AS IS'' AND ANY EXPRESS OR
! 17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 19: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
! 20: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 21: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 22: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 23: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 24: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 25: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 26: */
! 27:
! 28: #include <sys/types.h>
! 29: #include <sys/param.h>
! 30: #include <sys/systm.h>
! 31: #include <sys/kernel.h>
! 32: #include <sys/errno.h>
! 33: #include <sys/ioctl.h>
! 34: #include <sys/device.h>
! 35: #include <sys/malloc.h>
! 36: #include <sys/buf.h>
! 37: #include <sys/proc.h>
! 38: #include <sys/user.h>
! 39: #include <sys/mbuf.h>
! 40: #include <sys/socket.h>
! 41:
! 42: #include <net/if.h>
! 43: #include <net/if_dl.h>
! 44: #include <net/if_types.h>
! 45: #include <net/netisr.h>
! 46: #include <net/if_media.h>
! 47:
! 48: #ifdef INET
! 49: #include <netinet/in.h>
! 50: #include <netinet/in_systm.h>
! 51: #include <netinet/in_var.h>
! 52: #include <netinet/ip.h>
! 53: #include <netinet/if_ether.h>
! 54: #endif
! 55:
! 56: #include <sparc/autoconf.h>
! 57: #include <sparc/cpu.h>
! 58:
! 59: #include <sparc/dev/sbusvar.h>
! 60: #include <sparc/dev/dmareg.h>
! 61: #include <sparc/dev/qecreg.h>
! 62: #include <sparc/dev/qecvar.h>
! 63:
! 64: int qecprint(void *, const char *);
! 65: int qecmatch(struct device *, void *, void *);
! 66: void qecattach(struct device *, struct device *, void *);
! 67: void qec_fix_range(struct qec_softc *, struct sbus_softc *);
! 68: void qec_translate(struct qec_softc *, struct confargs *);
! 69:
! 70: struct cfattach qec_ca = {
! 71: sizeof(struct qec_softc), qecmatch, qecattach
! 72: };
! 73:
! 74: struct cfdriver qec_cd = {
! 75: NULL, "qec", DV_DULL
! 76: };
! 77:
! 78: int
! 79: qecprint(aux, name)
! 80: void *aux;
! 81: const char *name;
! 82: {
! 83: register struct confargs *ca = aux;
! 84:
! 85: if (name)
! 86: printf("%s at %s", ca->ca_ra.ra_name, name);
! 87: printf(" offset 0x%x", ca->ca_offset);
! 88: return (UNCONF);
! 89: }
! 90:
! 91: /*
! 92: * match a QEC device in a slot capable of DMA
! 93: */
! 94: int
! 95: qecmatch(parent, vcf, aux)
! 96: struct device *parent;
! 97: void *vcf, *aux;
! 98: {
! 99: struct cfdata *cf = vcf;
! 100: struct confargs *ca = aux;
! 101: struct romaux *ra = &ca->ca_ra;
! 102:
! 103: if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
! 104: return (0);
! 105:
! 106: if (!sbus_testdma((struct sbus_softc *)parent, ca))
! 107: return (0);
! 108:
! 109: return (1);
! 110: }
! 111:
! 112: /*
! 113: * Attach all the sub-devices we can find
! 114: */
! 115: void
! 116: qecattach(parent, self, aux)
! 117: struct device *parent, *self;
! 118: void *aux;
! 119: {
! 120: register struct confargs *ca = aux;
! 121: struct qec_softc *sc = (void *)self;
! 122: int node;
! 123: struct confargs oca;
! 124: char *name;
! 125: int sbusburst;
! 126:
! 127: /*
! 128: * The first i/o space is the qec global registers, and
! 129: * the second is a buffer used by the qec channels internally.
! 130: * (It's not necessary to map the second i/o space, but knowing
! 131: * its size is necessary).
! 132: */
! 133: sc->sc_regs = mapiodev(&ca->ca_ra.ra_reg[0], 0,
! 134: sizeof(struct qecregs));
! 135: sc->sc_bufsiz = ca->ca_ra.ra_reg[1].rr_len;
! 136: sc->sc_paddr = ca->ca_ra.ra_reg[0].rr_paddr;
! 137:
! 138: /*
! 139: * On qec+qe, the qec has the interrupt priority, but we
! 140: * need to pass that down so that the qe's can handle them.
! 141: */
! 142: if (ca->ca_ra.ra_nintr == 1)
! 143: sc->sc_pri = ca->ca_ra.ra_intr[0].int_pri;
! 144:
! 145: node = sc->sc_node = ca->ca_ra.ra_node;
! 146:
! 147: qec_fix_range(sc, (struct sbus_softc *)parent);
! 148:
! 149: /*
! 150: * Get transfer burst size from PROM
! 151: */
! 152: sbusburst = ((struct sbus_softc *)parent)->sc_burst;
! 153: if (sbusburst == 0)
! 154: sbusburst = SBUS_BURST_32 - 1; /* 1->16 */
! 155:
! 156: sc->sc_nchannels = getpropint(ca->ca_ra.ra_node, "#channels", -1);
! 157: if (sc->sc_nchannels == -1) {
! 158: printf(": no channels\n");
! 159: return;
! 160: }
! 161: else if (sc->sc_nchannels < 1 || sc->sc_nchannels > 4) {
! 162: printf(": invalid number of channels: %d\n", sc->sc_nchannels);
! 163: return;
! 164: }
! 165:
! 166: sc->sc_burst = getpropint(ca->ca_ra.ra_node, "burst-sizes", -1);
! 167: if (sc->sc_burst == -1)
! 168: /* take SBus burst sizes */
! 169: sc->sc_burst = sbusburst;
! 170:
! 171: /* Clamp at parent's burst sizes */
! 172: sc->sc_burst &= sbusburst;
! 173:
! 174: printf(": %dK memory %d channel%s",
! 175: sc->sc_bufsiz / 1024, sc->sc_nchannels,
! 176: (sc->sc_nchannels == 1) ? "" : "s");
! 177:
! 178: node = sc->sc_node = ca->ca_ra.ra_node;
! 179:
! 180: /* Propagate bootpath */
! 181: if (ca->ca_ra.ra_bp != NULL)
! 182: oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
! 183: else
! 184: oca.ca_ra.ra_bp = NULL;
! 185:
! 186: printf("\n");
! 187:
! 188: qec_reset(sc);
! 189:
! 190: /* search through children */
! 191: for (node = firstchild(node); node; node = nextsibling(node)) {
! 192: name = getpropstring(node, "name");
! 193: if (!romprop(&oca.ca_ra, name, node))
! 194: continue;
! 195:
! 196: qec_translate(sc, &oca);
! 197: oca.ca_bustype = BUS_SBUS;
! 198: (void) config_found(&sc->sc_dev, (void *)&oca, qecprint);
! 199: }
! 200: }
! 201:
! 202: void
! 203: qec_fix_range(sc, sbp)
! 204: struct qec_softc *sc;
! 205: struct sbus_softc *sbp;
! 206: {
! 207: int rlen, i, j;
! 208:
! 209: rlen = getproplen(sc->sc_node, "ranges");
! 210: sc->sc_range =
! 211: (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT);
! 212: if (sc->sc_range == NULL) {
! 213: printf("%s: PROM ranges too large: %d\n",
! 214: sc->sc_dev.dv_xname, rlen);
! 215: return;
! 216: }
! 217: sc->sc_nrange = rlen / sizeof(struct rom_range);
! 218: (void)getprop(sc->sc_node, "ranges", sc->sc_range, rlen);
! 219:
! 220: for (i = 0; i < sc->sc_nrange; i++) {
! 221: for (j = 0; j < sbp->sc_nrange; j++) {
! 222: if (sc->sc_range[i].pspace == sbp->sc_range[j].cspace) {
! 223: sc->sc_range[i].poffset +=
! 224: sbp->sc_range[j].poffset;
! 225: sc->sc_range[i].pspace =
! 226: sbp->sc_range[j].pspace;
! 227: break;
! 228: }
! 229: }
! 230: }
! 231: }
! 232:
! 233: /*
! 234: * Translate the register addresses of our children
! 235: */
! 236: void
! 237: qec_translate(sc, ca)
! 238: struct qec_softc *sc;
! 239: struct confargs *ca;
! 240: {
! 241: register int i;
! 242:
! 243: ca->ca_slot = ca->ca_ra.ra_iospace;
! 244: ca->ca_offset = sc->sc_range[ca->ca_slot].poffset - (long)sc->sc_paddr;
! 245:
! 246: /* Translate into parent address spaces */
! 247: for (i = 0; i < ca->ca_ra.ra_nreg; i++) {
! 248: int j, cspace = ca->ca_ra.ra_reg[i].rr_iospace;
! 249:
! 250: for (j = 0; j < sc->sc_nrange; j++) {
! 251: if (sc->sc_range[j].cspace == cspace) {
! 252: (int)ca->ca_ra.ra_reg[i].rr_paddr +=
! 253: sc->sc_range[j].poffset;
! 254: (int)ca->ca_ra.ra_reg[i].rr_iospace =
! 255: sc->sc_range[j].pspace;
! 256: break;
! 257: }
! 258: }
! 259: }
! 260: }
! 261:
! 262: /*
! 263: * Reset the QEC and initialize its global registers.
! 264: */
! 265: void
! 266: qec_reset(sc)
! 267: struct qec_softc *sc;
! 268: {
! 269: struct qecregs *qr = sc->sc_regs;
! 270: int i = 200;
! 271:
! 272: qr->ctrl = QEC_CTRL_RESET;
! 273: while (--i) {
! 274: if ((qr->ctrl & QEC_CTRL_RESET) == 0)
! 275: break;
! 276: DELAY(20);
! 277: }
! 278: if (i == 0) {
! 279: printf("%s: reset failed.\n", sc->sc_dev.dv_xname);
! 280: return;
! 281: }
! 282:
! 283: qr->msize = sc->sc_bufsiz / sc->sc_nchannels;
! 284: sc->sc_msize = qr->msize;
! 285:
! 286: qr->rsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
! 287: sc->sc_rsize = qr->rsize;
! 288:
! 289: qr->tsize = sc->sc_bufsiz / (sc->sc_nchannels * 2);
! 290:
! 291: qr->psize = QEC_PSIZE_2048;
! 292:
! 293: if (sc->sc_burst & SBUS_BURST_64)
! 294: i = QEC_CTRL_B64;
! 295: else if (sc->sc_burst & SBUS_BURST_32)
! 296: i = QEC_CTRL_B32;
! 297: else
! 298: i = QEC_CTRL_B16;
! 299:
! 300: qr->ctrl = (qr->ctrl & QEC_CTRL_MODEMASK) | i;
! 301: }
! 302:
! 303: /*
! 304: * Routine to copy from mbuf chain to transmit buffer in
! 305: * network buffer memory.
! 306: */
! 307: int
! 308: qec_put(buf, m0)
! 309: u_int8_t *buf;
! 310: struct mbuf *m0;
! 311: {
! 312: struct mbuf *m;
! 313: int len, tlen = 0;
! 314:
! 315: for (m = m0; m != NULL; m = m->m_next) {
! 316: len = m->m_len;
! 317: bcopy(mtod(m, caddr_t), buf, len);
! 318: buf += len;
! 319: tlen += len;
! 320: }
! 321: m_freem(m0);
! 322: return (tlen);
! 323: }
! 324:
! 325: /*
! 326: * Pull data off an interface.
! 327: * Len is the length of data, with local net header stripped.
! 328: * We copy the data into mbufs. When full cluster sized units are present,
! 329: * we copy into clusters.
! 330: */
! 331: struct mbuf *
! 332: qec_get(ifp, buf, totlen)
! 333: struct ifnet *ifp;
! 334: u_int8_t *buf;
! 335: int totlen;
! 336: {
! 337: struct mbuf *m, *top, **mp;
! 338: int len, pad;
! 339:
! 340: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 341: if (m == NULL)
! 342: return (NULL);
! 343: m->m_pkthdr.rcvif = ifp;
! 344: m->m_pkthdr.len = totlen;
! 345: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
! 346: len = MHLEN;
! 347: if (totlen >= MINCLSIZE) {
! 348: MCLGET(m, M_DONTWAIT);
! 349: if (m->m_flags & M_EXT)
! 350: len = MCLBYTES;
! 351: }
! 352: m->m_data += pad;
! 353: len -= pad;
! 354: top = NULL;
! 355: mp = ⊤
! 356:
! 357: while (totlen > 0) {
! 358: if (top) {
! 359: MGET(m, M_DONTWAIT, MT_DATA);
! 360: if (m == NULL) {
! 361: m_freem(top);
! 362: return NULL;
! 363: }
! 364: len = MLEN;
! 365: }
! 366: if (top && totlen >= MINCLSIZE) {
! 367: MCLGET(m, M_DONTWAIT);
! 368: if (m->m_flags & M_EXT)
! 369: len = MCLBYTES;
! 370: }
! 371: m->m_len = len = min(totlen, len);
! 372: bcopy(buf, mtod(m, caddr_t), len);
! 373: buf += len;
! 374: totlen -= len;
! 375: *mp = m;
! 376: mp = &m->m_next;
! 377: }
! 378:
! 379: return (top);
! 380: }
CVSweb