freebsd-skq/sys/dev/hfa/fore_buffer.c
Poul-Henning Kamp 1820df7a2d Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc.
This software was developed with the support of the Defense Advanced
Research Projects Agency (DARPA).
1998-09-15 08:23:17 +00:00

773 lines
16 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.
*
* @(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $
*
*/
/*
* FORE Systems 200-Series Adapter Support
* ---------------------------------------
*
* Buffer Supply queue management
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $";
#endif
#include <dev/hfa/fore_include.h>
/*
* Local functions
*/
static void fore_buf_drain __P((Fore_unit *));
static void fore_buf_supply_1s __P((Fore_unit *));
static void fore_buf_supply_1l __P((Fore_unit *));
/*
* Allocate Buffer Supply Queues Data Structures
*
* Here we are allocating memory for both Strategy 1 Small and Large
* structures contiguously.
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* 0 allocations successful
* else allocation failed
*/
int
fore_buf_allocate(fup)
Fore_unit *fup;
{
caddr_t memp;
/*
* Allocate non-cacheable memory for buffer supply status words
*/
memp = atm_dev_alloc(
sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
QSTAT_ALIGN, ATM_DEV_NONCACHE);
if (memp == NULL) {
return (1);
}
fup->fu_buf1s_stat = (Q_status *) memp;
fup->fu_buf1l_stat = ((Q_status *) memp) + BUF1_SM_QUELEN;
memp = DMA_GET_ADDR(fup->fu_buf1s_stat,
sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN),
QSTAT_ALIGN, ATM_DEV_NONCACHE);
if (memp == NULL) {
return (1);
}
fup->fu_buf1s_statd = (Q_status *) memp;
fup->fu_buf1l_statd = ((Q_status *) memp) + BUF1_SM_QUELEN;
/*
* Allocate memory for buffer supply descriptors
*/
memp = atm_dev_alloc(sizeof(Buf_descr) *
((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
(BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
BUF_DESCR_ALIGN, 0);
if (memp == NULL) {
return (1);
}
fup->fu_buf1s_desc = (Buf_descr *) memp;
fup->fu_buf1l_desc = ((Buf_descr *) memp) +
(BUF1_SM_QUELEN * BUF1_SM_ENTSIZE);
memp = DMA_GET_ADDR(fup->fu_buf1s_desc, sizeof(Buf_descr) *
((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
(BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
BUF_DESCR_ALIGN, 0);
if (memp == NULL) {
return (1);
}
fup->fu_buf1s_descd = (Buf_descr *) memp;
fup->fu_buf1l_descd = ((Buf_descr *) memp) +
(BUF1_SM_QUELEN * BUF1_SM_ENTSIZE);
return (0);
}
/*
* Buffer Supply Queues Initialization
*
* Allocate and initialize the host-resident buffer supply 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_buf_initialize(fup)
Fore_unit *fup;
{
Aali *aap = fup->fu_aali;
Buf_queue *cqp;
H_buf_queue *hbp;
Buf_descr *bdp;
Buf_descr *bdp_dma;
Q_status *qsp;
Q_status *qsp_dma;
int i;
/*
* Initialize Strategy 1 Small Queues
*/
/*
* Point to CP-resident buffer supply queue
*/
cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1s_q));
/*
* Point to host-resident buffer supply queue structures
*/
hbp = fup->fu_buf1s_q;
qsp = fup->fu_buf1s_stat;
qsp_dma = fup->fu_buf1s_statd;
bdp = fup->fu_buf1s_desc;
bdp_dma = fup->fu_buf1s_descd;
/*
* Loop thru all queue entries and do whatever needs doing
*/
for (i = 0; i < BUF1_SM_QUELEN; i++) {
/*
* Set queue status word to free
*/
*qsp = QSTAT_FREE;
/*
* Set up host queue entry and link into ring
*/
hbp->hbq_cpelem = cqp;
hbp->hbq_status = qsp;
hbp->hbq_descr = bdp;
hbp->hbq_descr_dma = bdp_dma;
if (i == (BUF1_SM_QUELEN - 1))
hbp->hbq_next = fup->fu_buf1s_q;
else
hbp->hbq_next = hbp + 1;
/*
* Now let the CP into the game
*/
cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
/*
* Bump all queue pointers
*/
hbp++;
qsp++;
qsp_dma++;
bdp += BUF1_SM_ENTSIZE;
bdp_dma += BUF1_SM_ENTSIZE;
cqp++;
}
/*
* Initialize queue pointers
*/
fup->fu_buf1s_head = fup->fu_buf1s_tail = fup->fu_buf1s_q;
/*
* Initialize Strategy 1 Large Queues
*/
/*
* Point to CP-resident buffer supply queue
*/
cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1l_q));
/*
* Point to host-resident buffer supply queue structures
*/
hbp = fup->fu_buf1l_q;
qsp = fup->fu_buf1l_stat;
qsp_dma = fup->fu_buf1l_statd;
bdp = fup->fu_buf1l_desc;
bdp_dma = fup->fu_buf1l_descd;
/*
* Loop thru all queue entries and do whatever needs doing
*/
for (i = 0; i < BUF1_LG_QUELEN; i++) {
/*
* Set queue status word to free
*/
*qsp = QSTAT_FREE;
/*
* Set up host queue entry and link into ring
*/
hbp->hbq_cpelem = cqp;
hbp->hbq_status = qsp;
hbp->hbq_descr = bdp;
hbp->hbq_descr_dma = bdp_dma;
if (i == (BUF1_LG_QUELEN - 1))
hbp->hbq_next = fup->fu_buf1l_q;
else
hbp->hbq_next = hbp + 1;
/*
* Now let the CP into the game
*/
cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma);
/*
* Bump all queue pointers
*/
hbp++;
qsp++;
qsp_dma++;
bdp += BUF1_LG_ENTSIZE;
bdp_dma += BUF1_LG_ENTSIZE;
cqp++;
}
/*
* Initialize queue pointers
*/
fup->fu_buf1l_head = fup->fu_buf1l_tail = fup->fu_buf1l_q;
return;
}
/*
* Supply Buffers to CP
*
* This function will resupply the CP with buffers to be used to
* store incoming data.
*
* May be called in interrupt state.
* Must be called with interrupts locked out.
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* none
*/
void
fore_buf_supply(fup)
Fore_unit *fup;
{
/*
* First, clean out the supply queues
*/
fore_buf_drain(fup);
/*
* Then, supply the buffers for each queue
*/
fore_buf_supply_1s(fup);
fore_buf_supply_1l(fup);
return;
}
/*
* Supply Strategy 1 Small Buffers to CP
*
* May be called in interrupt state.
* Must be called with interrupts locked out.
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* none
*/
static void
fore_buf_supply_1s(fup)
Fore_unit *fup;
{
H_buf_queue *hbp;
Buf_queue *cqp;
Buf_descr *bdp;
Buf_handle *bhp;
KBuffer *m;
int nvcc, nbuf, i;
/*
* Figure out how many buffers we should be giving to the CP.
* We're basing this calculation on the current number of open
* VCCs thru this device, with certain minimum and maximum values
* enforced. This will then allow us to figure out how many more
* buffers we need to supply to the CP. This will be rounded up
* to fill a supply queue entry.
*/
nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
nbuf = nvcc * 4;
nbuf = MIN(nbuf, BUF1_SM_CPPOOL);
nbuf -= fup->fu_buf1s_cnt;
nbuf = roundup(nbuf, BUF1_SM_ENTSIZE);
/*
* OK, now supply the buffers to the CP
*/
while (nbuf > 0) {
/*
* Acquire a supply queue entry
*/
hbp = fup->fu_buf1s_tail;
if (!((*hbp->hbq_status) & QSTAT_FREE))
break;
bdp = hbp->hbq_descr;
/*
* Get a buffer for each descriptor in the queue entry
*/
for (i = 0; i < BUF1_SM_ENTSIZE; i++, bdp++) {
caddr_t cp;
/*
* Get a small buffer
*/
KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA);
if (m == 0) {
break;
}
KB_HEADSET(m, BUF1_SM_DOFF);
/*
* Point to buffer handle structure
*/
bhp = (Buf_handle *)((caddr_t)m + BUF1_SM_HOFF);
bhp->bh_type = BHT_S1_SMALL;
/*
* Setup buffer descriptor
*/
bdp->bsd_handle = bhp;
KB_DATASTART(m, cp, caddr_t);
bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR(
cp, BUF1_SM_SIZE, BUF_DATA_ALIGN, 0);
if (bdp->bsd_buffer == NULL) {
/*
* Unable to assign dma address - free up
* this descriptor's buffer
*/
fup->fu_stats->st_drv.drv_bf_segdma++;
KB_FREEALL(m);
break;
}
/*
* All set, so queue buffer (handle)
*/
ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
}
/*
* If we we're not able to fill all the descriptors for
* an entry, free up what's been partially built
*/
if (i != BUF1_SM_ENTSIZE) {
/*
* Clean up each used descriptor
*/
for (bdp = hbp->hbq_descr; i; i--, bdp++) {
bhp = bdp->bsd_handle;
DEQUEUE(bhp, Buf_handle, bh_qelem,
fup->fu_buf1s_bq);
m = (KBuffer *)
((caddr_t)bhp - BUF1_SM_HOFF);
KB_FREEALL(m);
}
break;
}
/*
* Finally, we've got an entry ready for the CP.
* So claim the host queue entry and setup the CP-resident
* queue entry. The CP will (potentially) grab the supplied
* buffers when the descriptor pointer is set.
*/
fup->fu_buf1s_tail = hbp->hbq_next;
(*hbp->hbq_status) = QSTAT_PENDING;
cqp = hbp->hbq_cpelem;
cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
/*
* Update counters, etc for supplied buffers
*/
fup->fu_buf1s_cnt += BUF1_SM_ENTSIZE;
nbuf -= BUF1_SM_ENTSIZE;
}
return;
}
/*
* Supply Strategy 1 Large Buffers to CP
*
* May be called in interrupt state.
* Must be called with interrupts locked out.
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* none
*/
static void
fore_buf_supply_1l(fup)
Fore_unit *fup;
{
H_buf_queue *hbp;
Buf_queue *cqp;
Buf_descr *bdp;
Buf_handle *bhp;
KBuffer *m;
int nvcc, nbuf, i;
/*
* Figure out how many buffers we should be giving to the CP.
* We're basing this calculation on the current number of open
* VCCs thru this device, with certain minimum and maximum values
* enforced. This will then allow us to figure out how many more
* buffers we need to supply to the CP. This will be rounded up
* to fill a supply queue entry.
*/
nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC);
nbuf = nvcc * 4 * RECV_MAX_SEGS;
nbuf = MIN(nbuf, BUF1_LG_CPPOOL);
nbuf -= fup->fu_buf1l_cnt;
nbuf = roundup(nbuf, BUF1_LG_ENTSIZE);
/*
* OK, now supply the buffers to the CP
*/
while (nbuf > 0) {
/*
* Acquire a supply queue entry
*/
hbp = fup->fu_buf1l_tail;
if (!((*hbp->hbq_status) & QSTAT_FREE))
break;
bdp = hbp->hbq_descr;
/*
* Get a buffer for each descriptor in the queue entry
*/
for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) {
caddr_t cp;
/*
* Get a cluster buffer
*/
KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA);
if (m == 0) {
break;
}
KB_HEADSET(m, BUF1_LG_DOFF);
/*
* Point to buffer handle structure
*/
bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF);
bhp->bh_type = BHT_S1_LARGE;
/*
* Setup buffer descriptor
*/
bdp->bsd_handle = bhp;
KB_DATASTART(m, cp, caddr_t);
bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR(
cp, BUF1_LG_SIZE, BUF_DATA_ALIGN, 0);
if (bdp->bsd_buffer == NULL) {
/*
* Unable to assign dma address - free up
* this descriptor's buffer
*/
fup->fu_stats->st_drv.drv_bf_segdma++;
KB_FREEALL(m);
break;
}
/*
* All set, so queue buffer (handle)
*/
ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
}
/*
* If we we're not able to fill all the descriptors for
* an entry, free up what's been partially built
*/
if (i != BUF1_LG_ENTSIZE) {
/*
* Clean up each used descriptor
*/
for (bdp = hbp->hbq_descr; i; i--, bdp++) {
bhp = bdp->bsd_handle;
DEQUEUE(bhp, Buf_handle, bh_qelem,
fup->fu_buf1l_bq);
m = (KBuffer *)
((caddr_t)bhp - BUF1_LG_HOFF);
KB_FREEALL(m);
}
break;
}
/*
* Finally, we've got an entry ready for the CP.
* So claim the host queue entry and setup the CP-resident
* queue entry. The CP will (potentially) grab the supplied
* buffers when the descriptor pointer is set.
*/
fup->fu_buf1l_tail = hbp->hbq_next;
(*hbp->hbq_status) = QSTAT_PENDING;
cqp = hbp->hbq_cpelem;
cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma);
/*
* Update counters, etc for supplied buffers
*/
fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE;
nbuf -= BUF1_LG_ENTSIZE;
}
return;
}
/*
* Drain Buffer Supply Queues
*
* This function will free all completed entries at the head of each
* buffer supply queue. Since we consider the CP to "own" the buffers
* once we put them on a supply queue and since a completed supply queue
* entry is only telling us that the CP has accepted the buffers that we
* gave to it, there's not much to do here.
*
* May be called in interrupt state.
* Must be called with interrupts locked out.
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* none
*/
static void
fore_buf_drain(fup)
Fore_unit *fup;
{
H_buf_queue *hbp;
/*
* Drain Strategy 1 Small Queue
*/
/*
* Process each completed entry
*/
while (*fup->fu_buf1s_head->hbq_status & QSTAT_COMPLETED) {
hbp = fup->fu_buf1s_head;
if (*hbp->hbq_status & QSTAT_ERROR) {
/*
* XXX - what does this mean???
*/
log(LOG_ERR, "fore_buf_drain: buf1s queue error\n");
}
/*
* Mark this entry free for use and bump head pointer
* to the next entry in the queue
*/
*hbp->hbq_status = QSTAT_FREE;
fup->fu_buf1s_head = hbp->hbq_next;
}
/*
* Drain Strategy 1 Large Queue
*/
/*
* Process each completed entry
*/
while (*fup->fu_buf1l_head->hbq_status & QSTAT_COMPLETED) {
hbp = fup->fu_buf1l_head;
if (*hbp->hbq_status & QSTAT_ERROR) {
/*
* XXX - what does this mean???
*/
log(LOG_ERR, "fore_buf_drain: buf1l queue error\n");
}
/*
* Mark this entry free for use and bump head pointer
* to the next entry in the queue
*/
*hbp->hbq_status = QSTAT_FREE;
fup->fu_buf1l_head = hbp->hbq_next;
}
return;
}
/*
* Free Buffer Supply Queue Data Structures
*
* Arguments:
* fup pointer to device unit structure
*
* Returns:
* none
*/
void
fore_buf_free(fup)
Fore_unit *fup;
{
Buf_handle *bhp;
KBuffer *m;
/*
* Free any previously supplied and not returned buffers
*/
if (fup->fu_flags & CUF_INITED) {
/*
* Run through Strategy 1 Small queue
*/
while (bhp = Q_HEAD(fup->fu_buf1s_bq, Buf_handle)) {
caddr_t cp;
/*
* Back off to buffer
*/
m = (KBuffer *)((caddr_t)bhp - BUF1_SM_HOFF);
/*
* Dequeue handle and free buffer
*/
DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq);
KB_DATASTART(m, cp, caddr_t);
DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0);
KB_FREEALL(m);
}
/*
* Run through Strategy 1 Large queue
*/
while (bhp = Q_HEAD(fup->fu_buf1l_bq, Buf_handle)) {
caddr_t cp;
/*
* Back off to buffer
*/
m = (KBuffer *)((caddr_t)bhp - BUF1_LG_HOFF);
/*
* Dequeue handle and free buffer
*/
DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq);
KB_DATASTART(m, cp, caddr_t);
DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0);
KB_FREEALL(m);
}
}
/*
* Free the status words
*/
if (fup->fu_buf1s_stat) {
if (fup->fu_buf1s_statd) {
DMA_FREE_ADDR(fup->fu_buf1s_stat, fup->fu_buf1s_statd,
sizeof(Q_status) *
(BUF1_SM_QUELEN + BUF1_LG_QUELEN),
ATM_DEV_NONCACHE);
}
atm_dev_free((void *)fup->fu_buf1s_stat);
fup->fu_buf1s_stat = NULL;
fup->fu_buf1s_statd = NULL;
fup->fu_buf1l_stat = NULL;
fup->fu_buf1l_statd = NULL;
}
/*
* Free the transmit descriptors
*/
if (fup->fu_buf1s_desc) {
if (fup->fu_buf1s_descd) {
DMA_FREE_ADDR(fup->fu_buf1s_desc, fup->fu_buf1s_descd,
sizeof(Buf_descr) *
((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) +
(BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)),
0);
}
atm_dev_free(fup->fu_buf1s_desc);
fup->fu_buf1s_desc = NULL;
fup->fu_buf1s_descd = NULL;
fup->fu_buf1l_desc = NULL;
fup->fu_buf1l_descd = NULL;
}
return;
}