Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / atm / hfa / fore_transmit.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_transmit.c,v 1.4 1999/08/28 00:41:53 peter Exp $
27  *
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Transmit queue management
35  *
36  */
37
38 #include <dev/hfa/fore_include.h>
39
40 #ifndef lint
41 __RCSID("@(#) $FreeBSD: src/sys/dev/hfa/fore_transmit.c,v 1.4 1999/08/28 00:41:53 peter Exp $");
42 #endif
43
44
45 /*
46  * Allocate Transmit Queue Data Structures
47  *
48  * Arguments:
49  *      fup             pointer to device unit structure
50  *
51  * Returns:
52  *      0               allocations successful
53  *      else            allocation failed
54  */
55 int
56 fore_xmit_allocate(fup)
57         Fore_unit       *fup;
58 {
59         void            *memp;
60         H_xmit_queue    *hxp;
61         int             i;
62
63         /*
64          * Allocate non-cacheable memory for transmit status words
65          */
66         memp = atm_dev_alloc(sizeof(Q_status) * XMIT_QUELEN,
67                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
68         if (memp == NULL) {
69                 return (1);
70         }
71         fup->fu_xmit_stat = (Q_status *) memp;
72
73         memp = DMA_GET_ADDR(fup->fu_xmit_stat, sizeof(Q_status) * XMIT_QUELEN,
74                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
75         if (memp == NULL) {
76                 return (1);
77         }
78         fup->fu_xmit_statd = (Q_status *) memp;
79
80         /*
81          * Allocate memory for transmit descriptors
82          *
83          * We will allocate the transmit descriptors individually rather than 
84          * as a single memory block, which will often be larger than a memory
85          * page.  On some systems (eg. FreeBSD) the physical addresses of 
86          * adjacent virtual memory pages are not contiguous.
87          */
88         hxp = fup->fu_xmit_q;
89         for (i = 0; i < XMIT_QUELEN; i++, hxp++) {
90
91                 /*
92                  * Allocate a transmit descriptor for this queue entry
93                  */
94                 hxp->hxq_descr = atm_dev_alloc(sizeof(Xmit_descr),
95                         XMIT_DESCR_ALIGN, 0);
96                 if (hxp->hxq_descr == NULL) {
97                         return (1);
98                 }
99
100                 hxp->hxq_descr_dma = DMA_GET_ADDR(hxp->hxq_descr,
101                         sizeof(Xmit_descr), XMIT_DESCR_ALIGN, 0);
102                 if (hxp->hxq_descr_dma == NULL) {
103                         return (1);
104                 }
105         }
106
107         return (0);
108 }
109
110
111 /*
112  * Transmit Queue Initialization
113  *
114  * Allocate and initialize the host-resident transmit queue structures
115  * and then initialize the CP-resident queue structures.
116  * 
117  * Called at interrupt level.
118  *
119  * Arguments:
120  *      fup             pointer to device unit structure
121  *
122  * Returns:
123  *      none
124  */
125 void
126 fore_xmit_initialize(fup)
127         Fore_unit       *fup;
128 {
129         Aali            *aap = fup->fu_aali;
130         Xmit_queue      *cqp;
131         H_xmit_queue    *hxp;
132         Q_status        *qsp;
133         Q_status        *qsp_dma;
134         int             i;
135
136         /*
137          * Point to CP-resident transmit queue
138          */
139         cqp = (Xmit_queue *)(fup->fu_ram + CP_READ(aap->aali_xmit_q));
140
141         /*
142          * Point to host-resident transmit queue structures
143          */
144         hxp = fup->fu_xmit_q;
145         qsp = fup->fu_xmit_stat;
146         qsp_dma = fup->fu_xmit_statd;
147
148         /*
149          * Loop thru all queue entries and do whatever needs doing
150          */
151         for (i = 0; i < XMIT_QUELEN; i++) {
152
153                 /*
154                  * Set queue status word to free
155                  */
156                 *qsp = QSTAT_FREE;
157
158                 /*
159                  * Set up host queue entry and link into ring
160                  */
161                 hxp->hxq_cpelem = cqp;
162                 hxp->hxq_status = qsp;
163                 if (i == (XMIT_QUELEN - 1))
164                         hxp->hxq_next = fup->fu_xmit_q;
165                 else
166                         hxp->hxq_next = hxp + 1;
167
168                 /*
169                  * Now let the CP into the game
170                  */
171                 cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
172
173                 /*
174                  * Bump all queue pointers
175                  */
176                 hxp++;
177                 qsp++;
178                 qsp_dma++;
179                 cqp++;
180         }
181
182         /*
183          * Initialize queue pointers
184          */
185         fup->fu_xmit_head = fup->fu_xmit_tail = fup->fu_xmit_q;
186
187         return;
188 }
189
190
191 /*
192  * Drain Transmit Queue
193  *
194  * This function will free all completed entries at the head of the
195  * transmit queue.  Freeing the entry includes releasing the transmit
196  * buffers (buffer chain) back to the kernel.  
197  *
198  * May be called in interrupt state.
199  * Must be called with interrupts locked out.
200  *
201  * Arguments:
202  *      fup             pointer to device unit structure
203  *
204  * Returns:
205  *      none
206  */
207 void
208 fore_xmit_drain(fup)
209         Fore_unit       *fup;
210 {
211         H_xmit_queue    *hxp;
212         H_dma           *sdmap;
213         Fore_vcc        *fvp;
214         struct vccb     *vcp;
215         KBuffer         *m;
216
217         /*
218          * Process each completed entry
219          */
220         while (*fup->fu_xmit_head->hxq_status & QSTAT_COMPLETED) {
221
222                 hxp = fup->fu_xmit_head;
223
224                 /*
225                  * Release the entry's DMA addresses and buffer chain
226                  */
227                 for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m;
228                                 m = KB_NEXT(m), sdmap++) {
229                         caddr_t         cp;
230
231                         KB_DATASTART(m, cp, caddr_t);
232                         DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);
233                 }
234                 KB_FREEALL(hxp->hxq_buf);
235
236                 /*
237                  * Get VCC over which data was sent (may be null if
238                  * VCC has been closed in the meantime)
239                  */
240                 fvp = hxp->hxq_vcc;
241
242                 /*
243                  * Now collect some statistics
244                  */
245                 if (*hxp->hxq_status & QSTAT_ERROR) {
246                         /*
247                          * CP ran into problems, not much we can do
248                          * other than record the event
249                          */
250                         fup->fu_pif.pif_oerrors++;
251                         if (fvp) {
252                                 vcp = fvp->fv_connvc->cvc_vcc;
253                                 vcp->vc_oerrors++;
254                                 if (vcp->vc_nif)
255                                         vcp->vc_nif->nif_if.if_oerrors++;
256                         }
257                 } else {
258                         /*
259                          * Good transmission
260                          */
261                         int     len = XDS_GET_LEN(hxp->hxq_descr->xd_spec);
262
263                         fup->fu_pif.pif_opdus++;
264                         fup->fu_pif.pif_obytes += len;
265                         if (fvp) {
266                                 vcp = fvp->fv_connvc->cvc_vcc;
267                                 vcp->vc_opdus++;
268                                 vcp->vc_obytes += len;
269                                 if (vcp->vc_nif) {
270                                         vcp->vc_nif->nif_obytes += len;
271                                         vcp->vc_nif->nif_if.if_opackets++;
272 #if (defined(BSD) && (BSD >= 199103))
273                                         vcp->vc_nif->nif_if.if_obytes += len;
274 #endif
275                                 }
276                         }
277                 }
278
279                 /*
280                  * Mark this entry free for use and bump head pointer
281                  * to the next entry in the queue
282                  */
283                 *hxp->hxq_status = QSTAT_FREE;
284                 fup->fu_xmit_head = hxp->hxq_next;
285         }
286
287         return;
288 }
289
290
291 /*
292  * Free Transmit Queue Data Structures
293  *
294  * Arguments:
295  *      fup             pointer to device unit structure
296  *
297  * Returns:
298  *      none
299  */
300 void
301 fore_xmit_free(fup)
302         Fore_unit       *fup;
303 {
304         H_xmit_queue    *hxp;
305         H_dma           *sdmap;
306         KBuffer         *m;
307         int             i;
308
309         /*
310          * Free any transmit buffers left on the queue
311          */
312         if (fup->fu_flags & CUF_INITED) {
313                 while (*fup->fu_xmit_head->hxq_status != QSTAT_FREE) {
314
315                         hxp = fup->fu_xmit_head;
316
317                         /*
318                          * Release the entry's DMA addresses and buffer chain
319                          */
320                         for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m;
321                                         m = KB_NEXT(m), sdmap++) {
322                                 caddr_t         cp;
323
324                                 KB_DATASTART(m, cp, caddr_t);
325                                 DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);
326                         }
327                         KB_FREEALL(hxp->hxq_buf);
328
329                         *hxp->hxq_status = QSTAT_FREE;
330                         fup->fu_xmit_head = hxp->hxq_next;
331                 }
332         }
333
334         /*
335          * Free the status words
336          */
337         if (fup->fu_xmit_stat) {
338                 if (fup->fu_xmit_statd) {
339                         DMA_FREE_ADDR(fup->fu_xmit_stat, fup->fu_xmit_statd,
340                                 sizeof(Q_status) * XMIT_QUELEN,
341                                 ATM_DEV_NONCACHE);
342                 }
343                 atm_dev_free((volatile void *)fup->fu_xmit_stat);
344                 fup->fu_xmit_stat = NULL;
345                 fup->fu_xmit_statd = NULL;
346         }
347
348         /*
349          * Free the transmit descriptors
350          */
351         hxp = fup->fu_xmit_q;
352         for (i = 0; i < XMIT_QUELEN; i++, hxp++) {
353
354                 /*
355                  * Free the transmit descriptor for this queue entry
356                  */
357                 if (hxp->hxq_descr_dma) {
358                         DMA_FREE_ADDR(hxp->hxq_descr, hxp->hxq_descr_dma,
359                                 sizeof(Xmit_descr), 0);
360                         hxp->hxq_descr_dma = NULL;
361                 }
362
363                 if (hxp->hxq_descr) {
364                         atm_dev_free(hxp->hxq_descr);
365                         hxp->hxq_descr = NULL;
366                 }
367         }
368
369         return;
370 }
371