Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/pci major rework to fix link control breakage
details: https://anonhg.NetBSD.org/src/rev/4beca0029f19
branches: trunk
changeset: 460865:4beca0029f19
user: nisimura <nisimura%NetBSD.org@localhost>
date: Wed Nov 06 14:33:52 2019 +0000
description:
major rework to fix link control breakage
diffstat:
sys/dev/pci/if_kse.c | 192 +++++++++++++++++++++-----------------------------
1 files changed, 81 insertions(+), 111 deletions(-)
diffs (299 lines):
diff -r 635b232a3e3c -r 4beca0029f19 sys/dev/pci/if_kse.c
--- a/sys/dev/pci/if_kse.c Wed Nov 06 13:46:04 2019 +0000
+++ b/sys/dev/pci/if_kse.c Wed Nov 06 14:33:52 2019 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_kse.c,v 1.38 2019/05/29 10:07:29 msaitoh Exp $ */
+/* $NetBSD: if_kse.c,v 1.39 2019/11/06 14:33:52 nisimura Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1.38 2019/05/29 10:07:29 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_kse.c,v 1.39 2019/11/06 14:33:52 nisimura Exp $");
#include <sys/param.h>
@@ -58,6 +58,8 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcidevs.h>
+#define KSE_LINKDEBUG 0
+
#define CSR_READ_4(sc, off) \
bus_space_read_4(sc->sc_st, sc->sc_sh, off)
#define CSR_WRITE_4(sc, off, val) \
@@ -93,6 +95,17 @@
#define P1SR 0x514 /* port 1 status */
#define P2CR4 0x532 /* port 2 control 4 */
#define P2SR 0x534 /* port 2 status */
+#define PxCR_STARTNEG (1U << 9) /* restart auto negotiation */
+#define PxCR_AUTOEN (1U << 7) /* auto negotiation enable */
+#define PxCR_SPD100 (1U << 6) /* force speed 100 */
+#define PxCR_USEFDX (1U << 5) /* force full duplex */
+#define PxCR_USEFC (1U << 4) /* advertise pause flow control */
+#define PxSR_ACOMP (1U << 6) /* auto negotiation completed */
+#define PxSR_SPD100 (1U << 10) /* speed is 100Mbps */
+#define PxSR_FDX (1U << 9) /* full duplex */
+#define PxSR_LINKUP (1U << 5) /* link is good */
+#define PxSR_RXFLOW (1U << 12) /* receive flow control active */
+#define PxSR_TXFLOW (1U << 11) /* transmit flow control active */
#define TXC_BS_MSK 0x3f000000 /* burst size */
#define TXC_BS_SFT (24) /* 1,2,4,8,16,32 or 0 for unlimited */
@@ -207,8 +220,8 @@
void *sc_ih; /* interrupt cookie */
struct ifmedia sc_media; /* ifmedia information */
- int sc_media_status; /* PHY */
- int sc_media_active; /* PHY */
+ int sc_linkstatus; /* last P1SR register value */
+
callout_t sc_callout; /* MII tick callout */
callout_t sc_stat_ch; /* statistics counter callout */
@@ -313,11 +326,9 @@
static void rxintr(struct kse_softc *);
static void txreap(struct kse_softc *);
static void lnkchg(struct kse_softc *);
-static int ifmedia_upd(struct ifnet *);
-static void ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int ksephy_change(struct ifnet *);
+static void ksephy_status(struct ifnet *, struct ifmediareq *);
static void phy_tick(void *);
-static int ifmedia2_upd(struct ifnet *);
-static void ifmedia2_sts(struct ifnet *, struct ifmediareq *);
#ifdef KSE_EVENT_COUNTERS
static void stat_tick(void *);
static void zerostats(struct kse_softc *);
@@ -493,8 +504,9 @@
/* Initialize ifmedia structures. */
ifm = &sc->sc_media;
sc->sc_ethercom.ec_ifmedia = ifm;
+ sc->sc_linkstatus = 0;
if (sc->sc_chip == 0x8841) {
- ifmedia_init(ifm, 0, ifmedia_upd, ifmedia_sts);
+ ifmedia_init(ifm, 0, ksephy_change, ksephy_status);
ifmedia_add(ifm, IFM_ETHER | IFM_10_T, 0, NULL);
ifmedia_add(ifm, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
ifmedia_add(ifm, IFM_ETHER | IFM_100_TX, 0, NULL);
@@ -502,9 +514,10 @@
ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
} else {
- ifmedia_init(ifm, 0, ifmedia2_upd, ifmedia2_sts);
- ifmedia_add(ifm, IFM_ETHER | IFM_AUTO, 0, NULL);
- ifmedia_set(ifm, IFM_ETHER | IFM_AUTO);
+ ifmedia_init(ifm, 0, NULL, NULL);
+ ifmedia_add(ifm, IFM_ETHER | IFM_100_TX, 0, NULL);
+ ifmedia_add(ifm, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
+ ifmedia_set(ifm, IFM_ETHER | IFM_100_TX | IFM_FDX);
}
printf("%s: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, auto\n",
@@ -766,7 +779,8 @@
kse_set_filter(sc);
/* set current media */
- (void)ifmedia_upd(ifp);
+ if (sc->sc_chip == 0x8841)
+ (void)ksephy_change(ifp);
/* enable transmitter and receiver */
CSR_WRITE_4(sc, MDTXC, sc->sc_txc);
@@ -1257,92 +1271,77 @@
{
struct ifmediareq ifmr;
-#if 0 /* rambling link status */
- printf("%s: link %s\n", device_xname(sc->sc_dev),
- (CSR_READ_2(sc, P1SR) & (1U << 5)) ? "up" : "down");
+#if KSE_LINKDEBUG > 0
+printf("link change detected\n");
#endif
- ifmedia_sts(&sc->sc_ethercom.ec_if, &ifmr);
+ ksephy_status(&sc->sc_ethercom.ec_if, &ifmr);
}
static int
-ifmedia_upd(struct ifnet *ifp)
+ksephy_change(struct ifnet *ifp)
{
struct kse_softc *sc = ifp->if_softc;
struct ifmedia *ifm = &sc->sc_media;
- uint16_t ctl;
-
- ctl = 0;
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
- ctl |= (1U << 13); /* Restart AN */
- ctl |= (1U << 7); /* Enable AN */
- ctl |= (1U << 4); /* Advertise flow control pause */
- ctl |= (1U << 3) | (1U << 2) | (1U << 1) | (1U << 0);
+ uint16_t p1cr4;
+#if KSE_LINKDEBUG > 0
+printf("ifm_media: %x\n", ifm->ifm_cur->ifm_media);
+#endif
+ p1cr4 = 0;
+ if (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_AUTO) {
+ p1cr4 |= PxCR_STARTNEG; /* restart AN */
+ p1cr4 |= PxCR_AUTOEN; /* enable AN */
+ p1cr4 |= PxCR_USEFC; /* advertise flow control pause */
+ p1cr4 |= 0xf; /* advertise 100-FDX,100-HDX,10-FDX,10-HDX */
+ } else {
+ if (IFM_SUBTYPE(ifm->ifm_cur->ifm_media) == IFM_100_TX)
+ p1cr4 |= PxCR_SPD100;
+ if (ifm->ifm_media & IFM_FDX)
+ p1cr4 |= PxCR_USEFDX;
}
- else {
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX)
- ctl |= (1U << 6);
- if (ifm->ifm_media & IFM_FDX)
- ctl |= (1U << 5);
- }
- CSR_WRITE_2(sc, P1CR4, ctl);
-
- sc->sc_media_active = IFM_NONE;
- sc->sc_media_status = IFM_AVALID;
-
+ CSR_WRITE_2(sc, P1CR4, p1cr4);
+#if KSE_LINKDEBUG > 0
+printf("P1CR4: %04x\n", p1cr4);
+#endif
return 0;
}
static void
-ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+ksephy_status(struct ifnet *ifp, struct ifmediareq *ifmr)
{
struct kse_softc *sc = ifp->if_softc;
- struct ifmedia *ifm = &sc->sc_media;
- uint16_t ctl, sts, result;
+ int media_status;
+ u_int media_active;
+ uint16_t p1cr4, p1sr;
- ifmr->ifm_status = IFM_AVALID;
- ifmr->ifm_active = IFM_ETHER;
+ media_status = IFM_AVALID;
+ media_active = IFM_ETHER;
- ctl = CSR_READ_2(sc, P1CR4);
- sts = CSR_READ_2(sc, P1SR);
- if ((sts & (1U << 5)) == 0) {
- ifmr->ifm_active |= IFM_NONE;
- goto out; /* Link is down */
- }
- ifmr->ifm_status |= IFM_ACTIVE;
- if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) {
- if ((sts & (1U << 6)) == 0) {
- ifmr->ifm_active |= IFM_NONE;
+ p1cr4 = CSR_READ_2(sc, P1CR4);
+ p1sr = CSR_READ_2(sc, P1SR);
+#if KSE_LINKDEBUG > 0
+printf("P1SR: %04x link %s\n", p1sr, (p1sr & PxSR_LINKUP) ? "up" : "down");
+#endif
+ sc->sc_linkstatus = p1sr;
+ if (p1sr & PxSR_LINKUP)
+ media_status |= IFM_ACTIVE;
+
+ if (p1cr4 & PxCR_AUTOEN) {
+ if ((p1sr & PxSR_ACOMP) == 0) {
+ media_active |= IFM_NONE;
goto out; /* Negotiation in progress */
}
- result = ctl & sts & 017;
- if (result & (1U << 3))
- ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
- else if (result & (1U << 2))
- ifmr->ifm_active |= IFM_100_TX | IFM_HDX;
- else if (result & (1U << 1))
- ifmr->ifm_active |= IFM_10_T | IFM_FDX;
- else if (result & (1U << 0))
- ifmr->ifm_active |= IFM_10_T | IFM_HDX;
- else
- ifmr->ifm_active |= IFM_NONE;
- if (ctl & (1U << 4))
- ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
- if (sts & (1U << 4))
- ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
- }
- else {
- ifmr->ifm_active |= (sts & (1U << 10)) ? IFM_100_TX : IFM_10_T;
- if (sts & (1U << 9))
- ifmr->ifm_active |= IFM_FDX;
- if (sts & (1U << 12))
- ifmr->ifm_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
- if (sts & (1U << 11))
- ifmr->ifm_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
}
+ media_active |= (p1sr & PxSR_SPD100) ? IFM_100_TX : IFM_10_T;
+ if (p1sr & PxSR_FDX)
+ media_active |= IFM_FDX;
+ if (p1sr & PxSR_RXFLOW)
+ media_active |= IFM_FLOW | IFM_ETH_RXPAUSE;
+ if (p1sr & PxSR_TXFLOW)
+ media_active |= IFM_FLOW | IFM_ETH_TXPAUSE;
out:
- sc->sc_media_status = ifmr->ifm_status;
- sc->sc_media_active = ifmr->ifm_active;
+ ifmr->ifm_active = media_active;
+ ifmr->ifm_status = media_status;
}
static void
@@ -1351,46 +1350,17 @@
struct kse_softc *sc = arg;
struct ifmediareq ifmr;
int s;
+ uint16_t p1sr;
s = splnet();
- ifmedia_sts(&sc->sc_ethercom.ec_if, &ifmr);
+ p1sr = CSR_READ_2(sc, P1SR);
+ if (sc->sc_linkstatus != p1sr)
+ ksephy_status(&sc->sc_ethercom.ec_if, &ifmr);
splx(s);
callout_reset(&sc->sc_callout, hz, phy_tick, sc);
}
-static int
-ifmedia2_upd(struct ifnet *ifp)
-{
- struct kse_softc *sc = ifp->if_softc;
-
- sc->sc_media_status = IFM_AVALID;
- sc->sc_media_active = IFM_NONE;
- return 0;
-}
-
-static void
-ifmedia2_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
-{
- struct kse_softc *sc = ifp->if_softc;
- int p1sts, p2sts;
-
- ifmr->ifm_status = IFM_AVALID;
- ifmr->ifm_active = IFM_ETHER;
- p1sts = CSR_READ_2(sc, P1SR);
- p2sts = CSR_READ_2(sc, P2SR);
- if (((p1sts | p2sts) & (1U << 5)) == 0)
- ifmr->ifm_active |= IFM_NONE;
- else {
- ifmr->ifm_status |= IFM_ACTIVE;
- ifmr->ifm_active |= IFM_100_TX | IFM_FDX;
- ifmr->ifm_active |= IFM_FLOW
- | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE;
- }
- sc->sc_media_status = ifmr->ifm_status;
- sc->sc_media_active = ifmr->ifm_active;
-}
-
#ifdef KSE_EVENT_COUNTERS
static void
stat_tick(void *arg)
Home |
Main Index |
Thread Index |
Old Index