]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/hfa/fore_receive.c
Adjust some casts to quiet warnings.
[FreeBSD/FreeBSD.git] / sys / dev / hfa / fore_receive.c
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  * Receive queue management
35  *
36  */
37
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>
43 #include <vm/vm.h>
44 #include <vm/pmap.h>
45 #include <net/if.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>
65
66 #ifndef lint
67 __RCSID("@(#) $FreeBSD$");
68 #endif
69
70
71 /*
72  * Local functions
73  */
74 static void     fore_recv_stack(void *, KBuffer *);
75
76
77 /*
78  * Allocate Receive Queue Data Structures
79  *
80  * Arguments:
81  *      fup             pointer to device unit structure
82  *
83  * Returns:
84  *      0               allocations successful
85  *      else            allocation failed
86  */
87 int
88 fore_recv_allocate(fup)
89         Fore_unit       *fup;
90 {
91         caddr_t         memp;
92
93         /*
94          * Allocate non-cacheable memory for receive status words
95          */
96         memp = atm_dev_alloc(sizeof(Q_status) * RECV_QUELEN,
97                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
98         if (memp == NULL) {
99                 return (1);
100         }
101         fup->fu_recv_stat = (Q_status *) memp;
102
103         memp = (caddr_t)vtophys(fup->fu_recv_stat);
104         if (memp == NULL) {
105                 return (1);
106         }
107         fup->fu_recv_statd = (Q_status *) memp;
108
109         /*
110          * Allocate memory for receive descriptors
111          */
112         memp = atm_dev_alloc(sizeof(Recv_descr) * RECV_QUELEN,
113                         RECV_DESCR_ALIGN, 0);
114         if (memp == NULL) {
115                 return (1);
116         }
117         fup->fu_recv_desc = (Recv_descr *) memp;
118
119         memp = (caddr_t)vtophys(fup->fu_recv_desc);
120         if (memp == NULL) {
121                 return (1);
122         }
123         fup->fu_recv_descd = (Recv_descr *) memp;
124
125         return (0);
126 }
127
128
129 /*
130  * Receive Queue Initialization
131  *
132  * Allocate and initialize the host-resident receive queue structures
133  * and then initialize the CP-resident queue structures.
134  * 
135  * Called at interrupt level.
136  *
137  * Arguments:
138  *      fup             pointer to device unit structure
139  *
140  * Returns:
141  *      none
142  */
143 void
144 fore_recv_initialize(fup)
145         Fore_unit       *fup;
146 {
147         Aali            *aap = fup->fu_aali;
148         Recv_queue      *cqp;
149         H_recv_queue    *hrp;
150         Recv_descr      *rdp;
151         Recv_descr      *rdp_dma;
152         Q_status        *qsp;
153         Q_status        *qsp_dma;
154         int             i;
155
156         /*
157          * Point to CP-resident receive queue
158          */
159         cqp = (Recv_queue *)(fup->fu_ram + CP_READ(aap->aali_recv_q));
160
161         /*
162          * Point to host-resident receive queue structures
163          */
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;
169
170         /*
171          * Loop thru all queue entries and do whatever needs doing
172          */
173         for (i = 0; i < RECV_QUELEN; i++) {
174
175                 /*
176                  * Set queue status word to free
177                  */
178                 *qsp = QSTAT_FREE;
179
180                 /*
181                  * Set up host queue entry and link into ring
182                  */
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;
189                 else
190                         hrp->hrq_next = hrp + 1;
191
192                 /*
193                  * Now let the CP into the game
194                  */
195                 cqp->cq_descr = (CP_dma) CP_WRITE(rdp_dma);
196                 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
197
198                 /*
199                  * Bump all queue pointers
200                  */
201                 hrp++;
202                 qsp++;
203                 qsp_dma++;
204                 rdp++;
205                 rdp_dma++;
206                 cqp++;
207         }
208
209         /*
210          * Initialize queue pointers
211          */
212         fup->fu_recv_head = fup->fu_recv_q;
213
214         return;
215 }
216
217
218 /*
219  * Drain Receive Queue
220  *
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.
225  *
226  * May be called in interrupt state.
227  * Must be called with interrupts locked out.
228  *
229  * Arguments:
230  *      fup             pointer to device unit structure
231  *
232  * Returns:
233  *      none
234  */
235 void
236 fore_recv_drain(fup)
237         Fore_unit       *fup;
238 {
239         H_recv_queue    *hrp = NULL;
240         Recv_descr      *rdp;
241         Recv_seg_descr  *rsp;
242         Buf_handle      *bhp;
243         Fore_vcc        *fvp;
244         struct vccb     *vcp;
245         KBuffer         *m, *mhead, *mtail;
246         caddr_t         cp;
247         u_long          hdr, nsegs;
248         u_int           seglen, type0;
249         int             i, pdulen, retries = 0, error;
250
251         /* Silence the compiler */
252         mtail = NULL;
253         type0 = 0;
254
255         /*
256          * Process each completed entry
257          */
258 retry:
259         while (*fup->fu_recv_head->hrq_status & QSTAT_COMPLETED) {
260
261                 /*
262                  * Get completed entry's receive descriptor
263                  */
264                 hrp = fup->fu_recv_head;
265                 rdp = hrp->hrq_descr;
266
267 #ifdef VAC
268                 /*
269                  * Cache flush receive descriptor 
270                  */
271                 if (vac) {
272                         vac_flush((addr_t)rdp, sizeof(Recv_descr));
273                 }
274 #endif
275
276                 hdr = rdp->rd_cell_hdr;
277                 nsegs = rdp->rd_nsegs;
278
279                 pdulen = 0;
280                 error = 0;
281                 mhead = NULL;
282
283                 /*
284                  * Locate incoming VCC for this PDU
285                  */
286                 fvp = (Fore_vcc *) atm_dev_vcc_find((Cmn_unit *)fup,
287                         ATM_HDR_GET_VPI(hdr), ATM_HDR_GET_VCI(hdr), VCC_IN);
288
289                 /*
290                  * Check for a receive error
291                  *
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.
295                  */
296                 if (*hrp->hrq_status & QSTAT_ERROR) {
297
298                         fup->fu_pif.pif_ierrors++;
299                         if (fvp) {
300                                 vcp = fvp->fv_connvc->cvc_vcc;
301                                 vcp->vc_ierrors++;
302                                 if (vcp->vc_nif)
303                                         vcp->vc_nif->nif_if.if_ierrors++;
304                         }
305                         ATM_DEBUG1("fore receive error: hdr=0x%lx\n", hdr);
306                         error = 1;
307                 }
308
309                 /*
310                  * Build PDU buffer chain from receive segments
311                  */
312                 for (i = 0, rsp = rdp->rd_seg; i < nsegs; i++, rsp++) {
313
314                         bhp = rsp->rsd_handle;
315                         seglen = rsp->rsd_len;
316
317                         /*
318                          * Remove buffer from our supplied queue and get
319                          * to the underlying buffer
320                          */
321                         switch (bhp->bh_type) {
322
323                         case BHT_S1_SMALL:
324                                 DEQUEUE(bhp, Buf_handle, bh_qelem,
325                                         fup->fu_buf1s_bq);
326                                 fup->fu_buf1s_cnt--;
327                                 m = (KBuffer *) ((caddr_t)bhp - BUF1_SM_HOFF);
328                                 KB_DATASTART(m, cp, caddr_t);
329                                 break;
330
331                         case BHT_S1_LARGE:
332                                 DEQUEUE(bhp, Buf_handle, bh_qelem,
333                                         fup->fu_buf1l_bq);
334                                 fup->fu_buf1l_cnt--;
335                                 m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF);
336                                 KB_DATASTART(m, cp, caddr_t);
337                                 break;
338
339                         default:
340                                 log(LOG_ERR,
341                                         "fore_recv_drain: bhp=%p type=0x%x\n",
342                                         bhp, bhp->bh_type);
343                                 panic("fore_recv_drain: bad buffer type");
344                         }
345
346                         /*
347                          * Toss any zero-length or receive error buffers 
348                          */
349                         if ((seglen == 0) || error) {
350                                 KB_FREEALL(m);
351                                 continue;
352                         }
353
354                         /*
355                          * Link buffer into chain
356                          */
357                         if (mhead == NULL) {
358                                 type0 = bhp->bh_type;
359                                 KB_LINKHEAD(m, mhead);
360                                 mhead = m;
361                         } else {
362                                 KB_LINK(m, mtail);
363                         }
364                         KB_LEN(m) = seglen;
365                         pdulen += seglen;
366                         mtail = m;
367
368                         /*
369                          * Flush received buffer data
370                          */
371 #ifdef VAC
372                         if (vac) {
373                                 addr_t  dp;
374
375                                 KB_DATASTART(m, dp, addr_t);
376                                 vac_pageflush(dp);
377                         }
378 #endif
379                 }
380
381                 /*
382                  * Make sure we've got a non-null PDU
383                  */
384                 if (mhead == NULL) {
385                         goto free_ent;
386                 }
387
388                 /*
389                  * We only support user data PDUs (for now)
390                  */
391                 if (hdr & ATM_HDR_SET_PT(ATM_PT_NONUSER)) {
392                         KB_FREEALL(mhead);
393                         goto free_ent;
394                 }
395
396                 /*
397                  * Toss the data if there's no VCC
398                  */
399                 if (fvp == NULL) {
400                         fup->fu_stats->st_drv.drv_rv_novcc++;
401                         KB_FREEALL(mhead);
402                         goto free_ent;
403                 }
404
405 #ifdef DIAGNOSTIC
406                 if (atm_dev_print)
407                         atm_dev_pdu_print((Cmn_unit *)fup, (Cmn_vcc *)fvp, 
408                                 mhead, "fore_recv");
409 #endif
410
411                 /*
412                  * Make sure we have our queueing headroom at the front
413                  * of the buffer chain
414                  */
415                 if (type0 != BHT_S1_SMALL) {
416
417                         /*
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.
422                          */
423                         fup->fu_stats->st_drv.drv_rv_nosbf++;
424
425                         KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
426                         if (m == NULL) {
427                                 fup->fu_stats->st_drv.drv_rv_nomb++;
428                                 KB_FREEALL(mhead);
429                                 goto free_ent;
430                         }
431
432                         /*
433                          * Put new buffer at head of PDU chain
434                          */
435                         KB_LINKHEAD(m, mhead);
436                         KB_LEN(m) = 0;
437                         KB_HEADSET(m, BUF1_SM_DOFF);
438                         mhead = m;
439                 }
440
441                 /*
442                  * It looks like we've got a valid PDU - count it quick!!
443                  */
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;
451                 vcp->vc_ipdus++;
452                 vcp->vc_ibytes += pdulen;
453                 if (vcp->vc_nif) {
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;
458 #endif
459                 }
460
461                 /*
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.
466                  */
467
468                 /*
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.
472                  */
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;
478
479                 /*
480                  * Schedule callback
481                  */
482                 if (IF_HANDOFF(&atm_intrq, mhead, NULL)) {
483                         schednetisr(NETISR_ATM);
484                 } else {
485                         fup->fu_stats->st_drv.drv_rv_ifull++;
486                         goto free_ent;
487                 }
488
489 free_ent:
490                 /*
491                  * Mark this entry free for use and bump head pointer
492                  * to the next entry in the queue
493                  */
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;
498         }
499
500         /*
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.
507          */
508         if (hrp == NULL) {
509                 if (++retries <= FORE_RECV_RETRY) {
510                         DELAY(FORE_RECV_DELAY);
511                         goto retry;
512                 }
513         }
514
515         return;
516 }
517
518
519 /*
520  * Pass Incoming PDU up Stack
521  *
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.
525  *
526  * Called at splnet.
527  *
528  * Arguments:
529  *      tok             token to identify stack instantiation
530  *      m               pointer to incoming PDU buffer chain
531  *
532  * Returns:
533  *      none
534  */
535 static void
536 fore_recv_stack(tok, m)
537         void            *tok;
538         KBuffer         *m;
539 {
540         Fore_vcc        *fvp = (Fore_vcc *)tok;
541         int             err;
542
543         /*
544          * Send the data up the stack
545          */
546         STACK_CALL(CPCS_UNITDATA_SIG, fvp->fv_upper,
547                 fvp->fv_toku, fvp->fv_connvc, (intptr_t)m, 0, err);
548         if (err)
549                 KB_FREEALL(m);
550
551         return;
552 }
553
554
555 /*
556  * Free Receive Queue Data Structures
557  *
558  * Arguments:
559  *      fup             pointer to device unit structure
560  *
561  * Returns:
562  *      none
563  */
564 void
565 fore_recv_free(fup)
566         Fore_unit       *fup;
567 {
568         /*
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).
572          */
573         if (fup->fu_flags & CUF_INITED) {
574         }
575
576         /*
577          * Free the status words
578          */
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;
583         }
584
585         /*
586          * Free the receive descriptors
587          */
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;
592         }
593
594         return;
595 }
596