diff options
Diffstat (limited to 'sys/dev/hfa/fore_transmit.c')
-rw-r--r-- | sys/dev/hfa/fore_transmit.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/sys/dev/hfa/fore_transmit.c b/sys/dev/hfa/fore_transmit.c new file mode 100644 index 000000000000..744e7751c756 --- /dev/null +++ b/sys/dev/hfa/fore_transmit.c @@ -0,0 +1,371 @@ +/* + * + * =================================== + * HARP | Host ATM Research Platform + * =================================== + * + * + * This Host ATM Research Platform ("HARP") file (the "Software") is + * made available by Network Computing Services, Inc. ("NetworkCS") + * "AS IS". NetworkCS does not provide maintenance, improvements or + * support of any kind. + * + * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, + * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE + * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. + * In no event shall NetworkCS be responsible for any damages, including + * but not limited to consequential damages, arising from or relating to + * any use of the Software or related support. + * + * Copyright 1994-1998 Network Computing Services, Inc. + * + * Copies of this Software may be made, however, the above copyright + * notice must be reproduced on all copies. + * + * @(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Transmit queue management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Allocate Transmit Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 allocations successful + * else allocation failed + */ +int +fore_xmit_allocate(fup) + Fore_unit *fup; +{ + void *memp; + H_xmit_queue *hxp; + int i; + + /* + * Allocate non-cacheable memory for transmit status words + */ + memp = atm_dev_alloc(sizeof(Q_status) * XMIT_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_xmit_stat = (Q_status *) memp; + + memp = DMA_GET_ADDR(fup->fu_xmit_stat, sizeof(Q_status) * XMIT_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_xmit_statd = (Q_status *) memp; + + /* + * Allocate memory for transmit descriptors + * + * We will allocate the transmit descriptors individually rather than + * as a single memory block, which will often be larger than a memory + * page. On some systems (eg. FreeBSD) the physical addresses of + * adjacent virtual memory pages are not contiguous. + */ + hxp = fup->fu_xmit_q; + for (i = 0; i < XMIT_QUELEN; i++, hxp++) { + + /* + * Allocate a transmit descriptor for this queue entry + */ + hxp->hxq_descr = atm_dev_alloc(sizeof(Xmit_descr), + XMIT_DESCR_ALIGN, 0); + if (hxp->hxq_descr == NULL) { + return (1); + } + + hxp->hxq_descr_dma = DMA_GET_ADDR(hxp->hxq_descr, + sizeof(Xmit_descr), XMIT_DESCR_ALIGN, 0); + if (hxp->hxq_descr_dma == NULL) { + return (1); + } + } + + return (0); +} + + +/* + * Transmit Queue Initialization + * + * Allocate and initialize the host-resident transmit queue structures + * and then initialize the CP-resident queue structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_initialize(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + Xmit_queue *cqp; + H_xmit_queue *hxp; + Q_status *qsp; + Q_status *qsp_dma; + int i; + + /* + * Point to CP-resident transmit queue + */ + cqp = (Xmit_queue *)(fup->fu_ram + CP_READ(aap->aali_xmit_q)); + + /* + * Point to host-resident transmit queue structures + */ + hxp = fup->fu_xmit_q; + qsp = fup->fu_xmit_stat; + qsp_dma = fup->fu_xmit_statd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < XMIT_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hxp->hxq_cpelem = cqp; + hxp->hxq_status = qsp; + if (i == (XMIT_QUELEN - 1)) + hxp->hxq_next = fup->fu_xmit_q; + else + hxp->hxq_next = hxp + 1; + + /* + * Now let the CP into the game + */ + cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hxp++; + qsp++; + qsp_dma++; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_xmit_head = fup->fu_xmit_tail = fup->fu_xmit_q; + + return; +} + + +/* + * Drain Transmit Queue + * + * This function will free all completed entries at the head of the + * transmit queue. Freeing the entry includes releasing the transmit + * buffers (buffer chain) back to the kernel. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_drain(fup) + Fore_unit *fup; +{ + H_xmit_queue *hxp; + H_dma *sdmap; + Fore_vcc *fvp; + struct vccb *vcp; + KBuffer *m; + + /* + * Process each completed entry + */ + while (*fup->fu_xmit_head->hxq_status & QSTAT_COMPLETED) { + + hxp = fup->fu_xmit_head; + + /* + * Release the entry's DMA addresses and buffer chain + */ + for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m; + m = KB_NEXT(m), sdmap++) { + caddr_t cp; + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0); + } + KB_FREEALL(hxp->hxq_buf); + + /* + * Get VCC over which data was sent (may be null if + * VCC has been closed in the meantime) + */ + fvp = hxp->hxq_vcc; + + /* + * Now collect some statistics + */ + if (*hxp->hxq_status & QSTAT_ERROR) { + /* + * CP ran into problems, not much we can do + * other than record the event + */ + fup->fu_pif.pif_oerrors++; + if (fvp) { + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_oerrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_oerrors++; + } + } else { + /* + * Good transmission + */ + int len = XDS_GET_LEN(hxp->hxq_descr->xd_spec); + + fup->fu_pif.pif_opdus++; + fup->fu_pif.pif_obytes += len; + if (fvp) { + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_opdus++; + vcp->vc_obytes += len; + if (vcp->vc_nif) { + vcp->vc_nif->nif_obytes += len; + vcp->vc_nif->nif_if.if_opackets++; +#if (defined(BSD) && (BSD >= 199103)) + vcp->vc_nif->nif_if.if_obytes += len; +#endif + } + } + } + + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hxp->hxq_status = QSTAT_FREE; + fup->fu_xmit_head = hxp->hxq_next; + } + + return; +} + + +/* + * Free Transmit Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_free(fup) + Fore_unit *fup; +{ + H_xmit_queue *hxp; + H_dma *sdmap; + KBuffer *m; + int i; + + /* + * Free any transmit buffers left on the queue + */ + if (fup->fu_flags & CUF_INITED) { + while (*fup->fu_xmit_head->hxq_status != QSTAT_FREE) { + + hxp = fup->fu_xmit_head; + + /* + * Release the entry's DMA addresses and buffer chain + */ + for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m; + m = KB_NEXT(m), sdmap++) { + caddr_t cp; + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0); + } + KB_FREEALL(hxp->hxq_buf); + + *hxp->hxq_status = QSTAT_FREE; + fup->fu_xmit_head = hxp->hxq_next; + } + } + + /* + * Free the status words + */ + if (fup->fu_xmit_stat) { + if (fup->fu_xmit_statd) { + DMA_FREE_ADDR(fup->fu_xmit_stat, fup->fu_xmit_statd, + sizeof(Q_status) * XMIT_QUELEN, + ATM_DEV_NONCACHE); + } + atm_dev_free((void *)fup->fu_xmit_stat); + fup->fu_xmit_stat = NULL; + fup->fu_xmit_statd = NULL; + } + + /* + * Free the transmit descriptors + */ + hxp = fup->fu_xmit_q; + for (i = 0; i < XMIT_QUELEN; i++, hxp++) { + + /* + * Free the transmit descriptor for this queue entry + */ + if (hxp->hxq_descr_dma) { + DMA_FREE_ADDR(hxp->hxq_descr, hxp->hxq_descr_dma, + sizeof(Xmit_descr), 0); + hxp->hxq_descr_dma = NULL; + } + + if (hxp->hxq_descr) { + atm_dev_free(hxp->hxq_descr); + hxp->hxq_descr = NULL; + } + } + + return; +} + |