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 * Buffer Supply queue management
33 *
34 */
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/time.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 <netatm/port.h>
47 #include <netatm/queue.h>
48 #include <netatm/atm.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_sap.h>
51 #include <netatm/atm_cm.h>
52 #include <netatm/atm_if.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_buf_drain(Fore_unit *);
73 static void fore_buf_supply_1s(Fore_unit *);
74 static void fore_buf_supply_1l(Fore_unit *);
75
76
77 /*
78 * Allocate Buffer Supply Queues Data Structures
79 *
80 * Here we are allocating memory for both Strategy 1 Small and Large
81 * structures contiguously.
82 *
83 * Arguments:
84 * fup pointer to device unit structure
85 *
86 * Returns:
87 * 0 allocations successful
88 * else allocation failed
89 */
90 int
91 fore_buf_allocate(fup)
92 Fore_unit *fup;
93 {
94 caddr_t memp;
95 vm_paddr_t pmemp;
96
97 /*
98 * Allocate non-cacheable memory for buffer supply status words
99 */
100 memp = atm_dev_alloc(
101 sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
102 QSTAT_ALIGN, ATM_DEV_NONCACHE);
103 if (memp == NULL) {
104 return (1);
105 }
106 fup->fu_buf1s_stat = (Q_status *) memp;
107 fup->fu_buf1l_stat = ((Q_status *) memp) + BUF1_SM_QUELEN;
108
109 pmemp = vtophys(fup->fu_buf1s_stat);
110 if (pmemp == 0) {
111 return (1);
112 }
113 fup->fu_buf1s_statd = pmemp;
114
115 pmemp = vtophys(fup->fu_buf1l_stat);
116 if (pmemp == 0) {
117 return (1);
118 }
119 fup->fu_buf1l_statd = pmemp;
120
121 /*
122 * Allocate memory for buffer supply descriptors
123 */
124 memp = atm_dev_alloc(sizeof(Buf_descr) *
125 ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
126 (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
127 BUF_DESCR_ALIGN, 0);
128 if (memp == NULL) {
129 return (1);
130 }
131 fup->fu_buf1s_desc = (Buf_descr *) memp;
132 fup->fu_buf1l_desc = ((Buf_descr *) memp) +
133 (BUF1_SM_QUELEN * BUF1_SM_ENTSIZE);
134
135 pmemp = vtophys(fup->fu_buf1s_desc);
136 if (pmemp == 0) {
137 return (1);
138 }
139 fup->fu_buf1s_descd = pmemp;
140
141 pmemp = vtophys(fup->fu_buf1l_desc);
142 if (pmemp == 0) {
143 return (1);
144 }
145 fup->fu_buf1l_descd = pmemp;
146
147 return (0);
148 }
149
150
151 /*
152 * Buffer Supply Queues Initialization
153 *
154 * Allocate and initialize the host-resident buffer supply queue structures
155 * and then initialize the CP-resident queue structures.
156 *
157 * Called at interrupt level.
158 *
159 * Arguments:
160 * fup pointer to device unit structure
161 *
162 * Returns:
163 * none
164 */
165 void
166 fore_buf_initialize(fup)
167 Fore_unit *fup;
168 {
169 Aali *aap = fup->fu_aali;
170 Buf_queue *cqp;
171 H_buf_queue *hbp;
172 Buf_descr *bdp;
173 vm_paddr_t bdp_dma;
174 Q_status *qsp;
175 vm_paddr_t qsp_dma;
176 int i;
177
178 /*
179 * Initialize Strategy 1 Small Queues
180 */
181
182 /*
183 * Point to CP-resident buffer supply queue
184 */
185 cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1s_q));
186
187 /*
188 * Point to host-resident buffer supply queue structures
189 */
190 hbp = fup->fu_buf1s_q;
191 qsp = fup->fu_buf1s_stat;
192 qsp_dma = fup->fu_buf1s_statd;
193 bdp = fup->fu_buf1s_desc;
194 bdp_dma = fup->fu_buf1s_descd;
195
196 /*
197 * Loop thru all queue entries and do whatever needs doing
198 */
199 for (i = 0; i < BUF1_SM_QUELEN; i++) {
200
201 /*
202 * Set queue status word to free
203 */
204 *qsp = QSTAT_FREE;
205
206 /*
207 * Set up host queue entry and link into ring
208 */
209 hbp->hbq_cpelem = cqp;
210 hbp->hbq_status = qsp;
211 hbp->hbq_descr = bdp;
212 hbp->hbq_descr_dma = bdp_dma;
213 if (i == (BUF1_SM_QUELEN - 1))
214 hbp->hbq_next = fup->fu_buf1s_q;
215 else
216 hbp->hbq_next = hbp + 1;
217
218 /*
219 * Now let the CP into the game
220 */
221 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
222
223 /*
224 * Bump all queue pointers
225 */
226 hbp++;
227 qsp++;
228 qsp_dma += sizeof(Q_status);
229 bdp += BUF1_SM_ENTSIZE;
230 bdp_dma += BUF1_SM_ENTSIZE * sizeof(Buf_descr);
231 cqp++;
232 }
233
234 /*
235 * Initialize queue pointers
236 */
237 fup->fu_buf1s_head = fup->fu_buf1s_tail = fup->fu_buf1s_q;
238
239
240 /*
241 * Initialize Strategy 1 Large Queues
242 */
243
244 /*
245 * Point to CP-resident buffer supply queue
246 */
247 cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1l_q));
248
249 /*
250 * Point to host-resident buffer supply queue structures
251 */
252 hbp = fup->fu_buf1l_q;
253 qsp = fup->fu_buf1l_stat;
254 qsp_dma = fup->fu_buf1l_statd;
255 bdp = fup->fu_buf1l_desc;
256 bdp_dma = fup->fu_buf1l_descd;
257
258 /*
259 * Loop thru all queue entries and do whatever needs doing
260 */
261 for (i = 0; i < BUF1_LG_QUELEN; i++) {
262
263 /*
264 * Set queue status word to free
265 */
266 *qsp = QSTAT_FREE;
267
268 /*
269 * Set up host queue entry and link into ring
270 */
271 hbp->hbq_cpelem = cqp;
272 hbp->hbq_status = qsp;
273 hbp->hbq_descr = bdp;
274 hbp->hbq_descr_dma = bdp_dma;
275 if (i == (BUF1_LG_QUELEN - 1))
276 hbp->hbq_next = fup->fu_buf1l_q;
277 else
278 hbp->hbq_next = hbp + 1;
279
280 /*
281 * Now let the CP into the game
282 */
283 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
284
285 /*
286 * Bump all queue pointers
287 */
288 hbp++;
289 qsp++;
290 qsp_dma += sizeof(Q_status);
291 bdp += BUF1_LG_ENTSIZE;
292 bdp_dma += BUF1_LG_ENTSIZE * sizeof(Buf_descr);
293 cqp++;
294 }
295
296 /*
297 * Initialize queue pointers
298 */
299 fup->fu_buf1l_head = fup->fu_buf1l_tail = fup->fu_buf1l_q;
300
301 return;
302 }
303
304
305 /*
306 * Supply Buffers to CP
307 *
308 * This function will resupply the CP with buffers to be used to
309 * store incoming data.
310 *
311 * May be called in interrupt state.
312 * Must be called with interrupts locked out.
313 *
314 * Arguments:
315 * fup pointer to device unit structure
316 *
317 * Returns:
318 * none
319 */
320 void
321 fore_buf_supply(fup)
322 Fore_unit *fup;
323 {
324
325 /*
326 * First, clean out the supply queues
327 */
328 fore_buf_drain(fup);
329
330 /*
331 * Then, supply the buffers for each queue
332 */
333 fore_buf_supply_1s(fup);
334 fore_buf_supply_1l(fup);
335
336 return;
337 }
338
339
340 /*
341 * Supply Strategy 1 Small Buffers to CP
342 *
343 * May be called in interrupt state.
344 * Must be called with interrupts locked out.
345 *
346 * Arguments:
347 * fup pointer to device unit structure
348 *
349 * Returns:
350 * none
351 */
352 static void
353 fore_buf_supply_1s(fup)
354 Fore_unit *fup;
355 {
356 H_buf_queue *hbp;
357 Buf_queue *cqp;
358 Buf_descr *bdp;
359 Buf_handle *bhp;
360 KBuffer *m;
361 int nvcc, nbuf, i;
362
363 /*
364 * Figure out how many buffers we should be giving to the CP.
365 * We're basing this calculation on the current number of open
366 * VCCs thru this device, with certain minimum and maximum values
367 * enforced. This will then allow us to figure out how many more
368 * buffers we need to supply to the CP. This will be rounded up
369 * to fill a supply queue entry.
370 */
371 nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
372 nbuf = nvcc * 4;
373 nbuf = MIN(nbuf, BUF1_SM_CPPOOL);
374 nbuf -= fup->fu_buf1s_cnt;
375 nbuf = roundup(nbuf, BUF1_SM_ENTSIZE);
376
377 /*
378 * OK, now supply the buffers to the CP
379 */
380 while (nbuf > 0) {
381
382 /*
383 * Acquire a supply queue entry
384 */
385 hbp = fup->fu_buf1s_tail;
386 if (!((*hbp->hbq_status) & QSTAT_FREE))
387 break;
388 bdp = hbp->hbq_descr;
389
390 /*
391 * Get a buffer for each descriptor in the queue entry
392 */
393 for (i = 0; i < BUF1_SM_ENTSIZE; i++, bdp++) {
394 caddr_t cp;
395
396 /*
397 * Get a small buffer
398 */
399 KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
400 if (m == 0) {
401 break;
402 }
403 KB_HEADSET(m, BUF1_SM_DOFF);
404
405 /*
406 * Point to buffer handle structure
407 */
408 bhp = (Buf_handle *)((caddr_t)m + BUF1_SM_HOFF);
409 bhp->bh_type = BHT_S1_SMALL;
410
411 /*
412 * Setup buffer descriptor
413 */
414 bdp->bsd_handle = bhp;
415 KB_DATASTART(m, cp, caddr_t);
416 bhp->bh_dma = bdp->bsd_buffer = vtophys(cp);
417 if (bdp->bsd_buffer == 0) {
418 /*
419 * Unable to assign dma address - free up
420 * this descriptor's buffer
421 */
422 fup->fu_stats->st_drv.drv_bf_segdma++;
423 KB_FREEALL(m);
424 break;
425 }
426
427 /*
428 * All set, so queue buffer (handle)
429 */
430 ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
431 }
432
433 /*
434 * If we we're not able to fill all the descriptors for
435 * an entry, free up what's been partially built
436 */
437 if (i != BUF1_SM_ENTSIZE) {
438 caddr_t cp;
439
440 /*
441 * Clean up each used descriptor
442 */
443 for (bdp = hbp->hbq_descr; i; i--, bdp++) {
444
445 bhp = bdp->bsd_handle;
446
447 DEQUEUE(bhp, Buf_handle, bh_qelem,
448 fup->fu_buf1s_bq);
449
450 m = (KBuffer *)
451 ((caddr_t)bhp - BUF1_SM_HOFF);
452 KB_DATASTART(m, cp, caddr_t);
453 KB_FREEALL(m);
454 }
455 break;
456 }
457
458 /*
459 * Finally, we've got an entry ready for the CP.
460 * So claim the host queue entry and setup the CP-resident
461 * queue entry. The CP will (potentially) grab the supplied
462 * buffers when the descriptor pointer is set.
463 */
464 fup->fu_buf1s_tail = hbp->hbq_next;
465 (*hbp->hbq_status) = QSTAT_PENDING;
466 cqp = hbp->hbq_cpelem;
467 cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
468
469 /*
470 * Update counters, etc for supplied buffers
471 */
472 fup->fu_buf1s_cnt += BUF1_SM_ENTSIZE;
473 nbuf -= BUF1_SM_ENTSIZE;
474 }
475
476 return;
477 }
478
479
480 /*
481 * Supply Strategy 1 Large Buffers to CP
482 *
483 * May be called in interrupt state.
484 * Must be called with interrupts locked out.
485 *
486 * Arguments:
487 * fup pointer to device unit structure
488 *
489 * Returns:
490 * none
491 */
492 static void
493 fore_buf_supply_1l(fup)
494 Fore_unit *fup;
495 {
496 H_buf_queue *hbp;
497 Buf_queue *cqp;
498 Buf_descr *bdp;
499 Buf_handle *bhp;
500 KBuffer *m;
501 int nvcc, nbuf, i;
502
503 /*
504 * Figure out how many buffers we should be giving to the CP.
505 * We're basing this calculation on the current number of open
506 * VCCs thru this device, with certain minimum and maximum values
507 * enforced. This will then allow us to figure out how many more
508 * buffers we need to supply to the CP. This will be rounded up
509 * to fill a supply queue entry.
510 */
511 nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
512 nbuf = nvcc * 4 * RECV_MAX_SEGS;
513 nbuf = MIN(nbuf, BUF1_LG_CPPOOL);
514 nbuf -= fup->fu_buf1l_cnt;
515 nbuf = roundup(nbuf, BUF1_LG_ENTSIZE);
516
517 /*
518 * OK, now supply the buffers to the CP
519 */
520 while (nbuf > 0) {
521
522 /*
523 * Acquire a supply queue entry
524 */
525 hbp = fup->fu_buf1l_tail;
526 if (!((*hbp->hbq_status) & QSTAT_FREE))
527 break;
528 bdp = hbp->hbq_descr;
529
530 /*
531 * Get a buffer for each descriptor in the queue entry
532 */
533 for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) {
534 caddr_t cp;
535
536 /*
537 * Get a cluster buffer
538 */
539 KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA);
540 if (m == 0) {
541 break;
542 }
543 KB_HEADSET(m, BUF1_LG_DOFF);
544
545 /*
546 * Point to buffer handle structure
547 */
548 bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF);
549 bhp->bh_type = BHT_S1_LARGE;
550
551 /*
552 * Setup buffer descriptor
553 */
554 bdp->bsd_handle = bhp;
555 KB_DATASTART(m, cp, caddr_t);
556 bhp->bh_dma = bdp->bsd_buffer = vtophys(cp);
557 if (bdp->bsd_buffer == 0) {
558 /*
559 * Unable to assign dma address - free up
560 * this descriptor's buffer
561 */
562 fup->fu_stats->st_drv.drv_bf_segdma++;
563 KB_FREEALL(m);
564 break;
565 }
566
567 /*
568 * All set, so queue buffer (handle)
569 */
570 ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
571 }
572
573 /*
574 * If we we're not able to fill all the descriptors for
575 * an entry, free up what's been partially built
576 */
577 if (i != BUF1_LG_ENTSIZE) {
578 caddr_t cp;
579
580 /*
581 * Clean up each used descriptor
582 */
583 for (bdp = hbp->hbq_descr; i; i--, bdp++) {
584 bhp = bdp->bsd_handle;
585
586 DEQUEUE(bhp, Buf_handle, bh_qelem,
587 fup->fu_buf1l_bq);
588
589 m = (KBuffer *)
590 ((caddr_t)bhp - BUF1_LG_HOFF);
591 KB_DATASTART(m, cp, caddr_t);
592 KB_FREEALL(m);
593 }
594 break;
595 }
596
597 /*
598 * Finally, we've got an entry ready for the CP.
599 * So claim the host queue entry and setup the CP-resident
600 * queue entry. The CP will (potentially) grab the supplied
601 * buffers when the descriptor pointer is set.
602 */
603 fup->fu_buf1l_tail = hbp->hbq_next;
604 (*hbp->hbq_status) = QSTAT_PENDING;
605 cqp = hbp->hbq_cpelem;
606 cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
607
608 /*
609 * Update counters, etc for supplied buffers
610 */
611 fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE;
612 nbuf -= BUF1_LG_ENTSIZE;
613 }
614
615 return;
616 }
617
618
619 /*
620 * Drain Buffer Supply Queues
621 *
622 * This function will free all completed entries at the head of each
623 * buffer supply queue. Since we consider the CP to "own" the buffers
624 * once we put them on a supply queue and since a completed supply queue
625 * entry is only telling us that the CP has accepted the buffers that we
626 * gave to it, there's not much to do here.
627 *
628 * May be called in interrupt state.
629 * Must be called with interrupts locked out.
630 *
631 * Arguments:
632 * fup pointer to device unit structure
633 *
634 * Returns:
635 * none
636 */
637 static void
638 fore_buf_drain(fup)
639 Fore_unit *fup;
640 {
641 H_buf_queue *hbp;
642
643 /*
644 * Drain Strategy 1 Small Queue
645 */
646
647 /*
648 * Process each completed entry
649 */
650 while (*fup->fu_buf1s_head->hbq_status & QSTAT_COMPLETED) {
651
652 hbp = fup->fu_buf1s_head;
653
654 if (*hbp->hbq_status & QSTAT_ERROR) {
655 /*
656 * XXX - what does this mean???
657 */
658 log(LOG_ERR, "fore_buf_drain: buf1s queue error\n");
659 }
660
661 /*
662 * Mark this entry free for use and bump head pointer
663 * to the next entry in the queue
664 */
665 *hbp->hbq_status = QSTAT_FREE;
666 fup->fu_buf1s_head = hbp->hbq_next;
667 }
668
669
670 /*
671 * Drain Strategy 1 Large Queue
672 */
673
674 /*
675 * Process each completed entry
676 */
677 while (*fup->fu_buf1l_head->hbq_status & QSTAT_COMPLETED) {
678
679 hbp = fup->fu_buf1l_head;
680
681 if (*hbp->hbq_status & QSTAT_ERROR) {
682 /*
683 * XXX - what does this mean???
684 */
685 log(LOG_ERR, "fore_buf_drain: buf1l queue error\n");
686 }
687
688 /*
689 * Mark this entry free for use and bump head pointer
690 * to the next entry in the queue
691 */
692 *hbp->hbq_status = QSTAT_FREE;
693 fup->fu_buf1l_head = hbp->hbq_next;
694 }
695
696 return;
697 }
698
699
700 /*
701 * Free Buffer Supply Queue Data Structures
702 *
703 * Arguments:
704 * fup pointer to device unit structure
705 *
706 * Returns:
707 * none
708 */
709 void
710 fore_buf_free(fup)
711 Fore_unit *fup;
712 {
713 Buf_handle *bhp;
714 KBuffer *m;
715
716 /*
717 * Free any previously supplied and not returned buffers
718 */
719 if (fup->fu_flags & CUF_INITED) {
720
721 /*
722 * Run through Strategy 1 Small queue
723 */
724 while ((bhp = Q_HEAD(fup->fu_buf1s_bq, Buf_handle)) != NULL) {
725 caddr_t cp;
726
727 /*
728 * Back off to buffer
729 */
730 m = (KBuffer *)((caddr_t)bhp - BUF1_SM_HOFF);
731
732 /*
733 * Dequeue handle and free buffer
734 */
735 DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
736
737 KB_DATASTART(m, cp, caddr_t);
738 KB_FREEALL(m);
739 }
740
741 /*
742 * Run through Strategy 1 Large queue
743 */
744 while ((bhp = Q_HEAD(fup->fu_buf1l_bq, Buf_handle)) != NULL) {
745 caddr_t cp;
746
747 /*
748 * Back off to buffer
749 */
750 m = (KBuffer *)((caddr_t)bhp - BUF1_LG_HOFF);
751
752 /*
753 * Dequeue handle and free buffer
754 */
755 DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
756
757 KB_DATASTART(m, cp, caddr_t);
758 KB_FREEALL(m);
759 }
760 }
761
762 /*
763 * Free the status words
764 */
765 if (fup->fu_buf1s_stat) {
766 atm_dev_free((volatile void *)fup->fu_buf1s_stat);
767 fup->fu_buf1s_stat = NULL;
768 fup->fu_buf1s_statd = 0;
769 fup->fu_buf1l_stat = NULL;
770 fup->fu_buf1l_statd = 0;
771 }
772
773 /*
774 * Free the transmit descriptors
775 */
776 if (fup->fu_buf1s_desc) {
777 atm_dev_free(fup->fu_buf1s_desc);
778 fup->fu_buf1s_desc = NULL;
779 fup->fu_buf1s_descd = 0;
780 fup->fu_buf1l_desc = NULL;
781 fup->fu_buf1l_descd = 0;
782 }
783
784 return;
785 }
786
Cache object: c3b9dd1a66809749e76193e4646499fb
|