📄 smc8xx.c
字号:
/*---------------------------------------------------------------------*/
/* Update the status of the frame: may set a new (error) bit. */
/* NOTE: This is a accumulate error from each buffer processed. */
/*---------------------------------------------------------------------*/
rxstatus |= status & ~( SMC_RX_WRAP | SMC_RX_EMPTY | SMC_RX_INTR );
/*---------------------------------------------------------------------*/
/* Check rxstatus of frame */
/*---------------------------------------------------------------------*/
if (rxstatus != 0)
{
if (rxstatus & SMC_RX_IDLE)
*frameFlag |= SIOCMARK;
if (rxstatus & SMC_RX_BRKRCV)
*frameFlag |= SIOCBREAKR;
if (rxstatus & SMC_RX_FRMERR)
*frameFlag |= SIOCFRAMING;
if (rxstatus & SMC_RX_PARITY)
*frameFlag |= SIOCPARITY;
if (rxstatus & SMC_RX_OVERRUN)
*frameFlag |= SIOCOVERRUN;
if ((rxstatus & SMC_RX_CDLOST) &&
(chan->cfg.Cfg.Uart.Flags & SWDCD) == 0)
*frameFlag |= SIOCCDLOST;
}
_sync_io();
BufAdjust(frame, BufSize(frame) - length);
/*
* Increment receive frame statistics (both frame counts and bytes).
*/
++chan->stats.receive_Aframes;
chan->stats.receive_bytes += length;
return(frame);
}
/***********************************************************************/
/* frame_transmit: */
/* Transmit Frame. Check priority parameter and */
/* place on either hardware queue or backup queue. */
/* */
/* INPUTS: */
/* chan pointer to the structure that contains channel */
/* information */
/* */
/* RETURNS: error code */
/* */
/***********************************************************************/
static int
frame_transmit(chan_control *chan, mblk_t *frame, UINT priority)
{
ULONG imask; /* slpx saved level */
/*---------------------------------------------------------------------*/
/* Transmit the frame immediately if it has priority or if */
/* nothing is in the soft queue. */
/*---------------------------------------------------------------------*/
if (priority || (chan->soft_queued == 0))
{
if (hardware_transmit(chan, frame) == SIOCOK)
return(SIOCOK);
/*-----------------------------------------------------------------*/
/* If hardware transmit fails (lack of ring descriptors), */
/* queue in backup queue. */
/*-----------------------------------------------------------------*/
}
/*---------------------------------------------------------------------*/
/* Check space on backup queue and return error if there is */
/* no room (logically). */
/*---------------------------------------------------------------------*/
if ((chan->tx_count + chan->backup_count) > chan->credit)
{
chan->stats.xmit_queue_full++;
return(SIOCOQFULL);
}
/*---------------------------------------------------------------------*/
/* queue on soft que */
/*---------------------------------------------------------------------*/
imask = splx(MAX_ILEV);
BufListAppend(frame, &chan->backup_queue);
(void)splx(imask);
chan->backup_count++;
chan->soft_queued += BufSize(frame);
return (SIOCOK);
}
/***********************************************************************/
/* hardware_transmit */
/* Transmit a frame. Check for sufficient open */
/* descriptors. Transfer the pointers and lengths */
/* to the ring descriptors. Initiate a transmit immediate */
/* command to SMC if it was idle. */
/* */
/* INPUTS: */
/* chan pointer to the structure that contains channel */
/* information */
/* frame mblock to transmit */
/* */
/* RETURNS: */
/* SIOCOQFULL if transmit descriptors are all used */
/* SIOCOK on success */
/* */
/***********************************************************************/
static int
hardware_transmit(chan_control *chan, mblk_t *frame)
{
BuffDescType *ring; /* transmit descriptor ring pointer */
BuffDescType *last; /* last descriptor ring pointer */
UINT entries; /* number of segments in a frame */
UINT length; /* total length of frame */
mblk_t *segment; /* intermediate segment making up a frame */
ULONG imask; /* splx saved level */
/*---------------------------------------------------------------------*/
/* Count how many segments make up one frame. */
/*---------------------------------------------------------------------*/
for (segment = frame, entries = 0;
segment != (mblk_t *)NULL;
segment = BufSegNext(segment))
{
entries++;
}
/*---------------------------------------------------------------------*/
/* Check unused transmit descriptor space and transmit queue */
/* full condition, also report an exception. */
/*---------------------------------------------------------------------*/
if (entries > chan->unused_tx)
{
chan->stats.xmit_hwqueue_full++;
return(SIOCOQFULL);
}
length = BufSize(frame);
/*---------------------------------------------------------------------*/
/* Queue the buffer descriptor in the logical tx queue. */
/*---------------------------------------------------------------------*/
imask = splx(MAX_ILEV);
_sync_io();
BufListAppend(frame, &chan->tx_queue);
(void)splx(imask);
chan->tx_count++;
/*---------------------------------------------------------------------*/
/* Transfer buffer addresses to SMC descriptor ring */
/*---------------------------------------------------------------------*/
ring = chan->txrg_wr; /* get first descriptor address */
segment = frame; /* start from beginning of frame */
/*---------------------------------------------------------------------*/
/* Queue all mblocks that make up the frame */
/*---------------------------------------------------------------------*/
while (segment != (mblk_t *)NULL)
{
_sync_io();
ring->address = (void *)BufSegAddr(segment);
ring->length = BufSegSize(segment);
#if (BRD_DCACHE == YES) && (BRD_DCACHE_WRITE_THRU == NO)
SysDcacheFlush(ring->address, ring->length);
#endif
/*-----------------------------------------------------------------*/
/* Wrap descriptor pointer if bottom of ring. */
/* NOTE: don't set status here they need to be set when the hole */
/* frame is ready to go. */
/*-----------------------------------------------------------------*/
if (ring++ == chan->txrg_bottom)
ring = chan->txrg_top;
segment = BufSegNext(segment);
}
last = ring; /* actually: one past the last entry */
/*---------------------------------------------------------------------*/
/* Update transmit descriptor head pointer, unused descriptor */
/* counter, and transmit descriptor used statistics */
/*---------------------------------------------------------------------*/
chan->txrg_wr = ring;
chan->unused_tx -= entries;
/*---------------------------------------------------------------------*/
/* Fill descriptor status (starting from the last one, so that all */
/* the READY bits are set orderly). Note that the WRAP bit is */
/* already set in the bottom ring entry. */
/*---------------------------------------------------------------------*/
if (last-- == chan->txrg_top)
last = chan->txrg_bottom;
last->status |= (SMC_TX_READY | SMC_TX_INTR );
/*---------------------------------------------------------------------*/
/* Set READY bit for intermediate (and first) descriptors in chain */
/* One entry (the last) has already been taken into account. */
/*---------------------------------------------------------------------*/
while (--entries != 0)
{
_sync_io();
if (last-- == chan->txrg_top)
last = chan->txrg_bottom;
last->status |= SMC_TX_READY;
}
/*---------------------------------------------------------------------*/
/* Update frame transmit statistics and return: */
/*---------------------------------------------------------------------*/
++chan->stats.transmit_frames;
chan->stats.transmit_bytes += length;
chan->hard_queued += length;
return(SIOCOK);
}
/***********************************************************************/
/* buffer_done: */
/* Checks transmit descriptor ring for buffers finished */
/* transmitting and return them to the data link layer */
/* with their completion status. */
/* */
/* INPUTS: */
/* chan pointer to the structure that contains channel */
/* information */
/* */
/***********************************************************************/
static void
buffer_done(chan_control *chan)
{
BuffDescType *ring; /* transmit descriptor ring pointer */
mblk_t *mblk; /* data link layer buffer */
USHORT txstatus; /* txstatus of a transmitted frame */
USHORT status; /* status of current Rx BD */
ULONG frameFlag; /* frame transmission status */
ULONG imask; /* splx saved level */
/*---------------------------------------------------------------------*/
/* Initialize transmit ring pointer: restart from where we left off */
/*---------------------------------------------------------------------*/
ring = chan->txrg_rd;
/*---------------------------------------------------------------------*/
/* Let's assume the frame was sent OK */
/*---------------------------------------------------------------------*/
/* txstatus = 0; , ---deleted by szg , not used */
frameFlag = 0;
/*---------------------------------------------------------------------*/
/* Look for descriptors that contain meaningful data (i.e not NULL) */
/* and poll their READY bit. Return the buffer (found in the parallel */
/* transmit queue) when transmit is done and the ring descriptor entry */
/* is located at the end of frame. Otherwise just return... */
/*---------------------------------------------------------------------*/
while (ring->address != (void *)0)
{
status = ring->status;
_sync_io();
if ( !(status & SMC_TX_READY) )
{
/*-------------------------------------------------------------*/
/* Clear descriptor entry, increment unused count. */
/*-------------------------------------------------------------*/
if (++chan->unused_tx == chan->MaxBuffers)
chan->hard_queued = 0;
else
chan->hard_queued -= ring->length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -