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
|