summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_nge.c550
-rw-r--r--sys/dev/pci/if_ngereg.h38
2 files changed, 423 insertions, 165 deletions
diff --git a/sys/dev/pci/if_nge.c b/sys/dev/pci/if_nge.c
index 41f21ae0744..8007ba0c3c2 100644
--- a/sys/dev/pci/if_nge.c
+++ b/sys/dev/pci/if_nge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_nge.c,v 1.21 2002/09/21 15:05:49 nate Exp $ */
+/* $OpenBSD: if_nge.c,v 1.22 2002/09/21 15:29:46 nate Exp $ */
/*
* Copyright (c) 2001 Wind River Systems
* Copyright (c) 1997, 1998, 1999, 2000, 2001
@@ -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/dev/nge/if_nge.c,v 1.19 2001/07/25 00:19:55 brooks Exp $
+ * $FreeBSD: if_nge.c,v 1.35 2002/08/08 18:33:28 ambrisko Exp $
*/
/*
@@ -145,7 +145,6 @@ int nge_newbuf(struct nge_softc *, struct nge_desc *,
struct mbuf *);
int nge_encap(struct nge_softc *, struct mbuf *, u_int32_t *);
void nge_rxeof(struct nge_softc *);
-void nge_rxeoc(struct nge_softc *);
void nge_txeof(struct nge_softc *);
int nge_intr(void *);
void nge_tick(void *);
@@ -155,8 +154,10 @@ void nge_init(void *);
void nge_stop(struct nge_softc *);
void nge_watchdog(struct ifnet *);
void nge_shutdown(void *);
-int nge_ifmedia_upd(struct ifnet *);
-void nge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+int nge_ifmedia_mii_upd(struct ifnet *);
+void nge_ifmedia_mii_sts(struct ifnet *, struct ifmediareq *);
+int nge_ifmedia_tbi_upd(struct ifnet *);
+void nge_ifmedia_tbi_sts(struct ifnet *, struct ifmediareq *);
void nge_delay(struct nge_softc *);
void nge_eeprom_idle(struct nge_softc *);
@@ -538,6 +539,8 @@ nge_miibus_readreg(dev, phy, reg)
struct nge_softc *sc = (struct nge_softc *)dev;
struct nge_mii_frame frame;
+ DPRINTFN(9, ("%s: nge_miibus_readreg\n", sc->sc_dv.dv_xname));
+
bzero((char *)&frame, sizeof(frame));
frame.mii_phyaddr = phy;
@@ -556,6 +559,8 @@ nge_miibus_writereg(dev, phy, reg, data)
struct nge_mii_frame frame;
+ DPRINTFN(9, ("%s: nge_miibus_writereg\n", sc->sc_dv.dv_xname));
+
bzero((char *)&frame, sizeof(frame));
frame.mii_phyaddr = phy;
@@ -570,36 +575,32 @@ nge_miibus_statchg(dev)
{
struct nge_softc *sc = (struct nge_softc *)dev;
struct mii_data *mii = &sc->nge_mii;
+ u_int32_t txcfg, rxcfg;
+
+ txcfg = CSR_READ_4(sc, NGE_TX_CFG);
+ rxcfg = CSR_READ_4(sc, NGE_RX_CFG);
+
+ DPRINTFN(4, ("%s: nge_miibus_statchg txcfg=%#x, rxcfg=%#x\n",
+ sc->sc_dv.dv_xname, txcfg, rxcfg));
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);
+ txcfg |= (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR);
+ rxcfg |= (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);
+ txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR);
+ rxcfg &= ~(NGE_RXCFG_RX_FDX);
}
- switch (IFM_SUBTYPE(sc->nge_mii.mii_media_active)) {
- case IFM_1000_TX: /* Gigabit using GMII interface */
- NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
- NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_TBI_EN);
- break;
+ txcfg |= NGE_TXCFG_AUTOPAD;
+
+ CSR_WRITE_4(sc, NGE_TX_CFG, txcfg);
+ CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg);
- case IFM_1000_SX: /* Gigabit using TBI interface */
- case IFM_1000_CX:
- case IFM_1000_LX:
+ /* If we have a 1000Mbps link, set the mode_1000 bit. */
+ if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_TX)
+ NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
+ else
NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
- NGE_SETBIT(sc, NGE_CFG, NGE_CFG_TBI_EN);
- break;
-
- default: /* Default to MII interface */
- NGE_CLRBIT(sc, NGE_CFG, NGE_CFG_MODE_1000|
- NGE_CFG_TBI_EN);
- break;
- }
-
}
u_int32_t
@@ -658,7 +659,7 @@ nge_setmulti(sc)
*/
NGE_SETBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_MCHASH);
NGE_CLRBIT(sc, NGE_RXFILT_CTL,
- NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH);
+ NGE_RXFILTCTL_ALLMULTI|NGE_RXFILTCTL_UCHASH);
filtsave = CSR_READ_4(sc, NGE_RXFILT_CTL);
@@ -734,8 +735,6 @@ nge_probe(parent, match, aux)
return (0);
}
-struct nge_softc *my_nge_softc;
-
/*
* Attach the interface. Allocate softc structures, do ifmedia
* setup and ethernet/BPF attach.
@@ -762,12 +761,11 @@ nge_attach(parent, self, aux)
caddr_t kva;
s = splimp();
- my_nge_softc = sc;
/*
* Handle power management nonsense.
*/
- DPRINTFN(5, ("Preparing for conf read\n"));
+ DPRINTFN(5, ("%s: preparing for conf read\n", sc->sc_dv.dv_xname));
command = pci_conf_read(pc, pa->pa_tag, NGE_PCI_CAPID) & 0x000000FF;
if (command == 0x01) {
command = pci_conf_read(pc, pa->pa_tag, NGE_PCI_PWRMGMTCTRL);
@@ -797,7 +795,7 @@ nge_attach(parent, self, aux)
/*
* Map control/status registers.
*/
- DPRINTFN(5, ("Map control/status regs\n"));
+ DPRINTFN(5, ("%s: map control/status regs\n", sc->sc_dv.dv_xname));
command = pci_conf_read(pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
command |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE;
@@ -814,12 +812,12 @@ nge_attach(parent, self, aux)
/*
* Map control/status registers.
*/
- DPRINTFN(5, ("pci_io_find\n"));
+ DPRINTFN(5, ("%s: pci_io_find\n", sc->sc_dv.dv_xname));
if (pci_io_find(pc, pa->pa_tag, NGE_PCI_LOIO, &iobase, &iosize)) {
printf(": can't find i/o space\n");
goto fail;
}
- DPRINTFN(5, ("bus_space_map\n"));
+ DPRINTFN(5, ("%s: bus_space_map\n", sc->sc_dv.dv_xname));
if (bus_space_map(pa->pa_iot, iobase, iosize, 0, &sc->nge_bhandle)) {
printf(": can't map i/o space\n");
goto fail;
@@ -832,13 +830,13 @@ nge_attach(parent, self, aux)
error = ENXIO;
goto fail;
}
- DPRINTFN(5, ("pci_mem_find\n"));
+ DPRINTFN(5, ("%s: pci_mem_find\n", sc->sc_dv.dv_xname));
if (pci_mem_find(pc, pa->pa_tag, NGE_PCI_LOMEM, &iobase,
&iosize, NULL)) {
printf(": can't find mem space\n");
goto fail;
}
- DPRINTFN(5, ("bus_space_map\n"));
+ DPRINTFN(5, ("%s: bus_space_map\n", sc->sc_dv.dv_xname));
if (bus_space_map(pa->pa_memt, iobase, iosize, 0, &sc->nge_bhandle)) {
printf(": can't map mem space\n");
goto fail;
@@ -847,15 +845,18 @@ nge_attach(parent, self, aux)
sc->nge_btag = pa->pa_memt;
#endif
- DPRINTFN(5, ("pci_intr_map\n"));
+ /* Disable all interrupts */
+ CSR_WRITE_4(sc, NGE_IER, 0);
+
+ DPRINTFN(5, ("%s: pci_intr_map\n", sc->sc_dv.dv_xname));
if (pci_intr_map(pa, &ih)) {
printf(": couldn't map interrupt\n");
goto fail;
}
- DPRINTFN(5, ("pci_intr_string\n"));
+ DPRINTFN(5, ("%s: pci_intr_string\n", sc->sc_dv.dv_xname));
intrstr = pci_intr_string(pc, ih);
- DPRINTFN(5, ("pci_intr_establish\n"));
+ DPRINTFN(5, ("%s: pci_intr_establish\n", sc->sc_dv.dv_xname));
sc->nge_intrhand = pci_intr_establish(pc, ih, IPL_NET, nge_intr, sc,
sc->sc_dv.dv_xname);
if (sc->nge_intrhand == NULL) {
@@ -868,13 +869,13 @@ nge_attach(parent, self, aux)
printf(": %s", intrstr);
/* Reset the adapter. */
- DPRINTFN(5, ("nge_reset\n"));
+ DPRINTFN(5, ("%s: nge_reset\n", sc->sc_dv.dv_xname));
nge_reset(sc);
/*
* Get station address from the EEPROM.
*/
- DPRINTFN(5, ("nge_read_eeprom\n"));
+ DPRINTFN(5, ("%s: nge_read_eeprom\n", sc->sc_dv.dv_xname));
nge_read_eeprom(sc, (caddr_t)&eaddr[4], NGE_EE_NODEADDR, 1, 0);
nge_read_eeprom(sc, (caddr_t)&eaddr[2], NGE_EE_NODEADDR + 1, 1, 0);
nge_read_eeprom(sc, (caddr_t)&eaddr[0], NGE_EE_NODEADDR + 2, 1, 0);
@@ -887,13 +888,13 @@ nge_attach(parent, self, aux)
bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
sc->sc_dmatag = pa->pa_dmat;
- DPRINTFN(5, ("bus_dmamem_alloc\n"));
+ DPRINTFN(5, ("%s: bus_dmamem_alloc\n", sc->sc_dv.dv_xname));
if (bus_dmamem_alloc(sc->sc_dmatag, sizeof(struct nge_list_data),
PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
printf("%s: can't alloc rx buffers\n", sc->sc_dv.dv_xname);
goto fail;
}
- DPRINTFN(5, ("bus_dmamem_map\n"));
+ DPRINTFN(5, ("%s: bus_dmamem_map\n", sc->sc_dv.dv_xname));
if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg,
sizeof(struct nge_list_data), &kva,
BUS_DMA_NOWAIT)) {
@@ -902,7 +903,7 @@ nge_attach(parent, self, aux)
bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
goto fail;
}
- DPRINTFN(5, ("bus_dmamem_create\n"));
+ DPRINTFN(5, ("%s: bus_dmamem_create\n", sc->sc_dv.dv_xname));
if (bus_dmamap_create(sc->sc_dmatag, sizeof(struct nge_list_data), 1,
sizeof(struct nge_list_data), 0,
BUS_DMA_NOWAIT, &dmamap)) {
@@ -912,7 +913,7 @@ nge_attach(parent, self, aux)
bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
goto fail;
}
- DPRINTFN(5, ("bus_dmamem_load\n"));
+ DPRINTFN(5, ("%s: bus_dmamem_load\n", sc->sc_dv.dv_xname));
if (bus_dmamap_load(sc->sc_dmatag, dmamap, kva,
sizeof(struct nge_list_data), NULL,
BUS_DMA_NOWAIT)) {
@@ -923,12 +924,12 @@ nge_attach(parent, self, aux)
goto fail;
}
- DPRINTFN(5, ("bzero\n"));
+ DPRINTFN(5, ("%s: bzero\n", sc->sc_dv.dv_xname));
sc->nge_ldata = (struct nge_list_data *)kva;
bzero(sc->nge_ldata, sizeof(struct nge_list_data));
/* Try to allocate memory for jumbo buffers. */
- DPRINTFN(5, ("nge_alloc_jumbo_mem\n"));
+ DPRINTFN(5, ("%s: nge_alloc_jumbo_mem\n", sc->sc_dv.dv_xname));
if (nge_alloc_jumbo_mem(sc)) {
printf("%s: jumbo buffer allocation failed\n",
sc->sc_dv.dv_xname);
@@ -951,39 +952,67 @@ nge_attach(parent, self, aux)
#if NVLAN > 0
ifp->if_capabilities |= IFCAP_VLAN_MTU;
#endif
- DPRINTFN(5, ("bcopy\n"));
+ DPRINTFN(5, ("%s: bcopy\n", sc->sc_dv.dv_xname));
bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
/*
* Do MII setup.
*/
- DPRINTFN(5, ("mii setup\n"));
- sc->nge_mii.mii_ifp = ifp;
- sc->nge_mii.mii_readreg = nge_miibus_readreg;
- sc->nge_mii.mii_writereg = nge_miibus_writereg;
- sc->nge_mii.mii_statchg = nge_miibus_statchg;
- ifmedia_init(&sc->nge_mii.mii_media, 0, nge_ifmedia_upd,
- nge_ifmedia_sts);
- mii_attach(&sc->sc_dv, &sc->nge_mii, 0xffffffff, MII_PHY_ANY,
- MII_OFFSET_ANY, 0);
-
- if (LIST_FIRST(&sc->nge_mii.mii_phys) == NULL) {
- printf("%s: no PHY found!\n", sc->sc_dv.dv_xname);
- ifmedia_add(&sc->nge_mii.mii_media, IFM_ETHER|IFM_MANUAL,
- 0, NULL);
- ifmedia_set(&sc->nge_mii.mii_media, IFM_ETHER|IFM_MANUAL);
+ DPRINTFN(5, ("%s: mii setup\n", sc->sc_dv.dv_xname));
+ if (CSR_READ_4(sc, NGE_CFG) & NGE_CFG_TBI_EN) {
+ DPRINTFN(5, ("%s: TBI mode\n", sc->sc_dv.dv_xname));
+ sc->nge_tbi = 1;
+
+ ifmedia_init(&sc->nge_ifmedia, 0, nge_ifmedia_tbi_upd,
+ nge_ifmedia_tbi_sts);
+
+ ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_NONE, 0, NULL),
+ ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_1000_SX, 0, NULL);
+ ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_1000_SX|IFM_FDX,
+ 0, NULL);
+ ifmedia_add(&sc->nge_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL);
+
+ ifmedia_set(&sc->nge_ifmedia, IFM_ETHER|IFM_AUTO);
+
+ 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_GP4_OUTENB
+ | NGE_GPIO_GP5_OUTENB);
+
+ NGE_SETBIT(sc, NGE_CFG, NGE_CFG_MODE_1000);
+ } else {
+ sc->nge_mii.mii_ifp = ifp;
+ sc->nge_mii.mii_readreg = nge_miibus_readreg;
+ sc->nge_mii.mii_writereg = nge_miibus_writereg;
+ sc->nge_mii.mii_statchg = nge_miibus_statchg;
+
+ ifmedia_init(&sc->nge_mii.mii_media, 0, nge_ifmedia_mii_upd,
+ nge_ifmedia_mii_sts);
+ mii_attach(&sc->sc_dv, &sc->nge_mii, 0xffffffff, MII_PHY_ANY,
+ MII_OFFSET_ANY, 0);
+
+ if (LIST_FIRST(&sc->nge_mii.mii_phys) == NULL) {
+
+ printf("%s: no PHY found!\n", sc->sc_dv.dv_xname);
+ ifmedia_add(&sc->nge_mii.mii_media,
+ IFM_ETHER|IFM_MANUAL, 0, NULL);
+ ifmedia_set(&sc->nge_mii.mii_media,
+ IFM_ETHER|IFM_MANUAL);
+ }
+ else
+ ifmedia_set(&sc->nge_mii.mii_media,
+ IFM_ETHER|IFM_AUTO);
}
- else
- ifmedia_set(&sc->nge_mii.mii_media, IFM_ETHER|IFM_AUTO);
/*
* Call MI attach routine.
*/
- DPRINTFN(5, ("if_attach\n"));
+ DPRINTFN(5, ("%s: if_attach\n", sc->sc_dv.dv_xname));
if_attach(ifp);
- DPRINTFN(5, ("ether_ifattach\n"));
+ DPRINTFN(5, ("%s: ether_ifattach\n", sc->sc_dv.dv_xname));
ether_ifattach(ifp);
- DPRINTFN(5, ("timeout_set\n"));
+ DPRINTFN(5, ("%s: timeout_set\n", sc->sc_dv.dv_xname));
timeout_set(&sc->nge_timeout, nge_tick, sc);
timeout_add(&sc->nge_timeout, hz);
@@ -1113,7 +1142,8 @@ nge_newbuf(sc, c, m)
c->nge_mbuf = m_new;
c->nge_ptr = vtophys(mtod(m_new, caddr_t));
- DPRINTFN(7,("c->nge_ptr = 0x%08X\n", c->nge_ptr));
+ DPRINTFN(7,("%s: c->nge_ptr=%#x\n", sc->sc_dv.dv_xname,
+ c->nge_ptr));
c->nge_ctl = m_new->m_len;
c->nge_extsts = 0;
@@ -1158,8 +1188,9 @@ nge_alloc_jumbo_mem(sc)
return (ENOBUFS);
}
sc->nge_cdata.nge_jumbo_buf = (caddr_t)kva;
- DPRINTFN(1,("nge_jumbo_buf = 0x%08X\n", sc->nge_cdata.nge_jumbo_buf));
- DPRINTFN(1,("NGE_MCLBYTES = 0x%08X\n", NGE_MCLBYTES));
+ DPRINTFN(1,("%s: nge_jumbo_buf=%#x, NGE_MCLBYTES=%#x\n",
+ sc->sc_dv.dv_xname , sc->nge_cdata.nge_jumbo_buf,
+ NGE_MCLBYTES));
LIST_INIT(&sc->nge_jfree_listhead);
LIST_INIT(&sc->nge_jinuse_listhead);
@@ -1304,24 +1335,40 @@ nge_rxeof(sc)
continue;
}
-
/*
* Ok. NatSemi really screwed up here. This is the
* only gigE chip I know of with alignment constraints
* on receive buffers. RX buffers must be 64-bit aligned.
*/
- m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
- total_len + ETHER_ALIGN, 0, ifp, NULL);
- nge_newbuf(sc, cur_rx, m);
- if (m0 == NULL) {
- printf("%s: no receive buffers "
- "available -- packet dropped!\n",
- sc->sc_dv.dv_xname);
- ifp->if_ierrors++;
- continue;
+#ifdef __i386__
+ /*
+ * By popular demand, ignore the alignment problems
+ * on the Intel x86 platform. The performance hit
+ * incurred due to unaligned accesses is much smaller
+ * than the hit produced by forcing buffer copies all
+ * the time, especially with jumbo frames. We still
+ * need to fix up the alignment everywhere else though.
+ */
+ if (nge_newbuf(sc, cur_rx, NULL) == ENOBUFS) {
+#endif
+ m0 = m_devget(mtod(m, char *), total_len,
+ ETHER_ALIGN, ifp, NULL);
+ nge_newbuf(sc, cur_rx, m);
+ if (m0 == NULL) {
+ printf("%s: no receive buffers "
+ "available -- packet dropped!\n",
+ sc->sc_dv.dv_xname);
+ ifp->if_ierrors++;
+ continue;
+ }
+ m_adj(m0, ETHER_ALIGN);
+ m = m0;
+#ifdef __i386__
+ } else {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = total_len;
}
- m_adj(m0, ETHER_ALIGN);
- m = m0;
+#endif
ifp->if_ipackets++;
@@ -1371,18 +1418,6 @@ nge_rxeof(sc)
sc->nge_cdata.nge_rx_prod = i;
}
-void
-nge_rxeoc(sc)
- struct nge_softc *sc;
-{
- struct ifnet *ifp;
-
- ifp = &sc->arpcom.ac_if;
- nge_rxeof(sc);
- ifp->if_flags &= ~IFF_RUNNING;
- nge_init(sc);
-}
-
/*
* A frame was downloaded to the chip. It's safe for us to clean up
* the list buffers.
@@ -1457,20 +1492,70 @@ nge_tick(xsc)
s = splimp();
- mii_tick(mii);
+ DPRINTFN(10, ("%s: nge_tick: link=%d\n", sc->sc_dv.dv_xname,
+ sc->nge_link));
+
+ timeout_add(&sc->nge_timeout, hz);
+ if (sc->nge_link) {
+ splx(s);
+ return;
+ }
+
+ if (sc->nge_tbi) {
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ u_int32_t bmsr, anlpar, txcfg, rxcfg;
+
+ bmsr = CSR_READ_4(sc, NGE_TBI_BMSR);
+ DPRINTFN(2, ("%s: nge_tick: bmsr=%#x\n",
+ sc->sc_dv.dv_xname, bmsr));
- if (!sc->nge_link) {
+ if (!(bmsr & NGE_TBIBMSR_ANEG_DONE)) {
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, 0);
+
+ splx(s);
+ return;
+ }
+
+ anlpar = CSR_READ_4(sc, NGE_TBI_ANLPAR);
+ txcfg = CSR_READ_4(sc, NGE_TX_CFG);
+ rxcfg = CSR_READ_4(sc, NGE_RX_CFG);
+
+ DPRINTFN(2, ("%s: nge_tick: anlpar=%#x, txcfg=%#x, "
+ "rxcfg=%#x\n", sc->sc_dv.dv_xname, anlpar,
+ txcfg, rxcfg));
+
+ if (anlpar == 0 || anlpar & NGE_TBIANAR_FDX) {
+ txcfg |= (NGE_TXCFG_IGN_HBEAT|
+ NGE_TXCFG_IGN_CARR);
+ rxcfg |= NGE_RXCFG_RX_FDX;
+ } else {
+ txcfg &= ~(NGE_TXCFG_IGN_HBEAT|
+ NGE_TXCFG_IGN_CARR);
+ rxcfg &= ~(NGE_RXCFG_RX_FDX);
+ }
+ txcfg |= NGE_TXCFG_AUTOPAD;
+ CSR_WRITE_4(sc, NGE_TX_CFG, txcfg);
+ CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg);
+ }
+
+ DPRINTF(("%s: gigabit link up\n", sc->sc_dv.dv_xname));
+ sc->nge_link++;
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ nge_start(ifp);
+ } else {
+ mii_tick(mii);
mii_pollstat(mii);
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_TX)
- DPRINTFN("%s: gigabit link up\n",
- sc->sc_dv.dv_xname);
+ DPRINTF(("%s: gigabit link up\n",
+ sc->sc_dv.dv_xname));
if (!IFQ_IS_EMPTY(&ifp->if_snd))
nge_start(ifp);
- } else
- timeout_add(&sc->nge_timeout, hz);
+ }
+
}
splx(s);
@@ -1497,6 +1582,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);
@@ -1513,13 +1603,15 @@ nge_intr(arg)
nge_txeof(sc);
if ((status & NGE_ISR_RX_DESC_OK) ||
+ (status & NGE_ISR_RX_ERR) ||
+ (status & NGE_ISR_RX_OFLOW) ||
+ (status & NGE_ISR_RX_FIFO_OFLOW) ||
+ (status & NGE_ISR_RX_IDLE) ||
(status & NGE_ISR_RX_OK))
nge_rxeof(sc);
- if ((status & NGE_ISR_RX_ERR) ||
- (status & NGE_ISR_RX_OFLOW)) {
- nge_rxeoc(sc);
- }
+ if ((status & NGE_ISR_RX_IDLE))
+ NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
if (status & NGE_ISR_SYSERR) {
nge_reset(sc);
@@ -1527,10 +1619,17 @@ nge_intr(arg)
nge_init(sc);
}
- if (status & NGE_ISR_PHY_INTR) {
+#if 0
+ /*
+ * XXX: nge_tick() is not ready to be called this way
+ * it screws up the aneg timeout because mii_tick() is
+ * only to be called once per second.
+ */
+ if (status & NGE_IMR_PHY_INTR) {
sc->nge_link = 0;
nge_tick(sc);
}
+#endif
}
/* Re-enable interrupts. */
@@ -1539,6 +1638,11 @@ nge_intr(arg)
if (!IFQ_IS_EMPTY(&ifp->if_snd))
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 claimed;
}
@@ -1579,7 +1683,8 @@ nge_encap(sc, m_head, txidx)
f = &sc->nge_ldata->nge_tx_list[frag];
f->nge_ctl = NGE_CMDSTS_MORE | m->m_len;
f->nge_ptr = vtophys(mtod(m, vm_offset_t));
- DPRINTFN(7,("f->nge_ptr = 0x%08X\n", f->nge_ptr));
+ DPRINTFN(7,("%s: f->nge_ptr=%#x\n",
+ sc->sc_dv.dv_xname, f->nge_ptr));
if (cnt != 0)
f->nge_ctl |= NGE_CMDSTS_OWN;
cur = frag;
@@ -1599,13 +1704,13 @@ nge_encap(sc, m_head, txidx)
if (m_head->m_pkthdr.csum) {
if (m_head->m_pkthdr.csum & M_IPV4_CSUM_OUT)
sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
- NGE_TXEXTSTS_IPCSUM;
+ NGE_TXEXTSTS_IPCSUM;
if (m_head->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
- NGE_TXEXTSTS_TCPCSUM;
+ NGE_TXEXTSTS_TCPCSUM;
if (m_head->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
sc->nge_ldata->nge_tx_list[*txidx].nge_extsts |=
- NGE_TXEXTSTS_UDPCSUM;
+ NGE_TXEXTSTS_UDPCSUM;
}
#if NVLAN > 0
@@ -1686,16 +1791,15 @@ nge_start(ifp)
ifp->if_timer = 5;
}
-int nge_loop = 0;
-
void
nge_init(xsc)
void *xsc;
{
struct nge_softc *sc = xsc;
struct ifnet *ifp = &sc->arpcom.ac_if;
- struct mii_data *mii = &sc->nge_mii;
- int s;
+ struct mii_data *mii;
+ u_int32_t txcfg, rxcfg;
+ int s, media;
if (ifp->if_flags & IFF_RUNNING)
return;
@@ -1706,10 +1810,8 @@ nge_init(xsc)
* Cancel pending I/O and free all RX/TX buffers.
*/
nge_stop(sc);
- nge_reset(sc);
- /* Turn the receive filter off */
- NGE_CLRBIT(sc, NGE_RXFILT_CTL, NGE_RXFILTCTL_ENABLE);
+ mii = sc->nge_tbi ? NULL: &sc->nge_mii;
/* Set MAC address */
CSR_WRITE_4(sc, NGE_RXFILT_CTL, NGE_FILTADDR_PAR0);
@@ -1798,8 +1900,7 @@ nge_init(xsc)
#endif
/* Set TX configuration */
- CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG |
- (nge_loop ? NGE_TXCFG_LOOPBK : 0));
+ CSR_WRITE_4(sc, NGE_TX_CFG, NGE_TXCFG);
/*
* Enable TX IPv4 checksumming on a per-packet basis.
@@ -1817,16 +1918,32 @@ nge_init(xsc)
#endif
/* 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)
+ media = sc->nge_ifmedia.ifm_cur->ifm_media;
+ else
+ media = mii->mii_media_active;
+
+ txcfg = CSR_READ_4(sc, NGE_TX_CFG);
+ rxcfg = CSR_READ_4(sc, NGE_RX_CFG);
+
+ DPRINTFN(4, ("%s: nge_init txcfg=%#x, rxcfg=%#x\n",
+ sc->sc_dv.dv_xname, txcfg, rxcfg));
+
+ if ((media & IFM_GMASK) == IFM_FDX) {
+ txcfg |= (NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR);
+ rxcfg |= (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);
+ txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR);
+ rxcfg &= ~(NGE_RXCFG_RX_FDX);
}
+ txcfg |= NGE_TXCFG_AUTOPAD;
+
+ CSR_WRITE_4(sc, NGE_TX_CFG, txcfg);
+ CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg);
+
+ nge_tick(sc);
+
/*
* Enable the delivery of PHY interrupts based on
* link/speed/duplex status changes and enable return
@@ -1836,7 +1953,16 @@ nge_init(xsc)
NGE_SETBIT(sc, NGE_CFG, NGE_CFG_PHYINTR_SPD|NGE_CFG_PHYINTR_LNK|
NGE_CFG_PHYINTR_DUP|NGE_CFG_EXTSTS_ENB);
- DPRINTFN("NGE_CFG: 0x%08X\n", CSR_READ_4(sc, NGE_CFG));
+ DPRINTFN(1, ("%s: nge_init: config=%#x\n", sc->sc_dv.dv_xname,
+ CSR_READ_4(sc, NGE_CFG)));
+
+ /*
+ * Configure interrupt holdoff (moderation). We can
+ * have the chip delay interrupt delivery for a certain
+ * period. Units are in 100us, and the max setting
+ * is 25500us (0xFF x 100us). Default is a 100us holdoff.
+ */
+ CSR_WRITE_4(sc, NGE_IHR, 0x01);
/*
* Enable interrupts.
@@ -1848,7 +1974,10 @@ nge_init(xsc)
NGE_CLRBIT(sc, NGE_CSR, NGE_CSR_TX_DISABLE|NGE_CSR_RX_DISABLE);
NGE_SETBIT(sc, NGE_CSR, NGE_CSR_RX_ENABLE);
- nge_ifmedia_upd(ifp);
+ if (sc->nge_tbi)
+ nge_ifmedia_tbi_upd(ifp);
+ else
+ nge_ifmedia_mii_upd(ifp);
ifp->if_flags |= IFF_RUNNING;
ifp->if_flags &= ~IFF_OACTIVE;
@@ -1857,16 +1986,19 @@ nge_init(xsc)
}
/*
- * Set media options.
+ * Set mii media options.
*/
int
-nge_ifmedia_upd(ifp)
+nge_ifmedia_mii_upd(ifp)
struct ifnet *ifp;
{
struct nge_softc *sc = ifp->if_softc;
- struct mii_data *mii = &sc->nge_mii;
+ struct mii_data *mii = &sc->nge_mii;
+
+ DPRINTFN(2, ("%s: nge_ifmedia_mii_upd\n", sc->sc_dv.dv_xname));
sc->nge_link = 0;
+
if (mii->mii_instance) {
struct mii_softc *miisc;
for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
@@ -1879,21 +2011,127 @@ nge_ifmedia_upd(ifp)
}
/*
- * Report current media status.
+ * Report current mii media status.
*/
void
-nge_ifmedia_sts(ifp, ifmr)
+nge_ifmedia_mii_sts(ifp, ifmr)
struct ifnet *ifp;
struct ifmediareq *ifmr;
{
struct nge_softc *sc = ifp->if_softc;
- struct mii_data *mii = &sc->nge_mii;
+ struct mii_data *mii = &sc->nge_mii;
+
+ DPRINTFN(2, ("%s: nge_ifmedia_mii_sts\n", sc->sc_dv.dv_xname));
mii_pollstat(mii);
ifmr->ifm_active = mii->mii_media_active;
ifmr->ifm_status = mii->mii_media_status;
}
+/*
+ * Set mii media options.
+ */
+int
+nge_ifmedia_tbi_upd(ifp)
+ struct ifnet *ifp;
+{
+ struct nge_softc *sc = ifp->if_softc;
+
+ DPRINTFN(2, ("%s: nge_ifmedia_tbi_upd\n", sc->sc_dv.dv_xname));
+
+ sc->nge_link = 0;
+
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media)
+ == IFM_AUTO) {
+ u_int32_t anar, bmcr;
+ anar = CSR_READ_4(sc, NGE_TBI_ANAR);
+ anar |= (NGE_TBIANAR_HDX | NGE_TBIANAR_FDX);
+ CSR_WRITE_4(sc, NGE_TBI_ANAR, anar);
+
+ bmcr = CSR_READ_4(sc, NGE_TBI_BMCR);
+ bmcr |= (NGE_TBIBMCR_ENABLE_ANEG|NGE_TBIBMCR_RESTART_ANEG);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, bmcr);
+
+ bmcr &= ~(NGE_TBIBMCR_RESTART_ANEG);
+ CSR_WRITE_4(sc, NGE_TBI_BMCR, bmcr);
+ } else {
+ u_int32_t txcfg, rxcfg;
+ txcfg = CSR_READ_4(sc, NGE_TX_CFG);
+ rxcfg = CSR_READ_4(sc, NGE_RX_CFG);
+
+ if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK)
+ == IFM_FDX) {
+ txcfg |= NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR;
+ rxcfg |= NGE_RXCFG_RX_FDX;
+ } else {
+ txcfg &= ~(NGE_TXCFG_IGN_HBEAT|NGE_TXCFG_IGN_CARR);
+ rxcfg &= ~(NGE_RXCFG_RX_FDX);
+ }
+
+ txcfg |= NGE_TXCFG_AUTOPAD;
+ CSR_WRITE_4(sc, NGE_TX_CFG, txcfg);
+ CSR_WRITE_4(sc, NGE_RX_CFG, rxcfg);
+ }
+
+ NGE_CLRBIT(sc, NGE_GPIO, NGE_GPIO_GP3_OUT);
+
+ return(0);
+}
+
+/*
+ * Report current tbi media status.
+ */
+void
+nge_ifmedia_tbi_sts(ifp, ifmr)
+ struct ifnet *ifp;
+ struct ifmediareq *ifmr;
+{
+ struct nge_softc *sc = ifp->if_softc;
+ u_int32_t bmcr;
+
+ bmcr = CSR_READ_4(sc, NGE_TBI_BMCR);
+
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) == IFM_AUTO) {
+ u_int32_t bmsr = CSR_READ_4(sc, NGE_TBI_BMSR);
+ DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts bmsr=%#x, bmcr=%#x\n",
+ sc->sc_dv.dv_xname, bmsr, bmcr));
+
+ if (!(bmsr & NGE_TBIBMSR_ANEG_DONE)) {
+ ifmr->ifm_active = IFM_ETHER|IFM_NONE;
+ ifmr->ifm_status = IFM_AVALID;
+ return;
+ }
+ } else {
+ DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts bmcr=%#x\n",
+ sc->sc_dv.dv_xname, bmcr));
+ }
+
+ ifmr->ifm_status = IFM_AVALID|IFM_ACTIVE;
+ ifmr->ifm_active = IFM_ETHER|IFM_1000_SX;
+
+ if (bmcr & NGE_TBIBMCR_LOOPBACK)
+ ifmr->ifm_active |= IFM_LOOP;
+
+ if (IFM_SUBTYPE(sc->nge_ifmedia.ifm_cur->ifm_media) == IFM_AUTO) {
+ u_int32_t anlpar = CSR_READ_4(sc, NGE_TBI_ANLPAR);
+ DPRINTFN(2, ("%s: nge_ifmedia_tbi_sts anlpar=%#x\n",
+ sc->sc_dv.dv_xname, anlpar));
+
+ ifmr->ifm_active |= IFM_AUTO;
+ if (anlpar & NGE_TBIANLPAR_FDX) {
+ ifmr->ifm_active |= IFM_FDX;
+ } else if (anlpar & NGE_TBIANLPAR_HDX) {
+ ifmr->ifm_active |= IFM_HDX;
+ } else
+ ifmr->ifm_active |= IFM_FDX;
+
+ } else if ((sc->nge_ifmedia.ifm_cur->ifm_media & IFM_GMASK) == IFM_FDX)
+ ifmr->ifm_active |= IFM_FDX;
+ else
+ ifmr->ifm_active |= IFM_HDX;
+
+}
+
int
nge_ioctl(ifp, command, data)
struct ifnet *ifp;
@@ -1920,9 +2158,9 @@ nge_ioctl(ifp, command, data)
else {
ifp->if_mtu = ifr->ifr_mtu;
/*
- * If requested MTU is larger than the
- * size of the TX buffer, turn off TX
- * checksumming.
+ * Workaround: if the MTU is larger than
+ * 8152 (TX FIFO size minus 64 minus 18), turn off
+ * TX checksum offloading.
*/
if (ifr->ifr_mtu >= 8152)
ifp->if_capabilities &= ~(IFCAP_CSUM_IPv4 |
@@ -1987,8 +2225,14 @@ nge_ioctl(ifp, command, data)
break;
case SIOCGIFMEDIA:
case SIOCSIFMEDIA:
- mii = &sc->nge_mii;
- error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ if (sc->nge_tbi) {
+ error = ifmedia_ioctl(ifp, ifr, &sc->nge_ifmedia,
+ command);
+ } else {
+ mii = &sc->nge_mii;
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media,
+ command);
+ }
break;
default:
error = EINVAL;
@@ -2030,12 +2274,15 @@ nge_stop(sc)
{
int i;
struct ifnet *ifp;
- struct ifmedia_entry *ifm;
- struct mii_data *mii = &sc->nge_mii;
- int mtmp, itmp;
+ struct mii_data *mii;
ifp = &sc->arpcom.ac_if;
ifp->if_timer = 0;
+ if (sc->nge_tbi) {
+ mii = NULL;
+ } else {
+ mii = &sc->nge_mii;
+ }
timeout_del(&sc->nge_timeout);
CSR_WRITE_4(sc, NGE_IER, 0);
@@ -2045,19 +2292,8 @@ nge_stop(sc)
CSR_WRITE_4(sc, NGE_TX_LISTPTR, 0);
CSR_WRITE_4(sc, NGE_RX_LISTPTR, 0);
- /*
- * Isolate/power down the PHY, but leave the media selection
- * unchanged so that things will be put back to normal when
- * we bring the interface back up.
- */
- itmp = ifp->if_flags;
- ifp->if_flags |= IFF_UP;
- ifm = mii->mii_media.ifm_cur;
- mtmp = ifm->ifm_media;
- ifm->ifm_media = IFM_ETHER|IFM_NONE;
- mii_mediachg(mii);
- ifm->ifm_media = mtmp;
- ifp->if_flags = itmp;
+ if (!sc->nge_tbi)
+ mii_down(mii);
sc->nge_link = 0;
diff --git a/sys/dev/pci/if_ngereg.h b/sys/dev/pci/if_ngereg.h
index 65146807953..9a537de1978 100644
--- a/sys/dev/pci/if_ngereg.h
+++ b/sys/dev/pci/if_ngereg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ngereg.h,v 1.2 2001/07/02 05:38:28 nate Exp $ */
+/* $OpenBSD: if_ngereg.h,v 1.3 2002/09/21 15:29:46 nate Exp $ */
/*
* Copyright (c) 2001 Wind River Systems
* Copyright (c) 1997, 1998, 1999, 2000, 2001
@@ -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$
+ * $FreeBSD: if_ngereg.h,v 1.7 2002/08/08 18:33:28 ambrisko Exp $
*/
#define NGE_CSR 0x00
@@ -229,7 +229,9 @@
#define NGE_INTRS \
(NGE_IMR_RX_OFLOW|NGE_IMR_TX_UFLOW|NGE_IMR_TX_OK|\
NGE_IMR_TX_IDLE|NGE_IMR_RX_OK|NGE_IMR_RX_ERR|\
- NGE_IMR_SYSERR|NGE_IMR_PHY_INTR|NGE_IMR_RX_DESC_OK|NGE_IMR_TX_DESC_OK)
+ NGE_IMR_SYSERR|NGE_IMR_PHY_INTR|\
+ NGE_IMR_RX_DESC_OK|NGE_IMR_TX_DESC_OK|\
+ NGE_IMR_RX_IDLE|NGE_IMR_RX_FIFO_OFLOW)
/* Interrupt enable register */
#define NGE_IER_INTRENB 0x00000001
@@ -432,6 +434,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
@@ -439,6 +443,8 @@
/* TBI ANLPAR */
#define NGE_TBIANLPAR_HDX 0x00000020
#define NGE_TBIANLPAR_FDX 0x00000040
+#define NGE_TBIANLPAR_PS1 0x00000080
+#define NGE_TBIANLPAR_PS2 0x00000100
#define NGE_TBIANLPAR_PCAP 0x00000180
#define NGE_TBIANLPAR_REMFAULT 0x00003000
#define NGE_TBIANLPAR_NEXTPAGE 0x00008000
@@ -479,8 +485,14 @@ struct nge_desc_64 {
#define nge_ctl nge_cmdsts
u_int32_t nge_extsts;
/* Driver software section */
- struct mbuf *nge_mbuf;
- struct nge_desc_64 *nge_nextdesc;
+ union {
+ struct mbuf *nge_mbuf;
+ u_int64_t nge_dummy;
+ } nge_mb_u;
+ union {
+ struct nge_desc_64 *nge_nextdesc;
+ u_int64_t nge_dummy;
+ } nge_nd_u;
};
struct nge_desc_32 {
@@ -493,11 +505,19 @@ struct nge_desc_32 {
#define nge_ctl nge_cmdsts
u_int32_t nge_extsts;
/* Driver software section */
- struct mbuf *nge_mbuf;
- struct nge_desc_32 *nge_nextdesc;
+ union {
+ struct mbuf *nge_mbuf;
+ u_int64_t nge_dummy;
+ } nge_mb_u;
+ union {
+ struct nge_desc_32 *nge_nextdesc;
+ u_int64_t nge_dummy;
+ } nge_nd_u;
};
#define nge_desc nge_desc_32
+#define nge_mbuf nge_mb_u.nge_mbuf
+#define nge_nextdesc nge_nd_u.nge_nextdesc
#define NGE_CMDSTS_BUFLEN 0x0000FFFF
#define NGE_CMDSTS_PKT_OK 0x08000000
@@ -551,7 +571,7 @@ struct nge_desc_32 {
#define NGE_RXEXTSTS_UDPPKT 0x00200000
#define NGE_RXEXTSTS_UDPCSUMERR 0x00400000
-#define NGE_RX_LIST_CNT 64
+#define NGE_RX_LIST_CNT 128
#define NGE_TX_LIST_CNT 128
struct nge_list_data {
@@ -644,6 +664,8 @@ struct nge_softc {
struct timeout nge_timeout;
LIST_HEAD(__nge_jfreehead, nge_jpool_entry) nge_jfree_listhead;
LIST_HEAD(__nge_jinusehead, nge_jpool_entry) nge_jinuse_listhead;
+ u_int8_t nge_tbi;
+ struct ifmedia nge_ifmedia;
};
/*