if_etherc.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,128 行 · 第 1/3 页
C
1,128 行
#endif
}
cpd->tx_ring_alloc++;
if (cpd->tx_ring_alloc == cpd->tx_ring_cnt)
cpd->tx_ring_alloc = 0;
cpd->tx_ring_owned--;
#if FIXME
#ifdef KEEP_STATISTICS
{
cyg_uint16 reg;
reg = get_reg( sc, ETHERC_CSR_CSCR );
// Covering each bit in turn...
if ( reg & ETHERC_STATUS_TX_UNRN ) INCR_STAT( tx_underrun );
//if ( reg & ETHERC_STATUS_LINK_OK ) INCR_STAT( );
//if ( reg & ETHERC_STATUS_CTR_ROL ) INCR_STAT( );
//if ( reg & ETHERC_STATUS_EXC_DEF ) INCR_STAT( );
if ( reg & ETHERC_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
if ( reg & ETHERC_STATUS_LATCOL ) INCR_STAT( tx_late_collisions );
//if ( reg & ETHERC_STATUS_WAKEUP ) INCR_STAT( );
if ( reg & ETHERC_STATUS_TX_DEFR ) INCR_STAT( tx_deferred );
//if ( reg & ETHERC_STATUS_LTX_BRD ) INCR_STAT( );
if ( reg & ETHERC_STATUS_SQET ) INCR_STAT( tx_sqetesterrors );
if ( reg & ETHERC_STATUS_16COL ) INCR_STAT( tx_max_collisions );
//if ( reg & ETHERC_STATUS_LTX_MULT) INCR_STAT( );
if ( reg & ETHERC_STATUS_MUL_COL ) INCR_STAT( tx_mult_collisions );
if ( reg & ETHERC_STATUS_SNGL_COL ) INCR_STAT( tx_single_collisions );
if ( reg & ETHERC_STATUS_TX_SUC ) INCR_STAT( tx_good );
cpd->stats.tx_total_collisions =
cpd->stats.tx_late_collisions +
cpd->stats.tx_max_collisions +
cpd->stats.tx_mult_collisions +
cpd->stats.tx_single_collisions;
// We do not need to look in the Counter Register (ETHERC_COUNTER)
// because it just mimics the info we already have above.
}
#endif // KEEP_STATISTICS
#endif // FIXME
// Ack the TX int
put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_TC);
#if DEBUG & 4
db_printf("#####Tx packet freed 0x%08x\n", txd );
#endif
if ( cpd->txbusy ) {
cpd->txbusy = 0;
(sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success);
}
}
//
// This function is called when a packet has been received. Its job is
// to prepare to unload the packet from the hardware. Once the length of
// the packet is known, the upper layer of the driver can be told. When
// the upper layer is ready to unload the packet, the internal function
// 'etherc_recv' will be called to actually fetch it from the hardware.
//
static void
etherc_RxEvent(struct eth_drv_sc *sc)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
cyg_uint8 *rxd;
cyg_uint32 rstat;
cyg_uint32 ints;
cyg_uint16 len;
DEBUG_FUNCTION();
ints = get_reg(cpd, _REG_EESR);
#if DEBUG & 1
db_printf("RxEvent - ESSR: 0x%08x\n", ints);
#endif
while (1) {
// Get state of next (supposedly) full ring entry
cpd->rxpacket = cpd->rx_ring_next;
rxd = cpd->rx_ring + cpd->rxpacket*ETHERC_RD_SIZE;
rstat = _SU32(rxd, ETHERC_RD_STAT);
// Keep going until we hit an entry that is owned by the
// controller.
if (rstat & ETHERC_RD_STAT_RACT) {
#if DEBUG & 1
int i;
for (i = 0; i < cpd->rx_ring_cnt; i++) {
rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
rstat = _SU32(rxd, ETHERC_RD_STAT);
if (!(rstat & ETHERC_RD_STAT_RACT)) {
int i;
cyg_uint32 rstat;
cyg_uint16 mlen, blen;
cyg_uint8* rxd;
db_printf("%s: Inconsistent RX state for %d\n", __FUNCTION__, cpd->rxpacket);
for (i = 0; i < cpd->rx_ring_cnt; i++) {
rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
rstat = _SU32(rxd, ETHERC_RD_STAT);
blen = _SU16(rxd, ETHERC_RD_RBL);
mlen = _SU16(rxd, ETHERC_RD_RDL);
db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
}
}
}
#endif
break;
}
#if DEBUG & 4
db_printf("#####Rx packet at index %d\n", cpd->rxpacket);
#endif
// Increment counts
INCR_STAT( rx_count );
cpd->rx_ring_next++;
if (cpd->rx_ring_next == cpd->rx_ring_cnt) cpd->rx_ring_next = 0;
len = _SU16(rxd, ETHERC_RD_RDL);
#ifdef KEEP_STATISTICS
//if ( rstat & ETHERC_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
//if ( rstat & ETHERC_RD_PTR_OFLO ) INCR_STAT( );
if ( rstat & ETHERC_RD_STAT_RFOF ) INCR_STAT( rx_crc_errors );
//if ( rstat & ETHERC_RD_PTR_BUFF ) INCR_STAT( );
#endif // KEEP_STATISTICS
if (0 == (rstat & ETHERC_RD_STAT_RFE)) {
// It's OK
INCR_STAT( rx_good );
#if DEBUG & 1
db_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len);
#endif
// Check for bogusly short packets; can happen in promisc
// mode: Asserted against and checked by upper layer
// driver.
#ifdef CYGPKG_NET
if ( len > sizeof( struct ether_header ) )
// then it is acceptable; offer the data to the network stack
#endif
(sc->funs->eth_drv->recv)(sc, len);
} else {
// Not OK for one reason or another...
#if DEBUG & 1
db_printf("RxEvent - No RX bit: stat: 0x%08x, len: 0x%04x\n",
rstat, len);
#endif
}
// Free packet (clear all status flags, and set RACT)
_SU32(rxd, ETHERC_RD_STAT) &= ETHERC_RD_STAT_CLEAR;
_SU32(rxd, ETHERC_RD_STAT) |= ETHERC_RD_STAT_RACT;
}
// Ack RX interrupt set
put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_FR);
// ensure Receive Request is enabled
put_reg(cpd, _REG_EDRRR, CYGARC_REG_EDRRR_RR);
#if DEBUG & 1
ints = get_reg(cpd, _REG_EESR);
db_printf("RxEvent exit - ESSR: 0x%08x\n", ints);
#endif
}
//
// This function is called as a result of the "eth_drv_recv()" call above.
// Its job is to actually fetch data for a packet from the hardware once
// memory buffers have been allocated for the packet. Note that the buffers
// may come in pieces, using a scatter-gather list. This allows for more
// efficient processing in the upper layers of the stack.
//
static void
etherc_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
{
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
int i, mlen=0, plen;
cyg_uint8 *data, *rxd, *buf;
DEBUG_FUNCTION();
rxd = cpd->rx_ring + cpd->rxpacket*ETHERC_TD_SIZE;
buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
INCR_STAT( rx_deliver );
plen = _SU16(rxd, ETHERC_RD_RDL);
for (i = 0; i < sg_len; i++) {
data = (cyg_uint8*)sg_list[i].buf;
mlen = sg_list[i].len;
#if DEBUG & 1
db_printf("%s : mlen %04x, plen %04x\n", __FUNCTION__, mlen, plen);
#endif
if (data) {
while (mlen > 0) {
*data++ = *buf++;
mlen--;
plen--;
}
}
}
}
static void
etherc_poll(struct eth_drv_sc *sc)
{
cyg_uint32 event;
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
// DEBUG_FUNCTION();
while (1) {
// Get the (unmasked) requests
event = get_reg(cpd, _REG_EESR);
if (0 == event)
break;
if (event & CYGARC_REG_EESR_FR) {
etherc_RxEvent(sc);
}
else if (event & CYGARC_REG_EESR_TC) {
etherc_TxEvent(sc, event);
}
else if (event & CYGARC_REG_EESR_RDE) {
#if DEBUG & 1
int i;
cyg_uint32 rstat;
cyg_uint16 mlen, blen;
cyg_uint8* rxd;
struct etherc_priv_data *cpd =
(struct etherc_priv_data *)sc->driver_private;
db_printf("%s: Ran out of RX buffers (%04x)\n", __FUNCTION__, event);
for (i = 0; i < cpd->rx_ring_cnt; i++) {
rxd = cpd->rx_ring + i*ETHERC_RD_SIZE;
rstat = _SU32(rxd, ETHERC_RD_STAT);
blen = _SU16(rxd, ETHERC_RD_RBL);
mlen = _SU16(rxd, ETHERC_RD_RDL);
db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
}
#endif
// Just clear the flag - RF is handled earlier in the loop
// so a new RX block should be ready when this code
// executes.
put_reg(cpd, _REG_EESR, CYGARC_REG_EESR_RDE);
}
else {
#if DEBUG & 1
db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
#endif
put_reg(cpd, _REG_EESR, event);
}
}
// Make sure RX is enabled
if (cpd->active) {
cyg_uint32 reg;
reg = get_reg(cpd, _REG_ECMR);
reg |= CYGARC_REG_ECMR_RE;
put_reg(cpd, _REG_ECMR, reg);
}
}
//----------------------------------------------------------------------------
// MII accessors
#define _MII_WRITE_BIT(_cpd_, _b_) \
CYG_MACRO_START \
cyg_uint32 _d_ = (_b_) ? CYGARC_REG_PIR_MDO : 0; \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_); \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_ | CYGARC_REG_PIR_MDC); \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_WRITE | _d_); \
CYG_MACRO_END
#define _MII_READ_BIT(_cpd_, _b_) \
CYG_MACRO_START \
cyg_uint32 _d_; \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ | CYGARC_REG_PIR_MDC); \
HAL_READ_UINT32(_cpd_->base+_REG_PIR, _d_); \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ); \
(_b_) = (_d_ & CYGARC_REG_PIR_MDI) ? 1 : 0; \
CYG_MACRO_END
#define _MII_RELEASE(_cpd_) \
CYG_MACRO_START \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ); \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ | CYGARC_REG_PIR_MDC); \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ); \
CYG_MACRO_END
#define _MII_RELEASE_INDEP(_cpd_) \
CYG_MACRO_START \
HAL_WRITE_UINT32(_cpd_->base+_REG_PIR, CYGARC_REG_PIR_MMD_READ); \
CYG_MACRO_END
static void
etherc_write_MII(struct etherc_priv_data *cpd, int id, int reg, cyg_uint16 value)
{
int i;
// Pre
for(i = 0; i < 32; i++)
_MII_WRITE_BIT(cpd, 1);
// Start of frame
_MII_WRITE_BIT(cpd, 0);
_MII_WRITE_BIT(cpd, 1);
// Operation (write)
_MII_WRITE_BIT(cpd, 0);
_MII_WRITE_BIT(cpd, 1);
// Phy address
for (i = 4; i >= 0; i--)
_MII_WRITE_BIT(cpd, (id & (1<<i)) ? 1: 0);
// Register address
for (i = 4; i >= 0; i--)
_MII_WRITE_BIT(cpd, (reg & (1<<i)) ? 1: 0);
// TA
_MII_WRITE_BIT(cpd, 1);
_MII_WRITE_BIT(cpd, 0);
// Data
for (i = 15; i >= 0; i--)
_MII_WRITE_BIT(cpd, (value & (1<<i)) ? 1: 0);
// Release bus
_MII_RELEASE_INDEP(cpd);
}
static cyg_uint16
etherc_read_MII(struct etherc_priv_data *cpd, int id, int reg)
{
bool b;
int i;
cyg_uint16 val = 0;
// Pre
for(i = 0; i < 32; i++)
_MII_WRITE_BIT(cpd, 1);
// Start of frame
_MII_WRITE_BIT(cpd, 0);
_MII_WRITE_BIT(cpd, 1);
// Operation (read)
_MII_WRITE_BIT(cpd, 1);
_MII_WRITE_BIT(cpd, 0);
// Phy address
for (i = 4; i >= 0; i--)
_MII_WRITE_BIT(cpd, (id & (1<<i)) ? 1: 0);
// Register address
for (i = 4; i >= 0; i--)
_MII_WRITE_BIT(cpd, (reg & (1<<i)) ? 1: 0);
// TA
_MII_RELEASE(cpd);
// Data
for (i = 15; i >= 0; i--) {
_MII_READ_BIT(cpd, b);
val = val << 1;
if (b) val |= 1;
}
return val;
}
// EOF if_etherc.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?