The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/sbus/qec.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: cf32424e26d3c146dea5fae9b4db6bf7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.