📄 if_tx.c
字号:
* DP83840A data sheet * http://www.national.com/ds/DP/DP83840A.pdf */static int epic_autoneg( epic_softc_t * sc){ u_int16_t media; u_int16_t i; /* BMSR must be read twice to update the link status bit * since that bit is a latch bit */ PHY_READ_2( sc, DP83840_BMSR); i = PHY_READ_2( sc, DP83840_BMSR); if ((i & BMSR_LINK_STATUS) && (i & BMSR_AUTONEG_COMPLETE)){ i = PHY_READ_2( sc, DP83840_LPAR ); if ( i & (ANAR_100_TX_FD|ANAR_10_FD) ) return EPIC_FULL_DUPLEX; else return EPIC_HALF_DUPLEX; } else { /*Auto-negotiation or link status is not 1 Thus the auto-negotiation failed and one must take other means to fix it. */ /* ANER must be read twice to get the correct reading for the * Multiple link fault bit -- it is a latched bit */ PHY_READ_2( sc, DP83840_ANER ); i = PHY_READ_2( sc, DP83840_ANER ); if ( i & ANER_MULTIPLE_LINK_FAULT ) { /* it can be forced to 100Mb/s Half-Duplex */ media = PHY_READ_2( sc, DP83840_BMCR ); media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX); media |= BMCR_100MBPS; PHY_WRITE_2( sc, DP83840_BMCR, media ); /* read BMSR again to determine link status */ PHY_READ_2( sc, DP83840_BMSR ); i=PHY_READ_2( sc, DP83840_BMSR ); if (i & BMSR_LINK_STATUS){ /* port is linked to the non Auto-Negotiation * 100Mbs partner. */ return EPIC_HALF_DUPLEX; } else { media = PHY_READ_2( sc, DP83840_BMCR); media &= ~(BMCR_AUTONEGOTIATION | BMCR_FULL_DUPLEX | BMCR_100MBPS); PHY_WRITE_2( sc, DP83840_BMCR, media); PHY_READ_2( sc, DP83840_BMSR ); i = PHY_READ_2( sc, DP83840_BMSR ); if (i & BMSR_LINK_STATUS) { /*port is linked to the non * Auto-Negotiation10Mbs partner */ return EPIC_HALF_DUPLEX; } } } /* If we get here we are most likely not connected * so lets default it to half duplex */ return EPIC_HALF_DUPLEX; } }/* */static voidepic_set_tx_mode ( epic_softc_t *sc ){ if( sc->txcon & TXCON_EARLY_TRANSMIT_ENABLE ) CSR_WRITE_4( sc, ETXTHR, sc->tx_threshold ); CSR_WRITE_4( sc, TXCON, sc->txcon );}/* * Synopsis: This function should update multicast hash table. * I suppose there is a bug in chips MC filter so this function * only set it to receive all MC packets. The second problem is * that we should wait for TX and RX processes to stop before * reprogramming MC filter. The epic_stop_activity() and * epic_start_activity() should help to do this. */static voidepic_set_mc_table ( epic_softc_t * sc){ struct ifnet *ifp = &sc->sc_if; if( ifp->if_flags & IFF_MULTICAST ){ CSR_WRITE_4( sc, MC0, 0xFFFF ); CSR_WRITE_4( sc, MC1, 0xFFFF ); CSR_WRITE_4( sc, MC2, 0xFFFF ); CSR_WRITE_4( sc, MC3, 0xFFFF ); } return;}/* * Synopsis: Start receive process and transmit one, if they need. */static voidepic_start_activity __P(( epic_softc_t * sc)){ /* Start rx process */ CSR_WRITE_4(sc, COMMAND, COMMAND_RXQUEUED | COMMAND_START_RX | (sc->pending_txs?COMMAND_TXQUEUED:0)); dprintf((EPIC_FORMAT ": activity started\n",EPIC_ARGS(sc)));}/* * Synopsis: Completely stop Rx and Tx processes. If TQE is set additional * packet needs to be queued to stop Tx DMA. */static voidepic_stop_activity __P(( epic_softc_t * sc)){ int i; /* Stop Tx and Rx DMA */ CSR_WRITE_4(sc,COMMAND,COMMAND_STOP_RX|COMMAND_STOP_RDMA|COMMAND_STOP_TDMA); /* Wait Rx and Tx DMA to stop (why 1 ms ??? XXX) */ dprintf((EPIC_FORMAT ": waiting Rx and Tx DMA to stop\n",EPIC_ARGS(sc))); for(i=0;i<0x1000;i++) { if((CSR_READ_4(sc,INTSTAT) & (INTSTAT_TXIDLE | INTSTAT_RXIDLE)) == (INTSTAT_TXIDLE | INTSTAT_RXIDLE) ) break; DELAY(1); } if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_RXIDLE) ) printf(EPIC_FORMAT ": can't stop Rx DMA\n",EPIC_ARGS(sc)); if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) ) printf(EPIC_FORMAT ": can't stop Tx DMA\n",EPIC_ARGS(sc)); /* Catch all finished packets */ epic_rx_done(sc); epic_tx_done(sc); /* * May need to queue one more packet if TQE, this is rare but existing * case. */ if( (CSR_READ_4( sc, INTSTAT ) & INTSTAT_TQE) && !(CSR_READ_4( sc, INTSTAT ) & INTSTAT_TXIDLE) ) { struct epic_tx_desc *desc; struct epic_frag_list *flist; struct epic_tx_buffer *buf; struct mbuf *m0; dprintf((EPIC_FORMAT ": queue last packet\n",EPIC_ARGS(sc))); desc = sc->tx_desc + sc->cur_tx; flist = sc->tx_flist + sc->cur_tx; buf = sc->tx_buffer + sc->cur_tx; if ((desc->status & 0x8000) || (buf->mbuf != NULL)) return; MGETHDR(m0,M_DONTWAIT,MT_DATA); if (NULL == m0) return; /* Prepare mbuf */ m0->m_len = min(MHLEN,ETHER_MIN_LEN-ETHER_CRC_LEN); flist->frag[0].fraglen = m0->m_len; m0->m_pkthdr.len = m0->m_len; m0->m_pkthdr.rcvif = &sc->sc_if; bzero(mtod(m0,caddr_t),m0->m_len); /* Fill fragments list */ flist->frag[0].fraglen = m0->m_len; flist->frag[0].fragaddr = vtophys( mtod(m0, caddr_t) ); flist->numfrags = 1; /* Fill in descriptor */ buf->mbuf = m0; sc->pending_txs++; sc->cur_tx = (sc->cur_tx + 1) & TX_RING_MASK; desc->control = 0x01; desc->txlength = max(m0->m_pkthdr.len,ETHER_MIN_LEN-ETHER_CRC_LEN); desc->status = 0x8000; /* Launch transmition */ CSR_WRITE_4(sc, COMMAND, COMMAND_STOP_TDMA | COMMAND_TXQUEUED); /* Wait Tx DMA to stop (for how long??? XXX) */ dprintf((EPIC_FORMAT ": waiting Tx DMA to stop\n",EPIC_ARGS(sc))); for(i=0;i<1000;i++) { if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) == INTSTAT_TXIDLE ) break; DELAY(1); } if( !(CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) ) printf(EPIC_FORMAT ": can't stop TX DMA\n",EPIC_ARGS(sc)); else epic_tx_done(sc); } dprintf((EPIC_FORMAT ": activity stoped\n",EPIC_ARGS(sc)));}/* * Synopsis: Shut down board and deallocates rings. * * splimp() invoked here */static voidepic_stop __P(( epic_softc_t * sc)){ int s; s = splimp(); sc->sc_if.if_timer = 0; /* Disable interrupts */ CSR_WRITE_4( sc, INTMASK, 0 ); CSR_WRITE_4( sc, GENCTL, 0 ); /* Try to stop Rx and TX processes */ epic_stop_activity(sc); /* Reset chip */ CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET ); DELAY(1000); /* Make chip go to bed */ CSR_WRITE_4(sc, GENCTL, GENCTL_POWER_DOWN); /* Free memory allocated for rings */ epic_free_rings(sc); /* Mark as stoped */ sc->sc_if.if_flags &= ~IFF_RUNNING; splx(s); return;}/* * Synopsis: This function should free all memory allocated for rings. */ static voidepic_free_rings __P(( epic_softc_t * sc)){ int i; for(i=0;i<RX_RING_SIZE;i++){ struct epic_rx_buffer *buf = sc->rx_buffer + i; struct epic_rx_desc *desc = sc->rx_desc + i; desc->status = 0; desc->buflength = 0; desc->bufaddr = 0; if( buf->mbuf ) m_freem( buf->mbuf ); buf->mbuf = NULL; } for(i=0;i<TX_RING_SIZE;i++){ struct epic_tx_buffer *buf = sc->tx_buffer + i; struct epic_tx_desc *desc = sc->tx_desc + i; desc->status = 0; desc->buflength = 0; desc->bufaddr = 0; if( buf->mbuf ) m_freem( buf->mbuf ); buf->mbuf = NULL; }}/* * Synopsis: Allocates mbufs for Rx ring and point Rx descs to them. * Point Tx descs to fragment lists. Check that all descs and fraglists * are bounded and aligned properly. */static intepic_init_rings(epic_softc_t * sc){ int i; sc->cur_rx = sc->cur_tx = sc->dirty_tx = sc->pending_txs = 0; for (i = 0; i < RX_RING_SIZE; i++) { struct epic_rx_buffer *buf = sc->rx_buffer + i; struct epic_rx_desc *desc = sc->rx_desc + i; desc->status = 0; /* Owned by driver */ desc->next = vtophys( sc->rx_desc + ((i+1) & RX_RING_MASK) ); if( (desc->next & 3) || ((desc->next & 0xFFF) + sizeof(struct epic_rx_desc) > 0x1000 ) ) printf(EPIC_FORMAT ": WARNING! rx_desc is misbound or misaligned\n",EPIC_ARGS(sc)); EPIC_MGETCLUSTER( buf->mbuf ); if( NULL == buf->mbuf ) { epic_free_rings(sc); return -1; } desc->bufaddr = vtophys( mtod(buf->mbuf,caddr_t) ); desc->buflength = ETHER_MAX_FRAME_LEN; desc->status = 0x8000; /* Give to EPIC */ } for (i = 0; i < TX_RING_SIZE; i++) { struct epic_tx_buffer *buf = sc->tx_buffer + i; struct epic_tx_desc *desc = sc->tx_desc + i; desc->status = 0; desc->next = vtophys( sc->tx_desc + ( (i+1) & TX_RING_MASK ) ); if( (desc->next & 3) || ((desc->next & 0xFFF) + sizeof(struct epic_tx_desc) > 0x1000 ) ) printf(EPIC_FORMAT ": WARNING! tx_desc is misbound or misaligned\n",EPIC_ARGS(sc)); buf->mbuf = NULL; desc->bufaddr = vtophys( sc->tx_flist + i ); if( (desc->bufaddr & 3) || ((desc->bufaddr & 0xFFF) + sizeof(struct epic_frag_list) > 0x1000 ) ) printf(EPIC_FORMAT ": WARNING! frag_list is misbound or misaligned\n",EPIC_ARGS(sc)); } return 0;}/* * EEPROM operation functions */static void epic_write_eepromreg __P(( epic_softc_t *sc, u_int8_t val)){ u_int16_t i; CSR_WRITE_1( sc, EECTL, val ); for (i=0; i<0xFF; i++) if( !(CSR_READ_1( sc, EECTL ) & 0x20) ) break; return;}static u_int8_tepic_read_eepromreg __P(( epic_softc_t *sc)){ return CSR_READ_1( sc,EECTL );} static u_int8_tepic_eeprom_clock __P(( epic_softc_t *sc, u_int8_t val)){ epic_write_eepromreg( sc, val ); epic_write_eepromreg( sc, (val | 0x4) ); epic_write_eepromreg( sc, val ); return epic_read_eepromreg( sc );}static voidepic_output_eepromw __P(( epic_softc_t * sc, u_int16_t val)){ int i; for( i = 0xF; i >= 0; i--){ if( (val & (1 << i)) ) epic_eeprom_clock( sc, 0x0B ); else epic_eeprom_clock( sc, 3); }}static u_int16_tepic_input_eepromw __P(( epic_softc_t *sc)){ int i; int tmp; u_int16_t retval = 0; for( i = 0xF; i >= 0; i--) { tmp = epic_eeprom_clock( sc, 0x3 ); if( tmp & 0x10 ){ retval |= (1 << i); } } return retval;}static intepic_read_eeprom __P(( epic_softc_t *sc, u_int16_t loc)){ u_int16_t dataval; u_int16_t read_cmd; epic_write_eepromreg( sc , 3); if( epic_read_eepromreg( sc ) & 0x40 ) read_cmd = ( loc & 0x3F ) | 0x180; else read_cmd = ( loc & 0xFF ) | 0x600; epic_output_eepromw( sc, read_cmd ); dataval = epic_input_eepromw( sc ); epic_write_eepromreg( sc, 1 ); return dataval;}static u_int16_tepic_read_phy_register __P(( epic_softc_t *sc, u_int16_t loc)){ int i; CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0601) ); for (i=0;i<0x100;i++) { if( !(CSR_READ_4( sc, MIICTL )&1) ) break; DELAY(1); } return CSR_READ_4( sc, MIIDATA );}static voidepic_write_phy_register __P(( epic_softc_t * sc, u_int16_t loc, u_int16_t val)){ int i; CSR_WRITE_4( sc, MIIDATA, val ); CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0602) ); for( i=0;i<0x100;i++) { if( !(CSR_READ_4( sc, MIICTL )&2) ) break; DELAY(1); } return;}static voidepic_dump_state __P(( epic_softc_t * sc)){ int j; struct epic_tx_desc *tdesc; struct epic_rx_desc *rdesc; printf(EPIC_FORMAT ": cur_rx: %d, pending_txs: %d, dirty_tx: %d, cur_tx: %d\n", EPIC_ARGS(sc),sc->cur_rx,sc->pending_txs,sc->dirty_tx,sc->cur_tx); printf(EPIC_FORMAT ": COMMAND: 0x%08x, INTSTAT: 0x%08x\n",EPIC_ARGS(sc),CSR_READ_4(sc,COMMAND),CSR_READ_4(sc,INTSTAT)); printf(EPIC_FORMAT ": PRCDAR: 0x%08x, PTCDAR: 0x%08x\n",EPIC_ARGS(sc),CSR_READ_4(sc,PRCDAR),CSR_READ_4(sc,PTCDAR)); printf(EPIC_FORMAT ": dumping rx descriptors\n",EPIC_ARGS(sc)); for(j=0;j<RX_RING_SIZE;j++){ rdesc = sc->rx_desc + j; printf("desc%d: %4d 0x%04x, 0x%08x, %4d, 0x%08x\n", j, rdesc->rxlength,rdesc->status, rdesc->bufaddr, rdesc->buflength, rdesc->next ); } printf(EPIC_FORMAT ": dumping tx descriptors\n",EPIC_ARGS(sc)); for(j=0;j<TX_RING_SIZE;j++){ tdesc = sc->tx_desc + j; printf( "desc%d: %4d 0x%04x, 0x%08lx, 0x%04x %4u, 0x%08lx, mbuf: %p\n", j, tdesc->txlength,tdesc->status, (u_long)tdesc->bufaddr, tdesc->control,tdesc->buflength, (u_long)tdesc->next, (void *)sc->tx_buffer[j].mbuf ); }}#endif /* NPCI > 0 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -