📄 if_lancepci.c
字号:
#if DEBUG & 9 db_printf("Lancepci-control:done\n");#endif CYGACC_CALL_IF_DELAY_US(50000); // let VMware get a tick return res;}//// This routine is called to see if it is possible to send another packet.// It will return non-zero if a transmit is possible, zero otherwise.//static intlancepci_can_send(struct eth_drv_sc *sc){ struct lancepci_priv_data *cpd = (struct lancepci_priv_data *)sc->driver_private; DEBUG_FUNCTION(); return (0 == cpd->txbusy);}//// This routine is called to send data to the hardware.static voidlancepci_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len, int total_len, unsigned long key){ struct lancepci_priv_data *cpd = (struct lancepci_priv_data *)sc->driver_private; int i, len, plen, ring_entry; cyg_uint8* sdata = NULL; cyg_uint8 *d, *buf, *txd; cyg_uint16 ints; cyg_uint32 b; DEBUG_FUNCTION(); INCR_STAT( tx_count ); cpd->txbusy = 1; cpd->txbusyh=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 db_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*LANCE_TD_SIZE; buf = cpd->tx_buffers + ring_entry*_BUF_SIZE; CYG_ASSERT(0 == (_SU32(txd, LANCE_TD_PTR) & LANCE_TD_PTR_OWN), "TX descriptor not free");#if DEBUG & 4 db_printf("#####Tx descriptor 0x%08x buffer 0x%08x\n", 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" );#if DEBUG & 1 db_printf("CSCR %04x\n", get_reg(sc, LANCE_CSR_CSCR));#endif _SU16(txd, LANCE_TD_LEN) = (-plen); _SU16(txd, LANCE_TD_MISC) = 0; HAL_PCI_CPU_TO_BUS(buf, (cyg_uint8 *)b); _SU32(txd, LANCE_TD_PTR) = ((b & LANCE_TD_PTR_MASK) | LANCE_TD_PTR_OWN | LANCE_TD_PTR_STP | LANCE_TD_PTR_ENP);#if DEBUG & 1 db_printf("Last TX: LEN %04x MISC %04x PTR %08x\n", _SU16(txd, LANCE_TD_LEN), _SU16(txd, LANCE_TD_MISC), _SU32(txd, LANCE_TD_PTR));#endif // This delay seems to be necessary on some platforms // (Malta 5kc for example). // Why it is needed is not clear, but removing it or // 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 voidlancepci_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 voidlancepci_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 voidlancepci_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 voidlancepci_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -