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/isa/cs89x0isa.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: cs89x0isa.c,v 1.7 2003/05/09 23:51:28 fvdl Exp $ */
    2 
    3 /*
    4  * Copyright 1997
    5  * Digital Equipment Corporation. All rights reserved.
    6  *
    7  * This software is furnished under license and may be used and
    8  * copied only in accordance with the following terms and conditions.
    9  * Subject to these conditions, you may download, copy, install,
   10  * use, modify and distribute this software in source and/or binary
   11  * form. No title or ownership is transferred hereby.
   12  *
   13  * 1) Any source code used, modified or distributed must reproduce
   14  *    and retain this copyright notice and list of conditions as
   15  *    they appear in the source file.
   16  *
   17  * 2) No right is granted to use any trade name, trademark, or logo of
   18  *    Digital Equipment Corporation. Neither the "Digital Equipment
   19  *    Corporation" name nor any trademark or logo of Digital Equipment
   20  *    Corporation may be used to endorse or promote products derived
   21  *    from this software without the prior written permission of
   22  *    Digital Equipment Corporation.
   23  *
   24  * 3) This software is provided "AS-IS" and any express or implied
   25  *    warranties, including but not limited to, any implied warranties
   26  *    of merchantability, fitness for a particular purpose, or
   27  *    non-infringement are disclaimed. In no event shall DIGITAL be
   28  *    liable for any damages whatsoever, and in particular, DIGITAL
   29  *    shall not be liable for special, indirect, consequential, or
   30  *    incidental damages or damages for lost profits, loss of
   31  *    revenue or loss of use, whether such damages arise in contract,
   32  *    negligence, tort, under statute, in equity, at law or otherwise,
   33  *    even if advised of the possibility of such damage.
   34  */
   35 
   36 /* isa DMA routines for cs89x0 */
   37 
   38 #include <sys/cdefs.h>
   39 __KERNEL_RCSID(0, "$NetBSD: cs89x0isa.c,v 1.7 2003/05/09 23:51:28 fvdl Exp $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/mbuf.h>
   44 #include <sys/socket.h>
   45 #include <sys/device.h>
   46 
   47 #include "rnd.h"
   48 #if NRND > 0
   49 #include <sys/rnd.h>
   50 #endif
   51 
   52 #include <net/if.h>
   53 #include <net/if_ether.h>
   54 #include <net/if_media.h>
   55 
   56 #include <machine/bus.h>
   57 
   58 #include <dev/isa/isareg.h>
   59 #include <dev/isa/isavar.h>
   60 #include <dev/isa/isadmavar.h>
   61 
   62 #include <dev/ic/cs89x0reg.h>
   63 #include <dev/ic/cs89x0var.h>
   64 #include <dev/isa/cs89x0isavar.h>
   65 
   66 #define DMA_STATUS_BITS 0x0007  /* bit masks for checking DMA status */
   67 #define DMA_STATUS_OK 0x0004
   68 
   69 void
   70 cs_isa_dma_attach(struct cs_softc *sc)
   71 {
   72         struct cs_softc_isa *isc = (void *)sc;
   73 
   74         if (isc->sc_drq == ISACF_DRQ_DEFAULT)
   75                 printf("%s: DMA channel unspecified, not using DMA\n",
   76                     sc->sc_dev.dv_xname);
   77         else if (isc->sc_drq < 5 || isc->sc_drq > 7)
   78                 printf("%s: invalid DMA channel, not using DMA\n",
   79                     sc->sc_dev.dv_xname);
   80         else {
   81                 bus_size_t maxsize;
   82                 bus_addr_t dma_addr;
   83 
   84                 maxsize = isa_dmamaxsize(isc->sc_ic, isc->sc_drq);
   85                 if (maxsize < CS8900_DMASIZE) {
   86                         printf("%s: max DMA size %lu is less than required %d\n",
   87                             sc->sc_dev.dv_xname, (u_long)maxsize,
   88                             CS8900_DMASIZE);
   89                         goto after_dma_block;
   90                 }
   91 
   92                 if (isa_drq_alloc(isc->sc_ic, isc->sc_drq) != 0) {
   93                         printf("%s: unable to reserve drq %d\n",
   94                             sc->sc_dev.dv_xname, isc->sc_drq);
   95                         goto after_dma_block;
   96                 }
   97 
   98                 if (isa_dmamap_create(isc->sc_ic, isc->sc_drq,
   99                     CS8900_DMASIZE, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW) != 0) {
  100                         printf("%s: unable to create ISA DMA map\n",
  101                             sc->sc_dev.dv_xname);
  102                         goto after_dma_block;
  103                 }
  104                 if (isa_dmamem_alloc(isc->sc_ic, isc->sc_drq,
  105                     CS8900_DMASIZE, &dma_addr, BUS_DMA_NOWAIT) != 0) {
  106                         printf("%s: unable to allocate DMA buffer\n",
  107                             sc->sc_dev.dv_xname);
  108                         goto after_dma_block;
  109                 }
  110                 if (isa_dmamem_map(isc->sc_ic, isc->sc_drq, dma_addr,
  111                     CS8900_DMASIZE, &isc->sc_dmabase,
  112                        BUS_DMA_NOWAIT | BUS_DMA_COHERENT /* XXX */ ) != 0) {
  113                         printf("%s: unable to map DMA buffer\n",
  114                             sc->sc_dev.dv_xname);
  115                         isa_dmamem_free(isc->sc_ic, isc->sc_drq, dma_addr,
  116                             CS8900_DMASIZE);
  117                         goto after_dma_block;
  118                 }
  119 
  120                 isc->sc_dmasize = CS8900_DMASIZE;
  121                 sc->sc_cfgflags |= CFGFLG_DMA_MODE;
  122                 isc->sc_dmaaddr = dma_addr;
  123 after_dma_block:
  124                 ;
  125         }
  126 }
  127 
  128 void cs_isa_dma_chipinit(struct cs_softc *sc)
  129 {
  130         struct cs_softc_isa *isc = (void *)sc;
  131 
  132         if (sc->sc_cfgflags & CFGFLG_DMA_MODE) {
  133                 /*
  134                  * First we program the DMA controller and ensure the memory
  135                  * buffer is valid. If it isn't then we just go on without
  136                  * DMA.
  137                  */
  138                 if (isa_dmastart(isc->sc_ic, isc->sc_drq, isc->sc_dmabase,
  139                     isc->sc_dmasize, NULL, DMAMODE_READ | DMAMODE_LOOPDEMAND,
  140                     BUS_DMA_NOWAIT)) {
  141                         /* XXX XXX XXX */
  142                         panic("%s: unable to start DMA", sc->sc_dev.dv_xname);
  143                 }
  144                 isc->sc_dmacur = isc->sc_dmabase;
  145 
  146                 /* interrupt when a DMA'd frame is received */
  147                 CS_WRITE_PACKET_PAGE(sc, PKTPG_RX_CFG,
  148                     RX_CFG_ALL_IE | RX_CFG_RX_DMA_ONLY);
  149 
  150                 /*
  151                  * set the DMA burst bit so we don't tie up the bus for too
  152                  * long.
  153                  */
  154                 if (isc->sc_dmasize == 16384) {
  155                         CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL,
  156                             ((CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) &
  157                              ~BUS_CTL_DMA_SIZE) | BUS_CTL_DMA_BURST));
  158                 } else { /* use 64K */
  159                         CS_WRITE_PACKET_PAGE(sc, PKTPG_BUS_CTL,
  160                             CS_READ_PACKET_PAGE(sc, PKTPG_BUS_CTL) |
  161                              BUS_CTL_DMA_SIZE | BUS_CTL_DMA_BURST);
  162                 }
  163 
  164                 CS_WRITE_PACKET_PAGE(sc, PKTPG_DMA_CHANNEL, isc->sc_drq - 5);
  165         }
  166 }
  167 
  168 void cs_process_rx_dma(struct cs_softc *sc)
  169 {
  170         struct cs_softc_isa *isc = (void *)sc;
  171         struct ifnet *ifp;
  172         u_int16_t num_dma_frames;
  173         u_int16_t pkt_length;
  174         u_int16_t status;
  175         u_int to_copy;
  176         char *dma_mem_ptr;
  177         struct mbuf *m;
  178         u_char *pBuff;
  179         int pad;
  180 
  181         /* initialise the pointers */
  182         ifp = &sc->sc_ethercom.ec_if;
  183 
  184         /* Read the number of frames DMAed. */
  185         num_dma_frames = CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
  186         num_dma_frames &= (u_int16_t) (0x0fff);
  187 
  188         /*
  189          * Loop till number of DMA frames ready to read is zero. After
  190          * reading the frame out of memory we must check if any have been
  191          * received while we were processing
  192          */
  193         while (num_dma_frames != 0) {
  194                 dma_mem_ptr = isc->sc_dmacur;
  195 
  196                 /*
  197                  * process all of the DMA frames in memory
  198                  * 
  199                  * This loop relies on the dma_mem_ptr variable being set to the
  200                  * next frames start address.
  201                  */
  202                 for (; num_dma_frames > 0; num_dma_frames--) {
  203 
  204                         /*
  205                          * Get the length and status of the packet. Only the
  206                          * status is guaranteed to be at dma_mem_ptr, ie need
  207                          * to check for wraparound before reading the length
  208                          */
  209                         status = *((unsigned short *) dma_mem_ptr)++;
  210                         if (dma_mem_ptr > (isc->sc_dmabase + isc->sc_dmasize)) {
  211                                 dma_mem_ptr = isc->sc_dmabase;
  212                         }
  213                         pkt_length = *((unsigned short *) dma_mem_ptr)++;
  214 
  215                         /* Do some sanity checks on the length and status. */
  216                         if ((pkt_length > ETHER_MAX_LEN) ||
  217                             ((status & DMA_STATUS_BITS) != DMA_STATUS_OK)) {
  218                                 /*
  219                                  * the SCO driver kills the adapter in this
  220                                  * situation
  221                                  */
  222                                 /*
  223                                  * should increment the error count and reset
  224                                  * the DMA operation.
  225                                  */
  226                                 printf("%s: cs_process_rx_dma: DMA buffer out of sync about to reset\n",
  227                                     sc->sc_dev.dv_xname);
  228                                 ifp->if_ierrors++;
  229 
  230                                 /* skip the rest of the DMA buffer */
  231                                 isa_dmaabort(isc->sc_ic, isc->sc_drq);
  232 
  233                                 /* now reset the chip and reinitialise */
  234                                 cs_init(&sc->sc_ethercom.ec_if);
  235                                 return;
  236                         }
  237                         /* Check the status of the received packet. */
  238                         if (status & RX_EVENT_RX_OK) {
  239                                 /* get a new mbuf */
  240                                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  241                                 if (m == 0) {
  242                                         printf("%s: cs_process_rx_dma: unable to allocate mbuf\n",
  243                                             sc->sc_dev.dv_xname);
  244                                         ifp->if_ierrors++;
  245                                         /*
  246                                          * couldn't allocate an mbuf so
  247                                          * things are not good, may as well
  248                                          * drop all the packets I think.
  249                                          */
  250                                         CS_READ_PACKET_PAGE(sc,
  251                                             PKTPG_DMA_FRAME_COUNT);
  252 
  253                                         /* now reset DMA operation */
  254                                         isa_dmaabort(isc->sc_ic, isc->sc_drq);
  255 
  256                                         /*
  257                                          * now reset the chip and
  258                                          * reinitialise
  259                                          */
  260                                         cs_init(&sc->sc_ethercom.ec_if);
  261                                         return;
  262                                 }
  263                                 /*
  264                                  * save processing by always using a mbuf
  265                                  * cluster, guaranteed to fit packet
  266                                  */
  267                                 MCLGET(m, M_DONTWAIT);
  268                                 if ((m->m_flags & M_EXT) == 0) {
  269                                         /* couldn't allocate an mbuf cluster */
  270                                         printf("%s: cs_process_rx_dma: unable to allocate a cluster\n",
  271                                             sc->sc_dev.dv_xname);
  272                                         m_freem(m);
  273 
  274                                         /* skip the frame */
  275                                         CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
  276                                         isa_dmaabort(isc->sc_ic, isc->sc_drq);
  277 
  278                                         /*
  279                                          * now reset the chip and
  280                                          * reinitialise
  281                                          */
  282                                         cs_init(&sc->sc_ethercom.ec_if);
  283                                         return;
  284                                 }
  285                                 m->m_pkthdr.rcvif = ifp;
  286                                 m->m_pkthdr.len = pkt_length;
  287                                 m->m_len = pkt_length;
  288 
  289                                 /*
  290                                  * align ip header on word boundary for
  291                                  * ipintr
  292                                  */
  293                                 pad = ALIGN(sizeof(struct ether_header)) -
  294                                     sizeof(struct ether_header);
  295                                 m->m_data += pad;
  296 
  297                                 /*
  298                                  * set up the buffer pointer to point to the
  299                                  * data area
  300                                  */
  301                                 pBuff = mtod(m, char *);
  302 
  303                                 /*
  304                                  * Read the frame into free_pktbuf
  305                                  * The buffer is circular buffer, either
  306                                  * 16K or 64K in length.
  307                                  *
  308                                  * need to check where the end of the buffer
  309                                  * is and go back to the start.
  310                                  */
  311                                 if ((dma_mem_ptr + pkt_length) <
  312                                     (isc->sc_dmabase + isc->sc_dmasize)) {
  313                                         /*
  314                                          * No wrap around. Copy the frame
  315                                          * header
  316                                          */
  317                                         memcpy(pBuff, dma_mem_ptr, pkt_length);
  318                                         dma_mem_ptr += pkt_length;
  319                                 } else {
  320                                         to_copy = (u_int)
  321                                             ((isc->sc_dmabase + isc->sc_dmasize) -
  322                                             dma_mem_ptr);
  323 
  324                                         /* Copy the first half of the frame. */
  325                                         memcpy(pBuff, dma_mem_ptr, to_copy);
  326                                         pBuff += to_copy;
  327 
  328                                         /*
  329                                          * Rest of the frame is to be read
  330                                          * from the first byte of the DMA
  331                                          * memory.
  332                                          */
  333                                         /*
  334                                          * Get the number of bytes leftout in
  335                                          * the frame.
  336                                          */
  337                                         to_copy = pkt_length - to_copy;
  338 
  339                                         dma_mem_ptr = isc->sc_dmabase;
  340 
  341                                         /* Copy rest of the frame. */
  342                                         memcpy(pBuff, dma_mem_ptr, to_copy);
  343                                         dma_mem_ptr += to_copy;
  344                                 }
  345 
  346                                 cs_ether_input(sc, m);
  347                         }
  348                         /* (status & RX_OK) */ 
  349                         else {
  350                                 /* the frame was not received OK */
  351                                 /* Increment the input error count */
  352                                 ifp->if_ierrors++;
  353 
  354                                 /*
  355                                  * If debugging is enabled then log error
  356                                  * messages if we got any.
  357                                  */
  358                                 if ((ifp->if_flags & IFF_DEBUG) &&
  359                                     status != REG_NUM_RX_EVENT)
  360                                         cs_print_rx_errors(sc, status);
  361                         }
  362                         /*
  363                          * now update the current frame pointer. the
  364                          * dma_mem_ptr should point to the next packet to be
  365                          * received, without the alignment considerations.
  366                          * 
  367                          * The cs8900 pads all frames to start at the next 32bit
  368                          * aligned addres. hence we need to pad our offset
  369                          * pointer.
  370                          */
  371                         dma_mem_ptr += 3;
  372                         dma_mem_ptr = (char *)
  373                             ((long) dma_mem_ptr & 0xfffffffc);
  374                         if (dma_mem_ptr < (isc->sc_dmabase + isc->sc_dmasize)) {
  375                                 isc->sc_dmacur = dma_mem_ptr;
  376                         } else {
  377                                 dma_mem_ptr = isc->sc_dmacur = isc->sc_dmabase;
  378                         }
  379                 } /* for all frames */
  380                 /* Read the number of frames DMAed again. */
  381                 num_dma_frames = CS_READ_PACKET_PAGE(sc, PKTPG_DMA_FRAME_COUNT);
  382                 num_dma_frames &= (u_int16_t) (0x0fff);
  383         } /* while there are frames left */
  384 }

Cache object: e2b02f6e6c1fc219e23f2ab35b7996ca


[ 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.