diff options
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); |