At the request of Thomas Nystrom, I have now committed his patches to fix the hanging problems of some rhine chipsets and his fixes to allow 6105 (Rhine III) chips to work properly to -current. Naturally, I'm going to wait at least a week before MFCing this change to 4-stable. In the meantime, I'd like to request those who have had problems with Via Rhine cards (either hangs, or unsupported 6105 cards) to try out this patch and tell me how it works out. This patch contains all of the changes described above, and should apply cleanly to any relatively recent 4.7-stable machine.
Thanks, Mike "Silby" Silbersack
Index: if_vr.c =================================================================== RCS file: /home/ncvs/src/sys/pci/if_vr.c,v retrieving revision 1.26.2.11 diff -u -r1.26.2.11 if_vr.c --- if_vr.c 28 Nov 2002 03:00:59 -0000 1.26.2.11 +++ if_vr.c 1 Feb 2003 01:41:21 -0000 @@ -103,6 +103,8 @@ "$FreeBSD: src/sys/pci/if_vr.c,v 1.26.2.11 2002/11/28 03:00:59 silby Exp $"; #endif +#undef VR_USESWSHIFT + /* * Various supported device vendors/types and their names. */ @@ -113,6 +115,10 @@ "VIA VT86C100A Rhine II 10/100BaseTX" }, { VIA_VENDORID, VIA_DEVICEID_RHINE_II_2, "VIA VT6102 Rhine II 10/100BaseTX" }, + { VIA_VENDORID, VIA_DEVICEID_RHINE_III, + "VIA VT6105 Rhine III 10/100BaseTX" }, + { VIA_VENDORID, VIA_DEVICEID_RHINE_III_M, + "VIA VT6105M Rhine III 10/100BaseTX" }, { DELTA_VENDORID, DELTA_DEVICEID_RHINE_II, "Delta Electronics Rhine II 10/100BaseTX" }, { ADDTRON_VENDORID, ADDTRON_DEVICEID_RHINE_II, @@ -145,8 +151,10 @@ static int vr_ifmedia_upd __P((struct ifnet *)); static void vr_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); +#ifdef VR_USESWSHIFT static void vr_mii_sync __P((struct vr_softc *)); static void vr_mii_send __P((struct vr_softc *, u_int32_t, int)); +#endif static int vr_mii_readreg __P((struct vr_softc *, struct vr_mii_frame *)); static int vr_mii_writereg __P((struct vr_softc *, struct vr_mii_frame *)); static int vr_miibus_readreg __P((device_t, int, int)); @@ -230,6 +238,7 @@ CSR_WRITE_1(sc, VR_MIICMD, \ CSR_READ_1(sc, VR_MIICMD) & ~x) +#ifdef VR_USESWSHIFT /* * Sync the PHYs by setting data bit and strobing the clock 32 times. */ @@ -274,6 +283,7 @@ SIO_SET(VR_MIICMD_CLK); } } +#endif /* * Read an PHY register through the MII. @@ -282,6 +292,7 @@ struct vr_softc *sc; struct vr_mii_frame *frame; +#ifdef VR_USESWSHIFT { int i, ack, s; @@ -368,6 +379,34 @@ return(1); return(0); } +#else +{ + int s, i; + + s = splimp(); + + /* Set the PHY-adress */ + CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| + frame->mii_phyaddr); + + /* Set the register-adress */ + 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. @@ -376,6 +415,7 @@ struct vr_softc *sc; struct vr_mii_frame *frame; +#ifdef VR_USESWSHIFT { int s; @@ -421,6 +461,33 @@ return(0); } +#else +{ + int s, i; + + s = splimp(); + + /* Set the PHY-adress */ + CSR_WRITE_1(sc, VR_PHYADDR, (CSR_READ_1(sc, VR_PHYADDR)& 0xe0)| + frame->mii_phyaddr); + + /* Set the register-adress 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 static int vr_miibus_readreg(dev, phy, reg) device_t dev; @@ -430,6 +497,15 @@ struct vr_mii_frame frame; sc = device_get_softc(dev); + + 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; @@ -447,6 +523,15 @@ struct vr_mii_frame frame; sc = device_get_softc(dev); + + 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; @@ -747,6 +832,14 @@ /* Reset the adapter. */ vr_reset(sc); + /* + * Turn on bit2 (MIION) in PCI configuration register 0x53 during + * initialization and disable AUTOPOLL. + */ + pci_write_config(dev, VR_PCI_MODE, + pci_read_config(dev, VR_PCI_MODE, 4) | (VR_MODE3_MIION << 24), 4); + 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 @@ -991,33 +1084,23 @@ */ if (rxstat & VR_RXSTAT_RXERR) { ifp->if_ierrors++; - printf("vr%d: rx error: ", sc->vr_unit); - 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("vr%d: rx error (%02x):", + sc->vr_unit, rxstat & 0x000000ff); + if (rxstat & VR_RXSTAT_CRCERR) + printf(" crc error"); + if (rxstat & VR_RXSTAT_FRAMEALIGNERR) + printf(" frame alignment error\n"); + 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; } @@ -1058,9 +1141,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("vr%d: rx shutdown error!\n", sc->vr_unit); + 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); @@ -1094,14 +1197,22 @@ */ 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)) { - while (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON) + for (i = 0x400; + i && (CSR_READ_2(sc, VR_COMMAND) & VR_CMD_TX_ON); + i--) ; /* Wait for chip to shutdown */ + if (!i) { + printf("vr%d: tx shutdown timeout\n", sc->vr_unit); + 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; @@ -1167,6 +1278,14 @@ s = splimp(); sc = xsc; + if (sc->vr_flags & VR_F_RESTART) { + printf("vr%d: restarting\n", sc->vr_unit); + vr_stop(sc); + vr_reset(sc); + vr_init(sc); + sc->vr_flags &= ~VR_F_RESTART; + } + mii = device_get_softc(sc->vr_miibus); mii_tick(mii); @@ -1208,10 +1327,22 @@ if (status & VR_ISR_RX_OK) vr_rxeof(sc); + if (status & VR_ISR_RX_DROPPED) { + printf("vr%d: rx packet lost\n", sc->vr_unit); + 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("vr%d: receive error (%04x)", + sc->vr_unit, 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); } @@ -1430,13 +1561,13 @@ * 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); Index: if_vrreg.h =================================================================== RCS file: /home/ncvs/src/sys/pci/if_vrreg.h,v retrieving revision 1.7.2.4 diff -u -r1.7.2.4 if_vrreg.h --- if_vrreg.h 28 Nov 2002 03:00:59 -0000 1.7.2.4 +++ if_vrreg.h 1 Feb 2003 01:41:21 -0000 @@ -464,11 +464,14 @@ u_int8_t vr_unit; /* interface number */ u_int8_t vr_type; 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 callout_handle vr_stat_ch; }; +#define VR_F_RESTART 0x01 /* Restart unit on next tick */ + /* * register space access macros */ @@ -502,6 +505,8 @@ #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. @@ -533,6 +538,7 @@ #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 */ @@ -559,6 +565,9 @@ #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 */