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