📄 adi_ether_bf537.c
字号:
while (pnd) {
pnd->usage = Active;
pnd = pnd->pNext;
}
}
#endif
q->Pending = NULL;
CheckQueues(q);
}
//
// Queue Frames
// this function assumes that it is running within a critical region
//
static void QueueFrames(ADI_ETHER_BF537_DATA *dev, FRAME_QUEUE *q)
{
ADI_ETHER_BUFFER *lstpnd = q->Pending, *buf,*lstact,*nonact;
int no_needed;
BUFFER_INFO *bi,*bipend;
DMA_DESCRIPTOR *dmr,*lstdmr,*remdmr;
bool append=false;
int NoActive=0;
int i;
ADI_ETHER_BUFFER *iQ = q->Queued, *iQN=NULL, *iP= q->Pending,*iA = q->Active;
int iNoa = q->NoAvail;
int ists;
STATUS_AREA *sts;
CheckQueues(q);
// find the end of the pendinq queue
if (lstpnd) {
while (lstpnd->pNext != NULL) lstpnd = lstpnd->pNext;
}
// step through the queued allocating descriptors and appending then to the pending queue
buf = q->Queued;
while (buf!=NULL) {
no_needed = 2;
if ((q->Rcve == 0) && (buf->PayLoad != NULL)) {
no_needed = 3;
}
if ((no_needed > q->NoAvail) || (q->AvailStatus==NULL)) {
break;
}
if (((unsigned int)q->Avail)&3) {
int k=1;//##avail
}
dmr = q->Avail;
// update the CONFIG for the last descriptor to make it flow
if (lstpnd!=NULL) {
bi = (BUFFER_INFO *)lstpnd;
bi->Last->NEXT_DESC_PTR = dmr;
if (no_needed == 3) {
bi->Last->CONFIG &= 0xf0ff; // remove the current ndsize
bi->Last->CONFIG |= 0x7600; // or in flow as 7 and ndsize as 6
} else {
// the previous value will have been 8b
#ifdef USE_SYNC
bi->Last->CONFIG |= 0x7520; // or in flow as 7 and ndsize as 5 as SYNC
#else
bi->Last->CONFIG |= 0x7500; // or in flow as 7 and ndsize as 5
#endif
}
}
// layout the descriptors for the buffer
bi = (BUFFER_INFO *)buf;
bi->NoDesc = no_needed;
// set up the staus word area
bi->Status = sts = q->AvailStatus;
*((long long *)sts) = 0;
q->AvailStatus = sts->Next;
bi->First = dmr;
// dmr NEXT_DESC_PTR is already set
dmr->START_ADDR = (unsigned long)buf->Data;
dmr->X_COUNT = (no_needed==3?(buf->ElementCount*buf->ElementWidth+3)>>2:0);
if (q->Rcve == 0) {
// we need to set the length half word
unsigned short *lnth = (unsigned short *)buf->Data;
buf->ProcessedElementCount = (*lnth +2+buf->ElementWidth-1)/buf->ElementWidth;
if (no_needed == 3) {
// we need to get X_COUNT set to zero by next descriptor
#ifdef USE_SYNC
dmr->CONFIG = 0x7629; // flow=7,ndsize=6,wdsize=4,enable, mem read, use sync
#else
dmr->CONFIG = 0x7609; // flow=7,ndsize=6,wdsize=4,enable, mem read
#endif
} else {
#ifdef USE_SYNC
dmr->CONFIG = 0x7529; // flow=7,ndsize=5,wdsize=4,enable, mem read, use sync
#else
dmr->CONFIG = 0x7509; // flow=7,ndsize=5,wdsize=4,enable, mem read
#endif
}
} else {
#ifdef USE_SYNC
dmr->CONFIG = 0x752b; // flow=7,ndsize=5,wdsize=4,enable, mem write, use sync
#else
dmr->CONFIG = 0x750b; // flow=7,ndsize=5,wdsize=4,enable, mem write
#endif
}
FlushArea(&dmr,((char *)&dmr)+18);
dmr = dmr->NEXT_DESC_PTR;
if (no_needed == 3) {
// set up payload descriptor
dmr->START_ADDR = (unsigned long)buf->PayLoad;
#ifdef USE_SYNC
dmr->CONFIG = 0x7529; // flow=7,ndsize=5,wdsize=4,enable, mem read, use sync
#else
dmr->CONFIG = 0x7509; // flow=7,ndsize=5,wdsize=4,enable, mem read
#endif
dmr->X_COUNT = 0;
FlushArea(&dmr,((char *)&dmr)+18);
dmr = dmr->NEXT_DESC_PTR;
}
if (dev->Cache) {
char *data = (char *)buf->Data;
if (q->Rcve==0) {
// we need to flush the buffer
unsigned short lnth = *((unsigned short *)data);
if (no_needed == 3) {
// two data buffers
int no_bytes = buf->ElementCount*buf->ElementWidth;
FlushArea(data,data+no_bytes);
FlushArea(buf->PayLoad,((char *)buf->PayLoad)+lnth-no_bytes);
} else {
FlushArea(data,data+2+lnth);
}
} else {
// we need to invalidate the cache lines
FlushInvArea(data,data+MAX_RCVE_FRAME);
}
}
// now set the descriptor for the status word
#if 1
dmr->START_ADDR = ((q->Rcve!=0) && (dev->GenChksums!=0)?(unsigned long)&sts->IPHdrChksum:(unsigned long)&sts->StatusWord);
#else
dmr->START_ADDR = ((q->Rcve!=0) && (dev->GenChksums!=0)?(unsigned long)&buf->IPHdrChksum:(unsigned long)&buf->StatusWord);
#endif
// we also need to invalidate the status word space
SIMPLEFLUSHINV(sts); // flush and invalidate the staus owrr
// status word is always written
#ifdef USE_SYNC
dmr->CONFIG = 0x00AB; // flow=0,ndsize=0,wdsize=4,int enable, ensable, mem write, use sync
#else
dmr->CONFIG = 0x008B; // flow=0,ndsize=0,wdsize=4,int enable, ensable, mem write
#endif
bi->Last = dmr;
remdmr = dmr->NEXT_DESC_PTR;
// terminate the list of dmr's
dmr->NEXT_DESC_PTR = 0;
FlushArea(&dmr,((char *)&dmr)+18);
if (lstpnd == NULL) {
// form the pending queue
q->Pending = buf;
} else {
lstpnd->pNext = buf;
}
// update last pending buffer
lstpnd = buf;
#ifdef ADI_ETHER_BF537_DEBUG
buf->usage = Pending;
#endif
// step buf onto the next buffer if any in the queued queue
buf = buf->pNext;
// now terminate the pending queue
lstpnd->pNext = NULL;
q->NoAvail -= no_needed;
q->Avail = remdmr;
if (((unsigned int)q->Avail)&3) {
int k=1; //##avail
}
//## this only needed to allow CheckQueues to be invoked
q->Queued = buf; // remove frames from Queued list
CheckQueues(q);
//##
}
q->Queued = buf; // remove frames from Queued list
CheckQueues(q);
// check to see if there is anything in the pending queue
if (q->Pending) {
append = false;
// check to see if we have at least two uncompleted entries in active queue
NoActive = 0;
lstact = NULL;
buf = q->Active;
lstact = buf;
while (buf != NULL) {
lstact = buf;
bi = (BUFFER_INFO *)buf->Reserved;
sts = bi->Status;
SIMPLEFLUSHINV(sts); // flush and invalidate the status word
if ((sts->StatusWord&q->CompletedStatus)==0) {
NoActive++;
}
buf = buf->pNext;
}
CheckQueues(q);
if ((NoActive>=2) || (q->EnableMac!=0)) {
// if two non completed frames or DMA not yet started
CheckQueues(q);
AppendPending(q,lstact);
CheckQueues(q);
}
CheckQueues(q);
// check to see if the DMA is running
if (q->Dma == NULL) {
q->Dma = (DMA_REGISTERS *)(DMA0_NEXT_DESC_PTR+0x40*q->Channel);
//q->Dma->CONFIG = 0;
q->Dma->X_COUNT = 0;
q->Dma->X_MODIFY = 4;
}
iP = q->Pending; iA = q->Active;
ists = (q->Dma != NULL?q->Dma->IRQ_STATUS: -1);
if ((q->Dma != NULL) && ((q->Dma->IRQ_STATUS &0x8) == 0)) {
// DMA assigned but not running
// anything in the pending queue
if (q->Pending) {
AppendPending(q,lstact);
}
// start the DMA if anything in the active queue
nonact = q->Active;
while (nonact!=NULL) {
bi = (BUFFER_INFO *)nonact->Reserved;
sts = bi->Status;
SIMPLEFLUSHINV(sts); // flush and invalidate the status word
if ((sts->StatusWord&q->CompletedStatus)!=0) {
nonact = nonact->pNext;
} else {
break;
}
}
if (nonact) {
if (q->Rcve==0) {
NoTxStarts++;
} else {
NoRxStarts++;
}
// we need to trigger the DMA
bi = (BUFFER_INFO *)nonact;
q->Enabled = true;
q->Dma->NEXT_DESC_PTR = bi->First;
q->Dma->CONFIG = bi->First->CONFIG;
// now the DMA is running, we can enable the MAC
if (q->EnableMac!=0) {
u32 opmode = *pEMAC_OPMODE|q->EnableMac;
*pEMAC_OPMODE = opmode;
q->EnableMac = 0;
}
}
} else {
if (q->Rcve==0) {
int sts = q->Dma->IRQ_STATUS;
int k=2;
}
}
}
CheckQueues(q);
}
//
// Process DMA completion
//
static ADI_INT_HANDLER_RESULT ProcessCompletion(ADI_ETHER_BF537_DATA *dev, FRAME_QUEUE *q)
{
ADI_INT_HANDLER_RESULT result = ADI_INT_RESULT_NOT_PROCESSED;
ADI_ETHER_BUFFER *act,*lst,*fst;
BUFFER_INFO *bi;
int noposted=0;
STATUS_AREA *sts;
void *xit = EnterCriticalRegion(NULL);
breakpoint(2);
CheckQueues(q);
if (q->Dma->IRQ_STATUS&0x01) {
// interrupt asserted
result = ADI_INT_RESULT_PROCESSED;
// acknowedge the interrupt
q->Dma->IRQ_STATUS = 0x01;
if (q->Rcve) {
NoRxInts++;
} else {
NoTxInts++;
}
}
// check to see if any frames have completed
fst = act = q->Active;
lst = NULL;
while (act!=NULL) {
bi = (BUFFER_INFO *)act->Reserved;
sts = bi->Status;
SIMPLEFLUSHINV(sts); // flush and invalidate the status word
if ((sts->StatusWord&q->CompletedStatus)==0) break;
noposted++;
*((long long *)&act->IPHdrChksum) = *((long long *)sts);
// we can add the used descriptors to the Avail queue
q->NoAvail += bi->NoDesc;
bi->Last->NEXT_DESC_PTR = q->Avail;
q->Avail = bi->First;
if (((unsigned int)q->Avail)&3) {
int k=1;//##avail
}
// return the status area
sts->Next = q->AvailStatus;
q->AvailStatus = sts;
#ifdef ADI_ETHER_BF537_DEBUG
act->usage = Completed;
#endif
act->ProcessedFlag = TRUE;
// we need to set the processed element count for a received frame
// in the case of a transmit it is set up before transmission
if (q->Rcve) {
int nobytes = act->StatusWord&0x7ff;
if (!dev->NoRcveLnth) {
ADI_ETHER_FRAME_BUFFER *frm = act->Data;
frm->NoBytes = nobytes;
act->ProcessedElementCount = (nobytes+2+3)/act->ElementWidth;
} else {
act->ProcessedElementCount = (nobytes+3)/act->ElementWidth;
}
}
if (dev->MaxTraceEntries>0) {
// we need to trace the frame if it is OK
ADI_ETHER_BF537_TRACE_ENTRY *te = dev->Trc.OldestEntry;
if (q->Rcve) {
// received
if ((act->StatusWord&0x3000) == 0x3000) {
// valid frame received
int nobytes = act->StatusWord&0x7ff-dev->TraceFirstByte;
if (nobytes>0) {
if (nobytes>dev->TraceMaxBytes) nobytes = dev->TraceMaxBytes;
te->NoBytes = nobytes;
te->Dirn = 'R';
te->Seqn = (u8)(dev->TraceSequence++);
memcpy(te->Data,((char *)act->Data)+(dev->NoRcveLnth?0:2)+dev->TraceFirstByte,nobytes);
te = (ADI_ETHER_BF537_TRACE_ENTRY *)(((char *)te) + dev->Trc.EntryLnth);
if (dev->Trc.NoOfEntries<dev->MaxTraceEntries) {
dev->Trc.NoOfEntries++;
} else {
if (te>=dev->Trc.EndOfData) {
te = dev->Trc.BaseEntry;
}
}
dev->Trc.OldestEntry = te;
}
}
} else {
// transmitted
if ((act->StatusWord&0x3) == 0x3) {
// valid frame trasmitted
int nobytes = (act->StatusWord>>16)&0x7ff-dev->TraceFirstByte;
if (nobytes>0) {
if (nobytes>dev->TraceMaxBytes) nobytes = dev->TraceMaxBytes;
te->NoBytes = nobytes;
te->Dirn = 'T';
te->Seqn = (u8)(dev->TraceSequence++);
if (act->PayLoad!=NULL) {
int first = act->ElementCount*act->ElementWidth;
int pa = first - 2 - dev->TraceFirstByte;
if (nobytes<= pa) {
memcpy(te->Data,((char *)act->Data)+2+dev->TraceFirstByte,nobytes);
} else {
u8 *nxt = te->Data;
if (pa>0) {
memcpy(nxt,((char *)act->Data)+2+dev->TraceFirstByte,pa);
nobytes -= pa;
nxt += pa;
}
memcpy(nxt,((u8 *)act->PayLoad)-pa,nobytes);
}
} else {
memcpy(te->Data,((char *)act->Data)+2+dev->TraceFirstByte,nobytes);
}
te = (ADI_ETHER_BF537_TRACE_ENTRY *)(((char *)te) + dev->Trc.EntryLnth);
if (dev->Trc.NoOfEntries<dev->MaxTraceEntries) {
dev->Trc.NoOfEntries++;
} else {
if (te>=dev->Trc.EndOfData) {
te = dev->Trc.BaseEntry;
}
}
dev->Trc.OldestEntry = te;
}
} else {
TxErr++;
}
}
}
// step onto the next active element
q->NoCompletions++;
if ((q->NoCompletions%100000) == 0) {
int a;
a=1;
}
lst = act;
act = act->pNext;
}
// fst points to first active buffer
// lst if non NULL points to last completed buffer
// act points to the new head of the Active list
if (lst!=NULL) {
u32 event = (q->Rcve?ADI_ETHER_EVENT_FRAME_RCVD:ADI_ETHER_EVENT_FRAME_XMIT);
// at least one buffer has completed
q->UnProcessed -= noposted;
// detach the completed frames
q->Active = act;
// append the completed buffers to the Completed queue
lst->pNext = NULL;
if (q->Completed!=NULL) {
lst = q->Completed;
while (lst->pNext != NULL) {
noposted++;
lst = lst->pNext;
}
lst->pNext = fst;
} else {
q->Completed = fst;
}
// can we add any queued frames to the pending list and then to the active list
QueueFrames(dev,q);
if (q->Rcve && (q->Active == NULL) && (dev->FlowControl)) {
// the control to send pause frame
if ((*pEMAC_FLC & FLCBUSY) == 0) {
// if we're not currently sending a previous PAUSE Frame...
// send a PAUSE Frame for (almost) two max-length frame times
*pEMAC_FLC = SET_FLCPAUSE(48) | FLCBUSY | (dev->FlowControl?FLCE:0);
}
}
// q->Completed must be non-null
act = q->Completed;
q->Completed = NULL;
#ifdef ADI_ETHER_BF537_DEBUG
{
ADI_ETHER_BUFFER *pst = act;
noposted = 0;
while (pst != NULL) {
noposted++;
pst->usage = Posted;
pst = pst->pNext;
}
}
#endif
// finally invoke the user call back
if (dev->DMCallback!= NULL) {
int res;
if (dev->DCBHandle) {
#ifdef ADI_ETHER_BF537_DEBUG
ADI_ETHER_BF537_PostedBuffer = act->CallbackParameter;
ADI_ETHER_BF537_OutstandingPosts++;
#endif
if (ADI_DEV_RESULT_SUCCESS!=(res=adi_dcb_Post(dev->DCBHandle,0,dev->DMCallback, dev->DeviceHandle, event, act->CallbackParameter))) {
#ifdef ADI_ETHER_BF537_DEBUG
ADI_ETHER_BF537_OutstandingPosts--;
{
ADI_ETHER_BUFFER *pst = act;
while (pst != NULL) {
pst->usage = Completed;
pst = pst->pNext;
}
}
#endif
q->Completed = act;
FailedPosts++;
} else {
#ifdef ADI_ETHER_BF537_DEBUG
ADI_ETHER_BF537_NoPosted += noposted;
#endif
if (q->Rcve) {
NoRxPosts++;
} else {
NoTxPosts++;
}
}
} else {
ExitCriticalRegion(xit);
(dev->DMCallback)(dev->DeviceHandle, event,act->CallbackParameter);
xit = EnterCriticalRegion(NULL);
}
}
} else {
QueueFrames(dev,q);
}
CheckQueues(q);
ExitCriticalRegion(xit);
return result;
}
//
// EMAC RX complete event interrupt handler
//
static ADI_INT_HANDLER(RxInterruptHandler) // RX complete interrupt handler
{
ADI_INT_HANDLER_RESULT result,result1;
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)ClientArg;
result = ProcessCompletion(dev,&dev->Rx);
return result;
}
//
// EMAC TX complete event interrupt handler
//
static ADI_INT_HANDLER(TxInterruptHandler) // TX complete interrupt handler
{
ADI_INT_HANDLER_RESULT result;
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)ClientArg;
result = ProcessCompletion(dev,&dev->Tx);
return result;
}
#if defined(ADI_ETHER_DEBUG)
/*********************************************************************
Function: ValidatePDDHandle
Description: Validates a PDD handle
*********************************************************************/
static int ValidatePDDHandle(ADI_DEV_PDD_HANDLE PDDHandle) {
if (PDDHandle == (ADI_DEV_PDD_HANDLE)&dev) {
if (EtherDev.Open) {
return (ADI_DEV_RESULT_SUCCESS);
}
}
return (ADI_DEV_RESULT_BAD_PDD_HANDLE);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -