if_rhine.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,320 行 · 第 1/3 页
C
1,320 行
// This MII read forces the MIISR to get updated (void) rhine_read_MII(cpd, cpd->phys_id, MII_BMSR); HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_MIISR, stat); if (stat & RHINE_MIISR_LNKFL) {#if DEBUG & 1 diag_printf("*** Link failure\n");#endif return false; // Link not connected } return (cpd->txbusy == 0);}//// This routine is called to send data to the hardware.static void rhine_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; int i, len, plen, ring_entry; cyg_uint8* sdata = NULL; cyg_uint8 *d, *buf, *txd; cyg_uint16 status; cyg_uint8 cr0; DEBUG_FUNCTION(); INCR_STAT( tx_count ); // Worry about the engine stopping. HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, status); if ( 0 == (RHINE_CR0_STRT & status) ) {#if DEBUG & 1 diag_printf("%s: ENGINE RESTART: status %04x\n", __FUNCTION__, status);#endif status &= ~RHINE_CR0_STOP; status |= RHINE_CR0_STRT; HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, status); } cpd->txbusy = 1; cpd->txkey = key; // Find packet length plen = 0; for (i = 0; i < sg_len; i++) plen += sg_list[i].len; CYG_ASSERT( plen == total_len, "sg data length mismatch" ); // Get next TX descriptor ring_entry = cpd->tx_ring_free; do { if (cpd->tx_ring_owned == cpd->tx_ring_cnt) { // Is this a dead end? Probably is.#if DEBUG & 1 diag_printf("%s: Allocation failed! Retrying...\n", __FUNCTION__ );#endif continue; } cpd->tx_ring_free++; cpd->tx_ring_owned++; if (cpd->tx_ring_free == cpd->tx_ring_cnt) cpd->tx_ring_free = 0; } while (0); txd = cpd->tx_ring + ring_entry*RHINE_TD_SIZE; buf = cpd->tx_buffers + ring_entry*_BUF_SIZE; CYG_ASSERT(0 == (_SU32(txd, RHINE_TDES0) & RHINE_TDES0_OWN), "TX descriptor not free");#if DEBUG & 4 diag_printf("##Tx descriptor index %d TDES %08x buffer %08x\n", ring_entry, txd, buf);#endif // Put data into buffer d = buf; for (i = 0; i < sg_len; i++) { sdata = (cyg_uint8 *)sg_list[i].buf; len = sg_list[i].len; CYG_ASSERT( sdata, "No sg data pointer here" ); while(len--) *d++ = *sdata++; } CYG_ASSERT( sdata, "No sg data pointer outside" ); // Annoyingly the chip doesn't pad to minimal packet size, so do // that by steam if (plen < 60) { plen = 60;#if DEBUG & 4 diag_printf("Padded %d bytes packet to 60 bytes\n", plen);#endif } CYG_ASSERT( (plen & RHINE_TDES1_TLNG_mask) == plen, "packet too long"); CYG_ASSERT( (plen & RHINE_TDES1_TLNG_mask) >= 60, "packet too short"); _SU32(txd, RHINE_TDES1) &= ~RHINE_TDES1_TLNG_mask; _SU32(txd, RHINE_TDES1) |= plen; _SU32(txd, RHINE_TDES0) = RHINE_TDES0_OWN;#if DEBUG & 1 // FIXME diag_printf("Before TX: Desc (@0x%08lx) %08x %08x %08x %08x\n Next (@0x%08lx) %08x %08x %08x %08x\n", (unsigned long) txd, _SU32(txd, RHINE_TDES0), _SU32(txd, RHINE_TDES1), _SU32(txd, RHINE_TDES2), _SU32(txd, RHINE_TDES3), ( (unsigned long)txd)+0x10, _SU32(txd, (0x10+RHINE_TDES0)), _SU32(txd, (0x10+RHINE_TDES1)), _SU32(txd,(0x10+ RHINE_TDES2)), _SU32(txd,(0x10+ RHINE_TDES3)));#endif // Ack TX empty int HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PTX); // Set transmit demand HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, cr0); cr0 |= RHINE_CR0_TDMD; HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, cr0);#if DEBUG & 1 HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, status); diag_printf("%s:END: ints at TX: %04x\n", __FUNCTION__, status);#endif}static voidrhine_TxEvent(struct eth_drv_sc *sc, int stat){ struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; int success = 1; cyg_uint8 *txd; cyg_uint8 status; DEBUG_FUNCTION(); INCR_STAT( tx_complete ); txd = cpd->tx_ring + cpd->tx_ring_alloc*RHINE_TD_SIZE;#if DEBUG & 4 diag_printf("##Tx packet %d freed %08x %08x!\n", cpd->tx_ring_alloc, txd, _SU32(txd, RHINE_TDES0) );#endif if ((_SU32(txd, RHINE_TDES0) & RHINE_TDES0_OWN)) {#if DEBUG & 1 diag_printf("%s: got TX completion when buffer is still owned\n", __FUNCTION__);#endif // first dirty ring entry not freed - wtf? } cpd->tx_ring_alloc++; if (cpd->tx_ring_alloc == cpd->tx_ring_cnt) cpd->tx_ring_alloc = 0; cpd->tx_ring_owned--;#ifdef KEEP_STATISTICS { cyg_uint32 reg = _SU32(txd, RHINE_TDES0); int collisions; // Covering each bit in turn... if ( reg & RHINE_TDES0_TXOK ) INCR_STAT( tx_good ); if ( reg & RHINE_TDES0_CRS ) INCR_STAT( tx_carrier_loss ); if ( reg & RHINE_TDES0_OWC ) INCR_STAT( tx_late_collisions ); if ( reg & RHINE_TDES0_ABT ) INCR_STAT( tx_max_collisions ); if ( reg & RHINE_TDES0_DFR ) INCR_STAT( tx_deferred ); collisions = ((reg & RHINE_TDES0_NCR_mask) >> RHINE_TDES0_NCR_shift); if (1 == collisions) INCR_STAT( tx_single_collisions ); else if (1 < collisions) INCR_STAT( tx_mult_collisions ); 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; }#endif // KEEP_STATISTICS // We do not really care about Tx failure. Ethernet is not a reliable // medium. But we do care about the TX engine stopping. HAL_PCI_IO_READ_UINT8(cpd->base + RHINE_CR0, status); if ( 0 == (RHINE_CR0_STRT & status) ) {#if DEBUG & 1 diag_printf("%s: ENGINE RESTART: status %04x\n", __FUNCTION__, status);#endif status &= ~RHINE_CR0_STOP; status |= RHINE_CR0_STRT; HAL_PCI_IO_WRITE_UINT8(cpd->base + RHINE_CR0, status); success = 0; // And treat this as an error... } if ( cpd->txbusy ) { cpd->txbusy = 0; (sc->funs->eth_drv->tx_done)(sc, cpd->txkey, success); } // Ack TX interrupt set HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PTX);}//// 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// 'rhine_recv' will be called to actually fetch it from the hardware.//static voidrhine_RxEvent(struct eth_drv_sc *sc){ struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; cyg_uint8 *rxd; cyg_uint32 rstat; cyg_uint16 ints, len, mask; DEBUG_FUNCTION(); HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, ints);#if DEBUG & 1 diag_printf("RxEvent - CSR: 0x%04x\n", ints);#endif if ( 0 == (RHINE_ISR_PRX & ints) ) // Then there's no RX event pending return; // Mask interrupt HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask); mask &= ~RHINE_IMR_PRX; HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_IMR, mask); while (1) { // Get state of next (supposedly) full ring entry cpd->rxpacket = cpd->rx_ring_next; rxd = cpd->rx_ring + cpd->rxpacket*RHINE_RD_SIZE; rstat = _SU32(rxd, RHINE_RDES0); // Keep going until we hit an entry that is owned by the // controller. if (rstat & RHINE_RDES0_OWN) {#ifdef CYGDBG_USE_ASSERTS // Sanity check of queue int i; for (i = 0; i < cpd->rx_ring_cnt; i++) { rxd = cpd->rx_ring + i*RHINE_RD_SIZE; rstat = _SU32(rxd, RHINE_RDES0); if (!(rstat & RHINE_RDES0_OWN)) { int i; cyg_uint32 rstat; cyg_uint8* rxd; diag_printf("####Rx %s Inconsistent RX state - next was %d\n", __FUNCTION__, cpd->rx_ring_next); for (i = 0; i < cpd->rx_ring_cnt; i++) { rxd = cpd->rx_ring + i*RHINE_RD_SIZE; rstat = _SU32(rxd, RHINE_RDES0); diag_printf("#### %02d: 0x%08x\n", i, rstat); } } break; }#endif break; }#if DEBUG & 4 diag_printf("##Rx packet %d RDES %08x stat %08x\n", cpd->rxpacket, rxd, rstat);#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 = (rstat & RHINE_RDES0_FLNG_mask) >> RHINE_RDES0_FLNG_shift;#ifdef KEEP_STATISTICS if ( rstat & RHINE_RDES0_CRC ) INCR_STAT( rx_crc_errors ); if ( rstat & RHINE_RDES0_FAE ) INCR_STAT( rx_align_errors ); if ( rstat & RHINE_RDES0_LONG ) INCR_STAT( rx_too_long_frames );#endif // KEEP_STATISTICS if (RHINE_RDES0_RXOK & rstat) { // It's OK INCR_STAT( rx_good );#if DEBUG & 1 diag_printf("RxEvent good rx - stat: 0x%08x, len: 0x%04x\n", rstat, len); { unsigned char *buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE; int i; diag_printf("RDES: %08x %08x %08x %08x\n", _SU32(rxd, RHINE_RDES0), _SU32(rxd, RHINE_RDES1), _SU32(rxd, RHINE_RDES2), _SU32(rxd, RHINE_RDES3)); diag_printf("Packet data at %p\n", buf); for (i=0;i<len;i++) diag_printf("%02x ", buf[i]); diag_printf("\n"); }#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 diag_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, RHINE_RDES0) = RHINE_RDES0_OWN; } // Ack RX int HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_PRX); // And reenable the interrupt HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask); mask |= RHINE_IMR_PRX; HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_IMR, mask);}//// 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 voidrhine_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len){ struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; int i, mlen=0, plen; cyg_uint8 *data, *rxd, *buf; DEBUG_FUNCTION(); rxd = cpd->rx_ring + cpd->rxpacket*RHINE_RD_SIZE; buf = cpd->rx_buffers + cpd->rxpacket*_BUF_SIZE; INCR_STAT( rx_deliver ); plen = (_SU32(rxd, RHINE_RDES0) & RHINE_RDES0_FLNG_mask) >> RHINE_RDES0_FLNG_shift; for (i = 0; i < sg_len; i++) { data = (cyg_uint8*)sg_list[i].buf; mlen = sg_list[i].len;#if DEBUG & 1 diag_printf("%s : mlen %x, plen %x\n", __FUNCTION__, mlen, plen);#endif if (data) { while (mlen > 0) { *data++ = *buf++; mlen--; plen--; } } }}static voidrhine_poll(struct eth_drv_sc *sc){ struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; cyg_uint16 event, mask; static volatile bool locked = false;// DEBUG_FUNCTION(); while (1) { // Get the (unmasked) requests HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_ISR, event); HAL_PCI_IO_READ_UINT16(cpd->base + RHINE_IMR, mask); event &= mask; if (0 == event) break; if (event & RHINE_ISR_PRX) { rhine_RxEvent(sc); } else if (event & RHINE_ISR_PTX) { rhine_TxEvent(sc, event); } else if (event & RHINE_ISR_RU) {#if DEBUG & 1 int i; cyg_uint32 rstat; cyg_uint8* rxd; struct rhine_priv_data *cpd = (struct rhine_priv_data *)sc->driver_private; diag_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*RHINE_RD_SIZE; rstat = _SU32(rxd, RHINE_RDES0); diag_printf(" %02d: 0x%08x\n", i, rstat); }#endif HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, RHINE_ISR_RU); } else {#if DEBUG & 1 diag_printf("%s: Unknown interrupt: 0x%04x\n", __FUNCTION__, event);#endif // Clear unhandled interrupts and hope for the best // This should never happen though, since we only enable // the sources we handle. HAL_PCI_IO_WRITE_UINT16(cpd->base + RHINE_ISR, event); } } locked = false;}// EOF if_rhine.c
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?