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