root/dev/sbus/if_le_ledma.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. le_ledma_wrcsr
  2. le_ledma_rdcsr
  3. le_ledma_setutp
  4. le_ledma_setaui
  5. lemediachange
  6. lemediastatus
  7. le_ledma_hwreset
  8. le_ledma_hwinit
  9. le_ledma_nocarrier
  10. lematch_ledma
  11. leattach_ledma

    1 /*      $OpenBSD: if_le_ledma.c,v 1.13 2007/05/31 17:23:14 sobrado Exp $        */
    2 /*      $NetBSD: if_le_ledma.c,v 1.14 2001/05/30 11:46:35 mrg Exp $     */
    3 
    4 /*-
    5  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
   10  * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by the NetBSD
   23  *      Foundation, Inc. and its contributors.
   24  * 4. Neither the name of The NetBSD Foundation nor the names of its
   25  *    contributors may be used to endorse or promote products derived
   26  *    from this software without specific prior written permission.
   27  *
   28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   38  * POSSIBILITY OF SUCH DAMAGE.
   39  */
   40 
   41 #include "bpfilter.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/mbuf.h>
   46 #include <sys/syslog.h>
   47 #include <sys/socket.h>
   48 #include <sys/device.h>
   49 #include <sys/malloc.h>
   50 
   51 #include <net/if.h>
   52 #include <net/if_media.h>
   53 
   54 #ifdef INET
   55 #include <netinet/in.h>
   56 #include <netinet/if_ether.h>
   57 #endif
   58 
   59 #include <machine/bus.h>
   60 #include <machine/intr.h>
   61 #include <machine/autoconf.h>
   62 
   63 #include <dev/sbus/sbusvar.h>
   64 
   65 #include <dev/ic/lsi64854reg.h>
   66 #include <dev/ic/lsi64854var.h>
   67 
   68 #include <dev/ic/am7990reg.h>
   69 #include <dev/ic/am7990var.h>
   70 
   71 /*
   72  * LANCE registers.
   73  */
   74 #define LEREG1_RDP      0       /* Register Data port */
   75 #define LEREG1_RAP      2       /* Register Address port */
   76 
   77 struct  le_softc {
   78         struct  am7990_softc    sc_am7990;      /* glue to MI code */
   79         bus_space_tag_t         sc_bustag;
   80         bus_dmamap_t            sc_dmamap;
   81         bus_space_handle_t      sc_reg;         /* LANCE registers */
   82         struct  lsi64854_softc  *sc_dma;        /* pointer to my dma */
   83         u_int                   sc_laddr;       /* LANCE DMA address */
   84 };
   85 
   86 #define MEMSIZE         (16*1024)       /* LANCE memory size */
   87 #define LEDMA_BOUNDARY  (16*1024*1024)  /* must not cross 16MB boundary */
   88 
   89 int     lematch_ledma(struct device *, void *, void *);
   90 void    leattach_ledma(struct device *, struct device *, void *);
   91 
   92 /*
   93  * Media types supported by the Sun4m.
   94  */
   95 
   96 void    le_ledma_setutp(struct am7990_softc *);
   97 void    le_ledma_setaui(struct am7990_softc *);
   98 
   99 int     lemediachange(struct ifnet *);
  100 void    lemediastatus(struct ifnet *, struct ifmediareq *);
  101 
  102 struct cfattach le_ledma_ca = {
  103         sizeof(struct le_softc), lematch_ledma, leattach_ledma
  104 };
  105 
  106 void le_ledma_wrcsr(struct am7990_softc *, u_int16_t, u_int16_t);
  107 u_int16_t le_ledma_rdcsr(struct am7990_softc *, u_int16_t);
  108 void le_ledma_hwreset(struct am7990_softc *);
  109 void le_ledma_hwinit(struct am7990_softc *);
  110 void le_ledma_nocarrier(struct am7990_softc *);
  111 
  112 void
  113 le_ledma_wrcsr(struct am7990_softc *sc, u_int16_t port, u_int16_t val)
  114 {
  115         struct le_softc *lesc = (struct le_softc *)sc;
  116 
  117         bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, port);
  118         bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, 2,
  119             BUS_SPACE_BARRIER_WRITE);
  120         bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP, val);
  121         bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP, 2,
  122             BUS_SPACE_BARRIER_WRITE);
  123 
  124 #if defined(SUN4M)
  125         /*
  126          * We need to flush the SBus->MBus write buffers. This can most
  127          * easily be accomplished by reading back the register that we
  128          * just wrote (thanks to Chris Torek for this solution).
  129          */
  130         if (CPU_ISSUN4M) {
  131                 volatile u_int16_t discard;
  132                 discard = bus_space_read_2(lesc->sc_bustag, lesc->sc_reg,
  133                                            LEREG1_RDP);
  134         }
  135 #endif
  136 }
  137 
  138 u_int16_t
  139 le_ledma_rdcsr(struct am7990_softc *sc, u_int16_t port)
  140 {
  141         struct le_softc *lesc = (struct le_softc *)sc;
  142 
  143         bus_space_write_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, port);
  144         bus_space_barrier(lesc->sc_bustag, lesc->sc_reg, LEREG1_RAP, 2,
  145             BUS_SPACE_BARRIER_WRITE);
  146         return (bus_space_read_2(lesc->sc_bustag, lesc->sc_reg, LEREG1_RDP));
  147 }
  148 
  149 void
  150 le_ledma_setutp(struct am7990_softc *sc)
  151 {
  152         struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
  153         u_int32_t csr;
  154 
  155         csr = L64854_GCSR(dma);
  156         csr |= E_TP_AUI;
  157         L64854_SCSR(dma, csr);
  158         delay(20000);   /* must not touch le for 20ms */
  159 }
  160 
  161 void
  162 le_ledma_setaui(struct am7990_softc *sc)
  163 {
  164         struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
  165         u_int32_t csr;
  166 
  167         csr = L64854_GCSR(dma);
  168         csr &= ~E_TP_AUI;
  169         L64854_SCSR(dma, csr);
  170         delay(20000);   /* must not touch le for 20ms */
  171 }
  172 
  173 int
  174 lemediachange(struct ifnet *ifp)
  175 {
  176         struct am7990_softc *sc = ifp->if_softc;
  177         struct ifmedia *ifm = &sc->sc_ifmedia;
  178 
  179         if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
  180                 return (EINVAL);
  181 
  182         /*
  183          * Switch to the selected media.  If autoselect is
  184          * set, we don't really have to do anything.  We'll
  185          * switch to the other media when we detect loss of
  186          * carrier.
  187          */
  188         switch (IFM_SUBTYPE(ifm->ifm_media)) {
  189         case IFM_10_T:
  190                 le_ledma_setutp(sc);
  191                 break;
  192 
  193         case IFM_10_5:
  194                 le_ledma_setaui(sc);
  195                 break;
  196 
  197         case IFM_AUTO:
  198                 break;
  199 
  200         default:
  201                 return (EINVAL);
  202         }
  203 
  204         return (0);
  205 }
  206 
  207 void
  208 lemediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
  209 {
  210         struct am7990_softc *sc = ifp->if_softc;
  211         struct lsi64854_softc *dma = ((struct le_softc *)sc)->sc_dma;
  212 
  213         /*
  214          * Notify the world which media we're currently using.
  215          */
  216         if (L64854_GCSR(dma) & E_TP_AUI)
  217                 ifmr->ifm_active = IFM_ETHER|IFM_10_T;
  218         else
  219                 ifmr->ifm_active = IFM_ETHER|IFM_10_5;
  220 }
  221 
  222 void
  223 le_ledma_hwreset(struct am7990_softc *sc)
  224 {
  225         struct le_softc *lesc = (struct le_softc *)sc;
  226         struct lsi64854_softc *dma = lesc->sc_dma;
  227         u_int32_t csr;
  228         u_int aui_bit;
  229 
  230         /*
  231          * Reset DMA channel.
  232          */
  233         csr = L64854_GCSR(dma);
  234         aui_bit = csr & E_TP_AUI;
  235         DMA_RESET(dma);
  236 
  237         /* Write bits 24-31 of Lance address */
  238         bus_space_write_4(dma->sc_bustag, dma->sc_regs, L64854_REG_ENBAR,
  239                           lesc->sc_laddr & 0xff000000);
  240 
  241         DMA_ENINTR(dma);
  242 
  243         /*
  244          * Disable E-cache invalidates on chip writes.
  245          * Retain previous cable selection bit.
  246          */
  247         csr = L64854_GCSR(dma);
  248         csr |= (E_DSBL_WR_INVAL | aui_bit);
  249         L64854_SCSR(dma, csr);
  250         delay(20000);   /* must not touch le for 20ms */
  251 }
  252 
  253 void
  254 le_ledma_hwinit(struct am7990_softc *sc)
  255 {
  256 
  257         /*
  258          * Make sure we're using the currently-enabled media type.
  259          * XXX Actually, this is probably unnecessary, now.
  260          */
  261         switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_cur->ifm_media)) {
  262         case IFM_10_T:
  263                 le_ledma_setutp(sc);
  264                 break;
  265 
  266         case IFM_10_5:
  267                 le_ledma_setaui(sc);
  268                 break;
  269         }
  270 }
  271 
  272 void
  273 le_ledma_nocarrier(struct am7990_softc *sc)
  274 {
  275         struct le_softc *lesc = (struct le_softc *)sc;
  276 
  277         /*
  278          * Check if the user has requested a certain cable type, and
  279          * if so, honor that request.
  280          */
  281 
  282         if (L64854_GCSR(lesc->sc_dma) & E_TP_AUI) {
  283                 switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
  284                 case IFM_10_5:
  285                 case IFM_AUTO:
  286                         printf("%s: lost carrier on UTP port"
  287                             ", switching to AUI port\n", sc->sc_dev.dv_xname);
  288                         le_ledma_setaui(sc);
  289                 }
  290         } else {
  291                 switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
  292                 case IFM_10_T:
  293                 case IFM_AUTO:
  294                         printf("%s: lost carrier on AUI port"
  295                             ", switching to UTP port\n", sc->sc_dev.dv_xname);
  296                         le_ledma_setutp(sc);
  297                 }
  298         }
  299 }
  300 
  301 int
  302 lematch_ledma(struct device *parent, void *vcf, void *aux)
  303 {
  304         struct cfdata *cf = vcf;
  305         struct sbus_attach_args *sa = aux;
  306 
  307         return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
  308 }
  309 
  310 
  311 void
  312 leattach_ledma(struct device *parent, struct device *self, void *aux)
  313 {
  314         struct sbus_attach_args *sa = aux;
  315         struct le_softc *lesc = (struct le_softc *)self;
  316         struct lsi64854_softc *lsi = (struct lsi64854_softc *)parent;
  317         struct am7990_softc *sc = &lesc->sc_am7990;
  318         bus_dma_tag_t dmatag = sa->sa_dmatag;
  319         bus_dma_segment_t seg;
  320         int rseg, error;
  321         /* XXX the following declarations should be elsewhere */
  322         extern void myetheraddr(u_char *);
  323 
  324         lesc->sc_bustag = sa->sa_bustag;
  325 
  326         /* Establish link to `ledma' device */
  327         lesc->sc_dma = lsi;
  328         lesc->sc_dma->sc_client = lesc;
  329 
  330         /* Map device registers */
  331         if (sbus_bus_map(sa->sa_bustag,
  332                            sa->sa_slot,
  333                            sa->sa_offset,
  334                            sa->sa_size,
  335                            BUS_SPACE_MAP_LINEAR,
  336                            0, &lesc->sc_reg) != 0) {
  337                 printf("%s @ ledma: cannot map registers\n", self->dv_xname);
  338                 return;
  339         }
  340 
  341         /* Allocate buffer memory */
  342         sc->sc_memsize = MEMSIZE;
  343 
  344         /* Get a DMA handle */
  345         if ((error = bus_dmamap_create(dmatag, MEMSIZE, 1, MEMSIZE,
  346                                         LEDMA_BOUNDARY, BUS_DMA_NOWAIT,
  347                                         &lesc->sc_dmamap)) != 0) {
  348                 printf("%s: DMA map create error %d\n", self->dv_xname, error);
  349                 return;
  350         }
  351 
  352         /* Allocate DMA buffer */
  353         if ((error = bus_dmamem_alloc(dmatag, MEMSIZE, 0, LEDMA_BOUNDARY,
  354                                  &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
  355                 printf("%s @ ledma: DMA buffer alloc error %d\n",
  356                         self->dv_xname, error);
  357                 return;
  358         }
  359 
  360         /* Map DMA buffer into kernel space */
  361         if ((error = bus_dmamem_map(dmatag, &seg, rseg, MEMSIZE,
  362                                (caddr_t *)&sc->sc_mem,
  363                                BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
  364                 printf("%s @ ledma: DMA buffer map error %d\n",
  365                         self->dv_xname, error);
  366                 bus_dmamem_free(dmatag, &seg, rseg);
  367                 return;
  368         }
  369 
  370         /* Load DMA buffer */
  371         if ((error = bus_dmamap_load(dmatag, lesc->sc_dmamap, sc->sc_mem,
  372                         MEMSIZE, NULL, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
  373                 printf("%s: DMA buffer map load error %d\n",
  374                         self->dv_xname, error);
  375                 bus_dmamem_free(dmatag, &seg, rseg);
  376                 bus_dmamem_unmap(dmatag, sc->sc_mem, MEMSIZE);
  377                 return;
  378         }
  379 
  380         lesc->sc_laddr = lesc->sc_dmamap->dm_segs[0].ds_addr;
  381         sc->sc_addr = lesc->sc_laddr & 0xffffff;
  382         sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
  383 
  384         ifmedia_init(&sc->sc_ifmedia, 0, lemediachange, lemediastatus);
  385         ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
  386         ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
  387         ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
  388         ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
  389         sc->sc_hasifmedia = 1;
  390 
  391         myetheraddr(sc->sc_arpcom.ac_enaddr);
  392 
  393         sc->sc_copytodesc = am7990_copytobuf_contig;
  394         sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
  395         sc->sc_copytobuf = am7990_copytobuf_contig;
  396         sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
  397         sc->sc_zerobuf = am7990_zerobuf_contig;
  398 
  399         sc->sc_rdcsr = le_ledma_rdcsr;
  400         sc->sc_wrcsr = le_ledma_wrcsr;
  401         sc->sc_hwinit = le_ledma_hwinit;
  402         sc->sc_nocarrier = le_ledma_nocarrier;
  403         sc->sc_hwreset = le_ledma_hwreset;
  404 
  405         /* Establish interrupt handler */
  406         if (sa->sa_nintr != 0)
  407                 (void)bus_intr_establish(sa->sa_bustag, sa->sa_pri, IPL_NET, 0,
  408                                          am7990_intr, sc, self->dv_xname);
  409 
  410         am7990_config(&lesc->sc_am7990);
  411 
  412         /* now initialize DMA */
  413         le_ledma_hwreset(sc);
  414 }

/* [<][>][^][v][top][bottom][index][help] */