Add flag to indicate that the NIC does not have power control capability.
[dragonfly.git] / sys / dev / atm / hfa / fore_output.c
blob86f58776ab55453e9ab3e7d6c072cae34e4c5cb2
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/dev/hfa/fore_output.c,v 1.5 2000/01/15 21:01:04 mks Exp $
27 * @(#) $DragonFly: src/sys/dev/atm/hfa/fore_output.c,v 1.6 2008/03/01 22:03:13 swildner Exp $
31 * FORE Systems 200-Series Adapter Support
32 * ---------------------------------------
34 * PDU output processing
38 #include "fore_include.h"
41 * Local functions
43 static KBuffer * fore_xmit_segment (Fore_unit *, KBuffer *,
44 H_xmit_queue *, int *, int *);
45 static void fore_seg_dma_free (H_xmit_queue *, KBuffer *, int);
49 * Output a PDU
51 * This function is called via the common driver code after receiving a
52 * stack *_DATA* command. The common code has already validated most of
53 * the request so we just need to check a few more Fore-specific details.
54 * Then we just build a transmit descriptor request for the PDU and issue
55 * the command to the CP.
57 * Arguments:
58 * cup pointer to device common unit
59 * cvp pointer to common VCC entry
60 * m pointer to output PDU buffer chain head
62 * Returns:
63 * none
66 void
67 fore_output(Cmn_unit *cup, Cmn_vcc *cvp, KBuffer *m)
69 Fore_unit *fup = (Fore_unit *)cup;
70 Fore_vcc *fvp = (Fore_vcc *)cvp;
71 struct vccb *vcp;
72 H_xmit_queue *hxp;
73 Xmit_queue *cqp;
74 Xmit_descr *xdp;
75 int retry, nsegs, pdulen;
77 #ifdef DIAGNOSTIC
78 if (atm_dev_print)
79 atm_dev_pdu_print(cup, cvp, m, "fore_output");
80 #endif
82 vcp = fvp->fv_connvc->cvc_vcc;
85 * If we're still waiting for activation to finish, delay for
86 * a little while before we toss the PDU
88 if (fvp->fv_state == CVS_INITED) {
89 retry = 3;
90 while (retry-- && (fvp->fv_state == CVS_INITED))
91 DELAY(1000);
92 if (fvp->fv_state != CVS_ACTIVE) {
94 * Activation still hasn't finished, oh well....
96 fup->fu_stats->st_drv.drv_xm_notact++;
97 vcp->vc_oerrors++;
98 if (vcp->vc_nif)
99 vcp->vc_nif->nif_if.if_oerrors++;
100 KB_FREEALL(m);
101 return;
106 * Queue PDU at end of transmit queue
108 * If queue is full we'll delay a bit before tossing the PDU
110 crit_enter();
111 hxp = fup->fu_xmit_tail;
112 if (!((*hxp->hxq_status) & QSTAT_FREE)) {
114 fup->fu_stats->st_drv.drv_xm_full++;
115 retry = 3;
116 do {
117 DELAY(1000);
119 DEVICE_LOCK((Cmn_unit *)fup);
120 fore_xmit_drain(fup);
121 DEVICE_UNLOCK((Cmn_unit *)fup);
123 } while (--retry && (!((*hxp->hxq_status) & QSTAT_FREE)));
125 if (!((*hxp->hxq_status) & QSTAT_FREE)) {
127 * Queue is still full, bye-bye PDU
129 fup->fu_pif.pif_oerrors++;
130 vcp->vc_oerrors++;
131 if (vcp->vc_nif)
132 vcp->vc_nif->nif_if.if_oerrors++;
133 KB_FREEALL(m);
134 crit_exit();
135 return;
140 * We've got a free transmit queue entry
144 * Now build the transmit segment descriptors for this PDU
146 m = fore_xmit_segment(fup, m, hxp, &nsegs, &pdulen);
147 if (m == NULL) {
149 * The build failed, buffer chain has been freed
151 vcp->vc_oerrors++;
152 if (vcp->vc_nif)
153 vcp->vc_nif->nif_if.if_oerrors++;
154 crit_exit();
155 return;
159 * Set up the descriptor header
161 xdp = hxp->hxq_descr;
162 xdp->xd_cell_hdr = ATM_HDR_SET(vcp->vc_vpi, vcp->vc_vci, 0, 0);
163 xdp->xd_spec = XDS_SET_SPEC(0, fvp->fv_aal, nsegs, pdulen);
164 xdp->xd_rate = FORE_DEF_RATE;
167 * Everything is ready to go, so officially claim the host queue
168 * entry and setup the CP-resident queue entry. The CP will grab
169 * the PDU when the descriptor pointer is set.
171 fup->fu_xmit_tail = hxp->hxq_next;
172 hxp->hxq_buf = m;
173 hxp->hxq_vcc = fvp;
174 (*hxp->hxq_status) = QSTAT_PENDING;
175 cqp = hxp->hxq_cpelem;
176 cqp->cq_descr = (CP_dma)
177 CP_WRITE((u_long)hxp->hxq_descr_dma | XMIT_SEGS_TO_BLKS(nsegs));
179 crit_exit();
182 * See if there are any completed queue entries
184 DEVICE_LOCK((Cmn_unit *)fup);
185 fore_xmit_drain(fup);
186 DEVICE_UNLOCK((Cmn_unit *)fup);
191 * Build Transmit Segment Descriptors
193 * This function will take a supplied buffer chain of data to be transmitted
194 * and build the transmit segment descriptors for the data. This will include
195 * the dreaded operation of ensuring that the data for each transmit segment
196 * is full-word aligned and (except for the last segment) is an integral number
197 * of words in length. If the data isn't already aligned and sized as
198 * required, then the data must be shifted (copied) into place - a sure
199 * performance killer. Note that we rely on the fact that all buffer data
200 * areas are allocated with (at least) full-word alignments/lengths.
202 * If any errors are encountered, the buffer chain will be freed.
204 * Arguments:
205 * fup pointer to device unit
206 * m pointer to output PDU buffer chain head
207 * hxp pointer to host transmit queue entry
208 * segp pointer to return the number of transmit segments
209 * lenp pointer to return the pdu length
211 * Returns:
212 * m build successful, pointer to (possibly new) head of
213 * output PDU buffer chain
214 * NULL build failed, buffer chain freed
217 static KBuffer *
218 fore_xmit_segment(Fore_unit *fup, KBuffer *m, H_xmit_queue *hxp, int *segp,
219 int *lenp)
221 Xmit_descr *xdp = hxp->hxq_descr;
222 Xmit_seg_descr *xsp;
223 H_dma *sdmap;
224 KBuffer *m0, *m1, *mprev;
225 caddr_t cp, bfr;
226 void *dma;
227 int pdulen, nsegs, len, align;
228 int compressed = 0;
230 m0 = m;
232 retry:
233 xsp = xdp->xd_seg;
234 sdmap = hxp->hxq_dma;
235 mprev = NULL;
236 pdulen = 0;
237 nsegs = 0;
240 * Loop thru each buffer in the chain, performing the necessary
241 * data positioning and then building a segment descriptor for
242 * that data.
244 while (m) {
246 * Get rid of any zero-length buffers
248 if (KB_LEN(m) == 0) {
249 if (mprev) {
250 KB_UNLINK(m, mprev, m1);
251 } else {
252 KB_UNLINKHEAD(m, m1);
253 m0 = m1;
255 m = m1;
256 continue;
260 * Make sure we don't try to use too many segments
262 if (nsegs >= XMIT_MAX_SEGS) {
264 * First, free already allocated DMA addresses
266 fore_seg_dma_free(hxp, m0, nsegs);
269 * Try to compress buffer chain (but only once)
271 if (compressed) {
272 KB_FREEALL(m0);
273 return (NULL);
276 fup->fu_stats->st_drv.drv_xm_maxpdu++;
278 m = atm_dev_compress(m0);
279 if (m == NULL) {
280 return (NULL);
284 * Build segment descriptors for compressed chain
286 m0 = m;
287 compressed = 1;
288 goto retry;
292 * Get start of data onto full-word alignment
294 KB_DATASTART(m, cp, caddr_t);
295 if ((align = ((u_int)cp) & (XMIT_SEG_ALIGN - 1)) != 0) {
297 * Gotta slide the data up
299 fup->fu_stats->st_drv.drv_xm_segnoal++;
300 bfr = cp - align;
301 KM_COPY(cp, bfr, KB_LEN(m));
302 KB_HEADMOVE(m, -align);
303 } else {
305 * Data already aligned
307 bfr = cp;
311 * Now work on getting the data length correct
313 len = KB_LEN(m);
314 while ((align = (len & (XMIT_SEG_ALIGN - 1))) &&
315 (m1 = KB_NEXT(m))) {
318 * Have to move some data from following buffer(s)
319 * to word-fill this buffer
321 int ncopy = MIN(XMIT_SEG_ALIGN - align, KB_LEN(m1));
323 if (ncopy) {
325 * Move data to current buffer
327 caddr_t dest;
329 fup->fu_stats->st_drv.drv_xm_seglen++;
330 KB_DATASTART(m1, cp, caddr_t);
331 dest = bfr + len;
332 KB_HEADADJ(m1, -ncopy);
333 KB_TAILADJ(m, ncopy);
334 len += ncopy;
335 while (ncopy--) {
336 *dest++ = *cp++;
341 * If we've drained the buffer, free it
343 if (KB_LEN(m1) == 0) {
344 KBuffer *m2;
346 KB_UNLINK(m1, m, m2);
351 * Finally, build the segment descriptor
355 * Round last segment to fullword length (if needed)
357 if (len & (XMIT_SEG_ALIGN - 1))
358 xsp->xsd_len = KB_LEN(m) =
359 (len + XMIT_SEG_ALIGN) & ~(XMIT_SEG_ALIGN - 1);
360 else
361 xsp->xsd_len = KB_LEN(m) = len;
364 * Get a DMA address for the data
366 dma = DMA_GET_ADDR(bfr, xsp->xsd_len, XMIT_SEG_ALIGN, 0);
367 if (dma == NULL) {
368 fup->fu_stats->st_drv.drv_xm_segdma++;
369 fore_seg_dma_free(hxp, m0, nsegs);
370 KB_FREEALL(m0);
371 return (NULL);
375 * Now we're really ready to call it a segment
377 *sdmap++ = xsp->xsd_buffer = (H_dma) dma;
380 * Bump counters and get ready for next buffer
382 pdulen += len;
383 nsegs++;
384 xsp++;
385 mprev = m;
386 m = KB_NEXT(m);
390 * Validate PDU length
392 if (pdulen > XMIT_MAX_PDULEN) {
393 fup->fu_stats->st_drv.drv_xm_maxpdu++;
394 fore_seg_dma_free(hxp, m0, nsegs);
395 KB_FREEALL(m0);
396 return (NULL);
400 * Return the good news to the caller
402 *segp = nsegs;
403 *lenp = pdulen;
405 return (m0);
410 * Free Transmit Segment Queue DMA addresses
412 * Arguments:
413 * hxp pointer to host transmit queue entry
414 * m0 pointer to output PDU buffer chain head
415 * nsegs number of processed transmit segments
417 * Returns:
418 * none
421 static void
422 fore_seg_dma_free(H_xmit_queue *hxp, KBuffer *m0, int nsegs)
424 KBuffer *m = m0;
425 H_dma *sdmap = hxp->hxq_dma;
426 caddr_t cp;
427 int i;
429 for (i = 0; i < nsegs; i++) {
430 KB_DATASTART(m, cp, caddr_t);
431 DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);
432 m = KB_NEXT(m);
433 sdmap++;