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