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_receive.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  * HARP  |  Host ATM Research Platform
    4  * ===================================
    5  *
    6  * This Host ATM Research Platform ("HARP") file (the "Software") is
    7  * made available by Network Computing Services, Inc. ("NetworkCS")
    8  * "AS IS".  NetworkCS does not provide maintenance, improvements or
    9  * support of any kind.
   10  *
   11  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
   12  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
   13  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
   14  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
   15  * In no event shall NetworkCS be responsible for any damages, including
   16  * but not limited to consequential damages, arising from or relating to
   17  * any use of the Software or related support.
   18  *
   19  * Copyright 1994-1998 Network Computing Services, Inc.
   20  *
   21  * Copies of this Software may be made, however, the above copyright
   22  * notice must be reproduced on all copies.
   23  */
   24 
   25 #include <sys/cdefs.h>
   26 __FBSDID("$FreeBSD$");
   27 
   28 /*
   29  * FORE Systems 200-Series Adapter Support
   30  * ---------------------------------------
   31  *
   32  * Receive queue management
   33  *
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/socket.h>
   39 #include <sys/socketvar.h>
   40 #include <sys/syslog.h>
   41 #include <vm/vm.h>
   42 #include <vm/pmap.h>
   43 #include <net/if.h>
   44 #include <net/netisr.h>
   45 #include <netatm/port.h>
   46 #include <netatm/queue.h>
   47 #include <netatm/atm.h>
   48 #include <netatm/atm_sys.h>
   49 #include <netatm/atm_sap.h>
   50 #include <netatm/atm_cm.h>
   51 #include <netatm/atm_if.h>
   52 #include <netatm/atm_vc.h>
   53 #include <netatm/atm_stack.h>
   54 #include <netatm/atm_pcb.h>
   55 #include <netatm/atm_var.h>
   56 #include <dev/pci/pcivar.h>
   57 #include <dev/hfa/fore.h>
   58 #include <dev/hfa/fore_aali.h>
   59 #include <dev/hfa/fore_slave.h>
   60 #include <dev/hfa/fore_stats.h>
   61 #include <dev/hfa/fore_var.h>
   62 #include <dev/hfa/fore_include.h>
   63 
   64 #ifndef lint
   65 __RCSID("@(#) $FreeBSD$");
   66 #endif
   67 
   68 
   69 /*
   70  * Local functions
   71  */
   72 static void     fore_recv_stack(void *, KBuffer *);
   73 
   74 
   75 /*
   76  * Allocate Receive Queue Data Structures
   77  *
   78  * Arguments:
   79  *      fup             pointer to device unit structure
   80  *
   81  * Returns:
   82  *      0               allocations successful
   83  *      else            allocation failed
   84  */
   85 int
   86 fore_recv_allocate(fup)
   87         Fore_unit       *fup;
   88 {
   89         caddr_t         memp;
   90         vm_paddr_t      pmemp;
   91 
   92         /*
   93          * Allocate non-cacheable memory for receive status words
   94          */
   95         memp = atm_dev_alloc(sizeof(Q_status) * RECV_QUELEN,
   96                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
   97         if (memp == NULL) {
   98                 return (1);
   99         }
  100         fup->fu_recv_stat = (Q_status *) memp;
  101 
  102         pmemp = vtophys(fup->fu_recv_stat);
  103         if (pmemp == 0) {
  104                 return (1);
  105         }
  106         fup->fu_recv_statd = pmemp;
  107 
  108         /*
  109          * Allocate memory for receive descriptors
  110          */
  111         memp = atm_dev_alloc(sizeof(Recv_descr) * RECV_QUELEN,
  112                         RECV_DESCR_ALIGN, 0);
  113         if (memp == NULL) {
  114                 return (1);
  115         }
  116         fup->fu_recv_desc = (Recv_descr *) memp;
  117 
  118         pmemp = vtophys(fup->fu_recv_desc);
  119         if (pmemp == 0) {
  120                 return (1);
  121         }
  122         fup->fu_recv_descd = pmemp;
  123 
  124         return (0);
  125 }
  126 
  127 
  128 /*
  129  * Receive Queue Initialization
  130  *
  131  * Allocate and initialize the host-resident receive queue structures
  132  * and then initialize the CP-resident queue structures.
  133  * 
  134  * Called at interrupt level.
  135  *
  136  * Arguments:
  137  *      fup             pointer to device unit structure
  138  *
  139  * Returns:
  140  *      none
  141  */
  142 void
  143 fore_recv_initialize(fup)
  144         Fore_unit       *fup;
  145 {
  146         Aali            *aap = fup->fu_aali;
  147         Recv_queue      *cqp;
  148         H_recv_queue    *hrp;
  149         Recv_descr      *rdp;
  150         vm_paddr_t      rdp_dma;
  151         Q_status        *qsp;
  152         vm_paddr_t      qsp_dma;
  153         int             i;
  154 
  155         /*
  156          * Point to CP-resident receive queue
  157          */
  158         cqp = (Recv_queue *)(fup->fu_ram + CP_READ(aap->aali_recv_q));
  159 
  160         /*
  161          * Point to host-resident receive queue structures
  162          */
  163         hrp = fup->fu_recv_q;
  164         qsp = fup->fu_recv_stat;
  165         qsp_dma = fup->fu_recv_statd;
  166         rdp = fup->fu_recv_desc;
  167         rdp_dma = fup->fu_recv_descd;
  168 
  169         /*
  170          * Loop thru all queue entries and do whatever needs doing
  171          */
  172         for (i = 0; i < RECV_QUELEN; i++) {
  173 
  174                 /*
  175                  * Set queue status word to free
  176                  */
  177                 *qsp = QSTAT_FREE;
  178 
  179                 /*
  180                  * Set up host queue entry and link into ring
  181                  */
  182                 hrp->hrq_cpelem = cqp;
  183                 hrp->hrq_status = qsp;
  184                 hrp->hrq_descr = rdp;
  185                 hrp->hrq_descr_dma = rdp_dma;
  186                 if (i == (RECV_QUELEN - 1))
  187                         hrp->hrq_next = fup->fu_recv_q;
  188                 else
  189                         hrp->hrq_next = hrp + 1;
  190 
  191                 /*
  192                  * Now let the CP into the game
  193                  */
  194                 cqp->cq_descr = (CP_dma) CP_WRITE(rdp_dma);
  195                 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
  196 
  197                 /*
  198                  * Bump all queue pointers
  199                  */
  200                 hrp++;
  201                 qsp++;
  202                 qsp_dma += sizeof(Q_status);
  203                 rdp++;
  204                 rdp_dma += sizeof(Recv_descr);
  205                 cqp++;
  206         }
  207 
  208         /*
  209          * Initialize queue pointers
  210          */
  211         fup->fu_recv_head = fup->fu_recv_q;
  212 
  213         return;
  214 }
  215 
  216 
  217 /*
  218  * Drain Receive Queue
  219  *
  220  * This function will process all completed entries at the head of the
  221  * receive queue.  The received segments will be linked into a received
  222  * PDU buffer chain and it will then be passed up the PDU's VCC stack for 
  223  * processing by the next higher protocol layer.
  224  *
  225  * May be called in interrupt state.
  226  * Must be called with interrupts locked out.
  227  *
  228  * Arguments:
  229  *      fup             pointer to device unit structure
  230  *
  231  * Returns:
  232  *      none
  233  */
  234 void
  235 fore_recv_drain(fup)
  236         Fore_unit       *fup;
  237 {
  238         H_recv_queue    *hrp = NULL;
  239         Recv_descr      *rdp;
  240         Recv_seg_descr  *rsp;
  241         Buf_handle      *bhp;
  242         Fore_vcc        *fvp;
  243         struct vccb     *vcp;
  244         KBuffer         *m, *mhead, *mtail;
  245         caddr_t         cp;
  246         u_long          hdr, nsegs;
  247         u_int           seglen, type0;
  248         int             i, pdulen, retries = 0, error;
  249 
  250         /* Silence the compiler */
  251         mtail = NULL;
  252         type0 = 0;
  253 
  254         /*
  255          * Process each completed entry
  256          */
  257 retry:
  258         while (*fup->fu_recv_head->hrq_status & QSTAT_COMPLETED) {
  259 
  260                 /*
  261                  * Get completed entry's receive descriptor
  262                  */
  263                 hrp = fup->fu_recv_head;
  264                 rdp = hrp->hrq_descr;
  265 
  266 #ifdef VAC
  267                 /*
  268                  * Cache flush receive descriptor 
  269                  */
  270                 if (vac) {
  271                         vac_flush((addr_t)rdp, sizeof(Recv_descr));
  272                 }
  273 #endif
  274 
  275                 hdr = rdp->rd_cell_hdr;
  276                 nsegs = rdp->rd_nsegs;
  277 
  278                 pdulen = 0;
  279                 error = 0;
  280                 mhead = NULL;
  281 
  282                 /*
  283                  * Locate incoming VCC for this PDU
  284                  */
  285                 fvp = (Fore_vcc *) atm_dev_vcc_find((Cmn_unit *)fup,
  286                         ATM_HDR_GET_VPI(hdr), ATM_HDR_GET_VCI(hdr), VCC_IN);
  287 
  288                 /*
  289                  * Check for a receive error
  290                  *
  291                  * Apparently the receive descriptor itself contains valid 
  292                  * information, but the received pdu data is probably bogus.
  293                  * We'll arrange for the receive buffer segments to be tossed.
  294                  */
  295                 if (*hrp->hrq_status & QSTAT_ERROR) {
  296 
  297                         fup->fu_pif.pif_ierrors++;
  298                         if (fvp) {
  299                                 vcp = fvp->fv_connvc->cvc_vcc;
  300                                 vcp->vc_ierrors++;
  301                                 if (vcp->vc_nif)
  302                                         vcp->vc_nif->nif_if.if_ierrors++;
  303                         }
  304                         ATM_DEBUG1("fore receive error: hdr=0x%lx\n", hdr);
  305                         error = 1;
  306                 }
  307 
  308                 /*
  309                  * Build PDU buffer chain from receive segments
  310                  */
  311                 for (i = 0, rsp = rdp->rd_seg; i < nsegs; i++, rsp++) {
  312 
  313                         bhp = rsp->rsd_handle;
  314                         seglen = rsp->rsd_len;
  315 
  316                         /*
  317                          * Remove buffer from our supplied queue and get
  318                          * to the underlying buffer
  319                          */
  320                         switch (bhp->bh_type) {
  321 
  322                         case BHT_S1_SMALL:
  323                                 DEQUEUE(bhp, Buf_handle, bh_qelem,
  324                                         fup->fu_buf1s_bq);
  325                                 fup->fu_buf1s_cnt--;
  326                                 m = (KBuffer *) ((caddr_t)bhp - BUF1_SM_HOFF);
  327                                 KB_DATASTART(m, cp, caddr_t);
  328                                 break;
  329 
  330                         case BHT_S1_LARGE:
  331                                 DEQUEUE(bhp, Buf_handle, bh_qelem,
  332                                         fup->fu_buf1l_bq);
  333                                 fup->fu_buf1l_cnt--;
  334                                 m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF);
  335                                 KB_DATASTART(m, cp, caddr_t);
  336                                 break;
  337 
  338                         default:
  339                                 log(LOG_ERR,
  340                                         "fore_recv_drain: bhp=%p type=0x%x\n",
  341                                         bhp, bhp->bh_type);
  342                                 panic("fore_recv_drain: bad buffer type");
  343                         }
  344 
  345                         /*
  346                          * Toss any zero-length or receive error buffers 
  347                          */
  348                         if ((seglen == 0) || error) {
  349                                 KB_FREEALL(m);
  350                                 continue;
  351                         }
  352 
  353                         /*
  354                          * Link buffer into chain
  355                          */
  356                         if (mhead == NULL) {
  357                                 type0 = bhp->bh_type;
  358                                 KB_LINKHEAD(m, mhead);
  359                                 mhead = m;
  360                         } else {
  361                                 KB_LINK(m, mtail);
  362                         }
  363                         KB_LEN(m) = seglen;
  364                         pdulen += seglen;
  365                         mtail = m;
  366 
  367                         /*
  368                          * Flush received buffer data
  369                          */
  370 #ifdef VAC
  371                         if (vac) {
  372                                 addr_t  dp;
  373 
  374                                 KB_DATASTART(m, dp, addr_t);
  375                                 vac_pageflush(dp);
  376                         }
  377 #endif
  378                 }
  379 
  380                 /*
  381                  * Make sure we've got a non-null PDU
  382                  */
  383                 if (mhead == NULL) {
  384                         goto free_ent;
  385                 }
  386 
  387                 /*
  388                  * We only support user data PDUs (for now)
  389                  */
  390                 if (hdr & ATM_HDR_SET_PT(ATM_PT_NONUSER)) {
  391                         KB_FREEALL(mhead);
  392                         goto free_ent;
  393                 }
  394 
  395                 /*
  396                  * Toss the data if there's no VCC
  397                  */
  398                 if (fvp == NULL) {
  399                         fup->fu_stats->st_drv.drv_rv_novcc++;
  400                         KB_FREEALL(mhead);
  401                         goto free_ent;
  402                 }
  403 
  404 #ifdef DIAGNOSTIC
  405                 if (atm_dev_print)
  406                         atm_dev_pdu_print((Cmn_unit *)fup, (Cmn_vcc *)fvp, 
  407                                 mhead, "fore_recv");
  408 #endif
  409 
  410                 /*
  411                  * Make sure we have our queueing headroom at the front
  412                  * of the buffer chain
  413                  */
  414                 if (type0 != BHT_S1_SMALL) {
  415 
  416                         /*
  417                          * Small buffers already have headroom built-in, but
  418                          * if CP had to use a large buffer for the first 
  419                          * buffer, then we have to allocate a buffer here to
  420                          * contain the headroom.
  421                          */
  422                         fup->fu_stats->st_drv.drv_rv_nosbf++;
  423 
  424                         KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
  425                         if (m == NULL) {
  426                                 fup->fu_stats->st_drv.drv_rv_nomb++;
  427                                 KB_FREEALL(mhead);
  428                                 goto free_ent;
  429                         }
  430 
  431                         /*
  432                          * Put new buffer at head of PDU chain
  433                          */
  434                         KB_LINKHEAD(m, mhead);
  435                         KB_LEN(m) = 0;
  436                         KB_HEADSET(m, BUF1_SM_DOFF);
  437                         mhead = m;
  438                 }
  439 
  440                 /*
  441                  * It looks like we've got a valid PDU - count it quick!!
  442                  */
  443                 mhead->m_pkthdr.rcvif = NULL;
  444                 mhead->m_pkthdr.csum_flags = 0;
  445                 SLIST_INIT(&mhead->m_pkthdr.tags);
  446                 KB_PLENSET(mhead, pdulen);
  447                 fup->fu_pif.pif_ipdus++;
  448                 fup->fu_pif.pif_ibytes += pdulen;
  449                 vcp = fvp->fv_connvc->cvc_vcc;
  450                 vcp->vc_ipdus++;
  451                 vcp->vc_ibytes += pdulen;
  452                 if (vcp->vc_nif) {
  453                         vcp->vc_nif->nif_ibytes += pdulen;
  454                         vcp->vc_nif->nif_if.if_ipackets++;
  455 #if (defined(BSD) && (BSD >= 199103))
  456                         vcp->vc_nif->nif_if.if_ibytes += pdulen;
  457 #endif
  458                 }
  459 
  460                 /*
  461                  * The STACK_CALL needs to happen at splnet() in order
  462                  * for the stack sequence processing to work.  Schedule an
  463                  * interrupt queue callback at splnet() since we are 
  464                  * currently at device level.
  465                  */
  466 
  467                 /*
  468                  * Prepend callback function pointer and token value to buffer.
  469                  * We have already guaranteed that the space is available
  470                  * in the first buffer.
  471                  * Don't count this extra fields in m_pkthdr.len (XXX)
  472                  */
  473                 mhead->m_data -= sizeof(atm_intr_func_t) + sizeof(void *);
  474                 mhead->m_len += sizeof(atm_intr_func_t) + sizeof(void *);
  475                 cp = mtod(mhead, caddr_t);
  476                 *((atm_intr_func_t *)cp) = fore_recv_stack;
  477                 cp += sizeof(atm_intr_func_t);
  478                 *((void **)cp) = (void *)fvp;
  479 
  480                 /*
  481                  * Schedule callback
  482                  */
  483                 if (netisr_queue(NETISR_ATM, mhead)) {  /* (0) on success. */
  484                         fup->fu_stats->st_drv.drv_rv_ifull++;
  485                         goto free_ent;
  486                 }
  487 
  488 free_ent:
  489                 /*
  490                  * Mark this entry free for use and bump head pointer
  491                  * to the next entry in the queue
  492                  */
  493                 *hrp->hrq_status = QSTAT_FREE;
  494                 hrp->hrq_cpelem->cq_descr = 
  495                         (CP_dma) CP_WRITE((u_long)hrp->hrq_descr_dma);
  496                 fup->fu_recv_head = hrp->hrq_next;
  497         }
  498 
  499         /*
  500          * Nearly all of the interrupts generated by the CP will be due
  501          * to PDU reception.  However, we may receive an interrupt before
  502          * the CP has completed the status word DMA to host memory.  Thus,
  503          * if we haven't processed any PDUs during this interrupt, we will
  504          * wait a bit for completed work on the receive queue, rather than 
  505          * having to field an extra interrupt very soon.
  506          */
  507         if (hrp == NULL) {
  508                 if (++retries <= FORE_RECV_RETRY) {
  509                         DELAY(FORE_RECV_DELAY);
  510                         goto retry;
  511                 }
  512         }
  513 
  514         return;
  515 }
  516 
  517 
  518 /*
  519  * Pass Incoming PDU up Stack
  520  *
  521  * This function is called via the core ATM interrupt queue callback 
  522  * set in fore_recv_drain().  It will pass the supplied incoming 
  523  * PDU up the incoming VCC's stack.
  524  *
  525  * Called at splnet.
  526  *
  527  * Arguments:
  528  *      tok             token to identify stack instantiation
  529  *      m               pointer to incoming PDU buffer chain
  530  *
  531  * Returns:
  532  *      none
  533  */
  534 static void
  535 fore_recv_stack(tok, m)
  536         void            *tok;
  537         KBuffer         *m;
  538 {
  539         Fore_vcc        *fvp = (Fore_vcc *)tok;
  540         int             err;
  541 
  542         /*
  543          * Send the data up the stack
  544          */
  545         STACK_CALL(CPCS_UNITDATA_SIG, fvp->fv_upper,
  546                 fvp->fv_toku, fvp->fv_connvc, (intptr_t)m, 0, err);
  547         if (err)
  548                 KB_FREEALL(m);
  549 
  550         return;
  551 }
  552 
  553 
  554 /*
  555  * Free Receive Queue Data Structures
  556  *
  557  * Arguments:
  558  *      fup             pointer to device unit structure
  559  *
  560  * Returns:
  561  *      none
  562  */
  563 void
  564 fore_recv_free(fup)
  565         Fore_unit       *fup;
  566 {
  567         /*
  568          * We'll just let fore_buf_free() take care of freeing any
  569          * buffers sitting on the receive queue (which are also still
  570          * on the fu_*_bq queue).
  571          */
  572         if (fup->fu_flags & CUF_INITED) {
  573         }
  574 
  575         /*
  576          * Free the status words
  577          */
  578         if (fup->fu_recv_stat) {
  579                 atm_dev_free((volatile void *)fup->fu_recv_stat);
  580                 fup->fu_recv_stat = NULL;
  581                 fup->fu_recv_statd = 0;
  582         }
  583 
  584         /*
  585          * Free the receive descriptors
  586          */
  587         if (fup->fu_recv_desc) {
  588                 atm_dev_free(fup->fu_recv_desc);
  589                 fup->fu_recv_desc = NULL;
  590                 fup->fu_recv_descd = 0;
  591         }
  592 
  593         return;
  594 }
  595 

Cache object: f449ce7815d94cc8ed4dce75521ad1c3


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