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