3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
31 * FORE Systems 200-Series Adapter Support
32 * ---------------------------------------
34 * Receive queue management
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/syslog.h>
46 #include <net/netisr.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 <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>
67 __RCSID("@(#) $FreeBSD$");
74 static void fore_recv_stack(void *, KBuffer *);
78 * Allocate Receive Queue Data Structures
81 * fup pointer to device unit structure
84 * 0 allocations successful
85 * else allocation failed
88 fore_recv_allocate(fup)
94 * Allocate non-cacheable memory for receive status words
96 memp = atm_dev_alloc(sizeof(Q_status) * RECV_QUELEN,
97 QSTAT_ALIGN, ATM_DEV_NONCACHE);
101 fup->fu_recv_stat = (Q_status *) memp;
103 memp = (caddr_t)vtophys(fup->fu_recv_stat);
107 fup->fu_recv_statd = (Q_status *) memp;
110 * Allocate memory for receive descriptors
112 memp = atm_dev_alloc(sizeof(Recv_descr) * RECV_QUELEN,
113 RECV_DESCR_ALIGN, 0);
117 fup->fu_recv_desc = (Recv_descr *) memp;
119 memp = (caddr_t)vtophys(fup->fu_recv_desc);
123 fup->fu_recv_descd = (Recv_descr *) memp;
130 * Receive Queue Initialization
132 * Allocate and initialize the host-resident receive queue structures
133 * and then initialize the CP-resident queue structures.
135 * Called at interrupt level.
138 * fup pointer to device unit structure
144 fore_recv_initialize(fup)
147 Aali *aap = fup->fu_aali;
157 * Point to CP-resident receive queue
159 cqp = (Recv_queue *)(fup->fu_ram + CP_READ(aap->aali_recv_q));
162 * Point to host-resident receive queue structures
164 hrp = fup->fu_recv_q;
165 qsp = fup->fu_recv_stat;
166 qsp_dma = fup->fu_recv_statd;
167 rdp = fup->fu_recv_desc;
168 rdp_dma = fup->fu_recv_descd;
171 * Loop thru all queue entries and do whatever needs doing
173 for (i = 0; i < RECV_QUELEN; i++) {
176 * Set queue status word to free
181 * Set up host queue entry and link into ring
183 hrp->hrq_cpelem = cqp;
184 hrp->hrq_status = qsp;
185 hrp->hrq_descr = rdp;
186 hrp->hrq_descr_dma = rdp_dma;
187 if (i == (RECV_QUELEN - 1))
188 hrp->hrq_next = fup->fu_recv_q;
190 hrp->hrq_next = hrp + 1;
193 * Now let the CP into the game
195 cqp->cq_descr = (CP_dma) CP_WRITE(rdp_dma);
196 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
199 * Bump all queue pointers
210 * Initialize queue pointers
212 fup->fu_recv_head = fup->fu_recv_q;
219 * Drain Receive Queue
221 * This function will process all completed entries at the head of the
222 * receive queue. The received segments will be linked into a received
223 * PDU buffer chain and it will then be passed up the PDU's VCC stack for
224 * processing by the next higher protocol layer.
226 * May be called in interrupt state.
227 * Must be called with interrupts locked out.
230 * fup pointer to device unit structure
239 H_recv_queue *hrp = NULL;
245 KBuffer *m, *mhead, *mtail;
249 int i, pdulen, retries = 0, error;
251 /* Silence the compiler */
256 * Process each completed entry
259 while (*fup->fu_recv_head->hrq_status & QSTAT_COMPLETED) {
262 * Get completed entry's receive descriptor
264 hrp = fup->fu_recv_head;
265 rdp = hrp->hrq_descr;
269 * Cache flush receive descriptor
272 vac_flush((addr_t)rdp, sizeof(Recv_descr));
276 hdr = rdp->rd_cell_hdr;
277 nsegs = rdp->rd_nsegs;
284 * Locate incoming VCC for this PDU
286 fvp = (Fore_vcc *) atm_dev_vcc_find((Cmn_unit *)fup,
287 ATM_HDR_GET_VPI(hdr), ATM_HDR_GET_VCI(hdr), VCC_IN);
290 * Check for a receive error
292 * Apparently the receive descriptor itself contains valid
293 * information, but the received pdu data is probably bogus.
294 * We'll arrange for the receive buffer segments to be tossed.
296 if (*hrp->hrq_status & QSTAT_ERROR) {
298 fup->fu_pif.pif_ierrors++;
300 vcp = fvp->fv_connvc->cvc_vcc;
303 vcp->vc_nif->nif_if.if_ierrors++;
305 ATM_DEBUG1("fore receive error: hdr=0x%lx\n", hdr);
310 * Build PDU buffer chain from receive segments
312 for (i = 0, rsp = rdp->rd_seg; i < nsegs; i++, rsp++) {
314 bhp = rsp->rsd_handle;
315 seglen = rsp->rsd_len;
318 * Remove buffer from our supplied queue and get
319 * to the underlying buffer
321 switch (bhp->bh_type) {
324 DEQUEUE(bhp, Buf_handle, bh_qelem,
327 m = (KBuffer *) ((caddr_t)bhp - BUF1_SM_HOFF);
328 KB_DATASTART(m, cp, caddr_t);
332 DEQUEUE(bhp, Buf_handle, bh_qelem,
335 m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF);
336 KB_DATASTART(m, cp, caddr_t);
341 "fore_recv_drain: bhp=%p type=0x%x\n",
343 panic("fore_recv_drain: bad buffer type");
347 * Toss any zero-length or receive error buffers
349 if ((seglen == 0) || error) {
355 * Link buffer into chain
358 type0 = bhp->bh_type;
359 KB_LINKHEAD(m, mhead);
369 * Flush received buffer data
375 KB_DATASTART(m, dp, addr_t);
382 * Make sure we've got a non-null PDU
389 * We only support user data PDUs (for now)
391 if (hdr & ATM_HDR_SET_PT(ATM_PT_NONUSER)) {
397 * Toss the data if there's no VCC
400 fup->fu_stats->st_drv.drv_rv_novcc++;
407 atm_dev_pdu_print((Cmn_unit *)fup, (Cmn_vcc *)fvp,
412 * Make sure we have our queueing headroom at the front
413 * of the buffer chain
415 if (type0 != BHT_S1_SMALL) {
418 * Small buffers already have headroom built-in, but
419 * if CP had to use a large buffer for the first
420 * buffer, then we have to allocate a buffer here to
421 * contain the headroom.
423 fup->fu_stats->st_drv.drv_rv_nosbf++;
425 KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
427 fup->fu_stats->st_drv.drv_rv_nomb++;
433 * Put new buffer at head of PDU chain
435 KB_LINKHEAD(m, mhead);
437 KB_HEADSET(m, BUF1_SM_DOFF);
442 * It looks like we've got a valid PDU - count it quick!!
444 mhead->m_pkthdr.rcvif = NULL;
445 mhead->m_pkthdr.csum_flags = 0;
446 SLIST_INIT(&mhead->m_pkthdr.tags);
447 KB_PLENSET(mhead, pdulen);
448 fup->fu_pif.pif_ipdus++;
449 fup->fu_pif.pif_ibytes += pdulen;
450 vcp = fvp->fv_connvc->cvc_vcc;
452 vcp->vc_ibytes += pdulen;
454 vcp->vc_nif->nif_ibytes += pdulen;
455 vcp->vc_nif->nif_if.if_ipackets++;
456 #if (defined(BSD) && (BSD >= 199103))
457 vcp->vc_nif->nif_if.if_ibytes += pdulen;
462 * The STACK_CALL needs to happen at splnet() in order
463 * for the stack sequence processing to work. Schedule an
464 * interrupt queue callback at splnet() since we are
465 * currently at device level.
469 * Prepend callback function pointer and token value to buffer.
470 * We have already guaranteed that the space is available
471 * in the first buffer.
473 KB_HEADADJ(mhead, sizeof(atm_intr_func_t) + sizeof(int));
474 KB_DATASTART(mhead, cp, caddr_t);
475 *((atm_intr_func_t *)cp) = fore_recv_stack;
476 cp += sizeof(atm_intr_func_t);
477 *((void **)cp) = (void *)fvp;
482 if (IF_HANDOFF(&atm_intrq, mhead, NULL)) {
483 schednetisr(NETISR_ATM);
485 fup->fu_stats->st_drv.drv_rv_ifull++;
491 * Mark this entry free for use and bump head pointer
492 * to the next entry in the queue
494 *hrp->hrq_status = QSTAT_FREE;
495 hrp->hrq_cpelem->cq_descr =
496 (CP_dma) CP_WRITE((u_long)hrp->hrq_descr_dma);
497 fup->fu_recv_head = hrp->hrq_next;
501 * Nearly all of the interrupts generated by the CP will be due
502 * to PDU reception. However, we may receive an interrupt before
503 * the CP has completed the status word DMA to host memory. Thus,
504 * if we haven't processed any PDUs during this interrupt, we will
505 * wait a bit for completed work on the receive queue, rather than
506 * having to field an extra interrupt very soon.
509 if (++retries <= FORE_RECV_RETRY) {
510 DELAY(FORE_RECV_DELAY);
520 * Pass Incoming PDU up Stack
522 * This function is called via the core ATM interrupt queue callback
523 * set in fore_recv_drain(). It will pass the supplied incoming
524 * PDU up the incoming VCC's stack.
529 * tok token to identify stack instantiation
530 * m pointer to incoming PDU buffer chain
536 fore_recv_stack(tok, m)
540 Fore_vcc *fvp = (Fore_vcc *)tok;
544 * Send the data up the stack
546 STACK_CALL(CPCS_UNITDATA_SIG, fvp->fv_upper,
547 fvp->fv_toku, fvp->fv_connvc, (intptr_t)m, 0, err);
556 * Free Receive Queue Data Structures
559 * fup pointer to device unit structure
569 * We'll just let fore_buf_free() take care of freeing any
570 * buffers sitting on the receive queue (which are also still
571 * on the fu_*_bq queue).
573 if (fup->fu_flags & CUF_INITED) {
577 * Free the status words
579 if (fup->fu_recv_stat) {
580 atm_dev_free((volatile void *)fup->fu_recv_stat);
581 fup->fu_recv_stat = NULL;
582 fup->fu_recv_statd = NULL;
586 * Free the receive descriptors
588 if (fup->fu_recv_desc) {
589 atm_dev_free(fup->fu_recv_desc);
590 fup->fu_recv_desc = NULL;
591 fup->fu_recv_descd = NULL;