diff options
author | wpaul <wpaul@FreeBSD.org> | 1999-12-05 20:02:45 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1999-12-05 20:02:45 +0000 |
commit | c32cda93bb0a38fcd29308dd4bfc8c21cc56270e (patch) | |
tree | 735306ebb035539ac51f1f8bb95ef7df91c93f89 /sys/dev/sf | |
parent | 1dab24f2833c782b1a8539f3be0435f750f97616 (diff) | |
download | FreeBSD-src-c32cda93bb0a38fcd29308dd4bfc8c21cc56270e.zip FreeBSD-src-c32cda93bb0a38fcd29308dd4bfc8c21cc56270e.tar.gz |
Modify the Adaptec "starfire" driver to reset the PHY on the MII bus
before selecting a mode. The Seeq PHY chips on the Adaptec cards that
use the AIC-6915 controller seem to need it in order to get them to
change modes correctly.
This corrects a problem that I noticed where my ANA-62022 board failed
to correctly program the full duplex bit in the macconfig1 register
when the interface was brought up. Running ifconfig sf0 would mask this
problem in some cases because polling the PHY status would cause the
miibus code to notice that full duplex was now needed and the statchg
callback would be invoked to configure the duplex setting. However it
would still get it wrong other times.
Also changed sf_miibus_statchg() to program the IPG register to match
the duplex setting in accordance with Adaptec manual's recommendations
(0x15 for full duplex, 0x11 for half duplex).
Diffstat (limited to 'sys/dev/sf')
-rw-r--r-- | sys/dev/sf/if_sf.c | 48 | ||||
-rw-r--r-- | sys/dev/sf/if_sfreg.h | 10 |
2 files changed, 47 insertions, 11 deletions
diff --git a/sys/dev/sf/if_sf.c b/sys/dev/sf/if_sf.c index d0fb709..5af924b 100644 --- a/sys/dev/sf/if_sf.c +++ b/sys/dev/sf/if_sf.c @@ -415,8 +415,10 @@ static void sf_miibus_statchg(dev) if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX); + csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX); } else { SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX); + csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX); } return; @@ -487,6 +489,13 @@ static int sf_ifmedia_upd(ifp) sc = ifp->if_softc; mii = device_get_softc(sc->sf_miibus); + sc->sf_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); return(0); @@ -532,11 +541,21 @@ static int sf_ioctl(ifp, command, data) break; case SIOCSIFFLAGS: if (ifp->if_flags & IFF_UP) { - sf_init(sc); + if (ifp->if_flags & IFF_RUNNING && + ifp->if_flags & IFF_PROMISC && + !(sc->sf_if_flags & IFF_PROMISC)) { + SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC); + } else if (ifp->if_flags & IFF_RUNNING && + !(ifp->if_flags & IFF_PROMISC) && + sc->sf_if_flags & IFF_PROMISC) { + SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC); + } else if (!(ifp->if_flags & IFF_RUNNING)) + sf_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) sf_stop(sc); } + sc->sf_if_flags = ifp->if_flags; error = 0; break; case SIOCADDMULTI: @@ -785,7 +804,7 @@ static int sf_attach(dev) if (mii_phy_probe(dev, &sc->sf_miibus, sf_ifmedia_upd, sf_ifmedia_sts)) { printf("sf%d: MII without any phy!\n", sc->sf_unit); - free(sc->sf_ldata, M_DEVBUF); + contigfree(sc->sf_ldata,sizeof(struct sf_list_data),M_DEVBUF); bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq); bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res); @@ -842,7 +861,7 @@ static int sf_detach(dev) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq); bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res); - free(sc->sf_ldata, M_DEVBUF); + contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF); splx(s); @@ -1209,13 +1228,6 @@ static void sf_init(xsc) /* Enable autopadding of short TX frames. */ SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD); - /* Make sure the duplex mode is set correctly. */ - if ((mii->mii_media.ifm_media & IFM_GMASK) == IFM_FDX) { - SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX); - } else { - SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX); - } - /* Enable interrupts. */ csr_write_4(sc, SF_IMR, SF_INTRS); SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB); @@ -1224,7 +1236,8 @@ static void sf_init(xsc) SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB); SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB); - mii_mediachg(mii); + /*mii_mediachg(mii);*/ + sf_ifmedia_upd(ifp); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; @@ -1309,6 +1322,9 @@ static void sf_start(ifp) sc = ifp->if_softc; + if (!sc->sf_link) + return; + if (ifp->if_flags & IFF_OACTIVE) return; @@ -1370,6 +1386,8 @@ static void sf_stop(sc) csr_write_4(sc, SF_TXDQ_CTL, 0); sf_reset(sc); + sc->sf_link = 0; + for (i = 0; i < SF_RX_DLIST_CNT; i++) { if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) { m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf); @@ -1425,6 +1443,14 @@ static void sf_stats_update(xsc) stats.sf_tx_multi_colls + stats.sf_tx_excess_colls; mii_tick(mii); + if (!sc->sf_link) { + mii_pollstat(mii); + if (mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + sc->sf_link++; + if (ifp->if_snd.ifq_head != NULL) + sf_start(ifp); + } sc->sf_stat_ch = timeout(sf_stats_update, sc, hz); diff --git a/sys/dev/sf/if_sfreg.h b/sys/dev/sf/if_sfreg.h index 085d7f0..49fdd5a 100644 --- a/sys/dev/sf/if_sfreg.h +++ b/sys/dev/sf/if_sfreg.h @@ -613,6 +613,14 @@ #define SF_MACCFG1_SOFTRESET 0x00008000 /* + * There are the recommended IPG nibble counter settings + * specified in the Adaptec manual for full duplex and + * half duplex operation. + */ +#define SF_IPGT_FDX 0x15 +#define SF_IPGT_HDX 0x11 + +/* * RX filter registers 0x6000 to 0x6FFF */ #define SF_RXFILT_PERFECT_BASE 0x6000 @@ -1033,6 +1041,8 @@ struct sf_softc { u_int8_t sf_unit; /* interface number */ struct sf_list_data *sf_ldata; int sf_tx_cnt; + u_int8_t sf_link; + int sf_if_flags; struct callout_handle sf_stat_ch; }; |