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 | |
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')
-rw-r--r-- | sys/dev/pci/if_vr.c | 287 | ||||
-rw-r--r-- | sys/dev/pci/if_vrreg.h | 36 |
2 files changed, 251 insertions, 72 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); diff --git a/sys/dev/pci/if_vrreg.h b/sys/dev/pci/if_vrreg.h index 5cec54cf7dd..8602ea1fedc 100644 --- a/sys/dev/pci/if_vrreg.h +++ b/sys/dev/pci/if_vrreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vrreg.h,v 1.6 2003/02/09 10:53:24 jason Exp $ */ +/* $OpenBSD: if_vrreg.h,v 1.7 2003/02/19 14:38:23 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_vrreg.h,v 1.10 2001/02/09 06:11:21 bmilekic Exp $ + * $FreeBSD: src/sys/pci/if_vrreg.h,v 1.17 2003/02/01 01:27:05 silby Exp $ */ /* @@ -83,6 +83,10 @@ #define VR_CRC_CNT 0x7E #define VR_STICKHW 0x83 +/* Misc Registers */ +#define VR_MISC_CR1 0x81 +#define VR_MISCCR1_FORSRST 0x40 + /* * RX config bits. */ @@ -151,6 +155,8 @@ #define VR_ISR_STATSOFLOW 0x0080 /* stats counter oflow */ #define VR_ISR_RX_EARLY 0x0100 /* rx early */ #define VR_ISR_LINKSTAT 0x0200 /* MII status change */ +#define VR_ISR_ETI 0x0200 /* Tx early (3043/3071) */ +#define VR_ISR_UDFI 0x0200 /* Tx FIFO underflow (3065) */ #define VR_ISR_RX_OFLOW 0x0400 /* rx FIFO overflow */ #define VR_ISR_RX_DROPPED 0x0800 #define VR_ISR_RX_NOBUF2 0x1000 @@ -370,6 +376,7 @@ struct vr_desc { #define VR_TXSTAT_ABRT 0x00000100 #define VR_TXSTAT_LATECOLL 0x00000200 #define VR_TXSTAT_CARRLOST 0x00000400 +#define VR_TXSTAT_UDF 0x00000800 #define VR_TXSTAT_BUSERR 0x00002000 #define VR_TXSTAT_JABTIMEO 0x00004000 #define VR_TXSTAT_ERRSUM 0x00008000 @@ -454,12 +461,16 @@ struct vr_softc { bus_space_tag_t vr_btag; /* bus space tag */ bus_dma_tag_t sc_dmat; struct vr_type *vr_info; /* Rhine adapter info */ + u_int8_t vr_revid; /* Rhine chip revision */ + u_int8_t vr_flags; /* See VR_F_* below */ struct vr_list_data *vr_ldata; struct vr_chain_data vr_cdata; struct mii_data sc_mii; struct timeout sc_to; }; +#define VR_F_RESTART 0x01 /* Restart unit on next tick */ + /* * register space access macros */ @@ -493,6 +504,8 @@ struct vr_softc { #define VIA_DEVICEID_RHINE 0x3043 #define VIA_DEVICEID_RHINE_II 0x6100 #define VIA_DEVICEID_RHINE_II_2 0x3065 +#define VIA_DEVICEID_RHINE_III 0x3106 +#define VIA_DEVICEID_RHINE_III_M 0x3053 /* * Delta Electronics device ID. @@ -516,6 +529,21 @@ struct vr_softc { /* + * VIA Rhine revision IDs + */ + +#define REV_ID_VT3043_E 0x04 +#define REV_ID_VT3071_A 0x20 +#define REV_ID_VT3071_B 0x21 +#define REV_ID_VT3065_A 0x40 +#define REV_ID_VT3065_B 0x41 +#define REV_ID_VT3065_C 0x42 +#define REV_ID_VT6102_APOLLO 0x74 +#define REV_ID_VT3106 0x80 +#define REV_ID_VT3106_J 0x80 /* 0x80-0x8F */ +#define REV_ID_VT3106_S 0x90 /* 0x90-0xA0 */ + +/* * PCI low memory base and low I/O base register, and * other PCI registers. */ @@ -524,6 +552,7 @@ struct vr_softc { #define VR_PCI_DEVICE_ID 0x02 #define VR_PCI_COMMAND 0x04 #define VR_PCI_STATUS 0x06 +#define VR_PCI_REVID 0x08 #define VR_PCI_CLASSCODE 0x09 #define VR_PCI_LATENCY_TIMER 0x0D #define VR_PCI_HEADER_TYPE 0x0E @@ -536,6 +565,9 @@ struct vr_softc { #define VR_PCI_MINLAT 0x0F #define VR_PCI_RESETOPT 0x48 #define VR_PCI_EEPROM_DATA 0x4C +#define VR_PCI_MODE 0x50 + +#define VR_MODE3_MIION 0x04 /* power management registers */ #define VR_PCI_CAPID 0xDC /* 8 bits */ |