summaryrefslogtreecommitdiffstats
path: root/sys/dev/nge
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2002-08-08 18:33:28 +0000
committerambrisko <ambrisko@FreeBSD.org>2002-08-08 18:33:28 +0000
commit761cf38833d9eb8e909877dd244bfdfbf00825c7 (patch)
treec7460e9446d191b6de9e91d12b2bcd3d170da669 /sys/dev/nge
parent59f57c52dc28e958bb2791a0b0d4166665aabd43 (diff)
downloadFreeBSD-src-761cf38833d9eb8e909877dd244bfdfbf00825c7.zip
FreeBSD-src-761cf38833d9eb8e909877dd244bfdfbf00825c7.tar.gz
Add support for SX cards using TBI such as Netgear GA621.
Sponsored by: Vernier Networks. MFC after: 1 week
Diffstat (limited to 'sys/dev/nge')
-rw-r--r--sys/dev/nge/if_nge.c303
-rw-r--r--sys/dev/nge/if_ngereg.h9
2 files changed, 249 insertions, 63 deletions
diff --git a/sys/dev/nge/if_nge.c b/sys/dev/nge/if_nge.c
index 16f2636..a99aea5 100644
--- a/sys/dev/nge/if_nge.c
+++ b/sys/dev/nge/if_nge.c
@@ -620,30 +620,56 @@ static void
nge_miibus_statchg(dev)
device_t dev;
{
+ int status;
struct nge_softc *sc;
struct mii_data *mii;
sc = device_get_softc(dev);
- mii = device_get_softc(sc->nge_miibus);
+ if (sc->nge_tbi) {
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ status = CSR_READ_4(sc, NGE_TBI_ANLPAR);
+ if (status == 0 || status & NGE_TBIANAR_FDX) {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ }
- if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
- NGE_SETBIT(sc, NGE_TX_CFG,
- (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
- NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
+ != IFM_FDX) {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ }
} else {
- NGE_CLRBIT(sc, NGE_TX_CFG,
- (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
- NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
- }
+ mii = device_get_softc(sc->nge_miibus);
- /* If we have a 1000Mbps link, set the mode_1000 bit. */
- if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
- IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
- NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
- } else {
- NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
- }
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ }
+ /* If we have a 1000Mbps link, set the mode_1000 bit. */
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T ||
+ IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX) {
+ NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
+ } else {
+ NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
+ }
+ }
return;
}
@@ -802,6 +828,7 @@ nge_attach(dev)
struct nge_softc *sc;
struct ifnet *ifp;
int unit, error = 0, rid;
+ const char *sep = "";
s = splimp();
@@ -957,14 +984,48 @@ nge_attach(dev)
* Do MII setup.
*/
if (mii_phy_probe(dev, &sc->nge_miibus,
- nge_ifmedia_upd, nge_ifmedia_sts)) {
- printf("nge%d: MII without any PHY!\n", sc->nge_unit);
- nge_free_jumbo_mem(sc);
- bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
- bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
- bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
- error = ENXIO;
- goto fail;
+ nge_ifmedia_upd, nge_ifmedia_sts)) {
+ if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) {
+ sc->nge_tbi = 1;
+ device_printf(dev, "Using TBI\n");
+
+ sc->nge_miibus = dev;
+
+ ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_upd,
+ nge_ifmedia_sts);
+#define ADD(m, c) ifmedia_add(&sc->nge_ifmedia, (m), (c), NULL)
+#define PRINT(s) printf("%s%s", sep, s); sep = ", "
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, 0), 0);
+ device_printf(dev, " ");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 0), 0);
+ PRINT("1000baseSX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 0),0);
+ PRINT("1000baseSX-FDX");
+ ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0), 0);
+ PRINT("auto");
+
+ printf("\n");
+#undef ADD
+#undef PRINT
+ ifmedia_set(&sc->nge_ifmedia,
+ IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0));
+
+ CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
+ | NGE_GPIO_GP4_OUT
+ | NGE_GPIO_GP1_OUTENB | NGE_GPIO_GP2_OUTENB
+ | NGE_GPIO_GP3_OUTENB
+ | NGE_GPIO_GP3_IN | NGE_GPIO_GP4_IN);
+
+ } else {
+ printf("nge%d: MII without any PHY!\n", sc->nge_unit);
+ nge_free_jumbo_mem(sc);
+ bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
+ bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
+ bus_release_resource(dev, NGE_RES, NGE_RID,
+ sc->nge_res);
+ error = ENXIO;
+ goto fail;
+ }
}
/*
@@ -974,6 +1035,7 @@ nge_attach(dev)
callout_handle_init(&sc->nge_stat_ch);
fail:
+
splx(s);
mtx_destroy(&sc->nge_mtx);
return(error);
@@ -997,8 +1059,9 @@ nge_detach(dev)
ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
bus_generic_detach(dev);
- device_delete_child(dev, sc->nge_miibus);
-
+ if (!sc->nge_tbi) {
+ device_delete_child(dev, sc->nge_miibus);
+ }
bus_teardown_intr(dev, sc->nge_irq, sc->nge_intrhand);
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->nge_irq);
bus_release_resource(dev, NGE_RES, NGE_RID, sc->nge_res);
@@ -1284,7 +1347,6 @@ nge_rxeof(sc)
cur_rx->nge_mbuf = NULL;
total_len = NGE_RXBYTES(cur_rx);
NGE_INC(i, NGE_RX_LIST_CNT);
-
/*
* If an error occurs, update stats, clear the
* status word and leave the mbuf cluster in place:
@@ -1297,7 +1359,6 @@ nge_rxeof(sc)
continue;
}
-
/*
* Ok. NatSemi really screwed up here. This is the
* only gigE chip I know of with alignment constraints
@@ -1448,18 +1509,33 @@ nge_tick(xsc)
sc = xsc;
ifp = &sc->arpcom.ac_if;
- mii = device_get_softc(sc->nge_miibus);
- mii_tick(mii);
-
- if (!sc->nge_link) {
- if (mii->mii_media_status & IFM_ACTIVE &&
- IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
- sc->nge_link++;
- if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T)
+ if (sc->nge_tbi) {
+ if (!sc->nge_link) {
+ if (CSR_READ_4(sc, NGE_TBI_BMSR)
+ & NGE_TBIBMSR_ANEG_DONE) {
printf("nge%d: gigabit link up\n",
sc->nge_unit);
- if (ifp->if_snd.ifq_head != NULL)
- nge_start(ifp);
+ nge_miibus_statchg(sc->nge_miibus);
+ sc->nge_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ nge_start(ifp);
+ }
+ }
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ mii_tick(mii);
+
+ if (!sc->nge_link) {
+ if (mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->nge_link++;
+ if (IFM_SUBTYPE(mii->mii_media_active)
+ == IFM_1000_T)
+ printf("nge%d: gigabit link up\n",
+ sc->nge_unit);
+ if (ifp->if_snd.ifq_head != NULL)
+ nge_start(ifp);
+ }
}
}
sc->nge_stat_ch = timeout(nge_tick, sc, hz);
@@ -1489,6 +1565,11 @@ nge_intr(arg)
/* Disable interrupts. */
CSR_WRITE_4(sc, NGE_IER, 0);
+ /* Data LED on for TBI mode */
+ if(sc->nge_tbi)
+ CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
+ | NGE_GPIO_GP3_OUT);
+
for (;;) {
/* Reading the ISR register clears all interrupts. */
status = CSR_READ_4(sc, NGE_ISR);
@@ -1538,6 +1619,12 @@ nge_intr(arg)
if (ifp->if_snd.ifq_head != NULL)
nge_start(ifp);
+ /* Data LED off for TBI mode */
+
+ if(sc->nge_tbi)
+ CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
+ & ~NGE_GPIO_GP3_OUT);
+
return;
}
@@ -1691,7 +1778,11 @@ nge_init(xsc)
*/
nge_stop(sc);
- mii = device_get_softc(sc->nge_miibus);
+ if (sc->nge_tbi) {
+ mii = NULL;
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ }
/* Set MAC address */
CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0);
@@ -1790,14 +1881,27 @@ nge_init(xsc)
NGE_SETBIT(sc, NGE_VLAN_IP_TXCTL, NGE_VIPTXCTL_TAG_PER_PKT);
/* Set full/half duplex mode. */
- if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
- NGE_SETBIT(sc, NGE_TX_CFG,
- (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
- NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ if (sc->nge_tbi) {
+ if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
+ == IFM_FDX) {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ }
} else {
- NGE_CLRBIT(sc, NGE_TX_CFG,
- (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
- NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ } else {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+ }
}
nge_tick(sc);
@@ -1851,15 +1955,46 @@ nge_ifmedia_upd(ifp)
sc = ifp->if_softc;
- mii = device_get_softc(sc->nge_miibus);
- sc->nge_link = 0;
- if (mii->mii_instance) {
- struct mii_softc *miisc;
- for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
- miisc = LIST_NEXT(miisc, mii_list))
- mii_phy_reset(miisc);
+ if (sc->nge_tbi) {
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ CSR_WRITE_4(sc, NGE_TBI_ANAR,
+ CSR_READ_4(sc, NGE_TBI_ANAR)
+ | NGE_TBIANAR_HDX | NGE_TBIANAR_FDX
+ | NGE_TBIANAR_PS1 | NGE_TBIANAR_PS2);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG
+ | NGE_TBIBMCR_RESTART_ANEG);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, NGE_TBIBMCR_ENABLE_ANEG);
+ } else if ((sc->nge_ifmedia.ifm_cur->ifm_media
+ & IFM_GMASK) == IFM_FDX) {
+ NGE_SETBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_SETBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+
+ CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
+ } else {
+ NGE_CLRBIT(sc, NGE_TX_CFG,
+ (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR));
+ NGE_CLRBIT(sc, NGE_RX_CFG, NGE_RXCFG_RX_FDX);
+
+ CSR_WRITE_4(sc, NGE_TBI_ANAR, 0);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
+ }
+
+ CSR_WRITE_4(sc, NGE_GPIO, CSR_READ_4(sc, NGE_GPIO)
+ & ~NGE_GPIO_GP3_OUT);
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ sc->nge_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
+ miisc = LIST_NEXT(miisc, mii_list))
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
}
- mii_mediachg(mii);
return(0);
}
@@ -1877,10 +2012,43 @@ nge_ifmedia_sts(ifp, ifmr)
sc = ifp->if_softc;
- mii = device_get_softc(sc->nge_miibus);
- mii_pollstat(mii);
- ifmr->ifm_active = mii->mii_media_active;
- ifmr->ifm_status = mii->mii_media_status;
+ if (sc->nge_tbi) {
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+
+ if (CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
+ ifmr->ifm_status |= IFM_ACTIVE;
+ }
+ if (CSR_READ_4(sc, NGE_TBI_BMCR) & NGE_TBIBMCR_LOOPBACK)
+ ifmr->ifm_active |= IFM_LOOP;
+ if (!CSR_READ_4(sc, NGE_TBI_BMSR) & NGE_TBIBMSR_ANEG_DONE) {
+ ifmr->ifm_active |= IFM_NONE;
+ ifmr->ifm_status = 0;
+ return;
+ }
+ ifmr->ifm_active |= IFM_1000_SX;
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ ifmr->ifm_active |= IFM_AUTO;
+ if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
+ & NGE_TBIANAR_FDX) {
+ ifmr->ifm_active |= IFM_FDX;
+ }else if (CSR_READ_4(sc, NGE_TBI_ANLPAR)
+ & NGE_TBIANAR_HDX) {
+ ifmr->ifm_active |= IFM_HDX;
+ }
+ } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
+ == IFM_FDX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+ }
return;
}
@@ -1953,8 +2121,14 @@ nge_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
- mii = device_get_softc(sc->nge_miibus);
- error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ if (sc->nge_tbi) {
+ error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia,
+ command);
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
+ command);
+ }
break;
default:
error = EINVAL;
@@ -2002,7 +2176,11 @@ nge_stop(sc)
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
- mii = device_get_softc(sc->nge_miibus);
+ if (sc->nge_tbi) {
+ mii = NULL;
+ } else {
+ mii = device_get_softc(sc->nge_miibus);
+ }
untimeout(nge_tick, sc, sc->nge_stat_ch);
CSR_WRITE_4(sc, NGE_IER, 0);
@@ -2012,7 +2190,8 @@ nge_stop(sc)
CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0);
CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0);
- mii_down(mii);
+ if (!sc->nge_tbi)
+ mii_down(mii);
sc->nge_link = 0;
diff --git a/sys/dev/nge/if_ngereg.h b/sys/dev/nge/if_ngereg.h
index e529245..13baa7b 100644
--- a/sys/dev/nge/if_ngereg.h
+++ b/sys/dev/nge/if_ngereg.h
@@ -128,6 +128,7 @@
#define NGE_CFG_PHYINTR_LNK 0x00080000
#define NGE_CFG_PHYINTR_DUP 0x00100000
#define NGE_CFG_MODE_1000 0x00400000
+#define NGE_CFG_TBI_EN 0x01000000
#define NGE_CFG_DUPLEX_STS 0x10000000
#define NGE_CFG_SPEED_STS 0x60000000
#define NGE_CFG_LINK_STS 0x80000000
@@ -421,7 +422,7 @@
/* TBI BMCR */
#define NGE_TBIBMCR_RESTART_ANEG 0x00000200
#define NGE_TBIBMCR_ENABLE_ANEG 0x00001000
-#define NGE_TBIBMCR_LOOPBACK 0x00004000
+#define NGE_TBIBMCR_LOOPBACK 0x00004000
/* TBI BMSR */
#define NGE_TBIBMSR_ANEG_DONE 0x00000004
@@ -430,6 +431,8 @@
/* TBI ANAR */
#define NGE_TBIANAR_HDX 0x00000020
#define NGE_TBIANAR_FDX 0x00000040
+#define NGE_TBIANAR_PS1 0x00000080
+#define NGE_TBIANAR_PS2 0x00000100
#define NGE_TBIANAR_PCAP 0x00000180
#define NGE_TBIANAR_REMFAULT 0x00003000
#define NGE_TBIANAR_NEXTPAGE 0x00008000
@@ -437,6 +440,8 @@
/* TBI ANLPAR */
#define NGE_TBIANLPAR_HDX 0x00000020
#define NGE_TBIANLPAR_FDX 0x00000040
+#define NGE_TBIANAR_PS1 0x00000080
+#define NGE_TBIANAR_PS2 0x00000100
#define NGE_TBIANLPAR_PCAP 0x00000180
#define NGE_TBIANLPAR_REMFAULT 0x00003000
#define NGE_TBIANLPAR_NEXTPAGE 0x00008000
@@ -652,6 +657,8 @@ struct nge_softc {
SLIST_HEAD(__nge_jfreehead, nge_jpool_entry) nge_jfree_listhead;
SLIST_HEAD(__nge_jinusehead, nge_jpool_entry) nge_jinuse_listhead;
struct mtx nge_mtx;
+ u_int8_t nge_tbi;
+ struct ifmedia nge_ifmedia;
};
/*
OpenPOWER on IntegriCloud