Author: siarzhuk Date: 2011-07-08 22:06:13 +0200 (Fri, 08 Jul 2011) New Revision: 42391 Changeset: https://dev.haiku-os.org/changeset/42391 Added: haiku/vendor/freebsd/current/dev/dc/ haiku/vendor/freebsd/current/dev/dc/dcphy.c haiku/vendor/freebsd/current/dev/dc/if_dc.c haiku/vendor/freebsd/current/dev/dc/if_dcreg.h haiku/vendor/freebsd/current/dev/dc/pnphy.c haiku/vendor/freebsd/current/dev/mii/acphy.c haiku/vendor/freebsd/current/dev/mii/acphyreg.h haiku/vendor/freebsd/current/dev/mii/amphy.c haiku/vendor/freebsd/current/dev/mii/amphyreg.h haiku/vendor/freebsd/current/dev/xl/ haiku/vendor/freebsd/current/dev/xl/if_xl.c haiku/vendor/freebsd/current/dev/xl/if_xlreg.h Removed: haiku/vendor/freebsd/current/pci/if_xl.c haiku/vendor/freebsd/current/pci/if_xlreg.h Modified: haiku/vendor/freebsd/current/dev/fxp/if_fxp.c haiku/vendor/freebsd/current/dev/fxp/if_fxpreg.h haiku/vendor/freebsd/current/dev/fxp/if_fxpvar.h haiku/vendor/freebsd/current/dev/fxp/rcvbundl.h haiku/vendor/freebsd/current/dev/mii/bmtphy.c haiku/vendor/freebsd/current/dev/mii/bmtphyreg.h haiku/vendor/freebsd/current/dev/mii/exphy.c haiku/vendor/freebsd/current/dev/mii/inphy.c haiku/vendor/freebsd/current/dev/mii/inphyreg.h haiku/vendor/freebsd/current/dev/mii/rlphy.c haiku/vendor/freebsd/current/dev/mii/ukphy.c haiku/vendor/freebsd/current/dev/mii/ukphy_subr.c haiku/vendor/freebsd/current/pci/if_rl.c haiku/vendor/freebsd/current/pci/if_rlreg.h Log: * Porting DEC/21143 "dc" driver to Haiku; * Updating ipro100 ("fxp"), rtl8139 ("rl"), 3com ("xl") and related mii modules to FreeBSD RELEASE_8_2_0. Added: haiku/vendor/freebsd/current/dev/dc/dcphy.c =================================================================== --- haiku/vendor/freebsd/current/dev/dc/dcphy.c (rev 0) +++ haiku/vendor/freebsd/current/dev/dc/dcphy.c 2011-07-08 20:06:13 UTC (rev 42391) @@ -0,0 +1,421 @@ +/*- + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@xxxxxxxxxxxxxxx>. 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, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/sys/dev/dc/dcphy.c,v 1.35.2.5.2.1 2010/12/21 17:09:25 kensmith Exp $"); + +/* + * Pseudo-driver for internal NWAY support on DEC 21143 and workalike + * controllers. Technically we're abusing the miibus code to handle + * media selection and NWAY support here since there is no MII + * interface. However the logical operations are roughly the same, + * and the alternative is to create a fake MII interface in the driver, + * which is harder to do. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/lock.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include "miidevs.h" + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> + +#include <dev/pci/pcivar.h> + +#include <dev/dc/if_dcreg.h> + +#include "miibus_if.h" + +#define DC_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) | x) + +#define DC_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, \ + CSR_READ_4(sc, reg) & ~x) + +#define MIIF_AUTOTIMEOUT 0x0004 + +/* + * This is the subsystem ID for the built-in 21143 ethernet + * in several Compaq Presario systems. Apparently these are + * 10Mbps only, so we need to treat them specially. + */ +#define COMPAQ_PRESARIO_ID 0xb0bb0e11 + +static int dcphy_probe(device_t); +static int dcphy_attach(device_t); + +static device_method_t dcphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, dcphy_probe), + DEVMETHOD(device_attach, dcphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t dcphy_devclass; + +static driver_t dcphy_driver = { + "dcphy", + dcphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0); + +static int dcphy_service(struct mii_softc *, struct mii_data *, int); +static void dcphy_status(struct mii_softc *); +static void dcphy_reset(struct mii_softc *); +static int dcphy_auto(struct mii_softc *); + +static int +dcphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + + ma = device_get_ivars(dev); + + /* + * The dc driver will report the 21143 vendor and device + * ID to let us know that it wants us to attach. + */ + if (ma->mii_id1 != DC_VENDORID_DEC || + ma->mii_id2 != DC_DEVICEID_21143) + return (ENXIO); + + device_set_desc(dev, "Intel 21143 NWAY media interface"); + + return (BUS_PROBE_DEFAULT); +} + +static int +dcphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + struct dc_softc *dc_sc; + device_t brdev; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = ma->mii_data; + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + sc->mii_flags = miibus_get_flags(dev); + sc->mii_inst = mii->mii_instance++; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = dcphy_service; + sc->mii_pdata = mii; + + /* + * Apparently, we can neither isolate nor do loopback. + */ + sc->mii_flags |= MIIF_NOISOLATE | MIIF_NOLOOP; + + /*dcphy_reset(sc);*/ + dc_sc = mii->mii_ifp->if_softc; + CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0); + CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0); + + brdev = device_get_parent(sc->mii_dev); + switch (pci_get_subdevice(brdev) << 16 | pci_get_subvendor(brdev)) { + case COMPAQ_PRESARIO_ID: + /* Example of how to only allow 10Mbps modes. */ + sc->mii_capabilities = BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX; + break; + default: + if (dc_sc->dc_pmode == DC_PMODE_SIA) + sc->mii_capabilities = + BMSR_ANEG | BMSR_10TFDX | BMSR_10THDX; + else + sc->mii_capabilities = + BMSR_ANEG | BMSR_100TXFDX | BMSR_100TXHDX | + BMSR_10TFDX | BMSR_10THDX; + break; + } + + sc->mii_capabilities &= ma->mii_capmask; + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); + + MIIBUS_MEDIAINIT(sc->mii_dev); + return (0); +} + +static int +dcphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct dc_softc *dc_sc; + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + u_int32_t mode; + + dc_sc = mii->mii_ifp->if_softc; + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii->mii_media_active = IFM_NONE; + mode = CSR_READ_4(dc_sc, DC_NETCFG); + mode &= ~(DC_NETCFG_FULLDUPLEX | DC_NETCFG_PORTSEL | + DC_NETCFG_PCS | DC_NETCFG_SCRAMBLER | DC_NETCFG_SPEEDSEL); + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /*dcphy_reset(sc);*/ + (void) dcphy_auto(sc); + break; + case IFM_100_T4: + /* + * XXX Not supported as a manual setting right now. + */ + return (EINVAL); + case IFM_100_TX: + dcphy_reset(sc); + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + mode |= DC_NETCFG_PORTSEL | DC_NETCFG_PCS | + DC_NETCFG_SCRAMBLER; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mode |= DC_NETCFG_FULLDUPLEX; + else + mode &= ~DC_NETCFG_FULLDUPLEX; + CSR_WRITE_4(dc_sc, DC_NETCFG, mode); + break; + case IFM_10_T: + DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF); + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D); + else + DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F); + DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + mode &= ~DC_NETCFG_PORTSEL; + mode |= DC_NETCFG_SPEEDSEL; + if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) + mode |= DC_NETCFG_FULLDUPLEX; + else + mode &= ~DC_NETCFG_FULLDUPLEX; + CSR_WRITE_4(dc_sc, DC_NETCFG, mode); + break; + default: + return (EINVAL); + } + break; + + case MII_TICK: + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + break; + + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); + if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) + break; + + /* + * Only retry autonegotiation every 5 seconds. + * + * Otherwise, fall through to calling dcphy_status() + * since real Intel 21143 chips don't show valid link + * status until autonegotiation is switched off, and + * that only happens in dcphy_status(). Without this, + * successful autonegotiation is never recognised on + * these chips. + */ + if (++sc->mii_ticks <= 50) + break; + + sc->mii_ticks = 0; + dcphy_auto(sc); + + break; + } + + /* Update the media status. */ + dcphy_status(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +dcphy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + int reg, anlpar, tstat = 0; + struct dc_softc *dc_sc; + + dc_sc = mii->mii_ifp->if_softc; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return; + + reg = CSR_READ_4(dc_sc, DC_10BTSTAT); + if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100)) + mii->mii_media_status |= IFM_ACTIVE; + + if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) { + /* Erg, still trying, I guess... */ + tstat = CSR_READ_4(dc_sc, DC_10BTSTAT); + if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) { + if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) && + (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE) + goto skip; + mii->mii_media_active |= IFM_NONE; + return; + } + + if (tstat & DC_TSTAT_LP_CAN_NWAY) { + anlpar = tstat >> 16; + if (anlpar & ANLPAR_TX_FD && + sc->mii_capabilities & BMSR_100TXFDX) + mii->mii_media_active |= IFM_100_TX | IFM_FDX; + else if (anlpar & ANLPAR_T4 && + sc->mii_capabilities & BMSR_100T4) + mii->mii_media_active |= IFM_100_T4 | IFM_HDX; + else if (anlpar & ANLPAR_TX && + sc->mii_capabilities & BMSR_100TXHDX) + mii->mii_media_active |= IFM_100_TX | IFM_HDX; + else if (anlpar & ANLPAR_10_FD) + mii->mii_media_active |= IFM_10_T | IFM_FDX; + else if (anlpar & ANLPAR_10) + mii->mii_media_active |= IFM_10_T | IFM_HDX; + else + mii->mii_media_active |= IFM_NONE; + if (DC_IS_INTEL(dc_sc)) + DC_CLRBIT(dc_sc, DC_10BTCTRL, + DC_TCTL_AUTONEGENBL); + return; + } + + /* + * If the other side doesn't support NWAY, then the + * best we can do is determine if we have a 10Mbps or + * 100Mbps link. There's no way to know if the link + * is full or half duplex, so we default to half duplex + * and hope that the user is clever enough to manually + * change the media settings if we're wrong. + */ + if (!(reg & DC_TSTAT_LS100)) + mii->mii_media_active |= IFM_100_TX | IFM_HDX; + else if (!(reg & DC_TSTAT_LS10)) + mii->mii_media_active |= IFM_10_T | IFM_HDX; + else + mii->mii_media_active |= IFM_NONE; + if (DC_IS_INTEL(dc_sc)) + DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + return; + } + +skip: + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL) + mii->mii_media_active |= IFM_10_T; + else + mii->mii_media_active |= IFM_100_TX; + if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX) + mii->mii_media_active |= IFM_FDX; + else + mii->mii_media_active |= IFM_HDX; +} + +static int +dcphy_auto(struct mii_softc *mii) +{ + struct dc_softc *sc; + + sc = mii->mii_pdata->mii_ifp->if_softc; + + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX); + DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); + if (mii->mii_capabilities & BMSR_100TXHDX) + CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF); + else + CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF); + DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); + DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL); + DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE); + + return (EJUSTRETURN); +} + +static void +dcphy_reset(struct mii_softc *mii) +{ + struct dc_softc *sc; + + sc = mii->mii_pdata->mii_ifp->if_softc; + + DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); + DELAY(1000); + DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); +} Added: haiku/vendor/freebsd/current/dev/dc/if_dc.c =================================================================== --- haiku/vendor/freebsd/current/dev/dc/if_dc.c (rev 0) +++ haiku/vendor/freebsd/current/dev/dc/if_dc.c 2011-07-08 20:06:13 UTC (rev 42391) @@ -0,0 +1,3804 @@ +/*- + * Copyright (c) 1997, 1998, 1999 + * Bill Paul <wpaul@xxxxxxxxxxxxxxx>. 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, 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Bill Paul. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD + * 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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD: src/sys/dev/dc/if_dc.c,v 1.201.2.3.2.1 2010/12/21 17:09:25 kensmith Exp $"); + +/* + * DEC "tulip" clone ethernet driver. Supports the DEC/Intel 21143 + * series chips and several workalikes including the following: + * + * Macronix 98713/98715/98725/98727/98732 PMAC (www.macronix.com) + * Macronix/Lite-On 82c115 PNIC II (www.macronix.com) + * Lite-On 82c168/82c169 PNIC (www.litecom.com) + * ASIX Electronics AX88140A (www.asix.com.tw) + * ASIX Electronics AX88141 (www.asix.com.tw) + * ADMtek AL981 (www.admtek.com.tw) + * ADMtek AN983 (www.admtek.com.tw) + * ADMtek cardbus AN985 (www.admtek.com.tw) + * Netgear FA511 (www.netgear.com) Appears to be rebadged ADMTek cardbus AN985 + * Davicom DM9100, DM9102, DM9102A (www.davicom8.com) + * Accton EN1217 (www.accton.com) + * Xircom X3201 (www.xircom.com) + * Abocom FE2500 + * Conexant LANfinity (www.conexant.com) + * 3Com OfficeConnect 10/100B 3CSOHO100B (www.3com.com) + * + * Datasheets for the 21143 are available at developer.intel.com. + * Datasheets for the clone parts can be found at their respective sites. + * (Except for the PNIC; see www.freebsd.org/~wpaul/PNIC/pnic.ps.gz.) + * The PNIC II is essentially a Macronix 98715A chip; the only difference + * worth noting is that its multicast hash table is only 128 bits wide + * instead of 512. + * + * Written by Bill Paul <wpaul@xxxxxxxxxxxxxxx> + * Electrical Engineering Department + * Columbia University, New York City + */ +/* + * The Intel 21143 is the successor to the DEC 21140. It is basically + * the same as the 21140 but with a few new features. The 21143 supports + * three kinds of media attachments: + * + * o MII port, for 10Mbps and 100Mbps support and NWAY + * autonegotiation provided by an external PHY. + * o SYM port, for symbol mode 100Mbps support. + * o 10baseT port. + * o AUI/BNC port. + * + * The 100Mbps SYM port and 10baseT port can be used together in + * combination with the internal NWAY support to create a 10/100 + * autosensing configuration. + * + * Note that not all tulip workalikes are handled in this driver: we only + * deal with those which are relatively well behaved. The Winbond is + * handled separately due to its different register offsets and the + * special handling needed for its various bugs. The PNIC is handled + * here, but I'm not thrilled about it. + * + * All of the workalike chips use some form of MII transceiver support + * with the exception of the Macronix chips, which also have a SYM port. + * The ASIX AX88140A is also documented to have a SYM port, but all + * the cards I've seen use an MII transceiver, probably because the + * AX88140A doesn't support internal NWAY. + */ + +#ifdef HAVE_KERNEL_OPTION_HEADERS +#include "opt_device_polling.h" +#endif + +#include <sys/param.h> +#include <sys/endian.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_vlan_var.h> + +#include <net/bpf.h> + +#include <machine/bus.h> +#include <machine/resource.h> +#include <sys/bus.h> +#include <sys/rman.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#define DC_USEIOSPACE + +#include <dev/dc/if_dcreg.h> + +#ifdef __sparc64__ +#include <dev/ofw/openfirm.h> +#include <machine/ofw_machdep.h> +#endif + +MODULE_DEPEND(dc, pci, 1, 1, 1); +MODULE_DEPEND(dc, ether, 1, 1, 1); +MODULE_DEPEND(dc, miibus, 1, 1, 1); + +/* + * "device miibus" is required in kernel config. See GENERIC if you get + * errors here. + */ +#include "miibus_if.h" + +/* + * Various supported device vendors/types and their names. + */ +static const struct dc_type dc_devs[] = { + { DC_DEVID(DC_VENDORID_DEC, DC_DEVICEID_21143), 0, + "Intel 21143 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9009), 0, + "Davicom DM9009 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100), 0, + "Davicom DM9100 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102), DC_REVISION_DM9102A, + "Davicom DM9102A 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9102), 0, + "Davicom DM9102 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_AL981), 0, + "ADMtek AL981 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_AN983), 0, + "ADMtek AN983 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_AN985), 0, + "ADMtek AN985 cardBus 10/100BaseTX or clone" }, + { DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9511), 0, + "ADMtek ADM9511 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_ADM9513), 0, + "ADMtek ADM9513 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ASIX, DC_DEVICEID_AX88140A), DC_REVISION_88141, + "ASIX AX88141 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ASIX, DC_DEVICEID_AX88140A), 0, + "ASIX AX88140A 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_98713), DC_REVISION_98713A, + "Macronix 98713A 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_98713), 0, + "Macronix 98713 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_CP, DC_DEVICEID_98713_CP), DC_REVISION_98713A, + "Compex RL100-TX 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_CP, DC_DEVICEID_98713_CP), 0, + "Compex RL100-TX 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_987x5), DC_REVISION_98725, + "Macronix 98725 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_987x5), DC_REVISION_98715AEC_C, + "Macronix 98715AEC-C 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_987x5), 0, + "Macronix 98715/98715A 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_MX, DC_DEVICEID_98727), 0, + "Macronix 98727/98732 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_LO, DC_DEVICEID_82C115), 0, + "LC82C115 PNIC II 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_LO, DC_DEVICEID_82C168), DC_REVISION_82C169, + "82c169 PNIC 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_LO, DC_DEVICEID_82C168), 0, + "82c168 PNIC 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ACCTON, DC_DEVICEID_EN1217), 0, + "Accton EN1217 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ACCTON, DC_DEVICEID_EN2242), 0, + "Accton EN2242 MiniPCI 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_XIRCOM, DC_DEVICEID_X3201), 0, + "Xircom X3201 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_DLINK, DC_DEVICEID_DRP32TXD), 0, + "Neteasy DRP-32TXD Cardbus 10/100" }, + { DC_DEVID(DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500), 0, + "Abocom FE2500 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_ABOCOM, DC_DEVICEID_FE2500MX), 0, + "Abocom FE2500MX 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_CONEXANT, DC_DEVICEID_RS7112), 0, + "Conexant LANfinity MiniPCI 10/100BaseTX" }, + { DC_DEVID(DC_VENDORID_HAWKING, DC_DEVICEID_HAWKING_PN672TX), 0, + "Hawking CB102 CardBus 10/100" }, + { DC_DEVID(DC_VENDORID_PLANEX, DC_DEVICEID_FNW3602T), 0, + "PlaneX FNW-3602-T CardBus 10/100" }, + { DC_DEVID(DC_VENDORID_3COM, DC_DEVICEID_3CSOHOB), 0, + "3Com OfficeConnect 10/100B" }, + { DC_DEVID(DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN120), 0, + "Microsoft MN-120 CardBus 10/100" }, + { DC_DEVID(DC_VENDORID_MICROSOFT, DC_DEVICEID_MSMN130), 0, + "Microsoft MN-130 10/100" }, + { DC_DEVID(DC_VENDORID_LINKSYS, DC_DEVICEID_PCMPC200_AB08), 0, + "Linksys PCMPC200 CardBus 10/100" }, + { DC_DEVID(DC_VENDORID_LINKSYS, DC_DEVICEID_PCMPC200_AB09), 0, + "Linksys PCMPC200 CardBus 10/100" }, + { 0, 0, NULL } +}; + +static int dc_probe(device_t); +static int dc_attach(device_t); +static int dc_detach(device_t); +static int dc_suspend(device_t); +static int dc_resume(device_t); +static const struct dc_type *dc_devtype(device_t); +static int dc_newbuf(struct dc_softc *, int, int); +static int dc_encap(struct dc_softc *, struct mbuf **); +static void dc_pnic_rx_bug_war(struct dc_softc *, int); +static int dc_rx_resync(struct dc_softc *); +static int dc_rxeof(struct dc_softc *); +static void dc_txeof(struct dc_softc *); +static void dc_tick(void *); +static void dc_tx_underrun(struct dc_softc *); +static void dc_intr(void *); +static void dc_start(struct ifnet *); +static void dc_start_locked(struct ifnet *); +static int dc_ioctl(struct ifnet *, u_long, caddr_t); +static void dc_init(void *); +static void dc_init_locked(struct dc_softc *); +static void dc_stop(struct dc_softc *); +static void dc_watchdog(void *); +static int dc_shutdown(device_t); +static int dc_ifmedia_upd(struct ifnet *); +static void dc_ifmedia_sts(struct ifnet *, struct ifmediareq *); + +static void dc_delay(struct dc_softc *); +static void dc_eeprom_idle(struct dc_softc *); +static void dc_eeprom_putbyte(struct dc_softc *, int); +static void dc_eeprom_getword(struct dc_softc *, int, u_int16_t *); +static void dc_eeprom_getword_pnic(struct dc_softc *, int, u_int16_t *); +static void dc_eeprom_getword_xircom(struct dc_softc *, int, u_int16_t *); +static void dc_eeprom_width(struct dc_softc *); +static void dc_read_eeprom(struct dc_softc *, caddr_t, int, int, int); + +static void dc_mii_writebit(struct dc_softc *, int); +static int dc_mii_readbit(struct dc_softc *); +static void dc_mii_sync(struct dc_softc *); +static void dc_mii_send(struct dc_softc *, u_int32_t, int); +static int dc_mii_readreg(struct dc_softc *, struct dc_mii_frame *); +static int dc_mii_writereg(struct dc_softc *, struct dc_mii_frame *); +static int dc_miibus_readreg(device_t, int, int); +static int dc_miibus_writereg(device_t, int, int, int); +static void dc_miibus_statchg(device_t); +static void dc_miibus_mediainit(device_t); + +static void dc_setcfg(struct dc_softc *, int); +static uint32_t dc_mchash_le(struct dc_softc *, const uint8_t *); +static uint32_t dc_mchash_be(const uint8_t *); +static void dc_setfilt_21143(struct dc_softc *); +static void dc_setfilt_asix(struct dc_softc *); +static void dc_setfilt_admtek(struct dc_softc *); +static void dc_setfilt_xircom(struct dc_softc *); + +static void dc_setfilt(struct dc_softc *); + +static void dc_reset(struct dc_softc *); +static int dc_list_rx_init(struct dc_softc *); +static int dc_list_tx_init(struct dc_softc *); + +static void dc_read_srom(struct dc_softc *, int); +static void dc_parse_21143_srom(struct dc_softc *); +static void dc_decode_leaf_sia(struct dc_softc *, struct dc_eblock_sia *); +static void dc_decode_leaf_mii(struct dc_softc *, struct dc_eblock_mii *); +static void dc_decode_leaf_sym(struct dc_softc *, struct dc_eblock_sym *); +static void dc_apply_fixup(struct dc_softc *, int); + +#ifdef DC_USEIOSPACE +#define DC_RES SYS_RES_IOPORT +#define DC_RID DC_PCI_CFBIO +#else +#define DC_RES SYS_RES_MEMORY +#define DC_RID DC_PCI_CFBMA +#endif + +static device_method_t dc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dc_probe), + DEVMETHOD(device_attach, dc_attach), + DEVMETHOD(device_detach, dc_detach), + DEVMETHOD(device_suspend, dc_suspend), + DEVMETHOD(device_resume, dc_resume), + DEVMETHOD(device_shutdown, dc_shutdown), + + /* bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + /* MII interface */ + DEVMETHOD(miibus_readreg, dc_miibus_readreg), + DEVMETHOD(miibus_writereg, dc_miibus_writereg), + DEVMETHOD(miibus_statchg, dc_miibus_statchg), + DEVMETHOD(miibus_mediainit, dc_miibus_mediainit), + + { 0, 0 } +}; + +static driver_t dc_driver = { + "dc", + dc_methods, + sizeof(struct dc_softc) +}; + +static devclass_t dc_devclass; + +DRIVER_MODULE(dc, pci, dc_driver, dc_devclass, 0, 0); +DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0); + +#define DC_SETBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) + +#define DC_CLRBIT(sc, reg, x) \ + CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x)) + +#define SIO_SET(x) DC_SETBIT(sc, DC_SIO, (x)) +#define SIO_CLR(x) DC_CLRBIT(sc, DC_SIO, (x)) + +static void +dc_delay(struct dc_softc *sc) +{ + int idx; + + for (idx = (300 / 33) + 1; idx > 0; idx--) + CSR_READ_4(sc, DC_BUSCTL); +} + +static void +dc_eeprom_width(struct dc_softc *sc) +{ + int i; + + /* Force EEPROM to idle state. */ + dc_eeprom_idle(sc); + + /* Enter EEPROM access mode. */ + CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); + dc_delay(sc); + + for (i = 3; i--;) { + if (6 & (1 << i)) + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); + else + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + } + + for (i = 1; i <= 12; i++) { + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + if (!(CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT)) { + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + break; + } + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + } + + /* Turn off EEPROM access mode. */ + dc_eeprom_idle(sc); + + if (i < 4 || i > 12) + sc->dc_romwidth = 6; + else + sc->dc_romwidth = i; + + /* Enter EEPROM access mode. */ + CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); + dc_delay(sc); + + /* Turn off EEPROM access mode. */ + dc_eeprom_idle(sc); +} + +static void +dc_eeprom_idle(struct dc_softc *sc) +{ + int i; + + CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); + dc_delay(sc); + + for (i = 0; i < 25; i++) { + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + } + + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CS); + dc_delay(sc); + CSR_WRITE_4(sc, DC_SIO, 0x00000000); +} + +/* + * Send a read command and address to the EEPROM, check for ACK. + */ +static void +dc_eeprom_putbyte(struct dc_softc *sc, int addr) +{ + int d, i; + + d = DC_EECMD_READ >> 6; + for (i = 3; i--; ) { + if (d & (1 << i)) + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); + else + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_DATAIN); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + } + + /* + * Feed in each bit and strobe the clock. + */ + for (i = sc->dc_romwidth; i--;) { + if (addr & (1 << i)) { + SIO_SET(DC_SIO_EE_DATAIN); + } else { + SIO_CLR(DC_SIO_EE_DATAIN); + } + dc_delay(sc); + SIO_SET(DC_SIO_EE_CLK); + dc_delay(sc); + SIO_CLR(DC_SIO_EE_CLK); + dc_delay(sc); + } +} + +/* + * Read a word of data stored in the EEPROM at address 'addr.' + * The PNIC 82c168/82c169 has its own non-standard way to read + * the EEPROM. + */ +static void +dc_eeprom_getword_pnic(struct dc_softc *sc, int addr, u_int16_t *dest) +{ + int i; + u_int32_t r; + + CSR_WRITE_4(sc, DC_PN_SIOCTL, DC_PN_EEOPCODE_READ | addr); + + for (i = 0; i < DC_TIMEOUT; i++) { + DELAY(1); + r = CSR_READ_4(sc, DC_SIO); + if (!(r & DC_PN_SIOCTL_BUSY)) { + *dest = (u_int16_t)(r & 0xFFFF); + return; + } + } +} + +/* + * Read a word of data stored in the EEPROM at address 'addr.' + * The Xircom X3201 has its own non-standard way to read + * the EEPROM, too. + */ +static void +dc_eeprom_getword_xircom(struct dc_softc *sc, int addr, u_int16_t *dest) +{ + + SIO_SET(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); + + addr *= 2; + CSR_WRITE_4(sc, DC_ROM, addr | 0x160); + *dest = (u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff; + addr += 1; + CSR_WRITE_4(sc, DC_ROM, addr | 0x160); + *dest |= ((u_int16_t)CSR_READ_4(sc, DC_SIO) & 0xff) << 8; + + SIO_CLR(DC_SIO_ROMSEL | DC_SIO_ROMCTL_READ); +} + +/* + * Read a word of data stored in the EEPROM at address 'addr.' + */ +static void +dc_eeprom_getword(struct dc_softc *sc, int addr, u_int16_t *dest) +{ + int i; + u_int16_t word = 0; + + /* Force EEPROM to idle state. */ + dc_eeprom_idle(sc); + + /* Enter EEPROM access mode. */ + CSR_WRITE_4(sc, DC_SIO, DC_SIO_EESEL); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_ROMCTL_READ); + dc_delay(sc); + DC_CLRBIT(sc, DC_SIO, DC_SIO_EE_CLK); + dc_delay(sc); + DC_SETBIT(sc, DC_SIO, DC_SIO_EE_CS); + dc_delay(sc); + + /* + * Send address of word we want to read. + */ + dc_eeprom_putbyte(sc, addr); + + /* + * Start reading bits from EEPROM. + */ + for (i = 0x8000; i; i >>= 1) { + SIO_SET(DC_SIO_EE_CLK); + dc_delay(sc); + if (CSR_READ_4(sc, DC_SIO) & DC_SIO_EE_DATAOUT) + word |= i; + dc_delay(sc); + SIO_CLR(DC_SIO_EE_CLK); + dc_delay(sc); + } [... truncated: 16387 lines follow ...]