diff options
Diffstat (limited to 'sys/pci')
-rw-r--r-- | sys/pci/if_wx.c | 925 |
1 files changed, 618 insertions, 307 deletions
diff --git a/sys/pci/if_wx.c b/sys/pci/if_wx.c index b455618..9677413 100644 --- a/sys/pci/if_wx.c +++ b/sys/pci/if_wx.c @@ -1,6 +1,7 @@ /* $FreeBSD$ */ /* - * Copyright (c) 1999, Traakan Software + * Principal Author: Matthew Jacob + * Copyright (c) 1999, 2001 by Traakan Software * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,10 +26,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * + * Additional Copyright (c) 2001 by Parag Patel + * under same licence for MII PHY code. */ /* - * Intel Gigabit Ethernet (82452) Driver. + * Intel Gigabit Ethernet (82452/82453) Driver. * Inspired by fxp driver by David Greenman for FreeBSD, and by * Bill Paul's work in other FreeBSD network drivers. */ @@ -71,39 +74,48 @@ * Function Prototpes, yadda yadda... */ -static int wx_intr __P((void *)); -static void wx_handle_link_intr __P((wx_softc_t *)); -static void wx_check_link __P((wx_softc_t *)); -static void wx_handle_rxint __P((wx_softc_t *)); -static void wx_gc __P((wx_softc_t *)); -static void wx_start __P((struct ifnet *)); -static int wx_ioctl __P((struct ifnet *, IOCTL_CMD_TYPE, caddr_t)); -static int wx_ifmedia_upd __P((struct ifnet *)); -static void wx_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); -static int wx_init __P((void *)); -static void wx_hw_stop __P((wx_softc_t *)); -static void wx_set_addr __P((wx_softc_t *, int, u_int8_t *)); -static int wx_hw_initialize __P((wx_softc_t *)); -static void wx_stop __P((wx_softc_t *)); -static void wx_txwatchdog __P((struct ifnet *)); -static int wx_get_rbuf __P((wx_softc_t *, rxpkt_t *)); -static void wx_rxdma_map __P((wx_softc_t *, rxpkt_t *, struct mbuf *)); - -static INLINE void wx_eeprom_raise_clk __P((wx_softc_t *, u_int32_t)); -static INLINE void wx_eeprom_lower_clk __P((wx_softc_t *, u_int32_t)); -static INLINE void wx_eeprom_sobits __P((wx_softc_t *, u_int16_t, u_int16_t)); -static INLINE u_int16_t wx_eeprom_sibits __P((wx_softc_t *)); -static INLINE void wx_eeprom_cleanup __P((wx_softc_t *)); -static INLINE u_int16_t wx_read_eeprom_word __P((wx_softc_t *, int)); -static void wx_read_eeprom __P((wx_softc_t *, u_int16_t *, int, int)); - -static int wx_attach_common __P((wx_softc_t *)); -static void wx_watchdog __P((void *)); - -static INLINE void wx_mwi_whackon __P((wx_softc_t *)); -static INLINE void wx_mwi_unwhack __P((wx_softc_t *)); -static int wx_dring_setup __P((wx_softc_t *)); -static void wx_dring_teardown __P((wx_softc_t *)); +static int wx_intr(void *); +static void wx_handle_link_intr(wx_softc_t *); +static void wx_check_link(wx_softc_t *); +static void wx_handle_rxint(wx_softc_t *); +static void wx_gc(wx_softc_t *); +static void wx_start(struct ifnet *); +static int wx_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t); +static int wx_ifmedia_upd(struct ifnet *); +static void wx_ifmedia_sts(struct ifnet *, struct ifmediareq *); +static int wx_init(void *); +static void wx_hw_stop(wx_softc_t *); +static void wx_set_addr(wx_softc_t *, int, u_int8_t *); +static int wx_hw_initialize(wx_softc_t *); +static void wx_stop(wx_softc_t *); +static void wx_txwatchdog(struct ifnet *); +static int wx_get_rbuf(wx_softc_t *, rxpkt_t *); +static void wx_rxdma_map(wx_softc_t *, rxpkt_t *, struct mbuf *); + +static INLINE void wx_eeprom_raise_clk(wx_softc_t *, u_int32_t); +static INLINE void wx_eeprom_lower_clk(wx_softc_t *, u_int32_t); +static INLINE void wx_eeprom_sobits(wx_softc_t *, u_int16_t, u_int16_t); +static INLINE u_int16_t wx_eeprom_sibits(wx_softc_t *); +static INLINE void wx_eeprom_cleanup(wx_softc_t *); +static INLINE u_int16_t wx_read_eeprom_word(wx_softc_t *, int); +static void wx_read_eeprom(wx_softc_t *, u_int16_t *, int, int); + +static int wx_attach_common(wx_softc_t *); +static void wx_watchdog(void *); + +static INLINE void wx_mwi_whackon(wx_softc_t *); +static INLINE void wx_mwi_unwhack(wx_softc_t *); +static int wx_dring_setup(wx_softc_t *); +static void wx_dring_teardown(wx_softc_t *); + +static int wx_attach_phy(wx_softc_t *); +static int wx_miibus_readreg(void *, int, int); +static int wx_miibus_writereg(void *, int, int, int); +static void wx_miibus_statchg(void *); +static void wx_miibus_mediainit(void *); + +static u_int32_t wx_mii_shift_in(wx_softc_t *); +static void wx_mii_shift_out(wx_softc_t *, u_int32_t, u_int32_t); #define WX_DISABLE_INT(sc) WRITE_CSR(sc, WXREG_IMCLR, WXDISABLE) #define WX_ENABLE_INT(sc) WRITE_CSR(sc, WXREG_IMASK, sc->wx_ienable) @@ -115,6 +127,16 @@ static void wx_dring_teardown __P((wx_softc_t *)); #define WX_MAXMTU ETHERMTU #endif +#define DPRINTF(sc, x) if (sc->wx_debug) printf x +#define IPRINTF(sc, x) if (sc->wx_verbose) printf x + +static const char ldn[] = "%s: link down\n"; +static const char lup[] = "%s: link up\n"; +static const char sqe[] = "%s: receive sequence error\n"; +static const char ane[] = "%s: /C/ ordered sets seen- enabling ANE\n"; +static const char inane[] = "%s: no /C/ ordered sets seen- disabling ANE\n"; + + #if defined(__NetBSD__) || defined(__OpenBSD__) #if defined(__BROKEN_INDIRECT_CONFIG) || defined(__OpenBSD__) #define MATCHARG void * @@ -122,11 +144,11 @@ static void wx_dring_teardown __P((wx_softc_t *)); #define MATCHARG struct cfdata * #endif -static int wx_match __P((struct device *, MATCHARG, void *)); -static void wx_attach __P((struct device *, struct device *, void *)); -static void wx_shutdown __P((void *)); -static int wx_ether_ioctl __P((struct ifnet *, IOCTL_CMD_TYPE, caddr_t)); -static int wx_mc_setup __P((wx_softc_t *)); +static int wx_match(struct device *, MATCHARG, void *); +static void wx_attach(struct device *, struct device *, void *); +static void wx_shutdown(void *); +static int wx_ether_ioctl(struct ifnet *, IOCTL_CMD_TYPE, caddr_t); +static int wx_mc_setup(wx_softc_t *); #define ether_ioctl wx_ether_ioctl /* @@ -135,28 +157,21 @@ static int wx_mc_setup __P((wx_softc_t *)); * such that they cannot be used as part of a for loop, for example. */ -static INLINE u_int32_t _read_csr __P((struct wx_softc *, u_int32_t)); -static INLINE void _write_csr __P((struct wx_softc *, u_int32_t, u_int32_t)); +static INLINE u_int32_t _read_csr (wx_softc_t *, u_int32_t); +static INLINE void _write_csr(wx_softc_t *, u_int32_t, u_int32_t); -static INLINE u_int32_t _read_csr(sc, reg) - struct wx_softc *sc; - u_int32_t reg; +static INLINE u_int32_t +_read_csr(wx_softc_ *sc, u_int32_t reg) { return bus_space_read_4(sc->w.st, sc->w.sh, reg); } -static INLINE void _write_csr(sc, reg, val) - struct wx_softc *sc; - u_int32_t reg; - u_int32_t val; +static INLINE void +_write_csr(wx_softc_t *sc, u_int32_t reg, u_int32_t val) { bus_space_write_4(sc->w.st, sc->w.sh, reg, val); } - - -static wx_softc_t *wxlist; - struct cfattach wx_ca = { sizeof (wx_softc_t), wx_match, wx_attach }; @@ -171,10 +186,7 @@ struct cfdriver wx_cd = { * Check if a device is an 82452. */ static int -wx_match(parent, match, aux) - struct device *parent; - MATCHARG match; - void *aux; +wx_match(struct device *parent, MATCHARG match, void *aux) { struct pci_attach_args *pa = aux; if (PCI_VENDOR(pa->pa_id) != WX_VENDOR_INTEL) { @@ -184,6 +196,7 @@ wx_match(parent, match, aux) case WX_PRODUCT_82452: case WX_PRODUCT_LIVENGOOD: case WX_PRODUCT_82452_SC: + case WX_PRODUCT_82543: break; default: return (0); @@ -192,11 +205,9 @@ wx_match(parent, match, aux) } static void -wx_attach(parent, self, aux) - struct device *parent, *self; - void *aux; +wx_attach(struct device *parent, struct devuce *self, void *aux) { - wx_softc_t *tmp, *sc = (wx_softc_t *)self; + wx_softc_t *sc = (wx_softc_t *)self; struct pci_attach_args *pa = aux; pci_chipset_tag_t pc = pa->pa_pc; pci_intr_handle_t ih; @@ -248,6 +259,11 @@ wx_attach(parent, self, aux) data |= (WX_CACHELINE_SIZE << PCI_CACHELINE_SHIFT); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, data); +#if defined(__NetBSD__) + if (bootverbose) + sc->wx_verbose = 1; +#endif + if (wx_attach_common(sc)) { return; } @@ -284,15 +300,18 @@ wx_attach(parent, self, aux) * reboot before the driver initializes. */ shutdownhook_establish(wx_shutdown, sc); +} - tmp = wxlist; - if (tmp) { - while (tmp->wx_next) - tmp = tmp->wx_next; - tmp->wx_next = sc; - } else { - wxlist = sc; +static int +wx_attach_phy(wx_softc_t *sc) +{ + if (mii_phy_probe(dev, &sc->wx_miibus, wx_ifmedia_upd, + wx_ifmedia_sts)) { + printf("%s: no PHY probed!\n", sc->wx_name); + return (-1); } + sc->wx_mii = device_get_softc(sc->w.miibus); + return 0; } /* @@ -301,17 +320,13 @@ wx_attach(parent, self, aux) * kernel memory doesn't get clobbered during warmboot. */ static void -wx_shutdown(sc) - void *sc; +wx_shutdown(void *sc) { wx_hw_stop((wx_softc_t *) sc); } static int -wx_ether_ioctl(ifp, cmd, data) - struct ifnet *ifp; - IOCTL_CMD_TYPE cmd; - caddr_t data; +wx_ether_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE cmd, caddr_t data) { struct ifaddr *ifa = (struct ifaddr *) data; int error = 0; @@ -368,8 +383,7 @@ wx_ether_ioctl(ifp, cmd, data) * This function must be called at splimp, but it may sleep. */ static int -wx_mc_setup(sc) - wx_softc_t *sc; +wx_mc_setup(wx_softc_t *sc) { struct ifnet *ifp = &sc->wx_if; struct ether_multistep step; @@ -411,8 +425,7 @@ wx_mc_setup(sc) } static INLINE void -wx_mwi_whackon(sc) - wx_softc_t *sc; +wx_mwi_whackon(wx_softc_t *sc) { sc->wx_cmdw = pci_conf_read(sc->w.pci_pc, sc->w.pci_tag, PCI_COMMAND_STATUS_REG); @@ -421,8 +434,7 @@ wx_mwi_whackon(sc) } static INLINE void -wx_mwi_unwhack(sc) - wx_softc_t *sc; +wx_mwi_unwhack(wx_softc_t *sc) { if (sc->wx_cmdw & MWI) { pci_conf_write(sc->w.pci_pc, sc->w.pci_tag, @@ -431,8 +443,7 @@ wx_mwi_unwhack(sc) } static int -wx_dring_setup(sc) - wx_softc_t *sc; +wx_dring_setup(wx_softc_t *sc) { size_t len; @@ -449,7 +460,7 @@ wx_dring_setup(sc) return (-1); } - if (((u_long)sc->rdescriptors) & 0xfff) { + if (((intptr_t)sc->rdescriptors) & 0xfff) { printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name); return (-1); } @@ -467,7 +478,7 @@ wx_dring_setup(sc) printf("%s: could not allocate xmt descriptors\n", sc->wx_name); return (-1); } - if (((u_long)sc->tdescriptors) & 0xfff) { + if (((intptr_t)sc->tdescriptors) & 0xfff) { printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name); return (-1); } @@ -476,8 +487,7 @@ wx_dring_setup(sc) } static void -wx_dring_teardown(sc) - wx_softc_t *sc; +wx_dring_teardown(wx_softc_t *sc) { if (sc->rdescriptors) { WXFREE(sc->rdescriptors); @@ -490,15 +500,14 @@ wx_dring_teardown(sc) } #elif defined(__FreeBSD__) -static int wx_mc_setup __P((wx_softc_t *)); +static int wx_mc_setup(wx_softc_t *); /* * Program multicast addresses. * * This function must be called at splimp, but it may sleep. */ static int -wx_mc_setup(sc) - wx_softc_t *sc; +wx_mc_setup(wx_softc_t *sc) { struct ifnet *ifp = &sc->wx_if; struct ifmultiaddr *ifma; @@ -536,7 +545,6 @@ wx_mc_setup(sc) /* * Return identification string if this is device is ours. */ -static wx_softc_t *wxlist; static int wx_probe(device_t dev) { @@ -545,12 +553,16 @@ wx_probe(device_t dev) } switch (pci_get_device(dev)) { case WX_PRODUCT_82452: - device_set_desc(dev, "Intel GigaBit Ethernet (WISEMAN)"); + device_set_desc(dev, "Intel PRO/1000 Gigabit (WISEMAN)"); break; case WX_PRODUCT_LIVENGOOD: - device_set_desc(dev, "Intel GigaBit Ethernet (LIVENGOOD)"); + device_set_desc(dev, "Intel PRO/1000 (LIVENGOOD)"); + break; case WX_PRODUCT_82452_SC: - device_set_desc(dev, "Intel GigaBit Ethernet (LIVENGOOD_SC)"); + device_set_desc(dev, "Intel PRO/1000 F Gigabit Ethernet"); + break; + case WX_PRODUCT_82543: + device_set_desc(dev, "Intel PRO/1000 T Gigabit Ethernet"); break; default: return (ENXIO); @@ -562,9 +574,9 @@ static int wx_attach(device_t dev) { int error = 0; - wx_softc_t *tmp, *sc = device_get_softc(dev); + wx_softc_t *sc = device_get_softc(dev); struct ifnet *ifp; - u_long val; + u_int32_t val; int rid; bzero(sc, sizeof (wx_softc_t)); @@ -572,7 +584,10 @@ wx_attach(device_t dev) callout_handle_init(&sc->w.sch); sc->w.dev = dev; - if (getenv_int("wx_debug", &rid)) { + if (bootverbose) + sc->wx_verbose = 1; + + if (getenv_int ("wx_debug", &rid)) { if (rid & (1 << device_get_unit(dev))) { sc->wx_debug = 1; } @@ -675,20 +690,24 @@ wx_attach(device_t dev) ifp->if_watchdog = wx_txwatchdog; ifp->if_snd.ifq_maxlen = WX_MAX_TDESC - 1; ether_ifattach(ifp, ETHER_BPF_SUPPORTED); - tmp = wxlist; - if (tmp) { - while (tmp->wx_next) - tmp = tmp->wx_next; - tmp->wx_next = sc; - } else { - wxlist = sc; - } out: WX_UNLOCK(sc); return (error); } static int +wx_attach_phy(wx_softc_t *sc) +{ + if (mii_phy_probe(sc->w.dev, &sc->w.miibus, wx_ifmedia_upd, + wx_ifmedia_sts)) { + printf("%s: no PHY probed!\n", sc->wx_name); + return (-1); + } + sc->wx_mii = device_get_softc(sc->w.miibus); + return 0; +} + +static int wx_detach(device_t dev) { wx_softc_t *sc = device_get_softc(dev); @@ -696,6 +715,10 @@ wx_detach(device_t dev) WX_LOCK(sc); ether_ifdetach(&sc->w.arpcom.ac_if, ETHER_BPF_SUPPORTED); wx_stop(sc); + + bus_generic_detach(dev); + device_delete_child(dev, sc->w.miibus); + bus_teardown_intr(dev, sc->w.irq, sc->w.ih); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->w.irq); bus_release_resource(dev, SYS_RES_MEMORY, WX_MMBA, sc->w.mem); @@ -711,16 +734,14 @@ wx_shutdown(device_t dev) } static INLINE void -wx_mwi_whackon(sc) - wx_softc_t *sc; +wx_mwi_whackon(wx_softc_t *sc) { sc->wx_cmdw = pci_read_config(sc->w.dev, PCIR_COMMAND, 2); pci_write_config(sc->w.dev, PCIR_COMMAND, sc->wx_cmdw & ~MWI, 2); } static INLINE void -wx_mwi_unwhack(sc) - wx_softc_t *sc; +wx_mwi_unwhack(wx_softc_t *sc) { if (sc->wx_cmdw & MWI) { pci_write_config(sc->w.dev, PCIR_COMMAND, sc->wx_cmdw, 2); @@ -728,8 +749,7 @@ wx_mwi_unwhack(sc) } static int -wx_dring_setup(sc) - wx_softc_t *sc; +wx_dring_setup(wx_softc_t *sc) { size_t len; @@ -740,7 +760,7 @@ wx_dring_setup(sc) printf("%s: could not allocate rcv descriptors\n", sc->wx_name); return (-1); } - if (((u_long)sc->rdescriptors) & 0xfff) { + if (((intptr_t)sc->rdescriptors) & 0xfff) { contigfree(sc->rdescriptors, len, M_DEVBUF); sc->rdescriptors = NULL; printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name); @@ -758,7 +778,7 @@ wx_dring_setup(sc) printf("%s: could not allocate xmt descriptors\n", sc->wx_name); return (-1); } - if (((u_long)sc->tdescriptors) & 0xfff) { + if (((intptr_t)sc->tdescriptors) & 0xfff) { contigfree(sc->rdescriptors, sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); sc->rdescriptors = NULL; @@ -770,8 +790,7 @@ wx_dring_setup(sc) } static void -wx_dring_teardown(sc) - wx_softc_t *sc; +wx_dring_teardown(wx_softc_t *sc) { if (sc->rdescriptors) { contigfree(sc->rdescriptors, @@ -791,6 +810,17 @@ static device_method_t wx_methods[] = { DEVMETHOD(device_attach, wx_attach), DEVMETHOD(device_detach, wx_detach), DEVMETHOD(device_shutdown, wx_shutdown), + + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + /* MII interface */ + DEVMETHOD(miibus_readreg, wx_miibus_readreg), + DEVMETHOD(miibus_writereg, wx_miibus_writereg), + DEVMETHOD(miibus_statchg, wx_miibus_statchg), + DEVMETHOD(miibus_mediainit, wx_miibus_mediainit), + { 0, 0 } }; @@ -799,7 +829,7 @@ static driver_t wx_driver = { }; static devclass_t wx_devclass; DRIVER_MODULE(if_wx, pci, wx_driver, wx_devclass, 0, 0); - +DRIVER_MODULE(miibus, wx, miibus_driver, miibus_devclass, 0, 0); #endif /* @@ -807,8 +837,7 @@ DRIVER_MODULE(if_wx, pci, wx_driver, wx_devclass, 0, 0); * and our interrupt registered. */ static int -wx_attach_common(sc) - wx_softc_t *sc; +wx_attach_common(wx_softc_t *sc) { size_t len; u_int32_t tmp; @@ -843,17 +872,52 @@ wx_attach_common(sc) * Fifth, establish some adapter parameters. */ sc->wx_txint_delay = 128; - ifmedia_init(&sc->wx_media, IFM_IMASK, wx_ifmedia_upd, wx_ifmedia_sts); - ifmedia_add(&sc->wx_media, IFM_ETHER|IFM_1000_SX, 0, NULL); - ifmedia_add(&sc->wx_media, IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); - ifmedia_set(&sc->wx_media, IFM_ETHER|IFM_1000_SX|IFM_FDX); - sc->wx_media.ifm_media = sc->wx_media.ifm_cur->ifm_media; - ll += 1; + sc->wx_dcr = 0; + + if (IS_LIVENGOOD_CU(sc)) { + + /* settings to talk to PHY */ + sc->wx_dcr |= WXDCR_FRCSPD | WXDCR_FRCDPX | WXDCR_SLU; + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + + /* + * Raise the PHY's reset line to make it operational. + */ + tmp = READ_CSR(sc, WXREG_EXCT); + tmp |= WXPHY_RESET_DIR4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + + tmp = READ_CSR(sc, WXREG_EXCT); + tmp &= ~WXPHY_RESET4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + + tmp = READ_CSR(sc, WXREG_EXCT); + tmp |= WXPHY_RESET4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + + if (wx_attach_phy(sc)) { + goto fail; + } + } else { + ifmedia_init(&sc->wx_media, IFM_IMASK, + wx_ifmedia_upd, wx_ifmedia_sts); + + ifmedia_add(&sc->wx_media, + IFM_ETHER|IFM_1000_SX, 0, NULL); + ifmedia_add(&sc->wx_media, + IFM_ETHER|IFM_1000_SX|IFM_FDX, 0, NULL); + ifmedia_set(&sc->wx_media, IFM_ETHER|IFM_1000_SX|IFM_FDX); + + sc->wx_media.ifm_media = sc->wx_media.ifm_cur->ifm_media; + } /* * Sixth, establish a default device control register word. */ - sc->wx_dcr = 0; + ll += 1; if (sc->wx_cfg1 & WX_EEPROM_CTLR1_FD) sc->wx_dcr |= WXDCR_FD; if (sc->wx_cfg1 & WX_EEPROM_CTLR1_ILOS) @@ -869,7 +933,6 @@ wx_attach_common(sc) if (sc->wx_no_flow == 0) sc->wx_dcr |= WXDCR_RFCE | WXDCR_TFCE; - /* * Seventh, allocate various sw structures... */ @@ -916,28 +979,21 @@ fail: */ static INLINE void -wx_eeprom_raise_clk(sc, regval) - wx_softc_t *sc; - u_int32_t regval; +wx_eeprom_raise_clk(wx_softc_t *sc, u_int32_t regval) { WRITE_CSR(sc, WXREG_EECDR, regval | WXEECD_SK); DELAY(50); } static INLINE void -wx_eeprom_lower_clk(sc, regval) - wx_softc_t *sc; - u_int32_t regval; +wx_eeprom_lower_clk(wx_softc_t *sc, u_int32_t regval) { WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_SK); DELAY(50); } static INLINE void -wx_eeprom_sobits(sc, data, count) - wx_softc_t *sc; - u_int16_t data; - u_int16_t count; +wx_eeprom_sobits(wx_softc_t *sc, u_int16_t data, u_int16_t count) { u_int32_t regval, mask; @@ -957,10 +1013,8 @@ wx_eeprom_sobits(sc, data, count) WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_DI); } - static INLINE u_int16_t -wx_eeprom_sibits(sc) - wx_softc_t *sc; +wx_eeprom_sibits(wx_softc_t *sc) { unsigned int regval, i; u_int16_t data; @@ -979,11 +1033,8 @@ wx_eeprom_sibits(sc) return (data); } - - static INLINE void -wx_eeprom_cleanup(sc) - wx_softc_t *sc; +wx_eeprom_cleanup(wx_softc_t *sc) { u_int32_t regval; regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_CS); @@ -993,9 +1044,7 @@ wx_eeprom_cleanup(sc) } static u_int16_t INLINE -wx_read_eeprom_word(sc, offset) - wx_softc_t *sc; - int offset; +wx_read_eeprom_word(wx_softc_t *sc, int offset) { u_int16_t data; WRITE_CSR(sc, WXREG_EECDR, WXEECD_CS); @@ -1007,11 +1056,7 @@ wx_read_eeprom_word(sc, offset) } static void -wx_read_eeprom(sc, data, offset, words) - wx_softc_t *sc; - u_int16_t *data; - int offset; - int words; +wx_read_eeprom(wx_softc_t *sc, u_int16_t *data, int offset, int words) { int i; for (i = 0; i < words; i++) { @@ -1025,13 +1070,13 @@ wx_read_eeprom(sc, data, offset, words) */ static void -wx_start(ifp) - struct ifnet *ifp; +wx_start(struct ifnet *ifp) { wx_softc_t *sc = SOFTC_IFP(ifp); u_int16_t cidx, nactv; WX_LOCK(sc); + DPRINTF(sc, ("%s: wx_start\n", sc->wx_name)); nactv = sc->tactive; while (nactv < WX_MAX_TDESC) { int ndesc; @@ -1062,7 +1107,7 @@ wx_start(ifp) m_freem(mb_head); mb_head = m; } -again: + again: cidx = sc->tnxtfree; nactv = sc->tactive; @@ -1153,7 +1198,11 @@ again: sc->tnxtfree = cidx; sc->tactive = nactv; ifp->if_timer = 10; - WRITE_CSR(sc, WXREG_TDT, cidx); + if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_TDT, cidx); + } else { + WRITE_CSR(sc, WXREG_TDT_LIVENGOOD, cidx); + } if (ifp->if_bpf) bpf_mtap(WX_BPFTAP_ARG(ifp), mb_head); continue; @@ -1209,6 +1258,12 @@ again: sc->wx_xmitblocked++; ifp->if_flags |= IFF_OACTIVE; } + + /* used SW LED to indicate transmission active */ + if (sc->tactive > 0 && sc->wx_mii) { + WRITE_CSR(sc, WXREG_DCR, + READ_CSR(sc, WXREG_DCR) | (WXDCR_SWDPIO0|WXDCR_SWDPIN0)); + } WX_UNLOCK(sc); } @@ -1216,8 +1271,7 @@ again: * Process interface interrupts. */ static int -wx_intr(arg) - void *arg; +wx_intr(void *arg) { wx_softc_t *sc = arg; int claimed = 0; @@ -1231,7 +1285,7 @@ wx_intr(arg) claimed++; WX_DISABLE_INT(sc); sc->wx_intr++; - if (sc->wx_icr & (WXISR_LSC|WXISR_RXSEQ)) { + if (sc->wx_icr & (WXISR_LSC|WXISR_RXSEQ|WXISR_GPI_EN1)) { wx_handle_link_intr(sc); } wx_handle_rxint(sc); @@ -1248,14 +1302,33 @@ wx_intr(arg) } static void -wx_handle_link_intr(sc) - wx_softc_t *sc; +wx_handle_link_intr(wx_softc_t *sc) { u_int32_t txcw, rxcw, dcr, dsr; sc->wx_linkintr++; dcr = READ_CSR(sc, WXREG_DCR); + DPRINTF(sc, ("%s: handle_link_intr: icr=%#x dcr=%#x\n", + sc->wx_name, sc->wx_icr, dcr)); + if (sc->wx_mii) { + mii_pollstat(sc->wx_mii); + if (sc->wx_mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(sc->wx_mii->mii_media_active) == + IFM_NONE) { + IPRINTF(sc, (ldn, sc->wx_name)); + sc->linkup = 0; + } else { + IPRINTF(sc, (lup, sc->wx_name)); + sc->linkup = 1; + } + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); + } else if (sc->wx_icr & WXISR_RXSEQ) { + DPRINTF(sc, (sqe, sc->wx_name)); + } + return; + } + txcw = READ_CSR(sc, WXREG_XMIT_CFGW); rxcw = READ_CSR(sc, WXREG_RECV_CFGW); dsr = READ_CSR(sc, WXREG_DSR); @@ -1267,10 +1340,7 @@ wx_handle_link_intr(sc) if (((dcr & WXDCR_SWDPIN1) || (rxcw & WXRXCW_C)) && ((txcw & WXTXCW_ANE) == 0)) { - if (sc->wx_debug) { - printf("%s: /C/ ordered sets seen- enabling ANE\n", - sc->wx_name); - } + DPRINTF(sc, (ane, sc->wx_name)); WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); sc->wx_dcr &= ~WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); @@ -1279,28 +1349,30 @@ wx_handle_link_intr(sc) if (sc->wx_icr & WXISR_LSC) { if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { - if (sc->wx_debug) - printf("%s: gigabit link up\n", sc->wx_name); + IPRINTF(sc, (lup, sc->wx_name)); sc->linkup = 1; sc->wx_dcr |= (WXDCR_SWDPIO0|WXDCR_SWDPIN0); } else { - if (sc->wx_debug) - printf("%s: gigabit link down\n", sc->wx_name); + IPRINTF(sc, (ldn, sc->wx_name)); sc->linkup = 0; sc->wx_dcr &= ~(WXDCR_SWDPIO0|WXDCR_SWDPIN0); } WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); } else { - printf("%s: receive sequence error\n", sc->wx_name); + DPRINTF(sc, (sqe, sc->wx_name)); } } static void -wx_check_link(sc) - wx_softc_t *sc; +wx_check_link(wx_softc_t *sc) { u_int32_t rxcw, dcr, dsr; + if (sc->wx_mii) { + mii_pollstat(sc->wx_mii); + return; + } + rxcw = READ_CSR(sc, WXREG_RECV_CFGW); dcr = READ_CSR(sc, WXREG_DCR); dsr = READ_CSR(sc, WXREG_DSR); @@ -1311,20 +1383,14 @@ wx_check_link(sc) sc->ane_failed = 1; return; } - if (sc->wx_debug) { - printf("%s: no /C/ ordered sets seen- disabling ANE\n", - sc->wx_name); - } + DPRINTF(sc, (inane, sc->wx_name)); WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT & ~WXTXCW_ANE); if (sc->wx_idnrev < WX_WISEMAN_2_1) sc->wx_dcr &= ~WXDCR_TFCE; sc->wx_dcr |= WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); } else if ((rxcw & WXRXCW_C) != 0 && (dcr & WXDCR_SLU) != 0) { - if (sc->wx_debug) { - printf("%s: /C/ ordered sets seen- enabling ANE\n", - sc->wx_name); - } + DPRINTF(sc, (ane, sc->wx_name)); WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); sc->wx_dcr &= ~WXDCR_SLU; WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); @@ -1332,14 +1398,15 @@ wx_check_link(sc) } static void -wx_handle_rxint(sc) - wx_softc_t *sc; +wx_handle_rxint(wx_softc_t *sc) { struct ether_header *eh; struct mbuf *m0, *mb, *pending[WX_MAX_RDESC]; struct ifnet *ifp = &sc->wx_if; int npkts, ndesc, lidx, idx, tlen; + DPRINTF(sc, ("%s: wx_handle_rxint\n", sc->wx_name)); + for (m0 = sc->rpending, tlen = ndesc = npkts = 0, idx = sc->rnxt, lidx = R_PREV_IDX(idx); ndesc < WX_MAX_RDESC; ndesc++, lidx = idx, idx = R_NXT_IDX(idx)) { @@ -1358,10 +1425,8 @@ wx_handle_rxint(sc) } m0 = NULL; } - if (sc->wx_debug) { - printf("WXRX: ndesc %d idx %d lidx %d\n", - ndesc, idx, lidx); - } + DPRINTF(sc, ("%s: WXRX: ndesc %d idx %d lidx %d\n", + sc->wx_name, ndesc, idx, lidx)); break; } @@ -1457,10 +1522,8 @@ wx_handle_rxint(sc) tlen += length; } - if (sc->wx_debug) { - printf("%s: RDESC[%d] len %d off %d lastframe %d\n", - sc->wx_name, idx, mb->m_len, offset, lastframe); - } + DPRINTF(sc, ("%s: RDESC[%d] len %d off %d lastframe %d\n", + sc->wx_name, idx, mb->m_len, offset, lastframe)); if (m0 != mb) m_cat(m0, mb); if (lastframe == 0) { @@ -1482,7 +1545,11 @@ wx_handle_rxint(sc) } if (ndesc) { - WRITE_CSR(sc, WXREG_RDT0, lidx); + if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_RDT0, lidx); + } else { + WRITE_CSR(sc, WXREG_RDT0_LIVENGOOD, lidx); + } sc->rnxt = idx; } @@ -1492,14 +1559,14 @@ wx_handle_rxint(sc) for (idx = 0; idx < npkts; idx++) { mb = pending[idx]; +#if NBPFILTER > 0 if (ifp->if_bpf) { bpf_mtap(WX_BPFTAP_ARG(ifp), mb); } - ifp->if_ipackets++; - if (sc->wx_debug) { - printf("%s: RECV packet length %d\n", - sc->wx_name, mb->m_pkthdr.len); - } +#endif + ifp->if_ipackets++; + DPRINTF(sc, ("%s: RECV packet length %d\n", + sc->wx_name, mb->m_pkthdr.len)); #if defined(__FreeBSD__) || defined(__OpenBSD__) eh = mtod(mb, struct ether_header *); m_adj(mb, sizeof (struct ether_header)); @@ -1511,8 +1578,7 @@ wx_handle_rxint(sc) } static void -wx_gc(sc) - wx_softc_t *sc; +wx_gc(wx_softc_t *sc) { struct ifnet *ifp = &sc->wx_if; txpkt_t *txpkt; @@ -1520,7 +1586,11 @@ wx_gc(sc) WX_LOCK(sc); txpkt = sc->tbsyf; - tdh = READ_CSR(sc, WXREG_TDH); + if (IS_WISEMAN(sc)) { + tdh = READ_CSR(sc, WXREG_TDH); + } else { + tdh = READ_CSR(sc, WXREG_TDH_LIVENGOOD); + } while (txpkt != NULL) { u_int32_t end = txpkt->eidx, cidx = tdh; @@ -1548,10 +1618,8 @@ wx_gc(sc) */ if (txpkt->sidx <= cidx && cidx < txpkt->eidx) { - if (sc->wx_debug) { - printf("%s: TXGC %d..%d TDH %d\n", sc->wx_name, - txpkt->sidx, txpkt->eidx, tdh); - } + DPRINTF(sc, ("%s: TXGC %d..%d TDH %d\n", sc->wx_name, + txpkt->sidx, txpkt->eidx, tdh)); break; } ifp->if_opackets++; @@ -1569,24 +1637,20 @@ wx_gc(sc) td = &sc->tdescriptors[cidx]; if (td->status & TXSTS_EC) { - if (sc->wx_debug) - printf("%s: excess collisions\n", - sc->wx_name); + IPRINTF(sc, ("%s: excess collisions\n", + sc->wx_name)); ifp->if_collisions++; ifp->if_oerrors++; } if (td->status & TXSTS_LC) { - if (sc->wx_debug) - printf("%s: lost carrier\n", - sc->wx_name); + IPRINTF(sc, + ("%s: lost carrier\n", sc->wx_name)); ifp->if_oerrors++; } tmp = &sc->tbase[cidx]; - if (sc->wx_debug) { - printf("%s: TXGC[%d] %p %d..%d done nact %d " - "TDH %d\n", sc->wx_name, cidx, tmp->dptr, - txpkt->sidx, txpkt->eidx, sc->tactive, tdh); - } + DPRINTF(sc, ("%s: TXGC[%d] %p %d..%d done nact %d " + "TDH %d\n", sc->wx_name, cidx, tmp->dptr, + txpkt->sidx, txpkt->eidx, sc->tactive, tdh)); tmp->dptr = NULL; if (sc->tactive == 0) { printf("%s: nactive < 0?\n", sc->wx_name); @@ -1602,6 +1666,12 @@ wx_gc(sc) ifp->if_timer = 0; ifp->if_flags &= ~IFF_OACTIVE; } + + /* used SW LED to indicate transmission not active */ + if (sc->tactive == 0 && sc->wx_mii) { + WRITE_CSR(sc, WXREG_DCR, + READ_CSR(sc, WXREG_DCR) & ~(WXDCR_SWDPIO0|WXDCR_SWDPIN0)); + } WX_UNLOCK(sc); } @@ -1611,8 +1681,7 @@ wx_gc(sc) * and to handle link status changes. */ static void -wx_watchdog(arg) - void *arg; +wx_watchdog(void *arg) { wx_softc_t *sc = arg; @@ -1631,10 +1700,10 @@ wx_watchdog(arg) * Stop and reinitialize the hardware */ static void -wx_hw_stop(sc) - wx_softc_t *sc; +wx_hw_stop(wx_softc_t *sc) { u_int32_t icr; + DPRINTF(sc, ("%s: wx_hw_stop\n", sc->wx_name)); if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); } @@ -1649,12 +1718,10 @@ wx_hw_stop(sc) } static void -wx_set_addr(sc, idx, mac) - wx_softc_t *sc; - int idx; - u_int8_t *mac; +wx_set_addr(wx_softc_t *sc, int idx, u_int8_t *mac) { u_int32_t t0, t1; + DPRINTF(sc, ("%s: wx_set_addr\n", sc->wx_name)); t0 = (mac[0]) | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24); t1 = (mac[4] << 0) | (mac[5] << 8); t1 |= WX_RAL_AV; @@ -1663,17 +1730,11 @@ wx_set_addr(sc, idx, mac) } static int -wx_hw_initialize(sc) - wx_softc_t *sc; +wx_hw_initialize(wx_softc_t *sc) { int i; - if (IS_LIVENGOOD(sc)) { - if ((READ_CSR(sc, WXREG_DSR) & WXDSR_TBIMODE) == 0) { - printf("%s: no fibre mode detected\n", sc->wx_name); - return (-1); - } - } + DPRINTF(sc, ("%s: wx_hw_initialize\n", sc->wx_name)); WRITE_CSR(sc, WXREG_VET, 0); for (i = 0; i < (WX_VLAN_TAB_SIZE << 2); i += 4) { @@ -1717,15 +1778,33 @@ wx_hw_initialize(sc) WRITE_CSR(sc, WXREG_MTA + (sizeof (u_int32_t) * 4), 0); } - /* - * Handle link control - */ - WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr | WXDCR_LRST); - DELAY(50 * 1000); + if (IS_LIVENGOOD_CU(sc)) { + /* + * has a PHY - raise its reset line to make it operational + */ + u_int32_t tmp = READ_CSR(sc, WXREG_EXCT); + tmp |= WXPHY_RESET_DIR4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + + tmp = READ_CSR(sc, WXREG_EXCT); + tmp &= ~WXPHY_RESET4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + + tmp = READ_CSR(sc, WXREG_EXCT); + tmp |= WXPHY_RESET4; + WRITE_CSR(sc, WXREG_EXCT, tmp); + DELAY(20*1000); + } else if (IS_LIVENGOOD(sc)) { + u_int16_t tew; + /* + * Handle link control + */ + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr | WXDCR_LRST); + DELAY(50 * 1000); - if (IS_LIVENGOOD(sc)) { - u_int16_t tew; wx_read_eeprom(sc, &tew, WX_EEPROM_CTLR2_OFF, 1); tew = (tew & WX_EEPROM_CTLR2_SWDPIO) << WX_EEPROM_EXT_SHIFT; WRITE_CSR(sc, WXREG_EXCT, (u_int32_t)tew); @@ -1742,39 +1821,50 @@ wx_hw_initialize(sc) } WRITE_CSR(sc, WXREG_FLOW_XTIMER, WX_XTIMER_DFLT); - if (sc->wx_idnrev < WX_WISEMAN_2_1) { - WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0); - WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0); - sc->wx_dcr &= ~(WXDCR_RFCE|WXDCR_TFCE); + if (IS_WISEMAN(sc)) { + if (sc->wx_idnrev < WX_WISEMAN_2_1) { + WRITE_CSR(sc, WXREG_FLOW_RCV_HI, 0); + WRITE_CSR(sc, WXREG_FLOW_RCV_LO, 0); + sc->wx_dcr &= ~(WXDCR_RFCE|WXDCR_TFCE); + } else { + WRITE_CSR(sc, WXREG_FLOW_RCV_HI, WX_RCV_FLOW_HI_DFLT); + WRITE_CSR(sc, WXREG_FLOW_RCV_LO, WX_RCV_FLOW_LO_DFLT); + } } else { - WRITE_CSR(sc, WXREG_FLOW_RCV_HI, WX_RCV_FLOW_HI_DFLT); - WRITE_CSR(sc, WXREG_FLOW_RCV_LO, WX_RCV_FLOW_LO_DFLT); + WRITE_CSR(sc, WXREG_FLOW_RCV_HI_LIVENGOOD, WX_RCV_FLOW_HI_DFLT); + WRITE_CSR(sc, WXREG_FLOW_RCV_LO_LIVENGOOD, WX_RCV_FLOW_LO_DFLT); } - WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); + + if (!IS_LIVENGOOD_CU(sc)) + WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); + WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); DELAY(50 * 1000); - /* - * The pin stuff is all FM from the Linux driver. - */ - if ((READ_CSR(sc, WXREG_DCR) & WXDCR_SWDPIN1) == 0) { - for (i = 0; i < (WX_LINK_UP_TIMEOUT/10); i++) { - DELAY(10 * 1000); - if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { - sc->linkup = 1; - break; + if (!IS_LIVENGOOD_CU(sc)) { + /* + * The pin stuff is all FM from the Linux driver. + */ + if ((READ_CSR(sc, WXREG_DCR) & WXDCR_SWDPIN1) == 0) { + for (i = 0; i < (WX_LINK_UP_TIMEOUT/10); i++) { + DELAY(10 * 1000); + if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { + sc->linkup = 1; + break; + } } + if (sc->linkup == 0) { + sc->ane_failed = 1; + wx_check_link(sc); + } + sc->ane_failed = 0; + } else { + printf("%s: SWDPIO1 did not clear- check for reversed " + "or disconnected cable\n", sc->wx_name); + /* but return okay anyway */ } - if (sc->linkup == 0) { - sc->ane_failed = 1; - wx_check_link(sc); - } - sc->ane_failed = 0; - } else { - printf("%s: swdpio1 did not clear- check for reversed or " - "disconnected cable\n", sc->wx_name); - /* but return okay anyway */ } + sc->wx_ienable = WXIENABLE_DEFAULT; return (0); } @@ -1783,13 +1873,13 @@ wx_hw_initialize(sc) * Stop the interface. Cancels the statistics updater and resets the interface. */ static void -wx_stop(sc) - wx_softc_t *sc; +wx_stop(wx_softc_t *sc) { txpkt_t *txp; rxpkt_t *rxp; struct ifnet *ifp = &sc->wx_if; + DPRINTF(sc, ("%s: wx_stop\n", sc->wx_name)); /* * Cancel stats updater. */ @@ -1837,8 +1927,7 @@ wx_stop(sc) * Transmit Watchdog */ static void -wx_txwatchdog(ifp) - struct ifnet *ifp; +wx_txwatchdog(struct ifnet *ifp) { wx_softc_t *sc = SOFTC_IFP(ifp); printf("%s: device timeout\n", sc->wx_name); @@ -1850,8 +1939,7 @@ wx_txwatchdog(ifp) } static int -wx_init(xsc) - void *xsc; +wx_init(void *xsc) { struct ifmedia *ifm; wx_softc_t *sc = xsc; @@ -1861,6 +1949,7 @@ wx_init(xsc) size_t len; int i, bflags; + DPRINTF(sc, ("%s: wx_init\n", sc->wx_name)); WX_LOCK(sc); /* @@ -1875,6 +1964,7 @@ wx_init(xsc) */ if (wx_hw_initialize(sc)) { + DPRINTF(sc, ("%s: wx_hw_initialize failed\n", sc->wx_name)); WX_UNLOCK(sc); return (EIO); } @@ -1906,20 +1996,30 @@ wx_init(xsc) sc->tbsyf = sc->tbsyl = NULL; WRITE_CSR(sc, WXREG_TCTL, 0); DELAY(5 * 1000); - WRITE_CSR(sc, WXREG_TDBA_LO, - vtophys((vm_offset_t)&sc->tdescriptors[0])); - WRITE_CSR(sc, WXREG_TDBA_HI, 0); - WRITE_CSR(sc, WXREG_TDLEN, WX_MAX_TDESC * sizeof (wxtd_t)); - WRITE_CSR(sc, WXREG_TDH, 0); - WRITE_CSR(sc, WXREG_TDT, 0); - WRITE_CSR(sc, WXREG_TQSA_HI, 0); - WRITE_CSR(sc, WXREG_TQSA_LO, 0); if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_TDBA_LO, + vtophys((vm_offset_t)&sc->tdescriptors[0])); + WRITE_CSR(sc, WXREG_TDBA_HI, 0); + WRITE_CSR(sc, WXREG_TDLEN, WX_MAX_TDESC * sizeof (wxtd_t)); + WRITE_CSR(sc, WXREG_TDH, 0); + WRITE_CSR(sc, WXREG_TDT, 0); + WRITE_CSR(sc, WXREG_TQSA_HI, 0); + WRITE_CSR(sc, WXREG_TQSA_LO, 0); WRITE_CSR(sc, WXREG_TIPG, WX_WISEMAN_TIPG_DFLT); + WRITE_CSR(sc, WXREG_TIDV, sc->wx_txint_delay); } else { + WRITE_CSR(sc, WXREG_TDBA_LO_LIVENGOOD, + vtophys((vm_offset_t)&sc->tdescriptors[0])); + WRITE_CSR(sc, WXREG_TDBA_HI_LIVENGOOD, 0); + WRITE_CSR(sc, WXREG_TDLEN_LIVENGOOD, + WX_MAX_TDESC * sizeof (wxtd_t)); + WRITE_CSR(sc, WXREG_TDH_LIVENGOOD, 0); + WRITE_CSR(sc, WXREG_TDT_LIVENGOOD, 0); + WRITE_CSR(sc, WXREG_TQSA_HI, 0); + WRITE_CSR(sc, WXREG_TQSA_LO, 0); WRITE_CSR(sc, WXREG_TIPG, WX_LIVENGOOD_TIPG_DFLT); + WRITE_CSR(sc, WXREG_TIDV_LIVENGOOD, sc->wx_txint_delay); } - WRITE_CSR(sc, WXREG_TIDV, sc->wx_txint_delay); WRITE_CSR(sc, WXREG_TCTL, (WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN)); /* @@ -1929,13 +2029,24 @@ wx_init(xsc) sc->rnxt = 0; WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(5 * 1000); - WRITE_CSR(sc, WXREG_RDTR0, WXRDTR_FPD); - WRITE_CSR(sc, WXREG_RDBA0_LO, - vtophys((vm_offset_t)&sc->rdescriptors[0])); - WRITE_CSR(sc, WXREG_RDBA0_HI, 0); - WRITE_CSR(sc, WXREG_RDLEN0, WX_MAX_RDESC * sizeof (wxrd_t)); - WRITE_CSR(sc, WXREG_RDH0, 0); - WRITE_CSR(sc, WXREG_RDT0, (WX_MAX_RDESC - RXINCR)); + if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_RDTR0, WXRDTR_FPD); + WRITE_CSR(sc, WXREG_RDBA0_LO, + vtophys((vm_offset_t)&sc->rdescriptors[0])); + WRITE_CSR(sc, WXREG_RDBA0_HI, 0); + WRITE_CSR(sc, WXREG_RDLEN0, WX_MAX_RDESC * sizeof (wxrd_t)); + WRITE_CSR(sc, WXREG_RDH0, 0); + WRITE_CSR(sc, WXREG_RDT0, (WX_MAX_RDESC - RXINCR)); + } else { + WRITE_CSR(sc, WXREG_RDTR0_LIVENGOOD, WXRDTR_FPD); + WRITE_CSR(sc, WXREG_RDBA0_LO_LIVENGOOD, + vtophys((vm_offset_t)&sc->rdescriptors[0])); + WRITE_CSR(sc, WXREG_RDBA0_HI_LIVENGOOD, 0); + WRITE_CSR(sc, WXREG_RDLEN0_LIVENGOOD, + WX_MAX_RDESC * sizeof (wxrd_t)); + WRITE_CSR(sc, WXREG_RDH0_LIVENGOOD, 0); + WRITE_CSR(sc, WXREG_RDT0_LIVENGOOD, (WX_MAX_RDESC - RXINCR)); + } WRITE_CSR(sc, WXREG_RDTR1, 0); WRITE_CSR(sc, WXREG_RDBA1_LO, 0); WRITE_CSR(sc, WXREG_RDBA1_HI, 0); @@ -1965,11 +2076,16 @@ wx_init(xsc) ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - ifm = &sc->wx_media; - i = ifm->ifm_media; - ifm->ifm_media = ifm->ifm_cur->ifm_media; - wx_ifmedia_upd(ifp); - ifm->ifm_media = i; + if (sc->wx_mii) { + mii_mediachg(sc->wx_mii); + } else { + ifm = &sc->wx_media; + i = ifm->ifm_media; + ifm->ifm_media = ifm->ifm_cur->ifm_media; + wx_ifmedia_upd(ifp); + ifm->ifm_media = i; + } + WX_UNLOCK(sc); /* @@ -1995,19 +2111,14 @@ wx_init(xsc) * alignment and we'll catch the alignment on the backend at interrupt time. */ static void -wx_rxdma_map(sc, rxpkt, mb) - wx_softc_t *sc; - rxpkt_t *rxpkt; - struct mbuf *mb; +wx_rxdma_map(wx_softc_t *sc, rxpkt_t *rxpkt, struct mbuf *mb) { rxpkt->dptr = mb; rxpkt->dma_addr = vtophys(mtod(mb, vm_offset_t)); } static int -wx_get_rbuf(sc, rxpkt) - wx_softc_t *sc; - rxpkt_t *rxpkt; +wx_get_rbuf(wx_softc_t *sc, rxpkt_t *rxpkt) { struct mbuf *mb; MGETHDR(mb, M_DONTWAIT, MT_DATA); @@ -2026,10 +2137,7 @@ wx_get_rbuf(sc, rxpkt) } static int -wx_ioctl(ifp, command, data) - struct ifnet *ifp; - IOCTL_CMD_TYPE command; - caddr_t data; +wx_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE command, caddr_t data) { wx_softc_t *sc = SOFTC_IFP(ifp); struct ifreq *ifr = (struct ifreq *) data; @@ -2095,7 +2203,15 @@ wx_ioctl(ifp, command, data) #ifdef SIOCGIFMEDIA case SIOCGIFMEDIA: case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->wx_media, command); + DPRINTF(sc, ("%s: ioctl SIOC[GS]IFMEDIA: command=%#lx\n", + sc->wx_name, command)); + if (sc->wx_mii) { + error = ifmedia_ioctl(ifp, ifr, + &sc->wx_mii->mii_media, command); + } else { + error = ifmedia_ioctl(ifp, ifr, &sc->wx_media, command); + } + break; #endif default: @@ -2107,25 +2223,45 @@ wx_ioctl(ifp, command, data) } static int -wx_ifmedia_upd(ifp) - struct ifnet *ifp; +wx_ifmedia_upd(struct ifnet *ifp) { struct wx_softc *sc = SOFTC_IFP(ifp); - struct ifmedia *ifm = &sc->wx_media; + struct ifmedia *ifm; + + DPRINTF(sc, ("%s: ifmedia_upd\n", sc->wx_name)); + + if (sc->wx_mii) { + mii_mediachg(sc->wx_mii); + return 0; + } - if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) + ifm = &sc->wx_media; + + if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { return (EINVAL); + } + return (0); } static void -wx_ifmedia_sts(ifp, ifmr) - struct ifnet *ifp; - struct ifmediareq *ifmr; +wx_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { u_int32_t dsr; struct wx_softc *sc = SOFTC_IFP(ifp); + DPRINTF(sc, ("%s: ifmedia_sts: ", sc->wx_name)); + + if (sc->wx_mii) { + mii_pollstat(sc->wx_mii); + ifmr->ifm_active = sc->wx_mii->mii_media_active; + ifmr->ifm_status = sc->wx_mii->mii_media_status; + DPRINTF(sc, ("active=%#x status=%#x\n", + ifmr->ifm_active, ifmr->ifm_status)); + return; + } + + DPRINTF(sc, ("\n")); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; @@ -2136,7 +2272,12 @@ wx_ifmedia_sts(ifp, ifmr) dsr = READ_CSR(sc, WXREG_DSR); if (IS_LIVENGOOD(sc)) { if (dsr & WXDSR_1000BT) { - ifmr->ifm_status |= IFM_1000_SX; + if (IS_LIVENGOOD_CU(sc)) { + ifmr->ifm_status |= IFM_1000_TX; + } + else { + ifmr->ifm_status |= IFM_1000_SX; + } } else if (dsr & WXDSR_100BT) { ifmr->ifm_status |= IFM_100_FX; /* ?? */ } else { @@ -2149,3 +2290,173 @@ wx_ifmedia_sts(ifp, ifmr) ifmr->ifm_active |= IFM_FDX; } } + + +#define RAISE_CLOCK(sc, dcr) \ + WRITE_CSR(sc, WXREG_DCR, (dcr) | WXPHY_MDC), DELAY(2) + +#define LOWER_CLOCK(sc, dcr) \ + WRITE_CSR(sc, WXREG_DCR, (dcr) & ~WXPHY_MDC), DELAY(2) + +static u_int32_t +wx_mii_shift_in(wx_softc_t *sc) +{ + u_int32_t dcr, i; + u_int32_t data = 0; + + dcr = READ_CSR(sc, WXREG_DCR); + dcr &= ~(WXPHY_MDIO_DIR | WXPHY_MDIO); + WRITE_CSR(sc, WXREG_DCR, dcr); + RAISE_CLOCK(sc, dcr); + LOWER_CLOCK(sc, dcr); + + for (i = 0; i < 16; i++) { + data <<= 1; + RAISE_CLOCK(sc, dcr); + dcr = READ_CSR(sc, WXREG_DCR); + + if (dcr & WXPHY_MDIO) + data |= 1; + + LOWER_CLOCK(sc, dcr); + } + + RAISE_CLOCK(sc, dcr); + LOWER_CLOCK(sc, dcr); + return (data); +} + +static void +wx_mii_shift_out(wx_softc_t *sc, u_int32_t data, u_int32_t count) +{ + u_int32_t dcr, mask; + + dcr = READ_CSR(sc, WXREG_DCR); + dcr |= WXPHY_MDIO_DIR | WXPHY_MDC_DIR; + + for (mask = (1 << (count - 1)); mask; mask >>= 1) { + if (data & mask) + dcr |= WXPHY_MDIO; + else + dcr &= ~WXPHY_MDIO; + + WRITE_CSR(sc, WXREG_DCR, dcr); + DELAY(2); + RAISE_CLOCK(sc, dcr); + LOWER_CLOCK(sc, dcr); + } +} + +static int +wx_miibus_readreg(void *arg, int phy, int reg) +{ + wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); + unsigned int data = 0; + + if (!IS_LIVENGOOD_CU(sc)) { + return 0; + } + wx_mii_shift_out(sc, WXPHYC_PREAMBLE, WXPHYC_PREAMBLE_LEN); + wx_mii_shift_out(sc, reg | (phy << 5) | (WXPHYC_READ << 10) | + (WXPHYC_SOF << 12), 14); + data = wx_mii_shift_in(sc); + return (data & WXMDIC_DATA_MASK); +} + +static int +wx_miibus_writereg(void *arg, int phy, int reg, int data) +{ + wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); + if (!IS_LIVENGOOD_CU(sc)) { + return 0; + } + wx_mii_shift_out(sc, WXPHYC_PREAMBLE, WXPHYC_PREAMBLE_LEN); + wx_mii_shift_out(sc, (u_int32_t)data | (WXPHYC_TURNAROUND << 16) | + (reg << 18) | (phy << 23) | (WXPHYC_WRITE << 28) | + (WXPHYC_SOF << 30), 32); + return (0); +} + +static void +wx_miibus_statchg(void *arg) +{ + wx_softc_t *sc = WX_SOFTC_FROM_MII_ARG(arg); + mii_data_t *mii = sc->wx_mii; + u_int32_t dcr, tctl; + + if (mii == NULL) + return; + + dcr = sc->wx_dcr; + tctl = READ_CSR(sc, WXREG_TCTL); + DPRINTF(sc, ("%s: statchg dcr=%#x tctl=%#x", sc->wx_name, dcr, tctl)); + + dcr |= WXDCR_FRCSPD | WXDCR_FRCDPX | WXDCR_SLU; + dcr &= ~(WXDCR_SPEED_MASK | WXDCR_ASDE /* | WXDCR_ILOS */); + + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE) { + DPRINTF(sc, (" link-down\n")); + sc->linkup = 0; + return; + } + + sc->linkup = 1; + } + + if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_TX) { + DPRINTF(sc, (" 1000TX")); + dcr |= WXDCR_1000BT; + } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { + DPRINTF(sc, (" 100TX")); + dcr |= WXDCR_100BT; + } else /* assume IFM_10_TX */ { + DPRINTF(sc, (" 10TX")); + dcr |= WXDCR_10BT; + } + + if (mii->mii_media_active & IFM_FDX) { + DPRINTF(sc, ("-FD")); + tctl = WXTCTL_CT(WX_COLLISION_THRESHOLD) | + WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN; + dcr |= WXDCR_FD; + } else { + DPRINTF(sc, ("-HD")); + tctl = WXTCTL_CT(WX_COLLISION_THRESHOLD) | + WXTCTL_COLD(WX_HDX_COLLISION_DX) | WXTCTL_EN; + dcr &= ~WXDCR_FD; + } + + /* FLAG0==rx-flow-control FLAG1==tx-flow-control */ + if (mii->mii_media_active & IFM_FLAG0) { + dcr |= WXDCR_RFCE; + } else { + dcr &= ~WXDCR_RFCE; + } + + if (mii->mii_media_active & IFM_FLAG1) { + dcr |= WXDCR_TFCE; + } else { + dcr &= ~WXDCR_TFCE; + } + + if (dcr & (WXDCR_RFCE|WXDCR_TFCE)) { + WRITE_CSR(sc, WXREG_FCAL, FC_FRM_CONST_LO); + WRITE_CSR(sc, WXREG_FCAH, FC_FRM_CONST_HI); + WRITE_CSR(sc, WXREG_FCT, FC_TYP_CONST); + } else { + WRITE_CSR(sc, WXREG_FCAL, 0); + WRITE_CSR(sc, WXREG_FCAH, 0); + WRITE_CSR(sc, WXREG_FCT, 0); + } + + DPRINTF(sc, (" dcr=%#x tctl=%#x\n", dcr, tctl)); + WRITE_CSR(sc, WXREG_TCTL, tctl); + sc->wx_dcr = dcr; + WRITE_CSR(sc, WXREG_DCR, dcr); +} + +static void +wx_miibus_mediainit(void *arg) +{ +} |