summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2011-09-07 16:57:43 +0000
committeryongari <yongari@FreeBSD.org>2011-09-07 16:57:43 +0000
commitb3819a3c4828993bca7832b8b227cfd8448adeca (patch)
tree9368110321767182fa70e12c89b872153167341a
parent284bd48a4407bf3b284b474415d2f533460af230 (diff)
downloadFreeBSD-src-b3819a3c4828993bca7832b8b227cfd8448adeca.zip
FreeBSD-src-b3819a3c4828993bca7832b8b227cfd8448adeca.tar.gz
vge(4) hardwares poll media status and generates an interrupt
whenever the link state is changed. Using software based polling for media status tracking is known to cause MII access failure under certain conditions once link is established so vge(4) used to rely on link status change interrupt. However DEVICE_POLLING completely disables generation of all kind of interrupts on vge(4) such that this resulted in not detecting link state change event. This means vge(4) does not correctly detect established/lost link with DEVICE_POLLING. Losing the interrupt made vge(4) not to send any packets to peer since vge(4) does not try to send any packets when there is no established link. Work around the issue by generating link state change interrupt with DEVICE_POLLING. PR: kern/160442 Approved by: re (kib)
-rw-r--r--sys/dev/vge/if_vge.c18
-rw-r--r--sys/dev/vge/if_vgereg.h2
2 files changed, 13 insertions, 7 deletions
diff --git a/sys/dev/vge/if_vge.c b/sys/dev/vge/if_vge.c
index d9a58cc..9529702 100644
--- a/sys/dev/vge/if_vge.c
+++ b/sys/dev/vge/if_vge.c
@@ -1752,6 +1752,10 @@ vge_intr(void *arg)
#ifdef DEVICE_POLLING
if (ifp->if_capenable & IFCAP_POLLING) {
+ status = CSR_READ_4(sc, VGE_ISR);
+ CSR_WRITE_4(sc, VGE_ISR, status);
+ if (status != 0xFFFFFFFF && (status & VGE_ISR_LINKSTS) != 0)
+ vge_link_statchg(sc);
VGE_UNLOCK(sc);
return;
}
@@ -2109,11 +2113,10 @@ vge_init_locked(struct vge_softc *sc)
#ifdef DEVICE_POLLING
/*
- * Disable interrupts if we are polling.
+ * Disable interrupts except link state change if we are polling.
*/
if (ifp->if_capenable & IFCAP_POLLING) {
- CSR_WRITE_4(sc, VGE_IMR, 0);
- CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK);
+ CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS_POLLING);
} else /* otherwise ... */
#endif
{
@@ -2121,9 +2124,9 @@ vge_init_locked(struct vge_softc *sc)
* Enable interrupts.
*/
CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS);
- CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF);
- CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK);
}
+ CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF);
+ CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK);
sc->vge_flags &= ~VGE_FLAG_LINK;
mii_mediachg(mii);
@@ -2280,8 +2283,9 @@ vge_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
return (error);
VGE_LOCK(sc);
/* Disable interrupts */
- CSR_WRITE_4(sc, VGE_IMR, 0);
- CSR_WRITE_1(sc, VGE_CRC3, VGE_CR3_INT_GMSK);
+ CSR_WRITE_4(sc, VGE_IMR, VGE_INTRS_POLLING);
+ CSR_WRITE_4(sc, VGE_ISR, 0xFFFFFFFF);
+ CSR_WRITE_1(sc, VGE_CRS3, VGE_CR3_INT_GMSK);
ifp->if_capenable |= IFCAP_POLLING;
VGE_UNLOCK(sc);
} else {
diff --git a/sys/dev/vge/if_vgereg.h b/sys/dev/vge/if_vgereg.h
index 77cd61e..c8b3f1b 100644
--- a/sys/dev/vge/if_vgereg.h
+++ b/sys/dev/vge/if_vgereg.h
@@ -302,6 +302,8 @@
VGE_ISR_LINKSTS|VGE_ISR_RXNODESC| \
VGE_ISR_RXDMA_STALL|VGE_ISR_TXDMA_STALL)
+#define VGE_INTRS_POLLING (VGE_ISR_PHYINT|VGE_ISR_LINKSTS)
+
/* Interrupt mask register */
#define VGE_IMR_RXOK_HIPRIO 0x00000001 /* hi prio RX int */
OpenPOWER on IntegriCloud