summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_vr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/if_vr.c')
-rw-r--r--sys/dev/pci/if_vr.c287
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);