diff options
author | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-02-09 02:23:37 +0000 |
---|---|---|
committer | Aaron Campbell <aaron@cvs.openbsd.org> | 2001-02-09 02:23:37 +0000 |
commit | a4f1d6caa16d538d3dcf3c973b49101a1cf19cb7 (patch) | |
tree | 1f136bf202f3a48ae4830b7bfac96ec5224de727 /sys | |
parent | 18eff6bb082eee1ed861a997ea92b93a3f473ab5 (diff) |
Add support for parsing the media blocks from the SROM on the 21143 adapters.
These changes should make the driver work with the built-in Ethernet on the
Alpha Miata machines. From FreeBSD.
To make sure I didn't break anything (and as a general test), I tested the
modified driver with the following dc(4) variants: Macronix PMAC 98715,
Lite-On PNIC, Lite-On PNIC-II, ADMtek AL981, and ADMtek AN983.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/dc.c | 248 | ||||
-rw-r--r-- | sys/dev/ic/dcreg.h | 156 | ||||
-rw-r--r-- | sys/dev/pci/if_dc_pci.c | 63 |
3 files changed, 395 insertions, 72 deletions
diff --git a/sys/dev/ic/dc.c b/sys/dev/ic/dc.c index ec3c867db1b..e68665dd46b 100644 --- a/sys/dev/ic/dc.c +++ b/sys/dev/ic/dc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dc.c,v 1.20 2000/11/16 06:08:31 aaron Exp $ */ +/* $OpenBSD: dc.c,v 1.21 2001/02/09 02:23:34 aaron Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -76,27 +76,6 @@ * combination with the internal NWAY support to create a 10/100 * autosensing configuration. * - * Knowing which media is available on a given card is tough: you're - * supposed to go slogging through the EEPROM looking for media - * description structures. Unfortunately, some card vendors that use - * the 21143 don't obey the DEC SROM spec correctly, which means that - * what you find in the EEPROM may not agree with reality. Fortunately, - * the 21143 provides us a way to get around this issue: lurking in - * PCI configuration space is the Configuration Wake-Up Command Register. - * This register is loaded with a value from the EEPROM when wake on LAN - * mode is enabled; this value tells us quite clearly what kind of media - * is attached to the NIC. The main purpose of this register is to tell - * the NIC what media to scan when in wake on LAN mode, however by - * forcibly enabling wake on LAN mode, we can use to learn what kind of - * media a given NIC has available and adapt ourselves accordingly. - * - * Of course, if the media description blocks in the EEPROM are bogus. - * what are the odds that the CWUC aren't bogus as well, right? Well, - * the CWUC value is more likely to be correct since wake on LAN mode - * won't work correctly without it, and wake on LAN is a big selling - * point these days. It's also harder to screw up a single byte than - * a whole media descriptor block. - * * 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 @@ -154,6 +133,9 @@ #include <dev/pci/pcidevs.h> #define DC_USEIOSPACE +#ifdef __alpha__ +#define SRM_MEDIA +#endif #include <dev/ic/dcreg.h> @@ -209,6 +191,15 @@ void dc_reset __P((struct dc_softc *)); int dc_list_rx_init __P((struct dc_softc *)); int dc_list_tx_init __P((struct dc_softc *)); +void dc_parse_21143_srom __P((struct dc_softc *)); +void dc_decode_leaf_sia __P((struct dc_softc *, + struct dc_eblock_sia *)); +void dc_decode_leaf_mii __P((struct dc_softc *, + struct dc_eblock_mii *)); +void dc_decode_leaf_sym __P((struct dc_softc *, + struct dc_eblock_sym *)); +void dc_apply_fixup __P((struct dc_softc *, int)); + #define DC_SETBIT(sc, reg, x) \ CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x)) @@ -671,7 +662,7 @@ int dc_miibus_readreg(self, phy, reg) if (DC_IS_ADMTEK(sc) && phy != DC_ADMTEK_PHYADDR) return(0); - if (sc->dc_pmode == DC_PMODE_SYM) { + if (sc->dc_pmode != DC_PMODE_MII) { if (phy == (MII_NPHY - 1)) { switch(reg) { case MII_BMSR: @@ -838,6 +829,7 @@ void dc_miibus_statchg(self) if (DC_IS_ADMTEK(sc)) return; + mii = &sc->sc_mii; ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { @@ -1182,7 +1174,7 @@ void dc_setfilt_xircom(sc) /* 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]; + 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); @@ -1284,6 +1276,10 @@ void dc_setcfg(sc, media) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); + if (DC_IS_INTEL(sc)) + dc_apply_fixup(sc, + (media & IFM_GMASK) == IFM_FDX ? + IFM_100_TX|IFM_FDX : IFM_100_TX); } } @@ -1318,6 +1314,21 @@ void dc_setcfg(sc, media) DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PCS); DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_SCRAMBLER); + if (DC_IS_INTEL(sc)) { + DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); + if ((media & IFM_GMASK) == IFM_FDX) + DC_SETBIT(sc, DC_10BTCTRL, 0x7F3D); + else + DC_SETBIT(sc, DC_10BTCTRL, 0x7F3F); + DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); + DC_CLRBIT(sc, DC_10BTCTRL, + DC_TCTL_AUTONEGENBL); + dc_apply_fixup(sc, + (media & IFM_GMASK) == IFM_FDX ? + IFM_10_T|IFM_FDX : IFM_10_T); + DELAY(20000); + } } } @@ -1387,8 +1398,160 @@ void dc_reset(sc) * into a state where it will never come out of reset * until we reset the whole chip again. */ - if (DC_IS_INTEL(sc)) + if (DC_IS_INTEL(sc)) { DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET); + CSR_WRITE_4(sc, DC_10BTCTRL, 0); + CSR_WRITE_4(sc, DC_WATCHDOG, 0); + } + + return; +} + +void dc_apply_fixup(sc, media) + struct dc_softc *sc; + int media; +{ + struct dc_mediainfo *m; + u_int8_t *p; + int i; + u_int8_t reg; + + m = sc->dc_mi; + + while (m != NULL) { + if (m->dc_media == media) + break; + m = m->dc_next; + } + + if (m == NULL) + return; + + for (i = 0, p = m->dc_reset_ptr; i < m->dc_reset_len; i++, p += 2) { + reg = (p[0] | (p[1] << 8)) << 16; + CSR_WRITE_4(sc, DC_WATCHDOG, reg); + } + + for (i = 0, p = m->dc_gp_ptr; i < m->dc_gp_len; i++, p += 2) { + reg = (p[0] | (p[1] << 8)) << 16; + CSR_WRITE_4(sc, DC_WATCHDOG, reg); + } + + return; +} + +void dc_decode_leaf_sia(sc, l) + struct dc_softc *sc; + struct dc_eblock_sia *l; +{ + struct dc_mediainfo *m; + + m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT); + if (l->dc_sia_code == DC_SIA_CODE_10BT) + m->dc_media = IFM_10_T; + + if (l->dc_sia_code == DC_SIA_CODE_10BT_FDX) + m->dc_media = IFM_10_T|IFM_FDX; + + if (l->dc_sia_code == DC_SIA_CODE_10B2) + m->dc_media = IFM_10_2; + + if (l->dc_sia_code == DC_SIA_CODE_10B5) + m->dc_media = IFM_10_5; + + m->dc_gp_len = 2; + m->dc_gp_ptr = (u_int8_t *)&l->dc_sia_gpio_ctl; + + m->dc_next = sc->dc_mi; + sc->dc_mi = m; + + sc->dc_pmode = DC_PMODE_SIA; + + return; +} + +void dc_decode_leaf_sym(sc, l) + struct dc_softc *sc; + struct dc_eblock_sym *l; +{ + struct dc_mediainfo *m; + + m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT); + if (l->dc_sym_code == DC_SYM_CODE_100BT) + m->dc_media = IFM_100_TX; + + if (l->dc_sym_code == DC_SYM_CODE_100BT_FDX) + m->dc_media = IFM_100_TX|IFM_FDX; + + m->dc_gp_len = 2; + m->dc_gp_ptr = (u_int8_t *)&l->dc_sym_gpio_ctl; + + m->dc_next = sc->dc_mi; + sc->dc_mi = m; + + sc->dc_pmode = DC_PMODE_SYM; + + return; +} + +void dc_decode_leaf_mii(sc, l) + struct dc_softc *sc; + struct dc_eblock_mii *l; +{ + u_int8_t *p; + struct dc_mediainfo *m; + + m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT); + /* We abuse IFM_AUTO to represent MII. */ + m->dc_media = IFM_AUTO; + m->dc_gp_len = l->dc_gpr_len; + + p = (u_int8_t *)l; + p += sizeof(struct dc_eblock_mii); + m->dc_gp_ptr = p; + p += 2 * l->dc_gpr_len; + m->dc_reset_len = *p; + p++; + m->dc_reset_ptr = p; + + m->dc_next = sc->dc_mi; + sc->dc_mi = m; + + return; +} + +void dc_parse_21143_srom(sc) + struct dc_softc *sc; +{ + struct dc_leaf_hdr *lhdr; + struct dc_eblock_hdr *hdr; + int i, loff; + char *ptr; + + loff = sc->dc_srom[27]; + lhdr = (struct dc_leaf_hdr *)&(sc->dc_srom[loff]); + + ptr = (char *)lhdr; + ptr += sizeof(struct dc_leaf_hdr) - 1; + for (i = 0; i < lhdr->dc_mcnt; i++) { + hdr = (struct dc_eblock_hdr *)ptr; + switch(hdr->dc_type) { + case DC_EBLOCK_MII: + dc_decode_leaf_mii(sc, (struct dc_eblock_mii *)hdr); + break; + case DC_EBLOCK_SIA: + dc_decode_leaf_sia(sc, (struct dc_eblock_sia *)hdr); + break; + case DC_EBLOCK_SYM: + dc_decode_leaf_sym(sc, (struct dc_eblock_sym *)hdr); + break; + default: + /* Don't care. Yet. */ + break; + } + ptr += (hdr->dc_len & 0x7F); + ptr++; + } return; } @@ -1401,7 +1564,7 @@ void dc_attach_common(sc) struct dc_softc *sc; { struct ifnet *ifp; - int error = 0, mac_offset; + int error = 0, mac_offset, tmp; if (!DC_IS_XIRCOM(sc)) dc_eeprom_width(sc); @@ -1468,6 +1631,18 @@ void dc_attach_common(sc) ifp->if_snd.ifq_maxlen = DC_TX_LIST_CNT - 1; bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ); + /* Do MII setup. If this is a 21143, check for a PHY on the + * MII bus after applying any necessary fixups to twiddle the + * GPIO bits. If we don't end up finding a PHY, restore the + * old selection (SIA only or SIA/SYM) and attach the dcphy + * driver instead. + */ + if (DC_IS_INTEL(sc)) { + dc_apply_fixup(sc, IFM_AUTO); + tmp = sc->dc_pmode; + sc->dc_pmode = DC_PMODE_MII; + } + sc->sc_mii.mii_ifp = ifp; sc->sc_mii.mii_readreg = dc_miibus_readreg; sc->sc_mii.mii_writereg = dc_miibus_writereg; @@ -1488,7 +1663,9 @@ void dc_attach_common(sc) if (DC_IS_INTEL(sc)) { if (error) { - sc->dc_pmode = DC_PMODE_SYM; + sc->dc_pmode = tmp; + if (sc->dc_pmode != DC_PMODE_SIA) + sc->dc_pmode = DC_PMODE_SYM; sc->dc_flags |= DC_21143_NWAY; mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); @@ -2331,6 +2508,10 @@ void dc_start(ifp) if (ifp->if_bpf) bpf_mtap(ifp->if_bpf, m_head); #endif + if (sc->dc_flags & DC_TX_ONE) { + ifp->if_flags |= IFF_OACTIVE; + break; + } } /* Transmit */ @@ -2507,6 +2688,15 @@ void dc_init(xsc) timeout_add(&sc->dc_tick_tmo, hz); } +#ifdef SRM_MEDIA + if(sc->dc_srm_media) { + struct ifreq ifr; + + ifr.ifr_media = sc->dc_srm_media; + ifmedia_ioctl(ifp, &ifr, &mii->mii_media, SIOCSIFMEDIA); + sc->dc_srm_media = 0; +#endif + return; } @@ -2634,6 +2824,10 @@ int dc_ioctl(ifp, command, data) case SIOCSIFMEDIA: mii = &sc->sc_mii; error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); +#ifdef SRM_MEDIA + if (sc->dc_srm_media) + sc->dc_srm_media = 0; +#endif break; default: error = EINVAL; diff --git a/sys/dev/ic/dcreg.h b/sys/dev/ic/dcreg.h index 8144a61afe4..d5e8e263201 100644 --- a/sys/dev/ic/dcreg.h +++ b/sys/dev/ic/dcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dcreg.h,v 1.9 2000/10/26 20:50:43 aaron Exp $ */ +/* $OpenBSD: dcreg.h,v 1.10 2001/02/09 02:23:35 aaron Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -101,6 +101,7 @@ /* MII/symbol mode port types */ #define DC_PMODE_MII 0x1 #define DC_PMODE_SYM 0x2 +#define DC_PMODE_SIA 0x3 /* * Bus control bits. @@ -354,21 +355,21 @@ /* * 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 +#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. @@ -468,6 +469,15 @@ struct dc_chain_data { int dc_rx_prod; }; +struct dc_mediainfo { + int dc_media; + u_int8_t *dc_gp_ptr; + u_int8_t dc_gp_len; + u_int8_t *dc_reset_ptr; + u_int8_t dc_reset_len; + struct dc_mediainfo *dc_next; +}; + struct dc_type { u_int16_t dc_vid; u_int16_t dc_did; @@ -520,8 +530,8 @@ struct dc_mii_frame { /* * ASIX specific registers. */ -#define DC_AX_FILTIDX 0x68 /* RX filter index */ -#define DC_AX_FILTDATA 0x70 /* RX filter data */ +#define DC_AX_FILTIDX 0x68 /* RX filter index */ +#define DC_AX_FILTDATA 0x70 /* RX filter data */ /* * Special ASIX-specific bits in the ASIX NETCFG register (CSR6). @@ -681,12 +691,17 @@ struct dc_softc { int dc_if_media; u_int32_t dc_flags; u_int32_t dc_txthresh; + u_int8_t dc_srom[1024]; + struct dc_mediainfo *dc_mi; struct dc_list_data *dc_ldata; caddr_t dc_ldata_ptr; struct dc_chain_data dc_cdata; u_int32_t dc_csid; u_int dc_revision; struct timeout dc_tick_tmo; +#ifdef SRM_MEDIA + int dc_srm_media; +#endif }; #define DC_TX_POLL 0x00000001 @@ -704,6 +719,7 @@ struct dc_softc { #define DC_128BIT_HASH 0x00001000 #define DC_64BIT_HASH 0x00002000 #define DC_TULIP_LEDS 0x00004000 +#define DC_TX_ONE 0x00008000 /* * register space access macros @@ -866,6 +882,110 @@ struct dc_softc { #define DC_CWUC_SYM_ABILITY 0x00000080 #define DC_CWUC_LOCK 0x00000100 +/* + * SROM nonsense. + */ + +#define DC_IB_CTLRCNT 0x13 +#define DC_IB_LEAF0_CNUM 0x1A +#define DC_IB_LEAF0_OFFSET 0x1B + +struct dc_info_leaf { + u_int16_t dc_conntype; + u_int8_t dc_blkcnt; + u_int8_t dc_rsvd; + u_int16_t dc_infoblk; +}; + +#define DC_CTYPE_10BT 0x0000 +#define DC_CTYPE_10BT_NWAY 0x0100 +#define DC_CTYPE_10BT_FDX 0x0204 +#define DC_CTYPE_10B2 0x0001 +#define DC_CTYPE_10B5 0x0002 +#define DC_CTYPE_100BT 0x0003 +#define DC_CTYPE_100BT_FDX 0x0205 +#define DC_CTYPE_100T4 0x0006 +#define DC_CTYPE_100FX 0x0007 +#define DC_CTYPE_100FX_FDX 0x0208 +#define DC_CTYPE_MII_10BT 0x0009 +#define DC_CTYPE_MII_10BT_FDX 0x020A +#define DC_CTYPE_MII_100BT 0x000D +#define DC_CTYPE_MII_100BT_FDX 0x020E +#define DC_CTYPE_MII_100T4 0x000F +#define DC_CTYPE_MII_100FX 0x0010 +#define DC_CTYPE_MII_100FX_FDX 0x0211 +#define DC_CTYPE_DYN_PUP_AUTOSENSE 0x0800 +#define DC_CTYPE_PUP_AUTOSENSE 0x8800 +#define DC_CTYPE_NOMEDIA 0xFFFF + +#define DC_EBLOCK_SIA 0x0002 +#define DC_EBLOCK_MII 0x0003 +#define DC_EBLOCK_SYM 0x0004 +#define DC_EBLOCK_RESET 0x0005 +#define DC_EBLOCK_PHY_SHUTDOWN 0x0006 + +struct dc_leaf_hdr { + u_int16_t dc_mtype; + u_int8_t dc_mcnt; + u_int8_t dc_rsvd; +}; + +struct dc_eblock_hdr { + u_int8_t dc_len; + u_int8_t dc_type; +}; + +struct dc_eblock_sia { + struct dc_eblock_hdr dc_sia_hdr; + u_int8_t dc_sia_code; + u_int8_t dc_sia_mediaspec[6]; /* CSR13, CSR14, CSR15 */ + u_int8_t dc_sia_gpio_ctl[2]; + u_int8_t dc_sia_gpio_dat[2]; +}; + +#define DC_SIA_CODE_10BT 0x00 +#define DC_SIA_CODE_10B2 0x01 +#define DC_SIA_CODE_10B5 0x02 +#define DC_SIA_CODE_10BT_FDX 0x04 +#define DC_SIA_CODE_EXT 0x40 + +/* + * Note that the first word in the gpr and reset + * sequences is always a control word. + */ +struct dc_eblock_mii { + struct dc_eblock_hdr dc_mii_hdr; + u_int8_t dc_mii_phynum; + u_int8_t dc_gpr_len; +/* u_int16_t dc_gpr_dat[n]; */ +/* u_int8_t dc_reset_len; */ +/* u_int16_t dc_reset_dat[n]; */ +/* There are other fields after these, but we don't + * care about them since they can be determined by looking + * at the PHY. + */ +}; + +struct dc_eblock_sym { + struct dc_eblock_hdr dc_sym_hdr; + u_int8_t dc_sym_code; + u_int8_t dc_sym_gpio_ctl[2]; + u_int8_t dc_sym_gpio_dat[2]; + u_int8_t dc_sym_cmd[2]; +}; + +#define DC_SYM_CODE_100BT 0x03 +#define DC_SYM_CODE_100BT_FDX 0x05 +#define DC_SYM_CODE_100T4 0x06 +#define DC_SYM_CODE_100FX 0x07 +#define DC_SYM_CODE_100FX_FDX 0x08 + +struct dc_eblock_reset { + struct dc_eblock_hdr dc_reset_hdr; + u_int8_t dc_reset_len; +/* u_int16_t dc_reset_dat[n]; */ +}; + #ifdef __alpha__ #undef vtophys #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) diff --git a/sys/dev/pci/if_dc_pci.c b/sys/dev/pci/if_dc_pci.c index 27cb61a77aa..ff2b0aa6b38 100644 --- a/sys/dev/pci/if_dc_pci.c +++ b/sys/dev/pci/if_dc_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_dc_pci.c,v 1.11 2000/11/16 01:25:45 aaron Exp $ */ +/* $OpenBSD: if_dc_pci.c,v 1.12 2001/02/09 02:23:36 aaron Exp $ */ /* * Copyright (c) 1997, 1998, 1999 @@ -104,6 +104,10 @@ int dc_pci_probe __P((struct device *, void *, void *)); void dc_pci_attach __P((struct device *, struct device *, void *)); void dc_pci_acpi __P((struct device *, void *)); +extern void dc_read_eeprom __P((struct dc_softc *, caddr_t, int, int, + int)); +extern void dc_parse_21143_srom __P((struct dc_softc *)); + /* * Probe for a 21143 or clone chip. Check the PCI vendor and device * IDs against our list and return a device name if we find a match. @@ -263,6 +267,8 @@ void dc_pci_attach(parent, self, aux) sc->dc_type = DC_TYPE_21143; sc->dc_flags |= DC_TX_POLL|DC_TX_USE_TX_INTR; sc->dc_flags |= DC_REDUCED_MII_POLL; + /* Save EEPROM contents so we can parse them later. */ + dc_read_eeprom(sc, (caddr_t)&sc->dc_srom, 0, 512, 0); } break; case PCI_VENDOR_DAVICOM: @@ -424,32 +430,9 @@ void dc_pci_attach(parent, self, aux) * The tricky ones are the Macronix/PNIC II and the * Intel 21143. */ - if (DC_IS_INTEL(sc)) { - u_int32_t media, cwuc; - cwuc = pci_conf_read(pc, pa->pa_tag, DC_PCI_CWUC); - cwuc |= DC_CWUC_FORCE_WUL; - pci_conf_write(pc, pa->pa_tag, DC_PCI_CWUC, cwuc); - DELAY(10000); - media = pci_conf_read(pc, pa->pa_tag, DC_PCI_CWUC); - cwuc &= ~DC_CWUC_FORCE_WUL; - pci_conf_write(pc, pa->pa_tag, DC_PCI_CWUC, cwuc); - DELAY(10000); - if (media & DC_CWUC_MII_ABILITY) - sc->dc_pmode = DC_PMODE_MII; - if (media & DC_CWUC_SYM_ABILITY) { - sc->dc_pmode = DC_PMODE_SYM; - sc->dc_flags |= DC_21143_NWAY; - } - /* - * If none of the bits are set, then this NIC - * isn't meant to support 'wake up LAN' mode. - * This is usually only the case on multiport - * cards, and these cards almost always have - * MII transceivers. - */ - if (media == 0) - sc->dc_pmode = DC_PMODE_MII; - } else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { + if (DC_IS_INTEL(sc)) + dc_parse_21143_srom(sc); + else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { if (sc->dc_type == DC_TYPE_98713) sc->dc_pmode = DC_PMODE_MII; else @@ -457,6 +440,32 @@ void dc_pci_attach(parent, self, aux) } else if (!sc->dc_pmode) sc->dc_pmode = DC_PMODE_MII; +#ifdef SRM_MEDIA + sc->dc_srm_media = 0; + + /* Remember the SRM console media setting */ + if (DC_IS_INTEL(sc)) { + command = pci_read_config(dev, DC_PCI_CFDD, 4); + command &= ~(DC_CFDD_SNOOZE_MODE|DC_CFDD_SLEEP_MODE); + switch ((command >> 8) & 0xff) { + case 3: + sc->dc_srm_media = IFM_10_T; + break; + case 4: + sc->dc_srm_media = IFM_10_T | IFM_FDX; + break; + case 5: + sc->dc_srm_media = IFM_100_TX; + break; + case 6: + sc->dc_srm_media = IFM_100_TX | IFM_FDX; + break; + } + if (sc->dc_srm_media) + sc->dc_srm_media |= IFM_ACTIVE | IFM_ETHER; + } +#endif + dc_attach_common(sc); fail: |