Index: stable/4/sys/pci/if_wx.c =================================================================== --- stable/4/sys/pci/if_wx.c (revision 84384) +++ stable/4/sys/pci/if_wx.c (revision 84385) @@ -1,2462 +1,2089 @@ /* $FreeBSD$ */ /* - * Principal Author: Matthew Jacob + * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * 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/82453) Driver. * Inspired by fxp driver by David Greenman for FreeBSD, and by * Bill Paul's work in other FreeBSD network drivers. */ /* + * Many bug fixes gratefully acknowledged from: + * + * The folks at Sitara Networks + */ + +/* * Options */ /* * Use only every other 16 byte receive descriptor, leaving the ones * in between empty. This card is most efficient at reading/writing * 32 byte cache lines, so avoid all the (not working for early rev * cards) MWI and/or READ/MODIFY/WRITE cycles updating one descriptor * would have you do. * * This isn't debugged yet. */ /* #define PADDED_CELL 1 */ -/* - * Enable JumboGrams. This seems to work. - */ -/* #define WX_JUMBO 1 */ /* * Since the includes are a mess, they'll all be in if_wxvar.h */ -#if defined(__NetBSD__) || defined(__OpenBSD__) -#include -#elif defined(__FreeBSD__) #include -#endif #ifdef __alpha__ #undef vtophys #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)(va)) #endif /* __alpha__ */ /* * Function Prototpes, yadda yadda... */ 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) -#define JUMBOMTU (WX_MAX_PKT_SIZE_JUMBO - sizeof (struct ether_header)) -#ifdef WX_JUMBO -#define WX_MAXMTU JUMBOMTU -#else -#define WX_MAXMTU ETHERMTU -#endif +#define WX_MAXMTU (WX_MAX_PKT_SIZE_JUMBO - sizeof (struct ether_header)) #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 * -#else -#define MATCHARG struct cfdata * -#endif - -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 - /* - * Life *should* be simple- we only read/write 32 bit values in registers. - * Unfortunately, some platforms define bus_space functions in a fashion - * such that they cannot be used as part of a for loop, for example. - */ - -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(wx_softc_ *sc, u_int32_t reg) -{ - return bus_space_read_4(sc->w.st, sc->w.sh, reg); -} - -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); -} - -struct cfattach wx_ca = { - sizeof (wx_softc_t), wx_match, wx_attach -}; - -#ifdef __OpenBSD__ -struct cfdriver wx_cd = { - 0, "wx", DV_IFNET -}; -#endif - -/* - * Check if a device is an 82452. - */ -static int -wx_match(struct device *parent, MATCHARG match, void *aux) -{ - struct pci_attach_args *pa = aux; - if (PCI_VENDOR(pa->pa_id) != WX_VENDOR_INTEL) { - return (0); - } - switch (PCI_PRODUCT(pa->pa_id)) { - case WX_PRODUCT_82452: - case WX_PRODUCT_LIVENGOOD: - case WX_PRODUCT_82452_SC: - case WX_PRODUCT_82543: - break; - default: - return (0); - } - return (1); -} - -static void -wx_attach(struct device *parent, struct devuce *self, void *aux) -{ - 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; - const char *intrstr = NULL; - u_int32_t data; - struct ifnet *ifp; - - sc->w.pci_pc = pa->pa_pc; - sc->w.pci_tag = pa->pa_tag; - - /* - * Map control/status registers. - */ - if (pci_mapreg_map(pa, WX_MMBA, PCI_MAPREG_TYPE_MEM, 0, - &sc->w.st, &sc->w.sh, NULL, NULL)) { - printf(": can't map registers\n"); - return; - } - printf(": Intel GigaBit Ethernet\n"); - - /* - * Allocate our interrupt. - */ - if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin, - pa->pa_intrline, &ih)) { - printf("%s: couldn't map interrupt\n", sc->wx_name); - return; - } - intrstr = pci_intr_string(pc, ih); -#if defined(__OpenBSD__) - sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc, - self->dv_xname); -#else - sc->w.ih = pci_intr_establish(pc, ih, IPL_NET, wx_intr, sc); -#endif - if (sc->w.ih == NULL) { - printf("%s: couldn't establish interrupt", sc->wx_name); - if (intrstr != NULL) - printf(" at %s", intrstr); - printf("\n"); - return; - } - printf("%s: interrupting at %s\n", sc->wx_name, intrstr); - sc->wx_idnrev = (PCI_PRODUCT(pa->pa_id) << 16) | - (pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_CLASS_REG) & 0xff); - - data = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); - data &= ~(PCI_CACHELINE_MASK << PCI_CACHELINE_SHIFT); - 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; - } - - printf("%s: Ethernet address %s\n", - sc->wx_name, ether_sprintf(sc->wx_enaddr)); - - ifp = &sc->wx_if; - bcopy(sc->wx_name, ifp->if_xname, IFNAMSIZ); - ifp->if_mtu = WX_MAXMTU; - ifp->if_softc = sc; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; - ifp->if_ioctl = wx_ioctl; - ifp->if_start = wx_start; - ifp->if_watchdog = wx_txwatchdog; - - /* - * Attach the interface. - */ - if_attach(ifp); -#ifdef __OpenBSD__ - ether_ifattach(ifp); -#else - ether_ifattach(ifp, sc->wx_enaddr); -#endif - -#if NBPFILTER > 0 - bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, - sizeof (struct ether_header)); -#endif - /* - * Add shutdown hook so that DMA is disabled prior to reboot. Not - * doing do could allow DMA to corrupt kernel memory during the - * reboot before the driver initializes. - */ - shutdownhook_establish(wx_shutdown, 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; -} - -/* - * Device shutdown routine. Called at system shutdown after sync. The - * main purpose of this routine is to shut off receiver DMA so that - * kernel memory doesn't get clobbered during warmboot. - */ -static void -wx_shutdown(void *sc) -{ - wx_hw_stop((wx_softc_t *) sc); -} - -static int -wx_ether_ioctl(struct ifnet *ifp, IOCTL_CMD_TYPE cmd, caddr_t data) -{ - struct ifaddr *ifa = (struct ifaddr *) data; - int error = 0; - wx_softc_t *sc = SOFTC_IFP(ifp); - - switch (cmd) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - error = wx_init(sc); - if (error) { - ifp->if_flags &= ~IFF_UP; - break; - } - switch (ifa->ifa_addr->sa_family) { -#ifdef INET - case AF_INET: -#ifdef __OpenBSD__ - arp_ifinit(&sc->w.arpcom, ifa); -#else - arp_ifinit(ifp, ifa); -#endif - break; -#endif -#ifdef NS - case AF_NS: - { - register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr; - if (ns_nullhost(*ina)) - ina->x_host = *(union ns_host *) - LLADDR(ifp->if_sadl); - else - bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl), - ifp->if_addrlen); - break; - } -#endif - default: - break; - } - - break; - - default: - error = EINVAL; - break; - } - - return (0); -} - -/* * Program multicast addresses. * * This function must be called at splimp, but it may sleep. */ static int wx_mc_setup(wx_softc_t *sc) { struct ifnet *ifp = &sc->wx_if; - struct ether_multistep step; - struct ether_multi *enm; - - /* - * XXX: drain TX queue- use a tsleep/wakeup until done. - */ - if (sc->tactive) { - return (EBUSY); - } - - wx_stop(sc); - - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { - sc->all_mcasts = 1; - return (wx_init(sc)); - } - -#ifdef __OpenBSD__ - ETHER_FIRST_MULTI(step, &sc->w.arpcom, enm); -#else - ETHER_FIRST_MULTI(step, &sc->w.ethercom, enm); -#endif - - while (enm != NULL) { - if (memcmp(enm->enm_addrlo, enm->enm_addrhi, 6) != 0) - continue; - if (sc->wx_nmca >= WX_RAL_TAB_SIZE-1) { - sc->wx_nmca = 0; - sc->all_mcasts = 1; - break; - } - bcopy(enm->enm_addrlo, - (void *) &sc->wx_mcaddr[sc->wx_nmca++][0], 6); - ETHER_NEXT_MULTI(step, enm); - } - return (wx_init(sc)); -} - -static INLINE void -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); - pci_conf_write(sc->w.pci_pc, sc->w.pci_tag, - PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI); -} - -static INLINE void -wx_mwi_unwhack(wx_softc_t *sc) -{ - if (sc->wx_cmdw & MWI) { - pci_conf_write(sc->w.pci_pc, sc->w.pci_tag, - PCI_COMMAND_STATUS_REG, sc->wx_cmdw & ~MWI); - } -} - -static int -wx_dring_setup(wx_softc_t *sc) -{ - size_t len; - - len = sizeof (wxrd_t) * WX_MAX_RDESC; - if (len > NBPG) { - printf("%s: len (%lx) over a page for the receive ring\n", - sc->wx_name, len); - return (-1); - } - len = NBPG; - sc->rdescriptors = (wxrd_t *) WXMALLOC(len); - if (sc->rdescriptors == NULL) { - printf("%s: could not allocate rcv descriptors\n", sc->wx_name); - return (-1); - } - - if (((intptr_t)sc->rdescriptors) & 0xfff) { - printf("%s: rcv descriptors not 4KB aligned\n", sc->wx_name); - return (-1); - } - bzero(sc->rdescriptors, len); - - len = sizeof (wxtd_t) * WX_MAX_TDESC; - if (len > NBPG) { - printf("%s: len (%lx) over a page for the xmit ring\n", - sc->wx_name, len); - return (-1); - } - len = NBPG; - sc->tdescriptors = (wxtd_t *) WXMALLOC(len); - if (sc->tdescriptors == NULL) { - printf("%s: could not allocate xmt descriptors\n", sc->wx_name); - return (-1); - } - if (((intptr_t)sc->tdescriptors) & 0xfff) { - printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name); - return (-1); - } - bzero(sc->tdescriptors, len); - return (0); -} - -static void -wx_dring_teardown(wx_softc_t *sc) -{ - if (sc->rdescriptors) { - WXFREE(sc->rdescriptors); - sc->rdescriptors = NULL; - } - if (sc->tdescriptors) { - WXFREE(sc->tdescriptors); - sc->tdescriptors = NULL; - } -} - -#elif defined(__FreeBSD__) -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(wx_softc_t *sc) -{ - struct ifnet *ifp = &sc->wx_if; struct ifmultiaddr *ifma; /* - * XXX: drain TX queue- use a tsleep/wakeup until done. + * XXX: drain TX queue */ if (sc->tactive) { return (EBUSY); } wx_stop(sc); - if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { + if ((ifp->if_flags & IFF_ALLMULTI) || (ifp->if_flags & IFF_PROMISC)) { sc->all_mcasts = 1; return (wx_init(sc)); } + sc->wx_nmca = 0; for (ifma = ifp->if_multiaddrs.lh_first, sc->wx_nmca = 0; ifma != NULL; ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) { continue; } if (sc->wx_nmca >= WX_RAL_TAB_SIZE-1) { sc->wx_nmca = 0; sc->all_mcasts = 1; break; } bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), (void *) &sc->wx_mcaddr[sc->wx_nmca++][0], 6); } return (wx_init(sc)); } /* * Return identification string if this is device is ours. */ static int wx_probe(device_t dev) { if (pci_get_vendor(dev) != WX_VENDOR_INTEL) { return (ENXIO); } switch (pci_get_device(dev)) { case WX_PRODUCT_82452: device_set_desc(dev, "Intel PRO/1000 Gigabit (WISEMAN)"); break; case WX_PRODUCT_LIVENGOOD: device_set_desc(dev, "Intel PRO/1000 (LIVENGOOD)"); break; case WX_PRODUCT_82452_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); } return (0); } static int wx_attach(device_t dev) { int error = 0; wx_softc_t *sc = device_get_softc(dev); struct ifnet *ifp; u_int32_t val; int rid; bzero(sc, sizeof (wx_softc_t)); callout_handle_init(&sc->w.sch); sc->w.dev = dev; if (bootverbose) sc->wx_verbose = 1; if (getenv_int ("wx_debug", &rid)) { if (rid & (1 << device_get_unit(dev))) { sc->wx_debug = 1; } } if (getenv_int("wx_no_ilos", &rid)) { if (rid & (1 << device_get_unit(dev))) { sc->wx_no_ilos = 1; } } if (getenv_int("wx_ilos", &rid)) { if (rid & (1 << device_get_unit(dev))) { sc->wx_ilos = 1; } } if (getenv_int("wx_no_flow", &rid)) { if (rid & (1 << device_get_unit(dev))) { sc->wx_no_flow = 1; } } #ifdef SMPNG mtx_init(&sc->wx_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE); #endif - WX_LOCK(sc); /* * get revision && id... */ sc->wx_idnrev = (pci_get_device(dev) << 16) | (pci_get_revid(dev)); /* * Enable bus mastering, make sure that the cache line size is right. */ - val = pci_read_config(dev, PCIR_COMMAND, 2); - val |= (PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_write_config(dev, PCIR_COMMAND, val, 2); + pci_enable_busmaster(dev); + pci_enable_io(dev, SYS_RES_MEMORY); + val = pci_read_config(dev, PCIR_COMMAND, 4); + if ((val & PCIM_CMD_MEMEN) == 0) { + device_printf(dev, "failed to enable memory mapping\n"); + error = ENXIO; + goto out; + } + /* + * Let the BIOS do it's job- but check for sanity. + */ val = pci_read_config(dev, PCIR_CACHELNSZ, 1); - if (val != 0x10) { - pci_write_config(dev, PCIR_CACHELNSZ, 0x10, 1); + if (val < 4 || val > 32) { + pci_write_config(dev, PCIR_CACHELNSZ, 8, 1); } - /* * Map control/status registers. */ rid = WX_MMBA; sc->w.mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1, RF_ACTIVE); if (!sc->w.mem) { device_printf(dev, "could not map memory\n"); error = ENXIO; goto out; } sc->w.st = rman_get_bustag(sc->w.mem); sc->w.sh = rman_get_bushandle(sc->w.mem); rid = 0; sc->w.irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->w.irq == NULL) { device_printf(dev, "could not map interrupt\n"); error = ENXIO; goto out; } error = bus_setup_intr(dev, sc->w.irq, INTR_TYPE_NET, (void (*)(void *))wx_intr, sc, &sc->w.ih); if (error) { device_printf(dev, "could not setup irq\n"); goto out; } + (void) snprintf(sc->wx_name, sizeof (sc->wx_name) - 1, "wx%d", + device_get_unit(dev)); if (wx_attach_common(sc)) { 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); error = ENXIO; goto out; } device_printf(dev, "Ethernet address %02x:%02x:%02x:%02x:%02x:%02x\n", sc->w.arpcom.ac_enaddr[0], sc->w.arpcom.ac_enaddr[1], sc->w.arpcom.ac_enaddr[2], sc->w.arpcom.ac_enaddr[3], sc->w.arpcom.ac_enaddr[4], sc->w.arpcom.ac_enaddr[5]); - (void) snprintf(sc->wx_name, sizeof (sc->wx_name) - 1, "wx%d", - device_get_unit(dev)); ifp = &sc->w.arpcom.ac_if; ifp->if_unit = device_get_unit(dev); ifp->if_name = "wx"; - ifp->if_mtu = WX_MAXMTU; + ifp->if_mtu = ETHERMTU; /* we always start at ETHERMTU size */ ifp->if_output = ether_output; ifp->if_baudrate = 1000000000; ifp->if_init = (void (*)(void *))wx_init; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = wx_ioctl; ifp->if_start = wx_start; ifp->if_watchdog = wx_txwatchdog; ifp->if_snd.ifq_maxlen = WX_MAX_TDESC - 1; ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 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); + sc->wx_mii = 1; return 0; } static int wx_detach(device_t dev) { wx_softc_t *sc = device_get_softc(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); + if (sc->w.miibus) { + bus_generic_detach(dev); + device_delete_child(dev, sc->w.miibus); + } else { + ifmedia_removeall(&sc->wx_media); + } 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); WX_UNLOCK(sc); return (0); } static int wx_shutdown(device_t dev) { wx_hw_stop((wx_softc_t *) device_get_softc(dev)); return (0); } static INLINE void 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(wx_softc_t *sc) { if (sc->wx_cmdw & MWI) { pci_write_config(sc->w.dev, PCIR_COMMAND, sc->wx_cmdw, 2); } } static int wx_dring_setup(wx_softc_t *sc) { size_t len; len = sizeof (wxrd_t) * WX_MAX_RDESC; sc->rdescriptors = (wxrd_t *) contigmalloc(len, M_DEVBUF, M_NOWAIT, 0, ~0, 4096, 0); if (sc->rdescriptors == NULL) { printf("%s: could not allocate rcv descriptors\n", sc->wx_name); return (-1); } 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); return (-1); } bzero(sc->rdescriptors, len); len = sizeof (wxtd_t) * WX_MAX_TDESC; sc->tdescriptors = (wxtd_t *) contigmalloc(len, M_DEVBUF, M_NOWAIT, 0, ~0, 4096, 0); if (sc->tdescriptors == NULL) { contigfree(sc->rdescriptors, sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); sc->rdescriptors = NULL; printf("%s: could not allocate xmt descriptors\n", sc->wx_name); return (-1); } if (((intptr_t)sc->tdescriptors) & 0xfff) { contigfree(sc->rdescriptors, sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); sc->rdescriptors = NULL; printf("%s: xmt descriptors not 4KB aligned\n", sc->wx_name); return (-1); } bzero(sc->tdescriptors, len); return (0); } static void wx_dring_teardown(wx_softc_t *sc) { if (sc->rdescriptors) { contigfree(sc->rdescriptors, sizeof (wxrd_t) * WX_MAX_RDESC, M_DEVBUF); sc->rdescriptors = NULL; } if (sc->tdescriptors) { contigfree(sc->tdescriptors, sizeof (wxtd_t) * WX_MAX_TDESC, M_DEVBUF); sc->tdescriptors = NULL; } } static device_method_t wx_methods[] = { /* Device interface */ DEVMETHOD(device_probe, wx_probe), 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 } }; static driver_t wx_driver = { "wx", wx_methods, sizeof(wx_softc_t), }; 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 /* * Do generic parts of attach. Our registers have been mapped * and our interrupt registered. */ static int wx_attach_common(wx_softc_t *sc) { size_t len; u_int32_t tmp; int ll = 0; /* * First, check for revision support. */ if (sc->wx_idnrev < WX_WISEMAN_2_0) { printf("%s: cannot support ID 0x%x, revision %d chips\n", sc->wx_name, sc->wx_idnrev >> 16, sc->wx_idnrev & 0xffff); return (ENXIO); } /* * Second, reset the chip. */ wx_hw_stop(sc); /* * Third, validate our EEPROM. */ /* TBD */ /* * Fourth, read eeprom for our MAC address and other things. */ wx_read_eeprom(sc, (u_int16_t *)sc->wx_enaddr, WX_EEPROM_MAC_OFF, 3); /* * Fifth, establish some adapter parameters. */ sc->wx_txint_delay = 128; 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, 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. */ ll += 1; if (sc->wx_cfg1 & WX_EEPROM_CTLR1_FD) sc->wx_dcr |= WXDCR_FD; if (sc->wx_cfg1 & WX_EEPROM_CTLR1_ILOS) sc->wx_dcr |= WXDCR_ILOS; tmp = (sc->wx_cfg1 >> WX_EEPROM_CTLR1_SWDPIO_SHIFT) & WXDCR_SWDPIO_MASK; sc->wx_dcr |= (tmp << WXDCR_SWDPIO_SHIFT); if (sc->wx_no_ilos) sc->wx_dcr &= ~WXDCR_ILOS; if (sc->wx_ilos) sc->wx_dcr |= WXDCR_ILOS; if (sc->wx_no_flow == 0) sc->wx_dcr |= WXDCR_RFCE | WXDCR_TFCE; /* * Seventh, allocate various sw structures... */ len = sizeof (rxpkt_t) * WX_MAX_RDESC; sc->rbase = (rxpkt_t *) WXMALLOC(len); if (sc->rbase == NULL) { goto fail; } bzero(sc->rbase, len); ll += 1; len = sizeof (txpkt_t) * WX_MAX_TDESC; sc->tbase = (txpkt_t *) WXMALLOC(len); if (sc->tbase == NULL) { goto fail; } bzero(sc->tbase, len); ll += 1; /* * Eighth, allocate and dma map (platform dependent) descriptor rings. * They have to be aligned on a 4KB boundary. */ if (wx_dring_setup(sc) == 0) { return (0); } fail: printf("%s: failed to do common attach (%d)\n", sc->wx_name, ll); wx_dring_teardown(sc); if (sc->rbase) { WXFREE(sc->rbase); sc->rbase = NULL; } if (sc->tbase) { WXFREE(sc->tbase); sc->tbase = NULL; } return (ENOMEM); } /* * EEPROM functions. */ static INLINE void 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(wx_softc_t *sc, u_int32_t regval) { WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_SK); DELAY(50); } static INLINE void wx_eeprom_sobits(wx_softc_t *sc, u_int16_t data, u_int16_t count) { u_int32_t regval, mask; mask = 1 << (count - 1); regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_DO); do { if (data & mask) regval |= WXEECD_DI; else regval &= ~WXEECD_DI; WRITE_CSR(sc, WXREG_EECDR, regval); DELAY(50); wx_eeprom_raise_clk(sc, regval); wx_eeprom_lower_clk(sc, regval); mask >>= 1; } while (mask != 0); WRITE_CSR(sc, WXREG_EECDR, regval & ~WXEECD_DI); } static INLINE u_int16_t wx_eeprom_sibits(wx_softc_t *sc) { unsigned int regval, i; u_int16_t data; data = 0; regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_DO); for (i = 0; i != 16; i++) { data <<= 1; wx_eeprom_raise_clk(sc, regval); regval = READ_CSR(sc, WXREG_EECDR) & ~WXEECD_DI; if (regval & WXEECD_DO) { data |= 1; } wx_eeprom_lower_clk(sc, regval); } return (data); } static INLINE void wx_eeprom_cleanup(wx_softc_t *sc) { u_int32_t regval; regval = READ_CSR(sc, WXREG_EECDR) & ~(WXEECD_DI|WXEECD_CS); WRITE_CSR(sc, WXREG_EECDR, regval); DELAY(50); wx_eeprom_raise_clk(sc, regval); wx_eeprom_lower_clk(sc, regval); } static u_int16_t INLINE wx_read_eeprom_word(wx_softc_t *sc, int offset) { u_int16_t data; WRITE_CSR(sc, WXREG_EECDR, WXEECD_CS); wx_eeprom_sobits(sc, EEPROM_READ_OPCODE, 3); wx_eeprom_sobits(sc, offset, 6); data = wx_eeprom_sibits(sc); wx_eeprom_cleanup(sc); return (data); } static void wx_read_eeprom(wx_softc_t *sc, u_int16_t *data, int offset, int words) { int i; for (i = 0; i < words; i++) { *data++ = wx_read_eeprom_word(sc, offset++); } sc->wx_cfg1 = wx_read_eeprom_word(sc, WX_EEPROM_CTLR1_OFF); } /* * Start packet transmission on the interface. */ static void wx_start(struct ifnet *ifp) { wx_softc_t *sc = SOFTC_IFP(ifp); - u_int16_t cidx, nactv; + u_int16_t widx = WX_MAX_TDESC, cidx, nactv; WX_LOCK(sc); DPRINTF(sc, ("%s: wx_start\n", sc->wx_name)); nactv = sc->tactive; - while (nactv < WX_MAX_TDESC) { + while (nactv < WX_MAX_TDESC - 1) { int ndesc; int gctried = 0; struct mbuf *m, *mb_head; IF_DEQUEUE(&ifp->if_snd, mb_head); if (mb_head == NULL) { break; } sc->wx_xmitwanted++; /* * If we have a packet less than ethermin, pad it out. */ if (mb_head->m_pkthdr.len < WX_MIN_RPKT_SIZE) { MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { m_freem(mb_head); break; } m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(m, caddr_t)); m->m_pkthdr.len = m->m_len = WX_MIN_RPKT_SIZE; bzero(mtod(m, char *) + mb_head->m_pkthdr.len, WX_MIN_RPKT_SIZE - mb_head->m_pkthdr.len); sc->wx_xmitpullup++; m_freem(mb_head); mb_head = m; } again: cidx = sc->tnxtfree; nactv = sc->tactive; /* * Go through each of the mbufs in the chain and initialize * the transmit buffer descriptors with the physical address * and size of that mbuf. If we have a length less than our * minimum transmit size, we bail (to do a pullup). If we run * out of descriptors, we also bail and try and do a pullup. */ for (ndesc = 0, m = mb_head; m != NULL; m = m->m_next) { vm_offset_t vptr; wxtd_t *td; /* * If this mbuf has no data, skip it. */ if (m->m_len == 0) { continue; } /* * If this packet is too small for the chip's minimum, - * break out to to cluster it. + * break out to cluster it. */ if (m->m_len < WX_MIN_RPKT_SIZE) { sc->wx_xmitrunt++; break; } /* * Do we have a descriptor available for this mbuf? */ if (++nactv == WX_MAX_TDESC) { if (gctried++ == 0) { sc->wx_xmitgc++; wx_gc(sc); goto again; } break; } sc->tbase[cidx].dptr = m; td = &sc->tdescriptors[cidx]; td->length = m->m_len; vptr = mtod(m, vm_offset_t); td->address.highpart = 0; td->address.lowpart = vtophys(vptr); td->cso = 0; td->status = 0; td->special = 0; td->cmd = 0; td->css = 0; if (sc->wx_debug) { printf("%s: XMIT[%d] %p vptr %lx (length %d " "DMA addr %x) idx %d\n", sc->wx_name, ndesc, m, (long) vptr, td->length, td->address.lowpart, cidx); } ndesc++; cidx = T_NXT_IDX(cidx); } /* * If we get here and m is NULL, we can send * the the packet chain described by mb_head. */ if (m == NULL) { /* * Mark the last descriptor with EOP and tell the * chip to insert a final checksum. */ wxtd_t *td = &sc->tdescriptors[T_PREV_IDX(cidx)]; td->cmd = TXCMD_EOP|TXCMD_IFCS; sc->tbase[sc->tnxtfree].sidx = sc->tnxtfree; sc->tbase[sc->tnxtfree].eidx = cidx; sc->tbase[sc->tnxtfree].next = NULL; if (sc->tbsyf) { sc->tbsyl->next = &sc->tbase[sc->tnxtfree]; } else { sc->tbsyf = &sc->tbase[sc->tnxtfree]; } sc->tbsyl = &sc->tbase[sc->tnxtfree]; sc->tnxtfree = cidx; sc->tactive = nactv; ifp->if_timer = 10; - 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); + /* defer xmit until we've got them all */ + widx = cidx; continue; } /* * Otherwise, we couldn't send this packet for some reason. * * If don't have a descriptor available, and this is a * single mbuf packet, freeze output so that later we * can restart when we have more room. Otherwise, we'll * try and cluster the request. We've already tried to * garbage collect completed descriptors. */ if (nactv == WX_MAX_TDESC && mb_head->m_next == NULL) { sc->wx_xmitputback++; ifp->if_flags |= IFF_OACTIVE; IF_PREPEND(&ifp->if_snd, mb_head); break; } /* * Otherwise, it's either a fragment length somewhere in the * chain that isn't at least WX_MIN_XPKT_SIZE in length or * the number of fragments exceeds the number of descriptors * available. * * We could try a variety of strategies here- if this is * a length problem for single mbuf packet or a length problem * for the last mbuf in a chain (we could just try and adjust * it), but it's just simpler to try and cluster it. */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { m_freem(mb_head); break; } MCLGET(m, M_DONTWAIT); if ((m->m_flags & M_EXT) == 0) { m_freem(m); m_freem(mb_head); break; } m_copydata(mb_head, 0, mb_head->m_pkthdr.len, mtod(m, caddr_t)); m->m_pkthdr.len = m->m_len = mb_head->m_pkthdr.len; m_freem(mb_head); mb_head = m; sc->wx_xmitcluster++; goto again; } - if (sc->tactive == WX_MAX_TDESC) { + if (widx < WX_MAX_TDESC) { + if (IS_WISEMAN(sc)) { + WRITE_CSR(sc, WXREG_TDT, widx); + } else { + WRITE_CSR(sc, WXREG_TDT_LIVENGOOD, widx); + } + } + + if (sc->tactive == WX_MAX_TDESC - 1) { 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); } /* * Process interface interrupts. */ static int wx_intr(void *arg) { wx_softc_t *sc = arg; int claimed = 0; WX_ILOCK(sc); /* * Read interrupt cause register. Reading it clears bits. */ sc->wx_icr = READ_CSR(sc, WXREG_ICR); if (sc->wx_icr) { claimed++; WX_DISABLE_INT(sc); sc->wx_intr++; if (sc->wx_icr & (WXISR_LSC|WXISR_RXSEQ|WXISR_GPI_EN1)) { wx_handle_link_intr(sc); } wx_handle_rxint(sc); - if (sc->tactive) { + if (sc->wx_icr & WXISR_TXQE) { wx_gc(sc); } if (sc->wx_if.if_snd.ifq_head != NULL) { wx_start(&sc->wx_if); } WX_ENABLE_INT(sc); } WX_IUNLK(sc); return (claimed); } static void 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) { + mii_data_t *mii = WX_MII_FROM_SOFTC(sc); + mii_pollstat(mii); + if (mii->mii_media_status & IFM_ACTIVE) { + if (IFM_SUBTYPE(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); /* * If we have LOS or are now receiving Ordered Sets and are not * doing auto-negotiation, restore autonegotiation. */ if (((dcr & WXDCR_SWDPIN1) || (rxcw & WXRXCW_C)) && ((txcw & WXTXCW_ANE) == 0)) { 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); sc->ane_failed = 0; } if (sc->wx_icr & WXISR_LSC) { if (READ_CSR(sc, WXREG_DSR) & WXDSR_LU) { IPRINTF(sc, (lup, sc->wx_name)); sc->linkup = 1; sc->wx_dcr |= (WXDCR_SWDPIO0|WXDCR_SWDPIN0); } else { 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 { DPRINTF(sc, (sqe, sc->wx_name)); } } static void wx_check_link(wx_softc_t *sc) { u_int32_t rxcw, dcr, dsr; if (sc->wx_mii) { - mii_pollstat(sc->wx_mii); + mii_pollstat(WX_MII_FROM_SOFTC(sc)); return; } rxcw = READ_CSR(sc, WXREG_RECV_CFGW); dcr = READ_CSR(sc, WXREG_DCR); dsr = READ_CSR(sc, WXREG_DSR); if ((dsr & WXDSR_LU) == 0 && (dcr & WXDCR_SWDPIN1) == 0 && (rxcw & WXRXCW_C) == 0) { if (sc->ane_failed == 0) { sc->ane_failed = 1; return; } 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) { 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); } } static void 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)) { wxrd_t *rd; rxpkt_t *rxpkt; int length, offset, lastframe; rd = &sc->rdescriptors[idx]; + /* + * XXX: DMA Flush descriptor + */ if ((rd->status & RDSTAT_DD) == 0) { if (m0) { if (sc->rpending == NULL) { m0->m_pkthdr.len = tlen; sc->rpending = m0; } else { m_freem(m0); } m0 = NULL; } DPRINTF(sc, ("%s: WXRX: ndesc %d idx %d lidx %d\n", sc->wx_name, ndesc, idx, lidx)); break; } if (rd->errors != 0) { printf("%s: packet with errors (%x)\n", sc->wx_name, rd->errors); rd->status = 0; ifp->if_ierrors++; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } rxpkt = &sc->rbase[idx]; mb = rxpkt->dptr; if (mb == NULL) { printf("%s: receive descriptor with no mbuf\n", sc->wx_name); (void) wx_get_rbuf(sc, rxpkt); rd->status = 0; ifp->if_ierrors++; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } /* XXX: Flush DMA for rxpkt */ if (wx_get_rbuf(sc, rxpkt)) { sc->wx_rxnobuf++; wx_rxdma_map(sc, rxpkt, mb); ifp->if_ierrors++; rd->status = 0; if (m0) { m_freem(m0); m0 = NULL; if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } } continue; } /* * Save the completing packet's offset value and length * and install the new one into the descriptor. */ lastframe = (rd->status & RDSTAT_EOP) != 0; length = rd->length; offset = rd->address.lowpart & 0xff; bzero (rd, sizeof (*rd)); rd->address.lowpart = rxpkt->dma_addr + WX_RX_OFFSET_VALUE; mb->m_len = length; mb->m_data += offset; mb->m_next = NULL; if (m0 == NULL) { m0 = mb; tlen = length; } else if (m0 == sc->rpending) { /* * Pick up where we left off before. If * we have an offset (we're assuming the * first frame has an offset), then we've * lost sync somewhere along the line. */ if (offset) { printf("%s: lost sync with partial packet\n", sc->wx_name); m_freem(sc->rpending); sc->rpending = NULL; m0 = mb; tlen = length; } else { sc->rpending = NULL; tlen = m0->m_pkthdr.len; } } else { tlen += length; } 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) { continue; } m0->m_pkthdr.rcvif = ifp; m0->m_pkthdr.len = tlen - WX_CRC_LENGTH; mb->m_len -= WX_CRC_LENGTH; eh = mtod(m0, struct ether_header *); /* * No need to check for promiscous mode since * the decision to keep or drop the packet is * handled by ether_input() */ pending[npkts++] = m0; m0 = NULL; tlen = 0; } if (ndesc) { if (IS_WISEMAN(sc)) { WRITE_CSR(sc, WXREG_RDT0, lidx); } else { WRITE_CSR(sc, WXREG_RDT0_LIVENGOOD, lidx); } sc->rnxt = idx; } if (npkts) { sc->wx_rxintr++; } for (idx = 0; idx < npkts; idx++) { mb = pending[idx]; -#if NBPFILTER > 0 if (ifp->if_bpf) { bpf_mtap(WX_BPFTAP_ARG(ifp), mb); } -#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)); ether_input(ifp, eh, mb); -#else - (*ifp->if_input)(ifp, mb); -#endif } } static void wx_gc(wx_softc_t *sc) { struct ifnet *ifp = &sc->wx_if; txpkt_t *txpkt; u_int32_t tdh; WX_LOCK(sc); txpkt = sc->tbsyf; 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; /* * Normalize start..end indices to 2 * * WX_MAX_TDESC range to eliminate wrap. */ if (txpkt->eidx < txpkt->sidx) { end += WX_MAX_TDESC; } /* * Normalize current chip index to 2 * * WX_MAX_TDESC range to eliminate wrap. */ if (cidx < txpkt->sidx) { cidx += WX_MAX_TDESC; } /* * If the current chip index is between low and * high indices for this packet, it's not finished * transmitting yet. Because transmits are done FIFO, * this means we're done garbage collecting too. */ if (txpkt->sidx <= cidx && cidx < txpkt->eidx) { DPRINTF(sc, ("%s: TXGC %d..%d TDH %d\n", sc->wx_name, txpkt->sidx, txpkt->eidx, tdh)); break; } ifp->if_opackets++; if (txpkt->dptr) { (void) m_freem(txpkt->dptr); } else { printf("%s: null mbuf in gc\n", sc->wx_name); } for (cidx = txpkt->sidx; cidx != txpkt->eidx; cidx = T_NXT_IDX(cidx)) { txpkt_t *tmp; wxtd_t *td; td = &sc->tdescriptors[cidx]; if (td->status & TXSTS_EC) { IPRINTF(sc, ("%s: excess collisions\n", sc->wx_name)); ifp->if_collisions++; ifp->if_oerrors++; } if (td->status & TXSTS_LC) { IPRINTF(sc, ("%s: lost carrier\n", sc->wx_name)); ifp->if_oerrors++; } tmp = &sc->tbase[cidx]; 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); } else { sc->tactive -= 1; } bzero(td, sizeof (*td)); } sc->tbsyf = txpkt->next; txpkt = sc->tbsyf; } - if (sc->tactive < WX_MAX_TDESC) { + if (sc->tactive < WX_MAX_TDESC - 1) { 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); } /* * Periodic timer to update packet in/out/collision statistics, * and, more importantly, garbage collect completed transmissions * and to handle link status changes. */ static void wx_watchdog(void *arg) { wx_softc_t *sc = arg; WX_LOCK(sc); wx_gc(sc); wx_check_link(sc); WX_UNLOCK(sc); /* * Schedule another timeout one second from now. */ VTIMEOUT(sc, wx_watchdog, sc, hz); } /* * Stop and reinitialize the hardware */ static void wx_hw_stop(wx_softc_t *sc) { u_int32_t icr; DPRINTF(sc, ("%s: wx_hw_stop\n", sc->wx_name)); + WX_DISABLE_INT(sc); if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); } WRITE_CSR(sc, WXREG_DCR, WXDCR_RST); DELAY(20 * 1000); - WRITE_CSR(sc, WXREG_IMASK, ~0); icr = READ_CSR(sc, WXREG_ICR); if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_unwhack(sc); } - WX_DISABLE_INT(sc); } static void 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; WRITE_CSR(sc, WXREG_RAL_LO(idx), t0); WRITE_CSR(sc, WXREG_RAL_HI(idx), t1); } static int wx_hw_initialize(wx_softc_t *sc) { int i; 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) { WRITE_CSR(sc, (WXREG_VFTA + i), 0); } if (sc->wx_idnrev < WX_WISEMAN_2_1) { wx_mwi_whackon(sc); WRITE_CSR(sc, WXREG_RCTL, WXRCTL_RST); DELAY(5 * 1000); } /* * Load the first receiver address with our MAC address, * and load as many multicast addresses as can fit into * the receive address array. */ wx_set_addr(sc, 0, sc->wx_enaddr); for (i = 1; i <= sc->wx_nmca; i++) { if (i >= WX_RAL_TAB_SIZE) { break; } else { wx_set_addr(sc, i, sc->wx_mcaddr[i-1]); } } while (i < WX_RAL_TAB_SIZE) { WRITE_CSR(sc, WXREG_RAL_LO(i), 0); WRITE_CSR(sc, WXREG_RAL_HI(i), 0); i++; } if (sc->wx_idnrev < WX_WISEMAN_2_1) { WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(1 * 1000); wx_mwi_unwhack(sc); } /* * Clear out the hashed multicast table array. */ for (i = 0; i < WX_MC_TAB_SIZE; i++) { WRITE_CSR(sc, WXREG_MTA + (sizeof (u_int32_t) * 4), 0); } 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); 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); } if (sc->wx_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); } WRITE_CSR(sc, WXREG_FLOW_XTIMER, WX_XTIMER_DFLT); 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_LIVENGOOD, WX_RCV_FLOW_HI_DFLT); WRITE_CSR(sc, WXREG_FLOW_RCV_LO_LIVENGOOD, WX_RCV_FLOW_LO_DFLT); } if (!IS_LIVENGOOD_CU(sc)) WRITE_CSR(sc, WXREG_XMIT_CFGW, WXTXCW_DEFAULT); WRITE_CSR(sc, WXREG_DCR, sc->wx_dcr); DELAY(50 * 1000); 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 */ } } sc->wx_ienable = WXIENABLE_DEFAULT; return (0); } /* * Stop the interface. Cancels the statistics updater and resets the interface. */ static void 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. */ UNTIMEOUT(wx_watchdog, sc, sc); /* * Reset the chip */ wx_hw_stop(sc); /* * Release any xmit buffers. */ for (txp = sc->tbase; txp && txp < &sc->tbase[WX_MAX_TDESC]; txp++) { if (txp->dptr) { m_free(txp->dptr); txp->dptr = NULL; } } /* * Free all the receive buffers. */ for (rxp = sc->rbase; rxp && rxp < &sc->rbase[WX_MAX_RDESC]; rxp++) { if (rxp->dptr) { m_free(rxp->dptr); rxp->dptr = NULL; } } if (sc->rpending) { m_freem(sc->rpending); sc->rpending = NULL; } /* * And we're outta here... */ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0; } /* * Transmit Watchdog */ static void wx_txwatchdog(struct ifnet *ifp) { wx_softc_t *sc = SOFTC_IFP(ifp); printf("%s: device timeout\n", sc->wx_name); ifp->if_oerrors++; if (wx_init(sc)) { printf("%s: could not re-init device\n", sc->wx_name); VTIMEOUT(sc, (void (*)(void *))wx_init, sc, hz); } } static int wx_init(void *xsc) { struct ifmedia *ifm; wx_softc_t *sc = xsc; struct ifnet *ifp = &sc->wx_if; rxpkt_t *rxpkt; wxrd_t *rd; size_t len; int i, bflags; DPRINTF(sc, ("%s: wx_init\n", sc->wx_name)); WX_LOCK(sc); /* * Cancel any pending I/O by resetting things. * wx_stop will free any allocated mbufs. */ wx_stop(sc); /* * Reset the hardware. All network addresses loaded here, but * neither the receiver nor the transmitter are enabled. */ if (wx_hw_initialize(sc)) { DPRINTF(sc, ("%s: wx_hw_initialize failed\n", sc->wx_name)); WX_UNLOCK(sc); return (EIO); } /* * Set up the receive ring stuff. */ len = sizeof (wxrd_t) * WX_MAX_RDESC; bzero(sc->rdescriptors, len); for (rxpkt = sc->rbase, i = 0; rxpkt != NULL && i < WX_MAX_RDESC; i += RXINCR, rxpkt++) { rd = &sc->rdescriptors[i]; if (wx_get_rbuf(sc, rxpkt)) { break; } rd->address.lowpart = rxpkt->dma_addr + WX_RX_OFFSET_VALUE; } if (i != WX_MAX_RDESC) { printf("%s: could not set up rbufs\n", sc->wx_name); wx_stop(sc); WX_UNLOCK(sc); return (ENOMEM); } /* * Set up transmit parameters and enable the transmitter. */ sc->tnxtfree = sc->tactive = 0; sc->tbsyf = sc->tbsyl = NULL; WRITE_CSR(sc, WXREG_TCTL, 0); DELAY(5 * 1000); 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_TCTL, (WXTCTL_CT(WX_COLLISION_THRESHOLD) | WXTCTL_COLD(WX_FDX_COLLISION_DX) | WXTCTL_EN)); /* * Set up receive parameters and enable the receiver. */ sc->rnxt = 0; WRITE_CSR(sc, WXREG_RCTL, 0); DELAY(5 * 1000); 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); + /* + * The delay should yield ~10us receive interrupt delay + */ + WRITE_CSR(sc, WXREG_RDTR0_LIVENGOOD, WXRDTR_FPD | 0x40); 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); WRITE_CSR(sc, WXREG_RDLEN1, 0); WRITE_CSR(sc, WXREG_RDH1, 0); WRITE_CSR(sc, WXREG_RDT1, 0); if (ifp->if_mtu > ETHERMTU) { bflags = WXRCTL_EN | WXRCTL_LPE | WXRCTL_2KRBUF; } else { bflags = WXRCTL_EN | WXRCTL_2KRBUF; } WRITE_CSR(sc, WXREG_RCTL, bflags | ((ifp->if_flags & IFF_BROADCAST) ? WXRCTL_BAM : 0) | ((ifp->if_flags & IFF_PROMISC) ? WXRCTL_UPE : 0) | ((sc->all_mcasts) ? WXRCTL_MPE : 0)); /* * Enable Interrupts */ WX_ENABLE_INT(sc); - /* - * Mark that we're up and running... - */ - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; - if (sc->wx_mii) { - mii_mediachg(sc->wx_mii); + mii_mediachg(WX_MII_FROM_SOFTC(sc)); } 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); + /* + * Mark that we're up and running... + */ + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + /* * Start stats updater. */ TIMEOUT(sc, wx_watchdog, sc, hz); + WX_UNLOCK(sc); /* * And we're outta here... */ return (0); } /* * Get a receive buffer for our use (and dma map the data area). * - * This chip can have buffers be 256, 512, 1024 or 2048 bytes in size. + * The Wiseman chip can have buffers be 256, 512, 1024 or 2048 bytes in size. + * The LIVENGOOD chip can go higher (up to 16K), but what's the point as + * we aren't doing non-MCLGET memory management. + * * It wants them aligned on 256 byte boundaries, but can actually cope * with an offset in the first 255 bytes of the head of a receive frame. * * We'll allocate a MCLBYTE sized cluster but *not* adjust the data pointer * by any alignment value. Instead, we'll tell the chip to offset by any * alignment and we'll catch the alignment on the backend at interrupt time. */ static void 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(wx_softc_t *sc, rxpkt_t *rxpkt) { struct mbuf *mb; MGETHDR(mb, M_DONTWAIT, MT_DATA); if (mb == NULL) { rxpkt->dptr = NULL; return (-1); } MCLGET(mb, M_DONTWAIT); if ((mb->m_flags & M_EXT) == 0) { m_freem(mb); rxpkt->dptr = NULL; return (-1); } wx_rxdma_map(sc, rxpkt, mb); return (0); } static int 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; int error = 0; WX_LOCK(sc); switch (command) { case SIOCSIFADDR: -#if !defined(__NetBSD__) && !defined(__OpenBSD__) case SIOCGIFADDR: -#endif error = ether_ioctl(ifp, command, data); break; - -#ifdef SIOCSIFMTU case SIOCSIFMTU: if (ifr->ifr_mtu > WX_MAXMTU || ifr->ifr_mtu < ETHERMIN) { error = EINVAL; } else if (ifp->if_mtu != ifr->ifr_mtu) { ifp->if_mtu = ifr->ifr_mtu; error = wx_init(sc); } break; -#endif - case SIOCSIFFLAGS: sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; /* * If interface is marked up and not running, then start it. * If it is marked down and running, stop it. * If it's up then re-initialize it. This is so flags * such as IFF_PROMISC are handled. */ if (ifp->if_flags & IFF_UP) { error = wx_init(sc); } else { if (ifp->if_flags & IFF_RUNNING) { wx_stop(sc); } } break; -#ifdef SIOCADDMULTI case SIOCADDMULTI: case SIOCDELMULTI: -#if defined(__NetBSD__) - { - int all_mc_change = (sc->all_mcasts == - ((ifp->if_flags & IFF_ALLMULTI) ? 1 : 0)); - error = (command == SIOCADDMULTI) ? - ether_addmulti(ifr, &sc->w.ethercom) : - ether_delmulti(ifr, &sc->w.ethercom); - if (error != ENETRESET && all_mc_change == 0) { - break; - } - } -#endif sc->all_mcasts = (ifp->if_flags & IFF_ALLMULTI) ? 1 : 0; error = wx_mc_setup(sc); break; -#endif -#ifdef SIOCGIFMEDIA case SIOCGIFMEDIA: case SIOCSIFMEDIA: DPRINTF(sc, ("%s: ioctl SIOC[GS]IFMEDIA: command=%#lx\n", sc->wx_name, command)); if (sc->wx_mii) { + mii_data_t *mii = WX_MII_FROM_SOFTC(sc); error = ifmedia_ioctl(ifp, ifr, - &sc->wx_mii->mii_media, command); + &mii->mii_media, command); } else { error = ifmedia_ioctl(ifp, ifr, &sc->wx_media, command); } break; -#endif default: error = EINVAL; } WX_UNLOCK(sc); return (error); } static int wx_ifmedia_upd(struct ifnet *ifp) { struct wx_softc *sc = SOFTC_IFP(ifp); struct ifmedia *ifm; DPRINTF(sc, ("%s: ifmedia_upd\n", sc->wx_name)); if (sc->wx_mii) { - mii_mediachg(sc->wx_mii); + mii_mediachg(WX_MII_FROM_SOFTC(sc)); return 0; } ifm = &sc->wx_media; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) { return (EINVAL); } return (0); } static void 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; + mii_data_t *mii = WX_MII_FROM_SOFTC(sc); + mii_pollstat(mii); + ifmr->ifm_active = mii->mii_media_active; + ifmr->ifm_status = 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; if (sc->linkup == 0) return; ifmr->ifm_status |= IFM_ACTIVE; dsr = READ_CSR(sc, WXREG_DSR); if (IS_LIVENGOOD(sc)) { if (dsr & WXDSR_1000BT) { 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 { ifmr->ifm_status |= IFM_10_T; /* ?? */ } } else { ifmr->ifm_status |= IFM_1000_SX; } if (dsr & WXDSR_FD) { 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; + mii_data_t *mii = WX_MII_FROM_SOFTC(sc); 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) { } Index: stable/4/sys/pci/if_wxreg.h =================================================================== --- stable/4/sys/pci/if_wxreg.h (revision 84384) +++ stable/4/sys/pci/if_wxreg.h (revision 84385) @@ -1,465 +1,465 @@ /* $FreeBSD$ */ /* * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * 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. */ #define WX_VENDOR_INTEL 0x8086 #define WX_PRODUCT_82452 0x1000 #define WX_PRODUCT_LIVENGOOD 0x1001 #define WX_PRODUCT_82452_SC 0x1003 #define WX_PRODUCT_82543 0x1004 #define WX_MMBA 0x10 #define MWI 0x10 /* Memory Write Invalidate */ #define WX_CACHELINE_SIZE 0x20 /* Join PCI ID and revision into one value */ #define WX_WISEMAN_0 0x10000000 #define WX_WISEMAN_2_0 0x10000002 #define WX_WISEMAN_2_1 0x10000003 #define WX_LIVENGOOD 0x10010000 #define WX_LIVENGOOD_CU 0x10040002 #define IS_WISEMAN(sc) ((sc)->wx_idnrev < WX_LIVENGOOD) #define IS_LIVENGOOD(sc) ((sc)->wx_idnrev >= WX_LIVENGOOD) #define IS_LIVENGOOD_CU(sc) ((sc)->wx_idnrev == WX_LIVENGOOD_CU) /* * Information about this chipset gathered from a released Intel Linux driver, * which was clearly a port of an NT driver. */ /* * Various Descriptor Structures. * These are all in little endian format (for now). */ typedef struct { u_int32_t lowpart; u_int32_t highpart; } wxpa_t, wxrp_t; /* * Receive Descriptor. * The base address of a receive descriptor ring must be on a 4KB boundary, * and they must be allocated in multiples of 8. */ typedef struct { wxpa_t address; /* physical address of buffer */ u_int16_t length; u_int16_t csum; u_int8_t status; u_int8_t errors; u_int16_t special; } wxrd_t; #define RDSTAT_DD 0x1 /* descriptor done */ #define RDSTAT_EOP 0x2 /* end of packet */ #define RDSTAT_RSVD 0x74 /* reserved bits */ #define RDERR_CRC 0x1 /* CRC Error */ #define RDERR_SE 0x2 /* Symbol Error */ #define RDERR_SEQ 0x4 /* Sequence Error */ /* * Transmit Descriptor * The base address of a transmit descriptor ring must be on a 4KB boundary, * and they must be allocated in multiples of 8. */ typedef struct { wxpa_t address; u_int16_t length; u_int8_t cso; /* checksum offset */ u_int8_t cmd; /* cmd */ u_int8_t status; /* status */ u_int8_t css; /* checksum start */ u_int16_t special; } wxtd_t; #define TXCMD_EOP 0x1 /* last packet */ #define TXCMD_IFCS 0x2 /* insert FCS */ #define TXCMD_IC 0x4 /* insert checksum */ #define TXCMD_RS 0x8 /* report status */ #define TXCMD_RPS 0x10 /* report packet sent */ #define TXCMD_SM 0x20 /* symbol mode */ #define TXCMD_IDE 0x80 /* interrupt delay enable */ #define TXSTS_DD 0x1 /* descriptor done */ #define TXSTS_EC 0x2 /* excess collisions */ #define TXSTS_LC 0x4 /* late collision */ /* * This device can only be accessed via memory space. */ /* * Register access via offsets. * * Our brilliant friends at Intel decided to move registers offsets * around from chip version to chip version. It's amazing that some * deity doesn't zap these suckers. Really. */ #define WXREG_DCR 0x00000000 #define WXREG_DSR 0x00000008 #define WXREG_EECDR 0x00000010 #define WXREG_EXCT 0x00000018 #define WXREG_MDIC 0x00000020 #define WXREG_FCAL 0x00000028 #define WXREG_FCAH 0x0000002C #define WXREG_FCT 0x00000030 #define WXREG_VET 0x00000038 #define WXREG_RAL_BASE 0x00000040 #define WXREG_RAL_LO(x) (WXREG_RAL_BASE + ((x) << 3)) #define WXREG_RAL_HI(x) (WXREG_RAL_LO(x) + 4) #define WXREG_ICR 0x000000c0 #define WXREG_ICS 0x000000c8 #define WXREG_IMASK 0x000000d0 #define WXREG_IMCLR 0x000000d8 #define WXREG_RCTL 0x00000100 #define WXREG_RDTR0 0x00000108 #define WXREG_RDTR0_LIVENGOOD 0x00002820 #define WXREG_RDBA0_LO 0x00000110 #define WXREG_RDBA0_LO_LIVENGOOD 0x00002800 #define WXREG_RDBA0_HI 0x00000114 #define WXREG_RDBA0_HI_LIVENGOOD 0x00002804 #define WXREG_RDLEN0 0x00000118 #define WXREG_RDLEN0_LIVENGOOD 0x00002808 #define WXREG_RDH0 0x00000120 #define WXREG_RDH0_LIVENGOOD 0x00002810 #define WXREG_RDT0 0x00000128 #define WXREG_RDT0_LIVENGOOD 0x00002818 #define WXREG_RDTR1 0x00000130 #define WXREG_RDBA1_LO 0x00000138 #define WXREG_RDBA1_HI 0x0000013C #define WXREG_RDLEN1 0x00000140 #define WXREG_RDH1 0x00000148 #define WXREG_RDT1 0x00000150 #define WXREG_FLOW_RCV_HI 0x00000160 #define WXREG_FLOW_RCV_HI_LIVENGOOD 0x00002168 #define WXREG_FLOW_RCV_LO 0x00000168 #define WXREG_FLOW_RCV_LO_LIVENGOOD 0x00002160 #define WXREG_FLOW_XTIMER 0x00000170 #define WXREG_XMIT_CFGW 0x00000178 #define WXREG_RECV_CFGW 0x00000180 #define WXREG_MTA 0x00000200 #define WXREG_TCTL 0x00000400 #define WXREG_TQSA_LO 0x00000408 #define WXREG_TQSA_HI 0x0000040C #define WXREG_TIPG 0x00000410 #define WXREG_TQC 0x00000418 #define WXREG_TDBA_LO 0x00000420 #define WXREG_TDBA_LO_LIVENGOOD 0x00003800 #define WXREG_TDBA_HI 0x00000424 #define WXREG_TDBA_HI_LIVENGOOD 0x00003804 #define WXREG_TDLEN 0x00000428 #define WXREG_TDLEN_LIVENGOOD 0x00003808 #define WXREG_TDH 0x00000430 #define WXREG_TDH_LIVENGOOD 0x00003810 #define WXREG_TDT 0x00000438 #define WXREG_TDT_LIVENGOOD 0x00003818 #define WXREG_TIDV 0x00000440 #define WXREG_TIDV_LIVENGOOD 0x00003820 #define WXREG_VFTA 0x00000600 #define WX_RAL_TAB_SIZE 16 #define WX_RAL_AV 0x80000000 #define WX_MC_TAB_SIZE 128 #define WX_VLAN_TAB_SIZE 128 /* * Device Control Register Defines */ #define WXDCR_FD 0x1 /* full duplex */ #define WXDCR_BEM 0x2 /* big endian mode */ #define WXDCR_FAIR 0x4 /* 1->Fairness, 0->Receive Priority */ #define WXDCR_LRST 0x8 /* Link Reset */ #define WXDCR_ASDE 0x20 /* ??? */ #define WXDCR_SLE 0x20 /* ??? */ #define WXDCR_SLU 0x40 /* Set Link Up */ #define WXDCR_ILOS 0x80 /* Invert Loss-of-Signal */ #define WXDCR_10BT 0x000 /* set 10BaseT */ #define WXDCR_100BT 0x100 /* LIVENGOOD: Set 100BaseT */ #define WXDCR_1000BT 0x200 /* LIVENGOOD: Set 1000BaseT */ #define WXDCR_SPEED_MASK 0x300 #define WXDCR_BEM32 0x400 /* LIVENGOOD: Set Big Endian 32 (?) */ #define WXDCR_FRCSPD 0x800 /* LIVENGOOD: Force Speed (?) */ #define WXDCR_FRCDPX 0x1000 /* LIVENGOOD: Force Full Duplex */ /* * General purpose I/O pins * * Pin 0 is for the LED. * * Pin 1 is to detect loss of signal (LOS)- if it is set, we've lost signal. */ #define WXDCR_SWDPINS_SHIFT 18 #define WXDCR_SWDPINS_MASK 0xf #define WXDCR_SWDPIN0 (1 << 18) /* 0x00040000 - PHY reset */ #define WXDCR_SWDPIN1 (1 << 19) /* 0x00080000 */ #define WXDCR_SWDPIN2 (1 << 20) /* 0x00100000 - PHY data */ #define WXDCR_SWDPIN3 (1 << 21) /* 0x00200000 - PHY clk */ #define WXDCR_SWDPIO_SHIFT 22 #define WXDCR_SWDPIO_MASK 0xf #define WXDCR_SWDPIO0 (1 << 22) /* 0x00400000 - PHY rst dir */ #define WXDCR_SWDPIO1 (1 << 23) /* 0x00800000 */ #define WXDCR_SWDPIO2 (1 << 24) /* 0x01000000 - PHY data dir */ #define WXDCR_SWDPIO3 (1 << 25) /* 0x02000000 - PHY clk dir */ #define WXDCR_RST 0x04000000 /* Device Reset (self clearing) */ #define WXDCR_RFCE 0x08000000 /* Receive Flow Control Enable */ #define WXDCR_TFCE 0x10000000 /* Transmit Flow Control Enable */ #define WXDCR_RTE 0x20000000 /* Routing Tag Enable */ #define WXDCR_VME 0x40000000 /* VLAN Mode Enable */ /* * Device Status Register Defines */ #define WXDSR_FD 0x1 /* full duplex */ #define WXDSR_LU 0x2 /* link up */ #define WXDSR_TXCLK 0x4 /* transmit clock running */ #define WXDSR_RBCLK 0x8 /* receive clock running */ #define WXDSR_TXOFF 0x10 /* transmit paused */ #define WXDSR_TBIMODE 0x20 /* LIVENGOOD: Fibre Mode */ #define WXDSR_100BT 0x40 /* LIVENGOOD: 100BaseT */ #define WXDSR_1000BT 0x80 /* LIVENGOOD: 1000BaseT */ #define WXDSR_ASDV 0x300 /* LIVENGOOD: ?? */ #define WXDSR_MTXCKOK 0x400 /* LIVENGOOD: ?? */ #define WXDSR_PCI66 0x800 /* LIVENGOOD: 66 MHz bus */ #define WXDSR_BUS64 0x1000 /* LIVENGOOD: In 64 bit slot */ /* * EEPROM Register Defines */ #define WXEECD_SK 0x1 /* enable clock */ #define WXEECD_CS 0x2 /* chip select */ #define WXEECD_DI 0x4 /* data input */ #define WXEECD_DO 0x8 /* data output */ #define EEPROM_READ_OPCODE 0x6 /* * Constant Flow Control Frame MAC Address and Type values. */ #define FC_FRM_CONST_LO 0x00C28001 #define FC_FRM_CONST_HI 0x0100 #define FC_TYP_CONST 0x8808 /* * Bits pertinent for the Receive Address register pairs. The low address * is the low 32 bits of a 48 bit MAC address. The high address contains * bits 32-47 of the 48 bit MAC address. The top bit in the high address * is a 'valid' bit. */ #define WXRAH_RDR1 0x40000000 /* second receive descriptor ring */ #define WXRAH_VALID 0x80000000 /* * Interrupt Cause Bits */ #define WXISR_TXDW 0x1 /* transmit descriptor written back */ #define WXISR_TXQE 0x2 /* transmit queue empty */ #define WXISR_LSC 0x4 /* link status change */ #define WXISR_RXSEQ 0x8 /* receive sequence error */ #define WXISR_RXDMT0 0x10 /* receiver ring 0 getting empty */ #define WXISR_RXDMT1 0x20 /* receiver ring 1 getting empty */ #define WXISR_RXO 0x40 /* receiver overrun */ #define WXISR_RXT0 0x80 /* ring 0 receiver timer interrupt */ #define WXISR_RXT1 0x100 /* ring 1 receiver timer interrupt */ #define WXISR_PCIE 0x200 /* ?? Probably PCI interface error... */ #define WXISR_MDIAC 0x200 #define WXISR_RXCFG 0x400 #define WXISR_GPI_EN0 0x800 #define WXISR_GPI_EN1 0x1000 /* appears to be PHY intr line */ #define WXISR_GPI_EN2 0x2000 #define WXISR_GPI_EN3 0x4000 #define WXIENABLE_DEFAULT \ - (WXISR_RXO | WXISR_RXT0 | WXISR_RXDMT0 | WXISR_RXSEQ | \ + (WXISR_RXO | WXISR_RXT0 | WXISR_RXDMT0 | WXISR_RXSEQ | WXISR_TXQE |\ WXISR_LSC | WXISR_PCIE | WXISR_GPI_EN1) #define WXDISABLE 0xffffffff /* * Receive Control Register bits. */ #define WXRCTL_RST 0x1 /* receiver reset */ #define WXRCTL_EN 0x2 /* receiver enable */ #define WXRCTL_SBP 0x4 /* store bad packets */ #define WXRCTL_UPE 0x8 /* unicast promiscuos mode */ #define WXRCTL_MPE 0x10 /* multicast promiscuous mode */ #define WXRCTL_LPE 0x20 /* large packet enable */ #define WXRCTL_BAM 0x8000 /* broadcast accept mode */ #define WXRCTL_BSEX 0x2000000 /* LIVENGOOD: Buffer Size Extension */ #define WXRCTL_2KRBUF (0 << 16) /* 2KB Receive Buffers */ #define WXRCTL_1KRBUF (1 << 16) /* 1KB Receive Buffers */ #define WXRCTL_512BRBUF (2 << 16) /* 512 Byte Receive Buffers */ #define WXRCTL_256BRBUF (3 << 16) /* 256 Byte Receive Buffers */ #define WXRCTL_4KRBUF (3 << 16) /* LIVENGOOD: 4KB Receive Buffers */ #define WXRCTL_8KRBUF (2 << 16) /* LIVENGOOD: 8KB Receive Buffers */ #define WXRCTL_16KRBUF (1 << 16) /* LIVENGOOD: 16KB Receive Buffers */ /* * Receive Delay Timer Register bits. */ #define WXRDTR_FPD 0x80000000 /* flush partial descriptor */ /* * Transmit Configuration Word defines */ #define WXTXCW_FD 0x00000020 /* Full Duplex */ #define WXTXCW_PMASK 0x00000180 /* pause mask */ #define WXTXCW_ANE 0x80000000 /* AutoNegotiate */ #define WXTXCW_DEFAULT 0x800001A0 /* * Transmit Control Register defines. */ #define WXTCTL_RST 0x1 /* transmitter reset */ #define WXTCTL_EN 0x2 /* transmitter enable */ #define WXTCTL_PSP 0x8 /* pad short packets */ #define WXTCTL_CT(x) (((x) & 0xff) << 4) /* 4:11 - Collision Threshold */ #define WXTCTL_COLD(x) (((x) & 0x3ff) << 12) /* 12:21 - Collision Distance */ #define WXTCTL_SWXOFF (1 << 22) /* Software XOFF */ #define WX_COLLISION_THRESHOLD 15 #define WX_FDX_COLLISION_DX 64 #define WX_HDX_COLLISION_DX 512 /* * MDI control register bits - (best-guess) */ #define WXMDIC_WRITE 0x04000000 #define WXMDIC_READ 0x08000000 #define WXMDIC_READY 0x10000000 #define WXMDIC_INTR 0x20000000 #define WXMDIC_ERR 0x40000000 #define WXMDIC_REGADDR_MASK 0x001F0000 #define WXMDIC_REGADDR_SHIFT 16 #define WXMDIC_PHYADDR_MASK 0x03E00000 #define WXMDIC_PHYADDR_SHIFT 21 #define WXMDIC_DATA_MASK 0x0000FFFF /* * EXCT control register bits */ #define WXEXCT_GPI_EN0 0x00000001 #define WXEXCT_GPI_EN1 0x00000002 #define WXEXCT_GPI_EN2 0x00000004 #define WXEXCT_GPI_EN3 0x00000008 #define WXEXCT_SWDPIN4 0x00000010 #define WXEXCT_SWDPIN5 0x00000020 #define WXEXCT_SWDPIN6 0x00000040 #define WXEXCT_SWDPIN7 0x00000080 #define WXEXCT_SWDPIO4 0x00000100 #define WXEXCT_SWDPIO5 0x00000200 #define WXEXCT_SWDPIO6 0x00000400 #define WXEXCT_SWDPIO7 0x00000800 #define WXEXCT_ASDCHK 0x00001000 #define WXEXCT_EE_RST 0x00002000 #define WXEXCT_IPS 0x00004000 #define WXEXCT_SPD_BYPS 0x00008000 /* * PHY access using GPIO pins */ #define WXPHY_RESET_DIR WXDCR_SWDPIO0 #define WXPHY_RESET WXDCR_SWDPIN0 #define WXPHY_MDIO_DIR WXDCR_SWDPIO2 #define WXPHY_MDIO WXDCR_SWDPIN2 #define WXPHY_MDC_DIR WXDCR_SWDPIO3 #define WXPHY_MDC WXDCR_SWDPIN3 #define WXPHY_RESET_DIR4 WXEXCT_SWDPIO4 #define WXPHY_RESET4 WXEXCT_SWDPIN4 /* * PHY commands */ #define WXPHYC_PREAMBLE 0xFFFFFFFF #define WXPHYC_PREAMBLE_LEN 32 #define WXPHYC_SOF 0x01 #define WXPHYC_READ 0x02 #define WXPHYC_WRITE 0x01 #define WXPHYC_TURNAROUND 0x02 /* * Receive Configuration Word defines */ #define WXRXCW_CWMASK 0x0000ffff #define WXRXCW_NC 0x04000000 #define WXRXCW_IV 0x08000000 #define WXRXCW_CC 0x10000000 #define WXRXCW_C 0x20000000 #define WXRXCW_SYNCH 0x40000000 #define WXRXCW_ANC 0x80000000 /* * Miscellaneous */ #define WX_EEPROM_MAC_OFF 0 /* * Offset for Initialization Control Word #1 */ #define WX_EEPROM_CTLR1_OFF 0xA #define WX_EEPROM_CTLR1_FD (1 << 10) #define WX_EEPROM_CTLR1_SWDPIO_SHIFT 5 #define WX_EEPROM_CTLR1_ILOS (1 << 4) #define WX_EEPROM_CTLR2_OFF 0xF #define WX_EEPROM_CTLR2_SWDPIO 0xF0 #define WX_EEPROM_EXT_SHIFT 4 #define WX_XTIMER_DFLT 0x100 #define WX_RCV_FLOW_HI_DFLT 0x8000 #define WX_RCV_FLOW_LO_DFLT 0x4000 #define WX_WISEMAN_TIPG_DFLT (10 | (2 << 10) | (10 << 20)) #define WX_LIVENGOOD_TIPG_DFLT (6 | (8 << 10) | (6 << 20)) #define WX_LIVENGOOD_CU_TIPG_DFLT (8 | (8 << 10) | (6 << 20)) #define WX_CRC_LENGTH 4 /* * Hardware cannot transmit less than 16 bytes. It also cannot * successfully receive less than 60 bytes. */ #define WX_MIN_XPKT_SIZE 16 #define WX_MIN_RPKT_SIZE 60 #define WX_MAX_PKT_SIZE 1514 #define WX_MAX_PKT_SIZE_JUMBO 9014 Index: stable/4/sys/pci/if_wxvar.h =================================================================== --- stable/4/sys/pci/if_wxvar.h (revision 84384) +++ stable/4/sys/pci/if_wxvar.h (revision 84385) @@ -1,468 +1,277 @@ /* $FreeBSD$ */ /* * 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 * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * 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. */ /* * Softc definitions for the Intel Gigabit Ethernet driver. * * Guidance and inspiration from David Greenman's * if_fxp driver gratefully acknowledged here. */ /* * Platform specific defines and inline functions go here. * Look further below for more generic structures. */ -#if defined(__NetBSD__) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(SIOCSIFMEDIA) -#include -#endif -#include -#include -#include -#include - -#include "bpfilter.h" -#if NBPFILTER > 0 -#include -#include -#endif - -#ifdef INET -#include -#include -#include -#include -#endif -#ifdef NS -#include -#include -#endif -#include -#include -#include -#include -#if defined(INET) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -struct wxmdvar { - struct device dev; /* generic device structures */ - void * ih; /* interrupt handler cookie */ - struct ethercom ethercom; /* ethernet common part */ - pci_chipset_tag_t pci_pc; - pcitag_t pci_tag; - u_int8_t enaddr[6]; /* our mac address */ - u_int32_t cmdw; - bus_space_tag_t st; /* bus space tag */ - bus_space_handle_t sh; /* bus space handle */ - struct ifmedia ifm; - struct wx_softc * next; - int spl; -}; -#define wx_dev w.dev -#define wx_enaddr w.enaddr -#define wx_cmdw w.cmdw -#define wx_media w.ifm -#define wx_next w.next - -#define wx_if w.ethercom.ec_if -#define wx_name w.dev.dv_xname - -#define IOCTL_CMD_TYPE u_long -#define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT) -#define WXFREE(ptr) free(ptr, M_DEVBUF) -#define SOFTC_IFP(ifp) ifp->if_softc -#define WX_BPFTAP_ARG(ifp) (ifp)->if_bpf -#define TIMEOUT(sc, func, arg, time) timeout(func, arg, time) -#define VTIMEOUT(sc, func, arg, time) timeout(func, arg, time) -#define UNTIMEOUT(f, arg, sc) untimeout(f, arg) -#define INLINE inline -#define WX_LOCK(_sc) _sc->w.spl = splimp() -#define WX_UNLOCK(_sc) splx(_sc->w.spl) -#define WX_ILOCK(_sc) -#define WX_IUNLK(_sc) -#define WX_SOFTC_FROM_MII_ARG(x) (wx_softc_t *) x - -#define vm_offset_t vaddr_t -#ifndef IFM_1000_SX -#define IFM_1000_SX IFM_1000_FX -#endif -#define READ_CSR _read_csr -#define WRITE_CSR _write_csr - -#elif defined(__FreeBSD__) /* * Enable for FreeBSD 5.0 SMP code */ /* #define SMPNG 1 */ #include #include #include #include #include #include #include #include #include #include #ifdef NS #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NBPFILTER 1 +MODULE_DEPEND(wx, miibus, 1, 1, 1); #include "miibus_if.h" #include "opt_bdg.h" #ifdef BRIDGE #include #include #endif struct wxmdvar { - struct device * dev; /* backpointer to device */ + /* + * arpcom must be first + */ struct arpcom arpcom; /* per-interface network data */ + struct device * dev; /* backpointer to device */ struct resource * mem; /* resource descriptor for registers */ struct resource * irq; /* resource descriptor for interrupt */ void * ih; /* interrupt handler cookie */ u_int16_t cmdw; struct callout_handle sch; /* handle for timeouts */ char name[8]; bus_space_tag_t st; /* bus space tag */ bus_space_handle_t sh; /* bus space handle */ struct ifmedia ifm; device_t miibus; struct wx_softc * next; #ifdef SMPNG struct mtx wxmtx; #else int spl; #endif }; #define wx_dev w.dev #define wx_enaddr w.arpcom.ac_enaddr #define wx_cmdw w.cmdw #define wx_media w.ifm #define wx_next w.next #define wx_if w.arpcom.ac_if #define wx_name w.name #define wx_mtx w.wxmtx #define IOCTL_CMD_TYPE u_long #define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT) #define WXFREE(ptr) free(ptr, M_DEVBUF) #define SOFTC_IFP(ifp) ifp->if_softc #define WX_BPFTAP_ARG(ifp) ifp #define VTIMEOUT(sc, func, arg, time) (void) timeout(func, arg, time) #define TIMEOUT(sc, func, arg, time) (sc)->w.sch = timeout(func, arg, time) #define UNTIMEOUT(f, arg, sc) untimeout(f, arg, (sc)->w.sch) #define INLINE __inline #ifdef SMPNG -#define WX_LOCK(_sc) mtx_enter(&(_sc)->wx_mtx, MTX_DEF) -#define WX_UNLOCK(_sc) mtx_exit(&(_sc)->wx_mtx, MTX_DEF) -#define WX_ILOCK(_sc) mtx_enter(&(_sc)->wx_mtx, MTX_DEF) -#define WX_IUNLK(_sc) mtx_exit(&(_sc)->wx_mtx, MTX_DEF) +#define WX_LOCK(_sc) mtx_lock(&(_sc)->wx_mtx) +#define WX_UNLOCK(_sc) mtx_unlock(&(_sc)->wx_mtx) +#define WX_ILOCK(_sc) mtx_lock(&(_sc)->wx_mtx) +#define WX_IUNLK(_sc) mtx_unlock(&(_sc)->wx_mtx) #else #define WX_LOCK(_sc) _sc->w.spl = splimp() #define WX_UNLOCK(_sc) splx(_sc->w.spl) #define WX_ILOCK(_sc) #define WX_IUNLK(_sc) #endif #define WX_SOFTC_FROM_MII_ARG(x) device_get_softc(x) +#define WX_MII_FROM_SOFTC(x) device_get_softc((x)->w.miibus) #define READ_CSR(sc, reg) \ bus_space_read_4((sc)->w.st, (sc)->w.sh, (reg)) #define WRITE_CSR(sc, reg, val) \ bus_space_write_4((sc)->w.st, (sc)->w.sh, (reg), (val)) -#elif defined(__OpenBSD__) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef INET -#include -#include -#include -#include -#include -#endif -#ifdef NS -#include -#include -#endif - -#include "bpfilter.h" -#if NBPFILTER > 0 -#include -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct wxmdvar { - struct device dev; /* generic device structures */ - void * ih; /* interrupt handler cookie */ - struct arpcom arpcom; /* ethernet common part */ - pci_chipset_tag_t pci_pc; - pcitag_t pci_tag; - u_int32_t cmdw; - bus_space_tag_t st; /* bus space tag */ - bus_space_handle_t sh; /* bus space handle */ - struct ifmedia ifm; - struct wx_softc * next; - int locked; - int spl; -}; -#define wx_dev w.dev -#define wx_enaddr w.arpcom.ac_enaddr -#define wx_cmdw w.cmdw -#define wx_media w.ifm -#define wx_next w.next - -#define wx_if w.arpcom.ac_if -#define wx_name w.dev.dv_xname - -#define IOCTL_CMD_TYPE u_long -#define WXMALLOC(len) malloc(len, M_DEVBUF, M_NOWAIT) -#define WXFREE(ptr) free(ptr, M_DEVBUF) -#define SOFTC_IFP(ifp) ifp->if_softc -#define WX_BPFTAP_ARG(ifp) (ifp)->if_bpf -#define TIMEOUT(sc, func, arg, time) timeout(func, arg, time) -#define VTIMEOUT(sc, func, arg, time) timeout(func, arg, time) -#define UNTIMEOUT(f, arg, sc) untimeout(f, arg) -#define INLINE inline -#define WX_LOCK(wx) if (wx->w.locked++ == 0) wx->w.spl = splimp() -#define WX_UNLOCK(wx) if (wx->w.locked) { \ - if (--wx->w.locked == 0) \ - splx(wx->w.spl); \ - } -#define WX_ILOCK(_sc) -#define WX_IUNLK(_sc) -#define WX_SOFTC_FROM_MII_ARG(x) (wx_softc_t *) x - -#define vm_offset_t vaddr_t -#define READ_CSR _read_csr -#define WRITE_CSR _write_csr - -#endif - - /* * Transmit soft descriptor, used to manage packets as they come in. */ typedef struct rxpkt { struct mbuf *dptr; /* pointer to receive frame */ u_int32_t dma_addr; /* dma address */ } rxpkt_t; /* * Transmit soft descriptor, used to manage packets as they are transmitted. */ typedef struct txpkt { struct txpkt *next; /* next in a chain */ struct mbuf *dptr; /* pointer to mbuf being sent */ u_int32_t sidx; /* start index */ u_int32_t eidx; /* end index */ } txpkt_t; typedef struct wx_softc { /* * OS dependent storage... must be first... */ struct wxmdvar w; /* * misc goodies */ - u_int32_t : 24, + u_int32_t : 23, + wx_mii : 1, /* non-zero if we have a PHY */ wx_no_flow : 1, wx_ilos : 1, wx_no_ilos : 1, wx_verbose : 1, wx_debug : 1, ane_failed : 1, linkup : 1, all_mcasts : 1; u_int32_t wx_idnrev; /* chip revision && PCI ID */ u_int16_t wx_cfg1; u_int16_t wx_txint_delay; u_int32_t wx_ienable; /* current ienable to use */ u_int32_t wx_dcr; /* dcr used */ u_int32_t wx_icr; /* last icr */ - mii_data_t *wx_mii; /* non-NULL if we have a PHY */ - /* * Statistics, soft && hard */ u_int32_t wx_intr; u_int32_t wx_linkintr; u_int32_t wx_rxintr; u_int32_t wx_xmitgc; u_int32_t wx_xmitpullup; u_int32_t wx_xmitcluster; u_int32_t wx_xmitputback; u_int32_t wx_xmitwanted; u_int32_t wx_xmitblocked; u_int32_t wx_xmitblocked1; u_int32_t wx_xmitrunt; u_int32_t wx_rxnobuf; /* * Soft copies of multicast addresses. We're only * using (right now) the rest of the receive address * registers- not the hashed multicast table. */ u_int8_t wx_mcaddr[WX_RAL_TAB_SIZE-1][6]; u_int8_t wx_nmca; /* # active multicast addrs */ /* * Receive Management * We have software and shared memory rings in a buddy store format. */ wxrd_t *rdescriptors; /* receive descriptor ring */ rxpkt_t *rbase; /* base of soft rdesc list */ u_int16_t rnxt; /* next descriptor to check */ u_int16_t _pad; struct mbuf *rpending; /* pending partial packet */ /* * Transmit Management * We have software and shared memory rings in a buddy store format. */ txpkt_t *tbase; /* base of soft soft management */ txpkt_t *tbsyf, *tbsyl; /* linked busy list */ wxtd_t *tdescriptors; /* transmit descriptor ring */ u_int16_t tnxtfree; /* next free index (circular) */ u_int16_t tactive; /* # active */ } wx_softc_t; /* * We offset the the receive frame header by two bytes so that the actual * payload is 32 bit aligned. On platforms that require strict structure * alignment, this means that the ethernet frame header may have to be shifted * to align it at interrupt time, but because it's such a small amount * (fourteen bytes) and processors have gotten pretty fast, that's okay. * It may even turn out on some platforms that this doesn't have to happen. */ #define WX_RX_OFFSET_VALUE 2 /* * Tunable Parameters. * * Descriptor lengths must be in multiples of 8. */ #define WX_MAX_TDESC 256 /* number of transmit descriptors */ #define T_NXT_IDX(x) ((x + 1) & (WX_MAX_TDESC - 1)) #define T_PREV_IDX(x) ((x - 1) & (WX_MAX_TDESC - 1)) -#define WX_MAX_RDESC 64 /* number of receive descriptors */ +#define WX_MAX_RDESC 256 /* number of receive descriptors */ #ifdef PADDED_CELL #define RXINCR 2 #else #define RXINCR 1 #endif #define R_NXT_IDX(x) ((x + RXINCR) & (WX_MAX_RDESC - 1)) #define R_PREV_IDX(x) ((x - RXINCR) & (WX_MAX_RDESC - 1)) /* * Link Up timeout, in milliseconds. */ #define WX_LINK_UP_TIMEOUT 500