Index: sys/dev/dc/if_dc.c =================================================================== --- sys/dev/dc/if_dc.c (revision 218693) +++ sys/dev/dc/if_dc.c (working copy) @@ -287,11 +287,11 @@ 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 int dc_read_srom(struct dc_softc *, int); +static int dc_parse_21143_srom(struct dc_softc *); +static int dc_decode_leaf_sia(struct dc_softc *, struct dc_eblock_sia *); +static int dc_decode_leaf_mii(struct dc_softc *, struct dc_eblock_mii *); +static int dc_decode_leaf_sym(struct dc_softc *, struct dc_eblock_sym *); static void dc_apply_fixup(struct dc_softc *, int); static int dc_check_multiport(struct dc_softc *); @@ -944,6 +944,7 @@ dc_miibus_statchg(device_t dev) { struct dc_softc *sc; + struct ifnet *ifp; struct mii_data *mii; struct ifmedia *ifm; @@ -952,15 +953,47 @@ return; mii = device_get_softc(sc->dc_miibus); + ifp = sc->dc_ifp; + if (mii == NULL || ifp == NULL || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) + return; + ifm = &mii->mii_media; if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) { dc_setcfg(sc, ifm->ifm_media); sc->dc_if_media = ifm->ifm_media; - } else { - dc_setcfg(sc, mii->mii_media_active); - sc->dc_if_media = mii->mii_media_active; + return; } + + sc->dc_link = 0; + if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) == + (IFM_ACTIVE | IFM_AVALID)) { + switch (IFM_SUBTYPE(mii->mii_media_active)) { + case IFM_10_T: + printf("10Mbps LINK UP\n"); + sc->dc_link = 1; + break; + case IFM_100_TX: + printf("100Mbps LINK UP\n"); + sc->dc_link = 1; + break; + default: + break; + } + } + if (sc->dc_link == 0) { + printf("LINK DOWN\n"); + return; + } + +#if 1 + printf("media_active = 0x%08x\n", mii->mii_media_active); +#endif + sc->dc_if_media = mii->mii_media_active; + if (DC_IS_ADMTEK(sc)) + return; + dc_setcfg(sc, mii->mii_media_active); } /* @@ -1404,8 +1437,6 @@ if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); - if (DC_IS_INTEL(sc)) - dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_SETBIT(sc, DC_PN_GPIO_SPEEDSEL); @@ -1415,10 +1446,6 @@ 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); } } @@ -1442,8 +1469,6 @@ if (!DC_IS_DAVICOM(sc)) DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL); DC_CLRBIT(sc, DC_10BTCTRL, 0xFFFF); - if (DC_IS_INTEL(sc)) - dc_apply_fixup(sc, IFM_AUTO); } else { if (DC_IS_PNIC(sc)) { DC_PN_GPIO_CLRBIT(sc, DC_PN_GPIO_SPEEDSEL); @@ -1463,9 +1488,6 @@ 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); } } @@ -1537,7 +1559,7 @@ */ 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_10BTCTRL, 0xFFFFFFFF); CSR_WRITE_4(sc, DC_WATCHDOG, 0); } } @@ -1616,12 +1638,16 @@ } } -static void +static int dc_decode_leaf_sia(struct dc_softc *sc, struct dc_eblock_sia *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (m == NULL) { + device_printf(sc->dc_dev, "Could not allocate mediainfo\n"); + return (ENOMEM); + } switch (l->dc_sia_code & ~DC_SIA_CODE_EXT) { case DC_SIA_CODE_10BT: m->dc_media = IFM_10_T; @@ -1658,14 +1684,19 @@ sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SIA; + return (0); } -static void +static int dc_decode_leaf_sym(struct dc_softc *sc, struct dc_eblock_sym *l) { struct dc_mediainfo *m; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (m == NULL) { + device_printf(sc->dc_dev, "Could not allocate mediainfo\n"); + return (ENOMEM); + } if (l->dc_sym_code == DC_SYM_CODE_100BT) m->dc_media = IFM_100_TX; @@ -1679,15 +1710,20 @@ sc->dc_mi = m; sc->dc_pmode = DC_PMODE_SYM; + return (0); } -static void +static int dc_decode_leaf_mii(struct dc_softc *sc, struct dc_eblock_mii *l) { struct dc_mediainfo *m; u_int8_t *p; m = malloc(sizeof(struct dc_mediainfo), M_DEVBUF, M_NOWAIT | M_ZERO); + if (m == NULL) { + device_printf(sc->dc_dev, "Could not allocate mediainfo\n"); + return (ENOMEM); + } /* We abuse IFM_AUTO to represent MII. */ m->dc_media = IFM_AUTO; m->dc_gp_len = l->dc_gpr_len; @@ -1702,24 +1738,30 @@ m->dc_next = sc->dc_mi; sc->dc_mi = m; + return (0); } -static void +static int dc_read_srom(struct dc_softc *sc, int bits) { int size; - size = 2 << bits; + size = DC_ROM_SIZE(bits); sc->dc_srom = malloc(size, M_DEVBUF, M_NOWAIT); + if (sc->dc_srom == NULL) { + device_printf(sc->dc_dev, "Could not allocate SROM buffer\n"); + return (ENOMEM); + } dc_read_eeprom(sc, (caddr_t)sc->dc_srom, 0, (size / 2), 0); + return (0); } -static void +static int dc_parse_21143_srom(struct dc_softc *sc) { struct dc_leaf_hdr *lhdr; struct dc_eblock_hdr *hdr; - int have_mii, i, loff; + int error, have_mii, i, loff; char *ptr; have_mii = 0; @@ -1746,20 +1788,22 @@ */ ptr = (char *)lhdr; ptr += sizeof(struct dc_leaf_hdr) - 1; + error = 0; 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); + error = dc_decode_leaf_mii(sc, + (struct dc_eblock_mii *)hdr); break; case DC_EBLOCK_SIA: if (! have_mii) - dc_decode_leaf_sia(sc, + error = dc_decode_leaf_sia(sc, (struct dc_eblock_sia *)hdr); break; case DC_EBLOCK_SYM: if (! have_mii) - dc_decode_leaf_sym(sc, + error = dc_decode_leaf_sym(sc, (struct dc_eblock_sym *)hdr); break; default: @@ -1769,6 +1813,7 @@ ptr += (hdr->dc_len & 0x7F); ptr++; } + return (error); } static void @@ -1793,6 +1838,7 @@ u_int32_t command; struct dc_softc *sc; struct ifnet *ifp; + struct dc_mediainfo *m; u_int32_t reg, revision; int error, i, mac_offset, phy, rid, tmp; u_int8_t *mac; @@ -1835,6 +1881,7 @@ sc->dc_info = dc_devtype(dev); revision = pci_get_revid(dev); + error = 0; /* Get the eeprom width, but PNIC and XIRCOM have diff eeprom */ if (sc->dc_info->dc_devid != DC_DEVID(DC_VENDORID_LO, DC_DEVICEID_82C168) && @@ -1848,7 +1895,9 @@ 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_srom(sc, sc->dc_romwidth); + error = dc_read_srom(sc, sc->dc_romwidth); + if (error != 0) + goto fail; break; case DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9009): case DC_DEVID(DC_VENDORID_DAVICOM, DC_DEVICEID_DM9100): @@ -1867,7 +1916,9 @@ sc->dc_flags |= DC_TX_USE_TX_INTR; sc->dc_flags |= DC_TX_ADMTEK_WAR; sc->dc_pmode = DC_PMODE_MII; - dc_read_srom(sc, sc->dc_romwidth); + error = dc_read_srom(sc, sc->dc_romwidth); + if (error != 0) + goto fail; break; case DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_AN983): case DC_DEVID(DC_VENDORID_ADMTEK, DC_DEVICEID_AN985): @@ -1934,6 +1985,12 @@ sc->dc_flags |= DC_TX_STORENFWD | DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_PNIC_RX_BUG_WAR; sc->dc_pnic_rx_buf = malloc(DC_RXLEN * 5, M_DEVBUF, M_NOWAIT); + if (sc->dc_pnic_rx_buf == NULL) { + device_printf(sc->dc_dev, + "Could not allocate PNIC RX buffer\n"); + error = ENOMEM; + goto fail; + } if (revision < DC_REVISION_82C169) sc->dc_pmode = DC_PMODE_SYM; break; @@ -1959,7 +2016,9 @@ sc->dc_flags |= DC_TX_INTR_ALWAYS; sc->dc_flags |= DC_REDUCED_MII_POLL; sc->dc_pmode = DC_PMODE_MII; - dc_read_srom(sc, sc->dc_romwidth); + error = dc_read_srom(sc, sc->dc_romwidth); + if (error != 0) + goto fail; break; default: device_printf(dev, "unknown device: %x\n", @@ -1990,9 +2049,11 @@ * The tricky ones are the Macronix/PNIC II and the * Intel 21143. */ - if (DC_IS_INTEL(sc)) - dc_parse_21143_srom(sc); - else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { + if (DC_IS_INTEL(sc)) { + error = dc_parse_21143_srom(sc); + if (error != 0) + goto fail; + } else if (DC_IS_MACRONIX(sc) || DC_IS_PNICII(sc)) { if (sc->dc_type == DC_TYPE_98713) sc->dc_pmode = DC_PMODE_MII; else @@ -2071,8 +2132,24 @@ if ((sc->dc_eaddr[0] == 0 && (sc->dc_eaddr[1] & ~0xffff) == 0) || (sc->dc_eaddr[0] == 0xffffffff && (sc->dc_eaddr[1] & 0xffff) == 0xffff)) { - if (dc_check_multiport(sc) == 0) + error = dc_check_multiport(sc); + if (error == 0) { bcopy(sc->dc_eaddr, eaddr, sizeof(eaddr)); + /* Extract media information. */ + if (DC_IS_INTEL(sc) && sc->dc_srom != NULL) { + while (sc->dc_mi != NULL) { + m = sc->dc_mi->dc_next; + free(sc->dc_mi, M_DEVBUF); + sc->dc_mi = m; + } + error = dc_parse_21143_srom(sc); + if (error != 0) + goto fail; + } + } else if (error == ENOMEM) + goto fail; + else + error = 0; } /* Allocate a busdma tag and DMA safe memory for TX/RX descriptors. */ @@ -2909,11 +2986,8 @@ */ if ((DC_HAS_BROKEN_RXSTATE(sc) || (CSR_READ_4(sc, DC_ISR) & DC_ISR_RX_STATE) == DC_RXSTATE_WAIT) && - sc->dc_cdata.dc_tx_cnt == 0) { + sc->dc_cdata.dc_tx_cnt == 0) mii_tick(mii); - if (!(mii->mii_media_status & IFM_ACTIVE)) - sc->dc_link = 0; - } } } else mii_tick(mii); @@ -2937,12 +3011,8 @@ * that time, packets will stay in the send queue, and once the * link comes up, they will be flushed out to the wire. */ - if (!sc->dc_link && mii->mii_media_status & IFM_ACTIVE && - IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->dc_link++; - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - dc_start_locked(ifp); - } + if (sc->dc_link != 0 && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + dc_start_locked(ifp); if (sc->dc_flags & DC_21143_NWAY && !sc->dc_link) callout_reset(&sc->dc_stat_ch, hz/10, dc_tick, sc); @@ -3367,6 +3437,7 @@ { struct ifnet *ifp = sc->dc_ifp; struct mii_data *mii; + struct ifmedia *ifm; DC_LOCK_ASSERT(sc); @@ -3377,6 +3448,10 @@ */ dc_stop(sc); dc_reset(sc); + if (DC_IS_INTEL(sc)) { + ifm = &mii->mii_media; + dc_apply_fixup(sc, ifm->ifm_media); + } /* * Set cache alignment and burst length. @@ -3520,12 +3595,12 @@ DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_RX_ON); CSR_WRITE_4(sc, DC_RXSTART, 0xFFFFFFFF); + ifp->if_drv_flags |= IFF_DRV_RUNNING; + ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + mii_mediachg(mii); dc_setcfg(sc, sc->dc_if_media); - ifp->if_drv_flags |= IFF_DRV_RUNNING; - ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; - /* Don't start the ticker if this is a homePNA link. */ if (IFM_SUBTYPE(mii->mii_media.ifm_media) == IFM_HPNA_1) sc->dc_link = 1; @@ -3556,7 +3631,9 @@ mii_mediachg(mii); ifm = &mii->mii_media; - if (DC_IS_DAVICOM(sc) && + if (DC_IS_INTEL(sc)) + dc_setcfg(sc, ifm->ifm_media); + else if (DC_IS_DAVICOM(sc) && IFM_SUBTYPE(ifm->ifm_media) == IFM_HPNA_1) dc_setcfg(sc, ifm->ifm_media); else @@ -3839,11 +3916,27 @@ if (unit > device_get_unit(sc->dc_dev)) continue; dsc = device_get_softc(child); - device_printf(sc->dc_dev, "Using station address of %s as base", + device_printf(sc->dc_dev, + "Using station address of %s as base\n", device_get_nameunit(child)); bcopy(dsc->dc_eaddr, sc->dc_eaddr, ETHER_ADDR_LEN); eaddr = (uint8_t *)sc->dc_eaddr; eaddr[5]++; + /* Prepare SROM to parse again. */ + if (DC_IS_INTEL(sc) && dsc->dc_srom != NULL && + sc->dc_romwidth != 0) { + free(sc->dc_srom, M_DEVBUF); + sc->dc_romwidth = dsc->dc_romwidth; + sc->dc_srom = malloc(DC_ROM_SIZE(sc->dc_romwidth), + M_DEVBUF, M_NOWAIT); + if (sc->dc_srom == NULL) { + device_printf(sc->dc_dev, + "Could not allocate SROM buffer\n"); + return (ENOMEM); + } + bcopy(dsc->dc_srom, sc->dc_srom, + DC_ROM_SIZE(sc->dc_romwidth)); + } return (0); } return (ENOENT); Index: sys/dev/dc/if_dcreg.h =================================================================== --- sys/dev/dc/if_dcreg.h (revision 218693) +++ sys/dev/dc/if_dcreg.h (working copy) @@ -1064,6 +1064,8 @@ * SROM nonsense. */ +#define DC_ROM_SIZE(bits) (2 << (bits)) + #define DC_IB_CTLRCNT 0x13 #define DC_IB_LEAF0_CNUM 0x1A #define DC_IB_LEAF0_OFFSET 0x1B