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 $
31 * FORE Systems 200-Series Adapter Support
32 * ---------------------------------------
34 * PDU output processing
38 #include <dev/hfa/fore_include.h>
41 __RCSID("@(#) $FreeBSD: src/sys/dev/hfa/fore_output.c,v 1.5 2000/01/15 21:01:04 mks Exp $");
48 static KBuffer * fore_xmit_segment __P((Fore_unit *, KBuffer *,
49 H_xmit_queue *, int *, int *));
50 static void fore_seg_dma_free __P((H_xmit_queue *, KBuffer *, int));
56 * This function is called via the common driver code after receiving a
57 * stack *_DATA* command. The common code has already validated most of
58 * the request so we just need to check a few more Fore-specific details.
59 * Then we just build a transmit descriptor request for the PDU and issue
60 * the command to the CP.
63 * cup pointer to device common unit
64 * cvp pointer to common VCC entry
65 * m pointer to output PDU buffer chain head
72 fore_output(cup, cvp, m)
77 Fore_unit *fup = (Fore_unit *)cup;
78 Fore_vcc *fvp = (Fore_vcc *)cvp;
83 int retry, nsegs, pdulen;
88 atm_dev_pdu_print(cup, cvp, m, "fore_output");
91 vcp = fvp->fv_connvc->cvc_vcc;
94 * If we're still waiting for activation to finish, delay for
95 * a little while before we toss the PDU
97 if (fvp->fv_state == CVS_INITED) {
99 while (retry-- && (fvp->fv_state == CVS_INITED))
101 if (fvp->fv_state != CVS_ACTIVE) {
103 * Activation still hasn't finished, oh well....
105 fup->fu_stats->st_drv.drv_xm_notact++;
108 vcp->vc_nif->nif_if.if_oerrors++;
115 * Queue PDU at end of transmit queue
117 * If queue is full we'll delay a bit before tossing the PDU
120 hxp = fup->fu_xmit_tail;
121 if (!((*hxp->hxq_status) & QSTAT_FREE)) {
123 fup->fu_stats->st_drv.drv_xm_full++;
128 DEVICE_LOCK((Cmn_unit *)fup);
129 fore_xmit_drain(fup);
130 DEVICE_UNLOCK((Cmn_unit *)fup);
132 } while (--retry && (!((*hxp->hxq_status) & QSTAT_FREE)));
134 if (!((*hxp->hxq_status) & QSTAT_FREE)) {
136 * Queue is still full, bye-bye PDU
138 fup->fu_pif.pif_oerrors++;
141 vcp->vc_nif->nif_if.if_oerrors++;
149 * We've got a free transmit queue entry
153 * Now build the transmit segment descriptors for this PDU
155 m = fore_xmit_segment(fup, m, hxp, &nsegs, &pdulen);
158 * The build failed, buffer chain has been freed
162 vcp->vc_nif->nif_if.if_oerrors++;
168 * Set up the descriptor header
170 xdp = hxp->hxq_descr;
171 xdp->xd_cell_hdr = ATM_HDR_SET(vcp->vc_vpi, vcp->vc_vci, 0, 0);
172 xdp->xd_spec = XDS_SET_SPEC(0, fvp->fv_aal, nsegs, pdulen);
173 xdp->xd_rate = FORE_DEF_RATE;
176 * Everything is ready to go, so officially claim the host queue
177 * entry and setup the CP-resident queue entry. The CP will grab
178 * the PDU when the descriptor pointer is set.
180 fup->fu_xmit_tail = hxp->hxq_next;
183 (*hxp->hxq_status) = QSTAT_PENDING;
184 cqp = hxp->hxq_cpelem;
185 cqp->cq_descr = (CP_dma)
186 CP_WRITE((u_long)hxp->hxq_descr_dma | XMIT_SEGS_TO_BLKS(nsegs));
191 * See if there are any completed queue entries
193 DEVICE_LOCK((Cmn_unit *)fup);
194 fore_xmit_drain(fup);
195 DEVICE_UNLOCK((Cmn_unit *)fup);
202 * Build Transmit Segment Descriptors
204 * This function will take a supplied buffer chain of data to be transmitted
205 * and build the transmit segment descriptors for the data. This will include
206 * the dreaded operation of ensuring that the data for each transmit segment
207 * is full-word aligned and (except for the last segment) is an integral number
208 * of words in length. If the data isn't already aligned and sized as
209 * required, then the data must be shifted (copied) into place - a sure
210 * performance killer. Note that we rely on the fact that all buffer data
211 * areas are allocated with (at least) full-word alignments/lengths.
213 * If any errors are encountered, the buffer chain will be freed.
216 * fup pointer to device unit
217 * m pointer to output PDU buffer chain head
218 * hxp pointer to host transmit queue entry
219 * segp pointer to return the number of transmit segments
220 * lenp pointer to return the pdu length
223 * m build successful, pointer to (possibly new) head of
224 * output PDU buffer chain
225 * NULL build failed, buffer chain freed
229 fore_xmit_segment(fup, m, hxp, segp, lenp)
236 Xmit_descr *xdp = hxp->hxq_descr;
239 KBuffer *m0, *m1, *mprev;
242 int pdulen, nsegs, len, align;
249 sdmap = hxp->hxq_dma;
255 * Loop thru each buffer in the chain, performing the necessary
256 * data positioning and then building a segment descriptor for
261 * Get rid of any zero-length buffers
263 if (KB_LEN(m) == 0) {
265 KB_UNLINK(m, mprev, m1);
267 KB_UNLINKHEAD(m, m1);
275 * Make sure we don't try to use too many segments
277 if (nsegs >= XMIT_MAX_SEGS) {
279 * First, free already allocated DMA addresses
281 fore_seg_dma_free(hxp, m0, nsegs);
284 * Try to compress buffer chain (but only once)
291 fup->fu_stats->st_drv.drv_xm_maxpdu++;
293 m = atm_dev_compress(m0);
299 * Build segment descriptors for compressed chain
307 * Get start of data onto full-word alignment
309 KB_DATASTART(m, cp, caddr_t);
310 if ((align = ((u_int)cp) & (XMIT_SEG_ALIGN - 1)) != 0) {
312 * Gotta slide the data up
314 fup->fu_stats->st_drv.drv_xm_segnoal++;
316 KM_COPY(cp, bfr, KB_LEN(m));
317 KB_HEADMOVE(m, -align);
320 * Data already aligned
326 * Now work on getting the data length correct
329 while ((align = (len & (XMIT_SEG_ALIGN - 1))) &&
333 * Have to move some data from following buffer(s)
334 * to word-fill this buffer
336 int ncopy = MIN(XMIT_SEG_ALIGN - align, KB_LEN(m1));
340 * Move data to current buffer
344 fup->fu_stats->st_drv.drv_xm_seglen++;
345 KB_DATASTART(m1, cp, caddr_t);
347 KB_HEADADJ(m1, -ncopy);
348 KB_TAILADJ(m, ncopy);
356 * If we've drained the buffer, free it
358 if (KB_LEN(m1) == 0) {
361 KB_UNLINK(m1, m, m2);
366 * Finally, build the segment descriptor
370 * Round last segment to fullword length (if needed)
372 if (len & (XMIT_SEG_ALIGN - 1))
373 xsp->xsd_len = KB_LEN(m) =
374 (len + XMIT_SEG_ALIGN) & ~(XMIT_SEG_ALIGN - 1);
376 xsp->xsd_len = KB_LEN(m) = len;
379 * Get a DMA address for the data
381 dma = DMA_GET_ADDR(bfr, xsp->xsd_len, XMIT_SEG_ALIGN, 0);
383 fup->fu_stats->st_drv.drv_xm_segdma++;
384 fore_seg_dma_free(hxp, m0, nsegs);
390 * Now we're really ready to call it a segment
392 *sdmap++ = xsp->xsd_buffer = (H_dma) dma;
395 * Bump counters and get ready for next buffer
405 * Validate PDU length
407 if (pdulen > XMIT_MAX_PDULEN) {
408 fup->fu_stats->st_drv.drv_xm_maxpdu++;
409 fore_seg_dma_free(hxp, m0, nsegs);
415 * Return the good news to the caller
425 * Free Transmit Segment Queue DMA addresses
428 * hxp pointer to host transmit queue entry
429 * m0 pointer to output PDU buffer chain head
430 * nsegs number of processed transmit segments
437 fore_seg_dma_free(hxp, m0, nsegs)
443 H_dma *sdmap = hxp->hxq_dma;
447 for (i = 0; i < nsegs; i++) {
448 KB_DATASTART(m, cp, caddr_t);
449 DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0);