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