summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authorsemenu <semenu@FreeBSD.org>1999-03-14 08:30:23 +0000
committersemenu <semenu@FreeBSD.org>1999-03-14 08:30:23 +0000
commite557c4ccfc57fb0bbc3f8938b5efa11b7b19c607 (patch)
treef54f40864a258c41ae43771aba14934f80ee7cfc /sys/pci
parentaa8bb4e29a4095203d5a8e1b785b17a441f4903c (diff)
downloadFreeBSD-src-e557c4ccfc57fb0bbc3f8938b5efa11b7b19c607.zip
FreeBSD-src-e557c4ccfc57fb0bbc3f8938b5efa11b7b19c607.tar.gz
Implemented workaround for EPIC's Application Note 7-15 (concerning
chip int. and ext. clock synchronisation). Fixed workaround for transmit threshold underrun. Added volatile keyword to CSR_READ_* and CSR_WRITE_* macroses. Added DELAYs to eliminate randomness caused by processor speed. Fixed all TXCON and RXCON registers to be accessed only when chip is idle, as manual told. Changed epic_init_phy to drop link by isolating and going loopback, should should force link partner to restart autonegotiation. PR: kern/10535, kern/9742, kern/10575 Submitted by: Peter Jeremy, David Greenman
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/if_tx.c321
-rw-r--r--sys/pci/if_txvar.h23
2 files changed, 241 insertions, 103 deletions
diff --git a/sys/pci/if_tx.c b/sys/pci/if_tx.c
index 1519ba4..b6b7fc9 100644
--- a/sys/pci/if_tx.c
+++ b/sys/pci/if_tx.c
@@ -183,6 +183,22 @@ 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
------------------------------------------------------------------------- */
@@ -325,14 +341,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
@@ -431,6 +443,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)
@@ -511,14 +524,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
@@ -638,6 +647,8 @@ epic_ifioctl __P((
}
}
+ epic_stop_activity(sc);
+
/* Handle IFF_PROMISC flag */
epic_set_rx_mode(sc);
@@ -645,6 +656,7 @@ epic_ifioctl __P((
/* Handle IFF_LINKx flags */
epic_set_media_speed(sc);
#endif
+ epic_start_activity(sc);
break;
case SIOCADDMULTI:
@@ -718,8 +730,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++)
@@ -752,6 +764,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 )) ){
@@ -762,6 +775,7 @@ epic_ifstart(struct ifnet * const ifp){
}
return;
}
+#endif
/* Link is OK, queue packets to NIC */
while( sc->pending_txs < TX_RING_SIZE ){
@@ -782,7 +796,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;
}
@@ -934,7 +948,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((
@@ -1026,14 +1040,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: */
@@ -1041,6 +1055,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);
@@ -1093,13 +1111,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); */
}
}
}
@@ -1165,7 +1181,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;
}
@@ -1179,6 +1200,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 );
@@ -1194,9 +1218,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
@@ -1210,21 +1238,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 ) ) {
@@ -1248,10 +1280,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 );
@@ -1267,6 +1295,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;
@@ -1282,7 +1313,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(
@@ -1298,6 +1330,20 @@ epic_set_rx_mode(
return;
}
+void
+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:
*/
@@ -1307,24 +1353,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;
}
@@ -1332,40 +1392,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 =
@@ -1386,8 +1458,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 ) {
@@ -1405,6 +1478,8 @@ epic_set_media_speed __P((
/* Else it will be done when GP2 int occured */
}
+ epic_set_tx_mode(sc);
+
return;
}
@@ -1525,14 +1600,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)));
}
/*
@@ -1545,54 +1623,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)));
}
/*
@@ -1619,7 +1733,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);
@@ -1728,7 +1845,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;
@@ -1815,7 +1932,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 );
}
@@ -1831,7 +1951,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;
}
@@ -1871,4 +1994,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 */
diff --git a/sys/pci/if_txvar.h b/sys/pci/if_txvar.h
index efa282c..9d3f030 100644
--- a/sys/pci/if_txvar.h
+++ b/sys/pci/if_txvar.h
@@ -1,5 +1,5 @@
/* $OpenBSD: if_txvar.h,v 1.3 1998/10/10 04:30:09 jason Exp $ */
-/* $Id: if_txvar.h,v 1.3 1998/10/10 04:30:09 jason Exp $ */
+/* $Id: if_txvar.h,v 1.1 1998/11/01 07:44:33 semenu Exp $ */
/*-
* Copyright (c) 1997 Semen Ustimenko
@@ -192,6 +192,10 @@
#define TXCON_FULL_DUPLEX 0x00000006
#define TXCON_SLOT_TIME 0x00000078
+#define MIICFG_SMI_ENABLE 0x00000010
+
+#define TEST1_CLOCK_TEST 0x00000008
+
#define TXCON_DEFAULT (TXCON_SLOT_TIME | TXCON_EARLY_TRANSMIT_ENABLE)
#define TRANSMIT_THRESHOLD 0x80
@@ -214,10 +218,14 @@
#define DP83840_PHYIDR2 0x03
#define BMCR_RESET 0x8000
+#define BMCR_LOOPBACK 0x4000
#define BMCR_100MBPS 0x2000 /* 10/100 Mbps */
#define BMCR_AUTONEGOTIATION 0x1000 /* ON/OFF */
+#define BMCR_POWERDOWN 0x0800
+#define BMCR_ISOLATE 0x0400
#define BMCR_RESTART_AUTONEG 0x0200
#define BMCR_FULL_DUPLEX 0x0100
+#define BMCR_COL_TEST 0x0080
#define BMSR_100BASE_T4 0x8000
#define BMSR_100BASE_TX_FD 0x4000
@@ -246,6 +254,7 @@
#define QS6612_MCTL 17
#define QS6612_INTSTAT 29
#define QS6612_INTMASK 30
+#define QS6612_BPCR 31
#define MCTL_T4_PRESENT 0x1000 /* External T4 Enabled, ignored */
/* if AutoNeg is enabled */
@@ -370,17 +379,17 @@ typedef struct {
inb( (sc)->iobase + (u_int32_t)(reg) )
#else
#define CSR_WRITE_1(sc,reg,val) \
- ((*(u_int8_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int8_t)(val))
+ ((*(volatile u_int8_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int8_t)(val))
#define CSR_WRITE_2(sc,reg,val) \
- ((*(u_int16_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int16_t)(val))
+ ((*(volatile u_int16_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int16_t)(val))
#define CSR_WRITE_4(sc,reg,val) \
- ((*(u_int32_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int32_t)(val))
+ ((*(volatile u_int32_t*)((sc)->csr + (u_int32_t)(reg))) = (u_int32_t)(val))
#define CSR_READ_1(sc,reg) \
- (*(u_int8_t*)((sc)->csr + (u_int32_t)(reg)))
+ (*(volatile u_int8_t*)((sc)->csr + (u_int32_t)(reg)))
#define CSR_READ_2(sc,reg) \
- (*(u_int16_t*)((sc)->csr + (u_int32_t)(reg)))
+ (*(volatile u_int16_t*)((sc)->csr + (u_int32_t)(reg)))
#define CSR_READ_4(sc,reg) \
- (*(u_int32_t*)((sc)->csr + (u_int32_t)(reg)))
+ (*(volatile u_int32_t*)((sc)->csr + (u_int32_t)(reg)))
#endif
#else /* __OpenBSD__ */
#define EPIC_FORMAT "%s"
OpenPOWER on IntegriCloud