diff options
-rw-r--r-- | sys/conf/files | 1 | ||||
-rw-r--r-- | sys/dev/dc/if_dc.c | 183 | ||||
-rw-r--r-- | sys/dev/dc/if_dcreg.h | 33 | ||||
-rw-r--r-- | sys/dev/mii/tdkphy.c | 362 | ||||
-rw-r--r-- | sys/dev/mii/tdkphyreg.h | 82 | ||||
-rw-r--r-- | sys/pci/if_dc.c | 183 | ||||
-rw-r--r-- | sys/pci/if_dcreg.h | 33 |
7 files changed, 859 insertions, 18 deletions
diff --git a/sys/conf/files b/sys/conf/files index baec5aa..a88e292 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -229,6 +229,7 @@ dev/mii/nsphy.c optional miibus dev/mii/pnphy.c optional miibus dev/mii/pnaphy.c optional miibus dev/mii/rlphy.c optional miibus +dev/mii/tdkphy.c optional miibus dev/mii/tlphy.c optional miibus dev/mii/ukphy.c optional miibus dev/mii/ukphy_subr.c optional miibus diff --git a/sys/dev/dc/if_dc.c b/sys/dev/dc/if_dc.c index 6a437a4..84538e4 100644 --- a/sys/dev/dc/if_dc.c +++ b/sys/dev/dc/if_dc.c @@ -45,6 +45,7 @@ * ADMtek AN985 (www.admtek.com.tw) * Davicom DM9100, DM9102, DM9102A (www.davicom8.com) * Accton EN1217 (www.accton.com) + * Xircom X3201 (www.xircom.com) * * Datasheets for the 21143 are available at developer.intel.com. * Datasheets for the clone parts can be found at their respective sites. @@ -179,6 +180,8 @@ static struct dc_type dc_devs[] = { "82c169 PNIC 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN1217, "Accton EN1217 10/100BaseTX" }, + { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201, + "Xircom X3201 10/100BaseTX" }, { 0, 0, NULL } }; @@ -212,6 +215,8 @@ static void dc_eeprom_putbyte __P((struct dc_softc *, int)); static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *)); static void dc_eeprom_getword_pnic __P((struct dc_softc *, int, u_int16_t *)); +static void dc_eeprom_getword_xircom + __P((struct dc_softc *, int, u_int16_t *)); static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int, int, int)); @@ -232,6 +237,7 @@ static u_int32_t dc_crc_be __P((caddr_t)); static void dc_setfilt_21143 __P((struct dc_softc *)); static void dc_setfilt_asix __P((struct dc_softc *)); static void dc_setfilt_admtek __P((struct dc_softc *)); +static void dc_setfilt_xircom __P((struct dc_softc *)); static void dc_setfilt __P((struct dc_softc *)); @@ -284,6 +290,7 @@ static driver_t dc_driver = { static devclass_t dc_devclass; +DRIVER_MODULE(if_dc, cardbus, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0); @@ -402,6 +409,29 @@ static void dc_eeprom_getword_pnic(sc, addr, dest) /* * 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(sc, addr, dest) + 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); + return; +} + +/* + * Read a word of data stored in the EEPROM at address 'addr.' */ static void dc_eeprom_getword(sc, addr, dest) struct dc_softc *sc; @@ -466,6 +496,8 @@ static void dc_read_eeprom(sc, dest, off, cnt, swap) for (i = 0; i < cnt; i++) { if (DC_IS_PNIC(sc)) dc_eeprom_getword_pnic(sc, off + i, &word); + else if (DC_IS_XIRCOM(sc)) + dc_eeprom_getword_xircom(sc, off + i, &word); else dc_eeprom_getword(sc, off + i, &word); ptr = (u_int16_t *)(dest + (i * 2)); @@ -922,6 +954,15 @@ static u_int32_t dc_crc_le(sc, addr) if (sc->dc_flags & DC_64BIT_HASH) return (crc & ((1 << DC_BITS_64) - 1)); + /* Xircom's hash filtering table is different (read: weird) */ + /* Xircom uses the LEAST significant bits */ + if (DC_IS_XIRCOM(sc)) { + if ((crc & 0x180) == 0x180) + return (crc & 0x0F) + (crc & 0x70)*3 + (14 << 4); + else + return (crc & 0x1F) + ((crc>>1) & 0xF0)*3 + (12 << 4); + } + return (crc & ((1 << DC_BITS_512) - 1)); } @@ -1158,6 +1199,76 @@ void dc_setfilt_asix(sc) return; } +void dc_setfilt_xircom(sc) + struct dc_softc *sc; +{ + struct dc_desc *sframe; + u_int32_t h, *sp; + struct ifmultiaddr *ifma; + struct ifnet *ifp; + int i; + + ifp = &sc->arpcom.ac_if; + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)); + + i = sc->dc_cdata.dc_tx_prod; + DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); + sc->dc_cdata.dc_tx_cnt++; + sframe = &sc->dc_ldata->dc_tx_list[i]; + sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf; + bzero((char *)sp, DC_SFRAME_LEN); + + sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf); + sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | + DC_FILTER_HASHPERF | DC_TXCTL_FINT; + + sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf; + + /* If we want promiscuous mode, set the allframes bit. */ + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + + if (ifp->if_flags & IFF_ALLMULTI) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + else + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = dc_crc_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + sp[h >> 4] |= 1 << (h & 0xF); + } + + if (ifp->if_flags & IFF_BROADCAST) { + h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); + sp[h >> 4] |= 1 << (h & 0xF); + } + + /* Set our MAC address */ + sp[0] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0]; + sp[1] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1]; + sp[2] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2]; + + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); + ifp->if_flags |= IFF_RUNNING; + sframe->dc_status = DC_TXSTAT_OWN; + CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); + + /* + * wait some time... + */ + DELAY(1000); + + ifp->if_timer = 5; + + return; +} + static void dc_setfilt(sc) struct dc_softc *sc; { @@ -1171,7 +1282,10 @@ static void dc_setfilt(sc) if (DC_IS_ADMTEK(sc)) dc_setfilt_admtek(sc); - return; + if (DC_IS_XIRCOM(sc)) + dc_setfilt_xircom(sc); + + return; } /* @@ -1338,7 +1452,7 @@ static void dc_reset(sc) break; } - if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc)) { + if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) { DELAY(10000); DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); i = 0; @@ -1788,6 +1902,14 @@ static int dc_attach(dev) sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; break; + case DC_DEVICEID_X3201: + sc->dc_type = DC_TYPE_XIRCOM; + sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE; + /* + * We don't actually need to coalesce, but we're doing + * it to obtain a double word aligned buffer. + */ + break; default: printf("dc%d: unknown device: %x\n", sc->dc_unit, sc->dc_info->dc_did); @@ -1805,7 +1927,7 @@ static int dc_attach(dev) dc_reset(sc); /* Take 21143 out of snooze mode */ - if (DC_IS_INTEL(sc)) { + if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE); pci_write_config(dev, DC_PCI_CFDD, command, 4); @@ -1852,6 +1974,9 @@ static int dc_attach(dev) case DC_TYPE_AN985: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0); break; + case DC_TYPE_XIRCOM: + dc_read_eeprom(sc, (caddr_t)&eaddr, 3, 3, 0); + break; default: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; @@ -1883,6 +2008,7 @@ static int dc_attach(dev) ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "dc"; + /* XXX: bleah, MTU gets overwritten in ether_ifattach() */ ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = dc_ioctl; @@ -1937,6 +2063,19 @@ static int dc_attach(dev) goto fail; } + if (DC_IS_XIRCOM(sc)) { + /* + * setup General Purpose Port mode and data so the tulip + * can talk to the MII. + */ + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + } + /* * Call MI attach routine. */ @@ -2420,11 +2559,23 @@ static void dc_txeof(sc) continue; } - if (/*sc->dc_type == DC_TYPE_21143 &&*/ - sc->dc_pmode == DC_PMODE_MII && - ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| - DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST))) - txstat &= ~DC_TXSTAT_ERRSUM; + if (DC_IS_XIRCOM(sc)) { + /* + * XXX: Why does my Xircom taunt me so? + * For some reason it likes setting the CARRLOST flag + * even when the carrier is there. wtf?!? */ + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER))) + txstat &= ~DC_TXSTAT_ERRSUM; + } else { + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST))) + txstat &= ~DC_TXSTAT_ERRSUM; + } if (txstat & DC_TXSTAT_ERRSUM) { ifp->if_oerrors++; @@ -2557,7 +2708,8 @@ static void dc_intr(arg) /* Disable interrupts. */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); - while((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) { + while(((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) + && status != 0xFFFFFFFF) { CSR_WRITE_4(sc, DC_ISR, status); @@ -2883,6 +3035,19 @@ static void dc_init(xsc) DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715); } + if (DC_IS_XIRCOM(sc)) { + /* + * setup General Purpose Port mode and data so the tulip + * can talk to the MII. + */ + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + } + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES); diff --git a/sys/dev/dc/if_dcreg.h b/sys/dev/dc/if_dcreg.h index e72d8b4..f36d6b3 100644 --- a/sys/dev/dc/if_dcreg.h +++ b/sys/dev/dc/if_dcreg.h @@ -52,6 +52,7 @@ #define DC_SIARESET 0x68 /* SIA connectivity */ #define DC_10BTCTRL 0x70 /* SIA transmit and receive */ #define DC_WATCHDOG 0x78 /* SIA and general purpose port */ +#define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */ /* * There are two general 'types' of MX chips that we need to be @@ -75,6 +76,7 @@ #define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */ #define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */ #define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */ +#define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */ #define DC_IS_MACRONIX(x) \ (x->dc_type == DC_TYPE_98713 || \ @@ -92,6 +94,7 @@ #define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102) #define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII) #define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC) +#define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM) /* MII/symbol mode port types */ #define DC_PMODE_MII 0x1 @@ -349,6 +352,25 @@ #define DC_WDOG_CTLWREN 0x08000000 /* + * SIA and General Purpose Port register (X3201) + */ +#define DC_SIAGP_RXMATCH 0x40000000 +#define DC_SIAGP_INT1 0x20000000 +#define DC_SIAGP_INT0 0x10000000 +#define DC_SIAGP_WRITE_EN 0x08000000 +#define DC_SIAGP_RXMATCH_EN 0x04000000 +#define DC_SIAGP_INT1_EN 0x02000000 +#define DC_SIAGP_INT0_EN 0x01000000 +#define DC_SIAGP_LED3 0x00800000 +#define DC_SIAGP_LED2 0x00400000 +#define DC_SIAGP_LED1 0x00200000 +#define DC_SIAGP_LED0 0x00100000 +#define DC_SIAGP_MD_GP3_OUTPUT 0x00080000 +#define DC_SIAGP_MD_GP2_OUTPUT 0x00040000 +#define DC_SIAGP_MD_GP1_OUTPUT 0x00020000 +#define DC_SIAGP_MD_GP0_OUTPUT 0x00010000 + +/* * Size of a setup frame. */ #define DC_SFRAME_LEN 192 @@ -834,6 +856,17 @@ struct dc_softc { #define DC_DEVICEID_EN1217 0x1217 /* + * Xircom vendor ID + */ +#define DC_VENDORID_XIRCOM 0x115d + +/* + * Xircom device IDs. + */ +#define DC_DEVICEID_X3201 0x0003 + + +/* * PCI low memory base and low I/O base register, and * other PCI registers. */ diff --git a/sys/dev/mii/tdkphy.c b/sys/dev/mii/tdkphy.c new file mode 100644 index 0000000..e0cc5d8 --- /dev/null +++ b/sys/dev/mii/tdkphy.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2000,2001 Jonathan Chen. + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * $FreeBSD$ + */ + +/* + * Driver for the TDK 78Q2120 MII + * + * References: + * Datasheet for the 78Q2120 - http://www.tsc.tdk.com/lan/78q2120.pdf + * Most of this code stolen from ukphy.c + */ + +/* + * The TDK 78Q2120 is found on some Xircom X3201 based cardbus cards. It's just + * like any other normal phy, except it does auto negotiation in a different + * way. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/socket.h> +#include <sys/errno.h> +#include <sys/module.h> +#include <sys/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <machine/clock.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/mii/miidevs.h> + +#include <dev/mii/tdkphyreg.h> + +#include "miibus_if.h" + +#if !defined(lint) +static const char rcsid[] = + "$Id: tdkphy.c,v 1.3 2000/10/14 06:20:56 jon Exp $"; +#endif + +static int tdkphy_probe __P((device_t)); +static int tdkphy_attach __P((device_t)); +static int tdkphy_detach __P((device_t)); + +static device_method_t tdkphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, tdkphy_probe), + DEVMETHOD(device_attach, tdkphy_attach), + DEVMETHOD(device_detach, tdkphy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t tdkphy_devclass; + +static driver_t tdkphy_driver = { + "tdkphy", + tdkphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(tdkphy, miibus, tdkphy_driver, tdkphy_devclass, 0, 0); + +int tdkphy_service __P((struct mii_softc *, struct mii_data *, int)); +void tdkphy_status __P((struct mii_softc *)); + +static int +tdkphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + ma = device_get_ivars(dev); + if ((MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_TDK || + MII_MODEL(ma->mii_id2) != MII_MODEL_TDK_78Q2120)) + return (ENXIO); + + device_set_desc(dev, MII_STR_TDK_78Q2120); + return (0); +} + +static int +tdkphy_attach(device_t dev) +{ + struct mii_softc *sc; + struct mii_attach_args *ma; + struct mii_data *mii; + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + sc->mii_dev = device_get_parent(dev); + mii = device_get_softc(sc->mii_dev); + LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list); + + if (bootverbose) + device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n", + MII_OUI(ma->mii_id1, ma->mii_id2), + MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); + + sc->mii_inst = mii->mii_instance; + sc->mii_phy = ma->mii_phyno; + sc->mii_service = tdkphy_service; + sc->mii_pdata = mii; + + mii->mii_instance++; + + sc->mii_flags |= MIIF_NOISOLATE; + +#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) + + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), + BMCR_ISO); +#if 0 + ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst), + BMCR_LOOP|BMCR_S100); +#endif + + mii_phy_reset(sc); + + sc->mii_capabilities = + PHY_READ(sc, MII_BMSR) & ma->mii_capmask; + device_printf(dev, " "); + if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0) + printf("no media present"); + else + mii_add_media(mii, sc->mii_capabilities, + sc->mii_inst); + printf("\n"); +#undef ADD + + MIIBUS_MEDIAINIT(sc->mii_dev); + + return(0); +} + +static int tdkphy_detach(device_t dev) +{ + struct mii_softc *sc; + struct mii_data *mii; + + sc = device_get_softc(dev); + mii = device_get_softc(device_get_parent(dev)); + sc->mii_dev = NULL; + LIST_REMOVE(sc, mii_list); + + return(0); +} + +int +tdkphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + int reg; + + switch (cmd) { + case MII_POLLSTAT: + /* + * If we're not polling our PHY instance, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + break; + + case MII_MEDIACHG: + /* + * If the media indicates a different PHY instance, + * isolate ourselves. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) { + reg = PHY_READ(sc, MII_BMCR); + PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); + return (0); + } + + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + switch (IFM_SUBTYPE(ife->ifm_media)) { + case IFM_AUTO: + /* + * If we're already in auto mode, just return. + */ + if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) + return (0); + (void) mii_phy_auto(sc, 1); + break; + case IFM_100_T4: + /* + * Not supported on MII + */ + return (EINVAL); + default: + /* + * BMCR data is stored in the ifmedia entry. + */ + PHY_WRITE(sc, MII_ANAR, + mii_anar(ife->ifm_media)); + PHY_WRITE(sc, MII_BMCR, ife->ifm_data); + } + break; + + case MII_TICK: + /* + * If we're not currently selected, just return. + */ + if (IFM_INST(ife->ifm_media) != sc->mii_inst) + return (0); + + /* + * Only used for autonegotiation. + */ + if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) + return (0); + + /* + * Is the interface even up? + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + return (0); + + /* + * Check to see if we have link. If we do, we don't + * need to restart the autonegotiation process. Read + * the BMSR twice in case it's latched. + */ + reg = PHY_READ(sc, MII_BMSR) | + PHY_READ(sc, MII_BMSR); + if (reg & BMSR_LINK) + return (0); + + /* + * Only retry autonegotiation every 5 seconds. + */ + if (++sc->mii_ticks != 5) + return (0); + + sc->mii_ticks = 0; + mii_phy_reset(sc); + if (mii_phy_auto(sc, 0) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + tdkphy_status(sc); + if (sc->mii_pdata->mii_media_active & IFM_FDX) + PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) | BMCR_FDX); + else + PHY_WRITE(sc, MII_BMCR, PHY_READ(sc, MII_BMCR) & ~BMCR_FDX); + /* Callback if something changed. */ + if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) { + MIIBUS_STATCHG(sc->mii_dev); + sc->mii_active = mii->mii_media_active; + } + return (0); +} + +void +tdkphy_status(struct mii_softc *phy) +{ + struct mii_data *mii = phy->mii_pdata; + int bmsr, bmcr, anlpar, diag; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; + + bmsr = PHY_READ(phy, MII_BMSR) | PHY_READ(phy, MII_BMSR); + if (bmsr & BMSR_LINK) + mii->mii_media_status |= IFM_ACTIVE; + + bmcr = PHY_READ(phy, MII_BMCR); + if (bmcr & BMCR_ISO) { + mii->mii_media_active |= IFM_NONE; + mii->mii_media_status = 0; + return; + } + + if (bmcr & BMCR_LOOP) + mii->mii_media_active |= IFM_LOOP; + + if (bmcr & BMCR_AUTOEN) { + /* + * NWay autonegotiation takes the highest-order common + * bit of the ANAR and ANLPAR (i.e. best media advertised + * both by us and our link partner). + */ + if ((bmsr & BMSR_ACOMP) == 0) { + /* Erg, still trying, I guess... */ + mii->mii_media_active |= IFM_NONE; + return; + } + + anlpar = PHY_READ(phy, MII_ANAR) & PHY_READ(phy, MII_ANLPAR); + /* + * ANLPAR doesn't get set on my card, but we check it anyway, + * since it is mentioned in the 78Q2120 specs. + */ + if (anlpar & ANLPAR_T4) + mii->mii_media_active |= IFM_100_T4; + else if (anlpar & ANLPAR_TX_FD) + mii->mii_media_active |= IFM_100_TX|IFM_FDX; + else if (anlpar & ANLPAR_TX) + mii->mii_media_active |= IFM_100_TX; + 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; + else { + /* + * ANLPAR isn't set, which leaves two possibilities: + * 1) Auto negotiation failed + * 2) Auto negotiation completed, but the card forgot + * to set ANLPAR. + * So we check the MII_DIAG(18) register... + */ + diag = PHY_READ(phy, MII_DIAG); + if (diag & DIAG_NEGFAIL) /* assume 10baseT if no neg */ + mii->mii_media_active |= IFM_10_T; + else { + if (diag & DIAG_DUPLEX) + mii->mii_media_active |= IFM_FDX; + if (diag & DIAG_RATE_100) + mii->mii_media_active |= IFM_100_TX; + else + mii->mii_media_active |= IFM_10_T; + } + } + } else { + mii->mii_media_active = mii_media_from_bmcr(bmcr); + } +} diff --git a/sys/dev/mii/tdkphyreg.h b/sys/dev/mii/tdkphyreg.h new file mode 100644 index 0000000..1f10625 --- /dev/null +++ b/sys/dev/mii/tdkphyreg.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2000,2001 Jonathan Chen. + * 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, + * without modification, immediately at the beginning of the file. + * 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. + * + * $FreeBSD$ + */ + +/* + * Register definitions for TDK 78Q2120 + */ + +#ifndef _DEV_MII_TDKPHYREG_H_ +#define _DEV_MII_TDKPHYREG_H_ + +#define MII_VENDOR 16 +#define VENDOR_RXCC 0x0001 +#define VENDOR_PCSBP 0x0002 +#define VENDOR_RVSPOL 0x0010 +#define VENDOR_NOAPOL 0x0020 +#define VENDOR_GPIO0DIR 0x0040 +#define VENDOR_GPIO0DAT 0x0080 +#define VENDOR_GPIO1DIR 0x0100 +#define VENDOR_GPIO1DAT 0x0200 +#define VENDOR_10BTLOOP 0x0400 +#define VENDOR_NOSQE 0x0800 +#define VENDOR_TXHIM 0x1000 +#define VENDOR_INTLVL 0x4000 +#define VENDOR_RPTR 0x8000 + +#define MII_INT 17 +#define INT_STAT_MASK 0x00ff +#define INT_STAT_ACOMP 0x0001 +#define INT_STAT_RFAULT 0x0002 +#define INT_STAT_LSCHG 0x0004 +#define INT_STAT_LPACK 0x0008 +#define INT_STAT_PDF 0x0010 +#define INT_STAT_PRX 0x0020 +#define INT_STAT_RXERR 0x0040 +#define INT_STAT_JABBER 0x0080 +#define INT_CTRL_MASK 0xff00 +#define INT_CTRL_ACOMP 0x0100 +#define INT_CTRL_RFAULT 0x0200 +#define INT_CTRL_LSCHG 0x0400 +#define INT_CTRL_LPACK 0x0800 +#define INT_CTRL_PDF 0x1000 +#define INT_CTRL_PRX 0x2000 +#define INT_CTRL_RXERR 0x4000 +#define INT_CTRL_JABBER 0x8000 + + +#define MII_DIAG 18 +#define DIAG_RLOCK 0x0100 +#define DIAG_RPASS 0x0200 +#define DIAG_RATE_100 0x0400 +#define DIAG_DUPLEX 0x0800 +#define DIAG_NEGFAIL 0x1000 + + +#endif diff --git a/sys/pci/if_dc.c b/sys/pci/if_dc.c index 6a437a4..84538e4 100644 --- a/sys/pci/if_dc.c +++ b/sys/pci/if_dc.c @@ -45,6 +45,7 @@ * ADMtek AN985 (www.admtek.com.tw) * Davicom DM9100, DM9102, DM9102A (www.davicom8.com) * Accton EN1217 (www.accton.com) + * Xircom X3201 (www.xircom.com) * * Datasheets for the 21143 are available at developer.intel.com. * Datasheets for the clone parts can be found at their respective sites. @@ -179,6 +180,8 @@ static struct dc_type dc_devs[] = { "82c169 PNIC 10/100BaseTX" }, { DC_VENDORID_ACCTON, DC_DEVICEID_EN1217, "Accton EN1217 10/100BaseTX" }, + { DC_VENDORID_XIRCOM, DC_DEVICEID_X3201, + "Xircom X3201 10/100BaseTX" }, { 0, 0, NULL } }; @@ -212,6 +215,8 @@ static void dc_eeprom_putbyte __P((struct dc_softc *, int)); static void dc_eeprom_getword __P((struct dc_softc *, int, u_int16_t *)); static void dc_eeprom_getword_pnic __P((struct dc_softc *, int, u_int16_t *)); +static void dc_eeprom_getword_xircom + __P((struct dc_softc *, int, u_int16_t *)); static void dc_read_eeprom __P((struct dc_softc *, caddr_t, int, int, int)); @@ -232,6 +237,7 @@ static u_int32_t dc_crc_be __P((caddr_t)); static void dc_setfilt_21143 __P((struct dc_softc *)); static void dc_setfilt_asix __P((struct dc_softc *)); static void dc_setfilt_admtek __P((struct dc_softc *)); +static void dc_setfilt_xircom __P((struct dc_softc *)); static void dc_setfilt __P((struct dc_softc *)); @@ -284,6 +290,7 @@ static driver_t dc_driver = { static devclass_t dc_devclass; +DRIVER_MODULE(if_dc, cardbus, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(if_dc, pci, dc_driver, dc_devclass, 0, 0); DRIVER_MODULE(miibus, dc, miibus_driver, miibus_devclass, 0, 0); @@ -402,6 +409,29 @@ static void dc_eeprom_getword_pnic(sc, addr, dest) /* * 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(sc, addr, dest) + 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); + return; +} + +/* + * Read a word of data stored in the EEPROM at address 'addr.' */ static void dc_eeprom_getword(sc, addr, dest) struct dc_softc *sc; @@ -466,6 +496,8 @@ static void dc_read_eeprom(sc, dest, off, cnt, swap) for (i = 0; i < cnt; i++) { if (DC_IS_PNIC(sc)) dc_eeprom_getword_pnic(sc, off + i, &word); + else if (DC_IS_XIRCOM(sc)) + dc_eeprom_getword_xircom(sc, off + i, &word); else dc_eeprom_getword(sc, off + i, &word); ptr = (u_int16_t *)(dest + (i * 2)); @@ -922,6 +954,15 @@ static u_int32_t dc_crc_le(sc, addr) if (sc->dc_flags & DC_64BIT_HASH) return (crc & ((1 << DC_BITS_64) - 1)); + /* Xircom's hash filtering table is different (read: weird) */ + /* Xircom uses the LEAST significant bits */ + if (DC_IS_XIRCOM(sc)) { + if ((crc & 0x180) == 0x180) + return (crc & 0x0F) + (crc & 0x70)*3 + (14 << 4); + else + return (crc & 0x1F) + ((crc>>1) & 0xF0)*3 + (12 << 4); + } + return (crc & ((1 << DC_BITS_512) - 1)); } @@ -1158,6 +1199,76 @@ void dc_setfilt_asix(sc) return; } +void dc_setfilt_xircom(sc) + struct dc_softc *sc; +{ + struct dc_desc *sframe; + u_int32_t h, *sp; + struct ifmultiaddr *ifma; + struct ifnet *ifp; + int i; + + ifp = &sc->arpcom.ac_if; + DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_TX_ON|DC_NETCFG_RX_ON)); + + i = sc->dc_cdata.dc_tx_prod; + DC_INC(sc->dc_cdata.dc_tx_prod, DC_TX_LIST_CNT); + sc->dc_cdata.dc_tx_cnt++; + sframe = &sc->dc_ldata->dc_tx_list[i]; + sp = (u_int32_t *)&sc->dc_cdata.dc_sbuf; + bzero((char *)sp, DC_SFRAME_LEN); + + sframe->dc_data = vtophys(&sc->dc_cdata.dc_sbuf); + sframe->dc_ctl = DC_SFRAME_LEN | DC_TXCTL_SETUP | DC_TXCTL_TLINK | + DC_FILTER_HASHPERF | DC_TXCTL_FINT; + + sc->dc_cdata.dc_tx_chain[i] = (struct mbuf *)&sc->dc_cdata.dc_sbuf; + + /* If we want promiscuous mode, set the allframes bit. */ + if (ifp->if_flags & IFF_PROMISC) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + else + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_PROMISC); + + if (ifp->if_flags & IFF_ALLMULTI) + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + else + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_RX_ALLMULTI); + + for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL; + ifma = ifma->ifma_link.le_next) { + if (ifma->ifma_addr->sa_family != AF_LINK) + continue; + h = dc_crc_le(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); + sp[h >> 4] |= 1 << (h & 0xF); + } + + if (ifp->if_flags & IFF_BROADCAST) { + h = dc_crc_le(sc, (caddr_t)ðerbroadcastaddr); + sp[h >> 4] |= 1 << (h & 0xF); + } + + /* Set our MAC address */ + sp[0] = ((u_int16_t *)sc->arpcom.ac_enaddr)[0]; + sp[1] = ((u_int16_t *)sc->arpcom.ac_enaddr)[1]; + sp[2] = ((u_int16_t *)sc->arpcom.ac_enaddr)[2]; + + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_TX_ON); + DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); + ifp->if_flags |= IFF_RUNNING; + sframe->dc_status = DC_TXSTAT_OWN; + CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF); + + /* + * wait some time... + */ + DELAY(1000); + + ifp->if_timer = 5; + + return; +} + static void dc_setfilt(sc) struct dc_softc *sc; { @@ -1171,7 +1282,10 @@ static void dc_setfilt(sc) if (DC_IS_ADMTEK(sc)) dc_setfilt_admtek(sc); - return; + if (DC_IS_XIRCOM(sc)) + dc_setfilt_xircom(sc); + + return; } /* @@ -1338,7 +1452,7 @@ static void dc_reset(sc) break; } - if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc)) { + if (DC_IS_ASIX(sc) || DC_IS_ADMTEK(sc) || DC_IS_XIRCOM(sc) || DC_IS_INTEL(sc)) { DELAY(10000); DC_CLRBIT(sc, DC_BUSCTL, DC_BUSCTL_RESET); i = 0; @@ -1788,6 +1902,14 @@ static int dc_attach(dev) sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; break; + case DC_DEVICEID_X3201: + sc->dc_type = DC_TYPE_XIRCOM; + sc->dc_flags |= DC_TX_INTR_ALWAYS | DC_TX_COALESCE; + /* + * We don't actually need to coalesce, but we're doing + * it to obtain a double word aligned buffer. + */ + break; default: printf("dc%d: unknown device: %x\n", sc->dc_unit, sc->dc_info->dc_did); @@ -1805,7 +1927,7 @@ static int dc_attach(dev) dc_reset(sc); /* Take 21143 out of snooze mode */ - if (DC_IS_INTEL(sc)) { + if (DC_IS_INTEL(sc) || DC_IS_XIRCOM(sc)) { command = pci_read_config(dev, DC_PCI_CFDD, 4); command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE); pci_write_config(dev, DC_PCI_CFDD, command, 4); @@ -1852,6 +1974,9 @@ static int dc_attach(dev) case DC_TYPE_AN985: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_AL_EE_NODEADDR, 3, 0); break; + case DC_TYPE_XIRCOM: + dc_read_eeprom(sc, (caddr_t)&eaddr, 3, 3, 0); + break; default: dc_read_eeprom(sc, (caddr_t)&eaddr, DC_EE_NODEADDR, 3, 0); break; @@ -1883,6 +2008,7 @@ static int dc_attach(dev) ifp->if_softc = sc; ifp->if_unit = unit; ifp->if_name = "dc"; + /* XXX: bleah, MTU gets overwritten in ether_ifattach() */ ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = dc_ioctl; @@ -1937,6 +2063,19 @@ static int dc_attach(dev) goto fail; } + if (DC_IS_XIRCOM(sc)) { + /* + * setup General Purpose Port mode and data so the tulip + * can talk to the MII. + */ + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + } + /* * Call MI attach routine. */ @@ -2420,11 +2559,23 @@ static void dc_txeof(sc) continue; } - if (/*sc->dc_type == DC_TYPE_21143 &&*/ - sc->dc_pmode == DC_PMODE_MII && - ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| - DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST))) - txstat &= ~DC_TXSTAT_ERRSUM; + if (DC_IS_XIRCOM(sc)) { + /* + * XXX: Why does my Xircom taunt me so? + * For some reason it likes setting the CARRLOST flag + * even when the carrier is there. wtf?!? */ + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER))) + txstat &= ~DC_TXSTAT_ERRSUM; + } else { + if (/*sc->dc_type == DC_TYPE_21143 &&*/ + sc->dc_pmode == DC_PMODE_MII && + ((txstat & 0xFFFF) & ~(DC_TXSTAT_ERRSUM| + DC_TXSTAT_NOCARRIER|DC_TXSTAT_CARRLOST))) + txstat &= ~DC_TXSTAT_ERRSUM; + } if (txstat & DC_TXSTAT_ERRSUM) { ifp->if_oerrors++; @@ -2557,7 +2708,8 @@ static void dc_intr(arg) /* Disable interrupts. */ CSR_WRITE_4(sc, DC_IMR, 0x00000000); - while((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) { + while(((status = CSR_READ_4(sc, DC_ISR)) & DC_INTRS) + && status != 0xFFFFFFFF) { CSR_WRITE_4(sc, DC_ISR, status); @@ -2883,6 +3035,19 @@ static void dc_init(xsc) DC_SETBIT(sc, DC_MX_MAGICPACKET, DC_MX_MAGIC_98715); } + if (DC_IS_XIRCOM(sc)) { + /* + * setup General Purpose Port mode and data so the tulip + * can talk to the MII. + */ + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_WRITE_EN | DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + CSR_WRITE_4(sc, DC_SIAGP, DC_SIAGP_INT1_EN | + DC_SIAGP_MD_GP2_OUTPUT | DC_SIAGP_MD_GP0_OUTPUT); + DELAY(10); + } + DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_TX_THRESH); DC_SETBIT(sc, DC_NETCFG, DC_TXTHRESH_72BYTES); diff --git a/sys/pci/if_dcreg.h b/sys/pci/if_dcreg.h index e72d8b4..f36d6b3 100644 --- a/sys/pci/if_dcreg.h +++ b/sys/pci/if_dcreg.h @@ -52,6 +52,7 @@ #define DC_SIARESET 0x68 /* SIA connectivity */ #define DC_10BTCTRL 0x70 /* SIA transmit and receive */ #define DC_WATCHDOG 0x78 /* SIA and general purpose port */ +#define DC_SIAGP 0x78 /* SIA and general purpose port (X3201) */ /* * There are two general 'types' of MX chips that we need to be @@ -75,6 +76,7 @@ #define DC_TYPE_DM9102 0x8 /* Davicom DM9102 */ #define DC_TYPE_PNICII 0x9 /* 82c115 PNIC II */ #define DC_TYPE_PNIC 0xA /* 82c168/82c169 PNIC I */ +#define DC_TYPE_XIRCOM 0xB /* Xircom X3201 */ #define DC_IS_MACRONIX(x) \ (x->dc_type == DC_TYPE_98713 || \ @@ -92,6 +94,7 @@ #define DC_IS_DAVICOM(x) (x->dc_type == DC_TYPE_DM9102) #define DC_IS_PNICII(x) (x->dc_type == DC_TYPE_PNICII) #define DC_IS_PNIC(x) (x->dc_type == DC_TYPE_PNIC) +#define DC_IS_XIRCOM(x) (x->dc_type == DC_TYPE_XIRCOM) /* MII/symbol mode port types */ #define DC_PMODE_MII 0x1 @@ -349,6 +352,25 @@ #define DC_WDOG_CTLWREN 0x08000000 /* + * SIA and General Purpose Port register (X3201) + */ +#define DC_SIAGP_RXMATCH 0x40000000 +#define DC_SIAGP_INT1 0x20000000 +#define DC_SIAGP_INT0 0x10000000 +#define DC_SIAGP_WRITE_EN 0x08000000 +#define DC_SIAGP_RXMATCH_EN 0x04000000 +#define DC_SIAGP_INT1_EN 0x02000000 +#define DC_SIAGP_INT0_EN 0x01000000 +#define DC_SIAGP_LED3 0x00800000 +#define DC_SIAGP_LED2 0x00400000 +#define DC_SIAGP_LED1 0x00200000 +#define DC_SIAGP_LED0 0x00100000 +#define DC_SIAGP_MD_GP3_OUTPUT 0x00080000 +#define DC_SIAGP_MD_GP2_OUTPUT 0x00040000 +#define DC_SIAGP_MD_GP1_OUTPUT 0x00020000 +#define DC_SIAGP_MD_GP0_OUTPUT 0x00010000 + +/* * Size of a setup frame. */ #define DC_SFRAME_LEN 192 @@ -834,6 +856,17 @@ struct dc_softc { #define DC_DEVICEID_EN1217 0x1217 /* + * Xircom vendor ID + */ +#define DC_VENDORID_XIRCOM 0x115d + +/* + * Xircom device IDs. + */ +#define DC_DEVICEID_X3201 0x0003 + + +/* * PCI low memory base and low I/O base register, and * other PCI registers. */ |