Hi,
I've been seeing panics on a netbsd-4/i386 machine which appears to be
related to the reception of oversized frames:
re0: discarding oversize frame (len=8813)
I've narrowed down the problem here to a specific change.
Basically with netbsd-4 branch I see the failure, but if I revert
only the file:
./src/sys/dev/mii/rgephy.c
to netbsd-4-0-1-RELEASE the problem goes away. Looking at the difference
between the 2 revisions I would guess the most likely cause is the
difference in register writes in rgephy_reset?
Unfortunately for my purposes one of the two motherboard types I have
exhibiting the problem has an RTL8111C which (without the netbsd-4 changes)
fails to detect the media automatically (forcing it to 1000baseT has it
sync
at 100baseTX for some reason).
Are there any changes I could make to the netbsd-4 rgephy.c to find a
fix for this?(netbsd-5 has the same problem by the way)
Thanks,
Brad
# cd /usr/src/sys/dev/mii
# cvs diff -u -r netbsd-4-0-1-RELEASE -r netbsd-4 rgephy.c
Index: rgephy.c
===================================================================
RCS file: /cvsroot/src/sys/dev/mii/rgephy.c,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -u -r1.15 -r1.15.2.1
--- rgephy.c 29 Nov 2006 13:57:59 -0000 1.15
+++ rgephy.c 18 Aug 2009 09:46:50 -0000 1.15.2.1
@@ -1,4 +1,4 @@
-/* $NetBSD: rgephy.c,v 1.15 2006/11/29 13:57:59 tsutsui Exp $ */
+/* $NetBSD: rgephy.c,v 1.15.2.1 2009/08/18 09:46:50 bouyer Exp $ */
/*
* Copyright (c) 2003
@@ -33,7 +33,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: rgephy.c,v 1.15 2006/11/29 13:57:59 tsutsui
Exp $");
+__KERNEL_RCSID(0, "$NetBSD: rgephy.c,v 1.15.2.1 2009/08/18 09:46:50
bouyer Exp $");
/*
@@ -61,7 +61,12 @@
static int rgephy_match(struct device *, struct cfdata *, void *);
static void rgephy_attach(struct device *, struct device *, void *);
-CFATTACH_DECL(rgephy, sizeof(struct mii_softc),
+struct rgephy_softc {
+ struct mii_softc mii_sc;
+ int mii_revision;
+};
+
+CFATTACH_DECL(rgephy, sizeof(struct rgephy_softc),
rgephy_match, rgephy_attach, mii_phy_detach, mii_phy_activate);
@@ -72,8 +77,6 @@
static void rgephy_loop(struct mii_softc *);
static void rgephy_load_dspcode(struct mii_softc *);
-static int rgephy_mii_model;
-
static const struct mii_phy_funcs rgephy_funcs = {
rgephy_service, rgephy_status, rgephy_reset,
};
@@ -103,19 +106,26 @@
static void
rgephy_attach(struct device *parent, struct device *self, void *aux)
{
- struct mii_softc *sc = device_private(self);
+ struct rgephy_softc *rsc = device_private(self);
+ struct mii_softc *sc = &rsc->mii_sc;
struct mii_attach_args *ma = aux;
struct mii_data *mii = ma->mii_data;
const struct mii_phydesc *mpd;
int rev;
const char *sep = "";
+ rsc = device_private(self);
+ sc = &rsc->mii_sc;
+ ma = aux;
+ mii = ma->mii_data;
+
rev = MII_REV(ma->mii_id2);
mpd = mii_phy_match(ma, rgephys);
aprint_naive(": Media interface\n");
aprint_normal(": %s, rev. %d\n", mpd->mpd_name, rev);
- sc->mii_mpd_model = rev; /* XXX miivar.h comment vs usage? */
+ rsc->mii_revision = rev;
+
sc->mii_inst = mii->mii_instance;
sc->mii_phy = ma->mii_phyno;
sc->mii_pdata = mii;
@@ -124,23 +134,14 @@
sc->mii_funcs = &rgephy_funcs;
- /* Don't do isolate on this PHY. */
- sc->mii_flags |= MIIF_NOISOLATE;
-
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#define PRINT(n) aprint_normal("%s%s", sep, (n)); sep = ", "
-#if 0
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
- BMCR_ISO);
-#endif
#ifdef __FreeBSD__
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
BMCR_LOOP|BMCR_S100);
#endif
- rgephy_mii_model = MII_MODEL(ma->mii_id2);
-
sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
sc->mii_capabilities &= ~BMSR_ANEG;
@@ -149,19 +150,11 @@
* media explicitly. Why?
*/
aprint_normal("%s: ", sc->mii_dev.dv_xname);
-#ifdef __FreeBSD__
- mii_phy_add_media(sc);
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
- RGEPHY_BMCR_FDX);
- PRINT(", 1000baseTX");
- ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst), 0);
- PRINT("1000baseTX-FDX");
-#else
if (sc->mii_capabilities & BMSR_EXTSTAT) {
sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
}
mii_phy_add_media(sc);
-#endif
+
/* rtl8169S does not report auto-sense; add manually. */
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA);
sep =", ";
@@ -177,9 +170,12 @@
static int
rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
+ struct rgephy_softc *rsc;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg, speed, gig, anar;
+ rsc = (struct rgephy_softc *)sc;
+
switch (cmd) {
case MII_POLLSTAT:
/*
@@ -254,7 +250,7 @@
}
/*
- * When settning the link manually, one side must
+ * When setting the link manually, one side must
* be the master and the other the slave. However
* ifmedia doesn't give us a good way to specify
* this, so we fake it by using one of the LINK
@@ -271,11 +267,9 @@
PHY_WRITE(sc, RGEPHY_MII_BMCR, speed |
RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
break;
-#ifdef foo
case IFM_NONE:
PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
break;
-#endif
case IFM_100_T4:
default:
return EINVAL;
@@ -306,9 +300,20 @@
* need to restart the autonegotiation process. Read
* the BMSR twice in case it's latched.
*/
- reg = PHY_READ(sc, RTK_GMEDIASTAT);
- if ((reg & RTK_GMEDIASTAT_LINK) != 0)
- break;
+ if (rsc->mii_revision >= 2) {
+ /* RTL8211B(L) */
+ reg = PHY_READ(sc, RGEPHY_MII_SSR);
+ if (reg & RGEPHY_SSR_LINK) {
+ sc->mii_ticks = 0;
+ break;
+ }
+ } else {
+ reg = PHY_READ(sc, RTK_GMEDIASTAT);
+ if ((reg & RTK_GMEDIASTAT_LINK) != 0) {
+ sc->mii_ticks = 0;
+ break;
+ }
+ }
/*
* Only retry autonegotiation every 5 seconds.
@@ -333,7 +338,7 @@
sc->mii_media_status != mii->mii_media_status ||
cmd == MII_MEDIACHG) {
/* XXX only for v0/v1 phys. */
- if (sc->mii_mpd_model < 2)
+ if (rsc->mii_revision < 2)
rgephy_load_dspcode(sc);
}
mii_phy_update(sc, cmd);
@@ -343,18 +348,27 @@
static void
rgephy_status(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
struct mii_data *mii = sc->mii_pdata;
- int bmsr, bmcr;
+ int gstat, bmsr, bmcr;
+ uint16_t ssr;
mii->mii_media_status = IFM_AVALID;
mii->mii_media_active = IFM_ETHER;
- bmsr = PHY_READ(sc, RTK_GMEDIASTAT);
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision >= 2) {
+ ssr = PHY_READ(sc, RGEPHY_MII_SSR);
+ if (ssr & RGEPHY_SSR_LINK)
+ mii->mii_media_status |= IFM_ACTIVE;
+ } else {
+ gstat = PHY_READ(sc, RTK_GMEDIASTAT);
+ if ((gstat & RTK_GMEDIASTAT_LINK) != 0)
+ mii->mii_media_status |= IFM_ACTIVE;
+ }
- if ((bmsr & RTK_GMEDIASTAT_LINK) != 0)
- mii->mii_media_status |= IFM_ACTIVE;
bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
-
+ bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
if ((bmcr & RGEPHY_BMCR_ISO) != 0) {
@@ -374,19 +388,39 @@
}
}
- bmsr = PHY_READ(sc, RTK_GMEDIASTAT);
- if ((bmsr & RTK_GMEDIASTAT_1000MBPS) != 0)
- mii->mii_media_active |= IFM_1000_T;
- else if ((bmsr & RTK_GMEDIASTAT_100MBPS) != 0)
- mii->mii_media_active |= IFM_100_TX;
- else if ((bmsr & RTK_GMEDIASTAT_10MBPS) != 0)
- mii->mii_media_active |= IFM_10_T;
- else
- mii->mii_media_active |= IFM_NONE;
- if ((bmsr & RTK_GMEDIASTAT_FDX) != 0)
- mii->mii_media_active |= IFM_FDX;
-
- return;
+ if (rsc->mii_revision >= 2) {
+ ssr = PHY_READ(sc, RGEPHY_MII_SSR);
+ switch (ssr & RGEPHY_SSR_SPD_MASK) {
+ case RGEPHY_SSR_S1000:
+ mii->mii_media_active |= IFM_1000_T;
+ break;
+ case RGEPHY_SSR_S100:
+ mii->mii_media_active |= IFM_100_TX;
+ break;
+ case RGEPHY_SSR_S10:
+ mii->mii_media_active |= IFM_10_T;
+ break;
+ default:
+ mii->mii_media_active |= IFM_NONE;
+ break;
+ }
+ if (ssr & RGEPHY_SSR_FDX)
+ mii->mii_media_active |= IFM_FDX;
+ else
+ mii->mii_media_active |= IFM_HDX;
+ } else {
+ gstat = PHY_READ(sc, RTK_GMEDIASTAT);
+ if ((gstat & RTK_GMEDIASTAT_1000MBPS) != 0)
+ mii->mii_media_active |= IFM_1000_T;
+ else if ((gstat & RTK_GMEDIASTAT_100MBPS) != 0)
+ mii->mii_media_active |= IFM_100_TX;
+ else if ((gstat & RTK_GMEDIASTAT_10MBPS) != 0)
+ mii->mii_media_active |= IFM_10_T;
+ else
+ mii->mii_media_active |= IFM_NONE;
+ if ((gstat & RTK_GMEDIASTAT_FDX) != 0)
+ mii->mii_media_active |= IFM_FDX;
+ }
}
@@ -413,11 +447,15 @@
static void
rgephy_loop(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
uint32_t bmsr;
int i;
- PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
- DELAY(1000);
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision < 2) {
+ PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
+ DELAY(1000);
+ }
for (i = 0; i < 15000; i++) {
bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
@@ -540,21 +578,17 @@
static void
rgephy_reset(struct mii_softc *sc)
{
+ struct rgephy_softc *rsc;
mii_phy_reset(sc);
DELAY(1000);
- if (sc->mii_mpd_model < 2)
+ rsc = (struct rgephy_softc *)sc;
+ if (rsc->mii_revision < 2)
rgephy_load_dspcode(sc);
else {
- PHY_WRITE(sc, 0x1F, 0x0001);
- PHY_WRITE(sc, 0x09, 0x273a);
- PHY_WRITE(sc, 0x0e, 0x7bfb);
- PHY_WRITE(sc, 0x1b, 0x841e);
-
- PHY_WRITE(sc, 0x1F, 0x0002);
- PHY_WRITE(sc, 0x01, 0x90D0);
PHY_WRITE(sc, 0x1F, 0x0000);
+ PHY_WRITE(sc, 0x0e, 0x0000);
}
/* Reset capabilities */