diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2003-02-19 14:38:24 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2003-02-19 14:38:24 +0000 |
commit | 75faa5f2874dcd2ef6fcf024db3bf584f80b577e (patch) | |
tree | aca2124387872ecb3b7bf3389e2b00f96d871796 /sys/dev/pci/if_vr.c | |
parent | 2b468ca61594e528893aaeab816c6c98db4f618a (diff) |
Sync if_vr code with FreeBSD. This makes the driver much better when it comes
to trying to recover the hardware going nuts under the load.
Reported to work by various people including krw@and I.
Diffstat (limited to 'sys/dev/pci/if_vr.c')
-rw-r--r-- | sys/dev/pci/if_vr.c | 287 |
1 files changed, 217 insertions, 70 deletions
diff --git a/sys/dev/pci/if_vr.c b/sys/dev/pci/if_vr.c index 8f779ac75b9..d5f8e884696 100644 --- a/sys/dev/pci/if_vr.c +++ b/sys/dev/pci/if_vr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vr.c,v 1.30 2003/02/09 10:53:24 jason Exp $ */ +/* $OpenBSD: if_vr.c,v 1.31 2003/02/19 14:38:22 miod Exp $ */ /* * Copyright (c) 1997, 1998 @@ -31,7 +31,7 @@ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/sys/pci/if_vr.c,v 1.40 2001/02/06 10:11:48 phk Exp $ + * $FreeBSD: src/sys/pci/if_vr.c,v 1.61 2003/02/01 01:27:05 silby Exp $ */ /* @@ -97,6 +97,7 @@ #include <dev/pci/pcidevs.h> #define VR_USEIOSPACE +#undef VR_USESWSHIFT #include <dev/pci/if_vrreg.h> @@ -148,36 +149,37 @@ int vr_list_tx_init(struct vr_softc *); #define VR_SETBIT(sc, reg, x) \ CSR_WRITE_1(sc, reg, \ - CSR_READ_1(sc, reg) | x) + CSR_READ_1(sc, reg) | (x)) #define VR_CLRBIT(sc, reg, x) \ CSR_WRITE_1(sc, reg, \ - CSR_READ_1(sc, reg) & ~x) + CSR_READ_1(sc, reg) & ~(x)) #define VR_SETBIT16(sc, reg, x) \ CSR_WRITE_2(sc, reg, \ - CSR_READ_2(sc, reg) | x) + CSR_READ_2(sc, reg) | (x)) #define VR_CLRBIT16(sc, reg, x) \ CSR_WRITE_2(sc, reg, \ - CSR_READ_2(sc, reg) & ~x) + CSR_READ_2(sc, reg) & ~(x)) #define VR_SETBIT32(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) | x) + CSR_READ_4(sc, reg) | (x)) #define VR_CLRBIT32(sc, reg, x) \ CSR_WRITE_4(sc, reg, \ - CSR_READ_4(sc, reg) & ~x) + CSR_READ_4(sc, reg) & ~(x)) #define SIO_SET(x) \ CSR_WRITE_1(sc, VR_MIICMD, \ - CSR_READ_1(sc, VR_MIICMD) | x) + CSR_READ_1(sc, VR_MIICMD) | (x)) #define SIO_CLR(x) \ CSR_WRITE_1(sc, VR_MIICMD, \ - CSR_READ_1(sc, VR_MIICMD) & ~x) + CSR_READ_1(sc, VR_MIICMD) & ~(x)) +#ifdef VR_USESWSHIFT /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ @@ -224,6 +226,7 @@ vr_mii_send(sc, bits, cnt) SIO_SET(VR_MIICMD_CLK); } } +#endif /* * Read an PHY register through the MII. @@ -233,6 +236,7 @@ vr_mii_readreg(sc, frame) struct vr_softc *sc; struct vr_mii_frame *frame; +#ifdef VR_USESWSHIFT { int i, ack, s; @@ -276,9 +280,9 @@ vr_mii_readreg(sc, frame) /* Check for ack */ SIO_CLR(VR_MIICMD_CLK); DELAY(1); + ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; SIO_SET(VR_MIICMD_CLK); DELAY(1); - ack = CSR_READ_4(sc, VR_MIICMD) & VR_MIICMD_DATAOUT; /* * Now try reading data bits. If the ack failed, we still @@ -319,6 +323,34 @@ fail: return(1); return(0); } +#else +{ + int s, i; + + s = splimp(); + + /* Set the PHY-address */ + CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| + frame->mii_phyaddr); + + /* Set the register-address */ + CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); + VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_READ_ENB); + + for (i = 0; i < 10000; i++) { + if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_READ_ENB) == 0) + break; + DELAY(1); + } + + frame->mii_data = CSR_READ_2(sc, VR_MIIDATA); + + (void)splx(s); + + return(0); +} +#endif + /* * Write to a PHY register through the MII. @@ -328,6 +360,7 @@ vr_mii_writereg(sc, frame) struct vr_softc *sc; struct vr_mii_frame *frame; +#ifdef VR_USESWSHIFT { int s; @@ -373,6 +406,33 @@ vr_mii_writereg(sc, frame) return(0); } +#else +{ + int s, i; + + s = splimp(); + + /* Set the PHY-address */ + CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| + frame->mii_phyaddr); + + /* Set the register-address and data to write */ + CSR_WRITE_1(sc, VR_MIIADDR, frame->mii_regaddr); + CSR_WRITE_2(sc, VR_MIIDATA, frame->mii_data); + + VR_SETBIT(sc, VR_MIICMD, VR_MIICMD_WRITE_ENB); + + for (i = 0; i < 10000; i++) { + if ((CSR_READ_1(sc, VR_MIICMD) & VR_MIICMD_WRITE_ENB) == 0) + break; + DELAY(1); + } + + (void)splx(s); + + return(0); +} +#endif int vr_miibus_readreg(dev, phy, reg) @@ -382,6 +442,14 @@ vr_miibus_readreg(dev, phy, reg) struct vr_softc *sc = (struct vr_softc *)dev; struct vr_mii_frame frame; + switch (sc->vr_revid) { + case REV_ID_VT6102_APOLLO: + if (phy != 1) + return 0; + default: + break; + } + bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; @@ -399,6 +467,14 @@ vr_miibus_writereg(dev, phy, reg, data) struct vr_softc *sc = (struct vr_softc *)dev; struct vr_mii_frame frame; + switch (sc->vr_revid) { + case REV_ID_VT6102_APOLLO: + if (phy != 1) + return; + default: + break; + } + bzero((char *)&frame, sizeof(frame)); frame.mii_phyaddr = phy; @@ -546,8 +622,17 @@ vr_reset(sc) if (!(CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RESET)) break; } - if (i == VR_TIMEOUT) - printf("%s: reset never completed!\n", sc->sc_dev.dv_xname); + if (i == VR_TIMEOUT) { + if (sc->vr_revid < REV_ID_VT3065_A) + printf("%s: reset never completed!\n", + sc->sc_dev.dv_xname); + else { + /* Use newer force reset command */ + printf("%s: Using force reset command.\n", + sc->sc_dev.dv_xname); + VR_SETBIT(sc, VR_MISC_CR1, VR_MISCCR1_FORSRST); + } + } /* Wait a little while for the chip to get its brains in order. */ DELAY(1000); @@ -604,10 +689,10 @@ vr_attach(parent, self, aux) * Handle power management nonsense. */ command = pci_conf_read(pa->pa_pc, pa->pa_tag, - VR_PCI_CAPID) & 0x000000FF; + VR_PCI_CAPID) & 0x000000ff; if (command == 0x01) { command = pci_conf_read(pa->pa_pc, pa->pa_tag, - VR_PCI_PWRMGMTCTRL); + VR_PCI_PWRMGMTCTRL); if (command & VR_PSTATE_MASK) { u_int32_t iobase, membase, irq; @@ -697,6 +782,15 @@ vr_attach(parent, self, aux) vr_reset(sc); /* + * Turn on bit2 (MIION) in PCI configuration register 0x53 during + * initialization and disable AUTOPOLL. + */ + pci_conf_write(pa->pa_pc, pa->pa_tag, VR_PCI_MODE, + pci_conf_read(pa->pa_pc, pa->pa_tag, VR_PCI_MODE) | + (VR_MODE3_MIION << 24)); + VR_CLRBIT(sc, VR_MIICMD, VR_MIICMD_AUTOPOLL); + + /* * Get station address. The way the Rhine chips work, * you're not allowed to directly access the EEPROM once * they've been programmed a special way. Consequently, @@ -929,33 +1023,23 @@ vr_rxeof(sc) */ if (rxstat & VR_RXSTAT_RXERR) { ifp->if_ierrors++; - printf("%s: rx error: ", sc->sc_dev.dv_xname); - switch(rxstat & 0x000000FF) { - case VR_RXSTAT_CRCERR: - printf("crc error\n"); - break; - case VR_RXSTAT_FRAMEALIGNERR: - printf("frame alignment error\n"); - break; - case VR_RXSTAT_FIFOOFLOW: - printf("FIFO overflow\n"); - break; - case VR_RXSTAT_GIANT: - printf("received giant packet\n"); - break; - case VR_RXSTAT_RUNT: - printf("received runt packet\n"); - break; - case VR_RXSTAT_BUSERR: - printf("system bus error\n"); - break; - case VR_RXSTAT_BUFFERR: - printf("rx buffer error\n"); - break; - default: - printf("unknown rx error\n"); - break; - } + printf("%s: rx error (%02x):", + sc->sc_dev.dv_xname, rxstat & 0x000000ff); + if (rxstat & VR_RXSTAT_CRCERR) + printf(" crc error"); + if (rxstat & VR_RXSTAT_FRAMEALIGNERR) + printf(" frame alignment error"); + if (rxstat & VR_RXSTAT_FIFOOFLOW) + printf(" FIFO overflow"); + if (rxstat & VR_RXSTAT_GIANT) + printf(" received giant packet"); + if (rxstat & VR_RXSTAT_RUNT) + printf(" received runt packet"); + if (rxstat & VR_RXSTAT_BUSERR) + printf(" system bus error"); + if (rxstat & VR_RXSTAT_BUFFERR) + printf(" rx buffer error"); + printf("\n"); vr_newbuf(sc, cur_rx, m); continue; } @@ -1002,9 +1086,29 @@ void vr_rxeoc(sc) struct vr_softc *sc; { + struct ifnet *ifp; + int i; + + ifp = &sc->arpcom.ac_if; + + ifp->if_ierrors++; + + VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); + DELAY(10000); + + for (i = 0x400; + i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_RX_ON); + i--) + ; /* Wait for receiver to stop */ + + if (!i) { + printf("%s: rx shutdown error!\n", sc->sc_dev.dv_xname); + sc->vr_flags |= VR_F_RESTART; + return; + } vr_rxeof(sc); - VR_CLRBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); + CSR_WRITE_4(sc, VR_RXADDR, vtophys(sc->vr_cdata.vr_rx_head->vr_ptr)); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_ON); VR_SETBIT16(sc, VR_COMMAND, VR_CMD_RX_GO); @@ -1026,8 +1130,8 @@ vr_txeof(sc) ifp = &sc->arpcom.ac_if; - /* Clear the timeout timer. */ - ifp->if_timer = 0; + /* Reset the timeout timer; if_txeoc will clear it. */ + ifp->if_timer = 5; /* Sanity check. */ if (sc->vr_cdata.vr_tx_head == NULL) @@ -1039,10 +1143,28 @@ vr_txeof(sc) */ while(sc->vr_cdata.vr_tx_head->vr_mbuf != NULL) { u_int32_t txstat; + int i; cur_tx = sc->vr_cdata.vr_tx_head; txstat = cur_tx->vr_ptr->vr_status; + if ((txstat & VR_TXSTAT_ABRT) || + (txstat & VR_TXSTAT_UDF)) { + for (i = 0x400; + i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); + i--) + ; /* Wait for chip to shutdown */ + if (!i) { + printf("%s: tx shutdown timeout\n", + sc->sc_dev.dv_xname); + sc->vr_flags |= VR_F_RESTART; + break; + } + VR_TXOWN(cur_tx) = VR_TXSTAT_OWN; + CSR_WRITE_4(sc, VR_TXADDR, vtophys(cur_tx->vr_ptr)); + break; + } + if (txstat & VR_TXSTAT_OWN) break; @@ -1085,11 +1207,10 @@ vr_txeoc(sc) ifp = &sc->arpcom.ac_if; - ifp->if_timer = 0; - if (sc->vr_cdata.vr_tx_head == NULL) { ifp->if_flags &= ~IFF_OACTIVE; sc->vr_cdata.vr_tx_tail = NULL; + ifp->if_timer = 0; } return; @@ -1103,6 +1224,14 @@ vr_tick(xsc) int s; s = splimp(); + if (sc->vr_flags & VR_F_RESTART) { + printf("%s: restarting\n", sc->sc_dev.dv_xname); + vr_stop(sc); + vr_reset(sc); + vr_init(sc); + sc->vr_flags &= ~VR_F_RESTART; + } + mii_tick(&sc->sc_mii); timeout_add(&sc->sc_to, hz); splx(s); @@ -1143,30 +1272,46 @@ vr_intr(arg) if (status & VR_ISR_RX_OK) vr_rxeof(sc); + if (status & VR_ISR_RX_DROPPED) { + printf("%s: rx packet lost\n", sc->sc_dev.dv_xname); + ifp->if_ierrors++; + } + if ((status & VR_ISR_RX_ERR) || (status & VR_ISR_RX_NOBUF) || - (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW) || - (status & VR_ISR_RX_DROPPED)) { - vr_rxeof(sc); + (status & VR_ISR_RX_NOBUF) || (status & VR_ISR_RX_OFLOW)) { + printf("%s: receive error (%04x)", + sc->sc_dev.dv_xname, status); + if (status & VR_ISR_RX_NOBUF) + printf(" no buffers"); + if (status & VR_ISR_RX_OFLOW) + printf(" overflow"); + if (status & VR_ISR_RX_DROPPED) + printf(" packet lost"); + printf("\n"); vr_rxeoc(sc); } - if (status & VR_ISR_TX_OK) { - vr_txeof(sc); - vr_txeoc(sc); + if ((status & VR_ISR_BUSERR) || (status & VR_ISR_TX_UNDERRUN)) { + vr_reset(sc); + vr_init(sc); + break; } - if ((status & VR_ISR_TX_UNDERRUN)||(status & VR_ISR_TX_ABRT)){ - ifp->if_oerrors++; + if ((status & VR_ISR_TX_OK) || (status & VR_ISR_TX_ABRT) || + (status & VR_ISR_TX_ABRT2) || (status & VR_ISR_UDFI)) { vr_txeof(sc); - if (sc->vr_cdata.vr_tx_head != NULL) { - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_ON); - VR_SETBIT16(sc, VR_COMMAND, VR_CMD_TX_GO); - } - } - - if (status & VR_ISR_BUSERR) { - vr_reset(sc); - vr_init(sc); + if ((status & VR_ISR_UDFI) || + (status & VR_ISR_TX_ABRT2) || + (status & VR_ISR_TX_ABRT)) { + ifp->if_oerrors++; + if (sc->vr_cdata.vr_tx_head != NULL) { + VR_SETBIT16(sc, VR_COMMAND, + VR_CMD_TX_ON); + VR_SETBIT16(sc, VR_COMMAND, + VR_CMD_TX_GO); + } + } else + vr_txeoc(sc); } } @@ -1332,8 +1477,6 @@ vr_start(ifp) * Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; - - return; } void @@ -1359,18 +1502,22 @@ vr_init(xsc) for (i = 0; i < ETHER_ADDR_LEN; i++) CSR_WRITE_1(sc, VR_PAR0 + i, sc->arpcom.ac_enaddr[i]); + /* Set DMA size */ + VR_CLRBIT(sc, VR_BCR0, VR_BCR0_DMA_LENGTH); + VR_SETBIT(sc, VR_BCR0, VR_BCR0_DMA_STORENFWD); + /* - * BCR0 and BCR1 can override the RXCFG and TXCFG registers, + * BCR0 and BCR1 can override the RXCFG and TXCFG registers, * so we must set both. */ VR_CLRBIT(sc, VR_BCR0, VR_BCR0_RX_THRESH); - VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESHSTORENFWD); - + VR_SETBIT(sc, VR_BCR0, VR_BCR0_RXTHRESH128BYTES); + VR_CLRBIT(sc, VR_BCR1, VR_BCR1_TX_THRESH); VR_SETBIT(sc, VR_BCR1, VR_BCR1_TXTHRESHSTORENFWD); VR_CLRBIT(sc, VR_RXCFG, VR_RXCFG_RX_THRESH); - VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_STORENFWD); + VR_SETBIT(sc, VR_RXCFG, VR_RXTHRESH_128BYTES); VR_CLRBIT(sc, VR_TXCFG, VR_TXCFG_TX_THRESH); VR_SETBIT(sc, VR_TXCFG, VR_TXTHRESH_STORENFWD); |