diff options
author | Jason Wright <jason@cvs.openbsd.org> | 1999-03-16 04:26:40 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 1999-03-16 04:26:40 +0000 |
commit | 9b41976f45bafa7577055c499b0954baa83da50e (patch) | |
tree | 019725b644f6b1eab292bf5d2fd6094c89708d80 /sys/dev/pci/if_tx.c | |
parent | 9df8f50123314ed6e917908c8abbab15f2ec3163 (diff) |
merge with freesbd:
o put media types in a structure for ifmedia adding
o make sure ifp->if_snd.ifq_maxlen is initialized
o add workaround for app note 7-15
o more checks for IFF_UP
o use DELAY() instead of counters
Diffstat (limited to 'sys/dev/pci/if_tx.c')
-rw-r--r-- | sys/dev/pci/if_tx.c | 326 |
1 files changed, 228 insertions, 98 deletions
diff --git a/sys/dev/pci/if_tx.c b/sys/dev/pci/if_tx.c index 6453a677ae4..a414641f819 100644 --- a/sys/dev/pci/if_tx.c +++ b/sys/dev/pci/if_tx.c @@ -1,5 +1,5 @@ -/* $OpenBSD: if_tx.c,v 1.5 1999/03/10 20:04:13 jason Exp $ */ -/* $FreeBSD: if_tx.c,v 1.21 1999/03/09 17:30:12 andreas Exp $ */ +/* $OpenBSD: if_tx.c,v 1.6 1999/03/16 04:26:39 jason Exp $ */ +/* $FreeBSD: if_tx.c,v 1.22 1999/03/14 08:30:23 semenu Exp $ */ /*- * Copyright (c) 1997 Semen Ustimenko (semen@iclub.nsu.ru) @@ -178,12 +178,29 @@ static void epic_write_eepromreg __P((epic_softc_t *,u_int8_t)); static u_int8_t epic_read_eepromreg __P((epic_softc_t *)); static u_int16_t epic_read_phy_register __P((epic_softc_t *, u_int16_t)); static void epic_write_phy_register __P((epic_softc_t *, u_int16_t, u_int16_t)); +void epic_dump_phy_regs __P((epic_softc_t *)); #if !defined(EPIC_NOIFMEDIA) static int epic_ifmedia_change __P((struct ifnet *)); static void epic_ifmedia_status __P((struct ifnet *, struct ifmediareq *)); #endif +int epic_mtypes [] = { + IFM_ETHER | IFM_10_T, + IFM_ETHER | IFM_10_T | IFM_FDX, + IFM_ETHER | IFM_100_TX, + IFM_ETHER | IFM_100_TX | IFM_FDX, + IFM_ETHER | IFM_10_T | IFM_LOOP, + IFM_ETHER | IFM_10_T | IFM_FDX | IFM_LOOP, + IFM_ETHER | IFM_10_T | IFM_LOOP | IFM_FLAG1, + IFM_ETHER | IFM_100_TX | IFM_LOOP, + IFM_ETHER | IFM_100_TX | IFM_LOOP | IFM_FLAG1, + IFM_ETHER | IFM_100_TX | IFM_FDX | IFM_LOOP, + IFM_ETHER | IFM_AUTO +}; +#define EPIC_MTYPESNUM (sizeof(epic_mtypes) / sizeof(epic_mtypes[0])) + + /* ------------------------------------------------------------------------- OS-specific part ------------------------------------------------------------------------- */ @@ -326,14 +343,10 @@ epic_openbsd_attach( /* Init ifmedia interface */ #if !defined(EPIC_NOIFMEDIA) ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL); + + for (i=0; i<EPIC_MTYPESNUM; i++) + ifmedia_add(&sc->ifmedia,epic_mtypes[i],0,NULL); + ifmedia_set(&sc->ifmedia, tmp); #endif @@ -432,6 +445,7 @@ epic_freebsd_attach( ifp->if_init = (if_init_f_t*)epic_init; ifp->if_timer = 0; ifp->if_output = ether_output; + ifp->if_snd.ifq_maxlen = TX_RING_SIZE; /* Get iobase or membase */ #if defined(EPIC_USEIOSPACE) @@ -512,14 +526,10 @@ epic_freebsd_attach( /* Init ifmedia interface */ #if !defined(EPIC_NOIFMEDIA) ifmedia_init(&sc->ifmedia,0,epic_ifmedia_change,epic_ifmedia_status); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_10_T|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_LOOP,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_100_TX|IFM_FDX,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_AUTO,0,NULL); - ifmedia_add(&sc->ifmedia,IFM_ETHER|IFM_LOOP,0,NULL); + + for (i=0; i<EPIC_MTYPESNUM; i++) + ifmedia_add(&sc->ifmedia,epic_mtypes[i],0,NULL); + ifmedia_set(&sc->ifmedia, tmp); #endif @@ -639,6 +649,8 @@ epic_ifioctl __P(( } } + epic_stop_activity(sc); + /* Handle IFF_PROMISC flag */ epic_set_rx_mode(sc); @@ -646,6 +658,7 @@ epic_ifioctl __P(( /* Handle IFF_LINKx flags */ epic_set_media_speed(sc); #endif + epic_start_activity(sc); break; case SIOCADDMULTI: @@ -719,8 +732,8 @@ epic_common_attach( /* Bring the chip out of low-power mode. */ CSR_WRITE_4( sc, GENCTL, 0x0000 ); - /* Magic?! If we don't set this bit the MII interface won't work. */ - CSR_WRITE_4( sc, TEST1, 0x0008 ); + /* Workaround for Application Note 7-15 */ + for (i=0; i<16; i++) CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST); /* Read mac address from EEPROM */ for (i = 0; i < ETHER_ADDR_LEN / sizeof(u_int16_t); i++) @@ -753,6 +766,7 @@ epic_ifstart(struct ifnet * const ifp){ register struct mbuf *m; register int i; +#if 0 /* If no link is established, simply free all mbufs in queue */ PHY_READ_2( sc, DP83840_BMSR ); if( !(BMSR_LINK_STATUS & PHY_READ_2( sc, DP83840_BMSR )) ){ @@ -763,6 +777,7 @@ epic_ifstart(struct ifnet * const ifp){ } return; } +#endif /* Link is OK, queue packets to NIC */ while( sc->pending_txs < TX_RING_SIZE ){ @@ -783,7 +798,7 @@ epic_ifstart(struct ifnet * const ifp){ } if( buf->mbuf ) { - dprintf((EPIC_FORMAT ": mbuf not freed in ifstart, up and down interface plase\n",EPIC_ARGS(sc))); + dprintf((EPIC_FORMAT ": mbuf not freed in ifstart, up and down interface please\n",EPIC_ARGS(sc))); break; } @@ -928,7 +943,7 @@ epic_rx_done __P(( * Synopsis: Do last phase of transmission. I.e. if desc is * transmitted, decrease pending_txs counter, free mbuf contained * packet, switch to next descriptor and repeat until no packets - * are pending or descriptro is not transmitted yet. + * are pending or descriptor is not transmitted yet. */ static __inline void epic_tx_done __P(( @@ -1020,14 +1035,14 @@ epic_intr ( if( phystatus & INTSTAT_AN_COMPLETE ) { u_int32_t bmcr; if( epic_autoneg(sc) == EPIC_FULL_DUPLEX ) { + dprintf((EPIC_FORMAT ": going fullduplex\n",EPIC_ARGS(sc))); bmcr = BMCR_FULL_DUPLEX | PHY_READ_2( sc, DP83840_BMCR ); sc->txcon |= TXCON_FULL_DUPLEX; - CSR_WRITE_4( sc, TXCON, sc->txcon ); } else { /* Default to half-duplex */ + dprintf((EPIC_FORMAT ": going halfduplex\n",EPIC_ARGS(sc))); bmcr = ~BMCR_FULL_DUPLEX & PHY_READ_2( sc, DP83840_BMCR ); sc->txcon &= ~TXCON_FULL_DUPLEX; - CSR_WRITE_4( sc, TXCON, sc->txcon ); } /* There is apparently QS6612 chip bug: */ @@ -1035,6 +1050,10 @@ epic_intr ( /* autonegotiation process, so update it by hands */ /* so we can rely on it in epic_ifmedia_status() */ PHY_WRITE_2( sc, DP83840_BMCR, bmcr ); + + epic_stop_activity(sc); + epic_set_tx_mode(sc); + epic_start_activity(sc); } PHY_READ_2(sc, DP83840_BMSR); @@ -1087,13 +1106,11 @@ epic_intr ( dprintf((EPIC_FORMAT ": TX underrun error, tx threshold increased to %d\n",EPIC_ARGS(sc),sc->tx_threshold)); } + CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO | COMMAND_TXQUEUED); epic_stop_activity(sc); epic_set_tx_mode(sc); epic_start_activity(sc); sc->sc_if.if_oerrors++; - - /* Restart the transmit process. */ - /* CSR_WRITE_4(sc, COMMAND, COMMAND_TXUGO|COMMAND_TXQUEUED); */ } } } @@ -1159,7 +1176,12 @@ epic_ifmedia_change __P(( if (IFM_TYPE(sc->ifmedia.ifm_media) != IFM_ETHER) return (EINVAL); + if (!(ifp->if_flags & IFF_UP)) + return (0); + + epic_stop_activity(sc); epic_set_media_speed(sc); + epic_start_activity(sc); return 0; } @@ -1173,6 +1195,9 @@ epic_ifmedia_status __P(( u_int32_t bmcr; u_int32_t bmsr; + if (!(ifp->if_flags & IFF_UP)) + return; + bmcr = PHY_READ_2( sc, DP83840_BMCR ); PHY_READ_2( sc, DP83840_BMSR ); @@ -1188,9 +1213,13 @@ epic_ifmedia_status __P(( } ifmr->ifm_status |= IFM_ACTIVE; - ifmr->ifm_active |= (bmcr&BMCR_100MBPS)?IFM_100_TX:IFM_10_T; - ifmr->ifm_active |= (bmcr&BMCR_FULL_DUPLEX)?IFM_FDX:0; - ifmr->ifm_active |= ((CSR_READ_4(sc,TXCON)&TXCON_LOOPBACK_MODE)==TXCON_LOOPBACK_MODE_INT)?IFM_LOOP:0; + ifmr->ifm_active |= (bmcr & BMCR_100MBPS) ? IFM_100_TX : IFM_10_T; + ifmr->ifm_active |= (bmcr & BMCR_FULL_DUPLEX) ? IFM_FDX : 0; + if ((sc->txcon & TXCON_LOOPBACK_MODE) == TXCON_LOOPBACK_MODE_INT) + ifmr->ifm_active |= (IFM_LOOP | IFM_FLAG1); + else if ((sc->txcon & TXCON_LOOPBACK_MODE) == TXCON_LOOPBACK_MODE_PHY) + ifmr->ifm_active |= IFM_LOOP; + } #endif @@ -1204,21 +1233,25 @@ epic_init __P(( epic_softc_t * sc)) { struct ifnet *ifp = &sc->sc_if; - int s; + int s,i; s = splimp(); - /* Soft reset the chip */ + /* Soft reset the chip (we have to power up card before) */ + CSR_WRITE_4( sc, GENCTL, 0 ); CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET ); - /* Reset takes 15 pci ticks which depends on processor speed */ - DELAY(1); + /* + * Reset takes 15 pci ticks which depends on PCI bus speed. + * Assuming it >= 33000000 hz, we have wait at least 495e-6 sec. + */ + DELAY(500); /* Wake up */ CSR_WRITE_4( sc, GENCTL, 0 ); - /* ?????? */ - CSR_WRITE_4( sc, TEST1, 0x0008); + /* Workaround for Application Note 7-15 */ + for (i=0; i<16; i++) CSR_WRITE_4(sc, TEST1, TEST1_CLOCK_TEST); /* Initialize rings */ if( epic_init_rings( sc ) ) { @@ -1242,10 +1275,6 @@ epic_init __P(( /* Compute and set RXCON. */ epic_set_rx_mode( sc ); - /* Set media speed mode */ - epic_init_phy( sc ); - epic_set_media_speed( sc ); - /* Set multicast table */ epic_set_mc_table( sc ); @@ -1261,6 +1290,9 @@ epic_init __P(( GENCTL_ENABLE_INTERRUPT | GENCTL_MEMORY_READ_MULTIPLE | GENCTL_ONECOPY | GENCTL_RECEIVE_FIFO_THRESHOLD64 ); + /* Set media speed mode */ + epic_set_media_speed( sc ); + /* Mark interface running ... */ if( ifp->if_flags & IFF_UP ) ifp->if_flags |= IFF_RUNNING; else ifp->if_flags &= ~IFF_RUNNING; @@ -1276,7 +1308,8 @@ epic_init __P(( } /* - * Synopsis: calculate and set Rx mode + * Synopsis: calculate and set Rx mode. Chip must be in idle state to + * access RXCON. */ static void epic_set_rx_mode( @@ -1292,6 +1325,20 @@ epic_set_rx_mode( return; } +void +epic_dump_phy_regs(epic_softc_t *sc) { + + printf("BMCR: 0x%04x\n", PHY_READ_2(sc, DP83840_BMCR)); + printf("BMSR: 0x%04x\n", PHY_READ_2(sc, DP83840_BMSR)); + printf("ANAR: 0x%04x\n", PHY_READ_2(sc, DP83840_ANAR)); + printf("LPAR: 0x%04x\n", PHY_READ_2(sc, DP83840_LPAR)); + printf("ANER: 0x%04x\n", PHY_READ_2(sc, DP83840_ANER)); + printf("MCTL: 0x%04x\n", PHY_READ_2(sc, QS6612_MCTL)); + printf("INTSTAT: 0x%04x\n", PHY_READ_2(sc, QS6612_INTSTAT)); + printf("INTMASK: 0x%04x\n", PHY_READ_2(sc, QS6612_INTMASK)); + printf("BPCR: 0x%04x\n", PHY_READ_2(sc, QS6612_BPCR)); +} + /* * Synopsis: Reset PHY and do PHY-special initialization: */ @@ -1301,24 +1348,38 @@ epic_init_phy __P(( { u_int32_t i; - /* Reset PHY */ - PHY_WRITE_2( sc, DP83840_BMCR, BMCR_RESET ); - for(i=0;i<0x100000;i++) - if( !(PHY_READ_2( sc, DP83840_BMCR ) & BMCR_RESET) ) break; + /* Reset PHY (We have to take the delay from manual XXX) */ + PHY_WRITE_2(sc, DP83840_BMCR, BMCR_RESET); + DELAY(10); + for(i=0;i<0x1000;i++) { + if( !(PHY_READ_2(sc, DP83840_BMCR) & BMCR_RESET) ) + break; + DELAY(1); + } + + if( PHY_READ_2(sc, DP83840_BMCR) & BMCR_RESET ) + printf(EPIC_FORMAT ": WARNING! cant reset PHY\n",EPIC_ARGS(sc)); - if( PHY_READ_2( sc, DP83840_BMCR ) & BMCR_RESET ) - printf(EPIC_FORMAT ": WARNING! cannot reset PHY\n",EPIC_ARGS(sc)); + PHY_WRITE_2(sc, DP83840_BMCR, 0 ); + PHY_WRITE_2(sc, DP83840_BMCR, BMCR_LOOPBACK | BMCR_ISOLATE ); switch( sc->phyid ){ - case QS6612_OUI: - /* Init QS6612 and EPIC to generate interrupt when AN complete*/ - CSR_WRITE_4( sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE ); - PHY_READ_2( sc, QS6612_INTSTAT ); - PHY_WRITE_2( sc, QS6612_INTMASK, INTMASK_THUNDERLAN | INTSTAT_AN_COMPLETE | INTSTAT_LINK_STATUS ); + case QS6612_OUI: { + /* Init QS6612 and EPIC to generate interrupt */ + CSR_WRITE_4(sc, NVCTL, NVCTL_GP1_OUTPUT_ENABLE | NVCTL_GP1); + + /* Mask interrupts sources */ + PHY_WRITE_2(sc, QS6612_INTMASK, + PHY_READ_2(sc, QS6612_INTSTAT) | + INTMASK_THUNDERLAN | INTSTAT_AN_COMPLETE | + INTSTAT_LINK_STATUS ); /* Enable QS6612 extended cable length capabilites */ - PHY_WRITE_2( sc, QS6612_MCTL, PHY_READ_2( sc,QS6612_MCTL ) | MCTL_BTEXT ); + /* PHY_WRITE_2(sc, QS6612_MCTL, */ + /* PHY_READ_2(sc, QS6612_MCTL) | MCTL_BTEXT); */ + break; + } default: break; } @@ -1326,40 +1387,52 @@ epic_init_phy __P(( /* * Synopsis: Set PHY to media type specified by IFF_LINK* flags or - * ifmedia structure. + * ifmedia structure. Chip must be in idle state to access TXCON. */ static void epic_set_media_speed __P(( epic_softc_t * sc)) { u_int16_t media; - #if !defined(EPIC_NOIFMEDIA) u_int32_t tgtmedia = sc->ifmedia.ifm_cur->ifm_media; +#endif + + epic_init_phy(sc); +#if !defined(EPIC_NOIFMEDIA) if( IFM_SUBTYPE(tgtmedia) != IFM_AUTO ){ + /* Clean previous values */ + sc->txcon &= ~(TXCON_LOOPBACK_MODE | TXCON_FULL_DUPLEX); + media = 0; + /* Set mode */ - media = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX) ? BMCR_100MBPS : 0; - media|= (tgtmedia&IFM_FDX) ? BMCR_FULL_DUPLEX : 0; + media |= (IFM_SUBTYPE(tgtmedia)==IFM_100_TX) ? BMCR_100MBPS : 0; + if (tgtmedia & IFM_FDX) { + media |= BMCR_FULL_DUPLEX; + sc->txcon |= TXCON_FULL_DUPLEX; + } + if (tgtmedia & IFM_LOOP) { + if (tgtmedia & IFM_FLAG1) + sc->txcon |= TXCON_LOOPBACK_MODE_INT; + else { + media |= BMCR_LOOPBACK | BMCR_ISOLATE; + sc->txcon |= TXCON_LOOPBACK_MODE_PHY; + } + } sc->sc_if.if_baudrate = (IFM_SUBTYPE(tgtmedia)==IFM_100_TX)?100000000:10000000; PHY_WRITE_2( sc, DP83840_BMCR, media ); - - if( tgtmedia & IFM_FDX ) sc->txcon |= TXCON_FULL_DUPLEX; - else sc->txcon &= ~TXCON_FULL_DUPLEX; - if( tgtmedia & IFM_LOOP ) sc->txcon |= TXCON_LOOPBACK_MODE_INT; - else sc->txcon &= ~TXCON_LOOPBACK_MODE_INT; - - CSR_WRITE_4( sc, TXCON, sc->txcon ); } #else /* EPIC_NOIFMEDIA */ struct ifnet *ifp = &sc->sc_if; if( ifp->if_flags & IFF_LINK0 ) { /* Set mode */ - media = (ifp->if_flags & IFF_LINK2) ? BMCR_100MBPS : 0; + media = 0; + media|= (ifp->if_flags & IFF_LINK2) ? BMCR_100MBPS : 0; media|= (ifp->if_flags & IFF_LINK1) ? BMCR_FULL_DUPLEX : 0; sc->sc_if.if_baudrate = @@ -1380,8 +1453,9 @@ epic_set_media_speed __P(( CSR_WRITE_4(sc, TXCON, sc->txcon); /* Set and restart autoneg */ - PHY_WRITE_2( sc, DP83840_BMCR, - BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG ); + PHY_WRITE_2(sc, DP83840_BMCR, BMCR_AUTONEGOTIATION ); + PHY_WRITE_2(sc, DP83840_BMCR, + BMCR_AUTONEGOTIATION | BMCR_RESTART_AUTONEG); /* If it is not QS6612 PHY, try to get result of autoneg. */ if( QS6612_OUI != sc->phyid ) { @@ -1399,6 +1473,8 @@ epic_set_media_speed __P(( /* Else it will be done when GP2 int occured */ } + epic_set_tx_mode(sc); + return; } @@ -1519,14 +1595,17 @@ epic_set_mc_table ( /* - * Synopsis: Start receive process and transmit, if need + * Synopsis: Start receive process and transmit one, if they need. */ static void epic_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)); + /* 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))); } /* @@ -1539,54 +1618,90 @@ epic_stop_activity __P(( { int i; - /* Turn it to loopback mode */ - CSR_WRITE_4( sc, TXCON, TXCON_SLOT_TIME|TXCON_LOOPBACK_MODE_INT ); - /* Stop Tx and Rx DMA */ CSR_WRITE_4(sc,COMMAND,COMMAND_STOP_RX|COMMAND_STOP_RDMA|COMMAND_STOP_TDMA); - /* Wait only Rx DMA */ - dprintf((EPIC_FORMAT ": waiting Rx DMA to stop\n",EPIC_ARGS(sc))); + /* 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_RXIDLE) == INTSTAT_RXIDLE ) + 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)); + 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)); - /* May need to queue one more packet if TQE */ + /* 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) ){ + !(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))); - sc->tx_desc[sc->cur_tx].bufaddr = vtophys( sc ); - sc->tx_desc[sc->cur_tx].buflength = ETHER_MIN_LEN-ETHER_CRC_LEN; - sc->tx_desc[sc->cur_tx].control = 0x14; - sc->tx_desc[sc->cur_tx].txlength = ETHER_MIN_LEN-ETHER_CRC_LEN; - sc->tx_desc[sc->cur_tx].status = 0x8000; - sc->cur_tx = (sc->cur_tx + 1) & TX_RING_MASK; + 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; - CSR_WRITE_4( sc, COMMAND, COMMAND_TXQUEUED ); + /* 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))); - /* Wait TX DMA to stop */ - for(i=0;i<0x1000;i++) { - if( (CSR_READ_4(sc,INTSTAT)&INTSTAT_TXIDLE) == INTSTAT_TXIDLE ) { - sc->pending_txs--; + 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)); - - /* Restore old TX state */ - CSR_WRITE_4( sc, TXCON, sc->txcon ); + else + epic_tx_done(sc); } + + dprintf((EPIC_FORMAT ": activity stoped\n",EPIC_ARGS(sc))); } /* @@ -1613,7 +1728,10 @@ epic_stop __P(( /* Reset chip */ CSR_WRITE_4( sc, GENCTL, GENCTL_SOFT_RESET ); - DELAY(10); + DELAY(1000); + + /* Make chip go to bed */ + CSR_WRITE_4(sc, GENCTL, GENCTL_POWER_DOWN); /* Free memory allocated for rings */ epic_free_rings(sc); @@ -1722,7 +1840,7 @@ static void epic_write_eepromreg __P(( CSR_WRITE_1( sc, EECTL, val ); - for( i=0;i<0xFF; i++) + for (i=0; i<0xFF; i++) if( !(CSR_READ_1( sc, EECTL ) & 0x20) ) break; return; @@ -1809,7 +1927,10 @@ epic_read_phy_register __P(( CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0601) ); - for( i=0;i<0x100000;i++) if( !(CSR_READ_4( sc, MIICTL )&1) ) break; + for (i=0;i<0x100;i++) { + if( !(CSR_READ_4( sc, MIICTL )&1) ) break; + DELAY(1); + } return CSR_READ_4( sc, MIIDATA ); } @@ -1825,7 +1946,10 @@ epic_write_phy_register __P(( CSR_WRITE_4( sc, MIIDATA, val ); CSR_WRITE_4( sc, MIICTL, ((loc << 4) | 0x0602) ); - for( i=0;i<0x100000;i++) if( !(CSR_READ_4( sc, MIICTL )&2) ) break; + for( i=0;i<0x100;i++) { + if( !(CSR_READ_4( sc, MIICTL )&2) ) break; + DELAY(1); + } return; } @@ -1865,4 +1989,10 @@ epic_dump_state __P(( ); } } +#if 0 +static void epic_kldinit (void * a) { + pci_register_lkm (&txdevice, 0); +} +PSEUDO_SET(epic_kldinit,if_tx); +#endif #endif /* NPCI > 0 */ |