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/hfa/fore_output.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 /*-
    2  *
    3  * ===================================
    4  * HARP  |  Host ATM Research Platform
    5  * ===================================
    6  *
    7  *
    8  * This Host ATM Research Platform ("HARP") file (the "Software") is
    9  * made available by Network Computing Services, Inc. ("NetworkCS")
   10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
   11  * support of any kind.
   12  *
   13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   17  * In no event shall NetworkCS be responsible for any damages, including
   18  * but not limited to consequential damages, arising from or relating to
   19  * any use of the Software or related support.
   20  *
   21  * Copyright 1994-1998 Network Computing Services, Inc.
   22  *
   23  * Copies of this Software may be made, however, the above copyright
   24  * notice must be reproduced on all copies.
   25  *
   26  *      @(#) $FreeBSD$
   27  *
   28  */
   29 
   30 /*
   31  * FORE Systems 200-Series Adapter Support
   32  * ---------------------------------------
   33  *
   34  * PDU output processing
   35  *
   36  */
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/types.h>
   41 #include <sys/time.h>
   42 #include <sys/socket.h>
   43 #include <sys/socketvar.h>
   44 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 #include <net/if.h>
   47 #include <netatm/port.h>
   48 #include <netatm/queue.h>
   49 #include <netatm/atm.h>
   50 #include <netatm/atm_sys.h>
   51 #include <netatm/atm_sap.h>
   52 #include <netatm/atm_cm.h>
   53 #include <netatm/atm_if.h>
   54 #include <netatm/atm_vc.h>
   55 #include <netatm/atm_stack.h>
   56 #include <netatm/atm_pcb.h>
   57 #include <netatm/atm_var.h>
   58 #include <dev/pci/pcivar.h>
   59 #include <dev/hfa/fore.h>
   60 #include <dev/hfa/fore_aali.h>
   61 #include <dev/hfa/fore_slave.h>
   62 #include <dev/hfa/fore_stats.h>
   63 #include <dev/hfa/fore_var.h>
   64 #include <dev/hfa/fore_include.h>
   65 
   66 #ifndef lint
   67 __RCSID("@(#) $FreeBSD$");
   68 #endif
   69 
   70 
   71 /*
   72  * Local functions
   73  */
   74 static KBuffer *        fore_xmit_segment(Fore_unit *, KBuffer *,
   75                                 H_xmit_queue *, int *, int *);
   76 static void             fore_seg_dma_free(H_xmit_queue *, KBuffer *, int);
   77 
   78 
   79 /*
   80  * Output a PDU
   81  * 
   82  * This function is called via the common driver code after receiving a
   83  * stack *_DATA* command.  The common code has already validated most of
   84  * the request so we just need to check a few more Fore-specific details.
   85  * Then we just build a transmit descriptor request for the PDU and issue 
   86  * the command to the CP.  
   87  *
   88  * Arguments:
   89  *      cup     pointer to device common unit
   90  *      cvp     pointer to common VCC entry
   91  *      m       pointer to output PDU buffer chain head
   92  *
   93  * Returns:
   94  *      none
   95  *
   96  */
   97 void
   98 fore_output(cup, cvp, m)
   99         Cmn_unit        *cup;
  100         Cmn_vcc         *cvp;
  101         KBuffer         *m;
  102 {
  103         Fore_unit       *fup = (Fore_unit *)cup;
  104         Fore_vcc        *fvp = (Fore_vcc *)cvp;
  105         struct vccb     *vcp;
  106         H_xmit_queue    *hxp;
  107         Xmit_queue      *cqp;
  108         Xmit_descr      *xdp;
  109         int             retry, nsegs, pdulen;
  110         int             s;
  111 
  112 #ifdef DIAGNOSTIC
  113         if (atm_dev_print)
  114                 atm_dev_pdu_print(cup, cvp, m, "fore_output");
  115 #endif
  116 
  117         vcp = fvp->fv_connvc->cvc_vcc;
  118 
  119         /*
  120          * If we're still waiting for activation to finish, delay for
  121          * a little while before we toss the PDU
  122          */
  123         if (fvp->fv_state == CVS_INITED) {
  124                 retry = 3;
  125                 while (retry-- && (fvp->fv_state == CVS_INITED))
  126                         DELAY(1000);
  127                 if (fvp->fv_state != CVS_ACTIVE) {
  128                         /*
  129                          * Activation still hasn't finished, oh well....
  130                          */
  131                         fup->fu_stats->st_drv.drv_xm_notact++;
  132                         vcp->vc_oerrors++;
  133                         if (vcp->vc_nif)
  134                                 vcp->vc_nif->nif_if.if_oerrors++;
  135                         KB_FREEALL(m);
  136                         return;
  137                 }
  138         }
  139 
  140         /*
  141          * Queue PDU at end of transmit queue
  142          *
  143          * If queue is full we'll delay a bit before tossing the PDU
  144          */
  145         s = splnet();
  146         hxp = fup->fu_xmit_tail;
  147         if (!((*hxp->hxq_status) & QSTAT_FREE)) {
  148 
  149                 fup->fu_stats->st_drv.drv_xm_full++;
  150                 retry = 3;
  151                 do {
  152                         DELAY(1000);
  153 
  154                         DEVICE_LOCK((Cmn_unit *)fup);
  155                         fore_xmit_drain(fup);
  156                         DEVICE_UNLOCK((Cmn_unit *)fup);
  157 
  158                 } while (--retry && (!((*hxp->hxq_status) & QSTAT_FREE)));
  159 
  160                 if (!((*hxp->hxq_status) & QSTAT_FREE)) {
  161                         /*
  162                          * Queue is still full, bye-bye PDU
  163                          */
  164                         fup->fu_pif.pif_oerrors++;
  165                         vcp->vc_oerrors++;
  166                         if (vcp->vc_nif)
  167                                 vcp->vc_nif->nif_if.if_oerrors++;
  168                         KB_FREEALL(m);
  169                         (void) splx(s);
  170                         return;
  171                 }
  172         }
  173 
  174         /*
  175          * We've got a free transmit queue entry
  176          */
  177 
  178         /*
  179          * Now build the transmit segment descriptors for this PDU
  180          */
  181         m = fore_xmit_segment(fup, m, hxp, &nsegs, &pdulen);
  182         if (m == NULL) {
  183                 /*
  184                  * The build failed, buffer chain has been freed
  185                  */
  186                 vcp->vc_oerrors++;
  187                 if (vcp->vc_nif)
  188                         vcp->vc_nif->nif_if.if_oerrors++;
  189                 (void) splx(s);
  190                 return;
  191         }
  192 
  193         /*
  194          * Set up the descriptor header
  195          */
  196         xdp = hxp->hxq_descr;
  197         xdp->xd_cell_hdr = ATM_HDR_SET(vcp->vc_vpi, vcp->vc_vci, 0, 0);
  198         xdp->xd_spec = XDS_SET_SPEC(0, fvp->fv_aal, nsegs, pdulen);
  199         xdp->xd_rate = fvp->rate;
  200 
  201         /*
  202          * Everything is ready to go, so officially claim the host queue
  203          * entry and setup the CP-resident queue entry.  The CP will grab
  204          * the PDU when the descriptor pointer is set.
  205          */
  206         fup->fu_xmit_tail = hxp->hxq_next;
  207         hxp->hxq_buf = m;
  208         hxp->hxq_vcc = fvp;
  209         (*hxp->hxq_status) = QSTAT_PENDING;
  210         cqp = hxp->hxq_cpelem;
  211         cqp->cq_descr = (CP_dma)
  212                 CP_WRITE((u_long)hxp->hxq_descr_dma | XMIT_SEGS_TO_BLKS(nsegs));
  213 
  214         (void) splx(s);
  215 
  216         /*
  217          * See if there are any completed queue entries
  218          */
  219         DEVICE_LOCK((Cmn_unit *)fup);
  220         fore_xmit_drain(fup);
  221         DEVICE_UNLOCK((Cmn_unit *)fup);
  222 
  223         return;
  224 }
  225 
  226 
  227 /*
  228  * Build Transmit Segment Descriptors
  229  * 
  230  * This function will take a supplied buffer chain of data to be transmitted
  231  * and build the transmit segment descriptors for the data.  This will include 
  232  * the dreaded operation of ensuring that the data for each transmit segment
  233  * is full-word aligned and (except for the last segment) is an integral number
  234  * of words in length.  If the data isn't already aligned and sized as
  235  * required, then the data must be shifted (copied) into place - a sure
  236  * performance killer.  Note that we rely on the fact that all buffer data
  237  * areas are allocated with (at least) full-word alignments/lengths.
  238  *
  239  * If any errors are encountered, the buffer chain will be freed.
  240  * 
  241  * Arguments:
  242  *      fup     pointer to device unit
  243  *      m       pointer to output PDU buffer chain head
  244  *      hxp     pointer to host transmit queue entry
  245  *      segp    pointer to return the number of transmit segments
  246  *      lenp    pointer to return the pdu length
  247  *
  248  * Returns:
  249  *      m       build successful, pointer to (possibly new) head of 
  250  *              output PDU buffer chain
  251  *      NULL    build failed, buffer chain freed
  252  *
  253  */
  254 static KBuffer *
  255 fore_xmit_segment(fup, m, hxp, segp, lenp)
  256         Fore_unit       *fup;
  257         KBuffer         *m;
  258         H_xmit_queue    *hxp;
  259         int             *segp;
  260         int             *lenp;
  261 {
  262         Xmit_descr      *xdp = hxp->hxq_descr;
  263         Xmit_seg_descr  *xsp;
  264         H_dma           *sdmap;
  265         KBuffer         *m0, *m1, *mprev;
  266         caddr_t         cp, bfr;
  267         vm_paddr_t      dma;
  268         int             pdulen, nsegs, len, align;
  269         int             compressed = 0;
  270 
  271         m0 = m;
  272 
  273 retry:
  274         xsp = xdp->xd_seg;
  275         sdmap = hxp->hxq_dma;
  276         mprev = NULL;
  277         pdulen = 0;
  278         nsegs = 0;
  279 
  280         /*
  281          * Loop thru each buffer in the chain, performing the necessary
  282          * data positioning and then building a segment descriptor for
  283          * that data.
  284          */
  285         while (m) {
  286                 /*
  287                  * Get rid of any zero-length buffers
  288                  */
  289                 if (KB_LEN(m) == 0) {
  290                         if (mprev) {
  291                                 KB_UNLINK(m, mprev, m1);
  292                         } else {
  293                                 KB_UNLINKHEAD(m, m1);
  294                                 m0 = m1;
  295                         }
  296                         m = m1;
  297                         continue;
  298                 }
  299 
  300                 /*
  301                  * Make sure we don't try to use too many segments
  302                  */
  303                 if (nsegs >= XMIT_MAX_SEGS) {
  304                         /*
  305                          * First, free already allocated DMA addresses
  306                          */
  307                         fore_seg_dma_free(hxp, m0, nsegs);
  308 
  309                         /*
  310                          * Try to compress buffer chain (but only once)
  311                          */
  312                         if (compressed) {
  313                                 KB_FREEALL(m0);
  314                                 return (NULL);
  315                         }
  316 
  317                         fup->fu_stats->st_drv.drv_xm_maxpdu++;
  318 
  319                         m = atm_dev_compress(m0);
  320                         if (m == NULL) {
  321                                 return (NULL);
  322                         }
  323 
  324                         /*
  325                          * Build segment descriptors for compressed chain
  326                          */
  327                         m0 = m;
  328                         compressed = 1;
  329                         goto retry;
  330                 }
  331 
  332                 /*
  333                  * Get start of data onto full-word alignment
  334                  */
  335                 KB_DATASTART(m, cp, caddr_t);
  336                 if ((align = ((uintptr_t)cp) & (XMIT_SEG_ALIGN - 1)) != 0) {
  337                         /*
  338                          * Gotta slide the data up
  339                          */
  340                         fup->fu_stats->st_drv.drv_xm_segnoal++;
  341                         bfr = cp - align;
  342                         bcopy(cp, bfr, KB_LEN(m));
  343                         KB_HEADMOVE(m, -align);
  344                 } else {
  345                         /*
  346                          * Data already aligned
  347                          */
  348                         bfr = cp;
  349                 }
  350 
  351                 /*
  352                  * Now work on getting the data length correct
  353                  */
  354                 len = KB_LEN(m);
  355                 while ((align = (len & (XMIT_SEG_ALIGN - 1))) &&
  356                        (m1 = KB_NEXT(m))) {
  357 
  358                         /*
  359                          * Have to move some data from following buffer(s)
  360                          * to word-fill this buffer
  361                          */
  362                         int     ncopy = MIN(XMIT_SEG_ALIGN - align, KB_LEN(m1));
  363 
  364                         if (ncopy) {
  365                                 /*
  366                                  * Move data to current buffer
  367                                  */
  368                                 caddr_t         dest;
  369 
  370                                 fup->fu_stats->st_drv.drv_xm_seglen++;
  371                                 KB_DATASTART(m1, cp, caddr_t);
  372                                 dest = bfr + len;
  373                                 KB_HEADADJ(m1, -ncopy);
  374                                 KB_TAILADJ(m, ncopy);
  375                                 len += ncopy;
  376                                 while (ncopy--) {
  377                                         *dest++ = *cp++;
  378                                 }
  379                         }
  380 
  381                         /*
  382                          * If we've drained the buffer, free it
  383                          */
  384                         if (KB_LEN(m1) == 0) {
  385                                 KBuffer         *m2;
  386 
  387                                 KB_UNLINK(m1, m, m2);
  388                         }
  389                 }
  390 
  391                 /*
  392                  * Finally, build the segment descriptor
  393                  */
  394 
  395                 /*
  396                  * Round last segment to fullword length (if needed)
  397                  */
  398                 if (len & (XMIT_SEG_ALIGN - 1))
  399                         xsp->xsd_len = KB_LEN(m) =
  400                                 (len + XMIT_SEG_ALIGN) & ~(XMIT_SEG_ALIGN - 1);
  401                 else
  402                         xsp->xsd_len = KB_LEN(m) = len;
  403 
  404                 /*
  405                  * Get a DMA address for the data
  406                  */
  407                 dma = vtophys(bfr);
  408                 if (dma == 0) {
  409                         fup->fu_stats->st_drv.drv_xm_segdma++;
  410                         fore_seg_dma_free(hxp, m0, nsegs);
  411                         KB_FREEALL(m0);
  412                         return (NULL);
  413                 }
  414 
  415                 /*
  416                  * Now we're really ready to call it a segment
  417                  */
  418                 *sdmap++ = xsp->xsd_buffer = (H_dma) dma;
  419 
  420                 /*
  421                  * Bump counters and get ready for next buffer
  422                  */
  423                 pdulen += len;
  424                 nsegs++;
  425                 xsp++;
  426                 mprev = m;
  427                 m = KB_NEXT(m);
  428         }
  429 
  430         /*
  431          * Validate PDU length
  432          */
  433         if (pdulen > XMIT_MAX_PDULEN) {
  434                 fup->fu_stats->st_drv.drv_xm_maxpdu++;
  435                 fore_seg_dma_free(hxp, m0, nsegs);
  436                 KB_FREEALL(m0);
  437                 return (NULL);
  438         }
  439 
  440         /*
  441          * Return the good news to the caller
  442          */
  443         *segp = nsegs;
  444         *lenp = pdulen;
  445 
  446         return (m0);
  447 }
  448 
  449 
  450 /*
  451  * Free Transmit Segment Queue DMA addresses
  452  * 
  453  * Arguments:
  454  *      hxp     pointer to host transmit queue entry
  455  *      m0      pointer to output PDU buffer chain head
  456  *      nsegs   number of processed transmit segments
  457  *
  458  * Returns:
  459  *      none
  460  *
  461  */
  462 static void
  463 fore_seg_dma_free(hxp, m0, nsegs)
  464         H_xmit_queue    *hxp;
  465         KBuffer         *m0;
  466         int             nsegs;
  467 {
  468         KBuffer         *m = m0;
  469         H_dma           *sdmap = hxp->hxq_dma;
  470         caddr_t         cp;
  471         int             i;
  472 
  473         for (i = 0; i < nsegs; i++) {
  474                 KB_DATASTART(m, cp, caddr_t);
  475                 m = KB_NEXT(m);
  476                 sdmap++;
  477         }
  478 }
  479 

Cache object: fd14d397b9470279fd7aa23de6e2f13f


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