372 lines
7.5 KiB
C
372 lines
7.5 KiB
C
/*
|
|
*
|
|
* ===================================
|
|
* 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.
|
|
*
|
|
* @(#) $FreeBSD$
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* FORE Systems 200-Series Adapter Support
|
|
* ---------------------------------------
|
|
*
|
|
* Transmit queue management
|
|
*
|
|
*/
|
|
|
|
#include <dev/hfa/fore_include.h>
|
|
|
|
#ifndef lint
|
|
__RCSID("@(#) $FreeBSD$");
|
|
#endif
|
|
|
|
|
|
/*
|
|
* 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((volatile 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;
|
|
}
|
|
|