if_lancepci.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,324 行 · 第 1/4 页
C
1,324 行
// reducing it cause transmission failures in RedBoot (at least).
CYGACC_CALL_IF_DELAY_US(100);
// Set transmit demand
ints = get_reg(sc, LANCE_CSR_CSCR);
ints &= LANCE_CSR_CSCR_EV_MASK;
ints |= LANCE_CSR_CSCR_TDMD;
put_reg(sc, LANCE_CSR_CSCR, ints);
#if DEBUG & 1
ints = get_reg(sc, LANCE_CSR_CSCR);
db_printf("%s:END: ints at TX: 0x%04x\n", __FUNCTION__, ints);
#endif
// This is another mystery delay like the one above. This one is
// even stranger, since waiting here at the _end_ of the function
// should have no effect.
CYGACC_CALL_IF_DELAY_US(200);
}
static void
lancepci_TxEvent(struct eth_drv_sc *sc, int stat)
{
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
int success = 1;
cyg_uint8 *txd;
cyg_uint16 ints;
cyg_uint32 pkt_stat;
DEBUG_FUNCTION();
if (0 == cpd->tx_ring_owned) {
#if DEBUG & 1
db_printf("%s: got TX completion when no outstanding packets\n", __FUNCTION__);
#endif
return;
}
INCR_STAT( tx_complete );
txd = cpd->tx_ring + cpd->tx_ring_alloc*LANCE_TD_SIZE;
pkt_stat = _SU32(txd, LANCE_TD_PTR);
if (pkt_stat & LANCE_TD_PTR_OWN) {
#if DEBUG & 1
db_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);
#endif
// first dirty ring entry not freed - wtf?
}
if (pkt_stat & LANCE_TD_PTR_ERR) {
// We had an error. Tell the stack.
success = 0;
#if DEBUG & 1
db_printf("%s: TX failure, retrying...\n", __FUNCTION__);
#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, LANCE_CSR_CSCR );
// Covering each bit in turn...
if ( reg & LANCE_STATUS_TX_UNRN ) INCR_STAT( tx_underrun );
//if ( reg & LANCE_STATUS_LINK_OK ) INCR_STAT( );
//if ( reg & LANCE_STATUS_CTR_ROL ) INCR_STAT( );
//if ( reg & LANCE_STATUS_EXC_DEF ) INCR_STAT( );
if ( reg & LANCE_STATUS_LOST_CARR ) INCR_STAT( tx_carrier_loss );
if ( reg & LANCE_STATUS_LATCOL ) INCR_STAT( tx_late_collisions );
//if ( reg & LANCE_STATUS_WAKEUP ) INCR_STAT( );
if ( reg & LANCE_STATUS_TX_DEFR ) INCR_STAT( tx_deferred );
//if ( reg & LANCE_STATUS_LTX_BRD ) INCR_STAT( );
if ( reg & LANCE_STATUS_SQET ) INCR_STAT( tx_sqetesterrors );
if ( reg & LANCE_STATUS_16COL ) INCR_STAT( tx_max_collisions );
//if ( reg & LANCE_STATUS_LTX_MULT) INCR_STAT( );
if ( reg & LANCE_STATUS_MUL_COL ) INCR_STAT( tx_mult_collisions );
if ( reg & LANCE_STATUS_SNGL_COL ) INCR_STAT( tx_single_collisions );
if ( reg & LANCE_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 (LANCE_COUNTER)
// because it just mimics the info we already have above.
}
#endif // KEEP_STATISTICS
#endif // FIXME
// Ack the TX int which clears the packet from the TX completion
// queue.
ints = get_reg(sc, LANCE_CSR_CSCR);
ints |= LANCE_CSR_CSCR_TINT;
put_reg(sc, LANCE_CSR_CSCR, ints);
#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
// 'lancepci_recv' will be called to actually fetch it from the hardware.
//
static void
lancepci_RxEvent(struct eth_drv_sc *sc)
{
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
cyg_uint8 *rxd;
cyg_uint32 rstat;
cyg_uint16 ints, len;
DEBUG_FUNCTION();
ints = get_reg(sc, LANCE_CSR_CSCR);
#if DEBUG & 1
db_printf("RxEvent - CSR: 0x%04x\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*LANCE_RD_SIZE;
rstat = _SU32(rxd, LANCE_RD_PTR);
// Keep going until we hit an entry that is owned by the
// controller.
if (rstat & LANCE_RD_PTR_OWN) {
#if DEBUG & 1
int i;
for (i = 0; i < cpd->rx_ring_cnt; i++) {
rxd = cpd->rx_ring + i*LANCE_RD_SIZE;
rstat = _SU32(rxd, LANCE_RD_PTR);
if (!(rstat & LANCE_RD_PTR_OWN)) {
int i;
cyg_uint32 rstat;
cyg_uint16 mlen, blen;
cyg_uint8* rxd;
db_printf("%s: Inconsistent RX state\n", __FUNCTION__);
for (i = 0; i < cpd->rx_ring_cnt; i++) {
rxd = cpd->rx_ring + i*LANCE_RD_SIZE;
rstat = _SU32(rxd, LANCE_RD_PTR);
blen = _SU16(rxd, LANCE_RD_BLEN);
mlen = _SU16(rxd, LANCE_RD_MLEN);
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, LANCE_RD_MLEN);
#ifdef KEEP_STATISTICS
//if ( rstat & LANCE_RD_PTR_FRAM ) INCR_STAT( rx_frame_errors );
//if ( rstat & LANCE_RD_PTR_OFLO ) INCR_STAT( );
if ( rstat & LANCE_RD_PTR_CRC ) INCR_STAT( rx_crc_errors );
//if ( rstat & LANCE_RD_PTR_BUFF ) INCR_STAT( );
#endif // KEEP_STATISTICS
if (0 == (rstat & LANCE_RD_PTR_ERR)) {
// 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 OWN)
_SU32(rxd, LANCE_RD_PTR) &= LANCE_RD_PTR_MASK;
_SU32(rxd, LANCE_RD_PTR) |= LANCE_RD_PTR_OWN;
}
// Ack RX interrupt set
ints = get_reg(sc, LANCE_CSR_CSCR);
ints &= LANCE_CSR_CSCR_EV_MASK;
ints |= LANCE_CSR_CSCR_RINT;
put_reg(sc, LANCE_CSR_CSCR, ints);
}
//
// 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
lancepci_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len)
{
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
int i, mlen=0, plen;
cyg_uint8 *data, *rxd, *buf;
DEBUG_FUNCTION();
rxd = cpd->rx_ring + cpd->rxpacket*LANCE_RD_SIZE;
buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE;
INCR_STAT( rx_deliver );
plen = _SU16(rxd, LANCE_RD_MLEN);
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 %x, plen %x\n", __FUNCTION__, mlen, plen);
#endif
if (data) {
while (mlen > 0) {
*data++ = *buf++;
mlen--;
plen--;
}
}
}
}
static void
lancepci_poll(struct eth_drv_sc *sc)
{
cyg_uint16 event;
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
// DEBUG_FUNCTION();
while (1) {
// Get the (unmasked) requests
if (cpd->event) {
event=cpd->event;
cpd->event=0;
}
else
event = get_reg(sc, LANCE_CSR_CSCR);
if (!((LANCE_CSR_CSCR_ERR|LANCE_CSR_CSCR_INTR) & event))
break;
if (event & LANCE_CSR_CSCR_RINT) {
lancepci_RxEvent(sc);
}
else if (event & LANCE_CSR_CSCR_TINT) {
cpd->txbusyh=0; // again , for polled mode
lancepci_TxEvent(sc, event);
}
else if (event & LANCE_CSR_CSCR_MISS) {
#if DEBUG & 1
int i;
cyg_uint32 rstat;
cyg_uint16 mlen, blen;
cyg_uint8* rxd;
struct lancepci_priv_data *cpd =
(struct lancepci_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*LANCE_TD_SIZE;
rstat = _SU32(rxd, LANCE_RD_PTR);
blen = _SU16(rxd, LANCE_RD_BLEN);
mlen = _SU16(rxd, LANCE_RD_MLEN);
db_printf(" %02d: 0x%08x:0x%04x:0x%04x\n", i, rstat, blen, mlen);
}
#endif
event &= LANCE_CSR_CSCR_EV_MASK;
event |= LANCE_CSR_CSCR_MISS;
put_reg(sc, LANCE_CSR_CSCR, event);
}
else {
#if DEBUG & 1
db_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);
#endif
put_reg(sc, LANCE_CSR_CSCR, event);
}
}
}
// EOF if_lancepci.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?